1- from collections import defaultdict
21import os , re , sys
32
4- names = set () # names of rules (usually output files)
5- slist = {} # slist[name,i] is one of name's sources
6- scnt = defaultdict (int ) # where i is 1..scnt[name]
7- cmd = defaultdict (str ) # cmd[name] is the shell command to run
8- age = {} # age[file] is file's age (larger is older)
9- visited = {} # tracks visited files in update()
3+ slist = {} # slist[target] is list of target's sources
4+ cmd = {} # cmd[name] is the shell command to run
5+ age = {} # age[file] is file's age (larger is older)
106
117def main ():
128 for line in open ('makefile' ):
139 if re .match ('[A-Za-z]' , line ):
1410 line = line .replace (':' , '' )
1511 fields = line .split ()
1612 nm = fields [0 ]
17- if nm in names :
13+ if nm in slist :
1814 error (f'{ nm } is multiply defined' )
19- names .add (nm )
20- for field in fields [1 :]: # remember targets
21- scnt [nm ] += 1
22- slist [nm , scnt [nm ]] = field
23- elif line .startswith ('\t ' ): # remember cmd for
24- cmd [nm ] += line # current name
15+ slist [nm ] = fields [1 :] # remember targets
16+ elif line .startswith ('\t ' ): # remember cmd for current name
17+ cmd [nm ] = cmd .get (nm , '' ) + line
2518 elif line .strip ():
2619 error (f'illegal line in makefile: { line } ' )
2720 ages () # compute initial ages
28- if sys .argv [1 ] in names :
21+ if sys .argv [1 ] in slist :
2922 if not update (sys .argv [1 ]):
3023 print (sys .argv [1 ], 'is up to date' )
3124 else :
3225 error (f'{ sys .argv [1 ]} is not in makefile' )
3326
3427def ages ():
35- entries = sorted (os .scandir ('.' ), key = lambda e : e .stat ().st_mtime , reverse = True )
28+ entries = sorted (os .scandir (), key = lambda e : e .stat ().st_mtime , reverse = True )
3629 for t , entry in enumerate (entries , start = 1 ):
3730 age [entry .name ] = t # all existing files get an age
38- for n in names :
39- if n not in age : # if n has not been created
40- age [n ] = 9999 # make n really old
31+ for n in slist :
32+ if n not in age : # if n has not been created
33+ age [n ] = 9999 # make n really old
4134
42- def update (n ):
35+ def update (n , visited = {} ):
4336 if n not in age :
4437 error (f'{ n } does not exist' )
45- if n not in names :
38+ if n not in slist :
4639 return 0
47- changed = 0
40+ changed = False
4841 visited [n ] = 1
49- for i in range (1 , scnt .get (n , 0 )+ 1 ):
50- s = slist [n , i ]
42+ for s in slist .get (n , []):
5143 if s not in visited :
5244 update (s )
5345 elif visited [s ] == 1 :
5446 error (f'{ s } and { n } are circularly defined' )
5547 if age [s ] <= age [n ]:
56- changed += 1
48+ changed = True
5749 visited [n ] = 2
58- if changed or n not in scnt :
50+ if changed or len ( slist . get ( n , [])) == 0 :
5951 print (cmd [n ], end = '' )
6052 os .system (cmd [n ]) # execute cmd associated with n
6153 ages () # recompute all ages
@@ -64,7 +56,7 @@ def update(n):
6456 return 0
6557
6658def error (msg ):
67- print (f 'error: { msg } ' , file = sys .stderr )
59+ print ('error:' , msg , file = sys .stderr )
6860 sys .exit (1 )
6961
7062if __name__ == '__main__' :
0 commit comments