Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
| 2 | |
| 3 | import sys |
| 4 | import os |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 5 | import os.path |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 6 | import re |
| 7 | import subprocess |
| 8 | import tempfile |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 9 | import urllib.request |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 10 | import argparse |
| 11 | import hashlib |
| 12 | |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 13 | def initialize_apt(apt_dir, apt_args, args): |
| 14 | os.mkdir(os.path.join(apt_dir, 'etc')) |
| 15 | os.mkdir(os.path.join(apt_dir, 'etc', 'apt')) |
| 16 | os.mkdir(os.path.join(apt_dir, 'etc', 'apt', 'trusted.gpg.d')) |
| 17 | os.mkdir(os.path.join(apt_dir, 'etc', 'apt', 'preferences.d')) |
| 18 | os.mkdir(os.path.join(apt_dir, 'var')) |
| 19 | os.mkdir(os.path.join(apt_dir, 'var', 'lib')) |
| 20 | os.mkdir(os.path.join(apt_dir, 'var', 'lib', 'dpkg')) |
| 21 | with open(os.path.join(apt_dir, 'var', 'lib', 'dpkg', 'status'), 'w'): |
| 22 | pass |
| 23 | with open(os.path.join(apt_dir, 'etc', 'apt', 'sources.list'), 'w') as f: |
| 24 | f.write(""" |
| 25 | deb http://deb.debian.org/debian/ {release} main contrib non-free |
| 26 | deb-src http://deb.debian.org/debian/ {release} main contrib non-free |
| 27 | |
| 28 | deb https://security.debian.org/debian-security {release}-security main contrib non-free |
| 29 | deb-src https://security.debian.org/debian-security {release}-security main contrib non-free |
| 30 | |
| 31 | deb http://deb.debian.org/debian/ {release}-updates main contrib non-free |
| 32 | deb-src http://deb.debian.org/debian/ {release}-updates main contrib non-free |
| 33 | |
| 34 | deb http://deb.debian.org/debian {release}-backports main contrib non-free |
| 35 | deb-src http://deb.debian.org/debian {release}-backports main contrib non-free |
| 36 | """.format(release=args.release)) |
| 37 | for key in args.apt_key: |
| 38 | basename = os.path.basename(key) |
| 39 | urllib.request.urlretrieve(key, os.path.join(apt_dir, 'etc', 'apt', 'trusted.gpg.d', basename)) |
| 40 | subprocess.check_call(["apt-get"] + apt_args + ["update"]) |
| 41 | |
| 42 | def get_deps(apt_args, package): |
Brian Silverman | 4c7235a | 2021-11-17 19:04:37 -0800 | [diff] [blame] | 43 | env = dict(os.environ) |
| 44 | del env['LD_LIBRARY_PATH'] |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 45 | out = subprocess.check_output(["apt-rdepends"] + apt_args + [package], env=env) |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 46 | deps = out.splitlines() |
| 47 | return set([dep for dep in deps if not dep.startswith(b" ")]) |
| 48 | |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 49 | def get_all_deps(apt_args, packages): |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 50 | deps = set() |
Philipp Schrader | aedfc5c | 2018-03-10 19:32:30 -0800 | [diff] [blame] | 51 | for package in packages or (): |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 52 | deps.update(get_deps(apt_args, package)) |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 53 | return deps |
| 54 | |
Brian Silverman | 6470f44 | 2018-08-05 12:08:16 -0700 | [diff] [blame] | 55 | def map_virtual_packages(packages): |
| 56 | '''Maps known virtual packages to the preferred concrete packages which |
| 57 | provide them.''' |
| 58 | for package in packages: |
| 59 | if package == b'python-numpy-abi9': |
| 60 | yield b'python-numpy' |
| 61 | continue |
| 62 | if package == b'python3-numpy-abi9': |
| 63 | yield b'python3-numpy' |
| 64 | continue |
Tyler Chatow | 60671d3 | 2020-02-26 19:49:30 -0800 | [diff] [blame] | 65 | if package == b'libjack-0.125': |
| 66 | yield b'libjack-jackd2-0' |
| 67 | continue |
| 68 | if package == b'fonts-freefont': |
| 69 | yield b'fonts-freefont-ttf' |
| 70 | continue |
| 71 | if package == b'gsettings-backend': |
| 72 | yield b'dconf-gsettings-backend' |
| 73 | continue |
| 74 | if package == b'gdal-abi-2-4-0': |
| 75 | yield b'libgdal20' |
| 76 | continue |
| 77 | if package == b'libglu1': |
| 78 | yield b'libglu1-mesa' |
| 79 | continue |
| 80 | if package == b'liblapack.so.3': |
| 81 | yield b'liblapack3' |
| 82 | continue |
| 83 | if package == b'libopencl1': |
| 84 | yield b'ocl-icd-libopencl1' |
| 85 | continue |
Brian Silverman | 4c7235a | 2021-11-17 19:04:37 -0800 | [diff] [blame] | 86 | if package == b'libgcc1': |
| 87 | yield b'libgcc-s1' |
| 88 | continue |
| 89 | if package == b'libopencl-1.2-1': |
| 90 | yield b'ocl-icd-libopencl1' |
| 91 | continue |
Tyler Chatow | 60671d3 | 2020-02-26 19:49:30 -0800 | [diff] [blame] | 92 | if package == b'libblas.so.3': |
| 93 | yield b'libblas3' |
| 94 | continue |
Philipp Schrader | d0e33a4 | 2022-01-22 21:55:15 -0800 | [diff] [blame] | 95 | if package == b'debconf-2.0': |
| 96 | yield b'debconf' |
| 97 | continue |
Brian Silverman | 6470f44 | 2018-08-05 12:08:16 -0700 | [diff] [blame] | 98 | yield package |
| 99 | |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 100 | def download_deps(apt_args, packages, excludes, force_includes): |
| 101 | deps = get_all_deps(apt_args, packages) |
| 102 | exclude_deps = get_all_deps(apt_args, excludes) |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 103 | deps -= exclude_deps |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 104 | force_include_deps = get_all_deps(apt_args, force_includes) |
Philipp Schrader | aedfc5c | 2018-03-10 19:32:30 -0800 | [diff] [blame] | 105 | deps |= force_include_deps |
Brian Silverman | 4c7235a | 2021-11-17 19:04:37 -0800 | [diff] [blame] | 106 | env = dict(os.environ) |
| 107 | del env['LD_LIBRARY_PATH'] |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 108 | subprocess.check_call([b"apt-get"] + [a.encode('utf-8') for a in apt_args] + [b"download"] + list(map_virtual_packages(deps)), env=env) |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 109 | |
| 110 | def fixup_files(): |
| 111 | # Gotta remove those pesky epoch numbers in the file names. Bazel doesn't |
| 112 | # like them. |
| 113 | regex = re.compile(".%3a") |
| 114 | contents = os.listdir(os.getcwd()) |
| 115 | for deb in contents: |
| 116 | new_name = regex.sub("", deb) |
| 117 | if new_name != deb: |
| 118 | os.rename(deb, new_name) |
| 119 | |
| 120 | def sha256_checksum(filename, block_size=65536): |
| 121 | sha256 = hashlib.sha256() |
| 122 | with open(filename, 'rb') as f: |
| 123 | for block in iter(lambda: f.read(block_size), b''): |
| 124 | sha256.update(block) |
| 125 | return sha256.hexdigest() |
| 126 | |
| 127 | def print_file_list(): |
| 128 | contents = os.listdir(os.getcwd()) |
| 129 | contents.sort() |
| 130 | print("_files = {") |
| 131 | for deb in contents: |
| 132 | print(' "%s": "%s",' % (deb, sha256_checksum(deb))) |
| 133 | print("}") |
| 134 | |
Philipp Schrader | aedfc5c | 2018-03-10 19:32:30 -0800 | [diff] [blame] | 135 | _ALWAYS_EXCLUDE = [ |
Tyler Chatow | 60671d3 | 2020-02-26 19:49:30 -0800 | [diff] [blame] | 136 | "dbus-session-bus", |
Philipp Schrader | aedfc5c | 2018-03-10 19:32:30 -0800 | [diff] [blame] | 137 | "debconf", |
| 138 | "debconf-2.0", |
Tyler Chatow | 60671d3 | 2020-02-26 19:49:30 -0800 | [diff] [blame] | 139 | "default-dbus-session-bus", |
Philipp Schrader | aedfc5c | 2018-03-10 19:32:30 -0800 | [diff] [blame] | 140 | "dpkg", |
| 141 | "install-info", |
| 142 | "libc-dev", |
| 143 | "libc6", |
| 144 | "libc6-dev", |
| 145 | ] |
| 146 | |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 147 | def main(argv): |
| 148 | parser = argparse.ArgumentParser() |
| 149 | parser.add_argument("--exclude", "-e", type=str, action="append", help="A package to exclude from the list") |
Philipp Schrader | aedfc5c | 2018-03-10 19:32:30 -0800 | [diff] [blame] | 150 | parser.add_argument("--force-include", type=str, action="append", help="Force include this and its dependencies. Even if listed in excludes.") |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 151 | parser.add_argument("--arch", type=str, default="amd64", help="Architecture to download files for.") |
| 152 | parser.add_argument("--apt-dir", type=str, help=" ".join([ |
| 153 | "File to generate and store apt files in.", |
| 154 | "Helpful for saving time when downloading multiple groups of packages.", |
| 155 | "Some flags will be ignored in favor of the values used to create this folder, so be careful.", |
| 156 | ])) |
| 157 | parser.add_argument("--release", type=str, default="bullseye", help="Debian release to use.") |
| 158 | parser.add_argument("--apt-key", type=str, action="append", default=[ |
| 159 | "https://ftp-master.debian.org/keys/archive-key-11.asc", |
| 160 | "https://ftp-master.debian.org/keys/archive-key-11-security.asc", |
| 161 | ], help="URL of an additional apt archive key to trust.") |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 162 | parser.add_argument("package", nargs="+", help="The packages to download.") |
| 163 | args = parser.parse_args(argv[1:]) |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 164 | if args.apt_dir: |
| 165 | apt_dir = args.apt_dir |
| 166 | else: |
| 167 | apt_dir = tempfile.mkdtemp() |
| 168 | apt_args = ["-o", "Dir=" + apt_dir, "-o", "APT::Architecture=" + args.arch] |
| 169 | if not args.apt_dir: |
| 170 | print("Creating apt files in %s" % apt_dir) |
| 171 | initialize_apt(apt_dir, apt_args, args) |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 172 | folder = tempfile.mkdtemp() |
| 173 | os.chdir(folder) |
| 174 | excludes = args.exclude or [] |
| 175 | # Exclude common packages that don't make sense to include in everything all |
| 176 | # the time. |
Philipp Schrader | aedfc5c | 2018-03-10 19:32:30 -0800 | [diff] [blame] | 177 | excludes += _ALWAYS_EXCLUDE |
Brian Silverman | 4b90dd0 | 2022-01-08 18:16:22 -0800 | [diff] [blame] | 178 | download_deps(apt_args, args.package, excludes, args.force_include) |
Philipp Schrader | 0e19c60 | 2018-03-07 21:07:22 -0800 | [diff] [blame] | 179 | fixup_files() |
| 180 | print_file_list() |
| 181 | print("Your packages are all in %s" % folder) |
| 182 | |
| 183 | if __name__ == "__main__": |
| 184 | sys.exit(main(sys.argv)) |