forked from modm-io/modm
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrepo.lb
More file actions
192 lines (163 loc) · 7.44 KB
/
repo.lb
File metadata and controls
192 lines (163 loc) · 7.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
#
# Copyright (c) 2017, Fabian Greif
# Copyright (c) 2017-2018, Niklas Hauser
#
# This file is part of the modm project.
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# -----------------------------------------------------------------------------
import re
import sys
import glob
import hashlib
from pathlib import Path
from distutils.version import StrictVersion
from git import Repo
sys.path.append(repopath("ext/modm-devices/tools/device"))
try:
import modm_devices.parser
except Exception as e:
print(e, "\n")
print("You might be missing the git submodules in `ext/`.\n"
"Try:\n"
" cd modm\n"
" git submodule update --init\n"
"then build again.")
exit(1)
import lbuild
min_lbuild_version = "1.6.0"
if StrictVersion(getattr(lbuild, "__version__", "0.1.0")) < StrictVersion(min_lbuild_version):
print("modm requires at least lbuild v{}, please upgrade!\n"
" pip3 install -U lbuild".format(min_lbuild_version))
exit(1)
# =============================================================================
class DevicesCache(dict):
"""
Building the device enumeration from modm-device is quite expensive,
so we cache the results in `ext/modm-devices.cache`
The text file contains two maps:
1. partname -> file-name.xml
We use this to populate the `:target` option, but we only
actually parse the device file and build the device on the first
access of the value.
2. file-name.xml -> MD5 hash
This is used to check if any files have changed their contents.
No additional checks are done, if files have moved, this may fail.
"""
def __init__(self):
dict.__init__(self)
self.device_to_file = {}
def parse_all(self):
mapping = {}
device_file_names = glob.glob(repopath("ext/modm-devices/devices/**/*.xml"))
device_file_names += glob.glob(repopath("tools/devices/**/*.xml"))
# roughly filter to supported devices
supported = ["stm32f0", "stm32f1", "stm32f2", "stm32f3", "stm32f4", "stm32f7",
"stm32l4", "at90", "attiny", "atmega", "hosted"]
device_file_names = [dfn for dfn in device_file_names if any(s in dfn for s in supported)]
# Parse the files and build the :target enumeration
parser = modm_devices.parser.DeviceParser()
for device_file_name in device_file_names:
device_file = parser.parse(device_file_name)
for device in device_file.get_devices():
self[device.partname] = device
mapping[device.partname] = device_file_name
return mapping
def build(self):
cache = Path(repopath("ext/modm-devices.cache"))
repos = {p:None for p in [".", "ext/modm-devices"]}
recompute_required = not cache.exists()
if cache.exists():
# Read cache file and populate :target
for line in cache.read_text().splitlines():
line = line.split(" ")
if line[0].startswith("/"):
file = line[0][1:]
# Store repo shas
if file in repos.keys():
repos[file] = line[1]
continue
# Check normal files
file = Path(repopath(file))
if not file.exists() or (line[1] != hashlib.md5(file.read_bytes()).hexdigest()):
recompute_required = True
break
else:
# Store None as device file value
self.device_to_file[line[0]] = line[1]
self[line[0]] = None
try:
# Check with real repository shas
real_repos = {path:Repo(repopath(path)).commit().hexsha for path in repos}
if any(real_repos[path] != sha for path, sha in repos.items()):
recompute_required = True
repos = real_repos
except:
recompute_required = True
if recompute_required:
print("Recomputing device cache...")
content = self.parse_all()
# prefix the files with a / so we can distinguish them from partnames
files = ["/{} {}".format(Path(f).relative_to(repopath(".")),
hashlib.md5(Path(f).read_bytes()).hexdigest())
for f in set(content.values())]
content = ["{} {}".format(d, Path(f).relative_to(repopath(".")))
for (d, f) in content.items()]
repos = ["/{} {}".format(path, sha) for path, sha in repos.items()]
content = sorted(content) + sorted(files + repos)
cache.write_text("\n".join(content))
def __getitem__(self, item):
value = dict.__getitem__(self, item)
if value is None:
# Parse the device file and build its devices
parser = modm_devices.parser.DeviceParser()
device_file = parser.parse(repopath(self.device_to_file[item]))
for device in device_file.get_devices():
self[device.partname] = device
return self[item]
return value
from lbuild.format import ansi_escape as c
def modm_format_description(node, description):
# Remove the HTML comments we use for describing doc tests
description = re.sub(r"\n?<!--.*?-->", "", description, flags=re.S)
# Indent code content
for block in re.finditer(r"\n```.*?(\n.*?)\n```", description, flags=re.M|re.S):
description = description.replace(block.group(0), block.group(1).replace("\n", "\n "))
# format any markdown headers bold
description = re.sub(r"^(#+.*)", r"{}\g<1>{}".format(str(c("bold")), str(c("no_bold"))), description, flags=re.M)
return node.format_description(node, description)
def modm_format_short_description(node, description):
# All docs use Markdown, so they might start with a `# Header`
description = re.sub(r"\n?<!--.*?-->", "", description, flags=re.S)
return node.format_short_description(node, description.replace("#", ""))
# =============================================================================
def init(repo):
repo.name = "modm"
repo.description = FileReader("README.md")
repo.format_description = modm_format_description
repo.format_short_description = modm_format_short_description
repo.add_ignore_patterns("*/*.lb", "*/board.xml")
# Add the board configuration files as their module name aliases
for config in Path(repopath("src/modm/board")).glob("*/board.xml"):
name = re.search("<module>(modm:board:.*?)</module>", config.read_text()).group(1).replace("modm:", "")
repo.add_configuration(name, config)
devices = DevicesCache()
try:
devices.build()
except (modm_devices.ParserException) as e:
print(e)
exit(1)
repo.add_option(
EnumerationOption(name="target",
description="Meta-HAL target device",
enumeration=devices))
def prepare(repo, options):
repo.add_modules_recursive("ext", modulefile="*.lb")
repo.add_modules_recursive("src", modulefile="*.lb")
repo.add_modules_recursive("tools", modulefile="*.lb")
def build(env):
env.add_metadata("include_path", "modm/src")