Skip to content

Commit b9f9ef5

Browse files
committed
Update ab.
1 parent 9a50aea commit b9f9ef5

File tree

3 files changed

+67
-27
lines changed

3 files changed

+67
-27
lines changed

build/_progress.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import sys
2+
3+
(_, current, max) = sys.argv
4+
percent = int(100 * float(current) / float(max))
5+
print(f"[{percent:>3}%]")

build/ab.mk

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,15 @@ ifeq ($(OS), Windows_NT)
2828
endif
2929
EXT ?=
3030

31+
ifeq ($(PROGRESSINFO),)
32+
rulecount := $(shell test -f $(OBJ)/build.mk && $(MAKE) -n $(MAKECMDGOALS) PROGRESSINFO=XXXPROGRESSINFOXXX | grep XXXPROGRESSINFOXXX | wc -l)
33+
ruleindex := 1
34+
PROGRESSINFO = "$(shell $(PYTHON) build/_progress.py $(ruleindex) $(rulecount))$(eval ruleindex := $(shell expr $(ruleindex) + 1))"
35+
endif
36+
3137
include $(OBJ)/build.mk
3238

33-
MAKEFLAGS += -r -j$(nprocs)
39+
MAKEFLAGS += -r -j$(shell nproc)
3440
.DELETE_ON_ERROR:
3541

3642
.PHONY: update-ab

build/ab.py

Lines changed: 55 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import inspect
1717
import string
1818
import sys
19+
import hashlib
1920

2021
verbose = False
2122
quiet = False
@@ -131,6 +132,12 @@ def wrapper(*, name=None, replaces=None, **kwargs):
131132
return wrapper
132133

133134

135+
def _isiterable(xs):
136+
return isinstance(xs, Iterable) and not isinstance(
137+
xs, (str, bytes, bytearray)
138+
)
139+
140+
134141
class Target:
135142
def __init__(self, cwd, name):
136143
if verbose:
@@ -166,7 +173,7 @@ def format_field(self, value, format_spec):
166173
return ""
167174
if type(value) == str:
168175
return value
169-
if isinstance(value, (set, tuple)):
176+
if _isiterable(value):
170177
value = list(value)
171178
if type(value) != list:
172179
value = [value]
@@ -210,9 +217,23 @@ def materialise(self, replacing=False):
210217
# Actually call the callback.
211218

212219
cwdStack.append(self.cwd)
213-
self.callback(
214-
**{k: self.args[k] for k in self.binding.arguments.keys()}
215-
)
220+
if "kwargs" in self.binding.arguments.keys():
221+
# If the caller wants kwargs, return all arguments except the standard ones.
222+
cbargs = {
223+
k: v for k, v in self.args.items() if k not in {"dir"}
224+
}
225+
else:
226+
# Otherwise, just call the callback with the ones it asks for.
227+
cbargs = {}
228+
for k in self.binding.arguments.keys():
229+
if k != "kwargs":
230+
try:
231+
cbargs[k] = self.args[k]
232+
except KeyError:
233+
error(
234+
f"invocation of {self} failed because {k} isn't an argument"
235+
)
236+
self.callback(**cbargs)
216237
cwdStack.pop()
217238
except BaseException as e:
218239
print(f"Error materialising {self}: {self.callback}")
@@ -308,9 +329,7 @@ class Targets:
308329
def convert(value, target):
309330
if not value:
310331
return []
311-
assert isinstance(
312-
value, (list, tuple)
313-
), "cannot convert non-list to Targets"
332+
assert _isiterable(value), "cannot convert non-list to Targets"
314333
return [target.targetof(x) for x in flatten(value)]
315334

316335

@@ -334,7 +353,7 @@ def loadbuildfile(filename):
334353
def flatten(items):
335354
def generate(xs):
336355
for x in xs:
337-
if isinstance(x, Iterable) and not isinstance(x, (str, bytes)):
356+
if _isiterable(x):
338357
yield from generate(x)
339358
else:
340359
yield x
@@ -343,15 +362,13 @@ def generate(xs):
343362

344363

345364
def targetnamesof(items):
346-
if not isinstance(items, (list, tuple, set)):
347-
error("argument of filenamesof is not a list/tuple/set")
365+
assert _isiterable(items), "argument of filenamesof is not a collection"
348366

349367
return [t.name for t in items]
350368

351369

352370
def filenamesof(items):
353-
if not isinstance(items, (list, tuple, set)):
354-
error("argument of filenamesof is not a list/tuple/set")
371+
assert _isiterable(items), "argument of filenamesof is not a collection"
355372

356373
def generate(xs):
357374
for x in xs:
@@ -371,9 +388,12 @@ def filenameof(x):
371388
return xs[0]
372389

373390

374-
def emit(*args):
375-
outputFp.write(" ".join(args))
376-
outputFp.write("\n")
391+
def emit(*args, into=None):
392+
s = " ".join(args) + "\n"
393+
if into is not None:
394+
into += [s]
395+
else:
396+
outputFp.write(s)
377397

378398

379399
def emit_rule(name, ins, outs, cmds=[], label=None):
@@ -382,26 +402,35 @@ def emit_rule(name, ins, outs, cmds=[], label=None):
382402
nonobjs = [f for f in fouts if not f.startswith("$(OBJ)")]
383403

384404
emit("")
405+
406+
lines = []
385407
if nonobjs:
386-
emit("clean::")
387-
emit("\t$(hide) rm -f", *nonobjs)
408+
emit("clean::", into=lines)
409+
emit("\t$(hide) rm -f", *nonobjs, into=lines)
388410

389-
emit(".PHONY:", name)
411+
emit(".PHONY:", name, into=lines)
390412
if outs:
391-
emit(name, ":", *fouts)
392-
if cmds:
393-
emit(*fouts, "&:", *fins)
394-
else:
395-
emit(*fouts, ":", *fins)
413+
emit(name, ":", *fouts, into=lines)
414+
emit(*fouts, "&:", *fins, "\x01", into=lines)
396415

397416
if label:
398-
emit("\t$(hide)", "$(ECHO)", label)
417+
emit("\t$(hide)", "$(ECHO) $(PROGRESSINFO) ", label, into=lines)
399418
for c in cmds:
400-
emit("\t$(hide)", c)
419+
emit("\t$(hide)", c, into=lines)
401420
else:
402421
assert len(cmds) == 0, "rules with no outputs cannot have commands"
403-
emit(name, ":", *fins)
422+
emit(name, ":", *fins, into=lines)
423+
424+
cmd = "".join(lines)
425+
hash = hashlib.sha1(bytes(cmd, "utf-8")).hexdigest()
404426

427+
outputFp.write(cmd.replace("\x01", f"$(OBJ)/.hashes/{hash}"))
428+
429+
if outs:
430+
emit(f"$(OBJ)/.hashes/{hash}:")
431+
emit(
432+
f"\t$(hide) mkdir -p $(OBJ)/.hashes && touch $(OBJ)/.hashes/{hash}"
433+
)
405434
emit("")
406435

407436

0 commit comments

Comments
 (0)