xref: /haiku/src/tools/hardlink_packages.py (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 = []
49errorsOccurred = 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			errorsOccurred = 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) in packageFiles:
85				print("error: duplicated package: " + pkgname)
86				errorsOccurred = True
87			packageFiles.append('packages/' + greatestVersion)
88			# also hardlink the source package, if one exists
89			srcpkg = greatestVersion.replace("-" + args_arch + ".hpkg",
90				"-source.hpkg").replace('-', '_source-', 1)
91			if os.path.exists(args_src + srcpkg):
92				if not os.path.exists(args_dst_packages + srcpkg):
93					os.link(args_src + srcpkg, args_dst_packages + srcpkg)
94				if ('packages/' + srcpkg) not in packageFiles:
95					packageFiles.append('packages/' + srcpkg)
96		newFileForJam.append("\t" + greatestVersion[:greatestVersion.rfind('-')] + "\n");
97
98if errorsOccurred:
99	sys.exit(1)
100
101finalizedNewFile = "".join(newFileForJam).encode('UTF-8')
102with open(args_jamf, 'wb') as f:
103	f.write(finalizedNewFile)
104
105listhash = hashlib.sha256(finalizedNewFile).hexdigest()
106try:
107	os.mkdir(args_dst + listhash)
108except:
109	print("dir " + listhash + " already exists. No changes?")
110	sys.exit(1)
111
112repodir = args_dst + listhash + '/'
113os.symlink('../packages', repodir + 'packages')
114
115with open(args_dst + 'repo.info.template', 'r') as ritf:
116	repoInfoTemplate = ritf.read()
117
118repoInfoTemplate = repoInfoTemplate.replace("$ARCH$", args_arch)
119with open(repodir + 'repo.info', 'w') as rinf:
120	rinf.write(repoInfoTemplate)
121
122packageFiles.sort()
123with open(repodir + 'package.list', 'w') as pkgl:
124	pkgl.write("\n".join(packageFiles))
125
126if os.system('cd ' + repodir + ' && package_repo create repo.info ' + " ".join(packageFiles)) != 0:
127	print("failed to create package repo.")
128	sys.exit(1)
129
130if os.system('cd ' + repodir + ' && sha256sum repo >repo.sha256') != 0:
131	print("failed to checksum package repo.")
132	sys.exit(1)
133