1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# 4# Hardlink only packages used in the build from one directory to another, 5# and updates the RemotePackageRepository file at the same time. 6# 7# Copyright 2017-2020 Augustin Cavalier <waddlesplash> 8# Distributed under the terms of the MIT License. 9 10import sys, os, subprocess, re, hashlib 11from distutils.version import LooseVersion 12 13if len(sys.argv) != 5: 14 print("usage: hardlink_packages.py [arch] [jam RemotePackageRepository file] " 15 + "[prebuilt packages directory] [destination root directory]") 16 print("note that the [jam RemotePackageRepository file] will be modified.") 17 print("note that [target directory] is assumed to have a 'packages' subdirectory, " 18 + " and a repo.info.template file (using $ARCH$)") 19 sys.exit(1) 20 21if subprocess.run(['package_repo'], None, None, None, 22 subprocess.DEVNULL, subprocess.PIPE).returncode != 1: 23 print("package_repo command does not seem to exist.") 24 sys.exit(1) 25 26args_arch = sys.argv[1] 27args_jamf = sys.argv[2] 28args_src = sys.argv[3] 29args_dst = sys.argv[4] 30 31if not args_dst.endswith('/'): 32 args_dst = args_dst + '/' 33if not args_src.endswith('/'): 34 args_src = args_src + '/' 35 36args_dst_packages = args_dst + 'packages/' 37 38packageVersions = [] 39for filename in os.listdir(args_src): 40 if (not (filename.endswith("-" + args_arch + ".hpkg")) and 41 not (filename.endswith("-any.hpkg"))): 42 continue 43 packageVersions.append(filename) 44 45# Read RemotePackageRepository file and hardlink relevant packages 46pattern = re.compile("^[a-z0-9]") 47newFileForJam = [] 48packageFiles = [] 49filesNotFound = False 50with open(args_jamf) as f: 51 for line in f: 52 pkg = line.strip() 53 if (len(pkg) == 0): 54 continue 55 if not (pattern.match(pkg)): 56 # not a package (probably a Jam directive) 57 newFileForJam.append(line) 58 continue 59 60 try: 61 pkgname = pkg[:pkg.index('-')] 62 except: 63 pkgname = '' 64 if (len(pkgname) == 0): 65 # no version, likely a source/debuginfo listing 66 newFileForJam.append(line) 67 continue 68 69 greatestVersion = None 70 for pkgVersion in packageVersions: 71 if (pkgVersion.startswith(pkgname + '-') and 72 ((greatestVersion == None) 73 or (LooseVersion(pkgVersion) > LooseVersion(greatestVersion)))): 74 greatestVersion = pkgVersion 75 if (greatestVersion == None): 76 print("not found: " + pkg) 77 newFileForJam.append(line) 78 filesNotFound = True 79 continue 80 else: 81 # found it, so hardlink it 82 if not (os.path.exists(args_dst_packages + greatestVersion)): 83 os.link(args_src + greatestVersion, args_dst_packages + greatestVersion) 84 if ('packages/' + greatestVersion) not in packageFiles: 85 packageFiles.append('packages/' + greatestVersion) 86 # also hardlink the source package, if one exists 87 srcpkg = greatestVersion.replace("-" + args_arch + ".hpkg", 88 "-source.hpkg").replace('-', '_source-', 1) 89 if os.path.exists(args_src + srcpkg): 90 if not os.path.exists(args_dst_packages + srcpkg): 91 os.link(args_src + srcpkg, args_dst_packages + srcpkg) 92 if ('packages/' + srcpkg) not in packageFiles: 93 packageFiles.append('packages/' + srcpkg) 94 newFileForJam.append("\t" + greatestVersion[:greatestVersion.rfind('-')] + "\n"); 95 96if filesNotFound: 97 sys.exit(1) 98 99finalizedNewFile = "".join(newFileForJam).encode('UTF-8') 100with open(args_jamf, 'wb') as f: 101 f.write(finalizedNewFile) 102 103listhash = hashlib.sha256(finalizedNewFile).hexdigest() 104try: 105 os.mkdir(args_dst + listhash) 106except: 107 print("dir " + listhash + " already exists. No changes?") 108 sys.exit(1) 109 110repodir = args_dst + listhash + '/' 111os.symlink('../packages', repodir + 'packages') 112 113with open(args_dst + 'repo.info.template', 'r') as ritf: 114 repoInfoTemplate = ritf.read() 115 116repoInfoTemplate = repoInfoTemplate.replace("$ARCH$", args_arch) 117with open(repodir + 'repo.info', 'w') as rinf: 118 rinf.write(repoInfoTemplate) 119 120packageFiles.sort() 121with open(repodir + 'package.list', 'w') as pkgl: 122 pkgl.write("\n".join(packageFiles)) 123 124if os.system('cd ' + repodir + ' && package_repo create repo.info ' + " ".join(packageFiles)) != 0: 125 print("failed to create package repo.") 126 sys.exit(1) 127 128if os.system('cd ' + repodir + ' && sha256sum repo >repo.sha256') != 0: 129 print("failed to checksum package repo.") 130 sys.exit(1) 131