forked from modm-io/modm
-
Notifications
You must be signed in to change notification settings - Fork 0
/
repo.lb
180 lines (154 loc) · 7 KB
/
repo.lb
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
#!/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 os
import re
import sys
import glob
import hashlib
from pathlib import Path
from distutils.version import StrictVersion
sys.path.append(repopath("ext/modm-devices/tools/device"))
try:
import modm.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)
if sys.version_info[1] < 6:
print("modm will require Python 3.6 in the near future.\n"
"Please check if you can upgrade your installation!\n")
import lbuild
min_lbuild_version = "1.4.0"
if StrictVersion(getattr(lbuild, "__version__", "0.1.0")) < StrictVersion(min_lbuild_version):
print("modm requires at least lbuild v{}, please upgrade!\n"
" pip 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.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"))
recompute_required = False
if cache.exists():
# Read cache file and populate :target
for line in cache.read_text().splitlines():
line = line.split(" ")
if line[0].startswith("/"):
# If any file has changed, recompute
file = Path(repopath(line[0][1:]))
if not file.exists():
recompute_required = True
break
if 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
if not cache.exists() or 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()]
content = sorted(content) + sorted(files)
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.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.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")