rc.xsh 6.6 KB

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