Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 387 lines (356 sloc) 14.216 kb
e446d4d @apenwarr builder.py: don't import the 'random' module unless we need it.
authored
1 import sys, os, errno, stat
f7734c3 @apenwarr Split build functions into builder.py.
authored
2 import vars, jwack, state
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
3 from helpers import unlink, close_on_exec, join
e18fa85 @apenwarr The only thing in helpers.py that needed vars.py was the log stuff.
authored
4 from log import log, log_, debug, debug2, err, warn
f7734c3 @apenwarr Split build functions into builder.py.
authored
5
6
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
7 def _default_do_files(filename):
f7734c3 @apenwarr Split build functions into builder.py.
authored
8 l = filename.split('.')
9 for i in range(1,len(l)+1):
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
10 basename = join('.', l[:i])
11 ext = join('.', l[i:])
f7734c3 @apenwarr Split build functions into builder.py.
authored
12 if ext: ext = '.' + ext
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
13 yield ("default%s.do" % ext), basename, ext
14
f7734c3 @apenwarr Split build functions into builder.py.
authored
15
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
16 def _possible_do_files(t):
17 dirname,filename = os.path.split(t)
c077d77 @apenwarr builder.py: correctly set $3 to include the subdir path.
authored
18 yield (os.path.join(vars.BASE, dirname), "%s.do" % filename,
19 '', filename, '')
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
20
21 # It's important to try every possibility in a directory before resorting
22 # to a parent directory. Think about nested projects: I don't want
23 # ../../default.o.do to take precedence over ../default.do, because
24 # the former one might just be an artifact of someone embedding my project
25 # into theirs as a subdir. When they do, my rules should still be used
26 # for building my project in *all* cases.
27 t = os.path.normpath(os.path.join(vars.BASE, t))
28 dirname,filename = os.path.split(t)
29 dirbits = dirname.split('/')
30 for i in range(len(dirbits), -1, -1):
31 basedir = join('/', dirbits[:i])
32 subdir = join('/', dirbits[i:])
33 for dofile,basename,ext in _default_do_files(filename):
c077d77 @apenwarr builder.py: correctly set $3 to include the subdir path.
authored
34 yield (basedir, dofile,
35 subdir, os.path.join(subdir, basename), ext)
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
36
f7734c3 @apenwarr Split build functions into builder.py.
authored
37
6e6e453 @apenwarr Some speedups for doing redo-ifchange on a large number of static files.
authored
38 def _find_do_file(f):
c077d77 @apenwarr builder.py: correctly set $3 to include the subdir path.
authored
39 for dodir,dofile,basedir,basename,ext in _possible_do_files(f.name):
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
40 dopath = os.path.join(dodir, dofile)
41 debug2('%s: %s:%s ?\n' % (f.name, dodir, dofile))
42 if os.path.exists(dopath):
43 f.add_dep('m', dopath)
c077d77 @apenwarr builder.py: correctly set $3 to include the subdir path.
authored
44 return dodir,dofile,basedir,basename,ext
f7734c3 @apenwarr Split build functions into builder.py.
authored
45 else:
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
46 f.add_dep('c', dopath)
c077d77 @apenwarr builder.py: correctly set $3 to include the subdir path.
authored
47 return None,None,None,None,None
f7734c3 @apenwarr Split build functions into builder.py.
authored
48
49
f644f3b @apenwarr Remove the need for relpath (and thus abspath) in builder.py.
authored
50 def _nice(t):
43b74f3 @apenwarr builder._nice(): show the right filename in the case of chdir().
authored
51 return state.relpath(t, vars.STARTDIR)
f644f3b @apenwarr Remove the need for relpath (and thus abspath) in builder.py.
authored
52
53
6d767e2 @apenwarr user-friendliness sanity checks: catch common mistakes regarding $1/$…
authored
54 def _try_stat(filename):
55 try:
56 return os.stat(filename)
57 except OSError, e:
58 if e.errno == errno.ENOENT:
59 return None
60 else:
61 raise
62
63
0126f6b @apenwarr Don't wipe the timestamp when a target fails to redo.
authored
64 class ImmediateReturn(Exception):
65 def __init__(self, rv):
66 Exception.__init__(self, "immediate return with exit code %d" % rv)
67 self.rv = rv
68
69
3209316 @apenwarr builder.py: now the only exported function is main().
authored
70 class BuildJob:
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
71 def __init__(self, t, sf, lock, shouldbuildfunc, donefunc):
72 self.t = t # original target name, not relative to vars.BASE
73 self.sf = sf
2efbbc2 @apenwarr Don't crash on targets in directories that don't exist yet.
authored
74 tmpbase = t
75 while not os.path.isdir(os.path.dirname(tmpbase) or '.'):
76 ofs = tmpbase.rfind('/')
77 assert(ofs >= 0)
78 tmpbase = tmpbase[:ofs] + '__' + tmpbase[ofs+1:]
79 self.tmpname1 = '%s.redo1.tmp' % tmpbase
80 self.tmpname2 = '%s.redo2.tmp' % tmpbase
3209316 @apenwarr builder.py: now the only exported function is main().
authored
81 self.lock = lock
82 self.shouldbuildfunc = shouldbuildfunc
83 self.donefunc = donefunc
6d767e2 @apenwarr user-friendliness sanity checks: catch common mistakes regarding $1/$…
authored
84 self.before_t = _try_stat(self.t)
3209316 @apenwarr builder.py: now the only exported function is main().
authored
85
86 def start(self):
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
87 assert(self.lock.owned)
0126f6b @apenwarr Don't wipe the timestamp when a target fails to redo.
authored
88 try:
f702417 @apenwarr The second half of redo-stamp: out-of-order building.
authored
89 dirty = self.shouldbuildfunc(self.t)
90 if not dirty:
0126f6b @apenwarr Don't wipe the timestamp when a target fails to redo.
authored
91 # target doesn't need to be built; skip the whole task
92 return self._after2(0)
93 except ImmediateReturn, e:
94 return self._after2(e.rv)
f702417 @apenwarr The second half of redo-stamp: out-of-order building.
authored
95
91630a8 @apenwarr Whoops, redo-oob was slightly wrong when used with -j.
authored
96 if vars.NO_OOB or dirty == True:
f702417 @apenwarr The second half of redo-stamp: out-of-order building.
authored
97 self._start_do()
98 else:
db4c4fc @apenwarr Rename redo-oob to redo-unlocked, to more accurately represent its use.
authored
99 self._start_unlocked(dirty)
f702417 @apenwarr The second half of redo-stamp: out-of-order building.
authored
100
101 def _start_do(self):
102 assert(self.lock.owned)
103 t = self.t
104 sf = self.sf
f6d11d5 @apenwarr If a user manually changes a generated file, don't ever overwrite it.
authored
105 newstamp = sf.read_stamp()
106 if (sf.is_generated and
107 newstamp != state.STAMP_MISSING and
108 (sf.stamp != newstamp or sf.is_override)):
df85b3d @apenwarr Move dependency checking from redo-ifchange into deps.py.
authored
109 state.warn_override(_nice(t))
f6d11d5 @apenwarr If a user manually changes a generated file, don't ever overwrite it.
authored
110 sf.set_override()
111 sf.set_checked()
112 sf.save()
113 return self._after2(0)
c1a1f32 @apenwarr MacOS: "-e filename/." returns true even for non-directories.
authored
114 if (os.path.exists(t) and not os.path.isdir(t + '/.')
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
115 and not sf.is_generated):
51bbdc6 @apenwarr If we can't find a .do file for a target, mark it as not is_generated.
authored
116 # an existing source file that was not generated by us.
117 # This step is mentioned by djb in his notes.
118 # For example, a rule called default.c.do could be used to try
119 # to produce hello.c, but we don't want that to happen if
120 # hello.c was created by the end user.
121 # FIXME: always refuse to redo any file that was modified outside
122 # of redo? That would make it easy for someone to override a
123 # file temporarily, and could be undone by deleting the file.
a62bd50 @apenwarr Switch state.py to use sqlite3 instead of filesystem-based stamps.
authored
124 debug2("-- static (%r)\n" % t)
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
125 sf.set_static()
126 sf.save()
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
127 return self._after2(0)
c64b8a3 @apenwarr Fix a race condition caused by zap_deps().
authored
128 sf.zap_deps1()
c077d77 @apenwarr builder.py: correctly set $3 to include the subdir path.
authored
129 (dodir, dofile, basedir, basename, ext) = _find_do_file(sf)
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
130 if not dofile:
190dd65 @apenwarr It's okay if a file is marked as generated and doesn't have a .do.
authored
131 if os.path.exists(t):
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
132 sf.set_static()
133 sf.save()
190dd65 @apenwarr It's okay if a file is marked as generated and doesn't have a .do.
authored
134 return self._after2(0)
135 else:
136 err('no rule to make %r\n' % t)
137 return self._after2(1)
59201dd @apenwarr $3 and stdout no longer refer to the same file.
authored
138 unlink(self.tmpname1)
139 unlink(self.tmpname2)
140 ffd = os.open(self.tmpname1, os.O_CREAT|os.O_RDWR|os.O_EXCL, 0666)
2dbd471 @apenwarr state.py: reduce race condition between Lock.trylock() and unlock().
authored
141 close_on_exec(ffd, True)
135d1c1 @apenwarr builder.py: set FD_CLOEXEC flag on $3 when running a .do file.
authored
142 self.f = os.fdopen(ffd, 'w+')
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
143 # this will run in the dofile's directory, so use only basenames here
21f8809 @apenwarr Change definitions of $1,$2,$3 to match djb's redo.
authored
144 if vars.OLD_ARGS:
145 arg1 = basename # target name (no extension)
146 arg2 = ext # extension (if any), including leading dot
147 else:
148 arg1 = basename + ext # target name (including extension)
149 arg2 = basename # target name (without extension)
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
150 argv = ['sh', '-e',
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
151 dofile,
21f8809 @apenwarr Change definitions of $1,$2,$3 to match djb's redo.
authored
152 arg1,
153 arg2,
2efbbc2 @apenwarr Don't crash on targets in directories that don't exist yet.
authored
154 # temp output file name
155 state.relpath(os.path.abspath(self.tmpname2), dodir),
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
156 ]
157 if vars.VERBOSE: argv[1] += 'v'
158 if vars.XTRACE: argv[1] += 'x'
159 if vars.VERBOSE or vars.XTRACE: log_('\n')
e98696c @apenwarr Merge branch 'master' into search-parent-dirs
authored
160 firstline = open(os.path.join(dodir, dofile)).readline().strip()
f641e52 @apenwarr Handle .do files that start with "#!/" to specify an explicit interpr…
authored
161 if firstline.startswith('#!/'):
162 argv[0:2] = firstline[2:].split(' ')
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
163 log('%s\n' % _nice(t))
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
164 self.dodir = dodir
165 self.basename = basename
166 self.ext = ext
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
167 self.argv = argv
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
168 sf.is_generated = True
169 sf.save()
4c06332 @apenwarr builder.py: we weren't stamping .do files correctly if dodir!='.'.
authored
170 dof = state.File(name=os.path.join(dodir, dofile))
a62bd50 @apenwarr Switch state.py to use sqlite3 instead of filesystem-based stamps.
authored
171 dof.set_static()
172 dof.save()
29d6c9a @apenwarr Don't db.commit() so frequently.
authored
173 state.commit()
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
174 jwack.start_job(t, self._do_subproc, self._after)
175
db4c4fc @apenwarr Rename redo-oob to redo-unlocked, to more accurately represent its use.
authored
176 def _start_unlocked(self, dirty):
f702417 @apenwarr The second half of redo-stamp: out-of-order building.
authored
177 # out-of-band redo of some sub-objects. This happens when we're not
db4c4fc @apenwarr Rename redo-oob to redo-unlocked, to more accurately represent its use.
authored
178 # quite sure if t needs to be built or not (because some children
179 # look dirty, but might turn out to be clean thanks to checksums).
180 # We have to call redo-unlocked to figure it all out.
f702417 @apenwarr The second half of redo-stamp: out-of-order building.
authored
181 #
db4c4fc @apenwarr Rename redo-oob to redo-unlocked, to more accurately represent its use.
authored
182 # Note: redo-unlocked will handle all the updating of sf, so we
183 # don't have to do it here, nor call _after1. However, we have to
184 # hold onto the lock because otherwise we would introduce a race
185 # condition; that's why it's called redo-unlocked, because it doesn't
186 # grab a lock.
187 argv = ['redo-unlocked', self.sf.name] + [d.name for d in dirty]
f702417 @apenwarr The second half of redo-stamp: out-of-order building.
authored
188 log('(%s)\n' % _nice(self.t))
189 state.commit()
190 def run():
191 os.chdir(vars.BASE)
192 os.environ['REDO_DEPTH'] = vars.DEPTH + ' '
193 os.execvp(argv[0], argv)
194 assert(0)
195 # returns only if there's an exception
196 def after(t, rv):
197 return self._after2(rv)
198 jwack.start_job(self.t, run, after)
199
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
200 def _do_subproc(self):
c29de89 @apenwarr Fix more trouble with .do scripts that cd to other directories.
authored
201 # careful: REDO_PWD was the PWD relative to the STARTPATH at the time
202 # we *started* building the current target; but that target ran
203 # redo-ifchange, and it might have done it from a different directory
a62bd50 @apenwarr Switch state.py to use sqlite3 instead of filesystem-based stamps.
authored
204 # than we started it in. So os.getcwd() might be != REDO_PWD right
205 # now.
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
206 dn = self.dodir
c29de89 @apenwarr Fix more trouble with .do scripts that cd to other directories.
authored
207 newp = os.path.realpath(dn)
208 os.environ['REDO_PWD'] = state.relpath(newp, vars.STARTDIR)
0dcc3f6 @apenwarr Search parent directories for default*.do.
authored
209 os.environ['REDO_TARGET'] = self.basename + self.ext
8d0eba9 @apenwarr builder.py: use os.exec() instead of subprocess.call().
authored
210 os.environ['REDO_DEPTH'] = vars.DEPTH + ' '
211 if dn:
212 os.chdir(dn)
213 os.dup2(self.f.fileno(), 1)
214 os.close(self.f.fileno())
2dbd471 @apenwarr state.py: reduce race condition between Lock.trylock() and unlock().
authored
215 close_on_exec(1, False)
b3a14a2 @apenwarr When -x or -v is given, print the sh command we're executing.
authored
216 if vars.VERBOSE or vars.XTRACE: log_('* %s\n' % ' '.join(self.argv))
8d0eba9 @apenwarr builder.py: use os.exec() instead of subprocess.call().
authored
217 os.execvp(self.argv[0], self.argv)
135d1c1 @apenwarr builder.py: set FD_CLOEXEC flag on $3 when running a .do file.
authored
218 assert(0)
8d0eba9 @apenwarr builder.py: use os.exec() instead of subprocess.call().
authored
219 # returns only if there's an exception
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
220
221 def _after(self, t, rv):
2dbd471 @apenwarr state.py: reduce race condition between Lock.trylock() and unlock().
authored
222 try:
3ef2bd7 @apenwarr Don't check as often whether the .redo directory exists.
authored
223 state.check_sane()
6d767e2 @apenwarr user-friendliness sanity checks: catch common mistakes regarding $1/$…
authored
224 rv = self._after1(t, rv)
6e6e453 @apenwarr Some speedups for doing redo-ifchange on a large number of static files.
authored
225 state.commit()
2dbd471 @apenwarr state.py: reduce race condition between Lock.trylock() and unlock().
authored
226 finally:
227 self._after2(rv)
228
229 def _after1(self, t, rv):
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
230 f = self.f
6d767e2 @apenwarr user-friendliness sanity checks: catch common mistakes regarding $1/$…
authored
231 before_t = self.before_t
232 after_t = _try_stat(t)
59201dd @apenwarr $3 and stdout no longer refer to the same file.
authored
233 st1 = os.fstat(f.fileno())
234 st2 = _try_stat(self.tmpname2)
4bf569c @apenwarr builder.py: detect overrides by only ctime, not all of struct stat.
authored
235 if (after_t and
236 (not before_t or before_t.st_ctime != after_t.st_ctime) and
fb388b3 @apenwarr Automatically select a good shell instead of relying on /bin/sh.
authored
237 not stat.S_ISDIR(after_t.st_mode)):
59201dd @apenwarr $3 and stdout no longer refer to the same file.
authored
238 err('%s modified %s directly!\n' % (self.argv[2], t))
239 err('...you should update $3 (a temp file) or stdout, not $1.\n')
6d767e2 @apenwarr user-friendliness sanity checks: catch common mistakes regarding $1/$…
authored
240 rv = 206
59201dd @apenwarr $3 and stdout no longer refer to the same file.
authored
241 elif st2 and st1.st_size > 0:
242 err('%s wrote to stdout *and* created $3.\n' % self.argv[2])
6d767e2 @apenwarr user-friendliness sanity checks: catch common mistakes regarding $1/$…
authored
243 err('...you should write status messages to stderr, not stdout.\n')
244 rv = 207
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
245 if rv==0:
59201dd @apenwarr $3 and stdout no longer refer to the same file.
authored
246 if st2:
247 os.rename(self.tmpname2, t)
248 os.unlink(self.tmpname1)
249 elif st1.st_size > 0:
49f0a04 @apenwarr clean.do: cleanup *.tmp files that might have been left lying around.
authored
250 try:
251 os.rename(self.tmpname1, t)
252 except OSError, e:
253 if e.errno == errno.ENOENT:
254 unlink(t)
255 else:
256 raise
59201dd @apenwarr $3 and stdout no longer refer to the same file.
authored
257 if st2:
258 os.unlink(self.tmpname2)
259 else: # no output generated at all; that's ok
260 unlink(self.tmpname1)
261 unlink(t)
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
262 sf = self.sf
22617d3 @apenwarr Half-support for using file checksums instead of stamps.
authored
263 sf.refresh()
f6d11d5 @apenwarr If a user manually changes a generated file, don't ever overwrite it.
authored
264 sf.is_generated = True
22617d3 @apenwarr Half-support for using file checksums instead of stamps.
authored
265 sf.is_override = False
266 if sf.is_checked() or sf.is_changed():
267 # it got checked during the run; someone ran redo-stamp.
268 # update_stamp would call set_changed(); we don't want that
269 sf.stamp = sf.read_stamp()
270 else:
271 sf.csum = None
272 sf.update_stamp()
273 sf.set_changed()
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
274 else:
59201dd @apenwarr $3 and stdout no longer refer to the same file.
authored
275 unlink(self.tmpname1)
276 unlink(self.tmpname2)
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
277 sf = self.sf
0126f6b @apenwarr Don't wipe the timestamp when a target fails to redo.
authored
278 sf.set_failed()
c64b8a3 @apenwarr Fix a race condition caused by zap_deps().
authored
279 sf.zap_deps2()
280 sf.save()
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
281 f.close()
282 if rv != 0:
283 err('%s: exit code %d\n' % (_nice(t),rv))
284 else:
c64b8a3 @apenwarr Fix a race condition caused by zap_deps().
authored
285 if vars.VERBOSE or vars.XTRACE or vars.DEBUG:
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
286 log('%s (done)\n\n' % _nice(t))
6d767e2 @apenwarr user-friendliness sanity checks: catch common mistakes regarding $1/$…
authored
287 return rv
3209316 @apenwarr builder.py: now the only exported function is main().
authored
288
dcc2edb @apenwarr builder.py: further refactoring to run more stuff in the parent process
authored
289 def _after2(self, rv):
2dbd471 @apenwarr state.py: reduce race condition between Lock.trylock() and unlock().
authored
290 try:
291 self.donefunc(self.t, rv)
292 assert(self.lock.owned)
293 finally:
294 self.lock.unlock()
3209316 @apenwarr builder.py: now the only exported function is main().
authored
295
296
297 def main(targets, shouldbuildfunc):
f7734c3 @apenwarr Split build functions into builder.py.
authored
298 retcode = [0] # a list so that it can be reassigned from done()
299 if vars.SHUFFLE:
e446d4d @apenwarr builder.py: don't import the 'random' module unless we need it.
authored
300 import random
f7734c3 @apenwarr Split build functions into builder.py.
authored
301 random.shuffle(targets)
302
303 locked = []
304
305 def done(t, rv):
306 if rv:
307 retcode[0] = 1
308
7aa7c41 @apenwarr builder,jwack: slight cleanup to token passing.
authored
309 # In the first cycle, we just build as much as we can without worrying
310 # about any lock contention. If someone else has it locked, we move on.
294945b @apenwarr Assert that one instance never holds multiple locks on the same file …
authored
311 seen = {}
ea7057d @apenwarr redo-ifchange: remove special case for zero arguments.
authored
312 lock = None
f7734c3 @apenwarr Split build functions into builder.py.
authored
313 for t in targets:
294945b @apenwarr Assert that one instance never holds multiple locks on the same file …
authored
314 if t in seen:
315 continue
316 seen[t] = 1
6e6e453 @apenwarr Some speedups for doing redo-ifchange on a large number of static files.
authored
317 if not jwack.has_token():
318 state.commit()
f7734c3 @apenwarr Split build functions into builder.py.
authored
319 jwack.get_token(t)
b937e62 @apenwarr Add a new -k (--keep-going) option, like make has.
authored
320 if retcode[0] and not vars.KEEP_GOING:
321 break
3ef2bd7 @apenwarr Don't check as often whether the .redo directory exists.
authored
322 if not state.check_sane():
323 err('.redo directory disappeared; cannot continue.\n')
dce0076 @apenwarr Print a useful message and exit when the .redo directory disappears.
authored
324 retcode[0] = 205
325 break
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
326 f = state.File(name=t)
327 lock = state.Lock(f.id)
f702417 @apenwarr The second half of redo-stamp: out-of-order building.
authored
328 if vars.UNLOCKED:
329 lock.owned = True
330 else:
331 lock.trylock()
f7734c3 @apenwarr Split build functions into builder.py.
authored
332 if not lock.owned:
03a054c @apenwarr Add a --debug-locks option.
authored
333 if vars.DEBUG_LOCKS:
334 log('%s (locked...)\n' % _nice(t))
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
335 locked.append((f.id,t))
f7734c3 @apenwarr Split build functions into builder.py.
authored
336 else:
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
337 BuildJob(t, f, lock, shouldbuildfunc, done).start()
7aa7c41 @apenwarr builder,jwack: slight cleanup to token passing.
authored
338
294945b @apenwarr Assert that one instance never holds multiple locks on the same file …
authored
339 del lock
340
7aa7c41 @apenwarr builder,jwack: slight cleanup to token passing.
authored
341 # Now we've built all the "easy" ones. Go back and just wait on the
f70c028 @apenwarr With --debug-locks, print a message when we stop to wait on a lock.
authored
342 # remaining ones one by one. There's no reason to do it any more
343 # efficiently, because if these targets were previously locked, that
344 # means someone else was building them; thus, we probably won't need to
345 # do anything. The only exception is if we're invoked as redo instead
346 # of redo-ifchange; then we have to redo it even if someone else already
347 # did. But that should be rare.
f7734c3 @apenwarr Split build functions into builder.py.
authored
348 while locked or jwack.running():
6e6e453 @apenwarr Some speedups for doing redo-ifchange on a large number of static files.
authored
349 state.commit()
f7734c3 @apenwarr Split build functions into builder.py.
authored
350 jwack.wait_all()
3209316 @apenwarr builder.py: now the only exported function is main().
authored
351 # at this point, we don't have any children holding any tokens, so
352 # it's okay to block below.
b937e62 @apenwarr Add a new -k (--keep-going) option, like make has.
authored
353 if retcode[0] and not vars.KEEP_GOING:
354 break
f7734c3 @apenwarr Split build functions into builder.py.
authored
355 if locked:
3ef2bd7 @apenwarr Don't check as often whether the .redo directory exists.
authored
356 if not state.check_sane():
357 err('.redo directory disappeared; cannot continue.\n')
dce0076 @apenwarr Print a useful message and exit when the .redo directory disappears.
authored
358 retcode[0] = 205
359 break
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
360 fid,t = locked.pop(0)
361 lock = state.Lock(fid)
f70c028 @apenwarr With --debug-locks, print a message when we stop to wait on a lock.
authored
362 lock.trylock()
c4be005 @apenwarr Release the jwack token when doing a synchronous lock wait.
authored
363 while not lock.owned:
16bebd2 @apenwarr builder: the (WAITING) message from --debug-locks didn't print every …
authored
364 if vars.DEBUG_LOCKS:
f70c028 @apenwarr With --debug-locks, print a message when we stop to wait on a lock.
authored
365 warn('%s (WAITING)\n' % _nice(t))
c4be005 @apenwarr Release the jwack token when doing a synchronous lock wait.
authored
366 # this sequence looks a little silly, but the idea is to
367 # give up our personal token while we wait for the lock to
368 # be released; but we should never run get_token() while
369 # holding a lock, or we could cause deadlocks.
370 jwack.release_mine()
f70c028 @apenwarr With --debug-locks, print a message when we stop to wait on a lock.
authored
371 lock.waitlock()
c4be005 @apenwarr Release the jwack token when doing a synchronous lock wait.
authored
372 lock.unlock()
373 jwack.get_token(t)
374 lock.trylock()
f7734c3 @apenwarr Split build functions into builder.py.
authored
375 assert(lock.owned)
03a054c @apenwarr Add a --debug-locks option.
authored
376 if vars.DEBUG_LOCKS:
377 log('%s (...unlocked!)\n' % _nice(t))
0126f6b @apenwarr Don't wipe the timestamp when a target fails to redo.
authored
378 if state.File(name=t).is_failed():
f644f3b @apenwarr Remove the need for relpath (and thus abspath) in builder.py.
authored
379 err('%s: failed in another thread\n' % _nice(t))
f7734c3 @apenwarr Split build functions into builder.py.
authored
380 retcode[0] = 2
381 lock.unlock()
382 else:
84169c5 @apenwarr Change locking stuff from fifos to fcntl.lockf().
authored
383 BuildJob(t, state.File(id=fid), lock,
384 shouldbuildfunc, done).start()
29d6c9a @apenwarr Don't db.commit() so frequently.
authored
385 state.commit()
f7734c3 @apenwarr Split build functions into builder.py.
authored
386 return retcode[0]
Something went wrong with that request. Please try again.