1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
#!/usr/bin/env python3
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import argparse
import os
import tarfile
from pathlib import Path
from tempfile import TemporaryDirectory
import yaml
from vsdownload import downloadPackages, extractPackages
from zstandard import ZstdCompressor
def tzstd_path(path):
path = Path(path)
if path.suffix not in (".zst", ".zstd") or Path(path.stem).suffix != ".tar":
raise ValueError("F")
return path
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="Download and build a Visual Studio artifact"
)
parser.add_argument("manifest", help="YAML manifest of the contents to download")
parser.add_argument(
"-o", dest="output", type=tzstd_path, required=True, help="Output file"
)
args = parser.parse_args()
with open(args.manifest) as f:
selected = yaml.safe_load(f.read())
with TemporaryDirectory() as tmpdir:
tmpdir = Path(tmpdir)
dl_cache = tmpdir / "cache"
downloadPackages(selected, dl_cache)
unpacked = tmpdir / "unpack"
extractPackages(selected, dl_cache, unpacked)
stem = Path(Path(args.output.stem).stem)
vfs = {}
# Create an archive containing all the paths in lowercase form for
# cross-compiles.
with ZstdCompressor().stream_writer(open(args.output, "wb")) as z, tarfile.open(
mode="w|", fileobj=z
) as tar:
for subpath in ("VC", "Program Files/Windows Kits/10", "DIA SDK"):
dest = subpath
if dest.startswith("Program Files/"):
dest = dest[len("Program Files/") :]
subpath = unpacked / subpath
dest = Path(dest)
for root, dirs, files in os.walk(subpath):
relpath = Path(root).relative_to(subpath)
for f in files:
path = Path(root) / f
info = tar.gettarinfo(path)
with open(path, "rb") as fh:
lower_f = f.lower()
# Ideally, we'd use the overlay for .libs too but as of
# writing it's still impractical to use, so lowercase
# them for now, that'll be enough.
if lower_f.endswith(".lib"):
f = lower_f
info.name = str(stem / dest / relpath / f)
# Set executable flag on .exe files, the Firefox build
# system wants it.
if lower_f.endswith(".exe"):
info.mode |= (info.mode & 0o444) >> 2
print("Adding", info.name)
tar.addfile(info, fh)
if lower_f.endswith((".h", ".idl")):
vfs.setdefault(str(dest / relpath), []).append(f)
# Create an overlay file for use with clang's -ivfsoverlay flag.
overlay = {
"version": 0,
"case-sensitive": False,
"root-relative": "overlay-dir",
"overlay-relative": True,
"roots": [
{
"name": p,
"type": "directory",
"contents": [
{
"name": f,
"type": "file",
"external-contents": f"{p}/{f}",
}
for f in files
],
}
for p, files in vfs.items()
],
}
overlay_yaml = tmpdir / "overlay.yaml"
with overlay_yaml.open("w") as fh:
fh.write(yaml.dump(overlay))
info = tar.gettarinfo(overlay_yaml)
info.name = str(stem / "overlay.yaml")
tar.addfile(info, overlay_yaml.open("rb"))
|