From 568de5b03ee07eaee48e87d24bc451766d1405f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jelmer=20Vernoo=C4=B3?= Date: Thu, 22 Oct 2020 19:23:19 +0100 Subject: [PATCH] Add schroot module. --- ognibuild/schroot.py | 120 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 120 insertions(+) create mode 100644 ognibuild/schroot.py diff --git a/ognibuild/schroot.py b/ognibuild/schroot.py new file mode 100644 index 0000000..cf09d5d --- /dev/null +++ b/ognibuild/schroot.py @@ -0,0 +1,120 @@ +#!/usr/bin/python3 +# Copyright (C) 2020 Jelmer Vernooij +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +import shlex +import subprocess + +from typing import Optional, List, Dict + + +class Session(object): + + _cwd: Optional[str] + _location: Optional[str] + chroot: str + + def __init__(self, chroot: str): + if not isinstance(chroot, str): + raise TypeError('not a valid chroot: %r' % chroot) + self.chroot = chroot + self._location = None + self._cwd = None + + def _get_location(self) -> str: + return subprocess.check_output( + ['schroot', '--location', '-c', 'session:' + self.session_id + ]).strip().decode() + + def _end_session(self) -> None: + subprocess.check_output( + ['schroot', '-c', 'session:' + self.session_id, '-e']) + + def __enter__(self) -> 'Session': + self.session_id = subprocess.check_output( + ['schroot', '-c', self.chroot, '-b']).strip().decode() + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self._end_session() + return False + + def chdir(self, cwd: str) -> None: + self._cwd = cwd + + @property + def location(self) -> str: + if self._location is None: + self._location = self._get_location() + return self._location + + def _run_argv(self, argv: List[str], cwd: Optional[str] = None, + user: Optional[str] = None, + env: Optional[Dict[str, str]] = None): + base_argv = ['schroot', '-r', '-c', 'session:' + self.session_id] + if cwd is None: + cwd = self._cwd + if cwd is not None: + base_argv.extend(['-d', cwd]) + if user is not None: + base_argv.extend(['-u', user]) + if env: + argv = [ + 'sh', '-c', + ' '.join( + ['%s=%s ' % (key, shlex.quote(value)) + for (key, value) in env.items()] + + [shlex.quote(arg) for arg in argv])] + return base_argv + ['--'] + argv + + def check_call( + self, + argv: List[str], cwd: Optional[str] = None, + user: Optional[str] = None, + env: Optional[Dict[str, str]] = None): + try: + subprocess.check_call(self._run_argv(argv, cwd, user, env=env)) + except subprocess.CalledProcessError as e: + raise subprocess.CalledProcessError(e.returncode, argv) + + def check_output( + self, + argv: List[str], cwd: Optional[str] = None, + user: Optional[str] = None, + env: Optional[Dict[str, str]] = None) -> bytes: + try: + return subprocess.check_output( + self._run_argv(argv, cwd, user, env=env)) + except subprocess.CalledProcessError as e: + raise subprocess.CalledProcessError(e.returncode, argv) + + def Popen(self, argv, cwd: Optional[str] = None, + user: Optional[str] = None, **kwargs): + return subprocess.Popen(self._run_argv(argv, cwd, user), **kwargs) + + def call( + self, argv: List[str], cwd: Optional[str] = None, + user: Optional[str] = None): + return subprocess.call(self._run_argv(argv, cwd, user)) + + def create_home(self) -> None: + """Create the user's home directory.""" + home = self.check_output( + ['sh', '-c', 'echo $HOME']).decode().rstrip('\n') + user = self.check_output( + ['sh', '-c', 'echo $LOGNAME']).decode().rstrip('\n') + self.check_call(['mkdir', '-p', home], user='root') + self.check_call(['chown', user, home], user='root')