linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Julia Lawall <julia.lawall@lip6.fr>
To: "Luis R. Rodriguez" <mcgrof@kernel.org>
Cc: Julia.Lawall@lip6.fr, Gilles.Muller@lip6.fr,
	nicolas.palix@imag.fr, mmarek@suse.com,
	linux-kernel@vger.kernel.org, cocci@systeme.lip6.fr
Subject: Re: [PATCH 2/4] scripts: add reqs python library
Date: Wed, 15 Jun 2016 08:06:33 +0200 (CEST)	[thread overview]
Message-ID: <alpine.DEB.2.02.1606150806190.2231@localhost6.localdomain6> (raw)
In-Reply-To: <1465942217-14452-3-git-send-email-mcgrof@kernel.org>



On Tue, 14 Jun 2016, Luis R. Rodriguez wrote:

> This library can be used in other python scripts to require
> specific binary version requirements. It will be used first
> with coccinelle's python bindings to enable coccinelle SmPL
> files to specify version requirements per cocci file if it
> has any.
> 
> Signed-off-by: Luis R. Rodriguez <mcgrof@kernel.org>
> ---
>  MAINTAINERS             |   1 +
>  scripts/lib/__init__.py |   1 +
>  scripts/lib/reqs.py     | 211 ++++++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 213 insertions(+)
>  create mode 100644 scripts/lib/__init__.py
>  create mode 100644 scripts/lib/reqs.py
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index f83e19a2dd97..fdebbb513c1b 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -6521,6 +6521,7 @@ F:	scripts/Makefile.*
>  F:	scripts/basic/
>  F:	scripts/mk*
>  F:	scripts/package/
> +F:	scripts/lib/
>  
>  KERNEL JANITORS
>  L:	kernel-janitors@vger.kernel.org
> diff --git a/scripts/lib/__init__.py b/scripts/lib/__init__.py
> new file mode 100644
> index 000000000000..1bb8bf6d7fd4
> --- /dev/null
> +++ b/scripts/lib/__init__.py
> @@ -0,0 +1 @@
> +# empty
> diff --git a/scripts/lib/reqs.py b/scripts/lib/reqs.py
> new file mode 100644
> index 000000000000..1325fd21a87a
> --- /dev/null
> +++ b/scripts/lib/reqs.py
> @@ -0,0 +1,211 @@
> +import subprocess, os, sys, re
> +"""
> +Often enough Python code can grow to depend on binaries
> +on a system, you may also require only specific versions
> +of these. This small library helps with this. It also has
> +helpers for packages which we know to handle already.
> +"""
> +
> +class ReqError(Exception):
> +    pass
> +class ExecutionError(ReqError):
> +    def __init__(self, errcode):
> +        self.error_code = errcode
> +
> +class Req:
> +    "To be used for verifying binay package dependencies on Python code"

binay -> binary

> +    def __init__(self):
> +        self.all_reqs_ok = True
> +        self.debug = False
> +    def enable_debug(self):
> +        self.debug = True
> +    def reqs_match(self):
> +        if self.all_reqs_ok:
> +            return True
> +        sys.stdout.write("You have unfulfilled binary requirements\n")
> +        return False
> +    def req_missing(self, program):
> +        self.all_reqs_ok = False
> +        sys.stdout.write("You need to have installed: %s\n" % program)
> +    def req_old_program(self, program, version_req):
> +        self.all_reqs_ok = False
> +        sys.stdout.write("You need to have installed: %s >= %s\n" % (program, version_req))
> +    def which(self, program):
> +        cmd = ['which', program]
> +        process = subprocess.Popen(cmd,
> +                                   stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
> +                                   close_fds=True, universal_newlines=True)
> +        stdout = process.communicate()[0]
> +        process.wait()
> +        if process.returncode != 0:
> +            raise ExecutionError(process.returncode)
> +        return stdout
> +    def req_exists(self, program):
> +        cmd = ['which', program]
> +        process = subprocess.Popen(cmd,
> +                                   stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
> +                                   close_fds=True, universal_newlines=True)
> +        stdout = process.communicate()[0]
> +        process.wait()
> +        if process.returncode == 0:
> +            return True
> +        return False
> +    def req_get_prog_version(self, program, version_query, version_pos):
> +        '''
> +        Suppose you have a binary that outputs:
> +        $ spatch --version
> +        spatch version 1.0.0-rc21 with Python support and with PCRE support
> +
> +        Every program veries what it wants you to query it for a version string,
> +        prog_version() is designed so that you pass what the program expects for
> +        its version query, and the position you expect the version string to be
> +        on using python list.
> +        '''
> +        cmd = [program, version_query]
> +        process = subprocess.Popen(cmd,
> +                                   stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
> +                                   close_fds=True, universal_newlines=True)
> +        stdout = process.communicate()[0]
> +        process.wait()
> +        if process.returncode != 0:
> +            raise ExecutionError(process.returncode)
> +        if self.debug:
> +            sys.stdout.write("Running '%s' got us this break down:\n%s\n" %
> +                             (
> +                             ' '.join(cmd),
> +                             "\n".join(map(str, [[i, x] for i, x in enumerate(stdout.split())])),
> +                             ))
> +            sys.stdout.write("You are using for version: %s\n" % stdout.split()[version_pos])
> +            sys.stdout.write("Specifically your idx, element: %s\n" % ([[i, x] for i, x in enumerate(stdout.split())][version_pos]))
> +        return stdout.split()[version_pos]
> +
> +    MAX_RC = 25
> +    def __compute_rel_weight(self, rel_specs):
> +        weight = 0
> +        extra = 0
> +        sublevel = 0
> +        relmod = 0
> +
> +        if self.debug:
> +            sys.stdout.write("VERSION       = %s\n" % rel_specs['VERSION'])
> +            sys.stdout.write("PATCHLEVEL    = %s\n" % rel_specs['PATCHLEVEL'])
> +            sys.stdout.write("SUBLEVEL      = %s\n" % rel_specs['SUBLEVEL'])
> +            sys.stdout.write("EXTRAVERSION  = %s\n" % rel_specs['EXTRAVERSION'])
> +            sys.stdout.write("RELMOD_UPDATE = %s\n" % rel_specs['RELMOD_UPDATE'])
> +
> +        if rel_specs['EXTRAVERSION'] != '':
> +            if ("." in rel_specs['EXTRAVERSION'] or
> +                    "rc" in rel_specs['EXTRAVERSION']):
> +                rc = rel_specs['EXTRAVERSION'].lstrip("-rc")
> +                if (rc == ""):
> +                    rc = 0
> +                else:
> +                    rc = int(rc) - (Req.MAX_RC + 1)
> +                extra = int(rc)
> +            else:
> +                extra = int(rel_specs['EXTRAVERSION']) + 10
> +
> +        if rel_specs['SUBLEVEL'] != '':
> +            sublevel = int(rel_specs['SUBLEVEL'].lstrip(".")) * 20
> +        else:
> +            sublevel = 5
> +
> +        if rel_specs['RELMOD_UPDATE'] != '':
> +            mod = rel_specs['RELMOD_UPDATE']
> +            if (mod == ""):
> +                mod = 0
> +            else:
> +                mod = int(mod)
> +            relmod = int(mod)
> +
> +        weight = (int(rel_specs['VERSION'])    << 32) + \
> +                 (int(rel_specs['PATCHLEVEL']) << 16) + \
> +                 (sublevel   		       << 8 ) + \
> +                 (extra * 60) + (relmod * 2)
> +
> +        return weight
> +    def req_get_rel_spec(self, rel):
> +        if "rc" in rel:
> +            m = re.match(r"v*(?P<VERSION>\d+)\.+"
> +                         "(?P<PATCHLEVEL>\d+)[.]*"
> +                         "(?P<SUBLEVEL>\d*)"
> +                         "(?P<EXTRAVERSION>[-rc]+\w*)\-*"
> +                         "(?P<RELMOD_UPDATE>\d*)[-]*",
> +                         rel)
> +        else:
> +            m = re.match(r"v*(?P<VERSION>\d+)\.+"
> +                         "(?P<PATCHLEVEL>\d+)[.]*"
> +                         "(?P<SUBLEVEL>\d*)[.]*"
> +                         "(?P<EXTRAVERSION>\w*)\-*"
> +                         "(?P<RELMOD_UPDATE>\d*)[-]*",
> +                         rel)
> +        if not m:
> +            return m
> +        rel_specs = m.groupdict()
> +        return rel_specs
> +    def compute_rel_weight(self, rel):
> +        rel_specs = self.req_get_rel_spec(rel)
> +        if not rel_specs:
> +            return 0
> +        return self.__compute_rel_weight(rel_specs)
> +    def linux_version_cmp(self, version_req, version):
> +        '''
> +        If the program follows the linux version style scheme you can
> +        use this to compare versions.
> +        '''
> +        weight_has = self.compute_rel_weight(version)
> +        weight_req = self.compute_rel_weight(version_req)
> +
> +        if self.debug:
> +            sys.stdout.write("You have program weight: %s\n" % weight_has)
> +            sys.stdout.write("Required program weight: %s\n" % weight_req)
> +
> +        if weight_has < weight_req:
> +            return -1
> +        return 0
> +    def require_version(self, program, version_query, version_req, version_pos, version_cmp):
> +        '''
> +        If you have a program version requirement you can specify it here,
> +        as for the other flags refer to prog_version.
> +        '''
> +        if not self.require(program):
> +            return False
> +        version = self.req_get_prog_version(program, version_query, version_pos)
> +        if self.debug:
> +            sys.stdout.write("Checking release specs and weight: for: %s\n" % program)
> +            sys.stdout.write("You have version: %s\n" % version)
> +            sys.stdout.write("Required version: %s\n" % version_req)
> +        if version_cmp(version_req, version) != 0:
> +            self.req_old_program(program, version_req)
> +            return False
> +        return True
> +    def require(self, program):
> +        if self.req_exists(program):
> +            return True
> +        self.req_missing(program)
> +        return False
> +    def require_hint(self, program, package_hint):
> +        if self.require(program):
> +            return True
> +        sys.stdout.write("Try installing the package: %s\n" % package_hint)
> +        return False
> +    def coccinelle(self, version):
> +        if self.require_version('spatch', '--version', version, 2, self.linux_version_cmp):
> +            return True
> +        sys.stdout.write("Try installing the package: coccinelle\n")
> +        sys.stdout.write("If that is too old go grab the code from source:\n\n")
> +        sys.stdout.write("git clone https://github.com/coccinelle/coccinelle.git\n\n")
> +        sys.stdout.write("To build you will need: ocaml ncurses-devel\n\n")
> +        sys.stdout.write("If on SUSE / OpenSUSE you will also need: ocaml-ocamldoc\n\n")
> +        return False
> +    def kup(self):
> +        if self.require('kup'):
> +            return True
> +        sys.stdout.write("Try installing the package: kup\n")
> +        sys.stdout.write("If your distribution lacks that go get from source:\n\n")
> +        sys.stdout.write("git clone git://git.kernel.org/pub/scm/utils/kup/kup.git\n\n")
> +        return False
> +    def make(self, version):
> +        return self.require_version('make', '--version', version, 2, self.linux_version_cmp)
> +    def gcc(self, version):
> +        return self.require_version('gcc', '--version', version, 3, self.linux_version_cmp)
> -- 
> 2.8.2
> 
> 

  reply	other threads:[~2016-06-15  6:06 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-06-14 22:10 [PATCH 0/4] scripts: add basic python version library and use it Luis R. Rodriguez
2016-06-14 22:10 ` [PATCH 1/4] coccicheck: propagate error and stop processing after first error Luis R. Rodriguez
2016-06-14 22:10 ` [PATCH 2/4] scripts: add reqs python library Luis R. Rodriguez
2016-06-15  6:06   ` Julia Lawall [this message]
2016-06-15 16:04     ` Luis R. Rodriguez
2016-06-15  7:50   ` Michal Marek
2016-06-15 16:02     ` Luis R. Rodriguez
2016-06-15 19:11       ` Michal Marek
2016-06-15 20:26         ` Luis R. Rodriguez
2016-06-15 20:31           ` Julia Lawall
2016-06-15 12:01   ` Aw: [Cocci] " SF Markus Elfring
2016-06-15 15:51     ` Luis R. Rodriguez
2016-06-14 22:10 ` [PATCH 3/4] coccicheck: enable use of the kernel's " Luis R. Rodriguez
2016-06-15  7:51   ` Michal Marek
2016-06-15 15:43     ` Luis R. Rodriguez
2016-06-14 22:10 ` [PATCH 4/4] scripts/coccinelle: require coccinelle >= 1.0.4 on device_node_continue.cocci Luis R. Rodriguez
2016-06-15  6:08   ` Julia Lawall
2016-06-15 15:45     ` Luis R. Rodriguez
2016-06-15  8:43   ` Julia Lawall
2016-06-15 15:49     ` Luis R. Rodriguez
2016-06-15 15:55       ` Julia Lawall
2016-06-15 16:06         ` SF Markus Elfring
2016-06-15 16:08         ` [PATCH 4/4] " Luis R. Rodriguez
2016-06-15 16:11           ` Julia Lawall
2016-06-15 16:46             ` Luis R. Rodriguez
2016-06-15 16:52               ` Julia Lawall
2016-06-15 19:08                 ` Luis R. Rodriguez

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alpine.DEB.2.02.1606150806190.2231@localhost6.localdomain6 \
    --to=julia.lawall@lip6.fr \
    --cc=Gilles.Muller@lip6.fr \
    --cc=cocci@systeme.lip6.fr \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mcgrof@kernel.org \
    --cc=mmarek@suse.com \
    --cc=nicolas.palix@imag.fr \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).