diff options
author | Martin v. Loewis <martin@v.loewis.de> | 2012-04-27 16:10:21 +0200 |
---|---|---|
committer | Martin v. Loewis <martin@v.loewis.de> | 2012-04-27 16:10:21 +0200 |
commit | cfc1cc2996fd513aa96ff27060c36f3b5ea9dab5 (patch) | |
tree | dfd9755f1322cfa4f00396980d235caa26176d3a /Tools | |
parent | 8f825060f1c168b913f2ac299ca48d4e9375f34d (diff) | |
download | cpython-git-cfc1cc2996fd513aa96ff27060c36f3b5ea9dab5.tar.gz |
Issue #14642: Add "hg touch" extension, and "make touch" target.
Diffstat (limited to 'Tools')
-rw-r--r-- | Tools/hg/hgtouch.py | 99 |
1 files changed, 99 insertions, 0 deletions
diff --git a/Tools/hg/hgtouch.py b/Tools/hg/hgtouch.py new file mode 100644 index 0000000000..c7fde1057d --- /dev/null +++ b/Tools/hg/hgtouch.py @@ -0,0 +1,99 @@ +"""Bring time stamps of generated checked-in files into the right order + +A versioned configuration file .hgtouch specifies generated files, in the +syntax of make rules. + + output: input1 input2 + +In addition to the dependency syntax, #-comments are supported. +""" +import os + +def parse_config(repo): + configfile = repo.wjoin(".hgtouch") + if not os.path.exists(configfile): + return {} + result = {} + with open(configfile) as f: + for line in f: + # strip comments + line = line.split('#')[0].strip() + if ':' not in line: + continue + outputs, inputs = line.split(':', 1) + outputs = outputs.split() + inputs = inputs.split() + for o in outputs: + try: + result[o].extend(inputs) + except KeyError: + result[o] = inputs + return result + +def check_rule(ui, repo, modified, output, inputs): + f_output = repo.wjoin(output) + try: + o_time = os.stat(f_output).st_mtime + except OSError: + ui.warn("Generated file %s does not exist\n" % output) + return False + need_touch = False + backdate = None + backdate_source = None + for i in inputs: + f_i = repo.wjoin(i) + try: + i_time = os.stat(f_i).st_mtime + except OSError: + ui.warn(".hgtouch input file %s does not exist\n" % i) + return False + if i in modified: + # input is modified. Need to backdate at least to i_time + if backdate is None or backdate > i_time: + backdate = i_time + backdate_source = i + continue + if o_time <= i_time: + # generated file is older, touch + need_touch = True + if backdate is not None: + ui.warn("Input %s for file %s locally modified\n" % (backdate_source, output)) + # set to 1s before oldest modified input + backdate -= 1 + os.utime(f_output, (backdate, backdate)) + return False + if need_touch: + ui.note("Touching %s\n" % output) + os.utime(f_output, None) + return True + +def do_touch(ui, repo): + modified = repo.status()[0] + dependencies = parse_config(repo) + success = True + # try processing all rules in topological order + hold_back = {} + while dependencies: + output, inputs = dependencies.popitem() + # check whether any of the inputs is generated + for i in inputs: + if i in dependencies: + hold_back[output] = inputs + continue + success = check_rule(ui, repo, modified, output, inputs) + # put back held back rules + dependencies.update(hold_back) + hold_back = {} + if hold_back: + ui.warn("Cyclic dependency involving %s\n" % (' '.join(hold_back.keys()))) + return False + return success + +def touch(ui, repo): + "touch generated files that are older than their sources after an update." + do_touch(ui, repo) + +cmdtable = { + "touch": (touch, [], + "touch generated files according to the .hgtouch configuration") +} |