ssh kitten: A new option :code:--symlink-strategy to control how symlinks are copied to the remote machine

Fixes #5249
This commit is contained in:
Kovid Goyal 2022-07-03 14:03:56 +05:30
parent a94a0f3026
commit a8b756f040
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 28 additions and 4 deletions

View File

@ -62,6 +62,9 @@ Detailed list of changes
- ssh kitten: Allow ssh kitten to work from inside tmux, provided the tmux
session inherits the correct KITTY env vars (:iss:`5227`)
- ssh kitten: A new option :code:`--symlink-strategy` to control how symlinks
are copied to the remote machine (:iss:`5249`)
0.25.2 [2022-06-07]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -39,6 +39,17 @@ A glob pattern. Files with names matching this pattern are excluded from being
transferred. Useful when adding directories. Can
be specified multiple times, if any of the patterns match the file will be
excluded.
--symlink-strategy
default=preserve
choices=preserve,resolve,keep-path
Control what happens if the specified path is a symlink. The default is to preserve
the symlink, re-creating it on the remote machine. Setting this to :code:`resolve`
will cause the symlink to be followed and its target used as the file/directory to copy.
The value of :code:`keep-path` is the same as :code:`resolve` except that the remote
file path is derived from the symlink's path instead of the path of the symlink's target.
Note that this option does not apply to symlinks encountered while recursively copying directories.
'''
@ -100,5 +111,9 @@ def parse_copy_instructions(val: str, current_val: Dict[str, str]) -> Iterable[T
raise CopyCLIError('Specifying a remote location with more than one file is not supported')
home = home_path()
for loc in locations:
arcname = get_arcname(loc, opts.dest, home)
yield str(uuid.uuid4()), CopyInstruction(loc, arcname, tuple(opts.exclude))
if opts.symlink_strategy != 'preserve':
rp = os.path.realpath(loc)
else:
rp = loc
arcname = get_arcname(rp if opts.symlink_strategy == 'resolve' else loc, opts.dest, home)
yield str(uuid.uuid4()), CopyInstruction(rp, arcname, tuple(opts.exclude))

View File

@ -106,9 +106,13 @@ print(' '.join(map(str, buf)))'''), lines=13, cols=77)
touch('d1/d2/x')
touch('d1/d2/w.exclude')
os.symlink('d2/x', f'{local_home}/d1/y')
os.symlink('simple-file', f'{local_home}/s1')
os.symlink('simple-file', f'{local_home}/s2')
conf = '''\
copy simple-file
copy s1
copy --symlink-strategy=keep-name s2
copy --dest=a/sfa simple-file
copy --glob g.*
copy --exclude */w.* d1
@ -124,12 +128,14 @@ copy --exclude */w.* d1
self.assertTrue(os.path.lexists(f'{remote_home}/{tname}/78'))
self.assertTrue(os.path.exists(f'{remote_home}/{tname}/78/xterm-kitty'))
self.assertTrue(os.path.exists(f'{remote_home}/{tname}/x/xterm-kitty'))
for w in ('simple-file', 'a/sfa'):
for w in ('simple-file', 'a/sfa', 's2'):
with open(os.path.join(remote_home, w), 'r') as f:
self.ae(f.read(), simple_data)
self.assertFalse(os.path.islink(f.name))
self.assertTrue(os.path.lexists(f'{remote_home}/d1/y'))
self.assertTrue(os.path.exists(f'{remote_home}/d1/y'))
self.ae(os.readlink(f'{remote_home}/d1/y'), 'd2/x')
self.ae(os.readlink(f'{remote_home}/s1'), 'simple-file')
contents = set(files_in(remote_home))
contents.discard('.zshrc') # added by check_bootstrap()
# depending on platform one of these is a symlink and hence
@ -137,7 +143,7 @@ copy --exclude */w.* d1
contents.discard(f'{tname}/x/xterm-kitty')
contents.discard(f'{tname}/78/xterm-kitty')
self.ae(contents, {
'g.1', 'g.2', f'{tname}/kitty.terminfo', 'simple-file', 'd1/d2/x', 'd1/y', 'a/sfa',
'g.1', 'g.2', f'{tname}/kitty.terminfo', 'simple-file', 'd1/d2/x', 'd1/y', 'a/sfa', 's1', 's2',
'.local/share/kitty-ssh-kitten/kitty/version', '.local/share/kitty-ssh-kitten/kitty/bin/kitty'
})
self.ae(len(glob.glob(f'{remote_home}/{tname}/*/xterm-kitty')), 2)