Beispiel #1
0
def _parse_deb_version(changelog='debian/changelog'):
    try:
        clog = Changelog()
        clog.parse_changelog(open(changelog), max_blocks=1)
        return clog.full_version
    except IOError:
        raise LGPException("Debian changelog '%s' cannot be found" % changelog)
    except ChangelogParseError:
        raise LGPException("Malformed Debian changelog '%s'" % changelog)
Beispiel #2
0
def get_debian_name():
    """obtain the debian package name

    The information is found in debian/control withe the 'Source:' field
    """
    try:
        control = osp.join('debian', 'control')
        deb822 = Deb822(open(control), fields='Source')
        return deb822['Source']
    except IOError as err:
        raise LGPException('a Debian control file should exist in "%s"' %
                           control)
    except KeyError as err:
        raise LGPException("No 'Source' field in '%s'" % control)
Beispiel #3
0
def _parse_deb_project(changelog='debian/changelog'):
    clog = Changelog()
    try:
        clog.parse_changelog(open(changelog), max_blocks=1)
        return clog.package
    except ChangelogParseError:
        raise LGPException("Malformed Debian changelog '%s'" % changelog)
 def _run_command(self, cmd, **args):
     """run an internal declared command as new subprocess"""
     if isinstance(cmd, list):
         cmdline = ' '.join(cmd)
     else:
         cmd = COMMANDS[self.package_format][cmd]
         if callable(cmd):
             try:
                 return cmd()
             except IOError as err:
                 raise LGPException(err)
         cmdline = Template(cmd)
         setup_file = self._normpath(self.config.setup_file)
         cmdline = cmdline.substitute(setup=setup_file, **args)
     self.logger.debug('run subprocess command: %s' % cmdline)
     if args:
         self.logger.debug('command substitutions: %s' % args)
     process = Popen(cmdline.split(), stdout=PIPE)
     pipe = process.communicate()[0].strip()
     if process.returncode > 0:
         process.cmd = cmdline.split()
         raise LGPCommandException(
             "lgp aborted by the '%s' command child process" % cmdline,
             process)
     if not isinstance(pipe, string_types):
         pipe = pipe.decode('utf-8')  # py3k
     return pipe
 def _check_version_mismatch(self):
     upstream_version = self.get_upstream_version()
     #debian_upstream_version = self.get_versions()[0]
     debian_upstream_version = self.get_debian_version().rsplit('-', 1)[0]
     assert debian_upstream_version == self.get_versions(
     )[0], "get_versions() failed"
     if upstream_version != debian_upstream_version:
         msg = "version mismatch: upstream says '%s' and debian/changelog says '%s'"
         msg %= (upstream_version, debian_upstream_version)
         raise LGPException(msg)
Beispiel #6
0
    def make_rpm_source_package(self, specfile, distrib, tmpdir):
        """create a srpm"""
        if specfile is None:
            self.logger.error(
                "specfile not found, please use the '--specfile' option")
            raise LGPException("cannot build source distribution")
        if self.config.suffix is not None:
            # patch the spec file to inject the ~revision in the version
            suffix = self.config.suffix or '+%s' % int(time.time())
            with tempfile.NamedTemporaryFile() as out:
                for line in open(specfile):
                    if line.lower().startswith('release:'):
                        line = line.strip() + suffix + '\n'
                    out.write(line)
                out.flush()
                shutil.move(out.name, specfile)
                out.delete = False
                os.chmod(specfile, 0o644)

        # change directory to build source package
        # note: call os.chdir() HERE is needed in make_rpm_binary_package() below
        os.chdir(tmpdir)
        try:
            cmd = [
                "sudo", "mock", "--buildsrpm", "--spec", specfile,
                "--resultdir",
                os.getcwd(), "-r", distrib, "--uniqueext",
                str(os.getpid()), "--sources",
                osp.dirname(self._upstream_tarball)
            ]
            self.logger.debug("running mock command: %s ..." % " ".join(cmd))
            check_call(cmd, stdout=sys.stdout)
        except CalledProcessError as err:
            msg = "cannot build valid srpm file with command %s" % cmd
            raise LGPCommandException(msg, err)
        srpms = glob(osp.join(os.getcwd(), '*.src.rpm'))
        try:
            srpm, = srpms
        except ValueError:
            raise LGPException("couldn't find the SRPM")
        return srpm
    def _normpath(self, path):
        """helper method to normalize filepath arguments before
        changing current directory (will return absolute paths)

        XXX could be coded directly by option checker (optparse)
        """
        if path:
            assert self.old_current_directory
            path = osp.abspath(
                osp.join(self.old_current_directory, osp.expanduser(path)))
            if not osp.exists(path):
                msg = "file given in command line cannot be found:\n\t%s"
                raise LGPException(msg % path)
        return path
Beispiel #8
0
 def _check_file(filename):
     if osp.isfile(filename):
         hash1 = hashlib.md5(open(fullpath).read()).hexdigest()
         hash2 = hashlib.md5(open(filename).read()).hexdigest()
         if hash1 == hash2:
             self.logger.debug("overwrite same file file '%s'" %
                               filename)
         else:
             msg = "theses files shouldn't be different:\n"\
                   "- %s (%s)\n"\
                   "- %s (%s)"
             self.logger.warn(msg % (fullpath, hash1, filename, hash2))
             os.system('diff -u %s %s' % (fullpath, filename))
             raise LGPException(
                 "bad md5 sums of source archives (tarball)")
    def _set_package_format(self):
        """set the package format to be able to run COMMANDS

        setup_file must not be redefined since we can call this
        method several times
        """
        setup_file = self._normpath(self.config.setup_file)
        if setup_file:
            self.logger.info('use specific setup file: %s', setup_file)

        if osp.isfile('__pkginfo__.py') and not setup_file:
            # Logilab's specific format
            # FIXME Format is buggy if setup_file was set to 'setup.py'
            from logilab.packaging.lib import TextReporter
            self.config._package = PackageInfo(reporter=TextReporter(
                open(os.devnull, "w+")),
                                               directory=self.config.pkg_dir)
            assert osp.isfile('setup.py'), "setup.py is still mandatory"
        # other script can be used if compatible with the expected targets in COMMANDS
        elif osp.isfile(setup_file):
            if osp.basename(setup_file) == 'setup.py':
                # case for python project (distutils, setuptools)
                self.config._package = run_setup(setup_file,
                                                 None,
                                                 stop_after="init")
            else:
                # generic case: the setup file should only honor targets as:
                # sdist, project, version, clean (see COMMANDS)
                self.config._package = open(setup_file)
                if not os.stat(setup_file).st_mode & stat.S_IEXEC:
                    raise LGPException(
                        'setup file %s has no execute permission' % setup_file)
        else:
            if self.config.rpm:

                class rpm(object):
                    pass

                self.config._package = rpm()
            else:

                class debian(object):
                    pass

                self.config._package = debian()
        self.logger.debug("use setup package class format: %s" %
                          self.package_format)
Beispiel #10
0
def get_debian_architecture():
    """get debian architecture(s) to use in build

    The information is found in debian/control with the 'Architecture:' field
    """
    try:
        control = osp.join('debian', 'control')
        for line in open(control):
            line = line.split(' ', 1)
            if line[0] == "Architecture:":
                archi = line[1].rstrip().split(' ')
                if "source" in archi:
                    archi.pop('source')
                return archi
    except IOError as err:
        raise LGPException('a Debian control file should exist in "%s"' %
                           control)
 def go_into_package_dir(self, arguments):
     """go into package directory
     """
     self.old_current_directory = os.getcwd(
     )  # use for relative filename in parameters
     if arguments:
         if os.path.exists(arguments[0]):
             self.config.pkg_dir = osp.abspath(arguments[0])
         else:
             raise LGPException("project directory doesn't exist: %s" %
                                arguments[0])
         if os.path.isfile(self.config.pkg_dir):
             self.config.pkg_dir = os.path.dirname(self.config.pkg_dir)
         os.chdir(self.config.pkg_dir)
         self.logger.debug('change the current working directory to: %s' %
                           self.config.pkg_dir)
     else:
         self.config.pkg_dir = self.old_current_directory
Beispiel #12
0
    def manage_current_distribution(self, distrib):
        """manage debian files depending of the current distrib from options

        We copy debian_dir directory into tmp build depending of the target distribution
        in all cases, we copy the debian directory of the default version (unstable)
        If a file should not be included, touch an empty file in the overlay
        directory.

        This is specific to Logilab (debian directory is in project directory)
        """
        try:
            # don't forget the final slash!
            export(osp.join(self.config.pkg_dir, 'debian'),
                   osp.join(self.origpath, 'debian/'),
                   verbose=(self.config.verbose == 2))
        except IOError as err:
            raise LGPException(err)

        debian_dir = self.get_debian_dir(distrib)
        if debian_dir != "debian":
            self.logger.info("overriding files from '%s' directory..." %
                             debian_dir)
            # don't forget the final slash!
            export(osp.join(self.config.pkg_dir, debian_dir),
                   osp.join(self.origpath, 'debian/'),
                   verbose=self.config.verbose)

        from debian.changelog import Changelog
        debchangelog = osp.join(self.origpath, 'debian', 'changelog')
        changelog = Changelog(open(debchangelog))
        # substitute distribution string in changelog
        if distrib:
            # squeeze python-debian doesn't handle unicode well, see Debian bug#561805
            changelog.distributions = str(distrib)
        # append suffix string (or timestamp if suffix is empty) to debian revision
        if self.config.suffix is not None:
            suffix = self.config.suffix or '+%s' % int(time.time())
            self.logger.debug("suffix '%s' added to package version" % suffix)
            changelog.version = str(changelog.version) + suffix
        changelog.write_to_open_file(open(debchangelog, 'w'))

        return self.origpath
Beispiel #13
0
    def get_checklist(self, all=False):
        if all:
            return [
                funct for (name, funct) in globals().items()
                if name.startswith('check_')
            ]
        try:
            checks = CHECKS['default']

            # we try to compile a consistent set of checks to apply
            if os.path.exists('setup.py'):
                checks.update(CHECKS['distutils'])
            if os.path.exists('__pkginfo__.py'):
                checks.update(CHECKS['pkginfo'])
            if os.path.exists('debian'):
                checks.update(CHECKS['debian'])
            if self.config.set_checks:
                checks = set()

            for c in itertools.chain(self.config.set_checks,
                                     self.config.include_checks):
                if c in CHECKS:
                    checks.update(CHECKS[c])
                else:
                    checks.add(c)
            for c in self.config.exclude_checks:
                if c in CHECKS:
                    checks.difference_update(CHECKS[c])
                else:
                    if c in checks:
                        checks.remove(c)
            self.checklist = [globals()["check_%s" % name] for name in checks]
        except KeyError as err:
            msg = "check function or category %s was not found. Use lgp check --list"
            raise LGPException(msg % str(err))
        return self.checklist
Beispiel #14
0
    def make_orig_tarball(self, tmpdir="."):
        """make upstream pristine tarballs (Debian way)

        Create the tarball from working directory for the initial revision.
        For later ones call uscan to download the source tarball by looking at
        debian/watch (if the tarball wasn't passed on the command line).

        Finally copy pristine tarball with expected upstream filename convention.

        This method is responsible for setting config.orig_tarball to its right
        location.

        .. see::
            http://www.debian.org/doc/debian-policy/ch-source.html
        """
        has_debian_dir = osp.isdir('debian')
        if has_debian_dir:
            # _check_version_mismatch() is 100% Debian-specific
            self._check_version_mismatch()
            is_initial_debian_revision = self.is_initial_debian_revision()
        else:
            # always rebuild the source/orig tarball if debian/ is missing,
            # skip uscan altogether
            is_initial_debian_revision = True
        tarball = self.config.orig_tarball

        if tarball and is_initial_debian_revision:
            self.logger.warn("you are passing a pristine tarball in command "
                             "line for an initial Debian revision")

        upstream_name = self.get_upstream_name()
        fileparts = (upstream_name, self.get_upstream_version())
        if has_debian_dir:
            # note: tarball format can be guaranteed by uscan's repack option
            debian_tarball = '%s_%s.orig.tar.gz' % fileparts
        upstream_tarball = '%s-%s.tar.gz' % fileparts

        # run uscan to download the source tarball by looking at debian/watch
        if tarball is None and not is_initial_debian_revision:
            self.logger.info('running uscan to download the source tarball by '
                             'looking at debian/watch')
            try:
                check_call([
                    "uscan", "--noconf", "--download-current-version",
                    "--no-symlink", "--destdir", tmpdir
                ])
            except CalledProcessError as err:
                debian_name = self.get_debian_name()
                debian_revision = self.get_debian_version().rsplit('-', 1)[1]
                self.logger.error("Debian source archive (pristine tarball) is"\
                                  " required when you don't build the first "\
                                  " revision of a debian package "\
                                  "(use '--orig-tarball' option)")
                self.logger.info("If you haven't the original tarball version,"
                                 " you could run: "
                                 "'apt-get source --tar-only %s'" %
                                 debian_name)
                msg = ('unable to build upstream tarball of %s package for '
                       'Debian revision "%s"' % (debian_name, debian_revision))
                raise LGPCommandException(msg, err)
            else:
                tarball = osp.join(tmpdir, upstream_tarball)

        # create new pristine tarball from working directory if initial revision
        elif tarball is None and is_initial_debian_revision:
            self.logger.info("create pristine tarball from working directory")
            try:
                self._run_command("sdist", dist_dir=tmpdir)
            except CalledProcessError as err:
                self.logger.error("creation of the source archive failed")
                self.logger.error(
                    "check if the version '%s' is really tagged in "
                    "your repository" % self.get_upstream_version())
                raise LGPCommandException(
                    "source distribution wasn't properly built", err)
            else:
                tarball = osp.join(tmpdir, upstream_tarball)

        # Sanity check
        if not osp.basename(tarball).startswith(upstream_name):
            msg = "pristine tarball filename doesn't start with "\
                  "upstream name '%s'. really suspect..."
            self.logger.error(msg % upstream_name)

        # Make a copy of tarball ('path/to/xxx-version.tar.gz')...
        # ... with the debian name convention 'path/to/xxx_version.orig.tar.gz'
        if has_debian_dir:
            debian_tarball = osp.abspath(osp.join(tmpdir, debian_tarball))
            try:
                if not osp.exists(debian_tarball):
                    shutil.copy(tarball, debian_tarball)
            except EnvironmentError as err:
                msg = "pristine tarball can't be copied from given location: %s"
                self.logger.critical(msg % tarball)
                raise LGPException(err)
            self._debian_tarball = debian_tarball
        #
        self._upstream_tarball = tarball
        return tarball
Beispiel #15
0
 def _prune_pkg_dir(self):
     super(Builder, self)._prune_pkg_dir()
     if self.package_format == 'debian' and not osp.isdir('debian'):
         msg = ("You are not in a valid project root directory. "
                "Lgp expects a Debian directory here.")
         raise LGPException(msg)
 def get_basetgz(self, distrib, arch, check=True):
     basetgz = osp.join(self.config.basetgz, "%s-%s.tgz" % (distrib, arch))
     if check and not osp.exists(basetgz):
         msg = "lgp image '%s' not found. Please create it with lgp setup"
         raise LGPException(msg % basetgz)
     return basetgz