Skip to content

Commit 8cd153c

Browse files
committed
[tools] Improve example check script and fix issues
1 parent eb2efbf commit 8cd153c

File tree

6 files changed

+62
-21
lines changed

6 files changed

+62
-21
lines changed

.github/workflows/linux.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,10 +67,10 @@ jobs:
6767
run: |
6868
python3 tools/scripts/synchronize_docs.py -d
6969
git checkout .
70-
- name: Check for Unique Build Paths
70+
- name: Check Examples
7171
if: always()
7272
run: |
73-
python3 tools/scripts/examples_check.py examples
73+
python3 tools/scripts/examples_check.py
7474
7575
stm32-examples:
7676
runs-on: ubuntu-20.04
@@ -143,7 +143,7 @@ jobs:
143143
- name: Examples STM32F4 Without Discovery Board
144144
if: always()
145145
run: |
146-
(cd examples && ../tools/scripts/examples_compile.py nucleo_f401re nucleo_f411re nucleo_f429zi nucleo_f446re black_pill_f401 black_pill_f411 stm32f407vet6_devebox stm32_f4ve)
146+
(cd examples && ../tools/scripts/examples_compile.py nucleo_f401re nucleo_f411re nucleo_f429zi nucleo_f446re nucleo_f446ze nucleo_f439zi black_pill_f401 black_pill_f411 stm32f407vet6_devebox stm32_f4ve)
147147
148148
avr-examples:
149149
runs-on: ubuntu-20.04

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,5 +19,5 @@ before_install:
1919
script:
2020
- (cd test && make run-hosted-linux)
2121
- (cd examples && ../tools/scripts/examples_compile.py linux)
22-
- (cd examples && ../tools/scripts/examples_compile.py stm32f1_discovery nucleo_f103rb olimexino_stm32 stm32f103c8t6_blue_pill stm32f103c8t6_black_pill)
22+
- (cd examples && ../tools/scripts/examples_compile.py stm32f1_discovery nucleo_f103rb olimexino_stm32 blue_pill_f103 black_pill_f103)
2323
- (cd examples && ../tools/scripts/examples_compile.py rpi)

examples/arduino_nano/color/project.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<library>
22
<extends>modm:arduino-nano</extends>
33
<options>
4-
<option name="modm:build:build.path">../../../../build/arduino_nano/color</option>
4+
<option name="modm:build:build.path">../../../build/arduino_nano/color</option>
55
</options>
66
<modules>
77
<module>modm:build:scons</module>

examples/stm32_f4ve/gui/project.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<library>
22
<extends>modm:stm32_f4ve</extends>
33
<options>
4-
<option name="modm:build:build.path">../../../../build/stm32_f4ve/gui</option>
4+
<option name="modm:build:build.path">../../../build/stm32_f4ve/gui</option>
55
<option name="modm:build:image.source">images</option>
66
</options>
77
<modules>

tools/scripts/examples_check.py

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,75 @@
1111
from pathlib import Path
1212
from collections import defaultdict
1313

14-
def check_unique_paths(projects):
15-
# build paths *must* be unique, otherwise parallel compilation will overwrite build artifacts
14+
repopath = lambda path: Path(__file__).parents[2] / path
15+
relpath = lambda path: os.path.relpath(path, repopath("."))
16+
17+
def check_builds_paths(projects):
18+
# Get all build paths
1619
paths = defaultdict(list)
1720
for project in projects:
1821
match = re.search(r"<option name=\".*?:build.path\">(.*?)</option>", project.read_text())
1922
if match:
20-
match = match.group(1);
23+
path = match.group(1)
24+
match = (project.parent / match.group(1)).resolve();
2125
else:
22-
match = "build"
23-
paths[match].append(project)
26+
path = "build"
27+
match = path
28+
paths[match].append( (project, path) )
2429

2530
result = 0
2631
for path, projects in paths.items():
32+
# Check that all build paths are unique, otherwise parallel compilation will overwrite build artifacts
2733
if path == "build":
28-
for project in projects:
29-
print("'{}' has no build path set!".format(project), file=sys.stderr)
34+
for project, _ in projects:
35+
print("\nProject '{}' has no build path set!".format(relpath(project)), file=sys.stderr)
3036
result += 1
37+
# Check that all build paths are unique
3138
elif len(projects) > 1:
32-
print("The build path '{}' is used by these projects:".format(path), file=sys.stderr)
33-
for project in projects:
34-
print(" - '{}'".format(project), file=sys.stderr)
39+
print("\nThe build path '{}' is used by multiple projects:".format(path), file=sys.stderr)
40+
for project, bpath in projects:
41+
print(" - '{}': '{}'".format(relpath(project), bpath), file=sys.stderr)
42+
result += 1
43+
# Check that all build paths are actually inside the build folder
44+
if len(projects):
45+
relbuildpath = os.path.relpath(path, repopath("build"))
46+
if relbuildpath.startswith(".."):
47+
print("\nThe build path '{}' is outside of the 'modm/build' folder!"
48+
.format(relpath(path)), file=sys.stderr)
49+
for project, bpath in projects:
50+
print(" - '{}': '{}'".format(relpath(project), bpath), file=sys.stderr)
3551
result += 1
3652

3753
return result
3854

55+
def _get_paths_from_ci(files):
56+
paths = set()
57+
for file in files:
58+
matches = re.findall(r"examples_compile.py (.*?)\)", file.read_text())
59+
paths |= set(m for match in matches for m in match.split(" "))
60+
return paths
3961

40-
if __name__ == "__main__":
41-
# Find all project files
42-
projects = [p for path in sys.argv[1:] for p in Path(path).glob("**/project.xml")]
62+
def check_is_part_of_ci(projects):
63+
folders = set(p.relative_to(repopath("examples")).parts[0] for p in projects)
64+
result = 0
65+
# Linux files
66+
paths = _get_paths_from_ci([repopath(".github/workflows/linux.yml")])
67+
paths = folders - paths - {'rpi'}
68+
if paths:
69+
print("\nLinux CI is missing examples: '{}'"
70+
.format("', '".join(sorted(list(paths)))), file=sys.stderr)
71+
print(" Please add these example folders to the appropriate CI job in\n"
72+
" '.github/workflows/linux.yml'!")
4373

44-
result = check_unique_paths(projects)
74+
return len(paths)
4575

76+
if __name__ == "__main__":
77+
# Find all project files
78+
projects = list(repopath("examples").rglob("*/project.xml"))
79+
# Run a bunch of checks on them
80+
result = check_builds_paths(projects)
81+
result += check_is_part_of_ci(projects)
82+
# Return code if any
4683
exit(result)
4784

4885

tools/scripts/examples_compile.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,10 @@ def compile_examples(paths, jobs, split, part):
9393
# Create build folder to prevent process race
9494
cache_dir.mkdir(exist_ok=True, parents=True)
9595
(cache_dir / "config").write_text('{"prefix_len": 2}')
96+
# Validate that paths exist!
97+
invalid_paths = [p for p in paths if not Path(p).exists()]
98+
if invalid_paths: print("Invalid paths:\n- " + "\n- ".join(invalid_paths));
99+
results = len(invalid_paths)
96100
# Find all project files
97101
projects = [p for path in paths for p in Path(path).glob("**/project.xml")]
98102
projects.sort()
@@ -103,7 +107,7 @@ def compile_examples(paths, jobs, split, part):
103107
# first generate all projects
104108
with multiprocessing.Pool(jobs) as pool:
105109
projects = pool.map(generate, projects)
106-
results = projects.count(None)
110+
results += projects.count(None)
107111

108112
# Filter projects for successful generation
109113
projects = [p for p in projects if p is not None]

0 commit comments

Comments
 (0)