blob: aa64553c06b67e290408e48c3096c2e78ee2f0fd [file] [log] [blame]
Patrick Williamsc124f4f2015-09-15 14:41:29 -05001# Utility functions for reading and modifying recipes
2#
3# Some code borrowed from the OE layer index
4#
Brad Bishopd7bf8c12018-02-25 22:55:05 -05005# Copyright (C) 2013-2017 Intel Corporation
Patrick Williamsc124f4f2015-09-15 14:41:29 -05006#
7
8import sys
9import os
10import os.path
11import tempfile
12import textwrap
13import difflib
Patrick Williamsc0f7c042017-02-23 20:41:17 -060014from . import utils
Patrick Williamsc124f4f2015-09-15 14:41:29 -050015import shutil
16import re
17import fnmatch
Patrick Williamsc0f7c042017-02-23 20:41:17 -060018import glob
Patrick Williamsc124f4f2015-09-15 14:41:29 -050019from collections import OrderedDict, defaultdict
20
21
22# Help us to find places to insert values
Patrick Williamsc0f7c042017-02-23 20:41:17 -060023recipe_progression = ['SUMMARY', 'DESCRIPTION', 'HOMEPAGE', 'BUGTRACKER', 'SECTION', 'LICENSE', 'LICENSE_FLAGS', 'LIC_FILES_CHKSUM', 'PROVIDES', 'DEPENDS', 'PR', 'PV', 'SRCREV', 'SRCPV', 'SRC_URI', 'S', 'do_fetch()', 'do_unpack()', 'do_patch()', 'EXTRA_OECONF', 'EXTRA_OECMAKE', 'EXTRA_OESCONS', 'do_configure()', 'EXTRA_OEMAKE', 'do_compile()', 'do_install()', 'do_populate_sysroot()', 'INITSCRIPT', 'USERADD', 'GROUPADD', 'PACKAGES', 'FILES', 'RDEPENDS', 'RRECOMMENDS', 'RSUGGESTS', 'RPROVIDES', 'RREPLACES', 'RCONFLICTS', 'ALLOW_EMPTY', 'populate_packages()', 'do_package()', 'do_deploy()']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050024# Variables that sometimes are a bit long but shouldn't be wrapped
Brad Bishop316dfdd2018-06-25 12:45:53 -040025nowrap_vars = ['SUMMARY', 'HOMEPAGE', 'BUGTRACKER', 'SRC_URI\[(.+\.)?md5sum\]', 'SRC_URI\[(.+\.)?sha256sum\]']
Patrick Williamsc124f4f2015-09-15 14:41:29 -050026list_vars = ['SRC_URI', 'LIC_FILES_CHKSUM']
27meta_vars = ['SUMMARY', 'DESCRIPTION', 'HOMEPAGE', 'BUGTRACKER', 'SECTION']
28
29
Patrick Williamsc0f7c042017-02-23 20:41:17 -060030def pn_to_recipe(cooker, pn, mc=''):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050031 """Convert a recipe name (PN) to the path to the recipe file"""
Patrick Williamsc124f4f2015-09-15 14:41:29 -050032
Brad Bishop6e60e8b2018-02-01 10:27:11 -050033 best = cooker.findBestProvider(pn, mc)
34 return best[3]
Patrick Williamsc124f4f2015-09-15 14:41:29 -050035
36
37def get_unavailable_reasons(cooker, pn):
38 """If a recipe could not be found, find out why if possible"""
39 import bb.taskdata
40 taskdata = bb.taskdata.TaskData(None, skiplist=cooker.skiplist)
41 return taskdata.get_reasons(pn)
42
43
Patrick Williamsc0f7c042017-02-23 20:41:17 -060044def parse_recipe(cooker, fn, appendfiles):
Patrick Williamsc124f4f2015-09-15 14:41:29 -050045 """
46 Parse an individual recipe file, optionally with a list of
47 bbappend files.
48 """
49 import bb.cache
Patrick Williamsc0f7c042017-02-23 20:41:17 -060050 parser = bb.cache.NoCache(cooker.databuilder)
51 envdata = parser.loadDataFull(fn, appendfiles)
Patrick Williamsc124f4f2015-09-15 14:41:29 -050052 return envdata
53
54
Patrick Williamsc124f4f2015-09-15 14:41:29 -050055def get_var_files(fn, varlist, d):
56 """Find the file in which each of a list of variables is set.
57 Note: requires variable history to be enabled when parsing.
58 """
59 varfiles = {}
60 for v in varlist:
61 history = d.varhistory.variable(v)
62 files = []
63 for event in history:
64 if 'file' in event and not 'flag' in event:
65 files.append(event['file'])
66 if files:
67 actualfile = files[-1]
68 else:
69 actualfile = None
70 varfiles[v] = actualfile
71
72 return varfiles
73
74
Patrick Williamsf1e5d692016-03-30 15:21:19 -050075def split_var_value(value, assignment=True):
76 """
77 Split a space-separated variable's value into a list of items,
78 taking into account that some of the items might be made up of
79 expressions containing spaces that should not be split.
80 Parameters:
81 value:
82 The string value to split
83 assignment:
84 True to assume that the value represents an assignment
85 statement, False otherwise. If True, and an assignment
86 statement is passed in the first item in
87 the returned list will be the part of the assignment
88 statement up to and including the opening quote character,
89 and the last item will be the closing quote.
90 """
91 inexpr = 0
92 lastchar = None
93 out = []
94 buf = ''
95 for char in value:
96 if char == '{':
97 if lastchar == '$':
98 inexpr += 1
99 elif char == '}':
100 inexpr -= 1
101 elif assignment and char in '"\'' and inexpr == 0:
102 if buf:
103 out.append(buf)
104 out.append(char)
105 char = ''
106 buf = ''
107 elif char.isspace() and inexpr == 0:
108 char = ''
109 if buf:
110 out.append(buf)
111 buf = ''
112 buf += char
113 lastchar = char
114 if buf:
115 out.append(buf)
116
117 # Join together assignment statement and opening quote
118 outlist = out
119 if assignment:
120 assigfound = False
121 for idx, item in enumerate(out):
122 if '=' in item:
123 assigfound = True
124 if assigfound:
125 if '"' in item or "'" in item:
126 outlist = [' '.join(out[:idx+1])]
127 outlist.extend(out[idx+1:])
128 break
129 return outlist
130
131
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600132def patch_recipe_lines(fromlines, values, trailing_newline=True):
133 """Update or insert variable values into lines from a recipe.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500134 Note that some manual inspection/intervention may be required
135 since this cannot handle all situations.
136 """
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500137
138 import bb.utils
139
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600140 if trailing_newline:
141 newline = '\n'
142 else:
143 newline = ''
144
Brad Bishop316dfdd2018-06-25 12:45:53 -0400145 nowrap_vars_res = []
146 for item in nowrap_vars:
147 nowrap_vars_res.append(re.compile('^%s$' % item))
148
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500149 recipe_progression_res = []
150 recipe_progression_restrs = []
151 for item in recipe_progression:
152 if item.endswith('()'):
153 key = item[:-2]
154 else:
155 key = item
156 restr = '%s(_[a-zA-Z0-9-_$(){}]+|\[[^\]]*\])?' % key
157 if item.endswith('()'):
158 recipe_progression_restrs.append(restr + '()')
159 else:
160 recipe_progression_restrs.append(restr)
161 recipe_progression_res.append(re.compile('^%s$' % restr))
162
163 def get_recipe_pos(variable):
164 for i, p in enumerate(recipe_progression_res):
165 if p.match(variable):
166 return i
167 return -1
168
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500169 remainingnames = {}
170 for k in values.keys():
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500171 remainingnames[k] = get_recipe_pos(k)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600172 remainingnames = OrderedDict(sorted(remainingnames.items(), key=lambda x: x[1]))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500173
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500174 modifying = False
175
176 def outputvalue(name, lines, rewindcomments=False):
177 if values[name] is None:
178 return
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600179 rawtext = '%s = "%s"%s' % (name, values[name], newline)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500180 addlines = []
Brad Bishop316dfdd2018-06-25 12:45:53 -0400181 nowrap = False
182 for nowrap_re in nowrap_vars_res:
183 if nowrap_re.match(name):
184 nowrap = True
185 break
186 if nowrap:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500187 addlines.append(rawtext)
188 elif name in list_vars:
189 splitvalue = split_var_value(values[name], assignment=False)
190 if len(splitvalue) > 1:
191 linesplit = ' \\\n' + (' ' * (len(name) + 4))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600192 addlines.append('%s = "%s%s"%s' % (name, linesplit.join(splitvalue), linesplit, newline))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500193 else:
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500194 addlines.append(rawtext)
195 else:
196 wrapped = textwrap.wrap(rawtext)
197 for wrapline in wrapped[:-1]:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600198 addlines.append('%s \\%s' % (wrapline, newline))
199 addlines.append('%s%s' % (wrapped[-1], newline))
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500200
201 # Split on newlines - this isn't strictly necessary if you are only
202 # going to write the output to disk, but if you want to compare it
203 # (as patch_recipe_file() will do if patch=True) then it's important.
204 addlines = [line for l in addlines for line in l.splitlines(True)]
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500205 if rewindcomments:
206 # Ensure we insert the lines before any leading comments
207 # (that we'd want to ensure remain leading the next value)
208 for i, ln in reversed(list(enumerate(lines))):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600209 if not ln.startswith('#'):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500210 lines[i+1:i+1] = addlines
211 break
212 else:
213 lines.extend(addlines)
214 else:
215 lines.extend(addlines)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500216
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500217 existingnames = []
218 def patch_recipe_varfunc(varname, origvalue, op, newlines):
219 if modifying:
220 # Insert anything that should come before this variable
221 pos = get_recipe_pos(varname)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600222 for k in list(remainingnames):
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500223 if remainingnames[k] > -1 and pos >= remainingnames[k] and not k in existingnames:
224 outputvalue(k, newlines, rewindcomments=True)
225 del remainingnames[k]
226 # Now change this variable, if it needs to be changed
227 if varname in existingnames and op in ['+=', '=', '=+']:
228 if varname in remainingnames:
229 outputvalue(varname, newlines)
230 del remainingnames[varname]
231 return None, None, 0, True
232 else:
233 if varname in values:
234 existingnames.append(varname)
235 return origvalue, None, 0, True
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500236
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500237 # First run - establish which values we want to set are already in the file
238 varlist = [re.escape(item) for item in values.keys()]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600239 bb.utils.edit_metadata(fromlines, varlist, patch_recipe_varfunc)
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500240 # Second run - actually set everything
241 modifying = True
242 varlist.extend(recipe_progression_restrs)
243 changed, tolines = bb.utils.edit_metadata(fromlines, varlist, patch_recipe_varfunc, match_overrides=True)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500244
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500245 if remainingnames:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600246 if tolines and tolines[-1].strip() != '':
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500247 tolines.append('\n')
248 for k in remainingnames.keys():
249 outputvalue(k, tolines)
250
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600251 return changed, tolines
252
253
Brad Bishop316dfdd2018-06-25 12:45:53 -0400254def patch_recipe_file(fn, values, patch=False, relpath='', redirect_output=None):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600255 """Update or insert variable values into a recipe file (assuming you
256 have already identified the exact file you want to update.)
257 Note that some manual inspection/intervention may be required
258 since this cannot handle all situations.
259 """
260
261 with open(fn, 'r') as f:
262 fromlines = f.readlines()
263
264 _, tolines = patch_recipe_lines(fromlines, values)
265
Brad Bishop316dfdd2018-06-25 12:45:53 -0400266 if redirect_output:
267 with open(os.path.join(redirect_output, os.path.basename(fn)), 'w') as f:
268 f.writelines(tolines)
269 return None
270 elif patch:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500271 relfn = os.path.relpath(fn, relpath)
272 diff = difflib.unified_diff(fromlines, tolines, 'a/%s' % relfn, 'b/%s' % relfn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500273 return diff
274 else:
275 with open(fn, 'w') as f:
276 f.writelines(tolines)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500277 return None
278
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500279
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500280def localise_file_vars(fn, varfiles, varlist):
281 """Given a list of variables and variable history (fetched with get_var_files())
282 find where each variable should be set/changed. This handles for example where a
283 recipe includes an inc file where variables might be changed - in most cases
284 we want to update the inc file when changing the variable value rather than adding
285 it to the recipe itself.
286 """
287 fndir = os.path.dirname(fn) + os.sep
288
289 first_meta_file = None
290 for v in meta_vars:
291 f = varfiles.get(v, None)
292 if f:
293 actualdir = os.path.dirname(f) + os.sep
294 if actualdir.startswith(fndir):
295 first_meta_file = f
296 break
297
298 filevars = defaultdict(list)
299 for v in varlist:
300 f = varfiles[v]
301 # Only return files that are in the same directory as the recipe or in some directory below there
302 # (this excludes bbclass files and common inc files that wouldn't be appropriate to set the variable
303 # in if we were going to set a value specific to this recipe)
304 if f:
305 actualfile = f
306 else:
307 # Variable isn't in a file, if it's one of the "meta" vars, use the first file with a meta var in it
308 if first_meta_file:
309 actualfile = first_meta_file
310 else:
311 actualfile = fn
312
313 actualdir = os.path.dirname(actualfile) + os.sep
314 if not actualdir.startswith(fndir):
315 actualfile = fn
316 filevars[actualfile].append(v)
317
318 return filevars
319
Brad Bishop316dfdd2018-06-25 12:45:53 -0400320def patch_recipe(d, fn, varvalues, patch=False, relpath='', redirect_output=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500321 """Modify a list of variable values in the specified recipe. Handles inc files if
322 used by the recipe.
323 """
324 varlist = varvalues.keys()
325 varfiles = get_var_files(fn, varlist, d)
326 locs = localise_file_vars(fn, varfiles, varlist)
327 patches = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600328 for f,v in locs.items():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500329 vals = {k: varvalues[k] for k in v}
Brad Bishop316dfdd2018-06-25 12:45:53 -0400330 patchdata = patch_recipe_file(f, vals, patch, relpath, redirect_output)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500331 if patch:
332 patches.append(patchdata)
333
334 if patch:
335 return patches
336 else:
337 return None
338
339
340
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500341def copy_recipe_files(d, tgt_dir, whole_dir=False, download=True, all_variants=False):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500342 """Copy (local) recipe files, including both files included via include/require,
343 and files referred to in the SRC_URI variable."""
344 import bb.fetch2
345 import oe.path
346
347 # FIXME need a warning if the unexpanded SRC_URI value contains variable references
348
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500349 uri_values = []
350 localpaths = []
351 def fetch_urls(rdata):
352 # Collect the local paths from SRC_URI
353 srcuri = rdata.getVar('SRC_URI') or ""
354 if srcuri not in uri_values:
355 fetch = bb.fetch2.Fetch(srcuri.split(), rdata)
356 if download:
357 fetch.download()
358 for pth in fetch.localpaths():
359 if pth not in localpaths:
360 localpaths.append(pth)
361 uri_values.append(srcuri)
362
363 fetch_urls(d)
364 if all_variants:
365 # Get files for other variants e.g. in the case of a SRC_URI_append
366 localdata = bb.data.createCopy(d)
367 variants = (localdata.getVar('BBCLASSEXTEND') or '').split()
368 if variants:
369 # Ensure we handle class-target if we're dealing with one of the variants
370 variants.append('target')
371 for variant in variants:
372 localdata.setVar('CLASSOVERRIDE', 'class-%s' % variant)
373 fetch_urls(localdata)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500374
375 # Copy local files to target directory and gather any remote files
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500376 bb_dir = os.path.abspath(os.path.dirname(d.getVar('FILE'))) + os.sep
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500377 remotes = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600378 copied = []
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500379 # Need to do this in two steps since we want to check against the absolute path
380 includes = [os.path.abspath(path) for path in d.getVar('BBINCLUDED').split() if os.path.exists(path)]
381 # We also check this below, but we don't want any items in this list being considered remotes
382 includes = [path for path in includes if path.startswith(bb_dir)]
383 for path in localpaths + includes:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500384 # Only import files that are under the meta directory
385 if path.startswith(bb_dir):
386 if not whole_dir:
387 relpath = os.path.relpath(path, bb_dir)
388 subdir = os.path.join(tgt_dir, os.path.dirname(relpath))
389 if not os.path.exists(subdir):
390 os.makedirs(subdir)
391 shutil.copy2(path, os.path.join(tgt_dir, relpath))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600392 copied.append(relpath)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500393 else:
394 remotes.append(path)
395 # Simply copy whole meta dir, if requested
396 if whole_dir:
397 shutil.copytree(bb_dir, tgt_dir)
398
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600399 return copied, remotes
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500400
401
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500402def get_recipe_local_files(d, patches=False, archives=False):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500403 """Get a list of local files in SRC_URI within a recipe."""
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500404 import oe.patch
405 uris = (d.getVar('SRC_URI') or "").split()
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500406 fetch = bb.fetch2.Fetch(uris, d)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500407 # FIXME this list should be factored out somewhere else (such as the
408 # fetcher) though note that this only encompasses actual container formats
409 # i.e. that can contain multiple files as opposed to those that only
410 # contain a compressed stream (i.e. .tar.gz as opposed to just .gz)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400411 archive_exts = ['.tar', '.tgz', '.tar.gz', '.tar.Z', '.tbz', '.tbz2', '.tar.bz2', '.txz', '.tar.xz', '.tar.lz', '.zip', '.jar', '.rpm', '.srpm', '.deb', '.ipk', '.tar.7z', '.7z']
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500412 ret = {}
413 for uri in uris:
414 if fetch.ud[uri].type == 'file':
415 if (not patches and
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500416 oe.patch.patch_path(uri, fetch, '', expand=False)):
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500417 continue
418 # Skip files that are referenced by absolute path
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600419 fname = fetch.ud[uri].basepath
420 if os.path.isabs(fname):
421 continue
422 # Handle subdir=
423 subdir = fetch.ud[uri].parm.get('subdir', '')
424 if subdir:
425 if os.path.isabs(subdir):
426 continue
427 fname = os.path.join(subdir, fname)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500428 localpath = fetch.localpath(uri)
429 if not archives:
430 # Ignore archives that will be unpacked
431 if localpath.endswith(tuple(archive_exts)):
432 unpack = fetch.ud[uri].parm.get('unpack', True)
433 if unpack:
434 continue
435 ret[fname] = localpath
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500436 return ret
437
438
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500439def get_recipe_patches(d):
440 """Get a list of the patches included in SRC_URI within a recipe."""
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500441 import oe.patch
442 patches = oe.patch.src_patches(d, expand=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500443 patchfiles = []
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500444 for patch in patches:
445 _, _, local, _, _, parm = bb.fetch.decodeurl(patch)
446 patchfiles.append(local)
447 return patchfiles
448
449
450def get_recipe_patched_files(d):
451 """
452 Get the list of patches for a recipe along with the files each patch modifies.
453 Params:
454 d: the datastore for the recipe
455 Returns:
456 a dict mapping patch file path to a list of tuples of changed files and
457 change mode ('A' for add, 'D' for delete or 'M' for modify)
458 """
459 import oe.patch
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500460 patches = oe.patch.src_patches(d, expand=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500461 patchedfiles = {}
462 for patch in patches:
463 _, _, patchfile, _, _, parm = bb.fetch.decodeurl(patch)
464 striplevel = int(parm['striplevel'])
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500465 patchedfiles[patchfile] = oe.patch.PatchSet.getPatchedFiles(patchfile, striplevel, os.path.join(d.getVar('S'), parm.get('patchdir', '')))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500466 return patchedfiles
467
468
469def validate_pn(pn):
470 """Perform validation on a recipe name (PN) for a new recipe."""
471 reserved_names = ['forcevariable', 'append', 'prepend', 'remove']
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600472 if not re.match('^[0-9a-z-.+]+$', pn):
473 return 'Recipe name "%s" is invalid: only characters 0-9, a-z, -, + and . are allowed' % pn
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500474 elif pn in reserved_names:
475 return 'Recipe name "%s" is invalid: is a reserved keyword' % pn
476 elif pn.startswith('pn-'):
477 return 'Recipe name "%s" is invalid: names starting with "pn-" are reserved' % pn
Patrick Williamsd8c66bc2016-06-20 12:57:21 -0500478 elif pn.endswith(('.bb', '.bbappend', '.bbclass', '.inc', '.conf')):
479 return 'Recipe name "%s" is invalid: should be just a name, not a file name' % pn
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500480 return ''
481
482
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600483def get_bbfile_path(d, destdir, extrapathhint=None):
484 """
485 Determine the correct path for a recipe within a layer
486 Parameters:
487 d: Recipe-specific datastore
488 destdir: destination directory. Can be the path to the base of the layer or a
489 partial path somewhere within the layer.
490 extrapathhint: a path relative to the base of the layer to try
491 """
492 import bb.cookerdata
493
494 destdir = os.path.abspath(destdir)
495 destlayerdir = find_layerdir(destdir)
496
497 # Parse the specified layer's layer.conf file directly, in case the layer isn't in bblayers.conf
498 confdata = d.createCopy()
499 confdata.setVar('BBFILES', '')
500 confdata.setVar('LAYERDIR', destlayerdir)
501 destlayerconf = os.path.join(destlayerdir, "conf", "layer.conf")
502 confdata = bb.cookerdata.parse_config_file(destlayerconf, confdata)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500503 pn = d.getVar('PN')
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600504
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500505 bbfilespecs = (confdata.getVar('BBFILES') or '').split()
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600506 if destdir == destlayerdir:
507 for bbfilespec in bbfilespecs:
508 if not bbfilespec.endswith('.bbappend'):
509 for match in glob.glob(bbfilespec):
510 splitext = os.path.splitext(os.path.basename(match))
511 if splitext[1] == '.bb':
512 mpn = splitext[0].split('_')[0]
513 if mpn == pn:
514 return os.path.dirname(match)
515
516 # Try to make up a path that matches BBFILES
517 # this is a little crude, but better than nothing
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500518 bpn = d.getVar('BPN')
519 recipefn = os.path.basename(d.getVar('FILE'))
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600520 pathoptions = [destdir]
521 if extrapathhint:
522 pathoptions.append(os.path.join(destdir, extrapathhint))
523 if destdir == destlayerdir:
524 pathoptions.append(os.path.join(destdir, 'recipes-%s' % bpn, bpn))
525 pathoptions.append(os.path.join(destdir, 'recipes', bpn))
526 pathoptions.append(os.path.join(destdir, bpn))
527 elif not destdir.endswith(('/' + pn, '/' + bpn)):
528 pathoptions.append(os.path.join(destdir, bpn))
529 closepath = ''
530 for pathoption in pathoptions:
531 bbfilepath = os.path.join(pathoption, 'test.bb')
532 for bbfilespec in bbfilespecs:
533 if fnmatch.fnmatchcase(bbfilepath, bbfilespec):
534 return pathoption
535 return None
536
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500537def get_bbappend_path(d, destlayerdir, wildcardver=False):
538 """Determine how a bbappend for a recipe should be named and located within another layer"""
539
540 import bb.cookerdata
541
542 destlayerdir = os.path.abspath(destlayerdir)
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500543 recipefile = d.getVar('FILE')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500544 recipefn = os.path.splitext(os.path.basename(recipefile))[0]
545 if wildcardver and '_' in recipefn:
546 recipefn = recipefn.split('_', 1)[0] + '_%'
547 appendfn = recipefn + '.bbappend'
548
549 # Parse the specified layer's layer.conf file directly, in case the layer isn't in bblayers.conf
550 confdata = d.createCopy()
551 confdata.setVar('BBFILES', '')
552 confdata.setVar('LAYERDIR', destlayerdir)
553 destlayerconf = os.path.join(destlayerdir, "conf", "layer.conf")
554 confdata = bb.cookerdata.parse_config_file(destlayerconf, confdata)
555
556 origlayerdir = find_layerdir(recipefile)
557 if not origlayerdir:
558 return (None, False)
559 # Now join this to the path where the bbappend is going and check if it is covered by BBFILES
560 appendpath = os.path.join(destlayerdir, os.path.relpath(os.path.dirname(recipefile), origlayerdir), appendfn)
561 closepath = ''
562 pathok = True
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500563 for bbfilespec in confdata.getVar('BBFILES').split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500564 if fnmatch.fnmatchcase(appendpath, bbfilespec):
565 # Our append path works, we're done
566 break
567 elif bbfilespec.startswith(destlayerdir) and fnmatch.fnmatchcase('test.bbappend', os.path.basename(bbfilespec)):
568 # Try to find the longest matching path
569 if len(bbfilespec) > len(closepath):
570 closepath = bbfilespec
571 else:
572 # Unfortunately the bbappend layer and the original recipe's layer don't have the same structure
573 if closepath:
574 # bbappend layer's layer.conf at least has a spec that picks up .bbappend files
575 # Now we just need to substitute out any wildcards
576 appendsubdir = os.path.relpath(os.path.dirname(closepath), destlayerdir)
577 if 'recipes-*' in appendsubdir:
578 # Try to copy this part from the original recipe path
579 res = re.search('/recipes-[^/]+/', recipefile)
580 if res:
581 appendsubdir = appendsubdir.replace('/recipes-*/', res.group(0))
582 # This is crude, but we have to do something
583 appendsubdir = appendsubdir.replace('*', recipefn.split('_')[0])
584 appendsubdir = appendsubdir.replace('?', 'a')
585 appendpath = os.path.join(destlayerdir, appendsubdir, appendfn)
586 else:
587 pathok = False
588 return (appendpath, pathok)
589
590
Brad Bishop316dfdd2018-06-25 12:45:53 -0400591def bbappend_recipe(rd, destlayerdir, srcfiles, install=None, wildcardver=False, machine=None, extralines=None, removevalues=None, redirect_output=None):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500592 """
593 Writes a bbappend file for a recipe
594 Parameters:
595 rd: data dictionary for the recipe
596 destlayerdir: base directory of the layer to place the bbappend in
597 (subdirectory path from there will be determined automatically)
598 srcfiles: dict of source files to add to SRC_URI, where the value
599 is the full path to the file to be added, and the value is the
600 original filename as it would appear in SRC_URI or None if it
601 isn't already present. You may pass None for this parameter if
602 you simply want to specify your own content via the extralines
603 parameter.
604 install: dict mapping entries in srcfiles to a tuple of two elements:
605 install path (*without* ${D} prefix) and permission value (as a
606 string, e.g. '0644').
607 wildcardver: True to use a % wildcard in the bbappend filename, or
608 False to make the bbappend specific to the recipe version.
609 machine:
610 If specified, make the changes in the bbappend specific to this
611 machine. This will also cause PACKAGE_ARCH = "${MACHINE_ARCH}"
612 to be added to the bbappend.
613 extralines:
614 Extra lines to add to the bbappend. This may be a dict of name
615 value pairs, or simply a list of the lines.
616 removevalues:
617 Variable values to remove - a dict of names/values.
Brad Bishop316dfdd2018-06-25 12:45:53 -0400618 redirect_output:
619 If specified, redirects writing the output file to the
620 specified directory (for dry-run purposes)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500621 """
622
623 if not removevalues:
624 removevalues = {}
625
626 # Determine how the bbappend should be named
627 appendpath, pathok = get_bbappend_path(rd, destlayerdir, wildcardver)
628 if not appendpath:
629 bb.error('Unable to determine layer directory containing %s' % recipefile)
630 return (None, None)
631 if not pathok:
632 bb.warn('Unable to determine correct subdirectory path for bbappend file - check that what %s adds to BBFILES also matches .bbappend files. Using %s for now, but until you fix this the bbappend will not be applied.' % (os.path.join(destlayerdir, 'conf', 'layer.conf'), os.path.dirname(appendpath)))
633
634 appenddir = os.path.dirname(appendpath)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400635 if not redirect_output:
636 bb.utils.mkdirhier(appenddir)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500637
638 # FIXME check if the bbappend doesn't get overridden by a higher priority layer?
639
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500640 layerdirs = [os.path.abspath(layerdir) for layerdir in rd.getVar('BBLAYERS').split()]
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500641 if not os.path.abspath(destlayerdir) in layerdirs:
642 bb.warn('Specified layer is not currently enabled in bblayers.conf, you will need to add it before this bbappend will be active')
643
644 bbappendlines = []
645 if extralines:
646 if isinstance(extralines, dict):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600647 for name, value in extralines.items():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500648 bbappendlines.append((name, '=', value))
649 else:
650 # Do our best to split it
651 for line in extralines:
652 if line[-1] == '\n':
653 line = line[:-1]
654 splitline = line.split(None, 2)
655 if len(splitline) == 3:
656 bbappendlines.append(tuple(splitline))
657 else:
658 raise Exception('Invalid extralines value passed')
659
660 def popline(varname):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600661 for i in range(0, len(bbappendlines)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500662 if bbappendlines[i][0] == varname:
663 line = bbappendlines.pop(i)
664 return line
665 return None
666
667 def appendline(varname, op, value):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600668 for i in range(0, len(bbappendlines)):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500669 item = bbappendlines[i]
670 if item[0] == varname:
671 bbappendlines[i] = (item[0], item[1], item[2] + ' ' + value)
672 break
673 else:
674 bbappendlines.append((varname, op, value))
675
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500676 destsubdir = rd.getVar('PN')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500677 if srcfiles:
678 bbappendlines.append(('FILESEXTRAPATHS_prepend', ':=', '${THISDIR}/${PN}:'))
679
680 appendoverride = ''
681 if machine:
682 bbappendlines.append(('PACKAGE_ARCH', '=', '${MACHINE_ARCH}'))
683 appendoverride = '_%s' % machine
684 copyfiles = {}
685 if srcfiles:
686 instfunclines = []
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600687 for newfile, origsrcfile in srcfiles.items():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500688 srcfile = origsrcfile
689 srcurientry = None
690 if not srcfile:
691 srcfile = os.path.basename(newfile)
692 srcurientry = 'file://%s' % srcfile
693 # Double-check it's not there already
694 # FIXME do we care if the entry is added by another bbappend that might go away?
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500695 if not srcurientry in rd.getVar('SRC_URI').split():
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500696 if machine:
697 appendline('SRC_URI_append%s' % appendoverride, '=', ' ' + srcurientry)
698 else:
699 appendline('SRC_URI', '+=', srcurientry)
700 copyfiles[newfile] = srcfile
701 if install:
702 institem = install.pop(newfile, None)
703 if institem:
704 (destpath, perms) = institem
705 instdestpath = replace_dir_vars(destpath, rd)
706 instdirline = 'install -d ${D}%s' % os.path.dirname(instdestpath)
707 if not instdirline in instfunclines:
708 instfunclines.append(instdirline)
709 instfunclines.append('install -m %s ${WORKDIR}/%s ${D}%s' % (perms, os.path.basename(srcfile), instdestpath))
710 if instfunclines:
711 bbappendlines.append(('do_install_append%s()' % appendoverride, '', instfunclines))
712
Brad Bishop316dfdd2018-06-25 12:45:53 -0400713 if redirect_output:
714 bb.note('Writing append file %s (dry-run)' % appendpath)
715 outfile = os.path.join(redirect_output, os.path.basename(appendpath))
716 # Only take a copy if the file isn't already there (this function may be called
717 # multiple times per operation when we're handling overrides)
718 if os.path.exists(appendpath) and not os.path.exists(outfile):
719 shutil.copy2(appendpath, outfile)
720 else:
721 bb.note('Writing append file %s' % appendpath)
722 outfile = appendpath
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500723
Brad Bishop316dfdd2018-06-25 12:45:53 -0400724 if os.path.exists(outfile):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500725 # Work around lack of nonlocal in python 2
726 extvars = {'destsubdir': destsubdir}
727
728 def appendfile_varfunc(varname, origvalue, op, newlines):
729 if varname == 'FILESEXTRAPATHS_prepend':
730 if origvalue.startswith('${THISDIR}/'):
731 popline('FILESEXTRAPATHS_prepend')
732 extvars['destsubdir'] = rd.expand(origvalue.split('${THISDIR}/', 1)[1].rstrip(':'))
733 elif varname == 'PACKAGE_ARCH':
734 if machine:
735 popline('PACKAGE_ARCH')
736 return (machine, None, 4, False)
737 elif varname.startswith('do_install_append'):
738 func = popline(varname)
739 if func:
740 instfunclines = [line.strip() for line in origvalue.strip('\n').splitlines()]
741 for line in func[2]:
742 if not line in instfunclines:
743 instfunclines.append(line)
744 return (instfunclines, None, 4, False)
745 else:
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500746 splitval = split_var_value(origvalue, assignment=False)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500747 changed = False
748 removevar = varname
749 if varname in ['SRC_URI', 'SRC_URI_append%s' % appendoverride]:
750 removevar = 'SRC_URI'
751 line = popline(varname)
752 if line:
753 if line[2] not in splitval:
754 splitval.append(line[2])
755 changed = True
756 else:
757 line = popline(varname)
758 if line:
759 splitval = [line[2]]
760 changed = True
761
762 if removevar in removevalues:
763 remove = removevalues[removevar]
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600764 if isinstance(remove, str):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500765 if remove in splitval:
766 splitval.remove(remove)
767 changed = True
768 else:
769 for removeitem in remove:
770 if removeitem in splitval:
771 splitval.remove(removeitem)
772 changed = True
773
774 if changed:
775 newvalue = splitval
776 if len(newvalue) == 1:
777 # Ensure it's written out as one line
778 if '_append' in varname:
779 newvalue = ' ' + newvalue[0]
780 else:
781 newvalue = newvalue[0]
782 if not newvalue and (op in ['+=', '.='] or '_append' in varname):
783 # There's no point appending nothing
784 newvalue = None
785 if varname.endswith('()'):
786 indent = 4
787 else:
788 indent = -1
789 return (newvalue, None, indent, True)
790 return (origvalue, None, 4, False)
791
792 varnames = [item[0] for item in bbappendlines]
793 if removevalues:
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600794 varnames.extend(list(removevalues.keys()))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500795
Brad Bishop316dfdd2018-06-25 12:45:53 -0400796 with open(outfile, 'r') as f:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500797 (updated, newlines) = bb.utils.edit_metadata(f, varnames, appendfile_varfunc)
798
799 destsubdir = extvars['destsubdir']
800 else:
801 updated = False
802 newlines = []
803
804 if bbappendlines:
805 for line in bbappendlines:
806 if line[0].endswith('()'):
807 newlines.append('%s {\n %s\n}\n' % (line[0], '\n '.join(line[2])))
808 else:
809 newlines.append('%s %s "%s"\n\n' % line)
810 updated = True
811
812 if updated:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400813 with open(outfile, 'w') as f:
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500814 f.writelines(newlines)
815
816 if copyfiles:
817 if machine:
818 destsubdir = os.path.join(destsubdir, machine)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400819 if redirect_output:
820 outdir = redirect_output
821 else:
822 outdir = appenddir
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600823 for newfile, srcfile in copyfiles.items():
Brad Bishop316dfdd2018-06-25 12:45:53 -0400824 filedest = os.path.join(outdir, destsubdir, os.path.basename(srcfile))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500825 if os.path.abspath(newfile) != os.path.abspath(filedest):
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500826 if newfile.startswith(tempfile.gettempdir()):
827 newfiledisp = os.path.basename(newfile)
828 else:
829 newfiledisp = newfile
Brad Bishop316dfdd2018-06-25 12:45:53 -0400830 if redirect_output:
831 bb.note('Copying %s to %s (dry-run)' % (newfiledisp, os.path.join(appenddir, destsubdir, os.path.basename(srcfile))))
832 else:
833 bb.note('Copying %s to %s' % (newfiledisp, filedest))
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500834 bb.utils.mkdirhier(os.path.dirname(filedest))
835 shutil.copyfile(newfile, filedest)
836
837 return (appendpath, os.path.join(appenddir, destsubdir))
838
839
840def find_layerdir(fn):
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600841 """ Figure out the path to the base of the layer containing a file (e.g. a recipe)"""
Brad Bishopd7bf8c12018-02-25 22:55:05 -0500842 pth = os.path.abspath(fn)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500843 layerdir = ''
844 while pth:
845 if os.path.exists(os.path.join(pth, 'conf', 'layer.conf')):
846 layerdir = pth
847 break
848 pth = os.path.dirname(pth)
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600849 if pth == '/':
850 return None
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500851 return layerdir
852
853
854def replace_dir_vars(path, d):
855 """Replace common directory paths with appropriate variable references (e.g. /etc becomes ${sysconfdir})"""
856 dirvars = {}
857 # Sort by length so we get the variables we're interested in first
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600858 for var in sorted(list(d.keys()), key=len):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500859 if var.endswith('dir') and var.lower() == var:
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500860 value = d.getVar(var)
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500861 if value.startswith('/') and not '\n' in value and value not in dirvars:
862 dirvars[value] = var
Patrick Williamsc0f7c042017-02-23 20:41:17 -0600863 for dirpath in sorted(list(dirvars.keys()), reverse=True):
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500864 path = path.replace(dirpath, '${%s}' % dirvars[dirpath])
865 return path
866
867def get_recipe_pv_without_srcpv(pv, uri_type):
868 """
869 Get PV without SRCPV common in SCM's for now only
870 support git.
871
872 Returns tuple with pv, prefix and suffix.
873 """
874 pfx = ''
875 sfx = ''
876
877 if uri_type == 'git':
878 git_regex = re.compile("(?P<pfx>v?)(?P<ver>[^\+]*)((?P<sfx>\+(git)?r?(AUTOINC\+))(?P<rev>.*))?")
879 m = git_regex.match(pv)
880
881 if m:
882 pv = m.group('ver')
883 pfx = m.group('pfx')
884 sfx = m.group('sfx')
885 else:
886 regex = re.compile("(?P<pfx>(v|r)?)(?P<ver>.*)")
887 m = regex.match(pv)
888 if m:
889 pv = m.group('ver')
890 pfx = m.group('pfx')
891
892 return (pv, pfx, sfx)
893
894def get_recipe_upstream_version(rd):
895 """
896 Get upstream version of recipe using bb.fetch2 methods with support for
897 http, https, ftp and git.
898
899 bb.fetch2 exceptions can be raised,
900 FetchError when don't have network access or upstream site don't response.
901 NoMethodError when uri latest_versionstring method isn't implemented.
902
Brad Bishop316dfdd2018-06-25 12:45:53 -0400903 Returns a dictonary with version, repository revision, current_version, type and datetime.
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500904 Type can be A for Automatic, M for Manual and U for Unknown.
905 """
906 from bb.fetch2 import decodeurl
907 from datetime import datetime
908
909 ru = {}
Brad Bishop316dfdd2018-06-25 12:45:53 -0400910 ru['current_version'] = rd.getVar('PV')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500911 ru['version'] = ''
912 ru['type'] = 'U'
913 ru['datetime'] = ''
Brad Bishop316dfdd2018-06-25 12:45:53 -0400914 ru['revision'] = ''
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500915
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500916 # XXX: If don't have SRC_URI means that don't have upstream sources so
Patrick Williamsf1e5d692016-03-30 15:21:19 -0500917 # returns the current recipe version, so that upstream version check
918 # declares a match.
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500919 src_uris = rd.getVar('SRC_URI')
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500920 if not src_uris:
Brad Bishop316dfdd2018-06-25 12:45:53 -0400921 ru['version'] = ru['current_version']
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500922 ru['type'] = 'M'
923 ru['datetime'] = datetime.now()
924 return ru
925
926 # XXX: we suppose that the first entry points to the upstream sources
927 src_uri = src_uris.split()[0]
928 uri_type, _, _, _, _, _ = decodeurl(src_uri)
929
Brad Bishop316dfdd2018-06-25 12:45:53 -0400930 (pv, pfx, sfx) = get_recipe_pv_without_srcpv(rd.getVar('PV'), uri_type)
931 ru['current_version'] = pv
932
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500933 manual_upstream_version = rd.getVar("RECIPE_UPSTREAM_VERSION")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500934 if manual_upstream_version:
935 # manual tracking of upstream version.
936 ru['version'] = manual_upstream_version
937 ru['type'] = 'M'
938
Brad Bishop6e60e8b2018-02-01 10:27:11 -0500939 manual_upstream_date = rd.getVar("CHECK_DATE")
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500940 if manual_upstream_date:
941 date = datetime.strptime(manual_upstream_date, "%b %d, %Y")
942 else:
943 date = datetime.now()
944 ru['datetime'] = date
945
946 elif uri_type == "file":
947 # files are always up-to-date
948 ru['version'] = pv
949 ru['type'] = 'A'
950 ru['datetime'] = datetime.now()
951 else:
952 ud = bb.fetch2.FetchData(src_uri, rd)
Brad Bishop316dfdd2018-06-25 12:45:53 -0400953 if rd.getVar("UPSTREAM_CHECK_COMMITS") == "1":
954 revision = ud.method.latest_revision(ud, rd, 'default')
955 upversion = pv
956 if revision != rd.getVar("SRCREV"):
957 upversion = upversion + "-new-commits-available"
958 else:
959 pupver = ud.method.latest_versionstring(ud, rd)
960 (upversion, revision) = pupver
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500961
962 if upversion:
963 ru['version'] = upversion
964 ru['type'] = 'A'
965
Brad Bishop316dfdd2018-06-25 12:45:53 -0400966 if revision:
967 ru['revision'] = revision
968
Patrick Williamsc124f4f2015-09-15 14:41:29 -0500969 ru['datetime'] = datetime.now()
970
971 return ru