Skip to contentSkip to conversation

bitbake-layers: add a ability to query layer dependencies from layer index

PATCH In review Chong Lu 3 participants 5 messages Feb 12, 2015 – Feb 13, 2015

lore
Share & tools
lore

Chong Lu

author
#0 lore raw

v5 cover bitbake-layers: add a ability to query layer dependencies from layer index

Change since V4:
Change commit log for two variables.

The following changes since commit 35c9fa0588ed8e88b541a6c80cc1517324616cea:

maintainers: Update for non-maintained recipes (2015-01-20 21:39:41 +0000)

are available in the git repository at:

git://git.pokylinux.org/poky-contrib chonglu/layerindex
http://git.pokylinux.org/cgit.cgi/poky-contrib/log/?h=chonglu/layerindex

Chong Lu (2):
bitbake.conf: Add two variables for layer index
bitbake-layers: add a ability to query layer dependencies from layer index

 bitbake/bin/bitbake-layers | 244 +++++++++++++++++++++++++++++++++++++++++++++
 meta/conf/bitbake.conf     |   6 ++
 2 files changed, 250 insertions(+)
Signature · 1 line
1.9.1
author
#1 lore raw

PATCH v5 1/2 bitbake.conf: Add two variables for layer index

Add BBLAYERS_LAYERINDEX_URL variable that bitbake-layers can use to find layer index. Add BBLAYERS_FETCH_DIR variable that bitbake-layers can use to specify fetch directory.

[YOCTO #5348]

---
 meta/conf/bitbake.conf | 6 ++++++
 1 file changed, 6 insertions(+)
meta/conf/bitbake.conf +6 -0
index d22e9e8..a1c6b70 100644
@@ -549,6 +549,12 @@ SELECTED_OPTIMIZATION[vardeps] += "FULL_OPTIMIZATION DEBUG_OPTIMIZATION"
 BUILD_OPTIMIZATION = "-O2 -pipe"
 
 ##################################################################
+# Settings used by bitbake-layers.
+##################################################################
+BBLAYERS_LAYERINDEX_URL ??= "http://layers.openembedded.org/layerindex/"
+BBLAYERS_FETCH_DIR ??= "${COREBASE}"
+
+##################################################################
 # Download locations and utilities.
 ##################################################################
 
Signature · 1 line
1.9.1
author
#2 lore raw

PATCH v5 2/2 bitbake-layers: add a ability to query layer dependencies from layer index

In reply to Chong Lu

Add a command to query layer dependencies from layer index. Fetch layer and its dependency layers and add them into conf/bblayers.conf.

[YOCTO #5348]

---
 bitbake/bin/bitbake-layers | 244 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 244 insertions(+)
bitbake/bin/bitbake-layers +244 -0
index 9879498..699424f 100755
@@ -27,6 +27,8 @@ import sys
 import fnmatch
 from collections import defaultdict
 import re
+import httplib, urlparse, json
+import subprocess
 
 bindir = os.path.dirname(__file__)
 topdir = os.path.dirname(bindir)
@@ -157,6 +159,248 @@ usage: remove-layer <layerdir>
                 sys.stderr.write("No layers matching %s found in BBLAYERS\n" % item)
 
 
+    def get_json_data(self, apiurl):
+        proxy_settings = os.environ.get("http_proxy", None)
+        conn = None
+        _parsedurl = urlparse.urlparse(apiurl)
+        path = _parsedurl.path
+        query = _parsedurl.query
+        def parse_url(url):
+            parsedurl = urlparse.urlparse(url)
+            if parsedurl.netloc[0] == '[':
+                host, port = parsedurl.netloc[1:].split(']', 1)
+                if ':' in port:
+                    port = port.rsplit(':', 1)[1]
+                else:
+                    port = None
+            else:
+                if parsedurl.netloc.count(':') == 1:
+                    (host, port) = parsedurl.netloc.split(":")
+                else:
+                    host = parsedurl.netloc
+                    port = None
+            return (host, 80 if port is None else int(port))
+
+        if proxy_settings is None:
+            host, port = parse_url(apiurl)
+            conn = httplib.HTTPConnection(host, port)
+            conn.request("GET", path + "?" + query)
+        else:
+            host, port = parse_url(proxy_settings)
+            conn = httplib.HTTPConnection(host, port)
+            conn.request("GET", apiurl)
+
+        r = conn.getresponse()
+        if r.status != 200:
+            raise Exception("Failed to read " + path + ": %d %s" % (r.status, r.reason))
+        return json.loads(r.read())
+
+
+    def get_layer_deps(self, layername, layeritems, layerbranches, layerdependencies, branchnum, selfname=False):
+        def layeritems_info_id(items_name, layeritems):
+            litems_id = ""
+            for li in layeritems:
+                if li['name'] == items_name:
+                    litems_id = li['id']
+                    break
+            if litems_id:
+                return litems_id
+
+        def layerbranches_info(items_id, layerbranches):
+            lbranch = {}
+            for lb in layerbranches:
+                if lb['layer'] == items_id and lb['branch'] == branchnum:
+                    lbranch['id'] = lb['id']
+                    lbranch['vcs_subdir'] = lb['vcs_subdir']
+                    break
+            return lbranch
+
+        def layerdependencies_info(lb_id, layerdependencies):
+            ld_deps = []
+            for ld in layerdependencies:
+                if ld['layerbranch'] == lb_id and not ld['dependency'] in ld_deps:
+                    ld_deps.append(ld['dependency'])
+            if not ld_deps:
+                logger.error("The dependency of layerDependencies is not found.")
+                return
+            else:
+                return ld_deps
+
+        def layeritems_info_name_subdir(items_id, layeritems):
+            litems = {}
+            for li in layeritems:
+                if li['id'] == items_id:
+                    litems['vcs_url'] = li['vcs_url']
+                    litems['name'] = li['name']
+                    break
+            return litems
+
+        if selfname:
+            selfid = layeritems_info_id(layername, layeritems)
+            selfsubdir = layerbranches_info(selfid, layerbranches)
+            if selfsubdir:
+                selfsubdir = layerbranches_info(selfid, layerbranches)['vcs_subdir']
+            else:
+                logger.error("%s layer is not found in your specify branch." % layername)
+                return
+            selfurl = layeritems_info_name_subdir(selfid, layeritems)['vcs_url']
+            if selfurl:
+                return selfurl, selfsubdir
+            else:
+                logger.error("Can NOT get %s git repo and subdir" % layername)
+                return
+        ldict = {}
+        itemsid = layeritems_info_id(layername, layeritems)
+        if not itemsid:
+            return layername, None
+        lbid = layerbranches_info(itemsid, layerbranches)
+        if lbid:
+            lbid = layerbranches_info(itemsid, layerbranches)['id']
+        else:
+            logger.error("%s is not found in your specify branch." % layername)
+            return None, None
+        for dependency in layerdependencies_info(lbid, layerdependencies):
+            lname = layeritems_info_name_subdir(dependency, layeritems)['name']
+            lurl = layeritems_info_name_subdir(dependency, layeritems)['vcs_url']
+            lsubdir = layerbranches_info(dependency, layerbranches)['vcs_subdir']
+            ldict[lname] = lurl, lsubdir
+        return None, ldict
+
+
+    def get_fetch_layer(self, fetchdir, url, subdir, fetch_layer):
+        layername = self.get_layer_name(url)
+        if os.path.splitext(layername)[1] == '.git':
+            layername = os.path.splitext(layername)[0]
+        repodir = os.path.join(fetchdir, layername)
+        layerdir = os.path.join(repodir, subdir)
+        if not os.path.exists(repodir):
+            if fetch_layer:
+                result = subprocess.call('git clone %s %s' % (url, repodir), shell = True)
+                if result:
+                    logger.error("Failed to download %s" % url)
+                else:
+                    return layername, layerdir
+            else:
+                logger.plain('We need fetch %s layer, please add -f option.' % layername)
+                return layername, layerdir
+        elif os.path.exists(layerdir):
+            return layername, layerdir
+        else:
+            logger.error("%s is not in %s" % (url, subdir))
+
+
+    def do_show_layer_deps(self, args):
+        """Find layer dependencies from layer index. Fetch it and its dependency layers. Add them to conf/bblayers.conf.
+
+usage: show-layer-deps [-a] [-f] [-b[branch name]] <layername,...>
+
+Options:
+  -a   add layer to conf/bblayers.conf
+  -b   specify layer branch, such as master, dylan, danny, oe-classic, dora, daisy or dizzy. Default branch is master.
+  -f   fetch layer from git repository
+"""
+        add_layer = False
+        fetch_layer = False
+        layernames = ""
+        branchname = "master"
+        for arg in args.split():
+            if arg == '-a':
+                add_layer = True
+            elif arg == '-f':
+                fetch_layer = True
+            elif arg.startswith('-b'):
+                branchname = arg[2:]
+            elif not arg.startswith('-'):
+                layernames = arg
+            else:
+                sys.stderr.write("show-layer-deps: invalid option %s\n" % arg)
+                self.do_help('')
+                return
+        if branchname == "master":
+            branchnum = 1
+        elif branchname == "dylan":
+            branchnum = 2
+        elif branchname == "danny":
+            branchnum = 3
+        elif branchname == "oe-classic":
+            branchnum = 4
+        elif branchname == "dora":
+            branchnum = 5
+        elif branchname == "daisy":
+            branchnum = 6
+        elif branchname == "dizzy":
+            branchnum = 7
+        else:
+            sys.stderr.write("Invalid layer branch name: %s\n" % branchname)
+            return
+        if not layernames:
+            sys.stderr.write("Please specify layer name.\n")
+            return
+        self.init_bbhandler(config_only = True)
+        apiurl = self.bbhandler.config_data.getVar('BBLAYERS_LAYERINDEX_URL', True)
+        if not apiurl:
+            logger.error("Can NOT get BBLAYERS_LAYERINDEX_URL.")
+        else:
+            apiurl = apiurl + "api/"
+        apilinks = self.get_json_data(apiurl)
+        layeritems = self.get_json_data(apilinks['layerItems'])
+        layerbranches = self.get_json_data(apilinks['layerBranches'])
+        layerdependencies = self.get_json_data(apilinks['layerDependencies'])
+        invaluenames = []
+        repourls = []
+        printlayers = []
+        def query_dependencies(layernames, layeritems, layerbranches, layerdependencies, branchnum, invaluenames, repourls, printlayers):
+            depslayer = []
+            for layername in layernames.split(','):
+                if not layername == "meta":
+                    invaluename, layerdict = self.get_layer_deps(layername, layeritems, layerbranches, layerdependencies, branchnum)
+                    if layerdict:
+                        repourls.append(self.get_layer_deps(layername, layeritems, layerbranches, layerdependencies, branchnum, selfname=True))
+                        for layer in layerdict:
+                            if not layer == "openembedded-core":
+                                depslayer.append(layer)
+                            printlayers.append((layername, layer, layerdict[layer][0], layerdict[layer][1]))
+                            if not layer == "openembedded-core" and not (layerdict[layer][0], layerdict[layer][1]) in repourls:
+                                repourls.append((layerdict[layer][0], layerdict[layer][1]))
+                    if invaluename and not invaluename in invaluenames:
+                        invaluenames.append(invaluename)
+            return repourls, depslayer, invaluenames, printlayers
+
+        repourls, depslayers, invaluenames, printlayers = query_dependencies(layernames, layeritems, layerbranches, layerdependencies, branchnum, invaluenames, repourls, printlayers)
+        while depslayers:
+            repourls, depslayer, invaluenames, printlayers = query_dependencies(','.join(depslayers), layeritems, layerbranches, layerdependencies, branchnum, invaluenames, repourls, printlayers)
+            depslayers = depslayer
+        for invaluename in invaluenames:
+            logger.warn("%s is not found in layer index." % invaluename)
+        if printlayers:
+            logger.plain("%s  %s  %s  %s" % ("Layer".ljust(19), "Dependencies".ljust(19), "Git repository".ljust(54), "Subdirectory"))
+            logger.plain('=' * 115)
+        for layer, dependencies, gitrepo, subdirectory in set(printlayers):
+            logger.plain("%s %s %s %s" % (layer.ljust(20), dependencies.ljust(20), gitrepo.ljust(55), subdirectory))
+
+        if set(repourls):
+            fetchdir = self.bbhandler.config_data.getVar('BBLAYERS_FETCH_DIR', True)
+            if not fetchdir:
+                logger.error("Can NOT get BBLAYERS_FETCH_DIR.")
+                return
+            if not os.path.exists(fetchdir):
+                os.makedirs(fetchdir)
+            addlayers = []
+            for repourl, subdir in repourls:
+                name, layerdir = self.get_fetch_layer(fetchdir, repourl, subdir, fetch_layer)
+                addlayers.append((subdir, name, layerdir))
+        if add_layer:
+            for subdir, name, layerdir in set(addlayers):
+                if os.path.exists(layerdir):
+                    if subdir:
+                        logger.plain("Add \"%s\" to conf/bblayers.conf" % subdir)
+                    else:
+                        logger.plain("Add \"%s\" to conf/bblayers.conf" % name)
+                    self.do_add_layer(layerdir)
+                else:
+                    break
+
+
     def version_str(self, pe, pv, pr = None):
         verstr = "%s" % pv
         if pr:
Signature · 1 line
1.9.1
#3 lore raw
In reply to Chong Lu
Quoted 7 lines · On Thursday 12 February 2015 09:50:21 Chong Lu wrote:

Change since V4:
Change commit log for two variables.

The following changes since commit 35c9fa0588ed8e88b541a6c80cc1517324616cea:

maintainers: Update for non-maintained recipes (2015-01-20 21:39:41 +0000)

Quoted 8 lines

are available in the git repository at:

git://git.pokylinux.org/poky-contrib chonglu/layerindex
http://git.pokylinux.org/cgit.cgi/poky-contrib/log/?h=chonglu/layerindex

Chong Lu (2):
bitbake.conf: Add two variables for layer index
bitbake-layers: add a ability to query layer dependencies from layer index

Thanks for fixing nearly all of the issues from v3 - I've tested it and it works pretty well. However, there is one that is still not addressed:

Quoted 4 lines
Quoted 4 lines

* I think the new subcommand would make more sense if it were switched around so that it was fetching by default (and renamed as appropriate). Perhaps "layerindex-fetch" (with -n to avoid fetching and just report what it would fetch).

FWIW I'm happy if we still have a "layerindex-show-deps" that is just an alias for "layerindex-fetch -n", so it's really about the naming.

Additionally I'd really rather we did not hardcode the branch names - there's an API call available to get these in the layer index and we should use it. I also think we could improve the formatting of the output to make it a bit easier for the user to understand.

I know you'll be out of office for the next few weeks - perhaps I could address these issues while you're out and send a new series if you have no objections.

Cheers,
Paul

Signature · 2 lines
Paul Eggleton
Intel Open Source Technology Centre
#4 lore raw
Quoted 28 lines · Paul Eggleton
Quoted 7 lines · On Thursday 12 February 2015 09:50:21 Chong Lu wrote:

Change since V4:
Change commit log for two variables.

The following changes since commit 35c9fa0588ed8e88b541a6c80cc1517324616cea:

   maintainers: Update for non-maintained recipes (2015-01-20 21:39:41 +0000)
Quoted 8 lines

are available in the git repository at:

git://git.pokylinux.org/poky-contrib chonglu/layerindex
http://git.pokylinux.org/cgit.cgi/poky-contrib/log/?h=chonglu/layerindex

Chong Lu (2):
bitbake.conf: Add two variables for layer index
bitbake-layers: add a ability to query layer dependencies from layer index

Thanks for fixing nearly all of the issues from v3 - I've tested it and it works pretty well. However, there is one that is still not addressed:

Quoted 4 lines
Quoted 4 lines

* I think the new subcommand would make more sense if it were switched around so that it was fetching by default (and renamed as appropriate). Perhaps "layerindex-fetch" (with -n to avoid fetching and just report what it would fetch).

FWIW I'm happy if we still have a "layerindex-show-deps" that is just an alias for "layerindex-fetch -n", so it's really about the naming.

Quoted 7 lines

Additionally I'd really rather we did not hardcode the branch names - there's an API call available to get these in the layer index and we should use it. I also think we could improve the formatting of the output to make it a bit easier for the user to understand.

I know you'll be out of office for the next few weeks - perhaps I could address these issues while you're out and send a new series if you have no objections.

Thank you very much, I had talked with Chong today, he would be very happy if you can send the new series:-)

// Robert

Quoted 4 lines

Cheers,
Paul