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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134
|
#!/usr/bin/python3 -B
#/***************************************************************************
# * Copyright (C) 2019 Daniel Mueller (deso@posteo.net) *
# * *
# * This program is free software: you can redistribute it and/or modify *
# * it under the terms of the GNU General Public License as published by *
# * the Free Software Foundation, either version 3 of the License, or *
# * (at your option) any later version. *
# * *
# * This program is distributed in the hope that it will be useful, *
# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
# * GNU General Public License for more details. *
# * *
# * You should have received a copy of the GNU General Public License *
# * along with this program. If not, see <http://www.gnu.org/licenses/>. *
# ***************************************************************************/
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 d:
cwd = join(d, "nitrocli")
check_call(["git", "clone", root, d])
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:]))
|