return os.WEXITSTATUS(shell)
-class BuildEnviron(object):
- def __init__(self, pakfire, filename=None, distro_name=None, build_id=None, logfile=None, release_build=True, **kwargs):
- self.pakfire = pakfire
-
- # This build is a release build?
- self.release_build = release_build
-
- if self.release_build:
- # Disable the local build repository in release mode.
- self.pakfire.repos.disable_repo("build")
-
- # Log information about pakfire and some more information, when we
- # are running in release mode.
- logdata = {
- "host_arch" : system.arch,
- "hostname" : system.hostname,
- "time" : time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime()),
- "version" : "Pakfire %s" % PAKFIRE_VERSION,
- }
-
- for line in BUILD_LOG_HEADER.splitlines():
- self.log.info(line % logdata)
-
- # Where do we put the result?
- self.resultdir = os.path.join(self.pakfire.path, "result")
-
- # Open package.
- # If we have a plain makefile, we first build a source package and go with that.
- if filename:
- # Open source package.
- self.pkg = packages.SourcePackage(self.pakfire, None, filename)
- assert self.pkg, filename
-
- # Log the package information.
- self.log.info(_("Package information:"))
- for line in self.pkg.dump(int=True).splitlines():
- self.log.info(" %s" % line)
- self.log.info("")
-
- # Path where we extract the package and put all the source files.
- self.build_dir = os.path.join(self.path, "usr/src/packages", self.pkg.friendly_name)
- else:
- # No package :(
- self.pkg = None
-
- # Lock the buildroot
- self._lock = None
-
- # Save the build time.
- self.build_time = time.time()
-
- def start(self):
- # Extract all needed packages.
- self.extract()
-
- def stop(self):
- # Shut down pakfire instance.
- self.pakfire.destroy()
-
- @property
- def config(self):
- """
- Proxy method for easy access to the configuration.
- """
- return self.pakfire.config
-
- @property
- def distro(self):
- """
- Proxy method for easy access to the distribution.
- """
- return self.pakfire.distro
-
- @property
- def path(self):
- """
- Proxy method for easy access to the path.
- """
- return self.pakfire.path
-
- @property
- def arch(self):
- """
- Inherit architecture from distribution configuration.
- """
- return self.pakfire.distro.arch
-
- @property
- def personality(self):
- """
- Gets the personality from the distribution configuration.
- """
- return self.pakfire.distro.personality
-
- @property
- def info(self):
- return {
- "build_date" : time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(self.build_time)),
- "build_host" : socket.gethostname(),
- "build_id" : self.build_id,
- "build_time" : self.build_time,
- }
-
- def copy_result(self, resultdir):
- # XXX should use find_result_packages
-
- dir_in = self.chrootPath("result")
-
- for dir, subdirs, files in os.walk(dir_in):
- basename = os.path.basename(dir)
- dir = dir[len(self.chrootPath()):]
- for file in files:
- file_in = os.path.join(dir, file)
-
- file_out = os.path.join(
- resultdir,
- basename,
- file,
- )
-
- self.copyout(file_in, file_out)
-
- def find_result_packages(self):
- ret = []
-
- for dir, subdirs, files in os.walk(self.resultdir):
- for file in files:
- if not file.endswith(".%s" % PACKAGE_EXTENSION):
- continue
-
- file = os.path.join(dir, file)
- ret.append(file)
-
- return ret
-
- def extract(self, requires=None):
- """
- Gets a dependency set and extracts all packages
- to the environment.
- """
- if not requires:
- requires = []
-
- # Add neccessary build dependencies.
- requires += BUILD_PACKAGES
-
- # If we have ccache enabled, we need to extract it
- # to the build chroot.
- if self.settings.get("enable_ccache"):
- requires.append("ccache")
-
- # Get build dependencies from source package.
- if self.pkg:
- for req in self.pkg.requires:
- requires.append(req)
-
- # Install all packages.
- self.log.info(_("Install packages needed for build..."))
- self.install(requires)
-
- # Copy the makefile and load source tarballs.
- if self.pkg:
- self.pkg.extract(_("Extracting"), prefix=self.build_dir)
-
- # Add an empty line at the end.
- self.log.info("")
-
- def install(self, requires, **kwargs):
- """
- Install everything that is required in requires.
- """
- # If we got nothing to do, we quit immediately.
- if not requires:
- return
-
- kwargs.update({
- "interactive" : False,
- "logger" : self.log,
- })
-
- if "allow_downgrade" not in kwargs:
- kwargs["allow_downgrade"] = True
-
- # Install everything.
- self.pakfire.install(requires, **kwargs)
-
- def cleanup(self):
- self.log.debug("Cleaning environemnt.")
-
- # Remove the build directory and buildroot.
- dirs = (self.build_dir, self.chrootPath("result"),)
-
- for d in dirs:
- if not os.path.exists(d):
- continue
-
- util.rm(d)
- os.makedirs(d)
-
- @property
- def installed_packages(self):
- """
- Returns an iterator over all installed packages in this build environment.
- """
- # Get the repository of all installed packages.
- repo = self.pakfire.repos.get_repo("@system")
-
- # Return an iterator over the packages.
- return iter(repo)
-
- def write_config(self):
- # Cleanup everything in /etc/pakfire.
- util.rm(self.chrootPath(CONFIG_DIR))
-
- for i in (CONFIG_DIR, CONFIG_REPOS_DIR):
- i = self.chrootPath(i)
- if not os.path.exists(i):
- os.makedirs(i)
-
- # Write general.conf.
- f = open(self.chrootPath(CONFIG_DIR, "general.conf"), "w")
- f.close()
-
- # Write builder.conf.
- f = open(self.chrootPath(CONFIG_DIR, "builder.conf"), "w")
- f.write(self.distro.get_config())
- f.close()
-
- # Create pakfire configuration files.
- for repo in self.pakfire.repos:
- conf = repo.get_config()
-
- if not conf:
- continue
-
- filename = self.chrootPath(CONFIG_REPOS_DIR, "%s.repo" % repo.name)
- f = open(filename, "w")
- f.write("\n".join(conf))
- f.close()
-
- @property
- def pkg_makefile(self):
- return os.path.join(self.build_dir, "%s.%s" % (self.pkg.name, MAKEFILE_EXTENSION))
-
- def execute(self, command, logger=None, **kwargs):
- """
- Executes the given command in the build chroot.
- """
- # Environment variables
- env = self.environ
-
- if "env" in kwargs:
- env.update(kwargs.pop("env"))
-
- self.log.debug("Environment:")
- for k, v in sorted(env.items()):
- self.log.debug(" %s=%s" % (k, v))
-
- # Make every shell to a login shell because we set a lot of
- # environment things there.
- command = ["bash", "--login", "-c", command]
-
- args = {
- "chroot_path" : self.chrootPath(),
- "cgroup" : self.cgroup,
- "env" : env,
- "logger" : logger,
- "personality" : self.personality,
- "shell" : False,
- }
- args.update(kwargs)
-
- # Run the shit.
- shellenv = shell.ShellExecuteEnvironment(command, **args)
- shellenv.execute()
-
- return shellenv
-
- def build(self, install_test=True, prepare=False):
- if not self.pkg:
- raise BuildError(_("You cannot run a build when no package was given."))
-
- # Search for the package file in build_dir and raise BuildError if it is not present.
- if not os.path.exists(self.pkg_makefile):
- raise BuildError(_("Could not find makefile in build root: %s") % self.pkg_makefile)
-
- # Write pakfire configuration into the chroot.
- self.write_config()
-
- # Create the build command, that is executed in the chroot.
- build_command = [
- "/usr/lib/pakfire/builder",
- "--offline",
- "build",
- "/%s" % os.path.relpath(self.pkg_makefile, self.chrootPath()),
- "--arch", self.arch,
- "--nodeps",
- "--resultdir=/result",
- ]
-
- # Check if only the preparation stage should be run.
- if prepare:
- build_command.append("--prepare")
-
- build_command = " ".join(build_command)
-
- try:
- self.execute(build_command, logger=self.log)
-
- # Perform the install test after the actual build.
- if install_test and not prepare:
- self.install_test()
-
- except ShellEnvironmentError:
- self.log.error(_("Build failed"))
-
- except KeyboardInterrupt:
- self.log.error(_("Build interrupted"))
-
- raise
-
- # Catch all other errors.
- except:
- self.log.error(_("Build failed."), exc_info=True)
-
- else:
- # Don't sign packages in prepare mode.
- if prepare:
- return
-
- # Sign all built packages with the host key (if available).
- self.sign_packages()
-
- # Dump package information.
- self.dump()
-
- return
-
- # End here in case of an error.
- raise BuildError(_("The build command failed. See logfile for details."))
-
- def install_test(self):
- self.log.info(_("Running installation test..."))
-
- # Install all packages that were built.
- self.install(self.find_result_packages(), allow_vendorchange=True,
- allow_uninstall=True, signatures_mode="disabled")
-
- self.log.info(_("Installation test succeeded."))
- self.log.info("")
-
-
- def sign_packages(self, keyfp=None):
- # TODO needs to use new key code from libpakfire
-
- # Do nothing if signing is not requested.
- if not self.settings.get("sign_packages"):
- return
-
- # Get key, that should be used for signing.
- if not keyfp:
- keyfp = self.keyring.get_host_key_id()
-
- # Find all files to process.
- files = self.find_result_packages()
-
- # Create a progressbar.
- print(_("Signing packages..."))
- p = util.make_progress(keyfp, len(files))
- i = 0
-
- for file in files:
- # Update progressbar.
- if p:
- i += 1
- p.update(i)
-
- # Open package file.
- pkg = packages.open(self.pakfire, None, file)
-
- # Sign it.
- pkg.sign(keyfp)
-
- # Close progressbar.
- if p:
- p.finish()
- print("") # Print an empty line.
-
- def dump(self):
- pkgs = []
-
- for file in self.find_result_packages():
- pkg = packages.open(self.pakfire, None, file)
- pkgs.append(pkg)
-
- # If there are no packages, there is nothing to do.
- if not pkgs:
- return
-
- pkgs.sort()
-
- self.log.info(_("Dumping package information:"))
- for pkg in pkgs:
- dump = pkg.dump(int=True)
-
- for line in dump.splitlines():
- self.log.info(" %s" % line)
- self.log.info("") # Empty line.
-
-
class BuilderInternal(object):
def __init__(self, pakfire, filename, resultdir, **kwargs):
self.pakfire = pakfire