mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			129 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			129 lines
		
	
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
"""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
 | 
						|
import time
 | 
						|
 | 
						|
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, basedir, output, inputs):
 | 
						|
    """Verify that the output is newer than any of the inputs.
 | 
						|
    Return (status, stamp), where status is True if the update succeeded,
 | 
						|
    and stamp is the newest time stamp assigned  to any file (might be in
 | 
						|
    the future).
 | 
						|
 | 
						|
    If basedir is nonempty, it gives a directory in which the tree is to
 | 
						|
    be checked.
 | 
						|
    """
 | 
						|
    f_output = repo.wjoin(os.path.join(basedir, output))
 | 
						|
    try:
 | 
						|
        o_time = os.stat(f_output).st_mtime
 | 
						|
    except OSError:
 | 
						|
        ui.warn("Generated file %s does not exist\n" % output)
 | 
						|
        return False, 0
 | 
						|
    youngest = 0   # youngest dependency
 | 
						|
    backdate = None
 | 
						|
    backdate_source = None
 | 
						|
    for i in inputs:
 | 
						|
        f_i = repo.wjoin(os.path.join(basedir, 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, 0
 | 
						|
        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
 | 
						|
        youngest = max(i_time, youngest)
 | 
						|
    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, 0
 | 
						|
    if youngest >= o_time:
 | 
						|
        ui.note("Touching %s\n" % output)
 | 
						|
        youngest += 1
 | 
						|
        os.utime(f_output, (youngest, youngest))
 | 
						|
        return True, youngest
 | 
						|
    else:
 | 
						|
        # Nothing to update
 | 
						|
        return True, 0
 | 
						|
 | 
						|
def do_touch(ui, repo, basedir):
 | 
						|
    if basedir:
 | 
						|
        if not os.path.isdir(repo.wjoin(basedir)):
 | 
						|
            ui.warn("Abort: basedir %r does not exist\n" % basedir)
 | 
						|
            return
 | 
						|
        modified = []
 | 
						|
    else:
 | 
						|
        modified = repo.status()[0]
 | 
						|
    dependencies = parse_config(repo)
 | 
						|
    success = True
 | 
						|
    tstamp = 0       # newest time stamp assigned
 | 
						|
    # 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, _tstamp = check_rule(ui, repo, modified, basedir, output, inputs)
 | 
						|
        success = success and _success
 | 
						|
        tstamp = max(tstamp, _tstamp)
 | 
						|
        # put back held back rules
 | 
						|
        dependencies.update(hold_back)
 | 
						|
        hold_back = {}
 | 
						|
    now = time.time()
 | 
						|
    if tstamp > now:
 | 
						|
        # wait until real time has passed the newest time stamp, to
 | 
						|
        # avoid having files dated in the future
 | 
						|
        time.sleep(tstamp-now)
 | 
						|
    if hold_back:
 | 
						|
        ui.warn("Cyclic dependency involving %s\n" % (' '.join(hold_back.keys())))
 | 
						|
        return False
 | 
						|
    return success
 | 
						|
 | 
						|
def touch(ui, repo, basedir):
 | 
						|
    "touch generated files that are older than their sources after an update."
 | 
						|
    do_touch(ui, repo, basedir)
 | 
						|
 | 
						|
cmdtable = {
 | 
						|
    "touch": (touch,
 | 
						|
              [('b', 'basedir', '', 'base dir of the tree to apply touching')],
 | 
						|
              "hg touch [-b BASEDIR]")
 | 
						|
}
 |