1*4882a593Smuzhiyun#!/usr/bin/env python3 2*4882a593Smuzhiyun 3*4882a593Smuzhiyun# Report significant differences in the buildhistory repository since a specific revision 4*4882a593Smuzhiyun# 5*4882a593Smuzhiyun# Copyright (C) 2013 Intel Corporation 6*4882a593Smuzhiyun# Author: Paul Eggleton <paul.eggleton@linux.intel.com> 7*4882a593Smuzhiyun# 8*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0-only 9*4882a593Smuzhiyun# 10*4882a593Smuzhiyun 11*4882a593Smuzhiyunimport sys 12*4882a593Smuzhiyunimport os 13*4882a593Smuzhiyunimport argparse 14*4882a593Smuzhiyun 15*4882a593Smuzhiyun# Ensure PythonGit is installed (buildhistory_analysis needs it) 16*4882a593Smuzhiyuntry: 17*4882a593Smuzhiyun import git 18*4882a593Smuzhiyunexcept ImportError: 19*4882a593Smuzhiyun print("Please install GitPython (python3-git) 0.3.4 or later in order to use this script") 20*4882a593Smuzhiyun sys.exit(1) 21*4882a593Smuzhiyun 22*4882a593Smuzhiyundef get_args_parser(): 23*4882a593Smuzhiyun description = "Reports significant differences in the buildhistory repository." 24*4882a593Smuzhiyun 25*4882a593Smuzhiyun parser = argparse.ArgumentParser(description=description, 26*4882a593Smuzhiyun usage=""" 27*4882a593Smuzhiyun %(prog)s [options] [from-revision [to-revision]] 28*4882a593Smuzhiyun (if not specified, from-revision defaults to build-minus-1, and to-revision defaults to HEAD)""") 29*4882a593Smuzhiyun 30*4882a593Smuzhiyun default_dir = os.path.join(os.environ.get('BUILDDIR', '.'), 'buildhistory') 31*4882a593Smuzhiyun 32*4882a593Smuzhiyun parser.add_argument('-p', '--buildhistory-dir', 33*4882a593Smuzhiyun action='store', 34*4882a593Smuzhiyun dest='buildhistory_dir', 35*4882a593Smuzhiyun default=default_dir, 36*4882a593Smuzhiyun help="Specify path to buildhistory directory (defaults to buildhistory/ under cwd)") 37*4882a593Smuzhiyun parser.add_argument('-v', '--report-version', 38*4882a593Smuzhiyun action='store_true', 39*4882a593Smuzhiyun dest='report_ver', 40*4882a593Smuzhiyun default=False, 41*4882a593Smuzhiyun help="Report changes in PKGE/PKGV/PKGR even when the values are still the default (PE/PV/PR)") 42*4882a593Smuzhiyun parser.add_argument('-a', '--report-all', 43*4882a593Smuzhiyun action='store_true', 44*4882a593Smuzhiyun dest='report_all', 45*4882a593Smuzhiyun default=False, 46*4882a593Smuzhiyun help="Report all changes, not just the default significant ones") 47*4882a593Smuzhiyun parser.add_argument('-s', '---signatures', 48*4882a593Smuzhiyun action='store_true', 49*4882a593Smuzhiyun dest='sigs', 50*4882a593Smuzhiyun default=False, 51*4882a593Smuzhiyun help="Report list of signatures differing instead of output") 52*4882a593Smuzhiyun parser.add_argument('-S', '--signatures-with-diff', 53*4882a593Smuzhiyun action='store_true', 54*4882a593Smuzhiyun dest='sigsdiff', 55*4882a593Smuzhiyun default=False, 56*4882a593Smuzhiyun help="Report on actual signature differences instead of output (requires signature data to have been generated, either by running the actual tasks or using bitbake -S)") 57*4882a593Smuzhiyun parser.add_argument('-e', '--exclude-path', 58*4882a593Smuzhiyun action='append', 59*4882a593Smuzhiyun help="Exclude path from the output") 60*4882a593Smuzhiyun parser.add_argument('-c', '--colour', 61*4882a593Smuzhiyun choices=('yes', 'no', 'auto'), 62*4882a593Smuzhiyun default="auto", 63*4882a593Smuzhiyun help="Whether to colourise (defaults to auto)") 64*4882a593Smuzhiyun parser.add_argument('revisions', 65*4882a593Smuzhiyun default = ['build-minus-1', 'HEAD'], 66*4882a593Smuzhiyun nargs='*', 67*4882a593Smuzhiyun help=argparse.SUPPRESS) 68*4882a593Smuzhiyun return parser 69*4882a593Smuzhiyun 70*4882a593Smuzhiyundef main(): 71*4882a593Smuzhiyun 72*4882a593Smuzhiyun parser = get_args_parser() 73*4882a593Smuzhiyun args = parser.parse_args() 74*4882a593Smuzhiyun 75*4882a593Smuzhiyun if len(args.revisions) > 2: 76*4882a593Smuzhiyun sys.stderr.write('Invalid argument(s) specified: %s\n\n' % ' '.join(args.revisions[2:])) 77*4882a593Smuzhiyun parser.print_help() 78*4882a593Smuzhiyun 79*4882a593Smuzhiyun sys.exit(1) 80*4882a593Smuzhiyun 81*4882a593Smuzhiyun if not os.path.exists(args.buildhistory_dir): 82*4882a593Smuzhiyun sys.stderr.write('Buildhistory directory "%s" does not exist\n\n' % args.buildhistory_dir) 83*4882a593Smuzhiyun parser.print_help() 84*4882a593Smuzhiyun sys.exit(1) 85*4882a593Smuzhiyun 86*4882a593Smuzhiyun scripts_path = os.path.abspath(os.path.dirname(os.path.abspath(sys.argv[0]))) 87*4882a593Smuzhiyun lib_path = scripts_path + '/lib' 88*4882a593Smuzhiyun sys.path = sys.path + [lib_path] 89*4882a593Smuzhiyun 90*4882a593Smuzhiyun import scriptpath 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun # Set path to OE lib dir so we can import the buildhistory_analysis module 93*4882a593Smuzhiyun scriptpath.add_oe_lib_path() 94*4882a593Smuzhiyun # Set path to bitbake lib dir so the buildhistory_analysis module can load bb.utils 95*4882a593Smuzhiyun bitbakepath = scriptpath.add_bitbake_lib_path() 96*4882a593Smuzhiyun 97*4882a593Smuzhiyun if not bitbakepath: 98*4882a593Smuzhiyun sys.stderr.write("Unable to find bitbake by searching parent directory of this script or PATH\n") 99*4882a593Smuzhiyun sys.exit(1) 100*4882a593Smuzhiyun 101*4882a593Smuzhiyun if len(args.revisions) == 1: 102*4882a593Smuzhiyun if '..' in args.revisions[0]: 103*4882a593Smuzhiyun fromrev, torev = args.revisions[0].split('..') 104*4882a593Smuzhiyun else: 105*4882a593Smuzhiyun fromrev, torev = args.revisions[0], 'HEAD' 106*4882a593Smuzhiyun elif len(args.revisions) == 2: 107*4882a593Smuzhiyun fromrev, torev = args.revisions 108*4882a593Smuzhiyun 109*4882a593Smuzhiyun from oe.buildhistory_analysis import init_colours, process_changes 110*4882a593Smuzhiyun import gitdb 111*4882a593Smuzhiyun 112*4882a593Smuzhiyun init_colours({"yes": True, "no": False, "auto": sys.stdout.isatty()}[args.colour]) 113*4882a593Smuzhiyun 114*4882a593Smuzhiyun try: 115*4882a593Smuzhiyun changes = process_changes(args.buildhistory_dir, fromrev, torev, 116*4882a593Smuzhiyun args.report_all, args.report_ver, args.sigs, 117*4882a593Smuzhiyun args.sigsdiff, args.exclude_path) 118*4882a593Smuzhiyun except gitdb.exc.BadObject as e: 119*4882a593Smuzhiyun if not args.revisions: 120*4882a593Smuzhiyun sys.stderr.write("Unable to find previous build revision in buildhistory repository\n\n") 121*4882a593Smuzhiyun parser.print_help() 122*4882a593Smuzhiyun else: 123*4882a593Smuzhiyun sys.stderr.write('Specified git revision "%s" is not valid\n' % e.args[0]) 124*4882a593Smuzhiyun sys.exit(1) 125*4882a593Smuzhiyun 126*4882a593Smuzhiyun for chg in changes: 127*4882a593Smuzhiyun out = str(chg) 128*4882a593Smuzhiyun if out: 129*4882a593Smuzhiyun print(out) 130*4882a593Smuzhiyun 131*4882a593Smuzhiyun sys.exit(0) 132*4882a593Smuzhiyun 133*4882a593Smuzhiyunif __name__ == "__main__": 134*4882a593Smuzhiyun main() 135