[SCM] The rsync repository. - branch master updated

Rsync CVS commit messages rsync-cvs at lists.samba.org
Tue Dec 21 01:37:35 UTC 2021


The branch, master has been updated
       via  73ceea6a Convert atomic-rsync to python.
      from  39c3ae0e Convert munge-symlinks to python.

https://git.samba.org/?p=rsync.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 73ceea6ad2af00f251a5e79a0a258f9fee97d531
Author: Wayne Davison <wayne at opencoder.net>
Date:   Mon Dec 20 17:28:18 2021 -0800

    Convert atomic-rsync to python.

-----------------------------------------------------------------------

Summary of changes:
 support/atomic-rsync | 179 ++++++++++++++++++++++++++-------------------------
 1 file changed, 91 insertions(+), 88 deletions(-)


Changeset truncated at 500 lines:

diff --git a/support/atomic-rsync b/support/atomic-rsync
index 0346fb49..37363e43 100755
--- a/support/atomic-rsync
+++ b/support/atomic-rsync
@@ -1,92 +1,83 @@
-#!/usr/bin/env perl
-#
+#!/usr/bin/env python3
 # This script lets you update a hierarchy of files in an atomic way by
 # first creating a new hierarchy using rsync's --link-dest option, and
 # then swapping the hierarchy into place.  **See the usage message for
 # more details and some important caveats!**
 
-use strict;
-use warnings;
-use Cwd 'abs_path';
-
-my $RSYNC_PROG = '/usr/bin/rsync';
-my $RM_PROG = '/bin/rm';
-
-my $dest_dir = $ARGV[-1];
-&usage if !defined $dest_dir || $dest_dir =~ /(^-|^$)/ || grep(/^--help/, @ARGV);
-$dest_dir =~ s{(?<=.)/+$} {};
-
-if (!-d $dest_dir) {
-    die "$dest_dir is not a directory.\nUse --help for help.\n";
-}
-
-if (@_ = grep(/^--[a-z]+-dest\b/, @ARGV)) {
-    $_ = join(' or ', @_);
-    die "You cannot use the $_ option with atomic-rsync.\nUse --help for help.\n";
-}
-
-my $symlink_content = readlink $dest_dir; # undef when a real dir
-
-my $dest_arg = $dest_dir;
-# This gives us the real destination dir, with all symlinks dereferenced.
-$dest_dir = abs_path($dest_dir);
-if ($dest_dir eq '/') {
-    die qq|You must not use "/" as the destination directory.\nUse --help for help.\n|;
-}
-
-my($old_dir, $new_dir);
-if (defined $symlink_content && $dest_dir =~ /-([12])$/) {
-    my $num = 3 - $1;
-    $old_dir = undef;
-    ($new_dir = $dest_dir) =~ s/-[12]$/-$num/;
-    $symlink_content =~ s/-[12]$/-$num/;
-} else {
-    $old_dir = "$dest_dir~old~";
-    $new_dir = "$dest_dir~new~";
-}
-
-$ARGV[-1] = "$new_dir/";
-
-system($RM_PROG, '-rf', $old_dir) if defined $old_dir && -d $old_dir;
-system($RM_PROG, '-rf', $new_dir) if -d $new_dir;
-
-if (system($RSYNC_PROG, "--link-dest=$dest_dir", @ARGV)) {
-    if ($? == -1) {
-	print "failed to execute $RSYNC_PROG: $!\n";
-    } elsif ($? & 127) {
-	printf "child died with signal %d, %s coredump\n",
-	    ($? & 127),  ($? & 128) ? 'with' : 'without';
-    } else {
-	printf "child exited with value %d\n", $? >> 8;
-    }
-    exit 1;
-}
-
-if (!defined $old_dir) {
-    atomic_symlink($symlink_content, $dest_arg);
-    exit;
-}
-
-rename($dest_dir, $old_dir) or die "Unable to rename $dest_dir to $old_dir: $!";
-rename($new_dir, $dest_dir) or die "Unable to rename $new_dir to $dest_dir: $!";
-
-exit;
-
-sub atomic_symlink
-{
-    my($target, $link) = @_;
-    my $newlink = "$link~new~";
-
-    unlink($newlink); # Just in case
-    symlink($target, $newlink) or die "Unable to symlink $newlink -> $target: $!\n";
-    rename($newlink, $link) or die "Unable to rename $newlink to $link: $!\n";
-}
-
-
-sub usage
-{
-    die <<EOT;
-Usage: atomic-rsync [RSYNC-OPTIONS] HOST:/SOURCE/DIR/ /DEST/DIR/
+import os, sys, re, subprocess, shutil
+
+ALT_DEST_ARG_RE = re.compile('^--[a-z][^ =]+-dest(=|$)')
+
+RSYNC_PROG = '/usr/bin/rsync'
+
+def main():
+    cmd_args = sys.argv[1:]
+    if '--help' in cmd_args:
+        usage_and_exit()
+
+    if len(cmd_args) < 2:
+        usage_and_exit(True)
+
+    dest_dir = cmd_args[-1].rstrip('/')
+    if dest_dir == '' or dest_dir.startswith('-'):
+        usage_and_exit(True)
+
+    if not os.path.isdir(dest_dir):
+        die(dest_dir, "is not a directory or a symlink to a dir.\nUse --help for help.")
+
+    bad_args = [ arg for arg in cmd_args if ALT_DEST_ARG_RE.match(arg) ]
+    if bad_args:
+        die("You cannot use the", ' or '.join(bad_args), "option with atomic-rsync.\nUse --help for help.")
+
+    symlink_content = os.readlink(dest_dir) if os.path.islink(dest_dir) else None
+
+    dest_arg = dest_dir
+    dest_dir = os.path.realpath(dest_dir) # The real destination dir with all symlinks dereferenced
+    if dest_dir == '/':
+        die('You must not use "/" as the destination directory.\nUse --help for help.')
+
+    old_dir = new_dir = None
+    if symlink_content is not None and dest_dir.endswith(('-1','-2')):
+        if not symlink_content.endswith(dest_dir[-2:]):
+            die("Symlink suffix out of sync with dest_dir name:", symlink_content, 'vs', dest_dir)
+        num = 3 - int(dest_dir[-1]);
+        old_dir = None
+        new_dir = dest_dir[:-1] + str(num)
+        symlink_content = symlink_content[:-1] + str(num)
+    else:
+        old_dir = dest_dir + '~old~'
+        new_dir = dest_dir + '~new~'
+
+    cmd_args[-1] = new_dir + '/'
+
+    if old_dir is not None and os.path.isdir(old_dir):
+        shutil.rmtree(old_dir)
+    if os.path.isdir(new_dir):
+        shutil.rmtree(new_dir)
+
+    subprocess.run([RSYNC_PROG, '--link-dest=' + dest_dir, *cmd_args], check=True)
+
+    if old_dir is None:
+        atomic_symlink(symlink_content, dest_arg)
+        return
+
+    os.rename(dest_dir, old_dir)
+    os.rename(new_dir, dest_dir)
+
+
+def atomic_symlink(target, link):
+    newlink = link + "~new~"
+    try:
+        os.unlink(newlink); # Just in case
+    except OSError:
+        pass
+    os.symlink(target, newlink)
+    os.rename(newlink, link)
+
+
+def usage_and_exit(use_stderr=False):
+    usage_msg = """\
+Usage: atomic-rsync [RSYNC-OPTIONS] [HOST:]/SOURCE/DIR/ /DEST/DIR/
        atomic-rsync [RSYNC-OPTIONS] HOST::MOD/DIR/ /DEST/DIR/
 
 This script lets you update a hierarchy of files in an atomic way by first
@@ -96,7 +87,7 @@ to a local directory, and that directory must already exist.  For example:
 
     mkdir /local/files-1
     ln -s files-1 /local/files
-    atomic-rsync -av host:/remote/files/ /local/files/
+    atomic-rsync -aiv host:/remote/files/ /local/files/
 
 If /local/files is a symlink to a directory that ends in -1 or -2, the
 copy will go to the alternate suffix and the symlink will be changed to
@@ -111,12 +102,24 @@ will be deleted.
 
 In all likelihood, you do NOT want to specify this command:
 
-    atomic-rsync -av host:/remote/files /local/
+    atomic-rsync -aiv host:/remote/files /local/
 
 ... UNLESS you want the entire /local dir to be swapped out!
 
 See the "rsync" command for its list of options.  You may not use the
 --link-dest, --compare-dest, or --copy-dest options (since this script
 uses --link-dest to make the transfer efficient).
-EOT
-}
+"""
+    print(usage_msg, file=sys.stderr if use_stderr else sys.stdout)
+    sys.exit(1 if use_stderr else 0)
+
+
+def die(*args):
+    print(*args, file=sys.stderr)
+    sys.exit(1)
+
+
+if __name__ == '__main__':
+    main()
+
+# vim: sw=4 et


-- 
The rsync repository.



More information about the rsync-cvs mailing list