Work on parsing copy instructions

This commit is contained in:
Kovid Goyal 2022-02-27 22:54:50 +05:30
parent 77c9affc00
commit fadae42715
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
4 changed files with 77 additions and 8 deletions

View File

@ -2,5 +2,70 @@
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
class CopyInstruction:
import glob
import os
import shlex
from typing import Iterable, Iterator, List, Optional, Sequence, Tuple
from kitty.cli import parse_args
from kitty.cli_stub import CopyCLIOptions
from kitty.types import run_once
@run_once
def option_text() -> str:
return '''
--glob
type=bool-set
Interpret file arguments as glob patterns.
--dest
The destination on the remote computer to copy to. Relative paths are resolved
relative to HOME on the remote machine. When this option is not specified, the
local file path is used as the remote destination (with the HOME directory
getting automatically replaced by the remote HOME). Note that enviroment
variables and ~ are not expanded.
'''
def parse_copy_args(args: Optional[Sequence[str]] = None) -> Tuple[CopyCLIOptions, List[str]]:
args = list(args or ())
try:
opts, args = parse_args(result_class=CopyCLIOptions, args=args, ospec=option_text)
except SystemExit as e:
raise CopyCLIError from e
return opts, args
def resolve_file_spec(spec: str, is_glob: bool) -> Iterator[str]:
ans = os.path.expandvars(os.path.expanduser(spec))
if not os.path.isabs(ans):
ans = os.path.expanduser(f'~/{ans}')
if is_glob:
files = glob.glob(ans)
if not files:
raise CopyCLIError(f'{spec} does not exist')
else:
if not os.path.exists(ans):
raise CopyCLIError(f'{spec} does not exist')
files = [ans]
for x in files:
yield os.path.normpath(x).replace(os.sep, '/')
class CopyCLIError(ValueError):
pass
def parse_copy_instructions(val: str) -> Iterable[Tuple[str, CopyCLIOptions]]:
opts, args = parse_copy_args(shlex.split(val))
locations: List[str] = []
for a in args:
locations.extend(resolve_file_spec(a, opts.glob))
if not locations:
raise CopyCLIError('No files to copy specified')
if len(locations) > 1 and opts.dest:
raise CopyCLIError('Specifying a remote location with more than one file is not supported')
for loc in locations:
yield loc, opts

View File

@ -1,7 +1,7 @@
# generated by gen-config.py DO NOT edit
import typing
import kittens.ssh.copy
import kitty.cli_stub
option_names = ( # {{{
@ -12,7 +12,7 @@ class Options:
hostname: str = '*'
remote_dir: str = '.local/share/kitty-ssh-kitten'
shell_integration: str = 'inherit'
copy: typing.Dict[str, kittens.ssh.copy.CopyInstruction] = {}
copy: typing.Dict[str, kitty.cli_stub.CLIOptions] = {}
env: typing.Dict[str, str] = {}
config_paths: typing.Tuple[str, ...] = ()
config_overrides: typing.Tuple[str, ...] = ()

View File

@ -1,11 +1,12 @@
#!/usr/bin/env python
# License: GPLv3 Copyright: 2022, Kovid Goyal <kovid at kovidgoyal.net>
from typing import Any, Dict, Optional, Iterable, Tuple
import posixpath
from typing import Any, Dict, Iterable, Optional, Tuple
from ..copy import CopyInstruction
from kitty.cli_stub import CopyCLIOptions
from ..copy import parse_copy_instructions
DELETE_ENV_VAR = '_delete_this_env_var_'
@ -32,8 +33,8 @@ def env(val: str, current_val: Dict[str, str]) -> Iterable[Tuple[str, str]]:
yield val, DELETE_ENV_VAR
def copy(val: str, current_val: Dict[str, str]) -> Iterable[Tuple[str, CopyInstruction]]:
pass
def copy(val: str, current_val: Dict[str, str]) -> Iterable[Tuple[str, CopyCLIOptions]]:
yield from parse_copy_instructions(val)
def init_results_dict(ans: Dict[str, Any]) -> Dict[str, Any]:

View File

@ -13,7 +13,7 @@ LaunchCLIOptions = AskCLIOptions = ClipboardCLIOptions = DiffCLIOptions = CLIOpt
HintsCLIOptions = IcatCLIOptions = PanelCLIOptions = ResizeCLIOptions = CLIOptions
ErrorCLIOptions = UnicodeCLIOptions = RCOptions = RemoteFileCLIOptions = CLIOptions
QueryTerminalCLIOptions = BroadcastCLIOptions = ShowKeyCLIOptions = CLIOptions
ThemesCLIOptions = TransferCLIOptions = CLIOptions
ThemesCLIOptions = TransferCLIOptions = CopyCLIOptions = CLIOptions
def generate_stub() -> None:
@ -78,6 +78,9 @@ def generate_stub() -> None:
from kittens.transfer.main import option_text as OPTIONS
do(OPTIONS(), 'TransferCLIOptions')
from kittens.ssh.copy import option_text as OPTIONS
do(OPTIONS(), 'CopyCLIOptions')
from kitty.rc.base import all_command_names, command_for_name
for cmd_name in all_command_names():
cmd = command_for_name(cmd_name)