Merge ~morphis/snappy-hwe-snaps/+git/jenkins-jobs:f/kernel-cross-build-support into ~snappy-hwe-team/snappy-hwe-snaps/+git/jenkins-jobs:master
- Git
- lp:~morphis/snappy-hwe-snaps/+git/jenkins-jobs
- f/kernel-cross-build-support
- Merge into master
Status: | Merged |
---|---|
Approved by: | Alfonso Sanchez-Beato |
Approved revision: | c8dd33592bcd3af6477148d134a43800938e2b02 |
Merged at revision: | 5d818f78ab6785efa28bb6a8776dc4f7ca5569fc |
Proposed branch: | ~morphis/snappy-hwe-snaps/+git/jenkins-jobs:f/kernel-cross-build-support |
Merge into: | ~snappy-hwe-team/snappy-hwe-snaps/+git/jenkins-jobs:master |
Diff against target: |
609 lines (+503/-11) 3 files modified
jobs/snap/snap-build-worker.sh (+14/-1) tools/shyaml (+454/-0) tools/snapbuild.sh (+35/-10) |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Alfonso Sanchez-Beato | Approve | ||
System Enablement Bot | continuous-integration | Approve | |
Review via email: mp+325979@code.launchpad.net |
Commit message
Description of the change
Implement cross-build support for kernel type snaps
This imports the shyaml script into the tree as we don't have another way to install shyaml in our jenkins environment (even the proxy disallows python pip access).
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
A couple of inline comments. Also:
1. Please add to the header of "tools/shyaml" the external repo/commit from which it was taken so we cant track the origin an update easily in the future.
2. It would be a good opportunity to clean scripts of shellcheck warnings, see
https:/
and
https:/
Simon Fels (morphis) wrote : | # |
Let's move the shellcheck cleanup into another MP.
System Enablement Bot (system-enablement-ci-bot) wrote : | # |
PASSED: Continuous integration, rev:c8dd33592bc
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
SUCCESS: https:/
Click here to trigger a rebuild:
https:/
Alfonso Sanchez-Beato (alfonsosanchezbeato) wrote : | # |
Thanks for the changes. Re: shellcheck, alright, but tbh 90% of the warnings are just adding quotes around, so no big deal. We should develop the habit of running shellcheck whenever we modify a shell script, it is an incredibly helpful tool.
Preview Diff
1 | diff --git a/jobs/snap/snap-build-worker.sh b/jobs/snap/snap-build-worker.sh | |||
2 | index e393c74..0c62b2c 100644 | |||
3 | --- a/jobs/snap/snap-build-worker.sh | |||
4 | +++ b/jobs/snap/snap-build-worker.sh | |||
5 | @@ -82,12 +82,25 @@ sed -i "s/~$LAUNCHPAD_TEAM\/$LAUNCHPAD_PROJECT\/+git\/$REPO_NAME/~$LAUNCHPAD_TEA | |||
6 | 82 | # $WORKSPACE/.build_env file. | 82 | # $WORKSPACE/.build_env file. |
7 | 83 | 83 | ||
8 | 84 | if [ "$BUILD_ON_LAUNCHPAD" = False ]; then | 84 | if [ "$BUILD_ON_LAUNCHPAD" = False ]; then |
9 | 85 | SNAPBUILD_EXTRA_ARGS= | ||
10 | 86 | SNAP_TYPE=$($BUILD_SCRIPTS/tools/shyaml get-value type < $SNAPCRAFT_YAML_PATH) | ||
11 | 87 | case "$SNAP_TYPE" in | ||
12 | 88 | kernel) | ||
13 | 89 | if [ "$ARCH" != amd64 ]; then | ||
14 | 90 | # If we're building a kernel snap we have to cross-build it | ||
15 | 91 | # instead of building it in a native environment. | ||
16 | 92 | SNAPBUILD_EXTRA_ARGS="--cross-build" | ||
17 | 93 | fi | ||
18 | 94 | ;; | ||
19 | 95 | esac | ||
20 | 96 | |||
21 | 85 | sudo $BUILD_SCRIPTS/tools/snapbuild.sh \ | 97 | sudo $BUILD_SCRIPTS/tools/snapbuild.sh \ |
22 | 86 | --source-dir=$WORKSPACE/src \ | 98 | --source-dir=$WORKSPACE/src \ |
23 | 87 | --results-dir=$WORKSPACE/results \ | 99 | --results-dir=$WORKSPACE/results \ |
24 | 88 | --arch=$ARCHITECTURE \ | 100 | --arch=$ARCHITECTURE \ |
25 | 89 | --series=$SERIES \ | 101 | --series=$SERIES \ |
27 | 90 | --proxy=squid.internal:3128 | 102 | --proxy=squid.internal:3128 \ |
28 | 103 | $SNAPBUILD_EXTRA_ARGS | ||
29 | 91 | else | 104 | else |
30 | 92 | git remote add jenkins-ci git+ssh://$BOT_USERNAME@git.launchpad.net/~$LAUNCHPAD_TEAM/$LAUNCHPAD_PROJECT/+git/$CI_REPO | 105 | git remote add jenkins-ci git+ssh://$BOT_USERNAME@git.launchpad.net/~$LAUNCHPAD_TEAM/$LAUNCHPAD_PROJECT/+git/$CI_REPO |
31 | 93 | git push jenkins-ci --all | 106 | git push jenkins-ci --all |
32 | diff --git a/tools/shyaml b/tools/shyaml | |||
33 | 94 | new file mode 100755 | 107 | new file mode 100755 |
34 | index 0000000..e4618ec | |||
35 | --- /dev/null | |||
36 | +++ b/tools/shyaml | |||
37 | @@ -0,0 +1,454 @@ | |||
38 | 1 | #!/usr/bin/env python | ||
39 | 2 | |||
40 | 3 | # Taken from upstream git repository https://github.com/0k/shyaml | ||
41 | 4 | # at revision d77e30599a0971c51896ef97d21883550e7e9979 | ||
42 | 5 | |||
43 | 6 | ## Note: to launch test, you can use: | ||
44 | 7 | ## python -m doctest -d shyaml.py | ||
45 | 8 | ## or | ||
46 | 9 | ## nosetests | ||
47 | 10 | |||
48 | 11 | from __future__ import print_function | ||
49 | 12 | |||
50 | 13 | import sys | ||
51 | 14 | import yaml | ||
52 | 15 | import os.path | ||
53 | 16 | import re | ||
54 | 17 | |||
55 | 18 | PY3 = sys.version_info[0] >= 3 | ||
56 | 19 | |||
57 | 20 | EXNAME = os.path.basename(sys.argv[0]) | ||
58 | 21 | |||
59 | 22 | USAGE = """\ | ||
60 | 23 | Usage: | ||
61 | 24 | |||
62 | 25 | %(exname)s (-h|--help) | ||
63 | 26 | %(exname)s [-y|--yaml] ACTION KEY [DEFAULT] | ||
64 | 27 | """ % {"exname": EXNAME} | ||
65 | 28 | |||
66 | 29 | HELP = """ | ||
67 | 30 | Parses and output chosen subpart or values from YAML input. | ||
68 | 31 | It reads YAML in stdin and will output on stdout it's return value. | ||
69 | 32 | |||
70 | 33 | %(usage)s | ||
71 | 34 | |||
72 | 35 | Options: | ||
73 | 36 | |||
74 | 37 | -y, --yaml | ||
75 | 38 | Output only YAML safe value, more precisely, even | ||
76 | 39 | literal values will be YAML quoted. This behavior | ||
77 | 40 | is required if you want to output YAML subparts and | ||
78 | 41 | further process it. If you know you have are dealing | ||
79 | 42 | with safe literal value, then you don't need this. | ||
80 | 43 | (Default: no safe YAML output) | ||
81 | 44 | |||
82 | 45 | ACTION Depending on the type of data you've targetted | ||
83 | 46 | thanks to the KEY, ACTION can be: | ||
84 | 47 | |||
85 | 48 | These ACTIONs applies to any YAML type: | ||
86 | 49 | |||
87 | 50 | get-type ## returns a short string | ||
88 | 51 | get-value ## returns YAML | ||
89 | 52 | |||
90 | 53 | This ACTION applies to 'sequence' and 'struct' YAML type: | ||
91 | 54 | |||
92 | 55 | get-values{,-0} ## return list of YAML | ||
93 | 56 | |||
94 | 57 | These ACTION applies to 'struct' YAML type: | ||
95 | 58 | |||
96 | 59 | keys{,-0} ## return list of YAML | ||
97 | 60 | values{,-0} ## return list of YAML | ||
98 | 61 | key-values,{,-0} ## return list of YAML | ||
99 | 62 | |||
100 | 63 | Note that any value returned is returned on stdout, and | ||
101 | 64 | when returning ``list of YAML``, it'll be separated by | ||
102 | 65 | ``\\n`` or ``NUL`` char depending of you've used the | ||
103 | 66 | ``-0`` suffixed ACTION. | ||
104 | 67 | |||
105 | 68 | KEY Identifier to browse and target subvalues into YAML | ||
106 | 69 | structure. Use ``.`` to parse a subvalue. If you need | ||
107 | 70 | to use a literal ``.`` or ``\``, use ``\`` to quote it. | ||
108 | 71 | |||
109 | 72 | Use struct keyword to browse ``struct`` YAML data and use | ||
110 | 73 | integers to browse ``sequence`` YAML data. | ||
111 | 74 | |||
112 | 75 | DEFAULT if not provided and given KEY do not match any value in | ||
113 | 76 | the provided YAML, then DEFAULT will be returned. If no | ||
114 | 77 | default is provided and the KEY do not match any value | ||
115 | 78 | in the provided YAML, %(exname)s will fail with an error | ||
116 | 79 | message. | ||
117 | 80 | |||
118 | 81 | Examples: | ||
119 | 82 | |||
120 | 83 | ## get last grocery | ||
121 | 84 | cat recipe.yaml | %(exname)s get-value groceries.-1 | ||
122 | 85 | |||
123 | 86 | ## get all words of my french dictionary | ||
124 | 87 | cat dictionaries.yaml | %(exname)s keys-0 french.dictionary | ||
125 | 88 | |||
126 | 89 | ## get YAML config part of 'myhost' | ||
127 | 90 | cat hosts_config.yaml | %(exname)s get-value cfgs.myhost | ||
128 | 91 | |||
129 | 92 | """ % {"exname": EXNAME, "usage": USAGE} | ||
130 | 93 | |||
131 | 94 | ## | ||
132 | 95 | ## Keep previous order in YAML | ||
133 | 96 | ## | ||
134 | 97 | |||
135 | 98 | try: | ||
136 | 99 | # included in standard lib from Python 2.7 | ||
137 | 100 | from collections import OrderedDict | ||
138 | 101 | except ImportError: | ||
139 | 102 | # try importing the backported drop-in replacement | ||
140 | 103 | # it's available on PyPI | ||
141 | 104 | from ordereddict import OrderedDict | ||
142 | 105 | |||
143 | 106 | |||
144 | 107 | ## Ensure that there are no collision with legacy OrderedDict | ||
145 | 108 | ## that could be used for omap for instance. | ||
146 | 109 | class MyOrderedDict(OrderedDict): | ||
147 | 110 | pass | ||
148 | 111 | |||
149 | 112 | yaml.add_representer( | ||
150 | 113 | MyOrderedDict, | ||
151 | 114 | lambda cls, data: cls.represent_dict(data.items())) | ||
152 | 115 | |||
153 | 116 | |||
154 | 117 | def construct_omap(cls, node): | ||
155 | 118 | ## Force unfolding reference and merges | ||
156 | 119 | ## otherwise it would fail on 'merge' | ||
157 | 120 | cls.flatten_mapping(node) | ||
158 | 121 | return MyOrderedDict(cls.construct_pairs(node)) | ||
159 | 122 | |||
160 | 123 | |||
161 | 124 | yaml.add_constructor( | ||
162 | 125 | yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, | ||
163 | 126 | construct_omap) | ||
164 | 127 | |||
165 | 128 | |||
166 | 129 | ## | ||
167 | 130 | ## Key specifier | ||
168 | 131 | ## | ||
169 | 132 | |||
170 | 133 | def tokenize(s): | ||
171 | 134 | r"""Returns an iterable through all subparts of string splitted by '.' | ||
172 | 135 | |||
173 | 136 | So: | ||
174 | 137 | |||
175 | 138 | >>> list(tokenize('foo.bar.wiz')) | ||
176 | 139 | ['foo', 'bar', 'wiz'] | ||
177 | 140 | |||
178 | 141 | Contrary to traditional ``.split()`` method, this function has to | ||
179 | 142 | deal with any type of data in the string. So it actually | ||
180 | 143 | interprets the string. Characters with meaning are '.' and '\'. | ||
181 | 144 | Both of these can be included in a token by quoting them with '\'. | ||
182 | 145 | |||
183 | 146 | So dot of slashes can be contained in token: | ||
184 | 147 | |||
185 | 148 | >>> print('\n'.join(tokenize(r'foo.dot<\.>.slash<\\>'))) | ||
186 | 149 | foo | ||
187 | 150 | dot<.> | ||
188 | 151 | slash<\> | ||
189 | 152 | |||
190 | 153 | Notice that empty keys are also supported: | ||
191 | 154 | |||
192 | 155 | >>> list(tokenize(r'foo..bar')) | ||
193 | 156 | ['foo', '', 'bar'] | ||
194 | 157 | |||
195 | 158 | Given an empty string: | ||
196 | 159 | |||
197 | 160 | >>> list(tokenize(r'')) | ||
198 | 161 | [''] | ||
199 | 162 | |||
200 | 163 | And a None value: | ||
201 | 164 | |||
202 | 165 | >>> list(tokenize(None)) | ||
203 | 166 | [] | ||
204 | 167 | |||
205 | 168 | """ | ||
206 | 169 | if s is None: | ||
207 | 170 | raise StopIteration | ||
208 | 171 | tokens = (re.sub(r'\\(\\|\.)', r'\1', m.group(0)) | ||
209 | 172 | for m in re.finditer(r'((\\.|[^.\\])*)', s)) | ||
210 | 173 | ## an empty string superfluous token is added after all non-empty token | ||
211 | 174 | for token in tokens: | ||
212 | 175 | if len(token) != 0: | ||
213 | 176 | next(tokens) | ||
214 | 177 | yield token | ||
215 | 178 | |||
216 | 179 | |||
217 | 180 | def mget(dct, key): | ||
218 | 181 | r"""Allow to get values deep in recursive dict with doted keys | ||
219 | 182 | |||
220 | 183 | Accessing leaf values is quite straightforward: | ||
221 | 184 | |||
222 | 185 | >>> dct = {'a': {'x': 1, 'b': {'c': 2}}} | ||
223 | 186 | >>> mget(dct, 'a.x') | ||
224 | 187 | 1 | ||
225 | 188 | >>> mget(dct, 'a.b.c') | ||
226 | 189 | 2 | ||
227 | 190 | |||
228 | 191 | But you can also get subdict if your key is not targeting a | ||
229 | 192 | leaf value: | ||
230 | 193 | |||
231 | 194 | >>> mget(dct, 'a.b') | ||
232 | 195 | {'c': 2} | ||
233 | 196 | |||
234 | 197 | As a special feature, list access is also supported by providing a | ||
235 | 198 | (possibily signed) integer, it'll be interpreted as usual python | ||
236 | 199 | sequence access using bracket notation: | ||
237 | 200 | |||
238 | 201 | >>> mget({'a': {'x': [1, 5], 'b': {'c': 2}}}, 'a.x.-1') | ||
239 | 202 | 5 | ||
240 | 203 | >>> mget({'a': {'x': 1, 'b': [{'c': 2}]}}, 'a.b.0.c') | ||
241 | 204 | 2 | ||
242 | 205 | |||
243 | 206 | Keys that contains '.' can be accessed by escaping them: | ||
244 | 207 | |||
245 | 208 | >>> dct = {'a': {'x': 1}, 'a.x': 3, 'a.y': 4} | ||
246 | 209 | >>> mget(dct, 'a.x') | ||
247 | 210 | 1 | ||
248 | 211 | >>> mget(dct, r'a\.x') | ||
249 | 212 | 3 | ||
250 | 213 | >>> mget(dct, r'a.y') ## doctest: +IGNORE_EXCEPTION_DETAIL | ||
251 | 214 | Traceback (most recent call last): | ||
252 | 215 | ... | ||
253 | 216 | MissingKeyError: missing key 'y' in dict. | ||
254 | 217 | >>> mget(dct, r'a\.y') | ||
255 | 218 | 4 | ||
256 | 219 | |||
257 | 220 | As a consequence, if your key contains a '\', you should also escape it: | ||
258 | 221 | |||
259 | 222 | >>> dct = {r'a\x': 3, r'a\.x': 4, 'a.x': 5, 'a\\': {'x': 6}} | ||
260 | 223 | >>> mget(dct, r'a\\x') | ||
261 | 224 | 3 | ||
262 | 225 | >>> mget(dct, r'a\\\.x') | ||
263 | 226 | 4 | ||
264 | 227 | >>> mget(dct, r'a\\.x') | ||
265 | 228 | 6 | ||
266 | 229 | >>> mget({'a\\': {'b': 1}}, r'a\\.b') | ||
267 | 230 | 1 | ||
268 | 231 | >>> mget({r'a.b\.c': 1}, r'a\.b\\\.c') | ||
269 | 232 | 1 | ||
270 | 233 | |||
271 | 234 | And even empty strings key are supported: | ||
272 | 235 | |||
273 | 236 | >>> dct = {r'a': {'': {'y': 3}, 'y': 4}, 'b': {'': {'': 1}}, '': 2} | ||
274 | 237 | >>> mget(dct, r'a..y') | ||
275 | 238 | 3 | ||
276 | 239 | >>> mget(dct, r'a.y') | ||
277 | 240 | 4 | ||
278 | 241 | >>> mget(dct, r'') | ||
279 | 242 | 2 | ||
280 | 243 | >>> mget(dct, r'b..') | ||
281 | 244 | 1 | ||
282 | 245 | |||
283 | 246 | It will complain if you are trying to get into a leaf: | ||
284 | 247 | |||
285 | 248 | >>> mget({'a': 1}, 'a.y') ## doctest: +IGNORE_EXCEPTION_DETAIL | ||
286 | 249 | Traceback (most recent call last): | ||
287 | 250 | ... | ||
288 | 251 | NonDictLikeTypeError: can't query subvalue 'y' of a leaf... | ||
289 | 252 | |||
290 | 253 | if the key is None, the whole dct should be sent back: | ||
291 | 254 | |||
292 | 255 | >>> mget({'a': 1}, None) | ||
293 | 256 | {'a': 1} | ||
294 | 257 | |||
295 | 258 | """ | ||
296 | 259 | return aget(dct, tokenize(key)) | ||
297 | 260 | |||
298 | 261 | |||
299 | 262 | class MissingKeyError(KeyError): | ||
300 | 263 | """Raised when querying a dict-like structure on non-existing keys""" | ||
301 | 264 | |||
302 | 265 | def __str__(self): | ||
303 | 266 | return self.message | ||
304 | 267 | |||
305 | 268 | |||
306 | 269 | class NonDictLikeTypeError(TypeError): | ||
307 | 270 | """Raised when attempting to traverse non-dict like structure""" | ||
308 | 271 | |||
309 | 272 | |||
310 | 273 | class IndexNotIntegerError(ValueError): | ||
311 | 274 | """Raised when attempting to traverse sequence without using an integer""" | ||
312 | 275 | |||
313 | 276 | |||
314 | 277 | class IndexOutOfRange(IndexError): | ||
315 | 278 | """Raised when attempting to traverse sequence without using an integer""" | ||
316 | 279 | |||
317 | 280 | |||
318 | 281 | def aget(dct, key): | ||
319 | 282 | r"""Allow to get values deep in a dict with iterable keys | ||
320 | 283 | |||
321 | 284 | Accessing leaf values is quite straightforward: | ||
322 | 285 | |||
323 | 286 | >>> dct = {'a': {'x': 1, 'b': {'c': 2}}} | ||
324 | 287 | >>> aget(dct, ('a', 'x')) | ||
325 | 288 | 1 | ||
326 | 289 | >>> aget(dct, ('a', 'b', 'c')) | ||
327 | 290 | 2 | ||
328 | 291 | |||
329 | 292 | If key is empty, it returns unchanged the ``dct`` value. | ||
330 | 293 | |||
331 | 294 | >>> aget({'x': 1}, ()) | ||
332 | 295 | {'x': 1} | ||
333 | 296 | |||
334 | 297 | """ | ||
335 | 298 | key = iter(key) | ||
336 | 299 | try: | ||
337 | 300 | head = next(key) | ||
338 | 301 | except StopIteration: | ||
339 | 302 | return dct | ||
340 | 303 | |||
341 | 304 | if isinstance(dct, list): | ||
342 | 305 | try: | ||
343 | 306 | idx = int(head) | ||
344 | 307 | except ValueError: | ||
345 | 308 | raise IndexNotIntegerError( | ||
346 | 309 | "non-integer index %r provided on a list." | ||
347 | 310 | % head) | ||
348 | 311 | try: | ||
349 | 312 | value = dct[idx] | ||
350 | 313 | except IndexError: | ||
351 | 314 | raise IndexOutOfRange( | ||
352 | 315 | "index %d is out of range (%d elements in list)." | ||
353 | 316 | % (idx, len(dct))) | ||
354 | 317 | else: | ||
355 | 318 | try: | ||
356 | 319 | value = dct[head] | ||
357 | 320 | except KeyError: | ||
358 | 321 | ## Replace with a more informative KeyError | ||
359 | 322 | raise MissingKeyError( | ||
360 | 323 | "missing key %r in dict." | ||
361 | 324 | % (head, )) | ||
362 | 325 | except: | ||
363 | 326 | raise NonDictLikeTypeError( | ||
364 | 327 | "can't query subvalue %r of a leaf%s." | ||
365 | 328 | % (head, | ||
366 | 329 | (" (leaf value is %r)" % dct) | ||
367 | 330 | if len(repr(dct)) < 15 else "")) | ||
368 | 331 | return aget(value, key) | ||
369 | 332 | |||
370 | 333 | |||
371 | 334 | def stderr(msg): | ||
372 | 335 | """Convenience function to write short message to stderr.""" | ||
373 | 336 | sys.stderr.write(msg) | ||
374 | 337 | |||
375 | 338 | |||
376 | 339 | def stdout(value): | ||
377 | 340 | """Convenience function to write short message to stdout.""" | ||
378 | 341 | sys.stdout.write(value) | ||
379 | 342 | |||
380 | 343 | |||
381 | 344 | def die(msg, errlvl=1, prefix="Error: "): | ||
382 | 345 | """Convenience function to write short message to stderr and quit.""" | ||
383 | 346 | stderr("%s%s\n" % (prefix, msg)) | ||
384 | 347 | sys.exit(errlvl) | ||
385 | 348 | |||
386 | 349 | SIMPLE_TYPES = (str if PY3 else basestring, int, float, type(None)) | ||
387 | 350 | COMPLEX_TYPES = (list, dict) | ||
388 | 351 | |||
389 | 352 | |||
390 | 353 | def magic_dump(value): | ||
391 | 354 | """Returns a representation of values directly usable by bash. | ||
392 | 355 | |||
393 | 356 | Literal types are printed as-is (avoiding quotes around string for | ||
394 | 357 | instance). But complex type are written in a YAML useable format. | ||
395 | 358 | |||
396 | 359 | """ | ||
397 | 360 | return value if isinstance(value, SIMPLE_TYPES) \ | ||
398 | 361 | else yaml.dump(value, default_flow_style=False) | ||
399 | 362 | |||
400 | 363 | def yaml_dump(value): | ||
401 | 364 | """Returns a representation of values directly usable by bash. | ||
402 | 365 | |||
403 | 366 | Literal types are quoted and safe to use as YAML. | ||
404 | 367 | |||
405 | 368 | """ | ||
406 | 369 | return yaml.dump(value, default_flow_style=False) | ||
407 | 370 | |||
408 | 371 | |||
409 | 372 | def type_name(value): | ||
410 | 373 | """Returns pseudo-YAML type name of given value.""" | ||
411 | 374 | return "struct" if isinstance(value, dict) else \ | ||
412 | 375 | "sequence" if isinstance(value, (tuple, list)) else \ | ||
413 | 376 | type(value).__name__ | ||
414 | 377 | |||
415 | 378 | |||
416 | 379 | def main(args): ## pylint: disable=too-many-branches | ||
417 | 380 | """Entrypoint of the whole application""" | ||
418 | 381 | |||
419 | 382 | if len(args) == 0: | ||
420 | 383 | stderr("Error: Bad number of arguments.\n") | ||
421 | 384 | die(USAGE, errlvl=1, prefix="") | ||
422 | 385 | |||
423 | 386 | if len(args) == 1 and args[0] in ("-h", "--help"): | ||
424 | 387 | stdout(HELP) | ||
425 | 388 | exit(0) | ||
426 | 389 | |||
427 | 390 | dump = magic_dump | ||
428 | 391 | for arg in ["-y", "--yaml"]: | ||
429 | 392 | if arg in args: | ||
430 | 393 | args.remove(arg) | ||
431 | 394 | dump = yaml_dump | ||
432 | 395 | |||
433 | 396 | action = args[0] | ||
434 | 397 | key_value = None if len(args) == 1 else args[1] | ||
435 | 398 | default = args[2] if len(args) > 2 else None | ||
436 | 399 | contents = yaml.load(sys.stdin) | ||
437 | 400 | |||
438 | 401 | try: | ||
439 | 402 | try: | ||
440 | 403 | value = mget(contents, key_value) | ||
441 | 404 | except (IndexOutOfRange, MissingKeyError): | ||
442 | 405 | if default is None: | ||
443 | 406 | raise | ||
444 | 407 | value = default | ||
445 | 408 | except (IndexOutOfRange, MissingKeyError, | ||
446 | 409 | NonDictLikeTypeError, IndexNotIntegerError) as exc: | ||
447 | 410 | msg = str(exc.message) | ||
448 | 411 | die("invalid path %r, %s" | ||
449 | 412 | % (key_value, | ||
450 | 413 | msg.replace('list', 'sequence').replace('dict', 'struct'))) | ||
451 | 414 | |||
452 | 415 | tvalue = type_name(value) | ||
453 | 416 | termination = "\0" if action.endswith("-0") else "\n" | ||
454 | 417 | |||
455 | 418 | if action == "get-value": | ||
456 | 419 | print(dump(value), end='') | ||
457 | 420 | elif action in ("get-values", "get-values-0"): | ||
458 | 421 | if isinstance(value, dict): | ||
459 | 422 | for k, v in value.iteritems(): | ||
460 | 423 | stdout("%s%s%s%s" % (dump(k), termination, | ||
461 | 424 | dump(v), termination)) | ||
462 | 425 | elif isinstance(value, list): | ||
463 | 426 | for l in value: | ||
464 | 427 | stdout("%s%s" % (dump(l), termination)) | ||
465 | 428 | else: | ||
466 | 429 | die("%s does not support %r type. " | ||
467 | 430 | "Please provide or select a sequence or struct." | ||
468 | 431 | % (action, tvalue)) | ||
469 | 432 | elif action == "get-type": | ||
470 | 433 | print(tvalue) | ||
471 | 434 | elif action in ("keys", "keys-0", | ||
472 | 435 | "values", "values-0", | ||
473 | 436 | "key-values", "key-values-0"): | ||
474 | 437 | if isinstance(value, dict): | ||
475 | 438 | method = value.keys if action.startswith("keys") else \ | ||
476 | 439 | value.items if action.startswith("key-values") else \ | ||
477 | 440 | value.values | ||
478 | 441 | output = (lambda x: termination.join(str(dump(e)) for e in x)) \ | ||
479 | 442 | if action.startswith("key-values") else \ | ||
480 | 443 | dump | ||
481 | 444 | for k in method(): | ||
482 | 445 | stdout("%s%s" % (output(k), termination)) | ||
483 | 446 | else: | ||
484 | 447 | die("%s does not support %r type. " | ||
485 | 448 | "Please provide or select a struct." % (action, tvalue)) | ||
486 | 449 | else: | ||
487 | 450 | die("Invalid argument.\n%s" % USAGE) | ||
488 | 451 | |||
489 | 452 | |||
490 | 453 | if __name__ == "__main__": | ||
491 | 454 | sys.exit(main(sys.argv[1:])) | ||
492 | diff --git a/tools/snapbuild.sh b/tools/snapbuild.sh | |||
493 | index 20ca763..c98fcb4 100755 | |||
494 | --- a/tools/snapbuild.sh | |||
495 | +++ b/tools/snapbuild.sh | |||
496 | @@ -24,10 +24,16 @@ fi | |||
497 | 24 | SERIES=xenial | 24 | SERIES=xenial |
498 | 25 | SOURCE_DIR= | 25 | SOURCE_DIR= |
499 | 26 | RESULTS_DIR= | 26 | RESULTS_DIR= |
500 | 27 | # Whenever you change the chroot in a way which needs a regeneration | ||
501 | 28 | # on the build server bump the version here. This will tell the | ||
502 | 29 | # job which updates the chroots to generate a new one. | ||
503 | 27 | CHROOT_VERSION=1 | 30 | CHROOT_VERSION=1 |
505 | 28 | ARCH=amd64 | 31 | BUILD_ARCH=amd64 |
506 | 32 | TARGET_ARCH=amd64 | ||
507 | 29 | UPDATE_CHROOT=false | 33 | UPDATE_CHROOT=false |
508 | 30 | PROXY= | 34 | PROXY= |
509 | 35 | CROSS_BUILD=false | ||
510 | 36 | SNAPCRAFT_EXTRA_ARGS= | ||
511 | 31 | 37 | ||
512 | 32 | while [ -n "$1" ]; do | 38 | while [ -n "$1" ]; do |
513 | 33 | case "$1" in | 39 | case "$1" in |
514 | @@ -44,7 +50,8 @@ while [ -n "$1" ]; do | |||
515 | 44 | shift | 50 | shift |
516 | 45 | ;; | 51 | ;; |
517 | 46 | --arch=*) | 52 | --arch=*) |
519 | 47 | ARCH=${1#*=} | 53 | TARGET_ARCH=${1#*=} |
520 | 54 | BUILD_ARCH=$TARGET_ARCH | ||
521 | 48 | shift | 55 | shift |
522 | 49 | ;; | 56 | ;; |
523 | 50 | --update-chroot) | 57 | --update-chroot) |
524 | @@ -55,6 +62,10 @@ while [ -n "$1" ]; do | |||
525 | 55 | PROXY=${1#*=} | 62 | PROXY=${1#*=} |
526 | 56 | shift | 63 | shift |
527 | 57 | ;; | 64 | ;; |
528 | 65 | --cross-build) | ||
529 | 66 | CROSS_BUILD=true | ||
530 | 67 | shift | ||
531 | 68 | ;; | ||
532 | 58 | *) | 69 | *) |
533 | 59 | echo "ERROR: Unknown options $1" | 70 | echo "ERROR: Unknown options $1" |
534 | 60 | exit 1 | 71 | exit 1 |
535 | @@ -66,8 +77,14 @@ if [ -z "$SERIES" ]; then | |||
536 | 66 | exit 1 | 77 | exit 1 |
537 | 67 | fi | 78 | fi |
538 | 68 | 79 | ||
539 | 80 | # If we're cross-building we have to switch the architecture we're using | ||
540 | 81 | # for our build environment to match our host arch. | ||
541 | 82 | if [ "$CROSS_BUILD" = true ]; then | ||
542 | 83 | HOST_ARCH=$(dpkg --print-architecture) | ||
543 | 84 | fi | ||
544 | 85 | |||
545 | 69 | CHROOT_STORE_PATH=/build/chroots | 86 | CHROOT_STORE_PATH=/build/chroots |
547 | 70 | CHROOT_TARBALL=$SERIES-$ARCH-$CHROOT_VERSION-rootfs.tar | 87 | CHROOT_TARBALL=$SERIES-$BUILD_ARCH-$CHROOT_VERSION-rootfs.tar |
548 | 71 | 88 | ||
549 | 72 | if [ "$UPDATE_CHROOT" = true ]; then | 89 | if [ "$UPDATE_CHROOT" = true ]; then |
550 | 73 | if [ ! -e $CHROOT_STORE_PATH/$CHROOT_TARBALL ] ; then | 90 | if [ ! -e $CHROOT_STORE_PATH/$CHROOT_TARBALL ] ; then |
551 | @@ -77,7 +94,7 @@ if [ "$UPDATE_CHROOT" = true ]; then | |||
552 | 77 | 94 | ||
553 | 78 | DEBOOTSTRAP=debootstrap | 95 | DEBOOTSTRAP=debootstrap |
554 | 79 | DEB_REPO_URL= | 96 | DEB_REPO_URL= |
556 | 80 | case "$ARCH" in | 97 | case "$BUILD_ARCH" in |
557 | 81 | amd64) | 98 | amd64) |
558 | 82 | DEB_REPO_URL="http://archive.ubuntu.com/ubuntu/" | 99 | DEB_REPO_URL="http://archive.ubuntu.com/ubuntu/" |
559 | 83 | ;; | 100 | ;; |
560 | @@ -86,7 +103,7 @@ if [ "$UPDATE_CHROOT" = true ]; then | |||
561 | 86 | DEB_REPO_URL="http://ports.ubuntu.com/ubuntu-ports" | 103 | DEB_REPO_URL="http://ports.ubuntu.com/ubuntu-ports" |
562 | 87 | ;; | 104 | ;; |
563 | 88 | *) | 105 | *) |
565 | 89 | echo "ERROR: Unsupported architecture $ARCH" | 106 | echo "ERROR: Unsupported architecture $BUILD_ARCH" |
566 | 90 | exit 1 | 107 | exit 1 |
567 | 91 | ;; | 108 | ;; |
568 | 92 | esac | 109 | esac |
569 | @@ -97,7 +114,7 @@ if [ "$UPDATE_CHROOT" = true ]; then | |||
570 | 97 | 114 | ||
571 | 98 | trap cleanup INT EXIT | 115 | trap cleanup INT EXIT |
572 | 99 | 116 | ||
574 | 100 | $DEBOOTSTRAP --components=main,universe --arch $ARCH $SERIES $WORKDIR/rootfs | 117 | $DEBOOTSTRAP --components=main,universe --arch $BUILD_ARCH $SERIES $WORKDIR/rootfs |
575 | 101 | cat << EOF > $WORKDIR/rootfs/etc/apt/sources.list.d/updates.list | 118 | cat << EOF > $WORKDIR/rootfs/etc/apt/sources.list.d/updates.list |
576 | 102 | deb $DEB_REPO_URL xenial universe | 119 | deb $DEB_REPO_URL xenial universe |
577 | 103 | deb $DEB_REPO_URL xenial-updates main universe | 120 | deb $DEB_REPO_URL xenial-updates main universe |
578 | @@ -147,19 +164,27 @@ tar xf $CHROOT_STORE_PATH/$CHROOT_TARBALL -C $BUILDDIR | |||
579 | 147 | 164 | ||
580 | 148 | cp -ra $SOURCE_DIR $BUILDDIR/src | 165 | cp -ra $SOURCE_DIR $BUILDDIR/src |
581 | 149 | 166 | ||
582 | 167 | if [ "$CROSS_BUILD" = true ]; then | ||
583 | 168 | SNAPCRAFT_EXTRA_ARGS="$SNAPCRAFT_EXTRA_ARGS --target-arch=$TARGET_ARCH" | ||
584 | 169 | fi | ||
585 | 170 | |||
586 | 150 | cat << EOF > $BUILDDIR/do-build.sh | 171 | cat << EOF > $BUILDDIR/do-build.sh |
587 | 151 | #!/bin/sh | 172 | #!/bin/sh |
588 | 152 | set -ex | 173 | set -ex |
589 | 153 | apt update | 174 | apt update |
590 | 154 | apt upgrade -y | 175 | apt upgrade -y |
591 | 155 | cd /src | 176 | cd /src |
592 | 177 | |||
593 | 178 | # snapcraft is pretty unhappy when LC_ALL and LANG aren't set | ||
594 | 179 | export LC_ALL=C.UTF-8 | ||
595 | 180 | export LANG=C.UTF-8 | ||
596 | 181 | |||
597 | 182 | # To access certain things like the snap store we need a proxy in place | ||
598 | 183 | # in some environments | ||
599 | 156 | export http_proxy=$PROXY | 184 | export http_proxy=$PROXY |
600 | 157 | export https_proxy=$PROXY | 185 | export https_proxy=$PROXY |
602 | 158 | SNAPCRAFT_EXTRA_ARGS= | 186 | |
603 | 159 | snapcraft clean | 187 | snapcraft clean |
604 | 160 | if [ -e /src/.ci-setup.sh ]; then | ||
605 | 161 | . /src/.ci-setup.sh | ||
606 | 162 | fi | ||
607 | 163 | snapcraft $SNAPCRAFT_EXTRA_ARGS | 188 | snapcraft $SNAPCRAFT_EXTRA_ARGS |
608 | 164 | EOF | 189 | EOF |
609 | 165 | chmod +x $BUILDDIR/do-build.sh | 190 | chmod +x $BUILDDIR/do-build.sh |
PASSED: Continuous integration, rev:885a030d128 01820417586b754 577d7633060f08 /jenkins. canonical. com/system- enablement/ job/generic- build-snap/ 1674/ /jenkins. canonical. com/system- enablement/ job/generic- build-snap- worker/ 2204 /jenkins. canonical. com/system- enablement/ job/generic- update- snap-mp/ 1582/console /jenkins. canonical. com/system- enablement/ job/generic- test-snap/ 2568
https:/
Executed test runs:
SUCCESS: https:/
None: https:/
SUCCESS: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- enablement/ job/generic- build-snap/ 1674/rebuild
https:/