| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  | """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. | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2013-09-27 09:11:21 -04:00
										 |  |  | from __future__ import with_statement | 
					
						
							| 
									
										
										
										
											2012-04-27 11:56:30 -04:00
										 |  |  | import errno | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  | import os | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  | import time | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | def parse_config(repo): | 
					
						
							| 
									
										
										
										
											2012-04-27 11:56:30 -04:00
										 |  |  |     try: | 
					
						
							|  |  |  |         fp = repo.wfile(".hgtouch") | 
					
						
							|  |  |  |     except IOError, e: | 
					
						
							|  |  |  |         if e.errno != errno.ENOENT: | 
					
						
							|  |  |  |             raise | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |         return {} | 
					
						
							|  |  |  |     result = {} | 
					
						
							| 
									
										
										
										
											2012-04-27 11:56:30 -04:00
										 |  |  |     with fp: | 
					
						
							|  |  |  |         for line in fp: | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |             # 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  | def check_rule(ui, repo, modified, basedir, output, inputs): | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |     """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 | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  |     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)) | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |     try: | 
					
						
							|  |  |  |         o_time = os.stat(f_output).st_mtime | 
					
						
							|  |  |  |     except OSError: | 
					
						
							|  |  |  |         ui.warn("Generated file %s does not exist\n" % output) | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |         return False, 0 | 
					
						
							|  |  |  |     youngest = 0   # youngest dependency | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |     backdate = None | 
					
						
							|  |  |  |     backdate_source = None | 
					
						
							|  |  |  |     for i in inputs: | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  |         f_i = repo.wjoin(os.path.join(basedir, i)) | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |         try: | 
					
						
							|  |  |  |             i_time = os.stat(f_i).st_mtime | 
					
						
							|  |  |  |         except OSError: | 
					
						
							|  |  |  |             ui.warn(".hgtouch input file %s does not exist\n" % i) | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |             return False, 0 | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |         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 | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |         youngest = max(i_time, youngest) | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |     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)) | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |         return False, 0 | 
					
						
							|  |  |  |     if youngest >= o_time: | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |         ui.note("Touching %s\n" % output) | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |         youngest += 1 | 
					
						
							|  |  |  |         os.utime(f_output, (youngest, youngest)) | 
					
						
							|  |  |  |         return True, youngest | 
					
						
							|  |  |  |     else: | 
					
						
							|  |  |  |         # Nothing to update | 
					
						
							|  |  |  |         return True, 0 | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  | 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] | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |     dependencies = parse_config(repo) | 
					
						
							|  |  |  |     success = True | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |     tstamp = 0       # newest time stamp assigned | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |     # 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 | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  |         _success, _tstamp = check_rule(ui, repo, modified, basedir, output, inputs) | 
					
						
							|  |  |  |         success = success and _success | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |         tstamp = max(tstamp, _tstamp) | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |         # put back held back rules | 
					
						
							|  |  |  |         dependencies.update(hold_back) | 
					
						
							|  |  |  |         hold_back = {} | 
					
						
							| 
									
										
										
										
											2013-09-30 16:09:44 +02:00
										 |  |  |     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) | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |     if hold_back: | 
					
						
							|  |  |  |         ui.warn("Cyclic dependency involving %s\n" % (' '.join(hold_back.keys()))) | 
					
						
							|  |  |  |         return False | 
					
						
							|  |  |  |     return success | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  | def touch(ui, repo, basedir): | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  |     "touch generated files that are older than their sources after an update." | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  |     do_touch(ui, repo, basedir) | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | cmdtable = { | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  |     "touch": (touch, | 
					
						
							| 
									
										
										
										
											2014-03-09 10:22:10 +01:00
										 |  |  |               [('b', 'basedir', '', 'base dir of the tree to apply touching')], | 
					
						
							| 
									
										
										
										
											2014-01-27 08:22:49 +01:00
										 |  |  |               "hg touch [-b BASEDIR]") | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  | } |