diff options
| -rwxr-xr-x | nitrocli/var/binary-size.py | 134 | 
1 files changed, 134 insertions, 0 deletions
| diff --git a/nitrocli/var/binary-size.py b/nitrocli/var/binary-size.py new file mode 100755 index 0000000..3653814 --- /dev/null +++ b/nitrocli/var/binary-size.py @@ -0,0 +1,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:])) | 
