summaryrefslogtreecommitdiffstats
path: root/Tools/hg/hgtouch.py
diff options
context:
space:
mode:
Diffstat (limited to 'Tools/hg/hgtouch.py')
-rw-r--r--Tools/hg/hgtouch.py103
1 files changed, 103 insertions, 0 deletions
diff --git a/Tools/hg/hgtouch.py b/Tools/hg/hgtouch.py
new file mode 100644
index 0000000..5961a10
--- /dev/null
+++ b/Tools/hg/hgtouch.py
@@ -0,0 +1,103 @@
+"""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 errno
+import os
+
+def parse_config(repo):
+ try:
+ fp = repo.wfile(".hgtouch")
+ except IOError, e:
+ if e.errno != errno.ENOENT:
+ raise
+ return {}
+ result = {}
+ with fp:
+ for line in fp:
+ # 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")
+}