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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
#!/usr/bin/python3 -B
# Copyright (C) 2019-2020 The Nitrocli Developers
# SPDX-License-Identifier: GPL-3.0-or-later
from argparse import (
ArgumentParser,
ArgumentTypeError,
)
from concurrent.futures import (
ThreadPoolExecutor,
)
from json import (
loads as jsonLoad,
)
from os import (
stat,
)
from os.path import (
join,
)
from subprocess import (
check_call,
check_output,
)
from sys import (
argv,
exit,
)
from tempfile import (
TemporaryDirectory,
)
UNITS = {
"byte": 1,
"kib": 1024,
"mib": 1024 * 1024,
}
def unit(string):
"""Create a unit."""
if string in UNITS:
return UNITS[string]
else:
raise ArgumentTypeError("Invalid unit: \"%s\"." % string)
def nitrocliPath(cwd):
"""Determine the path to the nitrocli release build binary."""
out = check_output(["cargo", "metadata", "--format-version=1"], cwd=cwd)
data = jsonLoad(out)
return join(data["target_directory"], "release", "nitrocli")
def fileSize(path):
"""Determine the size of the file at the given path."""
return stat(path).st_size
def repoRoot():
"""Retrieve the root directory of the current git repository."""
out = check_output(["git", "rev-parse", "--show-toplevel"])
return out.decode().strip()
def resolveCommit(commit):
"""Resolve a commit into a SHA1 hash."""
out = check_output(["git", "rev-parse", "--verify", "%s^{commit}" % commit])
return out.decode().strip()
def determineSizeAt(root, rev):
"""Determine the size of the nitrocli release build binary at the given git revision."""
sha1 = resolveCommit(rev)
with TemporaryDirectory() as cwd:
check_call(["git", "clone", root, cwd])
check_call(["git", "checkout", "--quiet", sha1], cwd=cwd)
check_call(["cargo", "build", "--quiet", "--release"], cwd=cwd)
ncli = nitrocliPath(cwd)
check_call(["strip", ncli])
return fileSize(ncli)
def setupArgumentParser():
"""Create and initialize an argument parser."""
parser = ArgumentParser()
parser.add_argument(
"revs", metavar="REVS", nargs="+",
help="The revisions at which to measure the release binary size.",
)
parser.add_argument(
"-u", "--unit", default="byte", dest="unit", metavar="UNIT", type=unit,
help="The unit in which to output the result (%s)." % "|".join(UNITS.keys()),
)
return parser
def main(args):
"""Determine the size of the nitrocli binary at given git revisions."""
parser = setupArgumentParser()
ns = parser.parse_args(args)
root = repoRoot()
futures = []
executor = ThreadPoolExecutor()
for rev in ns.revs:
futures += [executor.submit(lambda r=rev: determineSizeAt(root, r))]
executor.shutdown(wait=True)
for future in futures:
print(int(round(future.result() / ns.unit, 0)))
return 0
if __name__ == "__main__":
exit(main(argv[1:]))
|