Skip to contentSkip to conversation

devtool fixes

PATCH Superseded Paul Eggleton 2 participants 11 messages Apr 23, 2015 – Apr 24, 2015

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover devtool fixes

This series rolls up 5 patches previously posted by Markus (with very minor tweaks to a couple of the commit messages), and adds three new patches from me.

The following changes since commit 166f2587468ae71988c610858aad3f7ef67eccba:

bison: don't depend on help2man (2015-04-21 11:29:30 +0100)

are available in the git repository at:

git://git.openembedded.org/openembedded-core-contrib paule/devtool-fixes2
http://cgit.openembedded.org/cgit.cgi/openembedded-core-contrib/log/?h=paule/devtool-fixes2

Markus Lehtonen (5):
devtool: modify: use B=S if that is the default for the recipe
devtool: modify: implement --no-same-dir
oe-selftest: devtool: fix update-recipe test after bd1aa28
devtool: extract: remove patches when S=WORKDIR
devtool: include bbappends in recipe parsing

Paul Eggleton (3):
devtool: handle . in recipe name
devtool: add: use correct bbappend file name with -V option
devtool: reset: avoid errors in case file no longer exists

 meta/lib/oe/recipeutils.py        | 10 ++---
 meta/lib/oeqa/selftest/devtool.py | 15 +++++--
 scripts/devtool                   |  2 +-
 scripts/lib/devtool/standard.py   | 90 ++++++++++++++++++++++++++++++---------
 4 files changed, 86 insertions(+), 31 deletions(-)
Signature · 1 line
2.1.0
#1 lore raw

PATCH 1/8 devtool: modify: use B=S if that is the default for the recipe

From: Markus Lehtonen <[email protected]>

Makes the build succeed for packages which do not support separate build directory, e.g. zlib. The same outcome could be achieved with the --same-dir option, but, it's generally hard to tell if a random package would need that option. The negative side effect of this patch is that dev srctree (of some packages that build fine without this modification) gets dirtied by build artefacts.

---
 scripts/lib/devtool/standard.py | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)
scripts/lib/devtool/standard.py +12 -5
index d5ded2f..fbac34e 100644
@@ -384,12 +384,19 @@ def modify(args, config, basepath, workspace):
         f.write('inherit externalsrc\n')
         f.write('# NOTE: We use pn- overrides here to avoid affecting multiple variants in the case where the recipe uses BBCLASSEXTEND\n')
         f.write('EXTERNALSRC_pn-%s = "%s"\n' % (args.recipename, srctree))
-        if args.same_dir or bb.data.inherits_class('autotools-brokensep', rd):
-            if args.same_dir:
-                logger.info('using source tree as build directory since --same-dir specified')
-            else:
-                logger.info('using source tree as build directory since original recipe inherits autotools-brokensep')
+
+        b_is_s = True
+        if args.same_dir:
+            logger.info('using source tree as build directory since --same-dir specified')
+        elif bb.data.inherits_class('autotools-brokensep', rd):
+            logger.info('using source tree as build directory since original recipe inherits autotools-brokensep')
+        elif rd.getVar('B', True) == s:
+            logger.info('using source tree as build directory since that is the default for this recipe')
+        else:
+            b_is_s = False
+        if b_is_s:
             f.write('EXTERNALSRC_BUILD_pn-%s = "%s"\n' % (args.recipename, srctree))
+
         if initial_rev:
             f.write('\n# initial_rev: %s\n' % initial_rev)
             for commit in commits:
Signature · 1 line
2.1.0
#2 lore raw

PATCH 2/8 devtool: modify: implement --no-same-dir

In reply to Paul Eggleton

From: Markus Lehtonen <[email protected]>

This option can be used to have a separate build directory, in order to keep the srctree directory clean for packages that do not need to be built in the source directory.

---
 scripts/lib/devtool/standard.py | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
scripts/lib/devtool/standard.py +7 -2
index fbac34e..aa30a98 100644
@@ -386,7 +386,10 @@ def modify(args, config, basepath, workspace):
         f.write('EXTERNALSRC_pn-%s = "%s"\n' % (args.recipename, srctree))
 
         b_is_s = True
-        if args.same_dir:
+        if args.no_same_dir:
+            logger.info('using separate build directory since --no-same-dir specified')
+            b_is_s = False
+        elif args.same_dir:
             logger.info('using source tree as build directory since --same-dir specified')
         elif bb.data.inherits_class('autotools-brokensep', rd):
             logger.info('using source tree as build directory since original recipe inherits autotools-brokensep')
@@ -664,7 +667,9 @@ def register_commands(subparsers, context):
     parser_modify.add_argument('srctree', help='Path to external source tree')
     parser_modify.add_argument('--wildcard', '-w', action="store_true", help='Use wildcard for unversioned bbappend')
     parser_modify.add_argument('--extract', '-x', action="store_true", help='Extract source as well')
-    parser_modify.add_argument('--same-dir', '-s', help='Build in same directory as source', action="store_true")
+    group = parser_modify.add_mutually_exclusive_group()
+    group.add_argument('--same-dir', '-s', help='Build in same directory as source', action="store_true")
+    group.add_argument('--no-same-dir', help='Force build in a separate build directory', action="store_true")
     parser_modify.add_argument('--branch', '-b', default="devtool", help='Name for development branch to checkout (only when using -x)')
     parser_modify.set_defaults(func=modify)
 
Signature · 1 line
2.1.0
#3 lore raw

PATCH 3/8 oe-selftest: devtool: fix update-recipe test after bd1aa28

In reply to Paul Eggleton

From: Markus Lehtonen <[email protected]>

Number of patches in mtd-utils changed in changeset bd1aa28.

---
 meta/lib/oeqa/selftest/devtool.py | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)
meta/lib/oeqa/selftest/devtool.py +9 -2
index dc1cf21..aa5bd76 100644
@@ -397,19 +397,26 @@ class DevtoolTests(oeSelfTest):
         result = runCmd('git status . --porcelain', cwd=os.path.dirname(recipefile))
         self.assertNotEqual(result.output.strip(), "", '%s recipe should be modified' % testrecipe)
         status = result.output.splitlines()
-        self.assertEqual(len(status), 3, 'Less/more files modified than expected. Entire status:\n%s' % result.output)
+        self.assertEqual(len(status), 4, 'Less/more files modified than expected. Entire status:\n%s' % result.output)
         for line in status:
             if line.endswith('add-exclusion-to-mkfs-jffs2-git-2.patch'):
                 self.assertEqual(line[:3], ' D ', 'Unexpected status in line: %s' % line)
             elif line.endswith('fix-armv7-neon-alignment.patch'):
                 self.assertEqual(line[:3], ' D ', 'Unexpected status in line: %s' % line)
+            elif line.endswith('-duplicate-hashtable_iterator_value-.patch'):
+                self.assertEqual(line[:3], ' D ', 'Unexpected status in line: %s' % line)
             elif re.search('%s_[^_]*.bb$' % testrecipe, line):
                 self.assertEqual(line[:3], ' M ', 'Unexpected status in line: %s' % line)
             else:
                 raise AssertionError('Unexpected modified file in status: %s' % line)
         result = runCmd('git diff %s' % os.path.basename(recipefile), cwd=os.path.dirname(recipefile))
         addlines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git"']
-        removelines = ['SRCREV = ".*"', 'SRC_URI = "git://git.infradead.org/mtd-utils.git \\\\', 'file://add-exclusion-to-mkfs-jffs2-git-2.patch \\\\', 'file://fix-armv7-neon-alignment.patch \\\\', '"']
+        removelines = ['SRCREV = ".*"',
+                       'SRC_URI = "git://git.infradead.org/mtd-utils.git \\\\',
+                       'file://add-exclusion-to-mkfs-jffs2-git-2.patch \\\\',
+                       'file://fix-armv7-neon-alignment.patch \\\\',
+                       'file://0001-hashtable-Remove-duplicate-hashtable_iterator_value-.patch \\\\',
+                       '"']
         for line in result.output.splitlines():
             if line.startswith('+++') or line.startswith('---'):
                 continue
Signature · 1 line
2.1.0
#4 lore raw

PATCH 4/8 devtool: extract: remove patches when S=WORKDIR

In reply to Paul Eggleton

From: Markus Lehtonen <[email protected]>

All local files from the layer, including patches, are added to to srctree repository when S==WORKDIR. The patch files are useless as they are automatically applied on top of the srctree by devtool.

This change causes devtool extract to not commit these unnecessary (and possibly confusing) patch file(s) into srctree repository.

[YOCTO #7602]

---
 scripts/lib/devtool/standard.py | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)
scripts/lib/devtool/standard.py +20 -0
index aa30a98..926ec6c 100644
@@ -153,6 +153,7 @@ def extract(args, config, basepath, workspace):
 
 def _extract_source(srctree, keep_temp, devbranch, d):
     import bb.event
+    import oe.recipeutils
 
     def eventfilter(name, handler, event, d):
         if name == 'base_eventhandler':
@@ -240,6 +241,13 @@ def _extract_source(srctree, keep_temp, devbranch, d):
             else:
                 os.rmdir(patchdir)
 
+        # Find local patches that were "unpacked" to srctree directory
+        recipe_patches = [os.path.basename(patch) for patch in
+                oe.recipeutils.get_recipe_patches(crd)]
+        patches = [fname for fname in os.listdir(workdir) if fname in
+                   recipe_patches]
+
+        # Set-up srctree repo
         if bb.data.inherits_class('kernel-yocto', d):
             (stdout, _) = bb.process.run('git --git-dir="%s" rev-parse HEAD' % crd.expand('${WORKDIR}/git'), cwd=srcsubdir)
             initial_rev = stdout.rstrip()
@@ -251,6 +259,10 @@ def _extract_source(srctree, keep_temp, devbranch, d):
             if not os.path.exists(os.path.join(srcsubdir, '.git')):
                 bb.process.run('git init', cwd=srcsubdir)
                 bb.process.run('git add .', cwd=srcsubdir)
+                # Do not commit patches (would happend if S=WORKDIR)
+                if patches and srcsubdir == workdir:
+                    bb.process.run('git reset -- %s' % " ".join(patches),
+                                    cwd=srcsubdir)
                 bb.process.run('git commit -q -m "Initial commit from upstream at version %s"' % crd.getVar('PV', True), cwd=srcsubdir)
 
             (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srcsubdir)
@@ -266,6 +278,14 @@ def _extract_source(srctree, keep_temp, devbranch, d):
 
         bb.process.run('git tag -f devtool-patched', cwd=srcsubdir)
 
+        # Remove patches if S=WORKDIR so that stale patch files are not present
+        # in the srtree
+        if patches and srcsubdir == workdir:
+            logger.info('Removing patch files...')
+            for patch in patches:
+                os.unlink(os.path.join(workdir, patch))
+
+
         if os.path.exists(patchdir):
             shutil.rmtree(patchdir)
             if haspatches:
Signature · 1 line
2.1.0
#5 lore raw

Re: [PATCH 4/8] devtool: extract: remove patches when S=WORKDIR

Hi,

Quoted 66 lines · Paul Eggleton

From: Markus Lehtonen <[email protected]>

All local files from the layer, including patches, are added to to srctree repository when S==WORKDIR. The patch files are useless as they are automatically applied on top of the srctree by devtool.

This change causes devtool extract to not commit these unnecessary (and possibly confusing) patch file(s) into srctree repository.

[YOCTO #7602]

---
scripts/lib/devtool/standard.py | 20 ++++++++++++++++++++

1 file changed, 20 insertions(+)
scripts/lib/devtool/standard.py +0 -0
index aa30a98..926ec6c 100644
@@ -153,6 +153,7 @@ def extract(args, config, basepath, workspace):
 

def _extract_source(srctree, keep_temp, devbranch, d):
import bb.event

scripts/lib/devtool/standard.py +1 -0
+    import oe.recipeutils
 
    def eventfilter(name, handler, event, d):
        if name == 'base_eventhandler':
@@ -240,6 +241,13 @@ def _extract_source(srctree, keep_temp, devbranch,

d):
else:
os.rmdir(patchdir)

scripts/lib/devtool/standard.py +7 -0
+        # Find local patches that were "unpacked" to srctree directory
+        recipe_patches = [os.path.basename(patch) for patch in
+                oe.recipeutils.get_recipe_patches(crd)]
+        patches = [fname for fname in os.listdir(workdir) if fname in
+                   recipe_patches]
+
+        # Set-up srctree repo
        if bb.data.inherits_class('kernel-yocto', d):
            (stdout, _) = bb.process.run('git --git-dir="%s" rev-parse

HEAD' % crd.expand('${WORKDIR}/git'), cwd=srcsubdir)
initial_rev = stdout.rstrip()

scripts/lib/devtool/standard.py +0 -0
@@ -251,6 +259,10 @@ def _extract_source(srctree, keep_temp, devbranch,

d):
if not os.path.exists(os.path.join(srcsubdir, '.git')):
bb.process.run('git init', cwd=srcsubdir) bb.process.run('git add .', cwd=srcsubdir)

scripts/lib/devtool/standard.py +4 -0
+                # Do not commit patches (would happend if S=WORKDIR)
+                if patches and srcsubdir == workdir:
+                    bb.process.run('git reset -- %s' % " ".join(patches),
+                                    cwd=srcsubdir)
                bb.process.run('git commit -q -m "Initial commit from

upstream at version %s"' % crd.getVar('PV', True), cwd=srcsubdir)

(stdout, _) = bb.process.run('git rev-parse HEAD',
cwd=srcsubdir)

scripts/lib/devtool/standard.py +0 -0
@@ -266,6 +278,14 @@ def _extract_source(srctree, keep_temp, devbranch,

d):

bb.process.run('git tag -f devtool-patched', cwd=srcsubdir)

+ # Remove patches if S=WORKDIR so that stale patch files are not
present

scripts/lib/devtool/standard.py def _extract_source(srctree, keep_temp, devbranch, d): · line 291

Quoted 10 lines
scripts/lib/devtool/standard.py +7 -0
+        # in the srtree
+        if patches and srcsubdir == workdir:
+            logger.info('Removing patch files...')
+            for patch in patches:
+                os.unlink(os.path.join(workdir, patch))
+
+
        if os.path.exists(patchdir):
            shutil.rmtree(patchdir)
            if haspatches:

NACK! Please skip this patch for now. I just found out it doesn't work as expected. I'll submit a new version when I've worked around the problems.

Thanks,
Markus

#6 lore raw

Re: [PATCH 4/8] devtool: extract: remove patches when S=WORKDIR

Quoted 2 lines · On Friday 24 April 2015 11:38:45 Markus Lehtonen wrote:

NACK! Please skip this patch for now. I just found out it doesn't work as expected. I'll submit a new version when I've worked around the problems.

OK, I've re-pushed the branch with this patch removed.

Cheers,
Paul

Signature · 2 lines
Paul Eggleton
Intel Open Source Technology Centre
#7 lore raw

PATCH 5/8 devtool: include bbappends in recipe parsing

In reply to Paul Eggleton

From: Markus Lehtonen <[email protected]>

In order to get correct metadata, SRCREV for example.

Fixes [YOCTO #7648].

---
 meta/lib/oe/recipeutils.py      |  6 +++---
 scripts/lib/devtool/standard.py | 35 ++++++++++++++++++++++-------------
 2 files changed, 25 insertions(+), 16 deletions(-)
meta/lib/oe/recipeutils.py +3 -3
index 159a103..09bd7fd 100644
@@ -44,10 +44,10 @@ def get_unavailable_reasons(cooker, pn):
     return taskdata.get_reasons(pn)
 
 
-def parse_recipe(fn, d):
+def parse_recipe(fn, appends, d):
     """Parse an individual recipe"""
     import bb.cache
-    envdata = bb.cache.Cache.loadDataFull(fn, [], d)
+    envdata = bb.cache.Cache.loadDataFull(fn, appends, d)
     return envdata
 
 
@@ -55,7 +55,7 @@ def get_var_files(fn, varlist, d):
     """Find the file in which each of a list of variables is set.
     Note: requires variable history to be enabled when parsing.
     """
-    envdata = parse_recipe(fn, d)
+    envdata = parse_recipe(fn, [], d)
     varfiles = {}
     for v in varlist:
         history = envdata.varhistory.variable(v)
scripts/lib/devtool/standard.py +22 -13
index 926ec6c..9abdbd4 100644
@@ -130,18 +130,29 @@ def _get_recipe_file(cooker, pn):
             logger.error("Unable to find any recipe file matching %s" % pn)
     return recipefile
 
+def _parse_recipe(config, tinfoil, pn, appends):
+    """Parse recipe of a package"""
+    import oe.recipeutils
+    recipefile = _get_recipe_file(tinfoil.cooker, pn)
+    if not recipefile:
+        # Error already logged
+        return None
+    if appends:
+        append_files = tinfoil.cooker.collection.get_file_appends(recipefile)
+        # Filter out appends from the workspace
+        append_files = [path for path in append_files if
+                        not path.startswith(config.workspace_path)]
+    return oe.recipeutils.parse_recipe(recipefile, append_files,
+                                       tinfoil.config_data)
 
 def extract(args, config, basepath, workspace):
     import bb
-    import oe.recipeutils
 
     tinfoil = setup_tinfoil()
 
-    recipefile = _get_recipe_file(tinfoil.cooker, args.recipename)
-    if not recipefile:
-        # Error already logged
+    rd = _parse_recipe(config, tinfoil, args.recipename, True)
+    if not rd:
         return -1
-    rd = oe.recipeutils.parse_recipe(recipefile, tinfoil.config_data)
 
     srctree = os.path.abspath(args.srctree)
     initial_rev = _extract_source(srctree, args.keep_temp, args.branch, rd)
@@ -347,11 +358,10 @@ def modify(args, config, basepath, workspace):
 
     tinfoil = setup_tinfoil()
 
-    recipefile = _get_recipe_file(tinfoil.cooker, args.recipename)
-    if not recipefile:
-        # Error already logged
+    rd = _parse_recipe(config, tinfoil, args.recipename, True)
+    if not rd:
         return -1
-    rd = oe.recipeutils.parse_recipe(recipefile, tinfoil.config_data)
+    recipefile = rd.getVar('FILE', True)
 
     if not _check_compatible_recipe(args.recipename, rd):
         return -1
@@ -448,11 +458,10 @@ def update_recipe(args, config, basepath, workspace):
     from oe.patch import GitApplyTree
     import oe.recipeutils
 
-    recipefile = _get_recipe_file(tinfoil.cooker, args.recipename)
-    if not recipefile:
-        # Error already logged
+    rd = _parse_recipe(config, tinfoil, args.recipename, True)
+    if not rd:
         return -1
-    rd = oe.recipeutils.parse_recipe(recipefile, tinfoil.config_data)
+    recipefile = rd.getVar('FILE', True)
 
     orig_src_uri = rd.getVar('SRC_URI', False) or ''
     if args.mode == 'auto':
Signature · 1 line
2.1.0
#8 lore raw

PATCH 6/8 devtool: handle . in recipe name

In reply to Paul Eggleton

Names such as glib-2.0 are valid (and used) recipe names, so we need to support them.

Fixes [YOCTO #7643].

---
 meta/lib/oe/recipeutils.py | 4 ++--
 scripts/devtool            | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
meta/lib/oe/recipeutils.py +2 -2
index 09bd7fd..19d97b6 100644
@@ -269,8 +269,8 @@ def get_recipe_patches(d):
 def validate_pn(pn):
     """Perform validation on a recipe name (PN) for a new recipe."""
     reserved_names = ['forcevariable', 'append', 'prepend', 'remove']
-    if not re.match('[0-9a-z-]+', pn):
-        return 'Recipe name "%s" is invalid: only characters 0-9, a-z and - are allowed' % pn
+    if not re.match('[0-9a-z-.]+', pn):
+        return 'Recipe name "%s" is invalid: only characters 0-9, a-z, - and . are allowed' % pn
     elif pn in reserved_names:
         return 'Recipe name "%s" is invalid: is a reserved keyword' % pn
     elif pn.startswith('pn-'):
scripts/devtool +1 -1
index 981ff51..841831c 100755
@@ -101,7 +101,7 @@ def read_workspace():
             _create_workspace(config.workspace_path, config, basepath)
 
     logger.debug('Reading workspace in %s' % config.workspace_path)
-    externalsrc_re = re.compile(r'^EXTERNALSRC(_pn-[a-zA-Z0-9-]*)? =.*$')
+    externalsrc_re = re.compile(r'^EXTERNALSRC(_pn-[^ =]+)? =.*$')
     for fn in glob.glob(os.path.join(config.workspace_path, 'appends', '*.bbappend')):
         pn = os.path.splitext(os.path.basename(fn))[0].split('_')[0]
         with open(fn, 'r') as f:
Signature · 1 line
2.1.0
#9 lore raw

PATCH 7/8 devtool: add: use correct bbappend file name with -V option

In reply to Paul Eggleton

We weren't adding the version into the bbappend file name which meant that building or resetting failed.

Also adjust one of the tests so that we're testing devtool add both with and without this option.

Fixes [YOCTO #7647].

---
 meta/lib/oeqa/selftest/devtool.py | 4 ++--
 scripts/lib/devtool/standard.py   | 2 +-
 2 files changed, 3 insertions(+), 3 deletions(-)
meta/lib/oeqa/selftest/devtool.py +2 -2
index aa5bd76..91d4c39 100644
@@ -150,10 +150,10 @@ class DevtoolTests(oeSelfTest):
         result = runCmd('tar xfv libftdi1-1.1.tar.bz2', cwd=tempdir)
         srcdir = os.path.join(tempdir, 'libftdi1-1.1')
         self.assertTrue(os.path.isfile(os.path.join(srcdir, 'CMakeLists.txt')), 'Unable to find CMakeLists.txt in source directory')
-        # Test devtool add
+        # Test devtool add (and use -V so we test that too)
         self.track_for_cleanup(workspacedir)
         self.add_command_to_tearDown('bitbake-layers remove-layer */workspace')
-        result = runCmd('devtool add libftdi %s' % srcdir)
+        result = runCmd('devtool add libftdi %s -V 1.1' % srcdir)
         self.assertTrue(os.path.exists(os.path.join(workspacedir, 'conf', 'layer.conf')), 'Workspace directory not created')
         # Test devtool status
         result = runCmd('devtool status')
scripts/lib/devtool/standard.py +1 -1
index 9abdbd4..8fa9e6f 100644
@@ -73,7 +73,7 @@ def add(args, config, basepath, workspace):
         (stdout, _) = bb.process.run('git rev-parse HEAD', cwd=srctree)
         initial_rev = stdout.rstrip()
 
-    appendfile = os.path.join(appendpath, '%s.bbappend' % args.recipename)
+    appendfile = os.path.join(appendpath, '%s.bbappend' % bp)
     with open(appendfile, 'w') as f:
         f.write('inherit externalsrc\n')
         f.write('EXTERNALSRC = "%s"\n' % srctree)
Signature · 1 line
2.1.0
#10 lore raw

PATCH 8/8 devtool: reset: avoid errors in case file no longer exists

In reply to Paul Eggleton

If you manually delete files in the workspace layer (which you really shouldn't) it was possible to get yourself into the situation where you couldn't reset because we were attempting to check if the file had been modified and erroring out if it couldn't be opened. If the file's not there anymore there's not much point checking if it needs to be preserved, just skip it.

---
 scripts/lib/devtool/standard.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
scripts/lib/devtool/standard.py +8 -1
index 8fa9e6f..9d13db5 100644
@@ -328,7 +328,14 @@ def _check_preserve(config, recipename):
                 splitline = line.rstrip().split('|')
                 if splitline[0] == recipename:
                     removefile = os.path.join(config.workspace_path, splitline[1])
-                    md5 = bb.utils.md5_file(removefile)
+                    try:
+                        md5 = bb.utils.md5_file(removefile)
+                    except IOError as err:
+                        if err.errno == 2:
+                            # File no longer exists, skip it
+                            continue
+                        else:
+                            raise
                     if splitline[2] != md5:
                         bb.utils.mkdirhier(preservepath)
                         preservefile = os.path.basename(removefile)
Signature · 1 line
2.1.0