devtool.py 97 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790
  1. import os
  2. import re
  3. import shutil
  4. import tempfile
  5. import glob
  6. import fnmatch
  7. import oeqa.utils.ftools as ftools
  8. from oeqa.selftest.case import OESelftestTestCase
  9. from oeqa.utils.commands import runCmd, bitbake, get_bb_var, create_temp_layer
  10. from oeqa.utils.commands import get_bb_vars, runqemu, get_test_layer
  11. from oeqa.core.decorator.oeid import OETestID
  12. oldmetapath = None
  13. def setUpModule():
  14. import bb.utils
  15. global templayerdir
  16. templayerdir = tempfile.mkdtemp(prefix='devtoolqa')
  17. corecopydir = os.path.join(templayerdir, 'core-copy')
  18. bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
  19. edited_layers = []
  20. # We need to take a copy of the meta layer so we can modify it and not
  21. # have any races against other tests that might be running in parallel
  22. # however things like COREBASE mean that you can't just copy meta, you
  23. # need the whole repository.
  24. def bblayers_edit_cb(layerpath, canonical_layerpath):
  25. global oldmetapath
  26. if not canonical_layerpath.endswith('/'):
  27. # This helps us match exactly when we're using this path later
  28. canonical_layerpath += '/'
  29. if not edited_layers and canonical_layerpath.endswith('/meta/'):
  30. canonical_layerpath = os.path.realpath(canonical_layerpath) + '/'
  31. edited_layers.append(layerpath)
  32. oldmetapath = os.path.realpath(layerpath)
  33. result = runCmd('git rev-parse --show-toplevel', cwd=canonical_layerpath)
  34. oldreporoot = result.output.rstrip()
  35. newmetapath = os.path.join(corecopydir, os.path.relpath(oldmetapath, oldreporoot))
  36. runCmd('git clone %s %s' % (oldreporoot, corecopydir), cwd=templayerdir)
  37. # Now we need to copy any modified files
  38. # You might ask "why not just copy the entire tree instead of
  39. # cloning and doing this?" - well, the problem with that is
  40. # TMPDIR or an equally large subdirectory might exist
  41. # under COREBASE and we don't want to copy that, so we have
  42. # to be selective.
  43. result = runCmd('git status --porcelain', cwd=oldreporoot)
  44. for line in result.output.splitlines():
  45. if line.startswith(' M ') or line.startswith('?? '):
  46. relpth = line.split()[1]
  47. pth = os.path.join(oldreporoot, relpth)
  48. if pth.startswith(canonical_layerpath):
  49. if relpth.endswith('/'):
  50. destdir = os.path.join(corecopydir, relpth)
  51. shutil.copytree(pth, destdir)
  52. else:
  53. destdir = os.path.join(corecopydir, os.path.dirname(relpth))
  54. bb.utils.mkdirhier(destdir)
  55. shutil.copy2(pth, destdir)
  56. return newmetapath
  57. else:
  58. return layerpath
  59. bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
  60. def tearDownModule():
  61. if oldmetapath:
  62. edited_layers = []
  63. def bblayers_edit_cb(layerpath, canonical_layerpath):
  64. if not edited_layers and canonical_layerpath.endswith('/meta'):
  65. edited_layers.append(layerpath)
  66. return oldmetapath
  67. else:
  68. return layerpath
  69. bblayers_conf = os.path.join(os.environ['BUILDDIR'], 'conf', 'bblayers.conf')
  70. bb.utils.edit_bblayers_conf(bblayers_conf, None, None, bblayers_edit_cb)
  71. shutil.rmtree(templayerdir)
  72. class DevtoolBase(OESelftestTestCase):
  73. @classmethod
  74. def setUpClass(cls):
  75. super(DevtoolBase, cls).setUpClass()
  76. bb_vars = get_bb_vars(['TOPDIR', 'SSTATE_DIR'])
  77. cls.original_sstate = bb_vars['SSTATE_DIR']
  78. cls.devtool_sstate = os.path.join(bb_vars['TOPDIR'], 'sstate_devtool')
  79. cls.sstate_conf = 'SSTATE_DIR = "%s"\n' % cls.devtool_sstate
  80. cls.sstate_conf += ('SSTATE_MIRRORS += "file://.* file:///%s/PATH"\n'
  81. % cls.original_sstate)
  82. @classmethod
  83. def tearDownClass(cls):
  84. cls.logger.debug('Deleting devtool sstate cache on %s' % cls.devtool_sstate)
  85. runCmd('rm -rf %s' % cls.devtool_sstate)
  86. super(DevtoolBase, cls).tearDownClass()
  87. def setUp(self):
  88. """Test case setup function"""
  89. super(DevtoolBase, self).setUp()
  90. self.workspacedir = os.path.join(self.builddir, 'workspace')
  91. self.assertTrue(not os.path.exists(self.workspacedir),
  92. 'This test cannot be run with a workspace directory '
  93. 'under the build directory')
  94. self.append_config(self.sstate_conf)
  95. def _check_src_repo(self, repo_dir):
  96. """Check srctree git repository"""
  97. self.assertTrue(os.path.isdir(os.path.join(repo_dir, '.git')),
  98. 'git repository for external source tree not found')
  99. result = runCmd('git status --porcelain', cwd=repo_dir)
  100. self.assertEqual(result.output.strip(), "",
  101. 'Created git repo is not clean')
  102. result = runCmd('git symbolic-ref HEAD', cwd=repo_dir)
  103. self.assertEqual(result.output.strip(), "refs/heads/devtool",
  104. 'Wrong branch in git repo')
  105. def _check_repo_status(self, repo_dir, expected_status):
  106. """Check the worktree status of a repository"""
  107. result = runCmd('git status . --porcelain',
  108. cwd=repo_dir)
  109. for line in result.output.splitlines():
  110. for ind, (f_status, fn_re) in enumerate(expected_status):
  111. if re.match(fn_re, line[3:]):
  112. if f_status != line[:2]:
  113. self.fail('Unexpected status in line: %s' % line)
  114. expected_status.pop(ind)
  115. break
  116. else:
  117. self.fail('Unexpected modified file in line: %s' % line)
  118. if expected_status:
  119. self.fail('Missing file changes: %s' % expected_status)
  120. def _test_recipe_contents(self, recipefile, checkvars, checkinherits):
  121. with open(recipefile, 'r') as f:
  122. invar = None
  123. invalue = None
  124. for line in f:
  125. var = None
  126. if invar:
  127. value = line.strip().strip('"')
  128. if value.endswith('\\'):
  129. invalue += ' ' + value[:-1].strip()
  130. continue
  131. else:
  132. invalue += ' ' + value.strip()
  133. var = invar
  134. value = invalue
  135. invar = None
  136. elif '=' in line:
  137. splitline = line.split('=', 1)
  138. var = splitline[0].rstrip()
  139. value = splitline[1].strip().strip('"')
  140. if value.endswith('\\'):
  141. invalue = value[:-1].strip()
  142. invar = var
  143. continue
  144. elif line.startswith('inherit '):
  145. inherits = line.split()[1:]
  146. if var and var in checkvars:
  147. needvalue = checkvars.pop(var)
  148. if needvalue is None:
  149. self.fail('Variable %s should not appear in recipe, but value is being set to "%s"' % (var, value))
  150. if isinstance(needvalue, set):
  151. if var == 'LICENSE':
  152. value = set(value.split(' & '))
  153. else:
  154. value = set(value.split())
  155. self.assertEqual(value, needvalue, 'values for %s do not match' % var)
  156. missingvars = {}
  157. for var, value in checkvars.items():
  158. if value is not None:
  159. missingvars[var] = value
  160. self.assertEqual(missingvars, {}, 'Some expected variables not found in recipe: %s' % checkvars)
  161. for inherit in checkinherits:
  162. self.assertIn(inherit, inherits, 'Missing inherit of %s' % inherit)
  163. def _check_bbappend(self, testrecipe, recipefile, appenddir):
  164. result = runCmd('bitbake-layers show-appends', cwd=self.builddir)
  165. resultlines = result.output.splitlines()
  166. inrecipe = False
  167. bbappends = []
  168. bbappendfile = None
  169. for line in resultlines:
  170. if inrecipe:
  171. if line.startswith(' '):
  172. bbappends.append(line.strip())
  173. else:
  174. break
  175. elif line == '%s:' % os.path.basename(recipefile):
  176. inrecipe = True
  177. self.assertLessEqual(len(bbappends), 2, '%s recipe is being bbappended by another layer - bbappends found:\n %s' % (testrecipe, '\n '.join(bbappends)))
  178. for bbappend in bbappends:
  179. if bbappend.startswith(appenddir):
  180. bbappendfile = bbappend
  181. break
  182. else:
  183. self.fail('bbappend for recipe %s does not seem to be created in test layer' % testrecipe)
  184. return bbappendfile
  185. def _create_temp_layer(self, templayerdir, addlayer, templayername, priority=999, recipepathspec='recipes-*/*'):
  186. create_temp_layer(templayerdir, templayername, priority, recipepathspec)
  187. if addlayer:
  188. self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
  189. result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
  190. def _process_ls_output(self, output):
  191. """
  192. Convert ls -l output to a format we can reasonably compare from one context
  193. to another (e.g. from host to target)
  194. """
  195. filelist = []
  196. for line in output.splitlines():
  197. splitline = line.split()
  198. if len(splitline) < 8:
  199. self.fail('_process_ls_output: invalid output line: %s' % line)
  200. # Remove trailing . on perms
  201. splitline[0] = splitline[0].rstrip('.')
  202. # Remove leading . on paths
  203. splitline[-1] = splitline[-1].lstrip('.')
  204. # Drop fields we don't want to compare
  205. del splitline[7]
  206. del splitline[6]
  207. del splitline[5]
  208. del splitline[4]
  209. del splitline[1]
  210. filelist.append(' '.join(splitline))
  211. return filelist
  212. class DevtoolTests(DevtoolBase):
  213. @OETestID(1158)
  214. def test_create_workspace(self):
  215. # Check preconditions
  216. result = runCmd('bitbake-layers show-layers')
  217. self.assertTrue('\nworkspace' not in result.output, 'This test cannot be run with a workspace layer in bblayers.conf')
  218. # Try creating a workspace layer with a specific path
  219. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  220. self.track_for_cleanup(tempdir)
  221. result = runCmd('devtool create-workspace %s' % tempdir)
  222. self.assertTrue(os.path.isfile(os.path.join(tempdir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
  223. result = runCmd('bitbake-layers show-layers')
  224. self.assertIn(tempdir, result.output)
  225. # Try creating a workspace layer with the default path
  226. self.track_for_cleanup(self.workspacedir)
  227. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  228. result = runCmd('devtool create-workspace')
  229. self.assertTrue(os.path.isfile(os.path.join(self.workspacedir, 'conf', 'layer.conf')), msg = "No workspace created. devtool output: %s " % result.output)
  230. result = runCmd('bitbake-layers show-layers')
  231. self.assertNotIn(tempdir, result.output)
  232. self.assertIn(self.workspacedir, result.output)
  233. class DevtoolAddTests(DevtoolBase):
  234. @OETestID(1159)
  235. def test_devtool_add(self):
  236. # Fetch source
  237. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  238. self.track_for_cleanup(tempdir)
  239. pn = 'pv'
  240. pv = '1.5.3'
  241. url = 'http://www.ivarch.com/programs/sources/pv-1.5.3.tar.bz2'
  242. result = runCmd('wget %s' % url, cwd=tempdir)
  243. result = runCmd('tar xfv %s' % os.path.basename(url), cwd=tempdir)
  244. srcdir = os.path.join(tempdir, '%s-%s' % (pn, pv))
  245. self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
  246. # Test devtool add
  247. self.track_for_cleanup(self.workspacedir)
  248. self.add_command_to_tearDown('bitbake -c cleansstate %s' % pn)
  249. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  250. result = runCmd('devtool add %s %s' % (pn, srcdir))
  251. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
  252. # Test devtool status
  253. result = runCmd('devtool status')
  254. recipepath = '%s/recipes/%s/%s_%s.bb' % (self.workspacedir, pn, pn, pv)
  255. self.assertIn(recipepath, result.output)
  256. self.assertIn(srcdir, result.output)
  257. # Test devtool find-recipe
  258. result = runCmd('devtool -q find-recipe %s' % pn)
  259. self.assertEqual(recipepath, result.output.strip())
  260. # Test devtool edit-recipe
  261. result = runCmd('VISUAL="echo 123" devtool -q edit-recipe %s' % pn)
  262. self.assertEqual('123 %s' % recipepath, result.output.strip())
  263. # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
  264. bitbake('%s -c cleansstate' % pn)
  265. # Test devtool build
  266. result = runCmd('devtool build %s' % pn)
  267. bb_vars = get_bb_vars(['D', 'bindir'], pn)
  268. installdir = bb_vars['D']
  269. self.assertTrue(installdir, 'Could not query installdir variable')
  270. bindir = bb_vars['bindir']
  271. self.assertTrue(bindir, 'Could not query bindir variable')
  272. if bindir[0] == '/':
  273. bindir = bindir[1:]
  274. self.assertTrue(os.path.isfile(os.path.join(installdir, bindir, 'pv')), 'pv binary not found in D')
  275. @OETestID(1423)
  276. def test_devtool_add_git_local(self):
  277. # We need dbus built so that DEPENDS recognition works
  278. bitbake('dbus')
  279. # Fetch source from a remote URL, but do it outside of devtool
  280. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  281. self.track_for_cleanup(tempdir)
  282. pn = 'dbus-wait'
  283. srcrev = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
  284. # We choose an https:// git URL here to check rewriting the URL works
  285. url = 'https://git.yoctoproject.org/git/dbus-wait'
  286. # Force fetching to "noname" subdir so we verify we're picking up the name from autoconf
  287. # instead of the directory name
  288. result = runCmd('git clone %s noname' % url, cwd=tempdir)
  289. srcdir = os.path.join(tempdir, 'noname')
  290. result = runCmd('git reset --hard %s' % srcrev, cwd=srcdir)
  291. self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure.ac')), 'Unable to find configure script in source directory')
  292. # Test devtool add
  293. self.track_for_cleanup(self.workspacedir)
  294. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  295. # Don't specify a name since we should be able to auto-detect it
  296. result = runCmd('devtool add %s' % srcdir)
  297. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
  298. # Check the recipe name is correct
  299. recipefile = get_bb_var('FILE', pn)
  300. self.assertIn('%s_git.bb' % pn, recipefile, 'Recipe file incorrectly named')
  301. self.assertIn(recipefile, result.output)
  302. # Test devtool status
  303. result = runCmd('devtool status')
  304. self.assertIn(pn, result.output)
  305. self.assertIn(srcdir, result.output)
  306. self.assertIn(recipefile, result.output)
  307. checkvars = {}
  308. checkvars['LICENSE'] = 'GPLv2'
  309. checkvars['LIC_FILES_CHKSUM'] = 'file://COPYING;md5=b234ee4d69f5fce4486a80fdaf4a4263'
  310. checkvars['S'] = '${WORKDIR}/git'
  311. checkvars['PV'] = '0.1+git${SRCPV}'
  312. checkvars['SRC_URI'] = 'git://git.yoctoproject.org/git/dbus-wait;protocol=https'
  313. checkvars['SRCREV'] = srcrev
  314. checkvars['DEPENDS'] = set(['dbus'])
  315. self._test_recipe_contents(recipefile, checkvars, [])
  316. @OETestID(1162)
  317. def test_devtool_add_library(self):
  318. # Fetch source
  319. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  320. self.track_for_cleanup(tempdir)
  321. version = '1.1'
  322. url = 'https://www.intra2net.com/en/developer/libftdi/download/libftdi1-%s.tar.bz2' % version
  323. result = runCmd('wget %s' % url, cwd=tempdir)
  324. result = runCmd('tar xfv libftdi1-%s.tar.bz2' % version, cwd=tempdir)
  325. srcdir = os.path.join(tempdir, 'libftdi1-%s' % version)
  326. self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
  327. # Test devtool add (and use -V so we test that too)
  328. self.track_for_cleanup(self.workspacedir)
  329. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  330. result = runCmd('devtool add libftdi %s -V %s' % (srcdir, version))
  331. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
  332. # Test devtool status
  333. result = runCmd('devtool status')
  334. self.assertIn('libftdi', result.output)
  335. self.assertIn(srcdir, result.output)
  336. # Clean up anything in the workdir/sysroot/sstate cache (have to do this *after* devtool add since the recipe only exists then)
  337. bitbake('libftdi -c cleansstate')
  338. # libftdi's python/CMakeLists.txt is a bit broken, so let's just disable it
  339. # There's also the matter of it installing cmake files to a path we don't
  340. # normally cover, which triggers the installed-vs-shipped QA test we have
  341. # within do_package
  342. recipefile = '%s/recipes/libftdi/libftdi_%s.bb' % (self.workspacedir, version)
  343. result = runCmd('recipetool setvar %s EXTRA_OECMAKE -- \'-DPYTHON_BINDINGS=OFF -DLIBFTDI_CMAKE_CONFIG_DIR=${datadir}/cmake/Modules\'' % recipefile)
  344. with open(recipefile, 'a') as f:
  345. f.write('\nFILES_${PN}-dev += "${datadir}/cmake/Modules"\n')
  346. # We don't have the ability to pick up this dependency automatically yet...
  347. f.write('\nDEPENDS += "libusb1"\n')
  348. f.write('\nTESTLIBOUTPUT = "${COMPONENTS_DIR}/${TUNE_PKGARCH}/${PN}/${libdir}"\n')
  349. # Test devtool build
  350. result = runCmd('devtool build libftdi')
  351. bb_vars = get_bb_vars(['TESTLIBOUTPUT', 'STAMP'], 'libftdi')
  352. staging_libdir = bb_vars['TESTLIBOUTPUT']
  353. self.assertTrue(staging_libdir, 'Could not query TESTLIBOUTPUT variable')
  354. self.assertTrue(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), "libftdi binary not found in STAGING_LIBDIR. Output of devtool build libftdi %s" % result.output)
  355. # Test devtool reset
  356. stampprefix = bb_vars['STAMP']
  357. result = runCmd('devtool reset libftdi')
  358. result = runCmd('devtool status')
  359. self.assertNotIn('libftdi', result.output)
  360. self.assertTrue(stampprefix, 'Unable to get STAMP value for recipe libftdi')
  361. matches = glob.glob(stampprefix + '*')
  362. self.assertFalse(matches, 'Stamp files exist for recipe libftdi that should have been cleaned')
  363. self.assertFalse(os.path.isfile(os.path.join(staging_libdir, 'libftdi1.so.2.1.0')), 'libftdi binary still found in STAGING_LIBDIR after cleaning')
  364. @OETestID(1160)
  365. def test_devtool_add_fetch(self):
  366. # Fetch source
  367. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  368. self.track_for_cleanup(tempdir)
  369. testver = '0.23'
  370. url = 'https://pypi.python.org/packages/source/M/MarkupSafe/MarkupSafe-%s.tar.gz' % testver
  371. testrecipe = 'python-markupsafe'
  372. srcdir = os.path.join(tempdir, testrecipe)
  373. # Test devtool add
  374. self.track_for_cleanup(self.workspacedir)
  375. self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
  376. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  377. result = runCmd('devtool add %s %s -f %s' % (testrecipe, srcdir, url))
  378. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
  379. self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
  380. self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
  381. # Test devtool status
  382. result = runCmd('devtool status')
  383. self.assertIn(testrecipe, result.output)
  384. self.assertIn(srcdir, result.output)
  385. # Check recipe
  386. recipefile = get_bb_var('FILE', testrecipe)
  387. self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
  388. checkvars = {}
  389. checkvars['S'] = '${WORKDIR}/MarkupSafe-${PV}'
  390. checkvars['SRC_URI'] = url.replace(testver, '${PV}')
  391. self._test_recipe_contents(recipefile, checkvars, [])
  392. # Try with version specified
  393. result = runCmd('devtool reset -n %s' % testrecipe)
  394. shutil.rmtree(srcdir)
  395. fakever = '1.9'
  396. result = runCmd('devtool add %s %s -f %s -V %s' % (testrecipe, srcdir, url, fakever))
  397. self.assertTrue(os.path.isfile(os.path.join(srcdir, 'setup.py')), 'Unable to find setup.py in source directory')
  398. # Test devtool status
  399. result = runCmd('devtool status')
  400. self.assertIn(testrecipe, result.output)
  401. self.assertIn(srcdir, result.output)
  402. # Check recipe
  403. recipefile = get_bb_var('FILE', testrecipe)
  404. self.assertIn('%s_%s.bb' % (testrecipe, fakever), recipefile, 'Recipe file incorrectly named')
  405. checkvars = {}
  406. checkvars['S'] = '${WORKDIR}/MarkupSafe-%s' % testver
  407. checkvars['SRC_URI'] = url
  408. self._test_recipe_contents(recipefile, checkvars, [])
  409. @OETestID(1161)
  410. def test_devtool_add_fetch_git(self):
  411. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  412. self.track_for_cleanup(tempdir)
  413. url = 'gitsm://git.yoctoproject.org/mraa'
  414. checkrev = 'ae127b19a50aa54255e4330ccfdd9a5d058e581d'
  415. testrecipe = 'mraa'
  416. srcdir = os.path.join(tempdir, testrecipe)
  417. # Test devtool add
  418. self.track_for_cleanup(self.workspacedir)
  419. self.add_command_to_tearDown('bitbake -c cleansstate %s' % testrecipe)
  420. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  421. result = runCmd('devtool add %s %s -a -f %s' % (testrecipe, srcdir, url))
  422. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created: %s' % result.output)
  423. self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
  424. # Test devtool status
  425. result = runCmd('devtool status')
  426. self.assertIn(testrecipe, result.output)
  427. self.assertIn(srcdir, result.output)
  428. # Check recipe
  429. recipefile = get_bb_var('FILE', testrecipe)
  430. self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
  431. checkvars = {}
  432. checkvars['S'] = '${WORKDIR}/git'
  433. checkvars['PV'] = '1.0+git${SRCPV}'
  434. checkvars['SRC_URI'] = url
  435. checkvars['SRCREV'] = '${AUTOREV}'
  436. self._test_recipe_contents(recipefile, checkvars, [])
  437. # Try with revision and version specified
  438. result = runCmd('devtool reset -n %s' % testrecipe)
  439. shutil.rmtree(srcdir)
  440. url_rev = '%s;rev=%s' % (url, checkrev)
  441. result = runCmd('devtool add %s %s -f "%s" -V 1.5' % (testrecipe, srcdir, url_rev))
  442. self.assertTrue(os.path.isfile(os.path.join(srcdir, 'imraa', 'imraa.c')), 'Unable to find imraa/imraa.c in source directory')
  443. # Test devtool status
  444. result = runCmd('devtool status')
  445. self.assertIn(testrecipe, result.output)
  446. self.assertIn(srcdir, result.output)
  447. # Check recipe
  448. recipefile = get_bb_var('FILE', testrecipe)
  449. self.assertIn('_git.bb', recipefile, 'Recipe file incorrectly named')
  450. checkvars = {}
  451. checkvars['S'] = '${WORKDIR}/git'
  452. checkvars['PV'] = '1.5+git${SRCPV}'
  453. checkvars['SRC_URI'] = url
  454. checkvars['SRCREV'] = checkrev
  455. self._test_recipe_contents(recipefile, checkvars, [])
  456. @OETestID(1391)
  457. def test_devtool_add_fetch_simple(self):
  458. # Fetch source from a remote URL, auto-detecting name
  459. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  460. self.track_for_cleanup(tempdir)
  461. testver = '1.6.0'
  462. url = 'http://www.ivarch.com/programs/sources/pv-%s.tar.bz2' % testver
  463. testrecipe = 'pv'
  464. srcdir = os.path.join(self.workspacedir, 'sources', testrecipe)
  465. # Test devtool add
  466. self.track_for_cleanup(self.workspacedir)
  467. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  468. result = runCmd('devtool add %s' % url)
  469. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. %s' % result.output)
  470. self.assertTrue(os.path.isfile(os.path.join(srcdir, 'configure')), 'Unable to find configure script in source directory')
  471. self.assertTrue(os.path.isdir(os.path.join(srcdir, '.git')), 'git repository for external source tree was not created')
  472. # Test devtool status
  473. result = runCmd('devtool status')
  474. self.assertIn(testrecipe, result.output)
  475. self.assertIn(srcdir, result.output)
  476. # Check recipe
  477. recipefile = get_bb_var('FILE', testrecipe)
  478. self.assertIn('%s_%s.bb' % (testrecipe, testver), recipefile, 'Recipe file incorrectly named')
  479. checkvars = {}
  480. checkvars['S'] = None
  481. checkvars['SRC_URI'] = url.replace(testver, '${PV}')
  482. self._test_recipe_contents(recipefile, checkvars, [])
  483. class DevtoolModifyTests(DevtoolBase):
  484. @OETestID(1164)
  485. def test_devtool_modify(self):
  486. import oe.path
  487. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  488. self.track_for_cleanup(tempdir)
  489. self.track_for_cleanup(self.workspacedir)
  490. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  491. self.add_command_to_tearDown('bitbake -c clean mdadm')
  492. result = runCmd('devtool modify mdadm -x %s' % tempdir)
  493. self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
  494. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
  495. matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'mdadm_*.bbappend'))
  496. self.assertTrue(matches, 'bbappend not created %s' % result.output)
  497. # Test devtool status
  498. result = runCmd('devtool status')
  499. self.assertIn('mdadm', result.output)
  500. self.assertIn(tempdir, result.output)
  501. self._check_src_repo(tempdir)
  502. bitbake('mdadm -C unpack')
  503. def check_line(checkfile, expected, message, present=True):
  504. # Check for $expected, on a line on its own, in checkfile.
  505. with open(checkfile, 'r') as f:
  506. if present:
  507. self.assertIn(expected + '\n', f, message)
  508. else:
  509. self.assertNotIn(expected + '\n', f, message)
  510. modfile = os.path.join(tempdir, 'mdadm.8.in')
  511. bb_vars = get_bb_vars(['PKGD', 'mandir'], 'mdadm')
  512. pkgd = bb_vars['PKGD']
  513. self.assertTrue(pkgd, 'Could not query PKGD variable')
  514. mandir = bb_vars['mandir']
  515. self.assertTrue(mandir, 'Could not query mandir variable')
  516. manfile = oe.path.join(pkgd, mandir, 'man8', 'mdadm.8')
  517. check_line(modfile, 'Linux Software RAID', 'Could not find initial string')
  518. check_line(modfile, 'antique pin sardine', 'Unexpectedly found replacement string', present=False)
  519. result = runCmd("sed -i 's!^Linux Software RAID$!antique pin sardine!' %s" % modfile)
  520. check_line(modfile, 'antique pin sardine', 'mdadm.8.in file not modified (sed failed)')
  521. bitbake('mdadm -c package')
  522. check_line(manfile, 'antique pin sardine', 'man file not modified. man searched file path: %s' % manfile)
  523. result = runCmd('git checkout -- %s' % modfile, cwd=tempdir)
  524. check_line(modfile, 'Linux Software RAID', 'man .in file not restored (git failed)')
  525. bitbake('mdadm -c package')
  526. check_line(manfile, 'Linux Software RAID', 'man file not updated. man searched file path: %s' % manfile)
  527. result = runCmd('devtool reset mdadm')
  528. result = runCmd('devtool status')
  529. self.assertNotIn('mdadm', result.output)
  530. @OETestID(1620)
  531. def test_devtool_buildclean(self):
  532. def assertFile(path, *paths):
  533. f = os.path.join(path, *paths)
  534. self.assertExists(f)
  535. def assertNoFile(path, *paths):
  536. f = os.path.join(path, *paths)
  537. self.assertNotExists(f)
  538. # Clean up anything in the workdir/sysroot/sstate cache
  539. bitbake('mdadm m4 -c cleansstate')
  540. # Try modifying a recipe
  541. tempdir_mdadm = tempfile.mkdtemp(prefix='devtoolqa')
  542. tempdir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
  543. builddir_m4 = tempfile.mkdtemp(prefix='devtoolqa')
  544. self.track_for_cleanup(tempdir_mdadm)
  545. self.track_for_cleanup(tempdir_m4)
  546. self.track_for_cleanup(builddir_m4)
  547. self.track_for_cleanup(self.workspacedir)
  548. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  549. self.add_command_to_tearDown('bitbake -c clean mdadm m4')
  550. self.write_recipeinc('m4', 'EXTERNALSRC_BUILD = "%s"\ndo_clean() {\n\t:\n}\n' % builddir_m4)
  551. try:
  552. runCmd('devtool modify mdadm -x %s' % tempdir_mdadm)
  553. runCmd('devtool modify m4 -x %s' % tempdir_m4)
  554. assertNoFile(tempdir_mdadm, 'mdadm')
  555. assertNoFile(builddir_m4, 'src/m4')
  556. result = bitbake('m4 -e')
  557. result = bitbake('mdadm m4 -c compile')
  558. self.assertEqual(result.status, 0)
  559. assertFile(tempdir_mdadm, 'mdadm')
  560. assertFile(builddir_m4, 'src/m4')
  561. # Check that buildclean task exists and does call make clean
  562. bitbake('mdadm m4 -c buildclean')
  563. assertNoFile(tempdir_mdadm, 'mdadm')
  564. assertNoFile(builddir_m4, 'src/m4')
  565. bitbake('mdadm m4 -c compile')
  566. assertFile(tempdir_mdadm, 'mdadm')
  567. assertFile(builddir_m4, 'src/m4')
  568. bitbake('mdadm m4 -c clean')
  569. # Check that buildclean task is run before clean for B == S
  570. assertNoFile(tempdir_mdadm, 'mdadm')
  571. # Check that buildclean task is not run before clean for B != S
  572. assertFile(builddir_m4, 'src/m4')
  573. finally:
  574. self.delete_recipeinc('m4')
  575. @OETestID(1166)
  576. def test_devtool_modify_invalid(self):
  577. # Try modifying some recipes
  578. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  579. self.track_for_cleanup(tempdir)
  580. self.track_for_cleanup(self.workspacedir)
  581. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  582. testrecipes = 'perf kernel-devsrc package-index core-image-minimal meta-toolchain packagegroup-core-sdk meta-ide-support'.split()
  583. # Find actual name of gcc-source since it now includes the version - crude, but good enough for this purpose
  584. result = runCmd('bitbake-layers show-recipes gcc-source*')
  585. for line in result.output.splitlines():
  586. # just match those lines that contain a real target
  587. m = re.match('(?P<recipe>^[a-zA-Z0-9.-]+)(?P<colon>:$)', line)
  588. if m:
  589. testrecipes.append(m.group('recipe'))
  590. for testrecipe in testrecipes:
  591. # Check it's a valid recipe
  592. bitbake('%s -e' % testrecipe)
  593. # devtool extract should fail
  594. result = runCmd('devtool extract %s %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
  595. self.assertNotEqual(result.status, 0, 'devtool extract on %s should have failed. devtool output: %s' % (testrecipe, result.output))
  596. self.assertNotIn('Fetching ', result.output, 'devtool extract on %s should have errored out before trying to fetch' % testrecipe)
  597. self.assertIn('ERROR: ', result.output, 'devtool extract on %s should have given an ERROR' % testrecipe)
  598. # devtool modify should fail
  599. result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)), ignore_status=True)
  600. self.assertNotEqual(result.status, 0, 'devtool modify on %s should have failed. devtool output: %s' % (testrecipe, result.output))
  601. self.assertIn('ERROR: ', result.output, 'devtool modify on %s should have given an ERROR' % testrecipe)
  602. @OETestID(1365)
  603. def test_devtool_modify_native(self):
  604. # Check preconditions
  605. self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
  606. # Try modifying some recipes
  607. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  608. self.track_for_cleanup(tempdir)
  609. self.track_for_cleanup(self.workspacedir)
  610. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  611. bbclassextended = False
  612. inheritnative = False
  613. testrecipes = 'mtools-native apt-native desktop-file-utils-native'.split()
  614. for testrecipe in testrecipes:
  615. checkextend = 'native' in (get_bb_var('BBCLASSEXTEND', testrecipe) or '').split()
  616. if not bbclassextended:
  617. bbclassextended = checkextend
  618. if not inheritnative:
  619. inheritnative = not checkextend
  620. result = runCmd('devtool modify %s -x %s' % (testrecipe, os.path.join(tempdir, testrecipe)))
  621. self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool modify output: %s' % result.output)
  622. result = runCmd('devtool build %s' % testrecipe)
  623. self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool build output: %s' % result.output)
  624. result = runCmd('devtool reset %s' % testrecipe)
  625. self.assertNotIn('ERROR: ', result.output, 'ERROR in devtool reset output: %s' % result.output)
  626. self.assertTrue(bbclassextended, 'None of these recipes are BBCLASSEXTENDed to native - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
  627. self.assertTrue(inheritnative, 'None of these recipes do "inherit native" - need to adjust testrecipes list: %s' % ', '.join(testrecipes))
  628. @OETestID(1165)
  629. def test_devtool_modify_git(self):
  630. # Check preconditions
  631. testrecipe = 'psplash'
  632. src_uri = get_bb_var('SRC_URI', testrecipe)
  633. self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
  634. # Clean up anything in the workdir/sysroot/sstate cache
  635. bitbake('%s -c cleansstate' % testrecipe)
  636. # Try modifying a recipe
  637. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  638. self.track_for_cleanup(tempdir)
  639. self.track_for_cleanup(self.workspacedir)
  640. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  641. self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
  642. result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
  643. self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
  644. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created. devtool output: %s' % result.output)
  645. matches = glob.glob(os.path.join(self.workspacedir, 'appends', 'psplash_*.bbappend'))
  646. self.assertTrue(matches, 'bbappend not created')
  647. # Test devtool status
  648. result = runCmd('devtool status')
  649. self.assertIn(testrecipe, result.output)
  650. self.assertIn(tempdir, result.output)
  651. # Check git repo
  652. self._check_src_repo(tempdir)
  653. # Try building
  654. bitbake(testrecipe)
  655. @OETestID(1167)
  656. def test_devtool_modify_localfiles(self):
  657. # Check preconditions
  658. testrecipe = 'lighttpd'
  659. src_uri = (get_bb_var('SRC_URI', testrecipe) or '').split()
  660. foundlocal = False
  661. for item in src_uri:
  662. if item.startswith('file://') and '.patch' not in item:
  663. foundlocal = True
  664. break
  665. self.assertTrue(foundlocal, 'This test expects the %s recipe to fetch local files and it seems that it no longer does' % testrecipe)
  666. # Clean up anything in the workdir/sysroot/sstate cache
  667. bitbake('%s -c cleansstate' % testrecipe)
  668. # Try modifying a recipe
  669. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  670. self.track_for_cleanup(tempdir)
  671. self.track_for_cleanup(self.workspacedir)
  672. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  673. self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
  674. result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
  675. self.assertExists(os.path.join(tempdir, 'configure.ac'), 'Extracted source could not be found')
  676. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
  677. matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % testrecipe))
  678. self.assertTrue(matches, 'bbappend not created')
  679. # Test devtool status
  680. result = runCmd('devtool status')
  681. self.assertIn(testrecipe, result.output)
  682. self.assertIn(tempdir, result.output)
  683. # Try building
  684. bitbake(testrecipe)
  685. @OETestID(1378)
  686. def test_devtool_modify_virtual(self):
  687. # Try modifying a virtual recipe
  688. virtrecipe = 'virtual/make'
  689. realrecipe = 'make'
  690. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  691. self.track_for_cleanup(tempdir)
  692. self.track_for_cleanup(self.workspacedir)
  693. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  694. result = runCmd('devtool modify %s -x %s' % (virtrecipe, tempdir))
  695. self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
  696. self.assertExists(os.path.join(self.workspacedir, 'conf', 'layer.conf'), 'Workspace directory not created')
  697. matches = glob.glob(os.path.join(self.workspacedir, 'appends', '%s_*.bbappend' % realrecipe))
  698. self.assertTrue(matches, 'bbappend not created %s' % result.output)
  699. # Test devtool status
  700. result = runCmd('devtool status')
  701. self.assertNotIn(virtrecipe, result.output)
  702. self.assertIn(realrecipe, result.output)
  703. # Check git repo
  704. self._check_src_repo(tempdir)
  705. # This is probably sufficient
  706. class DevtoolUpdateTests(DevtoolBase):
  707. @OETestID(1169)
  708. def test_devtool_update_recipe(self):
  709. # Check preconditions
  710. testrecipe = 'minicom'
  711. bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
  712. recipefile = bb_vars['FILE']
  713. src_uri = bb_vars['SRC_URI']
  714. self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
  715. self._check_repo_status(os.path.dirname(recipefile), [])
  716. # First, modify a recipe
  717. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  718. self.track_for_cleanup(tempdir)
  719. self.track_for_cleanup(self.workspacedir)
  720. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  721. # (don't bother with cleaning the recipe on teardown, we won't be building it)
  722. # We don't use -x here so that we test the behaviour of devtool modify without it
  723. result = runCmd('devtool modify %s %s' % (testrecipe, tempdir))
  724. # Check git repo
  725. self._check_src_repo(tempdir)
  726. # Add a couple of commits
  727. # FIXME: this only tests adding, need to also test update and remove
  728. result = runCmd('echo "Additional line" >> README', cwd=tempdir)
  729. result = runCmd('git commit -a -m "Change the README"', cwd=tempdir)
  730. result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
  731. result = runCmd('git add devtool-new-file', cwd=tempdir)
  732. result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
  733. self.add_command_to_tearDown('cd %s; rm %s/*.patch; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
  734. result = runCmd('devtool update-recipe %s' % testrecipe)
  735. expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
  736. ('??', '.*/0001-Change-the-README.patch$'),
  737. ('??', '.*/0002-Add-a-new-file.patch$')]
  738. self._check_repo_status(os.path.dirname(recipefile), expected_status)
  739. @OETestID(1172)
  740. def test_devtool_update_recipe_git(self):
  741. # Check preconditions
  742. testrecipe = 'mtd-utils'
  743. bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
  744. recipefile = bb_vars['FILE']
  745. src_uri = bb_vars['SRC_URI']
  746. self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
  747. patches = []
  748. for entry in src_uri.split():
  749. if entry.startswith('file://') and entry.endswith('.patch'):
  750. patches.append(entry[7:].split(';')[0])
  751. self.assertGreater(len(patches), 0, 'The %s recipe does not appear to contain any patches, so this test will not be effective' % testrecipe)
  752. self._check_repo_status(os.path.dirname(recipefile), [])
  753. # First, modify a recipe
  754. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  755. self.track_for_cleanup(tempdir)
  756. self.track_for_cleanup(self.workspacedir)
  757. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  758. # (don't bother with cleaning the recipe on teardown, we won't be building it)
  759. result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
  760. # Check git repo
  761. self._check_src_repo(tempdir)
  762. # Add a couple of commits
  763. # FIXME: this only tests adding, need to also test update and remove
  764. result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempdir)
  765. result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempdir)
  766. result = runCmd('echo "A new file" > devtool-new-file', cwd=tempdir)
  767. result = runCmd('git add devtool-new-file', cwd=tempdir)
  768. result = runCmd('git commit -m "Add a new file"', cwd=tempdir)
  769. self.add_command_to_tearDown('cd %s; rm -rf %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
  770. result = runCmd('devtool update-recipe -m srcrev %s' % testrecipe)
  771. expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile))] + \
  772. [(' D', '.*/%s$' % patch) for patch in patches]
  773. self._check_repo_status(os.path.dirname(recipefile), expected_status)
  774. result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
  775. addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"']
  776. srcurilines = src_uri.split()
  777. srcurilines[0] = 'SRC_URI = "' + srcurilines[0]
  778. srcurilines.append('"')
  779. removelines = ['SRCREV = ".*"'] + srcurilines
  780. for line in result.output.splitlines():
  781. if line.startswith('+++') or line.startswith('---'):
  782. continue
  783. elif line.startswith('+'):
  784. matched = False
  785. for item in addlines:
  786. if re.match(item, line[1:].strip()):
  787. matched = True
  788. break
  789. self.assertTrue(matched, 'Unexpected diff add line: %s' % line)
  790. elif line.startswith('-'):
  791. matched = False
  792. for item in removelines:
  793. if re.match(item, line[1:].strip()):
  794. matched = True
  795. break
  796. self.assertTrue(matched, 'Unexpected diff remove line: %s' % line)
  797. # Now try with auto mode
  798. runCmd('cd %s; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, os.path.basename(recipefile)))
  799. result = runCmd('devtool update-recipe %s' % testrecipe)
  800. result = runCmd('git rev-parse --show-toplevel', cwd=os.path.dirname(recipefile))
  801. topleveldir = result.output.strip()
  802. relpatchpath = os.path.join(os.path.relpath(os.path.dirname(recipefile), topleveldir), testrecipe)
  803. expected_status = [(' M', os.path.relpath(recipefile, topleveldir)),
  804. ('??', '%s/0001-Change-the-Makefile.patch' % relpatchpath),
  805. ('??', '%s/0002-Add-a-new-file.patch' % relpatchpath)]
  806. self._check_repo_status(os.path.dirname(recipefile), expected_status)
  807. @OETestID(1170)
  808. def test_devtool_update_recipe_append(self):
  809. # Check preconditions
  810. testrecipe = 'mdadm'
  811. bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
  812. recipefile = bb_vars['FILE']
  813. src_uri = bb_vars['SRC_URI']
  814. self.assertNotIn('git://', src_uri, 'This test expects the %s recipe to NOT be a git recipe' % testrecipe)
  815. self._check_repo_status(os.path.dirname(recipefile), [])
  816. # First, modify a recipe
  817. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  818. tempsrcdir = os.path.join(tempdir, 'source')
  819. templayerdir = os.path.join(tempdir, 'layer')
  820. self.track_for_cleanup(tempdir)
  821. self.track_for_cleanup(self.workspacedir)
  822. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  823. # (don't bother with cleaning the recipe on teardown, we won't be building it)
  824. result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
  825. # Check git repo
  826. self._check_src_repo(tempsrcdir)
  827. # Add a commit
  828. result = runCmd("sed 's!\\(#define VERSION\\W*\"[^\"]*\\)\"!\\1-custom\"!' -i ReadMe.c", cwd=tempsrcdir)
  829. result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
  830. self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
  831. # Create a temporary layer and add it to bblayers.conf
  832. self._create_temp_layer(templayerdir, True, 'selftestupdaterecipe')
  833. # Create the bbappend
  834. result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
  835. self.assertNotIn('WARNING:', result.output)
  836. # Check recipe is still clean
  837. self._check_repo_status(os.path.dirname(recipefile), [])
  838. # Check bbappend was created
  839. splitpath = os.path.dirname(recipefile).split(os.sep)
  840. appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
  841. bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
  842. patchfile = os.path.join(appenddir, testrecipe, '0001-Add-our-custom-version.patch')
  843. self.assertExists(patchfile, 'Patch file not created')
  844. # Check bbappend contents
  845. expectedlines = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
  846. '\n',
  847. 'SRC_URI += "file://0001-Add-our-custom-version.patch"\n',
  848. '\n']
  849. with open(bbappendfile, 'r') as f:
  850. self.assertEqual(expectedlines, f.readlines())
  851. # Check we can run it again and bbappend isn't modified
  852. result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
  853. with open(bbappendfile, 'r') as f:
  854. self.assertEqual(expectedlines, f.readlines())
  855. # Drop new commit and check patch gets deleted
  856. result = runCmd('git reset HEAD^', cwd=tempsrcdir)
  857. result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
  858. self.assertNotExists(patchfile, 'Patch file not deleted')
  859. expectedlines2 = ['FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:"\n',
  860. '\n']
  861. with open(bbappendfile, 'r') as f:
  862. self.assertEqual(expectedlines2, f.readlines())
  863. # Put commit back and check we can run it if layer isn't in bblayers.conf
  864. os.remove(bbappendfile)
  865. result = runCmd('git commit -a -m "Add our custom version"', cwd=tempsrcdir)
  866. result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
  867. result = runCmd('devtool update-recipe %s -a %s' % (testrecipe, templayerdir))
  868. self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
  869. self.assertExists(patchfile, 'Patch file not created (with disabled layer)')
  870. with open(bbappendfile, 'r') as f:
  871. self.assertEqual(expectedlines, f.readlines())
  872. # Deleting isn't expected to work under these circumstances
  873. @OETestID(1171)
  874. def test_devtool_update_recipe_append_git(self):
  875. # Check preconditions
  876. testrecipe = 'mtd-utils'
  877. bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
  878. recipefile = bb_vars['FILE']
  879. src_uri = bb_vars['SRC_URI']
  880. self.assertIn('git://', src_uri, 'This test expects the %s recipe to be a git recipe' % testrecipe)
  881. for entry in src_uri.split():
  882. if entry.startswith('git://'):
  883. git_uri = entry
  884. break
  885. self._check_repo_status(os.path.dirname(recipefile), [])
  886. # First, modify a recipe
  887. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  888. tempsrcdir = os.path.join(tempdir, 'source')
  889. templayerdir = os.path.join(tempdir, 'layer')
  890. self.track_for_cleanup(tempdir)
  891. self.track_for_cleanup(self.workspacedir)
  892. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  893. # (don't bother with cleaning the recipe on teardown, we won't be building it)
  894. result = runCmd('devtool modify %s -x %s' % (testrecipe, tempsrcdir))
  895. # Check git repo
  896. self._check_src_repo(tempsrcdir)
  897. # Add a commit
  898. result = runCmd('echo "# Additional line" >> Makefile.am', cwd=tempsrcdir)
  899. result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
  900. self.add_command_to_tearDown('cd %s; rm -f %s/*.patch; git checkout .' % (os.path.dirname(recipefile), testrecipe))
  901. # Create a temporary layer
  902. os.makedirs(os.path.join(templayerdir, 'conf'))
  903. with open(os.path.join(templayerdir, 'conf', 'layer.conf'), 'w') as f:
  904. f.write('BBPATH .= ":${LAYERDIR}"\n')
  905. f.write('BBFILES += "${LAYERDIR}/recipes-*/*/*.bbappend"\n')
  906. f.write('BBFILE_COLLECTIONS += "oeselftesttemplayer"\n')
  907. f.write('BBFILE_PATTERN_oeselftesttemplayer = "^${LAYERDIR}/"\n')
  908. f.write('BBFILE_PRIORITY_oeselftesttemplayer = "999"\n')
  909. f.write('BBFILE_PATTERN_IGNORE_EMPTY_oeselftesttemplayer = "1"\n')
  910. f.write('LAYERSERIES_COMPAT_oeselftesttemplayer = "${LAYERSERIES_COMPAT_core}"\n')
  911. self.add_command_to_tearDown('bitbake-layers remove-layer %s || true' % templayerdir)
  912. result = runCmd('bitbake-layers add-layer %s' % templayerdir, cwd=self.builddir)
  913. # Create the bbappend
  914. result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
  915. self.assertNotIn('WARNING:', result.output)
  916. # Check recipe is still clean
  917. self._check_repo_status(os.path.dirname(recipefile), [])
  918. # Check bbappend was created
  919. splitpath = os.path.dirname(recipefile).split(os.sep)
  920. appenddir = os.path.join(templayerdir, splitpath[-2], splitpath[-1])
  921. bbappendfile = self._check_bbappend(testrecipe, recipefile, appenddir)
  922. self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
  923. # Check bbappend contents
  924. result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
  925. expectedlines = set(['SRCREV = "%s"\n' % result.output,
  926. '\n',
  927. 'SRC_URI = "%s"\n' % git_uri,
  928. '\n'])
  929. with open(bbappendfile, 'r') as f:
  930. self.assertEqual(expectedlines, set(f.readlines()))
  931. # Check we can run it again and bbappend isn't modified
  932. result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
  933. with open(bbappendfile, 'r') as f:
  934. self.assertEqual(expectedlines, set(f.readlines()))
  935. # Drop new commit and check SRCREV changes
  936. result = runCmd('git reset HEAD^', cwd=tempsrcdir)
  937. result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
  938. self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
  939. result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
  940. expectedlines = set(['SRCREV = "%s"\n' % result.output,
  941. '\n',
  942. 'SRC_URI = "%s"\n' % git_uri,
  943. '\n'])
  944. with open(bbappendfile, 'r') as f:
  945. self.assertEqual(expectedlines, set(f.readlines()))
  946. # Put commit back and check we can run it if layer isn't in bblayers.conf
  947. os.remove(bbappendfile)
  948. result = runCmd('git commit -a -m "Change the Makefile"', cwd=tempsrcdir)
  949. result = runCmd('bitbake-layers remove-layer %s' % templayerdir, cwd=self.builddir)
  950. result = runCmd('devtool update-recipe -m srcrev %s -a %s' % (testrecipe, templayerdir))
  951. self.assertIn('WARNING: Specified layer is not currently enabled in bblayers.conf', result.output)
  952. self.assertNotExists(os.path.join(appenddir, testrecipe), 'Patch directory should not be created')
  953. result = runCmd('git rev-parse HEAD', cwd=tempsrcdir)
  954. expectedlines = set(['SRCREV = "%s"\n' % result.output,
  955. '\n',
  956. 'SRC_URI = "%s"\n' % git_uri,
  957. '\n'])
  958. with open(bbappendfile, 'r') as f:
  959. self.assertEqual(expectedlines, set(f.readlines()))
  960. # Deleting isn't expected to work under these circumstances
  961. @OETestID(1370)
  962. def test_devtool_update_recipe_local_files(self):
  963. """Check that local source files are copied over instead of patched"""
  964. testrecipe = 'makedevs'
  965. recipefile = get_bb_var('FILE', testrecipe)
  966. # Setup srctree for modifying the recipe
  967. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  968. self.track_for_cleanup(tempdir)
  969. self.track_for_cleanup(self.workspacedir)
  970. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  971. # (don't bother with cleaning the recipe on teardown, we won't be
  972. # building it)
  973. result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
  974. # Check git repo
  975. self._check_src_repo(tempdir)
  976. # Try building just to ensure we haven't broken that
  977. bitbake("%s" % testrecipe)
  978. # Edit / commit local source
  979. runCmd('echo "/* Foobar */" >> oe-local-files/makedevs.c', cwd=tempdir)
  980. runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
  981. runCmd('echo "Bar" > new-file', cwd=tempdir)
  982. runCmd('git add new-file', cwd=tempdir)
  983. runCmd('git commit -m "Add new file"', cwd=tempdir)
  984. self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
  985. os.path.dirname(recipefile))
  986. runCmd('devtool update-recipe %s' % testrecipe)
  987. expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
  988. (' M', '.*/makedevs/makedevs.c$'),
  989. ('??', '.*/makedevs/new-local$'),
  990. ('??', '.*/makedevs/0001-Add-new-file.patch$')]
  991. self._check_repo_status(os.path.dirname(recipefile), expected_status)
  992. @OETestID(1371)
  993. def test_devtool_update_recipe_local_files_2(self):
  994. """Check local source files support when oe-local-files is in Git"""
  995. testrecipe = 'devtool-test-local'
  996. recipefile = get_bb_var('FILE', testrecipe)
  997. recipedir = os.path.dirname(recipefile)
  998. result = runCmd('git status --porcelain .', cwd=recipedir)
  999. if result.output.strip():
  1000. self.fail('Recipe directory for %s contains uncommitted changes' % testrecipe)
  1001. # Setup srctree for modifying the recipe
  1002. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1003. self.track_for_cleanup(tempdir)
  1004. self.track_for_cleanup(self.workspacedir)
  1005. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1006. result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
  1007. # Check git repo
  1008. self._check_src_repo(tempdir)
  1009. # Add oe-local-files to Git
  1010. runCmd('rm oe-local-files/.gitignore', cwd=tempdir)
  1011. runCmd('git add oe-local-files', cwd=tempdir)
  1012. runCmd('git commit -m "Add local sources"', cwd=tempdir)
  1013. # Edit / commit local sources
  1014. runCmd('echo "# Foobar" >> oe-local-files/file1', cwd=tempdir)
  1015. runCmd('git commit -am "Edit existing file"', cwd=tempdir)
  1016. runCmd('git rm oe-local-files/file2', cwd=tempdir)
  1017. runCmd('git commit -m"Remove file"', cwd=tempdir)
  1018. runCmd('echo "Foo" > oe-local-files/new-local', cwd=tempdir)
  1019. runCmd('git add oe-local-files/new-local', cwd=tempdir)
  1020. runCmd('git commit -m "Add new local file"', cwd=tempdir)
  1021. runCmd('echo "Gar" > new-file', cwd=tempdir)
  1022. runCmd('git add new-file', cwd=tempdir)
  1023. runCmd('git commit -m "Add new file"', cwd=tempdir)
  1024. self.add_command_to_tearDown('cd %s; git clean -fd .; git checkout .' %
  1025. os.path.dirname(recipefile))
  1026. # Checkout unmodified file to working copy -> devtool should still pick
  1027. # the modified version from HEAD
  1028. runCmd('git checkout HEAD^ -- oe-local-files/file1', cwd=tempdir)
  1029. runCmd('devtool update-recipe %s' % testrecipe)
  1030. expected_status = [(' M', '.*/%s$' % os.path.basename(recipefile)),
  1031. (' M', '.*/file1$'),
  1032. (' D', '.*/file2$'),
  1033. ('??', '.*/new-local$'),
  1034. ('??', '.*/0001-Add-new-file.patch$')]
  1035. self._check_repo_status(os.path.dirname(recipefile), expected_status)
  1036. @OETestID(1627)
  1037. def test_devtool_update_recipe_local_files_3(self):
  1038. # First, modify the recipe
  1039. testrecipe = 'devtool-test-localonly'
  1040. bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
  1041. recipefile = bb_vars['FILE']
  1042. src_uri = bb_vars['SRC_URI']
  1043. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1044. self.track_for_cleanup(tempdir)
  1045. self.track_for_cleanup(self.workspacedir)
  1046. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1047. # (don't bother with cleaning the recipe on teardown, we won't be building it)
  1048. result = runCmd('devtool modify %s' % testrecipe)
  1049. # Modify one file
  1050. runCmd('echo "Another line" >> file2', cwd=os.path.join(self.workspacedir, 'sources', testrecipe, 'oe-local-files'))
  1051. self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
  1052. result = runCmd('devtool update-recipe %s' % testrecipe)
  1053. expected_status = [(' M', '.*/%s/file2$' % testrecipe)]
  1054. self._check_repo_status(os.path.dirname(recipefile), expected_status)
  1055. @OETestID(1629)
  1056. def test_devtool_update_recipe_local_patch_gz(self):
  1057. # First, modify the recipe
  1058. testrecipe = 'devtool-test-patch-gz'
  1059. if get_bb_var('DISTRO') == 'poky-tiny':
  1060. self.skipTest("The DISTRO 'poky-tiny' does not provide the dependencies needed by %s" % testrecipe)
  1061. bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
  1062. recipefile = bb_vars['FILE']
  1063. src_uri = bb_vars['SRC_URI']
  1064. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1065. self.track_for_cleanup(tempdir)
  1066. self.track_for_cleanup(self.workspacedir)
  1067. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1068. # (don't bother with cleaning the recipe on teardown, we won't be building it)
  1069. result = runCmd('devtool modify %s' % testrecipe)
  1070. # Modify one file
  1071. srctree = os.path.join(self.workspacedir, 'sources', testrecipe)
  1072. runCmd('echo "Another line" >> README', cwd=srctree)
  1073. runCmd('git commit -a --amend --no-edit', cwd=srctree)
  1074. self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
  1075. result = runCmd('devtool update-recipe %s' % testrecipe)
  1076. expected_status = [(' M', '.*/%s/readme.patch.gz$' % testrecipe)]
  1077. self._check_repo_status(os.path.dirname(recipefile), expected_status)
  1078. patch_gz = os.path.join(os.path.dirname(recipefile), testrecipe, 'readme.patch.gz')
  1079. result = runCmd('file %s' % patch_gz)
  1080. if 'gzip compressed data' not in result.output:
  1081. self.fail('New patch file is not gzipped - file reports:\n%s' % result.output)
  1082. @OETestID(1628)
  1083. def test_devtool_update_recipe_local_files_subdir(self):
  1084. # Try devtool update-recipe on a recipe that has a file with subdir= set in
  1085. # SRC_URI such that it overwrites a file that was in an archive that
  1086. # was also in SRC_URI
  1087. # First, modify the recipe
  1088. testrecipe = 'devtool-test-subdir'
  1089. bb_vars = get_bb_vars(['FILE', 'SRC_URI'], testrecipe)
  1090. recipefile = bb_vars['FILE']
  1091. src_uri = bb_vars['SRC_URI']
  1092. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1093. self.track_for_cleanup(tempdir)
  1094. self.track_for_cleanup(self.workspacedir)
  1095. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1096. # (don't bother with cleaning the recipe on teardown, we won't be building it)
  1097. result = runCmd('devtool modify %s' % testrecipe)
  1098. testfile = os.path.join(self.workspacedir, 'sources', testrecipe, 'testfile')
  1099. self.assertExists(testfile, 'Extracted source could not be found')
  1100. with open(testfile, 'r') as f:
  1101. contents = f.read().rstrip()
  1102. self.assertEqual(contents, 'Modified version', 'File has apparently not been overwritten as it should have been')
  1103. # Test devtool update-recipe without modifying any files
  1104. self.add_command_to_tearDown('cd %s; rm %s/*; git checkout %s %s' % (os.path.dirname(recipefile), testrecipe, testrecipe, os.path.basename(recipefile)))
  1105. result = runCmd('devtool update-recipe %s' % testrecipe)
  1106. expected_status = []
  1107. self._check_repo_status(os.path.dirname(recipefile), expected_status)
  1108. class DevtoolExtractTests(DevtoolBase):
  1109. @OETestID(1163)
  1110. def test_devtool_extract(self):
  1111. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1112. # Try devtool extract
  1113. self.track_for_cleanup(tempdir)
  1114. self.track_for_cleanup(self.workspacedir)
  1115. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1116. result = runCmd('devtool extract matchbox-terminal %s' % tempdir)
  1117. self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
  1118. self._check_src_repo(tempdir)
  1119. @OETestID(1379)
  1120. def test_devtool_extract_virtual(self):
  1121. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1122. # Try devtool extract
  1123. self.track_for_cleanup(tempdir)
  1124. self.track_for_cleanup(self.workspacedir)
  1125. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1126. result = runCmd('devtool extract virtual/make %s' % tempdir)
  1127. self.assertExists(os.path.join(tempdir, 'Makefile.am'), 'Extracted source could not be found')
  1128. self._check_src_repo(tempdir)
  1129. @OETestID(1168)
  1130. def test_devtool_reset_all(self):
  1131. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1132. self.track_for_cleanup(tempdir)
  1133. self.track_for_cleanup(self.workspacedir)
  1134. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1135. testrecipe1 = 'mdadm'
  1136. testrecipe2 = 'cronie'
  1137. result = runCmd('devtool modify -x %s %s' % (testrecipe1, os.path.join(tempdir, testrecipe1)))
  1138. result = runCmd('devtool modify -x %s %s' % (testrecipe2, os.path.join(tempdir, testrecipe2)))
  1139. result = runCmd('devtool build %s' % testrecipe1)
  1140. result = runCmd('devtool build %s' % testrecipe2)
  1141. stampprefix1 = get_bb_var('STAMP', testrecipe1)
  1142. self.assertTrue(stampprefix1, 'Unable to get STAMP value for recipe %s' % testrecipe1)
  1143. stampprefix2 = get_bb_var('STAMP', testrecipe2)
  1144. self.assertTrue(stampprefix2, 'Unable to get STAMP value for recipe %s' % testrecipe2)
  1145. result = runCmd('devtool reset -a')
  1146. self.assertIn(testrecipe1, result.output)
  1147. self.assertIn(testrecipe2, result.output)
  1148. result = runCmd('devtool status')
  1149. self.assertNotIn(testrecipe1, result.output)
  1150. self.assertNotIn(testrecipe2, result.output)
  1151. matches1 = glob.glob(stampprefix1 + '*')
  1152. self.assertFalse(matches1, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe1)
  1153. matches2 = glob.glob(stampprefix2 + '*')
  1154. self.assertFalse(matches2, 'Stamp files exist for recipe %s that should have been cleaned' % testrecipe2)
  1155. @OETestID(1272)
  1156. def test_devtool_deploy_target(self):
  1157. # NOTE: Whilst this test would seemingly be better placed as a runtime test,
  1158. # unfortunately the runtime tests run under bitbake and you can't run
  1159. # devtool within bitbake (since devtool needs to run bitbake itself).
  1160. # Additionally we are testing build-time functionality as well, so
  1161. # really this has to be done as an oe-selftest test.
  1162. #
  1163. # Check preconditions
  1164. machine = get_bb_var('MACHINE')
  1165. if not machine.startswith('qemu'):
  1166. self.skipTest('This test only works with qemu machines')
  1167. if not os.path.exists('/etc/runqemu-nosudo'):
  1168. self.skipTest('You must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
  1169. result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ip tuntap show', ignore_status=True)
  1170. if result.status != 0:
  1171. result = runCmd('PATH="$PATH:/sbin:/usr/sbin" ifconfig -a', ignore_status=True)
  1172. if result.status != 0:
  1173. self.skipTest('Failed to determine if tap devices exist with ifconfig or ip: %s' % result.output)
  1174. for line in result.output.splitlines():
  1175. if line.startswith('tap'):
  1176. break
  1177. else:
  1178. self.skipTest('No tap devices found - you must set up tap devices with scripts/runqemu-gen-tapdevs before running this test')
  1179. self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
  1180. # Definitions
  1181. testrecipe = 'mdadm'
  1182. testfile = '/sbin/mdadm'
  1183. testimage = 'oe-selftest-image'
  1184. testcommand = '/sbin/mdadm --help'
  1185. # Build an image to run
  1186. bitbake("%s qemu-native qemu-helper-native" % testimage)
  1187. deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
  1188. self.add_command_to_tearDown('bitbake -c clean %s' % testimage)
  1189. self.add_command_to_tearDown('rm -f %s/%s*' % (deploy_dir_image, testimage))
  1190. # Clean recipe so the first deploy will fail
  1191. bitbake("%s -c clean" % testrecipe)
  1192. # Try devtool modify
  1193. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1194. self.track_for_cleanup(tempdir)
  1195. self.track_for_cleanup(self.workspacedir)
  1196. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1197. self.add_command_to_tearDown('bitbake -c clean %s' % testrecipe)
  1198. result = runCmd('devtool modify %s -x %s' % (testrecipe, tempdir))
  1199. # Test that deploy-target at this point fails (properly)
  1200. result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe, ignore_status=True)
  1201. self.assertNotEqual(result.output, 0, 'devtool deploy-target should have failed, output: %s' % result.output)
  1202. self.assertNotIn(result.output, 'Traceback', 'devtool deploy-target should have failed with a proper error not a traceback, output: %s' % result.output)
  1203. result = runCmd('devtool build %s' % testrecipe)
  1204. # First try a dry-run of deploy-target
  1205. result = runCmd('devtool deploy-target -n %s root@localhost' % testrecipe)
  1206. self.assertIn(' %s' % testfile, result.output)
  1207. # Boot the image
  1208. with runqemu(testimage) as qemu:
  1209. # Now really test deploy-target
  1210. result = runCmd('devtool deploy-target -c %s root@%s' % (testrecipe, qemu.ip))
  1211. # Run a test command to see if it was installed properly
  1212. sshargs = '-o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no'
  1213. result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand))
  1214. # Check if it deployed all of the files with the right ownership/perms
  1215. # First look on the host - need to do this under pseudo to get the correct ownership/perms
  1216. bb_vars = get_bb_vars(['D', 'FAKEROOTENV', 'FAKEROOTCMD'], testrecipe)
  1217. installdir = bb_vars['D']
  1218. fakerootenv = bb_vars['FAKEROOTENV']
  1219. fakerootcmd = bb_vars['FAKEROOTCMD']
  1220. result = runCmd('%s %s find . -type f -exec ls -l {} \;' % (fakerootenv, fakerootcmd), cwd=installdir)
  1221. filelist1 = self._process_ls_output(result.output)
  1222. # Now look on the target
  1223. tempdir2 = tempfile.mkdtemp(prefix='devtoolqa')
  1224. self.track_for_cleanup(tempdir2)
  1225. tmpfilelist = os.path.join(tempdir2, 'files.txt')
  1226. with open(tmpfilelist, 'w') as f:
  1227. for line in filelist1:
  1228. splitline = line.split()
  1229. f.write(splitline[-1] + '\n')
  1230. result = runCmd('cat %s | ssh -q %s root@%s \'xargs ls -l\'' % (tmpfilelist, sshargs, qemu.ip))
  1231. filelist2 = self._process_ls_output(result.output)
  1232. filelist1.sort(key=lambda item: item.split()[-1])
  1233. filelist2.sort(key=lambda item: item.split()[-1])
  1234. self.assertEqual(filelist1, filelist2)
  1235. # Test undeploy-target
  1236. result = runCmd('devtool undeploy-target -c %s root@%s' % (testrecipe, qemu.ip))
  1237. result = runCmd('ssh %s root@%s %s' % (sshargs, qemu.ip, testcommand), ignore_status=True)
  1238. self.assertNotEqual(result, 0, 'undeploy-target did not remove command as it should have')
  1239. @OETestID(1366)
  1240. def test_devtool_build_image(self):
  1241. """Test devtool build-image plugin"""
  1242. # Check preconditions
  1243. self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
  1244. image = 'core-image-minimal'
  1245. self.track_for_cleanup(self.workspacedir)
  1246. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1247. self.add_command_to_tearDown('bitbake -c clean %s' % image)
  1248. bitbake('%s -c clean' % image)
  1249. # Add target and native recipes to workspace
  1250. recipes = ['mdadm', 'parted-native']
  1251. for recipe in recipes:
  1252. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1253. self.track_for_cleanup(tempdir)
  1254. self.add_command_to_tearDown('bitbake -c clean %s' % recipe)
  1255. runCmd('devtool modify %s -x %s' % (recipe, tempdir))
  1256. # Try to build image
  1257. result = runCmd('devtool build-image %s' % image)
  1258. self.assertNotEqual(result, 0, 'devtool build-image failed')
  1259. # Check if image contains expected packages
  1260. deploy_dir_image = get_bb_var('DEPLOY_DIR_IMAGE')
  1261. image_link_name = get_bb_var('IMAGE_LINK_NAME', image)
  1262. reqpkgs = [item for item in recipes if not item.endswith('-native')]
  1263. with open(os.path.join(deploy_dir_image, image_link_name + '.manifest'), 'r') as f:
  1264. for line in f:
  1265. splitval = line.split()
  1266. if splitval:
  1267. pkg = splitval[0]
  1268. if pkg in reqpkgs:
  1269. reqpkgs.remove(pkg)
  1270. if reqpkgs:
  1271. self.fail('The following packages were not present in the image as expected: %s' % ', '.join(reqpkgs))
  1272. class DevtoolUpgradeTests(DevtoolBase):
  1273. @OETestID(1367)
  1274. def test_devtool_upgrade(self):
  1275. # Check preconditions
  1276. self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
  1277. self.track_for_cleanup(self.workspacedir)
  1278. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1279. # Check parameters
  1280. result = runCmd('devtool upgrade -h')
  1281. for param in 'recipename srctree --version -V --branch -b --keep-temp --no-patch'.split():
  1282. self.assertIn(param, result.output)
  1283. # For the moment, we are using a real recipe.
  1284. recipe = 'devtool-upgrade-test1'
  1285. version = '1.6.0'
  1286. oldrecipefile = get_bb_var('FILE', recipe)
  1287. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1288. self.track_for_cleanup(tempdir)
  1289. # Check that recipe is not already under devtool control
  1290. result = runCmd('devtool status')
  1291. self.assertNotIn(recipe, result.output)
  1292. # Check upgrade. Code does not check if new PV is older or newer that current PV, so, it may be that
  1293. # we are downgrading instead of upgrading.
  1294. result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, version))
  1295. # Check if srctree at least is populated
  1296. self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, version))
  1297. # Check new recipe subdirectory is present
  1298. self.assertExists(os.path.join(self.workspacedir, 'recipes', recipe, '%s-%s' % (recipe, version)), 'Recipe folder should exist')
  1299. # Check new recipe file is present
  1300. newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, '%s_%s.bb' % (recipe, version))
  1301. self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
  1302. # Check devtool status and make sure recipe is present
  1303. result = runCmd('devtool status')
  1304. self.assertIn(recipe, result.output)
  1305. self.assertIn(tempdir, result.output)
  1306. # Check recipe got changed as expected
  1307. with open(oldrecipefile + '.upgraded', 'r') as f:
  1308. desiredlines = f.readlines()
  1309. with open(newrecipefile, 'r') as f:
  1310. newlines = f.readlines()
  1311. self.assertEqual(desiredlines, newlines)
  1312. # Check devtool reset recipe
  1313. result = runCmd('devtool reset %s -n' % recipe)
  1314. result = runCmd('devtool status')
  1315. self.assertNotIn(recipe, result.output)
  1316. self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
  1317. @OETestID(1433)
  1318. def test_devtool_upgrade_git(self):
  1319. # Check preconditions
  1320. self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
  1321. self.track_for_cleanup(self.workspacedir)
  1322. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1323. recipe = 'devtool-upgrade-test2'
  1324. commit = '6cc6077a36fe2648a5f993fe7c16c9632f946517'
  1325. oldrecipefile = get_bb_var('FILE', recipe)
  1326. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1327. self.track_for_cleanup(tempdir)
  1328. # Check that recipe is not already under devtool control
  1329. result = runCmd('devtool status')
  1330. self.assertNotIn(recipe, result.output)
  1331. # Check upgrade
  1332. result = runCmd('devtool upgrade %s %s -S %s' % (recipe, tempdir, commit))
  1333. # Check if srctree at least is populated
  1334. self.assertTrue(len(os.listdir(tempdir)) > 0, 'srctree (%s) should be populated with new (%s) source code' % (tempdir, commit))
  1335. # Check new recipe file is present
  1336. newrecipefile = os.path.join(self.workspacedir, 'recipes', recipe, os.path.basename(oldrecipefile))
  1337. self.assertExists(newrecipefile, 'Recipe file should exist after upgrade')
  1338. # Check devtool status and make sure recipe is present
  1339. result = runCmd('devtool status')
  1340. self.assertIn(recipe, result.output)
  1341. self.assertIn(tempdir, result.output)
  1342. # Check recipe got changed as expected
  1343. with open(oldrecipefile + '.upgraded', 'r') as f:
  1344. desiredlines = f.readlines()
  1345. with open(newrecipefile, 'r') as f:
  1346. newlines = f.readlines()
  1347. self.assertEqual(desiredlines, newlines)
  1348. # Check devtool reset recipe
  1349. result = runCmd('devtool reset %s -n' % recipe)
  1350. result = runCmd('devtool status')
  1351. self.assertNotIn(recipe, result.output)
  1352. self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after resetting')
  1353. @OETestID(1352)
  1354. def test_devtool_layer_plugins(self):
  1355. """Test that devtool can use plugins from other layers.
  1356. This test executes the selftest-reverse command from meta-selftest."""
  1357. self.track_for_cleanup(self.workspacedir)
  1358. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1359. s = "Microsoft Made No Profit From Anyone's Zunes Yo"
  1360. result = runCmd("devtool --quiet selftest-reverse \"%s\"" % s)
  1361. self.assertEqual(result.output, s[::-1])
  1362. def _copy_file_with_cleanup(self, srcfile, basedstdir, *paths):
  1363. dstdir = basedstdir
  1364. self.assertExists(dstdir)
  1365. for p in paths:
  1366. dstdir = os.path.join(dstdir, p)
  1367. if not os.path.exists(dstdir):
  1368. os.makedirs(dstdir)
  1369. self.track_for_cleanup(dstdir)
  1370. dstfile = os.path.join(dstdir, os.path.basename(srcfile))
  1371. if srcfile != dstfile:
  1372. shutil.copy(srcfile, dstfile)
  1373. self.track_for_cleanup(dstfile)
  1374. @OETestID(1625)
  1375. def test_devtool_load_plugin(self):
  1376. """Test that devtool loads only the first found plugin in BBPATH."""
  1377. self.track_for_cleanup(self.workspacedir)
  1378. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1379. devtool = runCmd("which devtool")
  1380. fromname = runCmd("devtool --quiet pluginfile")
  1381. srcfile = fromname.output
  1382. bbpath = get_bb_var('BBPATH')
  1383. searchpath = bbpath.split(':') + [os.path.dirname(devtool.output)]
  1384. plugincontent = []
  1385. with open(srcfile) as fh:
  1386. plugincontent = fh.readlines()
  1387. try:
  1388. self.assertIn('meta-selftest', srcfile, 'wrong bbpath plugin found')
  1389. for path in searchpath:
  1390. self._copy_file_with_cleanup(srcfile, path, 'lib', 'devtool')
  1391. result = runCmd("devtool --quiet count")
  1392. self.assertEqual(result.output, '1')
  1393. result = runCmd("devtool --quiet multiloaded")
  1394. self.assertEqual(result.output, "no")
  1395. for path in searchpath:
  1396. result = runCmd("devtool --quiet bbdir")
  1397. self.assertEqual(result.output, path)
  1398. os.unlink(os.path.join(result.output, 'lib', 'devtool', 'bbpath.py'))
  1399. finally:
  1400. with open(srcfile, 'w') as fh:
  1401. fh.writelines(plugincontent)
  1402. def _setup_test_devtool_finish_upgrade(self):
  1403. # Check preconditions
  1404. self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
  1405. self.track_for_cleanup(self.workspacedir)
  1406. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1407. # Use a "real" recipe from meta-selftest
  1408. recipe = 'devtool-upgrade-test1'
  1409. oldversion = '1.5.3'
  1410. newversion = '1.6.0'
  1411. oldrecipefile = get_bb_var('FILE', recipe)
  1412. recipedir = os.path.dirname(oldrecipefile)
  1413. result = runCmd('git status --porcelain .', cwd=recipedir)
  1414. if result.output.strip():
  1415. self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
  1416. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1417. self.track_for_cleanup(tempdir)
  1418. # Check that recipe is not already under devtool control
  1419. result = runCmd('devtool status')
  1420. self.assertNotIn(recipe, result.output)
  1421. # Do the upgrade
  1422. result = runCmd('devtool upgrade %s %s -V %s' % (recipe, tempdir, newversion))
  1423. # Check devtool status and make sure recipe is present
  1424. result = runCmd('devtool status')
  1425. self.assertIn(recipe, result.output)
  1426. self.assertIn(tempdir, result.output)
  1427. # Make a change to the source
  1428. result = runCmd('sed -i \'/^#include "pv.h"/a \\/* Here is a new comment *\\/\' src/pv/number.c', cwd=tempdir)
  1429. result = runCmd('git status --porcelain', cwd=tempdir)
  1430. self.assertIn('M src/pv/number.c', result.output)
  1431. result = runCmd('git commit src/pv/number.c -m "Add a comment to the code"', cwd=tempdir)
  1432. # Check if patch is there
  1433. recipedir = os.path.dirname(oldrecipefile)
  1434. olddir = os.path.join(recipedir, recipe + '-' + oldversion)
  1435. patchfn = '0001-Add-a-note-line-to-the-quick-reference.patch'
  1436. self.assertExists(os.path.join(olddir, patchfn), 'Original patch file does not exist')
  1437. return recipe, oldrecipefile, recipedir, olddir, newversion, patchfn
  1438. @OETestID(1623)
  1439. def test_devtool_finish_upgrade_origlayer(self):
  1440. recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
  1441. # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
  1442. self.assertIn('/meta-selftest/', recipedir)
  1443. # Try finish to the original layer
  1444. self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
  1445. result = runCmd('devtool finish %s meta-selftest' % recipe)
  1446. result = runCmd('devtool status')
  1447. self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
  1448. self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
  1449. self.assertNotExists(oldrecipefile, 'Old recipe file should have been deleted but wasn\'t')
  1450. self.assertNotExists(os.path.join(olddir, patchfn), 'Old patch file should have been deleted but wasn\'t')
  1451. newrecipefile = os.path.join(recipedir, '%s_%s.bb' % (recipe, newversion))
  1452. newdir = os.path.join(recipedir, recipe + '-' + newversion)
  1453. self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
  1454. self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
  1455. self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
  1456. @OETestID(1624)
  1457. def test_devtool_finish_upgrade_otherlayer(self):
  1458. recipe, oldrecipefile, recipedir, olddir, newversion, patchfn = self._setup_test_devtool_finish_upgrade()
  1459. # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
  1460. self.assertIn('/meta-selftest/', recipedir)
  1461. # Try finish to a different layer - should create a bbappend
  1462. # This cleanup isn't strictly necessary but do it anyway just in case it goes wrong and writes to here
  1463. self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
  1464. oe_core_dir = os.path.join(get_bb_var('COREBASE'), 'meta')
  1465. newrecipedir = os.path.join(oe_core_dir, 'recipes-test', 'devtool')
  1466. newrecipefile = os.path.join(newrecipedir, '%s_%s.bb' % (recipe, newversion))
  1467. self.track_for_cleanup(newrecipedir)
  1468. result = runCmd('devtool finish %s oe-core' % recipe)
  1469. result = runCmd('devtool status')
  1470. self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
  1471. self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
  1472. self.assertExists(oldrecipefile, 'Old recipe file should not have been deleted')
  1473. self.assertExists(os.path.join(olddir, patchfn), 'Old patch file should not have been deleted')
  1474. newdir = os.path.join(newrecipedir, recipe + '-' + newversion)
  1475. self.assertExists(newrecipefile, 'New recipe file should have been copied into existing layer but wasn\'t')
  1476. self.assertExists(os.path.join(newdir, patchfn), 'Patch file should have been copied into new directory but wasn\'t')
  1477. self.assertExists(os.path.join(newdir, '0002-Add-a-comment-to-the-code.patch'), 'New patch file should have been created but wasn\'t')
  1478. def _setup_test_devtool_finish_modify(self):
  1479. # Check preconditions
  1480. self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
  1481. # Try modifying a recipe
  1482. self.track_for_cleanup(self.workspacedir)
  1483. recipe = 'mdadm'
  1484. oldrecipefile = get_bb_var('FILE', recipe)
  1485. recipedir = os.path.dirname(oldrecipefile)
  1486. result = runCmd('git status --porcelain .', cwd=recipedir)
  1487. if result.output.strip():
  1488. self.fail('Recipe directory for %s contains uncommitted changes' % recipe)
  1489. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1490. self.track_for_cleanup(tempdir)
  1491. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1492. result = runCmd('devtool modify %s %s' % (recipe, tempdir))
  1493. self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
  1494. # Test devtool status
  1495. result = runCmd('devtool status')
  1496. self.assertIn(recipe, result.output)
  1497. self.assertIn(tempdir, result.output)
  1498. # Make a change to the source
  1499. result = runCmd('sed -i \'/^#include "mdadm.h"/a \\/* Here is a new comment *\\/\' maps.c', cwd=tempdir)
  1500. result = runCmd('git status --porcelain', cwd=tempdir)
  1501. self.assertIn('M maps.c', result.output)
  1502. result = runCmd('git commit maps.c -m "Add a comment to the code"', cwd=tempdir)
  1503. for entry in os.listdir(recipedir):
  1504. filesdir = os.path.join(recipedir, entry)
  1505. if os.path.isdir(filesdir):
  1506. break
  1507. else:
  1508. self.fail('Unable to find recipe files directory for %s' % recipe)
  1509. return recipe, oldrecipefile, recipedir, filesdir
  1510. @OETestID(1621)
  1511. def test_devtool_finish_modify_origlayer(self):
  1512. recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
  1513. # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
  1514. self.assertIn('/meta/', recipedir)
  1515. # Try finish to the original layer
  1516. self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
  1517. result = runCmd('devtool finish %s meta' % recipe)
  1518. result = runCmd('devtool status')
  1519. self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
  1520. self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
  1521. expected_status = [(' M', '.*/%s$' % os.path.basename(oldrecipefile)),
  1522. ('??', '.*/.*-Add-a-comment-to-the-code.patch$')]
  1523. self._check_repo_status(recipedir, expected_status)
  1524. @OETestID(1622)
  1525. def test_devtool_finish_modify_otherlayer(self):
  1526. recipe, oldrecipefile, recipedir, filesdir = self._setup_test_devtool_finish_modify()
  1527. # Ensure the recipe is where we think it should be (so that cleanup doesn't trash things)
  1528. self.assertIn('/meta/', recipedir)
  1529. relpth = os.path.relpath(recipedir, os.path.join(get_bb_var('COREBASE'), 'meta'))
  1530. appenddir = os.path.join(get_test_layer(), relpth)
  1531. self.track_for_cleanup(appenddir)
  1532. # Try finish to the original layer
  1533. self.add_command_to_tearDown('rm -rf %s ; cd %s ; git checkout %s' % (recipedir, os.path.dirname(recipedir), recipedir))
  1534. result = runCmd('devtool finish %s meta-selftest' % recipe)
  1535. result = runCmd('devtool status')
  1536. self.assertNotIn(recipe, result.output, 'Recipe should have been reset by finish but wasn\'t')
  1537. self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipe), 'Recipe directory should not exist after finish')
  1538. result = runCmd('git status --porcelain .', cwd=recipedir)
  1539. if result.output.strip():
  1540. self.fail('Recipe directory for %s contains the following unexpected changes after finish:\n%s' % (recipe, result.output.strip()))
  1541. recipefn = os.path.splitext(os.path.basename(oldrecipefile))[0]
  1542. recipefn = recipefn.split('_')[0] + '_%'
  1543. appendfile = os.path.join(appenddir, recipefn + '.bbappend')
  1544. self.assertExists(appendfile, 'bbappend %s should have been created but wasn\'t' % appendfile)
  1545. newdir = os.path.join(appenddir, recipe)
  1546. files = os.listdir(newdir)
  1547. foundpatch = None
  1548. for fn in files:
  1549. if fnmatch.fnmatch(fn, '*-Add-a-comment-to-the-code.patch'):
  1550. foundpatch = fn
  1551. if not foundpatch:
  1552. self.fail('No patch file created next to bbappend')
  1553. files.remove(foundpatch)
  1554. if files:
  1555. self.fail('Unexpected file(s) copied next to bbappend: %s' % ', '.join(files))
  1556. @OETestID(1626)
  1557. def test_devtool_rename(self):
  1558. # Check preconditions
  1559. self.assertTrue(not os.path.exists(self.workspacedir), 'This test cannot be run with a workspace directory under the build directory')
  1560. self.track_for_cleanup(self.workspacedir)
  1561. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1562. # First run devtool add
  1563. # We already have this recipe in OE-Core, but that doesn't matter
  1564. recipename = 'i2c-tools'
  1565. recipever = '3.1.2'
  1566. recipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, recipever))
  1567. url = 'http://downloads.yoctoproject.org/mirror/sources/i2c-tools-%s.tar.bz2' % recipever
  1568. def add_recipe():
  1569. result = runCmd('devtool add %s' % url)
  1570. self.assertExists(recipefile, 'Expected recipe file not created')
  1571. self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory not created')
  1572. checkvars = {}
  1573. checkvars['S'] = None
  1574. checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
  1575. self._test_recipe_contents(recipefile, checkvars, [])
  1576. add_recipe()
  1577. # Now rename it - change both name and version
  1578. newrecipename = 'mynewrecipe'
  1579. newrecipever = '456'
  1580. newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, newrecipever))
  1581. result = runCmd('devtool rename %s %s -V %s' % (recipename, newrecipename, newrecipever))
  1582. self.assertExists(newrecipefile, 'Recipe file not renamed')
  1583. self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
  1584. newsrctree = os.path.join(self.workspacedir, 'sources', newrecipename)
  1585. self.assertExists(newsrctree, 'Source directory not renamed')
  1586. checkvars = {}
  1587. checkvars['S'] = '${WORKDIR}/%s-%s' % (recipename, recipever)
  1588. checkvars['SRC_URI'] = url
  1589. self._test_recipe_contents(newrecipefile, checkvars, [])
  1590. # Try again - change just name this time
  1591. result = runCmd('devtool reset -n %s' % newrecipename)
  1592. shutil.rmtree(newsrctree)
  1593. add_recipe()
  1594. newrecipefile = os.path.join(self.workspacedir, 'recipes', newrecipename, '%s_%s.bb' % (newrecipename, recipever))
  1595. result = runCmd('devtool rename %s %s' % (recipename, newrecipename))
  1596. self.assertExists(newrecipefile, 'Recipe file not renamed')
  1597. self.assertNotExists(os.path.join(self.workspacedir, 'recipes', recipename), 'Old recipe directory still exists')
  1598. self.assertExists(os.path.join(self.workspacedir, 'sources', newrecipename), 'Source directory not renamed')
  1599. checkvars = {}
  1600. checkvars['S'] = '${WORKDIR}/%s-${PV}' % recipename
  1601. checkvars['SRC_URI'] = url.replace(recipever, '${PV}')
  1602. self._test_recipe_contents(newrecipefile, checkvars, [])
  1603. # Try again - change just version this time
  1604. result = runCmd('devtool reset -n %s' % newrecipename)
  1605. shutil.rmtree(newsrctree)
  1606. add_recipe()
  1607. newrecipefile = os.path.join(self.workspacedir, 'recipes', recipename, '%s_%s.bb' % (recipename, newrecipever))
  1608. result = runCmd('devtool rename %s -V %s' % (recipename, newrecipever))
  1609. self.assertExists(newrecipefile, 'Recipe file not renamed')
  1610. self.assertExists(os.path.join(self.workspacedir, 'sources', recipename), 'Source directory no longer exists')
  1611. checkvars = {}
  1612. checkvars['S'] = '${WORKDIR}/${BPN}-%s' % recipever
  1613. checkvars['SRC_URI'] = url
  1614. self._test_recipe_contents(newrecipefile, checkvars, [])
  1615. @OETestID(1577)
  1616. def test_devtool_virtual_kernel_modify(self):
  1617. """
  1618. Summary: The purpose of this test case is to verify that
  1619. devtool modify works correctly when building
  1620. the kernel.
  1621. Dependencies: NA
  1622. Steps: 1. Build kernel with bitbake.
  1623. 2. Save the config file generated.
  1624. 3. Clean the environment.
  1625. 4. Use `devtool modify virtual/kernel` to validate following:
  1626. 4.1 The source is checked out correctly.
  1627. 4.2 The resulting configuration is the same as
  1628. what was get on step 2.
  1629. 4.3 The Kernel can be build correctly.
  1630. 4.4 Changes made on the source are reflected on the
  1631. subsequent builds.
  1632. 4.5 Changes on the configuration are reflected on the
  1633. subsequent builds
  1634. Expected: devtool modify is able to checkout the source of the kernel
  1635. and modification to the source and configurations are reflected
  1636. when building the kernel.
  1637. """
  1638. kernel_provider = get_bb_var('PREFERRED_PROVIDER_virtual/kernel')
  1639. # Clean up the enviroment
  1640. bitbake('%s -c clean' % kernel_provider)
  1641. tempdir = tempfile.mkdtemp(prefix='devtoolqa')
  1642. tempdir_cfg = tempfile.mkdtemp(prefix='config_qa')
  1643. self.track_for_cleanup(tempdir)
  1644. self.track_for_cleanup(tempdir_cfg)
  1645. self.track_for_cleanup(self.workspacedir)
  1646. self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
  1647. self.add_command_to_tearDown('bitbake -c clean %s' % kernel_provider)
  1648. #Step 1
  1649. #Here is just generated the config file instead of all the kernel to optimize the
  1650. #time of executing this test case.
  1651. bitbake('%s -c configure' % kernel_provider)
  1652. bbconfig = os.path.join(get_bb_var('B', kernel_provider),'.config')
  1653. #Step 2
  1654. runCmd('cp %s %s' % (bbconfig, tempdir_cfg))
  1655. self.assertExists(os.path.join(tempdir_cfg, '.config'), 'Could not copy .config file from kernel')
  1656. tmpconfig = os.path.join(tempdir_cfg, '.config')
  1657. #Step 3
  1658. bitbake('%s -c clean' % kernel_provider)
  1659. #Step 4.1
  1660. runCmd('devtool modify virtual/kernel -x %s' % tempdir)
  1661. self.assertExists(os.path.join(tempdir, 'Makefile'), 'Extracted source could not be found')
  1662. #Step 4.2
  1663. configfile = os.path.join(tempdir,'.config')
  1664. diff = runCmd('diff %s %s' % (tmpconfig, configfile))
  1665. self.assertEqual(0,diff.status,'Kernel .config file is not the same using bitbake and devtool')
  1666. #Step 4.3
  1667. #NOTE: virtual/kernel is mapped to kernel_provider
  1668. result = runCmd('devtool build %s' % kernel_provider)
  1669. self.assertEqual(0,result.status,'Cannot build kernel using `devtool build`')
  1670. kernelfile = os.path.join(get_bb_var('KBUILD_OUTPUT', kernel_provider), 'vmlinux')
  1671. self.assertExists(kernelfile, 'Kernel was not build correctly')
  1672. #Modify the kernel source
  1673. modfile = os.path.join(tempdir,'arch/x86/boot/header.S')
  1674. modstring = "Use a boot loader. Devtool testing."
  1675. modapplied = runCmd("sed -i 's/Use a boot loader./%s/' %s" % (modstring, modfile))
  1676. self.assertEqual(0,modapplied.status,'Modification to %s on kernel source failed' % modfile)
  1677. #Modify the configuration
  1678. codeconfigfile = os.path.join(tempdir,'.config.new')
  1679. modconfopt = "CONFIG_SG_POOL=n"
  1680. modconf = runCmd("sed -i 's/CONFIG_SG_POOL=y/%s/' %s" % (modconfopt, codeconfigfile))
  1681. self.assertEqual(0,modconf.status,'Modification to %s failed' % codeconfigfile)
  1682. #Build again kernel with devtool
  1683. rebuild = runCmd('devtool build %s' % kernel_provider)
  1684. self.assertEqual(0,rebuild.status,'Fail to build kernel after modification of source and config')
  1685. #Step 4.4
  1686. bzimagename = 'bzImage-' + get_bb_var('KERNEL_VERSION_NAME', kernel_provider)
  1687. bzimagefile = os.path.join(get_bb_var('D', kernel_provider),'boot', bzimagename)
  1688. checkmodcode = runCmd("grep '%s' %s" % (modstring, bzimagefile))
  1689. self.assertEqual(0,checkmodcode.status,'Modification on kernel source failed')
  1690. #Step 4.5
  1691. checkmodconfg = runCmd("grep %s %s" % (modconfopt, codeconfigfile))
  1692. self.assertEqual(0,checkmodconfg.status,'Modification to configuration file failed')