[Buildroot] [PATCH 00/10] infra: add solution to dump metadata from packages (branch yem/misc)

Thomas De Schampheleire patrickdepinguin at gmail.com
Wed Apr 10 12:47:45 UTC 2019


Hi Yann,

El dom., 7 abr. 2019 a las 13:51, Yann E. MORIN
(<yann.morin.1998 at free.fr>) escribió:
>
> Hello All!
>
> This series is a proposal to allow extracting metadata about packages,
> in a way that makes it reusable for tooling outside of Buildroot, that
> is both reliable and extendable, without causing too much burden on
> Buildroot own infrastructure.
>
> This series introduces a global 'show-info' rule, and a per package and
> per filesystem 'show-info' rule, that dump the pacakge metadata as a
> JSON blob. JSON is a key-value based serialisation format. As such, it
> is easy to parse (there are implementations in virtually all languages,
> and there are even tools like jq, that can be used from shell scripts).
> But most importantly, it is easy to extend without breakign existing
> tools (as long as they use proper JSON parsers, that is).
>
> This series first introduces 4 cleanup preparatory patches in the
> download infra, so that it gets easy to get the list of URIs to report
> them. Strictly speaking, only patches 1 and 2 are required for this
> series, but the cleanup was extended to the infra with patches 3 and 4,
> for consistency.
>
> Then, the series introduces a per package and per filesystem show-info
> rule, as well as a recursive variant. The per filesystem rule is needed
> to be able to get the info about packages that are a dependency of
> filesystems.
>
> Finally, a global show-info rule is introduced that generates a JSON
> array with all the information about a build.
>
> In the end, the output for a packages would look like (beautified manually
> for ease of reading):
>
>     $ make cracklib-show-info
>     {
>       "name": "cracklib",
>       "type": "target",
>       "virtual": false,
>       "version": "2.9.7",
>       "licenses": "LGPL-2.1",
>       "downloads": [
>         {
>           "source": "cracklib-2.9.7.tar.gz",
>           "URIs": [
>             "https+https://github.com/cracklib/cracklib/releases/download/v2.9.7",
>             "http|urlencode+http://sources.buildroot.net/cracklib",
>             "http|urlencode+http://sources.buildroot.net"
>           ]
>         },
>         {
>           "source": "cracklib-words-2.9.7.gz",
>           "URIs": [
>             "https://github.com/cracklib/cracklib/releases/download/v2.9.7",
>             "http|urlencode+http://sources.buildroot.net/cracklib",
>             "http|urlencode+http://sources.buildroot.net"
>           ]
>         },
>         null
>       ],
>       "depends on": [
>         "host-cracklib",
>         "host-skeleton",
>         "skeleton",
>         "toolchain"
>       ],
>       "dependency of": [
>         "libpwquality",
>         "linux-pam"
>       ]
>     }
>
> While the whole show-info would look like (elipsed for readbility):
>
>     $ make show-info
>     [
>     { "name": "host-gcc-final", "type": "host", "virtual": false, ... },
>     { "name": "host-binutils", "type": "host", "virtual": false, ... },
>     { "name": "toolchain-buildroot", "type": "target", ... },
>     { "name": "gettext-tiny", "type": "target", "virtual": false, ... },
>     { "name": "gettext", "type": "target", "virtual": true, ... },
>     { "name": "ifupdown-scripts", "type": "target", "virtual": false, ... },
>     ...
>     { "name": "rootfs-common", "type": "rootfs", ... },
>     { "name": "rootfs-tar", "type": "rootfs", ... }
>     ]
>


Thanks for this series.
I gave some comments on the individual patches.

I cooked together a script to implement 'source-check' externally,
based on this show-info output.
It all works fine, all info needed is there.
I first process the show-info output into something like:

<name> <version> <filename> <uri1> <uri2> ...

using following jq query:

make show-info | jq -r '.[] | .["name"] as $pkg | .["version"] as
$version | .["downloads"][]? | $pkg + " " + $version + " " +
.["source"] + " " + (.["URIs"]? | select(. != null) | join(" "))'

And then I parse each resulting line, checking that for each package
at least one of the URIs that match my primary site / hg server work
fine.

For reference, below is the script as it is now (can probably still be
improved, the purpose was mainly to check if everything I need is
there, as feedback to your series):

#!/usr/bin/env python3

import os
import subprocess
import sys

LOCAL_MIRROR = 'my.local.mirror.example.com'

def sourcecheck_scp(pkg, version, filename, uri):
    real_uri = uri.split('+', 1)[1] + '/' + filename
    if real_uri.startswith('scp://'):
        real_uri = real_uri[6:]
    domain, path = real_uri.split(':', 1)
    with open(os.devnull, 'w') as devnull:
        ret = subprocess.call(['ssh', domain, 'test', '-f', path],
stderr=devnull)
    return ret == 0

def sourcecheck_hg(pkg, version, filename, uri):
    real_uri = uri.split('+', 1)[1]
    with open(os.devnull, 'w') as devnull:
        ret = subprocess.call(['hg', 'identify', '--rev', version,
real_uri], stdout=devnull, stderr=devnull)
    return ret == 0

def sourcecheck(pkg, version, filename, uri):
    if uri.startswith('scp'):
        handler = sourcecheck_scp
    elif uri.startswith('hg'):
        handler = sourcecheck_hg
    else:
        raise Exception("Cannot handle unknown URI type: '%s' for
package '%s'" % (uri, pkg))

    return handler(pkg, version, filename, uri)

def main():
    p1 = subprocess.Popen(['make', 'show-info'], stdout=subprocess.PIPE)
    p2 = subprocess.Popen(['jq', '-r', '.[] | .["name"] as $pkg |
.["version"] as $version | .["downloads"][]? | $pkg + " " + $version +
" " + .["source"] + " " + (.["URIs"]? | select(. != null) | join("
"))'],
            stdin=p1.stdout, stdout=subprocess.PIPE)
    p1.stdout.close()  # Allow p1 to receive a SIGPIPE if p2 exits.
    pkginfo = p2.communicate()[0].decode('utf-8')
    result = {}

    for line in pkginfo.splitlines():
        pkg, version, filename, *uris = line.split()

        success = any(sourcecheck(pkg, version, filename, uri) for uri
in uris if LOCAL_MIRROR in uri)
        result[pkg] = success

    print('Failed packages: ', [pkg for pkg in result if not result[pkg]])
    return all(result.values())

if __name__ == '__main__':
    ret = main()
    if not ret:
        sys.exit(1)


Best regards,
Thomas


More information about the buildroot mailing list