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