-
Simon McVittie authored
This file is read by the default /etc/bash.bashrc in Debian and included as a prefix to the prompt, in this style: (contents of /etc/debian_chroot) user@host:~$ It is automatically populated with the chroot name by schroot, but not by other container tools like Docker and Flatpak. We might as well give it a useful value for all Flatdeb-generated containers. Signed-off-by:
Simon McVittie <smcv@collabora.com>
Simon McVittie authoredThis file is read by the default /etc/bash.bashrc in Debian and included as a prefix to the prompt, in this style: (contents of /etc/debian_chroot) user@host:~$ It is automatically populated with the chroot name by schroot, but not by other container tools like Docker and Flatpak. We might as well give it a useful value for all Flatdeb-generated containers. Signed-off-by:
Simon McVittie <smcv@collabora.com>
set-build-id 7.00 KiB
#!/usr/bin/python3
# flatdeb — build Flatpak runtimes from Debian packages
#
# Copyright © 2016-2017 Simon McVittie
# Copyright © 2017-2019 Collabora Ltd.
#
# SPDX-License-Identifier: MIT
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# "Software"), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be included
# in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
import argparse
import logging
import os
import subprocess
import sys
try:
import typing
except ImportError:
pass
else:
typing # silence "unused" warnings
logger = logging.getLogger('flatdeb.set-build-id')
def quote(s):
# We can't use shlex.quote() because it relies on concatenated
# strings, which are valid for sh but not for /etc/os-release
quoted = s.replace(
'\\', '\\\\',
).replace(
'$', '\\$',
).replace(
'`', '\\`',
).replace(
'"', '\\"',
)
for c in quoted:
if c >= '\x7f' or not c.isalnum():
quoted = '"{}"'.format(quoted)
break
return quoted
def main():
# type: (...) -> None
parser = argparse.ArgumentParser(
description='Set build ID in chroot'
)
parser.add_argument('--build-id', default='')
parser.add_argument('--variant', default='')
parser.add_argument('--variant-id', default='')
parser.add_argument('--test-quoting', action='store_true')
parser.add_argument('sysroot')
args = parser.parse_args()
lines = []
if args.test_quoting:
for x in (
'debian',
'10',
):
assert quote(x) == x, x
for x in (
'Debian GNU/Linux 10 (buster)',
'3.141592654',
):
assert quote(x) == '"' + x + '"', x
for orig, quoted in (
("My 'great' distro", '"My \'great\' distro"'),
('My "great" distro', '"My \\"great\\" distro"'),
('$PATH', '"\\$PATH"'),
('C:\\Windows', '"C:\\\\Windows"'),
('Shell `injection`', '"Shell \\`injection\\`"'),
):
assert quote(orig) == quoted
unquoted = subprocess.check_output(
'printf "%s" ' + quoted,
universal_newlines=True,
shell=True,
)
assert unquoted == orig, (unquoted, orig)
return
os_id = ''
version_codename = ''
version_id = ''
with open(
os.path.join(args.sysroot, 'usr', 'lib', 'os-release'),
'r',
) as reader:
for line in reader:
if line.startswith(('VARIANT=', 'VARIANT_ID=', 'BUILD_ID=')):
logger.info('# Ignoring: %s', line.strip())
else:
logger.info('%s', line.strip())
lines.append(line)
value = line.split('=', 1)[1].strip()
if value[0] == '"':
assert value.endswith('"'), value
value = value[1:-1]
# Unescape \\, \", \$, \`. The string can't contain \n
# so we can use \n as a placeholder for a literal backslash.
value = value.replace('\\\\', '\n')
value = value.replace('\\', '')
value = value.replace('\n', '\\')
if line.startswith('ID='):
os_id = value
elif line.startswith('VERSION_CODENAME='):
version_codename = value
elif line.startswith('VERSION_ID='):
version_id = value
if args.build_id:
logger.info('Adding BUILD_ID=%s', quote(args.build_id))
lines.append('BUILD_ID={}\n'.format(quote(args.build_id)))
if args.variant:
logger.info('Adding VARIANT=%s', quote(args.variant))
lines.append('VARIANT={}\n'.format(quote(args.variant)))
if args.variant_id:
logger.info('Adding VARIANT_ID=%s', quote(args.variant_id))
lines.append('VARIANT_ID={}\n'.format(quote(args.variant_id)))
with open(
os.path.join(args.sysroot, 'usr', 'lib', 'os-release.new'),
'w',
) as writer:
writer.writelines(lines)
os.rename(
os.path.join(args.sysroot, 'usr', 'lib', 'os-release.new'),
os.path.join(args.sysroot, 'usr', 'lib', 'os-release'),
)
if version_codename:
# e.g. buster, leading to (buster) user@host:~$
chroot_name = version_codename
elif version_id:
# e.g. 10, leading to (10) user@host:~$
chroot_name = version_id
else:
chroot_name = ''
# We use the OS ID instead of the human-readable NAME because we want
# something short.
if os_id:
if chroot_name:
# e.g. leading to (debian buster) user@host:~$
# or (debian 10) user@host:~$
chroot_name = '{} {}'.format(os_id, chroot_name)
else:
# e.g. (debian) user@host:~$
chroot_name = os_id
if args.build_id:
if chroot_name:
# e.g. (debian buster 20190603) user@host:~$
chroot_name = '{} {}'.format(chroot_name, args.build_id)
else:
# e.g. (20190603) user@host:~$
chroot_name = args.build_id
if chroot_name:
logger.info('Setting debian_chroot to %r', chroot_name)
with open(
os.path.join(args.sysroot, 'etc', 'debian_chroot.new'),
'w',
) as writer:
writer.write(chroot_name + '\n')
else:
logger.info('Not setting debian_chroot')
os.rename(
os.path.join(args.sysroot, 'etc', 'debian_chroot.new'),
os.path.join(args.sysroot, 'etc', 'debian_chroot'),
)
if __name__ == '__main__':
if sys.stderr.isatty():
try:
import colorlog
except ImportError:
pass
else:
formatter = colorlog.ColoredFormatter(
'%(log_color)s%(levelname)s:%(name)s:%(reset)s %(message)s')
handler = logging.StreamHandler()
handler.setFormatter(formatter)
logging.getLogger().addHandler(handler)
else:
logging.basicConfig()
logging.getLogger().setLevel(logging.DEBUG)
try:
main()
except KeyboardInterrupt:
raise SystemExit(130)