xiwrap

slightly higher-level container setup utility
git clone https://git.ce9e.org/xiwrap.git

commit
8ea65f0a61f572c73999cc92e6b93ef3d7325c9c
parent
f4793cbb16842ba61da484cf17752a0aaeaeb962
Author
Tobias Bengfort <tobias.bengfort@posteo.de>
Date
2024-06-15 22:42
add dbus support

Diffstat

M rules/gui 8 ++++++++
M xiwrap.py 53 +++++++++++++++++++++++++++++++++++++++++++++++++++--

2 files changed, 59 insertions, 2 deletions


diff --git a/rules/gui b/rules/gui

@@ -1,5 +1,8 @@
    1     1 import graphics
   -1     2 
    2     3 env HOME
   -1     4 env GTK_USE_PORTAL 1
   -1     5 
    3     6 ro-bind /etc/fonts
    4     7 ro-bind /usr/share/fonts
    5     8 ro-bind /usr/share/icons
@@ -9,4 +12,9 @@ ro-bind $HOME/.local/share/icons
    9    12 ro-bind $HOME/.local/share/themes
   10    13 bind $HOME/.cache/fontconfig
   11    14 bind $HOME/.cache/thumbnails
   -1    15 
   12    16 ro-bind $HOME/.config/dconf/user
   -1    17 
   -1    18 dbus-talk org.a11y.Bus
   -1    19 dbus-talk org.freedesktop.portal.Desktop
   -1    20 dbus-talk org.freedesktop.portal.Documents

diff --git a/xiwrap.py b/xiwrap.py

@@ -1,11 +1,17 @@
    1     1 import os
   -1     2 import subprocess
    2     3 import sys
    3     4 from os.path import expandvars
    4     5 from pathlib import Path
    5     6 
    6    -1 USER_CONFIG = Path(os.getenv('XDG_CONFIG_HOME', '~/.config')) / 'xiwrap'
   -1     7 XDG_RUNTIME_DIR = Path(os.getenv('XDG_RUNTIME_DIR'))
   -1     8 XDG_CONFIG_HOME = Path(os.getenv('XDG_CONFIG_HOME', '~/.config')).expanduser()
   -1     9 
   -1    10 USER_CONFIG = XDG_CONFIG_HOME / 'xiwrap'
    7    11 SYSTEM_CONFIG = Path('/etc') / 'xiwrap'
    8    12 
   -1    13 DBUS_PROXY_PATH = XDG_RUNTIME_DIR / f'dbus-proxy-{os.getpid()}'
   -1    14 
    9    15 USAGE = """Usage: xiwrap [OPTION]... -- [BWRAP_OPTIONS]... CMD
   10    16 
   11    17 Example: xiwrap --import host-os --env TERM -- --chdir /tmp bash
@@ -26,6 +32,12 @@ The following options are available:
   26    32 --dev DEST              Mount new dev on DEST.
   27    33 --tmpfs DEST            Mount new tmpfs on DEST.
   28    34 --share-net             Do not create new network namespace.
   -1    35 --dbus-see NAME         Allow to see NAME on the session bus.
   -1    36 --dbus-talk NAME        Allow to talk to NAME on the session bus.
   -1    37 --dbus-own NAME         Allow to own NAME on the session bus.
   -1    38 --dbus-call NAME=RULE   Set a rule for calls on the given name.
   -1    39 --dbus-broadcast NAME=RULE
   -1    40                         Set a rule for broadcast signals from the given name.
   29    41 --import FILE           Load additional options from FILE. FILE can be an
   30    42                         absolute path or relative to the current directory,
   31    43                         $XDG_CONFIG_HOME/xiwrap/ or /etc/xiwrap/. FILE must
@@ -48,8 +60,9 @@ class RuleSet:
   48    60             '/dev': ('dev', None),
   49    61             '/proc': ('proc', None),
   50    62         }
   51    -1         self.dbus = set()  # TODO
   -1    63         self.dbus = {}
   52    64         self.share_net = False
   -1    65         self.sync_fds = None
   53    66         self.debug = False
   54    67         self.usage = False
   55    68 
@@ -80,6 +93,14 @@ class RuleSet:
   80    93         else:
   81    94             raise RuleError(key, args)
   82    95 
   -1    96     def ensure_dbus(self):
   -1    97         if self.sync_fds is not None:
   -1    98             return
   -1    99         self.sync_fds = os.pipe2(0)
   -1   100         bus = str(XDG_RUNTIME_DIR / 'bus')
   -1   101         self.paths[bus] = ('ro-bind', str(DBUS_PROXY_PATH))
   -1   102         self.env['DBUS_SESSION_BUS_ADDRESS'] = f'unix:path={bus}'
   -1   103 
   83   104     def push_rule(self, key, args, *, cwd):
   84   105         if key == 'import':
   85   106             if len(args) != 1:
@@ -90,6 +111,13 @@ class RuleSet:
   90   111             if len(args) != 0:
   91   112                 raise RuleError(key, args)
   92   113             self.share_net = True
   -1   114         elif key in [
   -1   115             'dbus-see', 'dbus-talk', 'dbus-own', 'dbus-call', 'dbus-broadcast'
   -1   116         ]:
   -1   117             if len(args) != 1:
   -1   118                 raise RuleError(key, args)
   -1   119             self.ensure_dbus()
   -1   120             self.dbus[args[0]] = key.removeprefix('dbus-')
   93   121         elif key == 'env':
   94   122             var, value = self.parse_env(key, args)
   95   123             self.env[var] = value
@@ -145,6 +173,8 @@ class RuleSet:
  145   173         ]
  146   174         if not self.share_net:
  147   175             cmd += ['--unshare-net']
   -1   176         if self.sync_fds is not None:
   -1   177             cmd += ['--sync-fd', str(self.sync_fds[0])]
  148   178         for key, value in self.env.items():
  149   179             if value is not None:
  150   180                 cmd += ['--setenv', key, value]
@@ -156,6 +186,20 @@ class RuleSet:
  156   186                 cmd += [f'--{typ}-try', src, target]
  157   187         return cmd + bwrap_args
  158   188 
   -1   189     def build_dbus(self):
   -1   190         if self.sync_fds is None:
   -1   191             return None
   -1   192         cmd = [
   -1   193             'xdg-dbus-proxy',
   -1   194             f'--fd={self.sync_fds[1]}',
   -1   195             os.getenv('DBUS_SESSION_BUS_ADDRESS'),
   -1   196             str(DBUS_PROXY_PATH),
   -1   197             '--filter',
   -1   198         ]
   -1   199         for value, typ in sorted(self.dbus.items()):
   -1   200             cmd.append(f'--{typ}={value}')
   -1   201         return cmd
   -1   202 
  159   203 
  160   204 if __name__ == '__main__':
  161   205     rules = RuleSet()
@@ -168,9 +212,14 @@ if __name__ == '__main__':
  168   212         print(USAGE)
  169   213         sys.exit(1)
  170   214     cmd = rules.build(tail)
   -1   215     dbus_cmd = rules.build_dbus()
  171   216     if rules.usage:
  172   217         print(USAGE)
  173   218     elif rules.debug:
  174   219         print(' '.join(cmd))
   -1   220         if dbus_cmd:
   -1   221             print(' '.join(dbus_cmd))
  175   222     else:
   -1   223         if dbus_cmd:
   -1   224             subprocess.Popen(dbus_cmd, pass_fds=[rules.sync_fds[1]])
  176   225         os.execvp('/usr/bin/bwrap', cmd)