User | Revision | Line number | New contents of line |
switches |
0:0e018d759a2a
|
1
|
""" Import and bulid a bunch of example programs
|
switches |
0:0e018d759a2a
|
2
|
|
switches |
0:0e018d759a2a
|
3
|
This library includes functions that are shared between the examples.py and
|
switches |
0:0e018d759a2a
|
4
|
the update.py modules.
|
switches |
0:0e018d759a2a
|
5
|
|
switches |
0:0e018d759a2a
|
6
|
"""
|
switches |
0:0e018d759a2a
|
7
|
import os
|
switches |
0:0e018d759a2a
|
8
|
from os.path import dirname, abspath, basename
|
switches |
0:0e018d759a2a
|
9
|
import os.path
|
switches |
0:0e018d759a2a
|
10
|
import sys
|
switches |
0:0e018d759a2a
|
11
|
import subprocess
|
switches |
0:0e018d759a2a
|
12
|
from shutil import rmtree
|
switches |
0:0e018d759a2a
|
13
|
|
switches |
0:0e018d759a2a
|
14
|
ROOT = abspath(dirname(dirname(dirname(dirname(__file__)))))
|
switches |
0:0e018d759a2a
|
15
|
sys.path.insert(0, ROOT)
|
switches |
0:0e018d759a2a
|
16
|
|
switches |
0:0e018d759a2a
|
17
|
from tools.build_api import get_mbed_official_release
|
switches |
0:0e018d759a2a
|
18
|
from tools.targets import TARGET_MAP
|
switches |
0:0e018d759a2a
|
19
|
from tools.export import EXPORTERS
|
switches |
0:0e018d759a2a
|
20
|
|
switches |
0:0e018d759a2a
|
21
|
SUPPORTED_TOOLCHAINS = ["ARM", "IAR", "GCC_ARM"]
|
switches |
0:0e018d759a2a
|
22
|
SUPPORTED_IDES = ["iar", "uvision", "make_gcc_arm", "make_iar", "make_armc5"]
|
switches |
0:0e018d759a2a
|
23
|
|
switches |
0:0e018d759a2a
|
24
|
def print_list(lst):
|
switches |
0:0e018d759a2a
|
25
|
"""Prints to screen the contents of a list
|
switches |
0:0e018d759a2a
|
26
|
|
switches |
0:0e018d759a2a
|
27
|
Args:
|
switches |
0:0e018d759a2a
|
28
|
lst - a list of any type, to be displayed
|
switches |
0:0e018d759a2a
|
29
|
|
switches |
0:0e018d759a2a
|
30
|
"""
|
switches |
0:0e018d759a2a
|
31
|
if lst:
|
switches |
0:0e018d759a2a
|
32
|
for thing in lst:
|
switches |
0:0e018d759a2a
|
33
|
print("# %s" % thing)
|
switches |
0:0e018d759a2a
|
34
|
|
switches |
0:0e018d759a2a
|
35
|
def print_summary(results, export=False):
|
switches |
0:0e018d759a2a
|
36
|
"""Prints to screen the results of compiling/exporting combinations of example programs,
|
switches |
0:0e018d759a2a
|
37
|
targets and compile toolchains/IDEs.
|
switches |
0:0e018d759a2a
|
38
|
|
switches |
0:0e018d759a2a
|
39
|
Args:
|
switches |
0:0e018d759a2a
|
40
|
results - results of the compilation stage. See compile_repos() and export_repos()
|
switches |
0:0e018d759a2a
|
41
|
for details of the format.
|
switches |
0:0e018d759a2a
|
42
|
|
switches |
0:0e018d759a2a
|
43
|
"""
|
switches |
0:0e018d759a2a
|
44
|
|
switches |
0:0e018d759a2a
|
45
|
print("#"*80)
|
switches |
0:0e018d759a2a
|
46
|
print("# Examples compilation summary")
|
switches |
0:0e018d759a2a
|
47
|
print("#"*80)
|
switches |
0:0e018d759a2a
|
48
|
print("#")
|
switches |
0:0e018d759a2a
|
49
|
print("# Passed example combinations")
|
switches |
0:0e018d759a2a
|
50
|
print("#")
|
switches |
0:0e018d759a2a
|
51
|
for key, val in results.iteritems():
|
switches |
0:0e018d759a2a
|
52
|
print_list(val[2])
|
switches |
0:0e018d759a2a
|
53
|
|
switches |
0:0e018d759a2a
|
54
|
second_result = "Failed example combinations" if not export else \
|
switches |
0:0e018d759a2a
|
55
|
"Failed export example combinations"
|
switches |
0:0e018d759a2a
|
56
|
|
switches |
0:0e018d759a2a
|
57
|
print("#")
|
switches |
0:0e018d759a2a
|
58
|
print("# %s"%second_result)
|
switches |
0:0e018d759a2a
|
59
|
print("#")
|
switches |
0:0e018d759a2a
|
60
|
for key, val in results.iteritems():
|
switches |
0:0e018d759a2a
|
61
|
print_list(val[3])
|
switches |
0:0e018d759a2a
|
62
|
|
switches |
0:0e018d759a2a
|
63
|
if export:
|
switches |
0:0e018d759a2a
|
64
|
print("#")
|
switches |
0:0e018d759a2a
|
65
|
print("# Failed build example combinations")
|
switches |
0:0e018d759a2a
|
66
|
print("#")
|
switches |
0:0e018d759a2a
|
67
|
for key, val in results.iteritems():
|
switches |
0:0e018d759a2a
|
68
|
print_list(val[4])
|
switches |
0:0e018d759a2a
|
69
|
|
switches |
0:0e018d759a2a
|
70
|
print("#")
|
switches |
0:0e018d759a2a
|
71
|
print("#"*80)
|
switches |
0:0e018d759a2a
|
72
|
|
switches |
0:0e018d759a2a
|
73
|
|
switches |
0:0e018d759a2a
|
74
|
def target_cross_toolchain(allowed_toolchains,
|
switches |
0:0e018d759a2a
|
75
|
features=[], targets=[]):
|
switches |
0:0e018d759a2a
|
76
|
"""Generate pairs of target and toolchains
|
switches |
0:0e018d759a2a
|
77
|
|
switches |
0:0e018d759a2a
|
78
|
Args:
|
switches |
0:0e018d759a2a
|
79
|
allowed_toolchains - a list of all possible toolchains
|
switches |
0:0e018d759a2a
|
80
|
|
switches |
0:0e018d759a2a
|
81
|
Kwargs:
|
switches |
0:0e018d759a2a
|
82
|
features - the features that must be in the features array of a
|
switches |
0:0e018d759a2a
|
83
|
target
|
switches |
0:0e018d759a2a
|
84
|
targets - a list of available targets
|
switches |
0:0e018d759a2a
|
85
|
"""
|
switches |
0:0e018d759a2a
|
86
|
if len(targets) == 0:
|
switches |
0:0e018d759a2a
|
87
|
targets=TARGET_MAP.keys()
|
switches |
0:0e018d759a2a
|
88
|
|
switches |
0:0e018d759a2a
|
89
|
for target, toolchains in get_mbed_official_release("5"):
|
switches |
0:0e018d759a2a
|
90
|
for toolchain in toolchains:
|
switches |
0:0e018d759a2a
|
91
|
if (toolchain in allowed_toolchains and
|
switches |
0:0e018d759a2a
|
92
|
target in targets and
|
switches |
0:0e018d759a2a
|
93
|
all(feature in TARGET_MAP[target].features
|
switches |
0:0e018d759a2a
|
94
|
for feature in features)):
|
switches |
0:0e018d759a2a
|
95
|
yield target, toolchain
|
switches |
0:0e018d759a2a
|
96
|
|
switches |
0:0e018d759a2a
|
97
|
|
switches |
0:0e018d759a2a
|
98
|
def target_cross_ide(allowed_ides,
|
switches |
0:0e018d759a2a
|
99
|
features=[], targets=[]):
|
switches |
0:0e018d759a2a
|
100
|
"""Generate pairs of target and ides
|
switches |
0:0e018d759a2a
|
101
|
|
switches |
0:0e018d759a2a
|
102
|
Args:
|
switches |
0:0e018d759a2a
|
103
|
allowed_ides - a list of all possible IDEs
|
switches |
0:0e018d759a2a
|
104
|
|
switches |
0:0e018d759a2a
|
105
|
Kwargs:
|
switches |
0:0e018d759a2a
|
106
|
features - the features that must be in the features array of a
|
switches |
0:0e018d759a2a
|
107
|
target
|
switches |
0:0e018d759a2a
|
108
|
targets - a list of available targets
|
switches |
0:0e018d759a2a
|
109
|
"""
|
switches |
0:0e018d759a2a
|
110
|
if len(targets) == 0:
|
switches |
0:0e018d759a2a
|
111
|
targets=TARGET_MAP.keys()
|
switches |
0:0e018d759a2a
|
112
|
|
switches |
0:0e018d759a2a
|
113
|
for target, toolchains in get_mbed_official_release("5"):
|
switches |
0:0e018d759a2a
|
114
|
for ide in allowed_ides:
|
switches |
0:0e018d759a2a
|
115
|
if (EXPORTERS[ide].TOOLCHAIN in toolchains and
|
switches |
0:0e018d759a2a
|
116
|
target in EXPORTERS[ide].TARGETS and
|
switches |
0:0e018d759a2a
|
117
|
target in targets and
|
switches |
0:0e018d759a2a
|
118
|
all(feature in TARGET_MAP[target].features
|
switches |
0:0e018d759a2a
|
119
|
for feature in features)):
|
switches |
0:0e018d759a2a
|
120
|
yield target, ide
|
switches |
0:0e018d759a2a
|
121
|
|
switches |
0:0e018d759a2a
|
122
|
|
switches |
0:0e018d759a2a
|
123
|
def get_repo_list(example):
|
switches |
0:0e018d759a2a
|
124
|
""" Returns a list of all the repos associated with the specific example in the json
|
switches |
0:0e018d759a2a
|
125
|
config file.
|
switches |
0:0e018d759a2a
|
126
|
If there are repos listed under the mbed section then these will be returned as a
|
switches |
0:0e018d759a2a
|
127
|
list. If not then the github single repo with be returned.
|
switches |
0:0e018d759a2a
|
128
|
NOTE: This does not currently deal with multiple examples underneath a github
|
switches |
0:0e018d759a2a
|
129
|
sourced exampe repo.
|
switches |
0:0e018d759a2a
|
130
|
|
switches |
0:0e018d759a2a
|
131
|
Args:
|
switches |
0:0e018d759a2a
|
132
|
example - Example for which the repo list is requested
|
switches |
0:0e018d759a2a
|
133
|
repos - The list of repos contained within that example in the json file
|
switches |
0:0e018d759a2a
|
134
|
|
switches |
0:0e018d759a2a
|
135
|
"""
|
switches |
0:0e018d759a2a
|
136
|
repos = []
|
switches |
0:0e018d759a2a
|
137
|
if len(example['mbed']) > 0:
|
switches |
0:0e018d759a2a
|
138
|
for repo in example['mbed']:
|
switches |
0:0e018d759a2a
|
139
|
repos.append(repo)
|
switches |
0:0e018d759a2a
|
140
|
else:
|
switches |
0:0e018d759a2a
|
141
|
repos.append(example['github'])
|
switches |
0:0e018d759a2a
|
142
|
return repos
|
switches |
0:0e018d759a2a
|
143
|
|
switches |
0:0e018d759a2a
|
144
|
def source_repos(config):
|
switches |
0:0e018d759a2a
|
145
|
""" Clones each of the repos associated with the specific examples name from the
|
switches |
0:0e018d759a2a
|
146
|
json config file. Note if there is already a clone of the repo then it will first
|
switches |
0:0e018d759a2a
|
147
|
be removed to ensure a clean, up to date cloning.
|
switches |
0:0e018d759a2a
|
148
|
Args:
|
switches |
0:0e018d759a2a
|
149
|
config - the json object imported from the file.
|
switches |
0:0e018d759a2a
|
150
|
|
switches |
0:0e018d759a2a
|
151
|
"""
|
switches |
0:0e018d759a2a
|
152
|
print("\nImporting example repos....\n")
|
switches |
0:0e018d759a2a
|
153
|
for example in config['examples']:
|
switches |
0:0e018d759a2a
|
154
|
for repo in get_repo_list(example):
|
switches |
0:0e018d759a2a
|
155
|
name = basename(repo)
|
switches |
0:0e018d759a2a
|
156
|
if os.path.exists(name):
|
switches |
0:0e018d759a2a
|
157
|
print("'%s' example directory already exists. Deleting..." % name)
|
switches |
0:0e018d759a2a
|
158
|
rmtree(name)
|
switches |
0:0e018d759a2a
|
159
|
|
switches |
0:0e018d759a2a
|
160
|
subprocess.call(["mbed-cli", "import", repo])
|
switches |
0:0e018d759a2a
|
161
|
|
switches |
0:0e018d759a2a
|
162
|
def get_num_failures(results, export=False):
|
switches |
0:0e018d759a2a
|
163
|
""" Returns the number of failed compilations from the results summary
|
switches |
0:0e018d759a2a
|
164
|
Args:
|
switches |
0:0e018d759a2a
|
165
|
results - results summary of the compilation stage. See compile_repos() for
|
switches |
0:0e018d759a2a
|
166
|
details of the format.
|
switches |
0:0e018d759a2a
|
167
|
num_failures
|
switches |
0:0e018d759a2a
|
168
|
|
switches |
0:0e018d759a2a
|
169
|
"""
|
switches |
0:0e018d759a2a
|
170
|
num_failures = 0
|
switches |
0:0e018d759a2a
|
171
|
|
switches |
0:0e018d759a2a
|
172
|
for key, val in results.iteritems():
|
switches |
0:0e018d759a2a
|
173
|
num_failures = num_failures + len(val[3])
|
switches |
0:0e018d759a2a
|
174
|
if export:
|
switches |
0:0e018d759a2a
|
175
|
num_failures += len(val[4])
|
switches |
0:0e018d759a2a
|
176
|
|
switches |
0:0e018d759a2a
|
177
|
return num_failures
|
switches |
0:0e018d759a2a
|
178
|
|
switches |
0:0e018d759a2a
|
179
|
|
switches |
0:0e018d759a2a
|
180
|
def export_repos(config, ides):
|
switches |
0:0e018d759a2a
|
181
|
def print_message(message, name):
|
switches |
0:0e018d759a2a
|
182
|
print(message+ " %s"%name)
|
switches |
0:0e018d759a2a
|
183
|
sys.stdout.flush()
|
switches |
0:0e018d759a2a
|
184
|
|
switches |
0:0e018d759a2a
|
185
|
results = {}
|
switches |
0:0e018d759a2a
|
186
|
print("\nExporting example repos....\n")
|
switches |
0:0e018d759a2a
|
187
|
for example in config['examples']:
|
switches |
0:0e018d759a2a
|
188
|
export_failures = []
|
switches |
0:0e018d759a2a
|
189
|
build_failures = []
|
switches |
0:0e018d759a2a
|
190
|
successes = []
|
switches |
0:0e018d759a2a
|
191
|
exported = True
|
switches |
0:0e018d759a2a
|
192
|
pass_status = True
|
switches |
0:0e018d759a2a
|
193
|
if example['export']:
|
switches |
0:0e018d759a2a
|
194
|
for repo in get_repo_list(example):
|
switches |
0:0e018d759a2a
|
195
|
example_project_name = basename(repo)
|
switches |
0:0e018d759a2a
|
196
|
os.chdir(example_project_name)
|
switches |
0:0e018d759a2a
|
197
|
# Check that the target, IDE, and features combinations are valid and return a
|
switches |
0:0e018d759a2a
|
198
|
# list of valid combinations to work through
|
switches |
0:0e018d759a2a
|
199
|
for target, ide in target_cross_ide(ides,
|
switches |
0:0e018d759a2a
|
200
|
example['features'],
|
switches |
0:0e018d759a2a
|
201
|
example['targets']):
|
switches |
0:0e018d759a2a
|
202
|
example_name = "{} {} {}".format(example_project_name, target,
|
switches |
0:0e018d759a2a
|
203
|
ide)
|
switches |
0:0e018d759a2a
|
204
|
def status(message):
|
switches |
0:0e018d759a2a
|
205
|
print(message + " %s" % example_name)
|
switches |
0:0e018d759a2a
|
206
|
sys.stdout.flush()
|
switches |
0:0e018d759a2a
|
207
|
|
switches |
0:0e018d759a2a
|
208
|
status("Exporting")
|
switches |
0:0e018d759a2a
|
209
|
proc = subprocess.Popen(["mbed-cli", "export", "-i", ide,
|
switches |
0:0e018d759a2a
|
210
|
"-m", target])
|
switches |
0:0e018d759a2a
|
211
|
proc.wait()
|
switches |
0:0e018d759a2a
|
212
|
if proc.returncode:
|
switches |
0:0e018d759a2a
|
213
|
export_failures.append(example_name)
|
switches |
0:0e018d759a2a
|
214
|
status("FAILURE exporting")
|
switches |
0:0e018d759a2a
|
215
|
else:
|
switches |
0:0e018d759a2a
|
216
|
status("SUCCESS exporting")
|
switches |
0:0e018d759a2a
|
217
|
status("Building")
|
switches |
0:0e018d759a2a
|
218
|
if EXPORTERS[ide].build(example_project_name):
|
switches |
0:0e018d759a2a
|
219
|
status("FAILURE building")
|
switches |
0:0e018d759a2a
|
220
|
build_failures.append(example_name)
|
switches |
0:0e018d759a2a
|
221
|
else:
|
switches |
0:0e018d759a2a
|
222
|
status("SUCCESS building")
|
switches |
0:0e018d759a2a
|
223
|
successes.append(example_name)
|
switches |
0:0e018d759a2a
|
224
|
os.chdir("..")
|
switches |
0:0e018d759a2a
|
225
|
|
switches |
0:0e018d759a2a
|
226
|
if len(build_failures+export_failures) > 0:
|
switches |
0:0e018d759a2a
|
227
|
pass_status= False
|
switches |
0:0e018d759a2a
|
228
|
else:
|
switches |
0:0e018d759a2a
|
229
|
exported = False
|
switches |
0:0e018d759a2a
|
230
|
|
switches |
0:0e018d759a2a
|
231
|
results[example['name']] = [exported, pass_status, successes, export_failures, build_failures]
|
switches |
0:0e018d759a2a
|
232
|
|
switches |
0:0e018d759a2a
|
233
|
return results
|
switches |
0:0e018d759a2a
|
234
|
|
switches |
0:0e018d759a2a
|
235
|
|
switches |
0:0e018d759a2a
|
236
|
def compile_repos(config, toolchains):
|
switches |
0:0e018d759a2a
|
237
|
"""Compiles combinations of example programs, targets and compile chains.
|
switches |
0:0e018d759a2a
|
238
|
|
switches |
0:0e018d759a2a
|
239
|
The results are returned in a [key: value] dictionary format:
|
switches |
0:0e018d759a2a
|
240
|
Where key = The example name from the json config file
|
switches |
0:0e018d759a2a
|
241
|
value = a list containing: pass_status, successes, and failures
|
switches |
0:0e018d759a2a
|
242
|
|
switches |
0:0e018d759a2a
|
243
|
where pass_status = The overall pass status for the compilation of the full
|
switches |
0:0e018d759a2a
|
244
|
set of example programs comprising the example suite.
|
switches |
0:0e018d759a2a
|
245
|
True if all examples pass, false otherwise
|
switches |
0:0e018d759a2a
|
246
|
successes = list of passing examples.
|
switches |
0:0e018d759a2a
|
247
|
failures = list of failing examples.
|
switches |
0:0e018d759a2a
|
248
|
|
switches |
0:0e018d759a2a
|
249
|
Both successes and failures contain the example name, target and compile chain
|
switches |
0:0e018d759a2a
|
250
|
|
switches |
0:0e018d759a2a
|
251
|
Args:
|
switches |
0:0e018d759a2a
|
252
|
config - the json object imported from the file.
|
switches |
0:0e018d759a2a
|
253
|
toolchains - List of toolchains to compile for.
|
switches |
0:0e018d759a2a
|
254
|
results - results of the compilation stage.
|
switches |
0:0e018d759a2a
|
255
|
|
switches |
0:0e018d759a2a
|
256
|
"""
|
switches |
0:0e018d759a2a
|
257
|
results = {}
|
switches |
0:0e018d759a2a
|
258
|
print("\nCompiling example repos....\n")
|
switches |
0:0e018d759a2a
|
259
|
for example in config['examples']:
|
switches |
0:0e018d759a2a
|
260
|
failures = []
|
switches |
0:0e018d759a2a
|
261
|
successes = []
|
switches |
0:0e018d759a2a
|
262
|
compiled = True
|
switches |
0:0e018d759a2a
|
263
|
pass_status = True
|
switches |
0:0e018d759a2a
|
264
|
if example['compile']:
|
switches |
0:0e018d759a2a
|
265
|
if len(example['toolchains']) > 0:
|
switches |
0:0e018d759a2a
|
266
|
toolchains = example['toolchains']
|
switches |
0:0e018d759a2a
|
267
|
|
switches |
0:0e018d759a2a
|
268
|
for repo in get_repo_list(example):
|
switches |
0:0e018d759a2a
|
269
|
os.chdir(basename(repo))
|
switches |
0:0e018d759a2a
|
270
|
|
switches |
0:0e018d759a2a
|
271
|
# Check that the target, toolchain and features combinations are valid and return a
|
switches |
0:0e018d759a2a
|
272
|
# list of valid combinations to work through
|
switches |
0:0e018d759a2a
|
273
|
for target, toolchain in target_cross_toolchain(toolchains,
|
switches |
0:0e018d759a2a
|
274
|
example['features'], example['targets']):
|
switches |
0:0e018d759a2a
|
275
|
proc = subprocess.Popen(["mbed-cli", "compile", "-t", toolchain,
|
switches |
0:0e018d759a2a
|
276
|
"-m", target, "--silent"])
|
switches |
0:0e018d759a2a
|
277
|
proc.wait()
|
switches |
0:0e018d759a2a
|
278
|
example_summary = "{} {} {}".format(basename(repo), target, toolchain)
|
switches |
0:0e018d759a2a
|
279
|
if proc.returncode:
|
switches |
0:0e018d759a2a
|
280
|
failures.append(example_summary)
|
switches |
0:0e018d759a2a
|
281
|
else:
|
switches |
0:0e018d759a2a
|
282
|
successes.append(example_summary)
|
switches |
0:0e018d759a2a
|
283
|
os.chdir("..")
|
switches |
0:0e018d759a2a
|
284
|
|
switches |
0:0e018d759a2a
|
285
|
# If there are any compilation failures for the example 'set' then the overall status is fail.
|
switches |
0:0e018d759a2a
|
286
|
if len(failures) > 0:
|
switches |
0:0e018d759a2a
|
287
|
pass_status = False
|
switches |
0:0e018d759a2a
|
288
|
else:
|
switches |
0:0e018d759a2a
|
289
|
compiled = False
|
switches |
0:0e018d759a2a
|
290
|
|
switches |
0:0e018d759a2a
|
291
|
results[example['name']] = [compiled, pass_status, successes, failures]
|
switches |
0:0e018d759a2a
|
292
|
|
switches |
0:0e018d759a2a
|
293
|
return results
|
switches |
0:0e018d759a2a
|
294
|
|
switches |
0:0e018d759a2a
|
295
|
|
switches |
0:0e018d759a2a
|
296
|
def update_mbedos_version(config, tag):
|
switches |
0:0e018d759a2a
|
297
|
""" For each example repo identified in the config json object, update the version of
|
switches |
0:0e018d759a2a
|
298
|
mbed-os to that specified by the supplied GitHub tag. This function assumes that each
|
switches |
0:0e018d759a2a
|
299
|
example repo has already been cloned.
|
switches |
0:0e018d759a2a
|
300
|
|
switches |
0:0e018d759a2a
|
301
|
Args:
|
switches |
0:0e018d759a2a
|
302
|
config - the json object imported from the file.
|
switches |
0:0e018d759a2a
|
303
|
tag - GitHub tag corresponding to a version of mbed-os to upgrade to.
|
switches |
0:0e018d759a2a
|
304
|
|
switches |
0:0e018d759a2a
|
305
|
"""
|
switches |
0:0e018d759a2a
|
306
|
print("Updating mbed-os in examples to version %s\n" % tag)
|
switches |
0:0e018d759a2a
|
307
|
for example in config['examples']:
|
switches |
0:0e018d759a2a
|
308
|
for repo in get_repo_list(example):
|
switches |
0:0e018d759a2a
|
309
|
update_dir = basename(repo) + "/mbed-os"
|
switches |
0:0e018d759a2a
|
310
|
print("\nChanging dir to %s\n" % update_dir)
|
switches |
0:0e018d759a2a
|
311
|
os.chdir(update_dir)
|
switches |
0:0e018d759a2a
|
312
|
subprocess.call(["mbed-cli", "update", tag, "--clean"])
|
switches |
0:0e018d759a2a
|
313
|
os.chdir("../..")
|
switches |
0:0e018d759a2a
|
314
|
|