| 
									
										
										
										
											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. | 
					
						
							|  |  |  | """
 | 
					
						
							| 
									
										
										
										
											2012-04-27 11:56:30 -04:00
										 |  |  | import errno | 
					
						
							| 
									
										
										
										
											2012-04-27 16:10:21 +02:00
										 |  |  | import os | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 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") | 
					
						
							|  |  |  | } |