mirror of
https://github.com/xxh/xxh
synced 2024-11-27 14:11:05 +00:00
commit
d5d7954444
5 changed files with 266 additions and 128 deletions
69
README.md
69
README.md
|
@ -21,41 +21,57 @@ pip install xonssh-xxh
|
||||||
```
|
```
|
||||||
Then try:
|
Then try:
|
||||||
```
|
```
|
||||||
xxh <hostname or servername from ~/.ssh/config>
|
xxh <[user@]host[:port] or servername from ~/.ssh/config>
|
||||||
```
|
```
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
```
|
```
|
||||||
$ ./xxh --help
|
$ xxh --help
|
||||||
usage: xxh [-h] [-i] [-if] [-lxh LOCAL_XXH_HOME] [-rxh REMOTE_XXH_HOME]
|
usage: xxh [user@]host[:port]
|
||||||
[-m METHOD] [-V]
|
|
||||||
|
usage: xxh [ssh arguments] destination [xxh arguments]
|
||||||
|
|
||||||
|
usage: xxh [-h] [-V] [-p SSH_PORT] [-l SSH_LOGIN_NAME] [-i SSH_IDENTITY_FILE]
|
||||||
|
[-o SSH_OPTIONS] [+i] [+if] [+lxh LOCAL_XXH_HOME]
|
||||||
|
[+hxh HOST_XXH_HOME] [+m METHOD] [+v] [+vv]
|
||||||
[destination]
|
[destination]
|
||||||
|
|
||||||
The xxh is for using the xonsh shell wherever you go through the ssh.
|
The xxh is for using the xonsh shell wherever you go through the ssh.
|
||||||
|
|
||||||
____ _________ @ @
|
___ __________ @ @
|
||||||
______ / \ \__/
|
_____ / \ \__/
|
||||||
____ / ____ \ / \ contribution
|
___ / ______ \ / \ contribution
|
||||||
_____ / / \ \ / _/ https://github.com/xonssh/xxh
|
____ / / __ \ \ / _/ https://github.com/xonssh/xxh
|
||||||
___ ( \ \_/ ) /
|
__ ( / / / \ \ /
|
||||||
\ \_____/ / / plugins
|
\ \___/ / / / plugins
|
||||||
___\___________/ / https://github.com/search?q=xxh-plugin
|
___\ /__/ / https://github.com/search?q=xxh-plugin
|
||||||
/__________________/
|
/ \________/ /
|
||||||
|
/___________________/
|
||||||
|
|
||||||
positional arguments:
|
required arguments:
|
||||||
destination Destination may be specified as hostname or server name from ~/.ssh/config
|
destination Destination may be specified as [user@]hostname[:port] or server name from ~/.ssh/config
|
||||||
|
|
||||||
optional arguments:
|
common arguments:
|
||||||
-h, --help show this help message and exit
|
-h, --help show this help message and exit
|
||||||
-i, --install Install xxh to distanation host
|
|
||||||
-if, --install-force Delete remote xxh home and install xonsh to distanation host
|
|
||||||
-lxh LOCAL_XXH_HOME, --local-xxh-home LOCAL_XXH_HOME
|
|
||||||
Local xxh home path. Default: ~/.xxh
|
|
||||||
-rxh REMOTE_XXH_HOME, --remote-xxh-home REMOTE_XXH_HOME
|
|
||||||
Remote xxh home path. Default: ~/.xxh
|
|
||||||
-m METHOD, --method METHOD
|
|
||||||
Installation method. Currently supported only 'appimage' method
|
|
||||||
-V, --version Show xxh version
|
-V, --version Show xxh version
|
||||||
|
|
||||||
|
ssh arguments:
|
||||||
|
-p SSH_PORT Port to connect to on the remote host.
|
||||||
|
-l SSH_LOGIN_NAME Specifies the user to log in as on the remote machine.
|
||||||
|
-i SSH_IDENTITY_FILE Selects a file from which the identity (private key) for public key authentication is read.
|
||||||
|
-o SSH_OPTIONS Options in the ssh configuration format. See ssh man page. Example: xxh -o Port=22 -o User=snail host
|
||||||
|
|
||||||
|
xxh arguments:
|
||||||
|
+i, ++install Install xxh to destination host.
|
||||||
|
+if, ++install-force Delete remote xxh home and install xonsh to destination host.
|
||||||
|
+lxh LOCAL_XXH_HOME, ++local-xxh-home LOCAL_XXH_HOME
|
||||||
|
Local xxh home path. Default: ~/.xxh
|
||||||
|
+hxh HOST_XXH_HOME, ++host-xxh-home HOST_XXH_HOME
|
||||||
|
Host xxh home path. Default: ~/.xxh
|
||||||
|
+m METHOD, ++method METHOD
|
||||||
|
Portable method: appimage
|
||||||
|
+v, ++verbose Verbose mode.
|
||||||
|
+vv, ++vverbose Super verbose mode.
|
||||||
```
|
```
|
||||||
|
|
||||||
## Plugins
|
## Plugins
|
||||||
|
@ -84,6 +100,13 @@ When you run `xxh <server>` command:
|
||||||
|
|
||||||
3. Finally xxh makes ssh connection to server and running remote portable xonsh shell without any affection on the target system.
|
3. Finally xxh makes ssh connection to server and running remote portable xonsh shell without any affection on the target system.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
Use [xxh-tests](https://github.com/xonssh/xxh-tests) environment for development and contribution.
|
||||||
|
|
||||||
|
What will make xxh more universal and stable in the future:
|
||||||
|
* [AppImages run on Alpine](https://github.com/AppImage/AppImageKit/issues/1015)
|
||||||
|
* [Fix xonsh for WSL1](https://github.com/xonsh/xonsh/issues/3367)
|
||||||
|
|
||||||
## Known Issues
|
## Known Issues
|
||||||
|
|
||||||
### GLIBs versions
|
### GLIBs versions
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -10,7 +10,7 @@ setuptools.setup(
|
||||||
install_requires=['xonsh'],
|
install_requires=['xonsh'],
|
||||||
platforms='Unix-like',
|
platforms='Unix-like',
|
||||||
scripts=['xxh'],
|
scripts=['xxh'],
|
||||||
package_data={'xonssh_xxh':['*.xsh']},
|
package_data={'xonssh_xxh':['*.xsh', '*.sh']},
|
||||||
packages=setuptools.find_packages(),
|
packages=setuptools.find_packages(),
|
||||||
classifiers=["Programming Language :: Python :: 3"],
|
classifiers=["Programming Language :: Python :: 3"],
|
||||||
license="BSD",
|
license="BSD",
|
||||||
|
|
17
xonssh_xxh/host_info.sh
Normal file
17
xonssh_xxh/host_info.sh
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
xxh_home_realpath=`realpath _xxh_home_`
|
||||||
|
mkdir -p $xxh_home_realpath
|
||||||
|
|
||||||
|
settings_path=$xxh_home_realpath/settings.py
|
||||||
|
xxh_version=`[ "$(ls -A $xxh_home_realpath)" ] && echo "0" || echo "-1"`
|
||||||
|
if [[ -f $settings_path ]]; then
|
||||||
|
xxh_version=`cat $settings_path | grep XXH_VERSION | sed -e "s/.*: '\(.*\)'/\\1/g"`
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo xxh_home_realpath=$xxh_home_realpath
|
||||||
|
echo xxh_version=$xxh_version
|
||||||
|
echo bash=`command -v bash`
|
||||||
|
echo rsync=`command -v rsync`
|
||||||
|
echo scp=`command -v scp`
|
||||||
|
echo xxh_home_freespace=`df -k --output=avail $xxh_home_realpath | tail -n1`
|
|
@ -1,10 +1,15 @@
|
||||||
import sys
|
import sys, os
|
||||||
|
|
||||||
global_settings = {
|
global_settings = {
|
||||||
'XXH_VERSION': '0.1'
|
'XXH_VERSION': '0.2.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
||||||
|
for e in ['XXH_HOME', 'PIP_TARGET', 'PYTHONPATH']:
|
||||||
|
if e in os.environ:
|
||||||
|
global_settings[e] = os.environ[e]
|
||||||
|
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
setting_name = sys.argv[1]
|
setting_name = sys.argv[1]
|
||||||
if setting_name in global_settings:
|
if setting_name in global_settings:
|
||||||
|
|
297
xxh
297
xxh
|
@ -1,9 +1,11 @@
|
||||||
#!/usr/bin/env xonsh
|
#!/usr/bin/env xonsh
|
||||||
|
|
||||||
import os, sys, glob, argparse
|
import os, sys, glob, argparse, datetime, re
|
||||||
|
from shutil import which
|
||||||
|
from sys import exit
|
||||||
from argparse import RawTextHelpFormatter
|
from argparse import RawTextHelpFormatter
|
||||||
|
from urllib.parse import urlparse
|
||||||
from random import randint
|
from random import randint
|
||||||
import datetime
|
|
||||||
|
|
||||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||||
import xonssh_xxh
|
import xonssh_xxh
|
||||||
|
@ -12,13 +14,16 @@ from xonssh_xxh.settings import global_settings
|
||||||
url_xxh_github = 'https://github.com/xonssh/xxh'
|
url_xxh_github = 'https://github.com/xonssh/xxh'
|
||||||
url_xxh_plugins_search = 'https://github.com/search?q=xxh-plugin'
|
url_xxh_plugins_search = 'https://github.com/search?q=xxh-plugin'
|
||||||
url_appimage = 'https://github.com/niess/linuxdeploy-plugin-python/releases/download/continuous/xonsh-x86_64.AppImage'
|
url_appimage = 'https://github.com/niess/linuxdeploy-plugin-python/releases/download/continuous/xonsh-x86_64.AppImage'
|
||||||
local_xxh_home_path = '~/.xxh'
|
|
||||||
local_xxh_version = global_settings['XXH_VERSION']
|
local_xxh_version = global_settings['XXH_VERSION']
|
||||||
remote_xxh_home_path = '~/.xxh'
|
local_xxh_home_path = '~/.xxh'
|
||||||
|
host_xxh_home_path = '~/.xxh'
|
||||||
|
portable_methods = ['appimage']
|
||||||
|
portable_methods_str = ', '.join(portable_methods)
|
||||||
|
xonsh_bin_name = 'xonsh'
|
||||||
|
|
||||||
if os.name == 'nt':
|
if os.name == 'nt':
|
||||||
print(f"Windows is not supported. WSL1 not recommended also. WSL2 is not tested yet.\nTry to contribution: {url_xxh_github}")
|
print(f"Windows is not supported. WSL1 not recommended also. WSL2 is not tested yet.\nTry to contribution: {url_xxh_github}")
|
||||||
sys.exit(1)
|
exit(1)
|
||||||
|
|
||||||
def xonssh():
|
def xonssh():
|
||||||
try:
|
try:
|
||||||
|
@ -30,42 +35,97 @@ def xonssh():
|
||||||
if terminal_cols < 70:
|
if terminal_cols < 70:
|
||||||
return f"\n\nContribution: {url_xxh_github}\n\nPlugins: {url_xxh_plugins_search}"
|
return f"\n\nContribution: {url_xxh_github}\n\nPlugins: {url_xxh_plugins_search}"
|
||||||
|
|
||||||
# Try: watch -n.2 xxh --help
|
|
||||||
l,r,s,t = (['@','-','_'][randint(0,2)], ['@','-','_'][randint(0,2)], ['_',' '][randint(0,1)], ['_',''][randint(0,1)])
|
l,r,s,t = (['@','-','_'][randint(0,2)], ['@','-','_'][randint(0,2)], ['_',' '][randint(0,1)], ['_',''][randint(0,1)])
|
||||||
return f"""
|
return f"""
|
||||||
|
|
||||||
{s}___ _________ {l} {r}
|
{s}___ __________ {l} {r}
|
||||||
{s}_____ / \\ \\__/
|
{s}_____ / \\ \\__/
|
||||||
{s}___ / ____ \\ / \\ contribution
|
{s}___ / ______ \\ / \\ contribution
|
||||||
{s}____ / / \\ \\ / _/ {url_xxh_github}
|
{s}____ / / __ \\ \\ / _/ {url_xxh_github}
|
||||||
{s}__ ( \\ \\_/ ) /
|
{s}__ ( / / / \\ \\ /
|
||||||
\\ \\_____/ / / plugins
|
\\ \\___/ / / / plugins
|
||||||
{' ' if not t else ''} _{t}_\\___________/ / {url_xxh_plugins_search}
|
{' ' if not t else ''} _{t}__\\ /__/ / {url_xxh_plugins_search}
|
||||||
{' ' if not t else ''} /_{t}________________/
|
{' ' if not t else ''} / {'' if not t else ' '} \\________/ /
|
||||||
|
{' ' if not t else ''} /_{t}__________________/
|
||||||
|
|
||||||
"""
|
""" # watch -n.2 xxh --help
|
||||||
|
|
||||||
argp = argparse.ArgumentParser(description=f"The xxh is for using the xonsh shell wherever you go through the ssh. {xonssh()}", formatter_class=RawTextHelpFormatter)
|
argp = argparse.ArgumentParser(description=f"The xxh is for using the xonsh shell wherever you go through the ssh. {xonssh()}", formatter_class=RawTextHelpFormatter, prefix_chars='-+')
|
||||||
argp.add_argument('destination', nargs='?', help="Destination may be specified as hostname or server name from ~/.ssh/config")
|
|
||||||
argp.add_argument('-i','--install', default=False, action='store_true', help="Install xxh to distanation host")
|
|
||||||
argp.add_argument('-if','--install-force', default=False, action='store_true', help="Delete remote xxh home and install xonsh to distanation host")
|
|
||||||
argp.add_argument('-lxh','--local-xxh-home', default=local_xxh_home_path, help=f"Local xxh home path. Default: {local_xxh_home_path}")
|
|
||||||
argp.add_argument('-rxh','--remote-xxh-home', default=remote_xxh_home_path, help=f"Remote xxh home path. Default: {remote_xxh_home_path}")
|
|
||||||
argp.add_argument('-m','--method', default='appimage', help="Installation method. Currently supported only 'appimage' method")
|
|
||||||
argp.add_argument('-V','--version', default=False, action='store_true', help="Show xxh version")
|
argp.add_argument('-V','--version', default=False, action='store_true', help="Show xxh version")
|
||||||
|
argp.add_argument('-p', dest='ssh_port', help="Port to connect to on the remote host.")
|
||||||
|
argp.add_argument('-l', dest='ssh_login_name', help="Specifies the user to log in as on the remote machine.")
|
||||||
|
argp.add_argument('-i', dest='ssh_identity_file', help="Selects a file from which the identity (private key) for public key authentication is read.")
|
||||||
|
argp.add_argument('-o', dest='ssh_options', action='append', help="Options in the ssh configuration format. See ssh man page. Example: xxh -o Port=22 -o User=snail host")
|
||||||
|
argp.add_argument('destination', nargs='?', help="Destination may be specified as [user@]hostname[:port] or server name from ~/.ssh/config")
|
||||||
|
argp.add_argument('+i','++install', default=False, action='store_true', help="Install xxh to destination host.")
|
||||||
|
argp.add_argument('+if','++install-force', default=False, action='store_true', help="Delete remote xxh home and install xonsh to destination host.")
|
||||||
|
argp.add_argument('+lxh','++local-xxh-home', default=local_xxh_home_path, help=f"Local xxh home path. Default: {local_xxh_home_path}")
|
||||||
|
argp.add_argument('+hxh','++host-xxh-home', default=host_xxh_home_path, help=f"Host xxh home path. Default: {host_xxh_home_path}")
|
||||||
|
argp.add_argument('+m','++method', default='appimage', help=f"Portable method: {portable_methods_str}")
|
||||||
|
argp.add_argument('+v','++verbose', default=False, action='store_true', help="Verbose mode.")
|
||||||
|
argp.add_argument('+vv','++vverbose', default=False, action='store_true', help="Super verbose mode.")
|
||||||
|
argp.usage = f'xxh [user@]host[:port]\n\nusage: xxh [ssh arguments] destination [xxh arguments]\n\n{argp.format_usage()}'
|
||||||
|
help = argp.format_help().replace('\n +','\n\nxxh arguments:\n +',1).replace('optional ', 'common ')\
|
||||||
|
.replace('xxh version', 'xxh version\n\nssh arguments:').replace('positional ', 'required ')
|
||||||
|
argp.format_help = lambda: help
|
||||||
opt = argp.parse_args()
|
opt = argp.parse_args()
|
||||||
|
|
||||||
|
if opt.vverbose:
|
||||||
|
opt.verbose = True
|
||||||
|
|
||||||
if opt.version:
|
if opt.version:
|
||||||
print(f"xonssh-xxh/{local_xxh_version}")
|
print(f"xonssh-xxh/{local_xxh_version}")
|
||||||
sys.exit(0)
|
exit(0)
|
||||||
|
|
||||||
if not opt.destination:
|
if not opt.destination:
|
||||||
print('Destination required. Try --help')
|
print('Destination required. Try --help')
|
||||||
sys.exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
if opt.method not in portable_methods:
|
||||||
|
print(f'Currently supported methods: {portable_methods_str}')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if 'ssh://' not in opt.destination:
|
||||||
|
opt.destination = f'ssh://{opt.destination}'
|
||||||
|
|
||||||
|
url = urlparse(opt.destination)
|
||||||
|
host = url.hostname
|
||||||
|
|
||||||
|
if not host:
|
||||||
|
print(f"Wrong distination '{host}'")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if url.port:
|
||||||
|
opt.ssh_port = url.port
|
||||||
|
|
||||||
|
if url.username:
|
||||||
|
opt.ssh_login_name = url.username
|
||||||
|
|
||||||
|
ssh_arguments = []
|
||||||
|
if not opt.verbose:
|
||||||
|
ssh_arguments = ['-o', 'LogLevel=QUIET']
|
||||||
|
if opt.ssh_port:
|
||||||
|
ssh_arguments += ['-o', f'Port={opt.ssh_port}']
|
||||||
|
if opt.ssh_identity_file:
|
||||||
|
ssh_arguments += ['-o', f'IdentityFile={opt.ssh_identity_file}']
|
||||||
|
if opt.ssh_login_name:
|
||||||
|
ssh_arguments += ['-o', f'User={opt.ssh_login_name}']
|
||||||
|
if opt.ssh_options:
|
||||||
|
for ssh_option in opt.ssh_options:
|
||||||
|
ssh_arguments += ['-o', ssh_option]
|
||||||
|
|
||||||
|
if opt.verbose:
|
||||||
|
print(f'ssh arguments: {ssh_arguments}')
|
||||||
|
|
||||||
|
if not which('ssh'):
|
||||||
|
print('Install OpenSSH client before using xxh: https://duckduckgo.com/?q=how+to+install+openssh+client+in+linux')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
dst = opt.destination
|
|
||||||
opt.install = True if opt.install_force else opt.install
|
opt.install = True if opt.install_force else opt.install
|
||||||
|
|
||||||
|
ssh_v = ['-v'] if opt.vverbose else []
|
||||||
|
|
||||||
local_xxh_home_path = os.path.expanduser(opt.local_xxh_home)
|
local_xxh_home_path = os.path.expanduser(opt.local_xxh_home)
|
||||||
local_xxh_home_parent = os.path.dirname(os.path.expanduser(local_xxh_home_path))
|
local_xxh_home_parent = os.path.dirname(os.path.expanduser(local_xxh_home_path))
|
||||||
package_dir_path = os.path.dirname(os.path.realpath(xonssh_xxh.__file__))
|
package_dir_path = os.path.dirname(os.path.realpath(xonssh_xxh.__file__))
|
||||||
|
@ -73,85 +133,80 @@ package_dir_path = os.path.dirname(os.path.realpath(xonssh_xxh.__file__))
|
||||||
if os.path.exists(local_xxh_home_path):
|
if os.path.exists(local_xxh_home_path):
|
||||||
if not os.access(local_xxh_home_path, os.W_OK):
|
if not os.access(local_xxh_home_path, os.W_OK):
|
||||||
print(f"The local xxh home path isn't writable: {local_xxh_home_path}" )
|
print(f"The local xxh home path isn't writable: {local_xxh_home_path}" )
|
||||||
sys.exit(1)
|
exit(1)
|
||||||
elif os.path.exists(local_xxh_home_parent):
|
elif os.path.exists(local_xxh_home_parent):
|
||||||
if os.access(local_xxh_home_parent, os.W_OK):
|
if os.access(local_xxh_home_parent, os.W_OK):
|
||||||
print(f'Create xxh home path: {local_xxh_home_path}')
|
print(f'Create local xxh home path: {local_xxh_home_path}')
|
||||||
mkdir -p @(local_xxh_home_path) @(local_xxh_home_path)/plugins
|
mkdir @(ssh_v) -p @(local_xxh_home_path) @(local_xxh_home_path)/plugins
|
||||||
else:
|
else:
|
||||||
print(f"Parent for local xxh home path isn't writable: {local_xxh_home_parent}")
|
print(f"Parent for local xxh home path isn't writable: {local_xxh_home_parent}")
|
||||||
sys.exit(1)
|
exit(1)
|
||||||
else:
|
else:
|
||||||
print(f"Paths aren't writable:\n {local_xxh_home_parent}\n {local_xxh_home_path}")
|
print(f"Paths aren't writable:\n {local_xxh_home_parent}\n {local_xxh_home_path}")
|
||||||
sys.exit(1)
|
exit(1)
|
||||||
|
|
||||||
# Fix env to avoid ssh warnings
|
# Fix env to avoid ssh warnings
|
||||||
for lc in ['LC_TIME','LC_MONETARY','LC_ADDRESS','LC_IDENTIFICATION','LC_MEASUREMENT','LC_NAME','LC_NUMERIC','LC_PAPER','LC_TELEPHONE']:
|
for lc in ['LC_TIME','LC_MONETARY','LC_ADDRESS','LC_IDENTIFICATION','LC_MEASUREMENT','LC_NAME','LC_NUMERIC','LC_PAPER','LC_TELEPHONE']:
|
||||||
${...}[lc] = "en_US.UTF-8"
|
${...}[lc] = "POSIX"
|
||||||
|
|
||||||
if opt.remote_xxh_home == '~/.xxh':
|
if os.path.abspath(opt.host_xxh_home) == '/':
|
||||||
dst_user_home = $(ssh @(dst) -T "bash -c 'cd ~ && pwd'").strip()
|
print("Host xxh home path {host_xxh_home} looks like /. Please check twice!")
|
||||||
|
|
||||||
if dst_user_home == '':
|
|
||||||
# https://github.com/xonsh/xonsh/issues/3367
|
|
||||||
print('Unknown answer from host when checking user home path')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
dst_xxh_home = os.path.join(dst_user_home, '.xxh')
|
|
||||||
else:
|
|
||||||
dst_xxh_home = opt.remote_xxh_home_path
|
|
||||||
|
|
||||||
dst_xxh_home_abspath = os.path.abspath(dst_xxh_home)
|
|
||||||
if dst_xxh_home_abspath == '/':
|
|
||||||
print("Remote xxh home path {dst_xxh_home} looks like / and is not supported ;)")
|
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
xonsh_bin = 'xonsh'
|
host_info = $(cat @(f"{package_dir_path}/host_info.sh") | sed @(f's|_xxh_home_|{opt.host_xxh_home}|') | ssh @(ssh_v) @(ssh_arguments) @(host) -T "bash -s" ).strip()
|
||||||
dst_xonsh_bin = os.path.join(dst_xxh_home, xonsh_bin)
|
|
||||||
dst_xonshrc = os.path.join( dst_xxh_home, 'xonshrc.xsh')
|
|
||||||
dst_xonsh_plugins_rc = os.path.join( dst_xxh_home, 'xxh_plugins_rc.xsh')
|
|
||||||
|
|
||||||
dst_has_xxh = $(echo @(f"[[ -d {dst_xxh_home} ]] && echo -n 1 || echo -n 0") | ssh @(dst) -T "bash -s")
|
if host_info == '':
|
||||||
|
print(f'Unknown answer from host when checking user home path. Check your connection parameters using ordinary ssh')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
if dst_has_xxh not in ['0','1']:
|
host_info = dict([l.split('=') for l in host_info.split('\n')])
|
||||||
# https://github.com/xonsh/xonsh/issues/3367
|
|
||||||
print(f'Unknown answer from host when checking direcotry {dst_xxh_home}: {dst_has_xxh}')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if dst_has_xxh == '1' and opt.install_force == False:
|
if opt.verbose:
|
||||||
|
print(f'host_info: {host_info}')
|
||||||
|
|
||||||
|
if host_info['xxh_home_realpath'] == '':
|
||||||
|
print(f'Unknown answer from host when getting realpath for directory {host_xxh_home}')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if host_info['xxh_version'] == '':
|
||||||
|
print(f'Unknown answer from host when getting version for directory {host_xxh_home}')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
if host_info['scp'] == '' and host_info['rsync'] == '':
|
||||||
|
print(f"There are no rsync or scp on target host. Sad but files can't be uploaded.")
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
host_xxh_home = host_info['xxh_home_realpath']
|
||||||
|
host_xonsh_bin = os.path.join(host_xxh_home, xonsh_bin_name)
|
||||||
|
host_xonshrc = os.path.join(host_xxh_home, 'xonshrc.xsh')
|
||||||
|
host_xonsh_plugins_rc = os.path.join(host_xxh_home, 'xxh_plugins_rc.xsh')
|
||||||
|
|
||||||
|
host_xxh_version = host_info['xxh_version']
|
||||||
|
|
||||||
|
if opt.install_force == False:
|
||||||
# Check version
|
# Check version
|
||||||
try:
|
|
||||||
dst_xxh_settings = os.path.join(dst_xxh_home, 'settings.py')
|
|
||||||
dst_xxh_version = $(ssh -o LogLevel=QUIET @(dst) -t @(dst_xonsh_bin) --no-script-cache @(dst_xxh_settings) XXH_VERSION).strip()
|
|
||||||
except:
|
|
||||||
dst_xxh_version = None
|
|
||||||
|
|
||||||
ask_type = None
|
|
||||||
ask = False
|
ask = False
|
||||||
if dst_xxh_version is None:
|
if host_xxh_version is '0':
|
||||||
ask_type = 1
|
ask = f'Host xxh home is not empty but something went wrong while getting host xxh version.'
|
||||||
ask = f'Something went wrong while getting the remote xxh version.'
|
elif host_xxh_version != '-1' and host_xxh_version != local_xxh_version:
|
||||||
elif dst_xxh_version != local_xxh_version:
|
ask = f"Local xxh version '{local_xxh_version}' is not equal host xxh version '{host_xxh_version}'."
|
||||||
ask_type = 2
|
|
||||||
ask = f"Local xxh version '{local_xxh_version}' is not equal remote xxh version '{dst_xxh_version}'."
|
|
||||||
|
|
||||||
if ask:
|
if ask:
|
||||||
choice = input(f"{ask} What's next? \n"
|
choice = input(f"{ask} What's next? \n"
|
||||||
+ f"s - [default] Stop here. You'll try to connect via ordinary ssh for backup current xxh home.\n"
|
+ f"s - [default] Stop here. You'll try to connect using ordinary ssh for backup current xxh home.\n"
|
||||||
+ f"u - Safe update. Remote xxh dir will be renamed and local xxh version will be installed.\n"
|
+ f"u - Safe update. Host xxh home will be renamed and local xxh version will be installed.\n"
|
||||||
+ f"f - Force install local xxh version on remote host. Remote xxh installation will be lost.\n"
|
+ f"f - Force install local xxh version on host. Host xxh installation will be lost.\n"
|
||||||
+ f"i - Ignore, cross fingers and continue the connection.\n"
|
+ f"i - Ignore, cross fingers and continue the connection.\n"
|
||||||
+ f"S/u/f/i? ").lower()
|
+ f"S/u/f/i? ").lower()
|
||||||
|
|
||||||
if choice == 's' or choice.strip() == '':
|
if choice == 's' or choice.strip() == '':
|
||||||
print('Stopped')
|
print('Stopped')
|
||||||
sys.exit(0)
|
exit(0)
|
||||||
elif choice == 'u':
|
elif choice == 'u':
|
||||||
local_time = datetime.datetime.now().isoformat()[:19]
|
local_time = datetime.datetime.now().isoformat()[:19]
|
||||||
print(f"Move {dst}:{dst_xxh_home} to {dst}:{dst_xxh_home}-{local_time}")
|
print(f"Move {host}:{host_xxh_home} to {host}:{host_xxh_home}-{local_time}")
|
||||||
echo @(f"mv {dst_xxh_home} {dst_xxh_home}-{local_time}" ) | ssh -o LogLevel=QUIET @(dst) -T "bash -s"
|
echo @(f"mv {host_xxh_home} {host_xxh_home}-{local_time}") | ssh @(ssh_v) @(ssh_arguments) @(host) -T "bash -s"
|
||||||
opt.install = True
|
opt.install = True
|
||||||
dst_has_xxh = '0'
|
|
||||||
elif choice == 'f':
|
elif choice == 'f':
|
||||||
opt.install = True
|
opt.install = True
|
||||||
opt.install_force = True
|
opt.install_force = True
|
||||||
|
@ -159,52 +214,90 @@ if dst_has_xxh == '1' and opt.install_force == False:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
print('Unknown answer')
|
print('Unknown answer')
|
||||||
sys.exit(1)
|
exit(1)
|
||||||
|
|
||||||
|
if host_xxh_version == '-1':
|
||||||
if not opt.install and dst_has_xxh == '0':
|
yn = input(f"{host}:{host_xxh_home} not found. Install xxh? [Y/n] ").strip().lower()
|
||||||
yn = input(f"{dst}:{dst_xxh_home} not found. Install xxh? [y/n] ").lower()
|
if yn == 'y' or yn == '':
|
||||||
if yn == 'y':
|
|
||||||
opt.install = True
|
opt.install = True
|
||||||
else:
|
else:
|
||||||
print('Unknown answer')
|
print('Unknown answer')
|
||||||
sys.exit(1)
|
exit(1)
|
||||||
|
|
||||||
if opt.install:
|
if opt.install:
|
||||||
print("\033[0;33m", end='')
|
print("\033[0;33m", end='')
|
||||||
if opt.method == 'appimage':
|
if opt.method == 'appimage':
|
||||||
appimage_fullpath = os.path.join(local_xxh_home_path, xonsh_bin)
|
local_xonsh_appimage_fullpath = os.path.join(local_xxh_home_path, xonsh_bin_name)
|
||||||
if not os.path.isfile(appimage_fullpath):
|
if not os.path.isfile(local_xonsh_appimage_fullpath):
|
||||||
print(f'First time download and save xonsh AppImage from {url_appimage}')
|
print(f'First time download and save xonsh AppImage from {url_appimage}')
|
||||||
wget -q --show-progress @(url_appimage) -O @(appimage_fullpath)
|
if which('wget'):
|
||||||
chmod +x @(appimage_fullpath)
|
r=![wget -q --show-progress @(url_appimage) -O @(local_xonsh_appimage_fullpath)]
|
||||||
|
if r.returncode != 0:
|
||||||
|
print(f'Error while download appimage using wget: {r}')
|
||||||
|
exit(0)
|
||||||
|
elif which('curl'):
|
||||||
|
r=![curl @(url_appimage) -o @(local_xonsh_appimage_fullpath)]
|
||||||
|
if r.returncode != 0:
|
||||||
|
print(f'Error while download appimage using curl: {r}')
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
print('Please install wget or curl and try again. Howto: https://duckduckgo.com/?q=how+to+install+wget+in+linux')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
chmod +x @(local_xonsh_appimage_fullpath)
|
||||||
else:
|
else:
|
||||||
print(f'Method "{opt.method}" is not supported now')
|
print(f'Method "{opt.method}" is not supported now')
|
||||||
|
|
||||||
if dst_has_xxh == "1":
|
if opt.install_force:
|
||||||
if opt.install_force:
|
print(f'Before upload xxh remove host directory {host}:{host_xxh_home}')
|
||||||
print(f'Before install xxh remove remote directory {dst}:{dst_xxh_home}')
|
echo @(f"rm -rf {host_xxh_home}/*") | ssh @(ssh_v) @(ssh_arguments) @(host) -T "bash -s"
|
||||||
echo @(f"rm -rf {dst_xxh_home}" ) | ssh -o LogLevel=QUIET @(dst) -T "bash -s"
|
|
||||||
else:
|
|
||||||
print(f'Remote directory exists: {dst_xxh_home}')
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
print(f"Install xxh to {dst}:{dst_xxh_home}" )
|
print(f"Install xxh to {host}:{host_xxh_home}" )
|
||||||
rsync -az --info=progress2 --include ".*" @(local_xxh_home_path)/ @(dst):@(dst_xxh_home)/
|
if which('rsync') and host_info['rsync']:
|
||||||
rsync -az --info=progress2 --include ".*" @(package_dir_path)/ @(dst):@(dst_xxh_home)/
|
print('Upload using rsync')
|
||||||
|
rsync @(ssh_v) -e @(f"ssh {'' if ssh_v == [] else '-v'} {' '.join(ssh_arguments)}") -az --info=progress2 --include ".*" --exclude='*.pyc' @(local_xxh_home_path)/ @(host):@(host_xxh_home)/
|
||||||
|
rsync @(ssh_v) -e @(f"ssh {'' if ssh_v == [] else '-v'} {' '.join(ssh_arguments)}") -az --info=progress2 --include ".*" --exclude='*.pyc' @(package_dir_path)/ @(host):@(host_xxh_home)/
|
||||||
|
elif which('scp') and host_info['scp']:
|
||||||
|
print("Upload using scp. Note: install rsync on local and remote host to increase speed.")
|
||||||
|
scp_host = f"{host}:{host_xxh_home}/"
|
||||||
|
scp @(ssh_v) @(ssh_arguments) -r -C @([] if opt.verbose else ['-q']) @(local_xxh_home_path)/* @(scp_host)
|
||||||
|
scp @(ssh_v) @(ssh_arguments) -r -C @([] if opt.verbose else ['-q']) @(package_dir_path)/* @(scp_host)
|
||||||
|
else:
|
||||||
|
print('scp or rsync not found!')
|
||||||
|
|
||||||
plugins_fullpath = os.path.join(local_xxh_home_path, 'plugins')
|
plugins_fullpath = os.path.join(local_xxh_home_path, 'plugins')
|
||||||
if os.path.exists(plugins_fullpath):
|
if os.path.exists(plugins_fullpath):
|
||||||
print(f'Run plugins post install on {dst}')
|
print(f'Run plugins post install on {host}')
|
||||||
scripts=''
|
scripts=''
|
||||||
for script in sorted(glob.glob(os.path.join(plugins_fullpath, os.path.join('*','install.xsh')), recursive=True)):
|
for script in sorted(glob.glob(os.path.join(plugins_fullpath, os.path.join('*','install.xsh')), recursive=True)):
|
||||||
scripts += " && %s -i --rc %s -- %s" % (dst_xonsh_bin, dst_xonshrc, script.replace(local_xxh_home_path + os.sep, ''))
|
scripts += " && %s -i --rc %s -- %s" % (host_xonsh_bin, host_xonshrc, script.replace(local_xxh_home_path + os.sep, ''))
|
||||||
print(f' * {script}')
|
print(f' * {script}')
|
||||||
|
|
||||||
if scripts:
|
if scripts:
|
||||||
echo @(f"cd {dst_xxh_home} {scripts}" ) | ssh -o LogLevel=QUIET @(dst) -T "bash -s"
|
echo @(f"cd {host_xxh_home} {scripts}" ) | ssh @(ssh_v) @(ssh_arguments) @(host) -T "bash -s"
|
||||||
|
|
||||||
print(f'First run xonsh on {dst}\033[0m')
|
print('Check xonsh')
|
||||||
|
host_settings_file = os.path.join(host_xxh_home, 'settings.py')
|
||||||
|
check = $(ssh @(ssh_v) @(ssh_arguments) @(host) -t @(host_xonsh_bin) --no-script-cache -i --rc @(host_xonshrc) -- @(host_settings_file) )
|
||||||
|
|
||||||
dst_plugins_rc = $(ssh -o LogLevel=QUIET @(dst) -t @(dst_xonsh_bin) --no-script-cache -i --rc @(dst_xonshrc) -- @(dst_xonsh_plugins_rc)).split('xxh-plugins#')[1]
|
if opt.verbose:
|
||||||
ssh -o LogLevel=QUIET @(dst) -t @(dst_xonsh_bin) --no-script-cache -i --rc @(dst_xonshrc) @(dst_plugins_rc)
|
print(f'Check xonsh result:\n{check}')
|
||||||
|
|
||||||
|
if check == '' or 'AppImages require FUSE to run' in check:
|
||||||
|
print('Check failed. Unpack AppImage...')
|
||||||
|
host_xonsh_bin_new = os.path.join(host_xxh_home, 'xonsh-squashfs/usr/python/bin/xonsh')
|
||||||
|
ssh @(ssh_v) @(ssh_arguments) @(host) -t @(f"cd {host_xxh_home} && ./{xonsh_bin_name} --appimage-extract | grep -E 'usr/python/bin/xonsh$' && mv squashfs-root xonsh-squashfs && mv {host_xonsh_bin} {host_xonsh_bin}-disabled && ln -s {host_xonsh_bin_new}")
|
||||||
|
host_xonsh_bin = host_xonsh_bin_new
|
||||||
|
|
||||||
|
print(f'First run xonsh on {host}\033[0m')
|
||||||
|
|
||||||
|
host_plugins_rc = $(ssh @(ssh_v) @(ssh_arguments) @(host) -t @(host_xonsh_bin) --no-script-cache -i --rc @(host_xonshrc) -- @(host_xonsh_plugins_rc) )
|
||||||
|
|
||||||
|
host_plugins_rc_list = host_plugins_rc.split('xxh-plugins#')
|
||||||
|
if len(host_plugins_rc_list) > 1:
|
||||||
|
host_plugins_rc_list = host_plugins_rc_list[1]
|
||||||
|
else:
|
||||||
|
print(f'Something went wrong while getting plugins info. Host answer: {host_plugins_rc}')
|
||||||
|
exit(1)
|
||||||
|
|
||||||
|
ssh @(ssh_v) @(ssh_arguments) @(host) -t @(host_xonsh_bin) --no-script-cache -i --rc @(host_xonshrc) @(host_plugins_rc_list)
|
||||||
|
|
Loading…
Reference in a new issue