main.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  1. #!/usr/bin/env python
  2. # License: GPL v3 Copyright: 2018, Kovid Goyal <kovid at kovidgoyal.net>
  3. import sys
  4. from typing import List, Optional
  5. from kitty.conf.types import Definition
  6. from kitty.types import run_once
  7. copy_message = '''\
  8. Copy files and directories from local to remote hosts. The specified files are
  9. assumed to be relative to the HOME directory and copied to the HOME on the
  10. remote. Directories are copied recursively. If absolute paths are used, they are
  11. copied as is.'''
  12. @run_once
  13. def option_text() -> str:
  14. return '''
  15. --glob
  16. type=bool-set
  17. Interpret file arguments as glob patterns. Globbing is based on
  18. standard wildcards with the addition that ``/**/`` matches any number of directories.
  19. See the :link:`detailed syntax <https://github.com/bmatcuk/doublestar#patterns>`.
  20. --dest
  21. The destination on the remote host to copy to. Relative paths are resolved
  22. relative to HOME on the remote host. When this option is not specified, the
  23. local file path is used as the remote destination (with the HOME directory
  24. getting automatically replaced by the remote HOME). Note that environment
  25. variables and ~ are not expanded.
  26. --exclude
  27. type=list
  28. A glob pattern. Files with names matching this pattern are excluded from being
  29. transferred. Only used when copying directories. Can
  30. be specified multiple times, if any of the patterns match the file will be
  31. excluded. If the pattern includes a :code:`/` then it will match against the full
  32. path, not just the filename. In such patterns you can use :code:`/**/` to match zero
  33. or more directories. For example, to exclude a directory and everything under it use
  34. :code:`**/directory_name`.
  35. See the :link:`detailed syntax <https://github.com/bmatcuk/doublestar#patterns>` for
  36. how wildcards match.
  37. --symlink-strategy
  38. default=preserve
  39. choices=preserve,resolve,keep-path
  40. Control what happens if the specified path is a symlink. The default is to preserve
  41. the symlink, re-creating it on the remote machine. Setting this to :code:`resolve`
  42. will cause the symlink to be followed and its target used as the file/directory to copy.
  43. The value of :code:`keep-path` is the same as :code:`resolve` except that the remote
  44. file path is derived from the symlink's path instead of the path of the symlink's target.
  45. Note that this option does not apply to symlinks encountered while recursively copying directories,
  46. those are always preserved.
  47. '''
  48. definition = Definition(
  49. '!kittens.ssh',
  50. )
  51. agr = definition.add_group
  52. egr = definition.end_group
  53. opt = definition.add_option
  54. agr('bootstrap', 'Host bootstrap configuration') # {{{
  55. opt('hostname', '*', long_text='''
  56. The hostname that the following options apply to. A glob pattern to match
  57. multiple hosts can be used. Multiple hostnames can also be specified, separated
  58. by spaces. The hostname can include an optional username in the form
  59. :code:`user@host`. When not specified options apply to all hosts, until the
  60. first hostname specification is found. Note that matching of hostname is done
  61. against the name you specify on the command line to connect to the remote host.
  62. If you wish to include the same basic configuration for many different hosts,
  63. you can do so with the :ref:`include <include>` directive. In version 0.28.0
  64. the behavior of this option was changed slightly, now, when a hostname is encountered
  65. all its config values are set to defaults instead of being inherited from a previous
  66. matching hostname block. In particular it means hostnames dont inherit configurations,
  67. thereby avoiding hard to understand action-at-a-distance.
  68. ''')
  69. opt('interpreter', 'sh', long_text='''
  70. The interpreter to use on the remote host. Must be either a POSIX complaint
  71. shell or a :program:`python` executable. If the default :program:`sh` is not
  72. available or broken, using an alternate interpreter can be useful.
  73. ''')
  74. opt('remote_dir', '.local/share/kitty-ssh-kitten', long_text='''
  75. The location on the remote host where the files needed for this kitten are
  76. installed. Relative paths are resolved with respect to :code:`$HOME`.
  77. ''')
  78. opt('+copy', '', add_to_default=False, ctype='CopyInstruction', long_text=f'''
  79. {copy_message} For example::
  80. copy .vimrc .zshrc .config/some-dir
  81. Use :code:`--dest` to copy a file to some other destination on the remote host::
  82. copy --dest some-other-name some-file
  83. Glob patterns can be specified to copy multiple files, with :code:`--glob`::
  84. copy --glob images/*.png
  85. Files can be excluded when copying with :code:`--exclude`::
  86. copy --glob --exclude *.jpg --exclude *.bmp images/*
  87. Files whose remote name matches the exclude pattern will not be copied.
  88. For more details, see :ref:`ssh_copy_command`.
  89. ''')
  90. egr() # }}}
  91. agr('shell', 'Login shell environment') # {{{
  92. opt('shell_integration', 'inherited', long_text='''
  93. Control the shell integration on the remote host. See :ref:`shell_integration`
  94. for details on how this setting works. The special value :code:`inherited` means
  95. use the setting from :file:`kitty.conf`. This setting is useful for overriding
  96. integration on a per-host basis.
  97. ''')
  98. opt('login_shell', '', long_text='''
  99. The login shell to execute on the remote host. By default, the remote user
  100. account's login shell is used.
  101. ''')
  102. opt('+env', '', add_to_default=False, ctype='EnvInstruction', long_text='''
  103. Specify the environment variables to be set on the remote host. Using the
  104. name with an equal sign (e.g. :code:`env VAR=`) will set it to the empty string.
  105. Specifying only the name (e.g. :code:`env VAR`) will remove the variable from
  106. the remote shell environment. The special value :code:`_kitty_copy_env_var_`
  107. will cause the value of the variable to be copied from the local environment.
  108. The definitions are processed alphabetically. Note that environment variables
  109. are expanded recursively, for example::
  110. env VAR1=a
  111. env VAR2=${HOME}/${VAR1}/b
  112. The value of :code:`VAR2` will be :code:`<path to home directory>/a/b`.
  113. ''')
  114. opt('cwd', '', long_text='''
  115. The working directory on the remote host to change to. Environment variables in
  116. this value are expanded. The default is empty so no changing is done, which
  117. usually means the HOME directory is used.
  118. ''')
  119. opt('color_scheme', '', long_text='''
  120. Specify a color scheme to use when connecting to the remote host. If this option
  121. ends with :code:`.conf`, it is assumed to be the name of a config file to load
  122. from the kitty config directory, otherwise it is assumed to be the name of a
  123. color theme to load via the :doc:`themes kitten </kittens/themes>`. Note that
  124. only colors applying to the text/background are changed, other config settings
  125. in the .conf files/themes are ignored.
  126. ''')
  127. opt('remote_kitty', 'if-needed', choices=('if-needed', 'no', 'yes'), long_text='''
  128. Make :program:`kitten` available on the remote host. Useful to run kittens such
  129. as the :doc:`icat kitten </kittens/icat>` to display images or the
  130. :doc:`transfer file kitten </kittens/transfer>` to transfer files. Only works if
  131. the remote host has an architecture for which :link:`pre-compiled kitten binaries
  132. <https://github.com/kovidgoyal/kitty/releases>` are available. Note that kitten
  133. is not actually copied to the remote host, instead a small bootstrap script is
  134. copied which will download and run kitten when kitten is first executed on the
  135. remote host. A value of :code:`if-needed` means kitten is installed only if not
  136. already present in the system-wide PATH. A value of :code:`yes` means that kitten
  137. is installed even if already present, and the installed kitten takes precedence.
  138. Finally, :code:`no` means no kitten is installed on the remote host. The
  139. installed kitten can be updated by running: :code:`kitten update-self` on the
  140. remote host.
  141. ''')
  142. egr() # }}}
  143. agr('ssh', 'SSH configuration') # {{{
  144. opt('share_connections', 'yes', option_type='to_bool', long_text='''
  145. Within a single kitty instance, all connections to a particular server can be
  146. shared. This reduces startup latency for subsequent connections and means that
  147. you have to enter the password only once. Under the hood, it uses SSH
  148. ControlMasters and these are automatically cleaned up by kitty when it quits.
  149. You can map a shortcut to :ac:`close_shared_ssh_connections` to disconnect all
  150. active shared connections.
  151. ''')
  152. opt('askpass', 'unless-set', choices=('unless-set', 'ssh', 'native'), long_text='''
  153. Control the program SSH uses to ask for passwords or confirmation of host keys
  154. etc. The default is to use kitty's native :program:`askpass`, unless the
  155. :envvar:`SSH_ASKPASS` environment variable is set. Set this option to
  156. :code:`ssh` to not interfere with the normal ssh askpass mechanism at all, which
  157. typically means that ssh will prompt at the terminal. Set it to :code:`native`
  158. to always use kitty's native, built-in askpass implementation. Note that not
  159. using the kitty askpass implementation means that SSH might need to use the
  160. terminal before the connection is established, so the kitten cannot use the
  161. terminal to send data without an extra roundtrip, adding to initial connection
  162. latency.
  163. ''')
  164. opt('delegate', '', long_text='''
  165. Do not use the SSH kitten for this host. Instead run the command specified as the delegate.
  166. For example using :code:`delegate ssh` will run the ssh command with all arguments passed
  167. to the kitten, except kitten specific ones. This is useful if some hosts are not capable
  168. of supporting the ssh kitten.
  169. ''')
  170. opt('forward_remote_control', 'no', option_type='to_bool', long_text='''
  171. Forward the kitty remote control socket to the remote host. This allows using the kitty
  172. remote control facilities from the remote host. WARNING: This allows any software
  173. on the remote host full access to the local computer, so only do it for trusted remote hosts.
  174. Note that this does not work with abstract UNIX sockets such as :file:`@mykitty` because of SSH limitations.
  175. This option uses SSH socket forwarding to forward the socket pointed to by the :envvar:`KITTY_LISTEN_ON`
  176. environment variable.
  177. ''')
  178. egr() # }}}
  179. def main(args: List[str]) -> Optional[str]:
  180. raise SystemExit('This should be run as kitten ssh')
  181. if __name__ == '__main__':
  182. main([])
  183. elif __name__ == '__wrapper_of__':
  184. cd = getattr(sys, 'cli_docs')
  185. cd['wrapper_of'] = 'ssh'
  186. elif __name__ == '__conf__':
  187. setattr(sys, 'options_definition', definition)
  188. elif __name__ == '__extra_cli_parsers__':
  189. setattr(sys, 'extra_cli_parsers', {'copy': option_text()})