rc.xsh 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. $VI_MODE = True
  2. $AUTO_PUSHD = True
  3. $XONSH_AUTOPAIR = True
  4. # tab selection: do not execute cmd when pressing enter
  5. $COMPLETIONS_CONFIRM = True
  6. xontrib load vox z
  7. def _last_exit_status():
  8. try:
  9. exit_status = __xonsh_history__.rtns[-1]
  10. return exit_status if exit_status != 0 else None
  11. except IndexError:
  12. return None
  13. $PROMPT_FIELDS['last_exit_status'] = _last_exit_status
  14. $SHLVL = int($SHLVL) + 1 if 'SHLVL' in ${...} else 1
  15. $XONSH_STDERR_PREFIX = '{RED}'
  16. $XONSH_STDERR_POSTFIX = '{NO_COLOR}'
  17. $DYNAMIC_CWD_WIDTH = '30%'
  18. $DYNAMIC_CWD_ELISION_CHAR = '…'
  19. $PROMPT = ''.join([
  20. '{RED}{last_exit_status:[{}] }',
  21. '{BOLD_GREEN}{user}@{hostname} ',
  22. '{YELLOW}{cwd} ',
  23. '{{BLUE}}{} '.format('{prompt_end}' * $SHLVL),
  24. '{NO_COLOR}',
  25. ])
  26. $RIGHT_PROMPT = '{gitstatus}{env_name: {}}'
  27. import datetime as dt
  28. import io
  29. import json
  30. import os
  31. import re
  32. import select
  33. import shutil
  34. import subprocess
  35. import sys
  36. import threading
  37. # default locale
  38. # will be used for all non-explicitly set LC_* variables
  39. $LANG = 'en_US.UTF-8'
  40. # fallback locales
  41. # GNU gettext gives preference to LANGUAGE over LC_ALL and LANG
  42. # for the purpose of message handling
  43. # https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html
  44. # cave: if this list contains 'de(_.*)?' at any (sic!) position
  45. # vim 7.4.1689 will switch to german
  46. $LANGUAGE = ':'.join(['en_US', 'en'])
  47. $LC_COLLATE = 'C.UTF-8'
  48. # char classification, case conversion & other char attrs
  49. $LC_CTYPE = 'de_AT.UTF-8'
  50. # $ locale currency_symbol
  51. $LC_MONETARY = 'de_AT.UTF-8'
  52. # $ locale -k LC_NUMERIC | head -n 3
  53. # decimal_point="."
  54. # thousands_sep=""
  55. # grouping=-1
  56. $LC_NUMERIC = 'C.UTF-8'
  57. # A4
  58. $LC_PAPER = 'de_AT.UTF-8'
  59. USER_BIN_PATH = os.path.join($HOME, '.local', 'bin')
  60. if os.path.isdir(USER_BIN_PATH):
  61. $PATH.insert(0, USER_BIN_PATH)
  62. $PAGER = 'less'
  63. $EDITOR = 'vim'
  64. # required by pinentry-tty when using gpg command:
  65. $GPG_TTY = $(tty)
  66. if shutil.which('gpgconf'):
  67. # required by scute
  68. $GPG_AGENT_INFO = $(gpgconf --list-dir agent-socket).rstrip() + ':0:1'
  69. if not 'SSH_CLIENT' in ${...}:
  70. # in gnupg 2.1.13 the location of agents socket changed
  71. $SSH_AUTH_SOCK = $(gpgconf --list-dir agent-ssh-socket).rstrip()
  72. # wrapper for termite required when launching termite from ranger:
  73. $TERMCMD = os.path.join(os.path.dirname(__file__), 'ranger-termite-termcmd')
  74. # https://docs.docker.com/engine/security/trust/content_trust/
  75. $DOCKER_CONTENT_TRUST = 1
  76. class DockerImage:
  77. def __init__(self, image):
  78. attrs, = json.loads(subprocess.check_output(['sudo', 'docker', 'image', 'inspect', image])
  79. .decode(sys.stdout.encoding))
  80. self._id = attrs['Id']
  81. self._tags = attrs['RepoTags']
  82. def __repr__(self):
  83. return '{}(id={!r}, tags={!r})'.format(type(self).__name__, self._id, self._tags)
  84. @classmethod
  85. def pull(cls, image):
  86. out = io.BytesIO()
  87. with StdoutTee(out) as tee:
  88. subprocess.run(['sudo', 'docker', 'image', 'pull', image], stdout=tee)
  89. repo_digest, = re.search(rb'^Digest: (sha\S+:\S+)$', out.getvalue(), re.MULTILINE).groups()
  90. return cls('{}@{}'.format(image, repo_digest.decode()))
  91. class StdoutTee:
  92. def __init__(self, sink):
  93. self._sink = sink
  94. def __enter__(self):
  95. self._read_fd, self._write_fd = os.pipe()
  96. self._thread = threading.Thread(target=self._loop)
  97. self._thread.start()
  98. return self
  99. def _loop(self):
  100. while True:
  101. try:
  102. data = os_read_non_blocking(self._read_fd)
  103. except OSError: # fd closed
  104. return
  105. if data:
  106. self._sink.write(data)
  107. sys.stdout.buffer.write(data)
  108. sys.stdout.flush()
  109. def fileno(self):
  110. return self._write_fd
  111. def __exit__(self, exc_type, exc_value, traceback):
  112. os.close(self._read_fd)
  113. os.close(self._write_fd)
  114. self._thread.join()
  115. def dpkg_listfiles(pkg_name):
  116. assert isinstance(pkg_name, str)
  117. paths = $(dpkg --listfiles @(pkg_name)).split('\n')[:-1]
  118. assert len(paths) > 0, 'pkg {!r} not installed'.format(pkg_name)
  119. return paths
  120. def dpkg_search(path_search_pattern):
  121. assert isinstance(path_search_pattern, str)
  122. return re.findall(
  123. '^(\S+): (.*)$\n',
  124. $(dpkg --search @(path_search_pattern)),
  125. flags=re.MULTILINE,
  126. )
  127. def dpkg_welse(cmd):
  128. pkg_name, cmd_path = dpkg_which(cmd)
  129. return dpkg_listfiles(pkg_name)
  130. def dpkg_which(cmd):
  131. cmd_path = shutil.which(cmd)
  132. assert cmd_path, 'cmd {!r} not found'.format(cmd)
  133. matches = dpkg_search(cmd_path)
  134. assert len(matches) != 0, '{!r} not installed via dpkg'.format(cmd_path)
  135. assert len(matches) == 1
  136. return matches[0]
  137. def docker_build(dockerfile):
  138. p = subprocess.Popen(['sudo', 'docker', 'build', '-'],
  139. stdin=subprocess.PIPE, stdout=subprocess.PIPE)
  140. p.stdin.write(dockerfile.encode())
  141. p.stdin.close()
  142. image_id_regex = re.compile(rb'^Successfully built (\S+)\n$')
  143. image_id = None
  144. for line in p.stdout:
  145. sys.stdout.write(line.decode(sys.stdout.encoding))
  146. image_id_match = image_id_regex.search(line)
  147. if image_id_match:
  148. image_id, = image_id_match.groups()
  149. assert not image_id is None, 'could not determine image id'
  150. return image_id.decode(sys.stdout.encoding)
  151. def docker_run(image_id=None, dockerfile=None, caps=[]):
  152. assert image_id is None or dockerfile is None, \
  153. 'either pass kwarg image_id or dockerfile'
  154. if not image_id:
  155. image_id = docker_build(dockerfile)
  156. params = ['sudo', 'docker', 'run',
  157. '--rm=true', '--interactive=true', '--tty=true',
  158. '--cap-drop=all', '--security-opt=no-new-privileges']
  159. params.extend(['--cap-add={}'.format(c) for c in caps])
  160. params.append(image_id)
  161. import shlex
  162. print(' '.join([shlex.quote(p) for p in params]))
  163. subprocess.run(params, check=True)
  164. def locate(*patterns, match_all=True, ignore_case=True):
  165. params = []
  166. if match_all:
  167. params.insert(0, '--all')
  168. if ignore_case:
  169. params.insert(0, '--ignore-case')
  170. return $(locate @(params) -- @(patterns)).split('\n')[:-1]
  171. def os_read_non_blocking(fd, buffer_size_bytes=8*1024, timeout_seconds=0.1):
  172. if fd in select.select([fd], [], [], timeout_seconds)[0]:
  173. return os.read(fd, buffer_size_bytes)
  174. else:
  175. return None
  176. def timestamp_now_utc():
  177. return dt.datetime.utcnow().replace(tzinfo=dt.timezone.utc)
  178. def timestamp_now_local():
  179. # if called without tz argument astimezone() assumes
  180. # the system local timezone for the target timezone
  181. return timestamp_now_utc().astimezone()
  182. def timestamp_iso_local():
  183. # if called without tz argument astimezone() assumes
  184. # the system local timezone for the target timezone
  185. return timestamp_now_local().strftime('%Y%m%dT%H%M%S%z')
  186. aliases['d'] = ['sudo', 'docker']
  187. aliases['d-r'] = lambda args: docker_run(**{
  188. 'dockerfile' if '\n' in args[0] else 'image_id': args[0],
  189. })
  190. aliases['dpkg-welse'] = lambda args: '\n'.join(dpkg_welse(args[0]))
  191. aliases['dpkg-which'] = lambda args: '\t'.join(dpkg_which(args[0]))
  192. aliases['g'] = ['git']
  193. aliases['ll'] = ['ls', '-l', '--all', '--indicator-style=slash',
  194. '--human-readable', '--time-style=long-iso', '--color=auto']
  195. if shutil.which('startx') and $(tty).rstrip() == '/dev/tty1':
  196. startx
  197. # vim: filetype=python