def _do_cmdline(args): original_dir = os.getcwd() dry_run = False # TODO: allow switches after args. while args: word = args[0] if word in ('-h', '--help', '-?'): print __doc__ return elif word in ('--dry-run', '-n'): dry_run = True elif word[0] == '-': raise GiveUp, "Unexpected command line option %s"%word else: break args = args[1:] if len(args) != 1: raise GiveUp, "Incorrect non-option argument count (expected 1, the email destination)" email_dest = args[0] builder = find_and_load(original_dir, muddle_binary=None) # Don't bother determining muddle_binary: our invocation of find_and_load # doesn't make use of it. (Tibs writes: it's only needed for when # running makefiles, for when they use $(MUDDLE).) if not builder: raise GiveUp("Cannot find a build tree.") rootrepo = builder.db.RootRepository_pathfile.get() repo = parse_repo_url(rootrepo) rules = builder.all_checkout_rules() dirs = [] for r in rules: key = r.target # Unfortunately, we do not currently support subdomains if key.domain: continue rel_dir = builder.db.get_checkout_location(key) if rel_dir.startswith("src/"): # as it should rel_dir = rel_dir[4:] dirs.append(rel_dir) # in testing, use dirs[0:2] (or something similarly small) in place of dirs. repo.run_script(dirs, builder.build_name, email_dest, dry_run)
def _do_cmdline(args): original_dir = os.getcwd() dry_run = False # TODO: allow switches after args. while args: word = args[0] if word in ('-h', '--help', '-?'): print __doc__ return elif word in ('--dry-run', '-n'): dry_run = True elif word[0] == '-': raise GiveUp, "Unexpected command line option %s" % word else: break args = args[1:] if len(args) != 1: raise GiveUp, "Incorrect non-option argument count (expected 1, the email destination)" email_dest = args[0] builder = find_and_load(original_dir, muddle_binary=None) # Don't bother determining muddle_binary: our invocation of find_and_load # doesn't make use of it. (Tibs writes: it's only needed for when # running makefiles, for when they use $(MUDDLE).) if not builder: raise GiveUp("Cannot find a build tree.") rootrepo = builder.db.RootRepository_pathfile.get() repo = parse_repo_url(rootrepo) rules = builder.all_checkout_rules() dirs = [] for r in rules: key = r.target # Unfortunately, we do not currently support subdomains if key.domain: continue rel_dir = builder.db.get_checkout_location(key) if rel_dir.startswith("src/"): # as it should rel_dir = rel_dir[4:] dirs.append(rel_dir) # in testing, use dirs[0:2] (or something similarly small) in place of dirs. repo.run_script(dirs, builder.build_name, email_dest, dry_run)
def process(goals): if goals and goals[0] in ('-h', '-help', '--help'): print __doc__ sys.exit(0) ## ... find a build tree original_dir = os.getcwd() gbuilder = find_and_load(original_dir, muddle_binary=None) # Don't bother determining muddle_binary: our invocation of find_and_load # doesn't make use of it. (Tibs writes: it's only needed for when # running makefiles, for when they use $(MUDDLE).) if not gbuilder: raise GiveUp('Not in a muddle build tree') if not goals: print '# No goals given: assuming default deployments' default_deployment_labels = gbuilder.default_deployment_labels goals = map(str, default_deployment_labels) print '# %s'%', '.join(goals) if not goals: raise GiveUp('No goals given, and no default deployments. Giving up.') # Do we care about labelling the edges? hideEdgeLabels = True # Do we care about nodes touching an AptGetBuilder? omitAptGetNodes = True full_goals = [] for g in goals: labels = gbuilder.label_from_fragment(g, default_type=LabelType.Package) for label in labels: if gbuilder.target_label_exists(label): full_goals.append(str(label)) if not full_goals: raise GiveUp("None of the given goals %s is a target"%(map(str, goals))) for g in full_goals: Node(g, isGoal=True, extras="shape=parallelogram") # color=green fillcolor=green style=filled...? for g in full_goals: do_deps(gbuilder, g) # Nodes created by AptGetBuilders aren't very interesting. if omitAptGetNodes: for k,e in Edge.all_edges.items(): if e.nodeFrom.isAptGet: del Edge.all_edges[k] for k,n in Node.all_nodes.items(): if n.isAptGet: del Node.all_nodes[k] # If we have A/preconfig -> A/configured -> A/built -> A/installed # [ -> A/preinstalled], we can condense them into one. reductio = { 'preconfig' : 'configured', 'configured' : 'built', 'built' : 'installed', 'installed' : 'postinstalled', } while True: madeChange = False for k,e in Edge.all_edges.items(): if e.nodeTo.isGoal: continue # Don't conflate explicit goal nodes nFrom = e.nodeFrom.rawname.rsplit('/',1) nTo = e.nodeTo.rawname.rsplit('/',1) if not nFrom[0] == nTo[0]: continue # labels are not the same, no chance of reduction # TODO: This logic is horrible! reducable = False try: if reductio[nFrom[1]] == nTo[1]: reducable = True except KeyError: pass for aux in e.nodeFrom.auxNames: try: auxFrom = aux.rsplit('/',1) assert auxFrom[0] == nFrom[0] if reductio[auxFrom[1]] == nTo[1]: reducable = True break except KeyError: pass if not reducable: continue # Are there any other edges to nodeTo? If so, we can't reduce. count = 0 for ee in Edge.all_edges.values(): if ee.nodeTo.rawname == e.nodeTo.rawname: count=count+1 if count > 1: # NOTE: This code path is untested... continue # OK, it's safe to conflate the two. #print "WOULD REDUCE: %s -> %s" %(e.nodeFrom.rawname,e.nodeTo.rawname) oldname = e.nodeFrom.displayname if e.nodeTo.displayname.find('+') != -1: substr = e.nodeTo.displayname.rsplit('/')[1] e.nodeFrom.displayname = "%s+%s" %(e.nodeFrom.displayname, substr) else: e.nodeFrom.displayname = "%s+%s" %(e.nodeFrom.displayname, nTo[1]) #print "RENAME: %s => %s"%(oldname, e.nodeFrom.displayname) e.nodeFrom.auxNames.add(e.nodeTo.rawname) e.nodeFrom.auxNames |= e.nodeTo.auxNames # Now kill all nodes B->C, replace with A'->C: for kk,ee in Edge.all_edges.items(): if ee.nodeFrom == e.nodeTo: Edge(e.nodeFrom, ee.nodeTo, e.label) del Edge.all_edges[kk] # Finally, kill off edge A->B and node B themselves: del Edge.all_edges[k] del Node.all_nodes[e.nodeTo.rawname] madeChange = True break if not madeChange: break # else loop forever # Now tidy up the conflated display names: for n in Node.all_nodes.values(): if len(n.auxNames)>0: tmp = n.displayname.rsplit('/',1) n.displayname = '%s/\\n%s'%(tmp[0],tmp[1]) print 'digraph muddle {' print "\n# Nodes" print "node [shape=box];" for n in Node.all_nodes.values(): print n.todot() print "\n# Edges" print "edge [fontsize=9, labelangle=90, decorate=true];" for e in Edge.all_edges.values(): print e.todot(hideEdgeLabels) print '}'
def process(args): goals = [] omitCheckouts = False shortLabels = False while args: word = args.pop(0) if word in ('-h', '-help', '--help'): print __doc__ return elif word in ('--hide-checkouts'): omitCheckouts = True elif word in ('--short-labels'): shortLabels = True elif word[0] == '-': print 'Unrecognised switch', word return else: goals.append(word) ## ... find a build tree original_dir = os.getcwd() gbuilder = find_and_load(original_dir, muddle_binary=None) # Don't bother determining muddle_binary: our invocation of find_and_load # doesn't make use of it. (Tibs writes: it's only needed for when # running makefiles, for when they use $(MUDDLE).) if not gbuilder: raise GiveUp('Not in a muddle build tree') if not goals: print '# No goals given: assuming default deployments' default_deployment_labels = gbuilder.default_deployment_labels goals = map(str, default_deployment_labels) print '# %s' % ', '.join(goals) if not goals: raise GiveUp('No goals given, and no default deployments. Giving up.') # Do we care about labelling the edges? hideEdgeLabels = True # Do we care about nodes touching an AptGetBuilder? omitAptGetNodes = True full_goals = [] for g in goals: labels = gbuilder.label_from_fragment(g, default_type=LabelType.Package) for label in labels: if gbuilder.target_label_exists(label): full_goals.append(str(label)) if not full_goals: raise GiveUp("None of the given goals %s is a target" % (map(str, goals))) for g in full_goals: Node(g, isGoal=True, extras="shape=parallelogram, fillcolor=gold") # color=green fillcolor=green style=filled...? for g in full_goals: do_deps(gbuilder, g) # Nodes created by AptGetBuilders aren't very interesting. if omitAptGetNodes: for k, e in Edge.all_edges.items(): if e.nodeFrom.isAptGet: del Edge.all_edges[k] for k, n in Node.all_nodes.items(): if n.isAptGet: del Node.all_nodes[k] # Maybe don't bother with checkouts either if omitCheckouts: for k, e in Edge.all_edges.items(): if e.nodeFrom.isCheckout: del Edge.all_edges[k] for k, n in Node.all_nodes.items(): if n.isCheckout: del Node.all_nodes[k] # If we have A/preconfig -> A/configured -> A/built -> A/installed # [ -> A/preinstalled], we can condense them into one. reductio = { 'preconfig': 'configured', 'configured': 'built', 'built': 'installed', 'installed': 'postinstalled', } while True: madeChange = False for k, e in Edge.all_edges.items(): if e.nodeTo.isGoal: continue # Don't conflate explicit goal nodes nFrom = e.nodeFrom.rawname.rsplit('/', 1) nTo = e.nodeTo.rawname.rsplit('/', 1) if not nFrom[0] == nTo[0]: continue # labels are not the same, no chance of reduction # TODO: This logic is horrible! reducable = False try: if reductio[nFrom[1]] == nTo[1]: reducable = True except KeyError: pass for aux in e.nodeFrom.auxNames: try: auxFrom = aux.rsplit('/', 1) assert auxFrom[0] == nFrom[0] if reductio[auxFrom[1]] == nTo[1]: reducable = True break except KeyError: pass if not reducable: continue # Are there any other edges to nodeTo? If so, we can't reduce. count = 0 for ee in Edge.all_edges.values(): if ee.nodeTo.rawname == e.nodeTo.rawname: count = count + 1 if count > 1: # NOTE: This code path is untested... continue # OK, it's safe to conflate the two. #print "WOULD REDUCE: %s -> %s" %(e.nodeFrom.rawname,e.nodeTo.rawname) oldname = e.nodeFrom.displayname if e.nodeTo.displayname.find('+') != -1: substr = e.nodeTo.displayname.rsplit('/')[1] e.nodeFrom.displayname = "%s+%s" % (e.nodeFrom.displayname, substr) else: e.nodeFrom.displayname = "%s+%s" % (e.nodeFrom.displayname, nTo[1]) #print "RENAME: %s => %s"%(oldname, e.nodeFrom.displayname) e.nodeFrom.auxNames.add(e.nodeTo.rawname) e.nodeFrom.auxNames |= e.nodeTo.auxNames # Now kill all nodes B->C, replace with A'->C: for kk, ee in Edge.all_edges.items(): if ee.nodeFrom == e.nodeTo: Edge(e.nodeFrom, ee.nodeTo, e.label) del Edge.all_edges[kk] # Finally, kill off edge A->B and node B themselves: del Edge.all_edges[k] del Node.all_nodes[e.nodeTo.rawname] madeChange = True break if not madeChange: break # else loop forever # Now tidy up the conflated display names: if shortLabels: for n in Node.all_nodes.values(): n.displayname = n.displayname.rsplit('/', 1)[0] if n.displayname.startswith('package:'): n.displayname = n.displayname[8:] else: for n in Node.all_nodes.values(): if len(n.auxNames) > 0: tmp = n.displayname.rsplit('/', 1) n.displayname = '%s/\\n%s' % (tmp[0], tmp[1]) print 'digraph muddle {' print "\n# Nodes" print "node [shape=box];" for n in Node.all_nodes.values(): print n.todot() print "\n# Edges" print "edge [fontsize=9, labelangle=90, decorate=true];" for e in Edge.all_edges.values(): print e.todot(hideEdgeLabels) print '}'
def _do_cmdline(args): original_dir = os.getcwd() original_env = os.environ.copy() dry_run = False verbose = False # TODO: allow switches after args. while args: word = args[0] if word in ("-h", "--help", "-?"): print __doc__ return elif word in ("--dry-run", "-n"): dry_run = True elif word in ("-v", "--verbose"): verbose = True elif word[0] == "-": raise GiveUp, "Unexpected command line option %s" % word else: break args = args[1:] if len(args) != 0: raise GiveUp, "Unexpected non-option arguments given" builder = find_and_load(original_dir, muddle_binary=None) # Don't bother determining muddle_binary: our invocation of find_and_load # doesn't make use of it. (Tibs writes: it's only needed for when # running makefiles, for when they use $(MUDDLE).) if not builder: raise GiveUp("Cannot find a build tree.") rootrepo = builder.db.RootRepository_pathfile.get() rules = builder.all_checkout_rules() rr = [] for r in rules: co_dir = builder.db.get_checkout_path(r.target) if isinstance(r.action.vcs, muddled.vcs.git.Git): if verbose: print "In %s:" % co_dir os.chdir(co_dir) raw = get_cmd_data("git show-ref --heads", verbose=verbose) raw_heads = raw[1].rstrip("\n").split("\n") pat = re.compile("[0-9a-f]+ refs/heads/(.+)") heads = set() for h in raw_heads: m = pat.match(h) if m is None: raise GiveUp("Unparseable output from git: %s" % h) heads.add(m.group(1)) g = r.action.vcs # print "heads is %s"%heads.__str__() if g.branch is not None: if g.branch in heads: if verbose: print "%s: ok (has %s)" % (co_dir, g.branch) else: bfrom = "master" # desired branch not found; if we have a master then try to fixup: if bfrom in heads: # if verbose: print "===\nFixing %s: %s --> %s" % (co_dir, bfrom, g.branch) (rc, lines, igno) = get_cmd_data("git status --porcelain -uall", verbose=verbose) lines = lines.rstrip("\n") if lines != "": if not verbose: print "> git status --porcelain -uall" print ">>%s<<" % lines print ( "Uncommitted changes or untracked files found in %s, deal with these before continuing" % co_dir ) raise GiveUp maybe_run_cmd("git fetch origin %s" % (g.branch), dry_run, verbose) maybe_run_cmd("git fetch origin %s:%s" % (g.branch, g.branch), dry_run, verbose) maybe_run_cmd("git checkout %s" % g.branch, dry_run, verbose) maybe_run_cmd("git config branch.%s.remote origin" % g.branch, dry_run, verbose) maybe_run_cmd("git config branch.%s.merge %s" % (g.branch, g.branch), dry_run, verbose) try: maybe_run_cmd("git branch -d %s" % bfrom, dry_run, verbose) except GiveUp: print "\n* * * HEALTH WARNING * * *" print "Unmerged changes were found committed to the '%s' branch in %s" % (bfrom, co_dir) print "YOU MUST MERGE THESE INTO '%s' YOURSELF OR LOSE THEM!" % g.branch # print "This script will not revisit this checkout." print "The relevant changes are:" run0("git log --oneline --topo-order --graph --decorate=short %s..%s" % (g.branch, bfrom)) raise else: raise GiveUp( "Error: %s wants a branch named '%s', does not have one, and does not have a '%s' either - I don't know how to fix this" % (co_dir, g.branch, bfrom) ) else: # want master, don't care about others if verbose: print "%s heads are: %s" % (co_dir, heads) if not "master" in heads: raise GiveUp( "Error: %s wants a 'master' branch but does not have one, I don't know how to fix this" % co_dir ) else: if verbose: print "Ignoring %s (not powered by git)" % co_dir