Skip to content

Commit

Permalink
Issue python#14642: Add "hg touch" extension, and "make touch" target.
Browse files Browse the repository at this point in the history
  • Loading branch information
loewis committed Apr 27, 2012
1 parent 8f82506 commit cfc1cc2
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 1 deletion.
12 changes: 12 additions & 0 deletions .hgtouch
Original file line number Diff line number Diff line change
@@ -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
6 changes: 5 additions & 1 deletion Makefile.pre.in
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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
Expand Down
6 changes: 6 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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
-----

Expand Down
99 changes: 99 additions & 0 deletions Tools/hg/hgtouch.py
Original file line number Diff line number Diff line change
@@ -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")
}

0 comments on commit cfc1cc2

Please sign in to comment.