versioninfo.py (4569B)
1 #!/usr/bin/env python 2 3 # This Source Code Form is subject to the terms of the Mozilla Public 4 # License, v. 2.0. If a copy of the MPL was not distributed with this file, 5 # You can obtain one at http://mozilla.org/MPL/2.0/. 6 7 """ 8 List mozbase package dependencies or generate changelogs 9 from commit messages. 10 """ 11 12 import argparse 13 import os 14 import subprocess 15 import sys 16 from collections.abc import Iterable 17 18 from packaging.version import Version 19 20 here = os.path.abspath(os.path.dirname(__file__)) 21 sys.path.insert(0, here) 22 23 import setup_development 24 25 26 def run_hg(command): 27 command = command[:] 28 if not isinstance(command, Iterable): 29 command = command.split() 30 command.insert(0, "hg") 31 try: 32 output = subprocess.check_output(command, cwd=here, universal_newlines=True) 33 except subprocess.CalledProcessError: 34 sys.exit(1) 35 return output 36 37 38 def changelog(args): 39 setup = os.path.join(args.module, "setup.py") 40 41 def get_version_rev(v=None): 42 revisions = run_hg(["log", setup, "--template={rev},"]).split(",")[:-1] 43 for rev in revisions: 44 diff = run_hg(["diff", "-c", rev, setup, "-U0"]) 45 minus_version = None 46 plus_version = None 47 for line in diff.splitlines(): 48 if line.startswith("-PACKAGE_VERSION"): 49 try: 50 minus_version = Version(line.split()[-1].strip("\"'")) 51 except ValueError: 52 pass 53 elif line.startswith("+PACKAGE_VERSION"): 54 try: 55 plus_version = Version(line.split()[-1].strip("\"'")) 56 except ValueError: 57 break 58 59 # make sure the change isn't a backout 60 if not minus_version or plus_version > minus_version: 61 if not v: 62 return rev 63 64 if Version(v) == plus_version: 65 return rev 66 67 print( 68 "Could not find %s revision for version %s." % (args.module, v or "latest") 69 ) 70 sys.exit(1) 71 72 from_ref = args.from_ref or get_version_rev() 73 to_ref = args.to_ref or "tip" 74 75 if "." in from_ref: 76 from_ref = get_version_rev(from_ref) 77 if "." in to_ref: 78 to_ref = get_version_rev(to_ref) 79 80 delim = "\x12\x59\x52\x99\x05" 81 changelog = run_hg([ 82 "log", 83 "-r", 84 "%s:children(%s)" % (to_ref, from_ref), 85 "--template={desc}%s" % delim, 86 "-M", 87 args.module, 88 ]).split(delim)[:-1] 89 90 def prettify(desc): 91 lines = desc.splitlines() 92 lines = [("* %s" if i == 0 else " %s") % l for i, l in enumerate(lines)] 93 return "\n".join(lines) 94 95 # pylint --py3k: W1636 96 changelog = list(map(prettify, changelog)) 97 print("\n".join(changelog)) 98 99 100 def dependencies(args): 101 # get package information 102 info = {} 103 dependencies = {} 104 for package in setup_development.mozbase_packages: 105 directory = os.path.join(setup_development.here, package) 106 info[directory] = setup_development.info(directory) 107 name, _dependencies = setup_development.get_dependencies(directory) 108 assert name == info[directory]["Name"] 109 dependencies[name] = _dependencies 110 111 # print package version information 112 for value in info.values(): 113 print( 114 "%s %s : %s" 115 % (value["Name"], value["Version"], ", ".join(dependencies[value["Name"]])) 116 ) 117 118 119 def main(args=sys.argv[1:]): 120 parser = argparse.ArgumentParser() 121 subcommands = parser.add_subparsers(help="Sub-commands") 122 123 p_deps = subcommands.add_parser("dependencies", help="Print dependencies.") 124 p_deps.set_defaults(func=dependencies) 125 126 p_changelog = subcommands.add_parser("changelog", help="Print a changelog.") 127 p_changelog.add_argument("module", help="Module to get changelog from.") 128 p_changelog.add_argument( 129 "--from", 130 dest="from_ref", 131 default=None, 132 help="Starting version or revision to list " 133 "changes from. [defaults to latest version]", 134 ) 135 p_changelog.add_argument( 136 "--to", 137 dest="to_ref", 138 default=None, 139 help="Ending version or revision to list changes to. [defaults to tip]", 140 ) 141 p_changelog.set_defaults(func=changelog) 142 143 # default to showing dependencies 144 if args == []: 145 args.append("dependencies") 146 args = parser.parse_args(args) 147 args.func(args) 148 149 150 if __name__ == "__main__": 151 main()