xref: /haiku/src/tools/hardlink_packages.py (revision 8c78892580f132d10e624aef96f835df8d94bf19)
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