diff --git a/.hgtouch b/.hgtouch new file mode 100644 index 00000000000..ad936fad736 --- /dev/null +++ b/.hgtouch @@ -0,0 +1,12 @@ +# -*- Makefile -*- +# Define dependencies of generated files that are checked into hg. +# The syntax of this file uses make rule dependencies, without actions + +Python/importlib.h: Lib/importlib/_bootstrap.py Python/freeze_importlib.py + +Include/ast.h: Parser/Python.asdl Parser/asdl.py Parser/asdl_c.py +Python/Python-ast.c: Include/ast.h + +Python/opcode_targets.h: Python/makeopcodetargets.py Lib/opcode.py + +Objects/typeslots.inc: Include/typeslots.h Objects/typeslots.py \ No newline at end of file diff --git a/Makefile.pre.in b/Makefile.pre.in index e6b37f85eca..38ffa34ff32 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1337,6 +1337,10 @@ TAGS:: etags Include/*.h; \ for i in $(SRCDIRS); do etags -a $$i/*.[ch]; done +# Touch generated files +touch: + hg --config extensions.touch=Tools/hg/hgtouch.py touch -v + # Sanitation targets -- clean leaves libraries, executables and tags # files, which clobber removes as well pycremoval: @@ -1445,7 +1449,7 @@ Python/thread.o: @THREADHEADERS@ .PHONY: frameworkinstall frameworkinstallframework frameworkinstallstructure .PHONY: frameworkinstallmaclib frameworkinstallapps frameworkinstallunixtools .PHONY: frameworkaltinstallunixtools recheck autoconf clean clobber distclean -.PHONY: smelly funny patchcheck +.PHONY: smelly funny patchcheck touch .PHONY: gdbhooks # IF YOU PUT ANYTHING HERE IT WILL GO AWAY diff --git a/Misc/NEWS b/Misc/NEWS index 21cead03115..c4da5b09a67 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -176,6 +176,12 @@ Library - Issue #14493: Use gvfs-open or xdg-open in webbrowser. +Build +----- + +- "make touch" will now touch generated files that are checked into Mercurial, + after a "hg update" which failed to bring the timestamps into the right order. + Tests ----- diff --git a/Tools/hg/hgtouch.py b/Tools/hg/hgtouch.py new file mode 100644 index 00000000000..c7fde1057d4 --- /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") +}