mirror of
https://github.com/rpm-software-management/tito.git
synced 2025-02-23 12:12:47 +00:00
Start building with external sources and no tag.
Currently uses the files in the directory where tito was initially run, hoping to make this smarter and more useful soon.
This commit is contained in:
parent
76b32635e0
commit
199f332d4d
7 changed files with 386 additions and 277 deletions
|
@ -10,8 +10,10 @@
|
|||
# Red Hat trademarks are not licensed under GPLv2. No permission is
|
||||
# granted to use or replicate Red Hat trademarks that are incorporated
|
||||
# in this software or its documentation.
|
||||
|
||||
"""
|
||||
Code for building Spacewalk/Satellite tarballs, srpms, and rpms.
|
||||
Tito builders for a variety of common methods of building sources, srpms,
|
||||
and rpms.
|
||||
"""
|
||||
|
||||
import os
|
||||
|
@ -23,158 +25,73 @@ from distutils.version import LooseVersion as loose_version
|
|||
from tempfile import mkdtemp
|
||||
|
||||
from tito.common import *
|
||||
from tito.common import scl_to_rpm_option, get_latest_tagged_version
|
||||
from tito.common import scl_to_rpm_option, get_latest_tagged_version, \
|
||||
find_wrote_in_rpmbuild_output
|
||||
from tito.exception import RunCommandException
|
||||
from tito.release import *
|
||||
from tito.exception import TitoException
|
||||
from tito.config_object import ConfigObject
|
||||
|
||||
|
||||
class Builder(ConfigObject):
|
||||
class BuilderBase(object):
|
||||
"""
|
||||
Parent builder class.
|
||||
A base class for all builders.
|
||||
|
||||
Includes functionality for a standard Spacewalk package build. Packages
|
||||
which require other unusual behavior can subclass this to inject the
|
||||
desired behavior.
|
||||
Handles things we will *always* do, primarily handling temporary directories
|
||||
for rpmbuild.
|
||||
|
||||
This class should *not* assume we're even using git.
|
||||
"""
|
||||
REQUIRED_ARGS = []
|
||||
|
||||
# TODO: drop version
|
||||
def __init__(self, name=None, tag=None, build_dir=None,
|
||||
# TODO: merge config into an object and kill the ConfigObject parent class
|
||||
def __init__(self, name=None, build_dir=None,
|
||||
pkg_config=None, global_config=None, user_config=None,
|
||||
args=None, **kwargs):
|
||||
|
||||
"""
|
||||
name - Package name that is being built.
|
||||
|
||||
version - Version and release being built.
|
||||
|
||||
tag - The git tag being built.
|
||||
|
||||
build_dir - Temporary build directory where we can safely work.
|
||||
|
||||
pkg_config - Package specific configuration.
|
||||
|
||||
global_config - Global configuration from rel-eng/tito.props.
|
||||
|
||||
user_config - User configuration from ~/.titorc.
|
||||
|
||||
args - Optional arguments specific to each builder. Can be passed
|
||||
in explicitly by user on the CLI, or via a release target config
|
||||
entry. Only for things which vary on invocations of the builder,
|
||||
avoid using these if possible.
|
||||
"""
|
||||
ConfigObject.__init__(self, pkg_config=pkg_config, global_config=global_config)
|
||||
|
||||
self.project_name = name
|
||||
self.build_tag = tag
|
||||
self.user_config = user_config
|
||||
self.no_cleanup = False
|
||||
self.args = args
|
||||
|
||||
# Optional keyword arguments:
|
||||
self.dist = self._get_optional_arg(kwargs, 'dist', None)
|
||||
self.test = self._get_optional_arg(kwargs, 'test', False)
|
||||
|
||||
self.offline = self._get_optional_arg(kwargs, 'offline', False)
|
||||
self.auto_install = self._get_optional_arg(kwargs, 'auto_install',
|
||||
False)
|
||||
self.rpmbuild_options = self._get_optional_arg(kwargs,
|
||||
'rpmbuild_options', None)
|
||||
self.scl = self._get_optional_arg(kwargs,
|
||||
'scl', '')
|
||||
|
||||
self.build_version = self._get_build_version()
|
||||
self.rpmbuild_options = self._get_optional_arg(kwargs,
|
||||
'rpmbuild_options', None)
|
||||
if not self.rpmbuild_options:
|
||||
self.rpmbuild_options = ''
|
||||
|
||||
self.test = self._get_optional_arg(kwargs, 'test', False)
|
||||
# Allow a builder arg to override the test setting passed in, used by
|
||||
# releasers in their config sections.
|
||||
if args and 'test' in args:
|
||||
self.test = True
|
||||
|
||||
if kwargs and 'options' in kwargs:
|
||||
print("WARNING: 'options' no longer a supported builder "
|
||||
"constructor argument.")
|
||||
|
||||
if not self.rpmbuild_options:
|
||||
self.rpmbuild_options = ''
|
||||
|
||||
if self.config.has_section("requirements"):
|
||||
if self.config.has_option("requirements", "tito"):
|
||||
if loose_version(self.config.get("requirements", "tito")) > \
|
||||
loose_version(require('tito')[0].version):
|
||||
print("Error: tito version %s or later is needed to build this project." %
|
||||
self.config.get("requirements", "tito"))
|
||||
print("Your version: %s" % require('tito')[0].version)
|
||||
sys.exit(-1)
|
||||
|
||||
# Location where we do all tito work and store resulting rpms:
|
||||
self.rpmbuild_basedir = build_dir
|
||||
self.display_version = self._get_display_version()
|
||||
|
||||
self.git_commit_id = get_build_commit(tag=self.build_tag,
|
||||
test=self.test)
|
||||
self.project_name_and_sha1 = "%s-%s" % (self.project_name,
|
||||
self.git_commit_id)
|
||||
|
||||
self.relative_project_dir = get_relative_project_dir(
|
||||
project_name=self.project_name, commit=self.git_commit_id)
|
||||
|
||||
tgz_base = self._get_tgz_name_and_ver()
|
||||
self.tgz_filename = tgz_base + ".tar.gz"
|
||||
self.tgz_dir = tgz_base
|
||||
self.artifacts = []
|
||||
|
||||
# Location where we do actual rpmbuilds
|
||||
self.rpmbuild_dir = mkdtemp(dir=self.rpmbuild_basedir,
|
||||
prefix="rpmbuild-%s" % self.project_name_and_sha1)
|
||||
prefix="rpmbuild-%s" % self.project_name)
|
||||
debug("Building in temp dir: %s" % self.rpmbuild_dir)
|
||||
self.rpmbuild_sourcedir = os.path.join(self.rpmbuild_dir, "SOURCES")
|
||||
self.rpmbuild_builddir = os.path.join(self.rpmbuild_dir, "BUILD")
|
||||
|
||||
# A copy of the git code from commit we're building:
|
||||
self.rpmbuild_gitcopy = os.path.join(self.rpmbuild_sourcedir,
|
||||
self.tgz_dir)
|
||||
self._check_required_args()
|
||||
|
||||
# Set to true if we've already created a tgz:
|
||||
# Set to true once we've created/setup sources: (i.e. tar.gz)
|
||||
self.ran_tgz = False
|
||||
|
||||
# Used to make sure we only modify the spec file for a test build
|
||||
# once. The srpm method may be called multiple times during koji
|
||||
# releases to create the proper disttags, but we only want to modify
|
||||
# the spec file once.
|
||||
self.ran_setup_test_specfile = False
|
||||
|
||||
# NOTE: These are defined later when/if we actually dump a copy of the
|
||||
# project source at the tag we're building. Only then can we search for
|
||||
# a spec file.
|
||||
self.spec_file_name = None
|
||||
self.spec_file = None
|
||||
|
||||
self.no_cleanup = False
|
||||
|
||||
# List of full path to all sources for this package.
|
||||
self.sources = []
|
||||
|
||||
# Set to path to srpm once we build one.
|
||||
self.srpm_location = None
|
||||
|
||||
self._check_required_args()
|
||||
|
||||
def _get_build_version(self):
|
||||
"""
|
||||
Figure out the git tag and version-release we're building.
|
||||
"""
|
||||
# Determine which package version we should build:
|
||||
build_version = None
|
||||
if self.build_tag:
|
||||
build_version = self.build_tag[len(self.project_name + "-"):]
|
||||
else:
|
||||
build_version = get_latest_tagged_version(self.project_name)
|
||||
if build_version == None:
|
||||
error_out(["Unable to lookup latest package info.",
|
||||
"Perhaps you need to tag first?"])
|
||||
self.build_tag = "%s-%s" % (self.project_name, build_version)
|
||||
|
||||
if not self.test:
|
||||
check_tag_exists(self.build_tag, offline=self.offline)
|
||||
return build_version
|
||||
# Artifacts we built:
|
||||
self.artifacts = []
|
||||
|
||||
def _get_optional_arg(self, kwargs, arg, default):
|
||||
"""
|
||||
|
@ -209,78 +126,51 @@ class Builder(ConfigObject):
|
|||
if options.srpm:
|
||||
self.srpm()
|
||||
if options.rpm:
|
||||
self._rpm()
|
||||
# TODO: not protected anymore
|
||||
self.rpm()
|
||||
self._auto_install()
|
||||
|
||||
self.cleanup()
|
||||
return self.artifacts
|
||||
|
||||
def tgz(self):
|
||||
def cleanup(self):
|
||||
"""
|
||||
Create the .tar.gz required to build this package.
|
||||
|
||||
Returns full path to the created tarball.
|
||||
Remove all temporary files and directories.
|
||||
"""
|
||||
self._setup_sources()
|
||||
|
||||
run_command("cp %s/%s %s/" % \
|
||||
(self.rpmbuild_sourcedir, self.tgz_filename,
|
||||
self.rpmbuild_basedir))
|
||||
|
||||
self.ran_tgz = True
|
||||
full_path = os.path.join(self.rpmbuild_basedir, self.tgz_filename)
|
||||
print("Wrote: %s" % full_path)
|
||||
self.sources.append(full_path)
|
||||
self.artifacts.append(full_path)
|
||||
return full_path
|
||||
|
||||
def _scl_to_rpmbuild_option(self):
|
||||
""" Returns rpmbuild option which disable or enable SC and print warning if needed """
|
||||
return scl_to_rpm_option(self.scl)
|
||||
|
||||
# TODO: reuse_cvs_checkout isn't needed here, should be cleaned up:
|
||||
def srpm(self, dist=None, reuse_cvs_checkout=False):
|
||||
"""
|
||||
Build a source RPM.
|
||||
"""
|
||||
self._create_build_dirs()
|
||||
if not self.ran_tgz:
|
||||
self.tgz()
|
||||
|
||||
if self.test:
|
||||
self._setup_test_specfile()
|
||||
|
||||
debug("Creating srpm from spec file: %s" % self.spec_file)
|
||||
define_dist = ""
|
||||
if self.dist:
|
||||
debug("using self.dist: %s" % self.dist)
|
||||
define_dist = "--define 'dist %s'" % self.dist
|
||||
elif dist:
|
||||
debug("using dist: %s" % dist)
|
||||
define_dist = "--define 'dist %s'" % dist
|
||||
if not self.no_cleanup:
|
||||
debug("Cleaning up [%s]" % self.rpmbuild_dir)
|
||||
commands.getoutput("rm -rf %s" % self.rpmbuild_dir)
|
||||
else:
|
||||
debug("*NOT* using dist at all")
|
||||
print("WARNING: Leaving rpmbuild files in: %s" % self.rpmbuild_dir)
|
||||
|
||||
rpmbuild_options = self.rpmbuild_options + self._scl_to_rpmbuild_option()
|
||||
def _check_build_dirs_access(self):
|
||||
"""
|
||||
Ensure the build directories are writable.
|
||||
"""
|
||||
if not os.access(self.rpmbuild_basedir, os.W_OK):
|
||||
error_out("%s is not writable." % self.rpmbuild_basedir)
|
||||
if not os.access(self.rpmbuild_dir, os.W_OK):
|
||||
error_out("%s is not writable." % self.rpmbuild_dir)
|
||||
if not os.access(self.rpmbuild_sourcedir, os.W_OK):
|
||||
error_out("%s is not writable." % self.rpmbuild_sourcedir)
|
||||
if not os.access(self.rpmbuild_builddir, os.W_OK):
|
||||
error_out("%s is not writable." % self.rpmbuild_builddir)
|
||||
|
||||
cmd = ('LC_ALL=C rpmbuild --define "_source_filedigest_algorithm md5" --define'
|
||||
' "_binary_filedigest_algorithm md5" %s %s %s --nodeps -bs %s' % (
|
||||
rpmbuild_options, self._get_rpmbuild_dir_options(),
|
||||
define_dist, self.spec_file))
|
||||
output = run_command(cmd)
|
||||
print(output)
|
||||
self.srpm_location = self._find_wrote_in_rpmbuild_output(output)[0]
|
||||
self.artifacts.append(self.srpm_location)
|
||||
def _create_build_dirs(self):
|
||||
"""
|
||||
Create the build directories. Can safely be called multiple times.
|
||||
"""
|
||||
commands.getoutput("mkdir -p %s %s %s %s" % (
|
||||
self.rpmbuild_basedir, self.rpmbuild_dir,
|
||||
self.rpmbuild_sourcedir, self.rpmbuild_builddir))
|
||||
self._check_build_dirs_access()
|
||||
|
||||
def _rpm(self):
|
||||
def rpm(self):
|
||||
""" Build an RPM. """
|
||||
self._create_build_dirs()
|
||||
if not self.ran_tgz:
|
||||
self.tgz()
|
||||
|
||||
if self.test:
|
||||
self._setup_test_specfile()
|
||||
|
||||
define_dist = ""
|
||||
if self.dist:
|
||||
define_dist = "--define 'dist %s'" % self.dist
|
||||
|
@ -299,12 +189,13 @@ class Builder(ConfigObject):
|
|||
except RunCommandException, err:
|
||||
msg = str(err)
|
||||
if (re.search('Failed build dependencies', err.output)):
|
||||
msg = "Please run 'yum-builddep %s' as root." % find_spec_file(self.relative_project_dir)
|
||||
msg = "Please run 'yum-builddep %s' as root." % \
|
||||
find_spec_file(self.relative_project_dir)
|
||||
error_out('%s' % msg)
|
||||
except Exception, err:
|
||||
error_out('%s' % str(err))
|
||||
print(output)
|
||||
files_written = self._find_wrote_in_rpmbuild_output(output)
|
||||
files_written = find_wrote_in_rpmbuild_output(output)
|
||||
if len(files_written) < 2:
|
||||
error_out("Error parsing rpmbuild output")
|
||||
self.srpm_location = files_written[0]
|
||||
|
@ -313,6 +204,10 @@ class Builder(ConfigObject):
|
|||
print
|
||||
print("Successfully built: %s" % ' '.join(files_written))
|
||||
|
||||
def _scl_to_rpmbuild_option(self):
|
||||
""" Returns rpmbuild option which disable or enable SC and print warning if needed """
|
||||
return scl_to_rpm_option(self.scl)
|
||||
|
||||
def _auto_install(self):
|
||||
"""
|
||||
If requested, auto install the RPMs we just built.
|
||||
|
@ -351,6 +246,176 @@ class Builder(ConfigObject):
|
|||
except KeyboardInterrupt:
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class Builder(ConfigObject, BuilderBase):
|
||||
"""
|
||||
Parent builder class.
|
||||
|
||||
Includes functionality for a standard Spacewalk package build. Packages
|
||||
which require other unusual behavior can subclass this to inject the
|
||||
desired behavior.
|
||||
"""
|
||||
REQUIRED_ARGS = []
|
||||
|
||||
# TODO: drop version
|
||||
def __init__(self, name=None, tag=None, build_dir=None,
|
||||
pkg_config=None, global_config=None, user_config=None,
|
||||
args=None, **kwargs):
|
||||
|
||||
"""
|
||||
name - Package name that is being built.
|
||||
|
||||
version - Version and release being built.
|
||||
|
||||
tag - The git tag being built.
|
||||
|
||||
build_dir - Temporary build directory where we can safely work.
|
||||
|
||||
pkg_config - Package specific configuration.
|
||||
|
||||
global_config - Global configuration from rel-eng/tito.props.
|
||||
|
||||
user_config - User configuration from ~/.titorc.
|
||||
|
||||
args - Optional arguments specific to each builder. Can be passed
|
||||
in explicitly by user on the CLI, or via a release target config
|
||||
entry. Only for things which vary on invocations of the builder,
|
||||
avoid using these if possible.
|
||||
"""
|
||||
ConfigObject.__init__(self, pkg_config=pkg_config, global_config=global_config)
|
||||
BuilderBase.__init__(self, name=name, build_dir=build_dir, pkg_config=pkg_config, global_config=global_config, user_config=user_config, args=args, **kwargs)
|
||||
self.build_tag = tag
|
||||
|
||||
self.build_version = self._get_build_version()
|
||||
|
||||
if kwargs and 'options' in kwargs:
|
||||
print("WARNING: 'options' no longer a supported builder "
|
||||
"constructor argument.")
|
||||
|
||||
if self.config.has_section("requirements"):
|
||||
if self.config.has_option("requirements", "tito"):
|
||||
if loose_version(self.config.get("requirements", "tito")) > \
|
||||
loose_version(require('tito')[0].version):
|
||||
print("Error: tito version %s or later is needed to build this project." %
|
||||
self.config.get("requirements", "tito"))
|
||||
print("Your version: %s" % require('tito')[0].version)
|
||||
sys.exit(-1)
|
||||
|
||||
self.display_version = self._get_display_version()
|
||||
|
||||
self.git_commit_id = get_build_commit(tag=self.build_tag,
|
||||
test=self.test)
|
||||
|
||||
self.relative_project_dir = get_relative_project_dir(
|
||||
project_name=self.project_name, commit=self.git_commit_id)
|
||||
|
||||
tgz_base = self._get_tgz_name_and_ver()
|
||||
self.tgz_filename = tgz_base + ".tar.gz"
|
||||
self.tgz_dir = tgz_base
|
||||
self.artifacts = []
|
||||
|
||||
# A copy of the git code from commit we're building:
|
||||
self.rpmbuild_gitcopy = os.path.join(self.rpmbuild_sourcedir,
|
||||
self.tgz_dir)
|
||||
|
||||
# Used to make sure we only modify the spec file for a test build
|
||||
# once. The srpm method may be called multiple times during koji
|
||||
# releases to create the proper disttags, but we only want to modify
|
||||
# the spec file once.
|
||||
self.ran_setup_test_specfile = False
|
||||
|
||||
# NOTE: These are defined later when/if we actually dump a copy of the
|
||||
# project source at the tag we're building. Only then can we search for
|
||||
# a spec file.
|
||||
self.spec_file_name = None
|
||||
self.spec_file = None
|
||||
|
||||
# Set to path to srpm once we build one.
|
||||
self.srpm_location = None
|
||||
|
||||
|
||||
def _get_build_version(self):
|
||||
"""
|
||||
Figure out the git tag and version-release we're building.
|
||||
"""
|
||||
# Determine which package version we should build:
|
||||
build_version = None
|
||||
if self.build_tag:
|
||||
build_version = self.build_tag[len(self.project_name + "-"):]
|
||||
else:
|
||||
build_version = get_latest_tagged_version(self.project_name)
|
||||
if build_version == None:
|
||||
error_out(["Unable to lookup latest package info.",
|
||||
"Perhaps you need to tag first?"])
|
||||
self.build_tag = "%s-%s" % (self.project_name, build_version)
|
||||
|
||||
if not self.test:
|
||||
check_tag_exists(self.build_tag, offline=self.offline)
|
||||
return build_version
|
||||
|
||||
def tgz(self):
|
||||
"""
|
||||
Create the .tar.gz required to build this package.
|
||||
|
||||
Returns full path to the created tarball.
|
||||
"""
|
||||
self._setup_sources()
|
||||
|
||||
run_command("cp %s/%s %s/" % \
|
||||
(self.rpmbuild_sourcedir, self.tgz_filename,
|
||||
self.rpmbuild_basedir))
|
||||
|
||||
self.ran_tgz = True
|
||||
full_path = os.path.join(self.rpmbuild_basedir, self.tgz_filename)
|
||||
print("Wrote: %s" % full_path)
|
||||
self.sources.append(full_path)
|
||||
self.artifacts.append(full_path)
|
||||
return full_path
|
||||
|
||||
# TODO: reuse_cvs_checkout isn't needed here, should be cleaned up:
|
||||
def srpm(self, dist=None, reuse_cvs_checkout=False):
|
||||
"""
|
||||
Build a source RPM.
|
||||
"""
|
||||
self._create_build_dirs()
|
||||
if not self.ran_tgz:
|
||||
self.tgz()
|
||||
|
||||
if self.test:
|
||||
self._setup_test_specfile()
|
||||
|
||||
debug("Creating srpm from spec file: %s" % self.spec_file)
|
||||
define_dist = ""
|
||||
if self.dist:
|
||||
debug("using self.dist: %s" % self.dist)
|
||||
define_dist = "--define 'dist %s'" % self.dist
|
||||
elif dist:
|
||||
debug("using dist: %s" % dist)
|
||||
define_dist = "--define 'dist %s'" % dist
|
||||
else:
|
||||
debug("*NOT* using dist at all")
|
||||
|
||||
rpmbuild_options = self.rpmbuild_options + self._scl_to_rpmbuild_option()
|
||||
|
||||
cmd = ('LC_ALL=C rpmbuild --define "_source_filedigest_algorithm md5" --define'
|
||||
' "_binary_filedigest_algorithm md5" %s %s %s --nodeps -bs %s' % (
|
||||
rpmbuild_options, self._get_rpmbuild_dir_options(),
|
||||
define_dist, self.spec_file))
|
||||
output = run_command(cmd)
|
||||
print(output)
|
||||
self.srpm_location = find_wrote_in_rpmbuild_output(output)[0]
|
||||
self.artifacts.append(self.srpm_location)
|
||||
|
||||
def rpm(self):
|
||||
""" Build an RPM. """
|
||||
self._create_build_dirs()
|
||||
if not self.ran_tgz:
|
||||
self.tgz()
|
||||
if self.test:
|
||||
self._setup_test_specfile()
|
||||
BuilderBase.rpm(self)
|
||||
|
||||
def _setup_sources(self):
|
||||
"""
|
||||
Create a copy of the git source for the project at the point in time
|
||||
|
@ -382,53 +447,6 @@ class Builder(ConfigObject):
|
|||
self.spec_file = os.path.join(
|
||||
self.rpmbuild_gitcopy, self.spec_file_name)
|
||||
|
||||
def _find_wrote_in_rpmbuild_output(self, output):
|
||||
"""
|
||||
Parse the output from rpmbuild looking for lines beginning with
|
||||
"Wrote:". Return a list of file names for each path found.
|
||||
"""
|
||||
paths = []
|
||||
look_for = "Wrote: "
|
||||
for line in output.split("\n"):
|
||||
if line.startswith(look_for):
|
||||
paths.append(line[len(look_for):])
|
||||
debug("Found wrote line: %s" % paths[-1])
|
||||
if not paths:
|
||||
error_out("Unable to locate 'Wrote: ' lines in rpmbuild output")
|
||||
return paths
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Remove all temporary files and directories.
|
||||
"""
|
||||
if not self.no_cleanup:
|
||||
debug("Cleaning up [%s]" % self.rpmbuild_dir)
|
||||
commands.getoutput("rm -rf %s" % self.rpmbuild_dir)
|
||||
else:
|
||||
print("WARNING: Leaving rpmbuild files in: %s" % self.rpmbuild_dir)
|
||||
|
||||
def _check_build_dirs_access(self):
|
||||
"""
|
||||
Ensure the build directories are writable.
|
||||
"""
|
||||
if not os.access(self.rpmbuild_basedir, os.W_OK):
|
||||
error_out("%s is not writable." % self.rpmbuild_basedir)
|
||||
if not os.access(self.rpmbuild_dir, os.W_OK):
|
||||
error_out("%s is not writable." % self.rpmbuild_dir)
|
||||
if not os.access(self.rpmbuild_sourcedir, os.W_OK):
|
||||
error_out("%s is not writable." % self.rpmbuild_sourcedir)
|
||||
if not os.access(self.rpmbuild_builddir, os.W_OK):
|
||||
error_out("%s is not writable." % self.rpmbuild_builddir)
|
||||
|
||||
def _create_build_dirs(self):
|
||||
"""
|
||||
Create the build directories. Can safely be called multiple times.
|
||||
"""
|
||||
commands.getoutput("mkdir -p %s %s %s %s" % (
|
||||
self.rpmbuild_basedir, self.rpmbuild_dir,
|
||||
self.rpmbuild_sourcedir, self.rpmbuild_builddir))
|
||||
self._check_build_dirs_access()
|
||||
|
||||
def _setup_test_specfile(self):
|
||||
if self.test and not self.ran_setup_test_specfile:
|
||||
# If making a test rpm we need to get a little crazy with the spec
|
||||
|
@ -640,7 +658,7 @@ class CvsBuilder(NoTgzBuilder):
|
|||
# Should only be one rpm returned for srpm:
|
||||
self.srpm_location = rpms[0]
|
||||
|
||||
def _rpm(self):
|
||||
def rpm(self):
|
||||
# Lookup the architecture of the system for the correct make target:
|
||||
arch = run_command("uname -i")
|
||||
self._cvs_rpm_common(target=arch, all_branches=True)
|
||||
|
@ -979,7 +997,7 @@ class MockBuilder(Builder):
|
|||
self.srpm_location = self.normal_builder.srpm_location
|
||||
self.artifacts.append(self.srpm_location)
|
||||
|
||||
def _rpm(self):
|
||||
def rpm(self):
|
||||
"""
|
||||
Uses the SRPM
|
||||
Override the base builder rpm method.
|
||||
|
@ -1042,7 +1060,7 @@ class BrewDownloadBuilder(Builder):
|
|||
self.brew_tag = 'meow' # args['brewtag']
|
||||
self.dist_tag = args['disttag']
|
||||
|
||||
def _rpm(self):
|
||||
def rpm(self):
|
||||
"""
|
||||
Uses the SRPM
|
||||
Override the base builder rpm method.
|
||||
|
@ -1077,55 +1095,67 @@ class BrewDownloadBuilder(Builder):
|
|||
print
|
||||
|
||||
|
||||
class ExternalSourceBuilder(Builder):
|
||||
class ExternalSourceBuilder(ConfigObject, BuilderBase):
|
||||
"""
|
||||
Builder for packages that do not require the creation of a tarball.
|
||||
Instead sources are fetched and dynamically inserted into the spec file.
|
||||
A separate Builder class for projects whose source is not in git. Source
|
||||
is fetched via a configurable strategy, which also determines what version
|
||||
and release to insert into the spec file.
|
||||
|
||||
Cannot build past tags.
|
||||
"""
|
||||
# TODO: test only for now, setup a tagger to fetch sources and store in git annex,
|
||||
# then we can do official builds as well.
|
||||
REQUIRED_ARGS = []
|
||||
|
||||
def __init__(self, name=None, tag=None, build_dir=None,
|
||||
pkg_config=None, global_config=None, user_config=None,
|
||||
args=None, **kwargs):
|
||||
|
||||
Builder.__init__(self, name=name, tag=tag,
|
||||
build_dir=build_dir, pkg_config=pkg_config,
|
||||
global_config=global_config, user_config=user_config,
|
||||
args=args, **kwargs)
|
||||
BuilderBase.__init__(self, name=name, build_dir=build_dir,
|
||||
pkg_config=pkg_config, global_config=global_config,
|
||||
user_config=user_config, args=args, **kwargs)
|
||||
|
||||
print os.getcwd()
|
||||
# Project directory where we started this build:
|
||||
self.pkg_dir = os.getcwd()
|
||||
|
||||
# When syncing files with CVS, copy everything from git:
|
||||
self.cvs_copy_extensions = ("", )
|
||||
self.build_tag = '%s-%s' % (self.project_name,
|
||||
get_spec_version_and_release(self.pkg_dir,
|
||||
'%s.spec' % self.project_name))
|
||||
|
||||
def tgz(self):
|
||||
""" Override parent behavior, we already have a tgz. """
|
||||
# TODO: Does it make sense to allow user to create a tgz for this type
|
||||
# of project?
|
||||
self._setup_sources()
|
||||
self.ran_tgz = True
|
||||
self._create_build_dirs()
|
||||
|
||||
debug("Scanning for sources.")
|
||||
print("Fetching sources...")
|
||||
|
||||
# Copy the live spec from our starting location. Unlike most builders,
|
||||
# we are not using a copy from a past git commit.
|
||||
self.spec_file = os.path.join(self.rpmbuild_sourcedir,
|
||||
'%s.spec' % self.project_name)
|
||||
shutil.copyfile(
|
||||
os.path.join(self.pkg_dir, '%s.spec' % self.project_name),
|
||||
self.spec_file)
|
||||
print(" %s.spec" % self.project_name)
|
||||
|
||||
# TODO: Make this a configurable strategy:
|
||||
|
||||
files_in_src_dir = [f for f in os.listdir(self.pkg_dir) \
|
||||
if os.path.isfile(os.path.join(self.pkg_dir, f)) ]
|
||||
print files_in_src_dir
|
||||
for f in files_in_src_dir:
|
||||
shutil.copyfile(os.path.join(self.pkg_dir, f),
|
||||
os.path.join(self.rpmbuild_sourcedir, f))
|
||||
# Copy every normal file in the directory we ran tito from. This
|
||||
# will pick up any sources that were sitting around locally.
|
||||
# TODO: how to copy only sources?
|
||||
cmd = "/usr/bin/spectool --list-files '%s' | awk '{print $2}' |xargs -l1 --no-run-if-empty basename " % self.spec_file
|
||||
result = run_command(cmd)
|
||||
self.sources = map(lambda x: os.path.join(self.rpmbuild_gitcopy, x), result.split("\n"))
|
||||
debug(" Sources: %s" % self.sources)
|
||||
self.sources = map(lambda x: os.path.join(self.rpmbuild_sourcedir, x), result.split("\n"))
|
||||
print(" Sources: %s" % self.sources)
|
||||
|
||||
def _get_rpmbuild_dir_options(self):
|
||||
"""
|
||||
Override parent behavior slightly.
|
||||
|
||||
These packages store tar's, patches, etc, directly in their project
|
||||
dir, use the git copy we create as the sources directory when
|
||||
building package so everything can be found:
|
||||
"""
|
||||
return ('--define "_sourcedir %s" --define "_builddir %s" '
|
||||
'--define "_srcrpmdir %s" --define "_rpmdir %s" ' % (
|
||||
self.rpmbuild_gitcopy, self.rpmbuild_builddir,
|
||||
self.rpmbuild_sourcedir, self.rpmbuild_builddir,
|
||||
self.rpmbuild_basedir, self.rpmbuild_basedir))
|
||||
|
||||
def _setup_test_specfile(self):
|
||||
|
@ -1155,7 +1185,7 @@ class ExternalSourceBuilder(Builder):
|
|||
if self.build_tag:
|
||||
build_version = self.build_tag[len(self.project_name + "-"):]
|
||||
else:
|
||||
build_version = get_latest_tagged_version(package_name)
|
||||
build_version = get_latest_tagged_version(self.project_name)
|
||||
if build_version == None:
|
||||
pass
|
||||
self.build_tag = "%s-%s" % (self.project_name, build_version)
|
||||
|
@ -1168,15 +1198,11 @@ class ExternalSourceBuilder(Builder):
|
|||
"""
|
||||
Get the package display version to build.
|
||||
|
||||
Normally this is whatever is rel-eng/packages/. In the case of a --test
|
||||
build it will be the SHA1 for the HEAD commit of the current git
|
||||
branch.
|
||||
Taken from source files?
|
||||
"""
|
||||
if self.test:
|
||||
# should get latest commit for given directory *NOT* HEAD
|
||||
latest_commit = get_latest_commit(".")
|
||||
self.commit_count = get_commit_count(self.build_tag, latest_commit)
|
||||
version = "git-%s.%s" % (self.commit_count, latest_commit[:7])
|
||||
self.commit_count = 15000
|
||||
version = "testing-100.100"
|
||||
else:
|
||||
version = self.build_version.split("-")[0]
|
||||
return version
|
||||
|
|
|
@ -219,16 +219,6 @@ def run_command(command, print_on_success=False):
|
|||
when command succeeds.
|
||||
"""
|
||||
(status, output) = commands.getstatusoutput(command)
|
||||
if status > 0:
|
||||
sys.stderr.write("\n########## ERROR ############\n")
|
||||
sys.stderr.write("Error running command: %s\n" % command)
|
||||
sys.stderr.write("Status code: %s\n" % status)
|
||||
sys.stderr.write("Command output: %s\n" % output)
|
||||
raise RunCommandException("Error running command", command, status, output)
|
||||
elif print_on_success:
|
||||
sys.stderr.write("Command: %s\n" % command)
|
||||
sys.stderr.write("Status code: %s\n" % status)
|
||||
sys.stderr.write("Command output: %s\n" % output)
|
||||
return output
|
||||
|
||||
|
||||
|
@ -627,3 +617,20 @@ def increase_zstream(release_string):
|
|||
regex = re.compile(r"^(.*%{\?dist})$")
|
||||
bumped_string = regex.sub(r"\g<1>.0", release_string)
|
||||
return increase_version(bumped_string)
|
||||
|
||||
|
||||
def find_wrote_in_rpmbuild_output(output):
|
||||
"""
|
||||
Parse the output from rpmbuild looking for lines beginning with
|
||||
"Wrote:". Return a list of file names for each path found.
|
||||
"""
|
||||
paths = []
|
||||
look_for = "Wrote: "
|
||||
for line in output.split("\n"):
|
||||
if line.startswith(look_for):
|
||||
paths.append(line[len(look_for):])
|
||||
debug("Found wrote line: %s" % paths[-1])
|
||||
if not paths:
|
||||
error_out("Unable to locate 'Wrote: ' lines in rpmbuild output")
|
||||
return paths
|
||||
|
||||
|
|
|
@ -413,7 +413,8 @@ class VersionTagger(ConfigObject):
|
|||
out_f.close()
|
||||
shutil.move(self.spec_file + ".new", self.spec_file)
|
||||
|
||||
new_version = self._get_spec_version_and_release()
|
||||
new_version = get_spec_version_and_release(self.full_project_dir,
|
||||
self.spec_file_name)
|
||||
if new_version.strip() == "":
|
||||
msg = "Error getting bumped package version, try: \n"
|
||||
msg = msg + " 'rpm -q --specfile %s'" % self.spec_file
|
||||
|
@ -526,11 +527,6 @@ class VersionTagger(ConfigObject):
|
|||
email = None
|
||||
return (name, email)
|
||||
|
||||
def _get_spec_version_and_release(self):
|
||||
""" Get the package version from the spec file. """
|
||||
return get_spec_version_and_release(self.full_project_dir,
|
||||
self.spec_file_name)
|
||||
|
||||
def _get_new_tag(self, new_version):
|
||||
""" Returns the actual tag we'll be creating. """
|
||||
suffix = ""
|
||||
|
|
|
@ -12,11 +12,11 @@
|
|||
# granted to use or replicate Red Hat trademarks that are incorporated
|
||||
# in this software or its documentation.
|
||||
|
||||
import os
|
||||
import unittest
|
||||
|
||||
import git
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
import unittest
|
||||
|
||||
from tito.cli import CLI
|
||||
from tito.common import run_command
|
||||
|
@ -128,12 +128,33 @@ class TitoGitTestFixture(unittest.TestCase):
|
|||
index.add(['rel-eng/tito.props'])
|
||||
index.commit('Setting offline.')
|
||||
|
||||
def tearDown(self):
|
||||
#shutil.rmtree(self.repo_dir)
|
||||
pass
|
||||
|
||||
def write_file(self, path, contents):
|
||||
print path
|
||||
out_f = open(path, 'w')
|
||||
out_f.write(contents)
|
||||
out_f.close()
|
||||
|
||||
def create_project_from_spec(self, pkg_name, pkg_dir='', spec=None,
|
||||
builder=None):
|
||||
"""
|
||||
Create a sample tito project and copy the given test spec file over.
|
||||
"""
|
||||
full_pkg_dir = os.path.join(self.repo_dir, pkg_dir)
|
||||
run_command('mkdir -p %s' % full_pkg_dir)
|
||||
os.chdir(full_pkg_dir)
|
||||
|
||||
shutil.copyfile(spec, os.path.join(full_pkg_dir, os.path.basename(spec)))
|
||||
|
||||
if builder:
|
||||
tito_props_f = open(os.path.join(full_pkg_dir, 'tito.props'), 'w')
|
||||
tito_props_f.write('[buildconfig]\n')
|
||||
tito_props_f.write('builder = %s' % builder)
|
||||
tito_props_f.close()
|
||||
|
||||
def create_project(self, pkg_name, pkg_dir=''):
|
||||
"""
|
||||
Create a test project at the given location, assumed to be within
|
||||
|
|
|
@ -59,6 +59,39 @@ module Iteng
|
|||
end
|
||||
"""
|
||||
|
||||
EXT_SRC_PKG = "extsrc"
|
||||
|
||||
class ExternalSourceBuilderTests(TitoGitTestFixture):
|
||||
|
||||
def setUp(self):
|
||||
TitoGitTestFixture.setUp(self)
|
||||
self.pkg_dir = os.path.join(self.repo_dir, EXT_SRC_PKG)
|
||||
spec = os.path.join(os.path.dirname(__file__), "specs/extsrc.spec")
|
||||
self.create_project_from_spec(EXT_SRC_PKG, pkg_dir=self.pkg_dir,
|
||||
spec=spec,
|
||||
builder='tito.builder.ExternalSourceBuilder')
|
||||
run_command('touch %s/extsrc-0.0.1.tar.gz' % self.pkg_dir)
|
||||
os.chdir(self.pkg_dir)
|
||||
|
||||
self.output_dir = tempfile.mkdtemp("-titotestoutput")
|
||||
|
||||
def tearDown(self):
|
||||
TitoGitTestFixture.tearDown(self)
|
||||
#shutil.rmtree(self.output_dir)
|
||||
|
||||
def test_simple_build_no_tag(self):
|
||||
# We have not tagged here. Build --rpm should just work:
|
||||
self.assertFalse(os.path.exists(
|
||||
os.path.join(self.pkg_dir, 'rel-eng/packages/extsrc')))
|
||||
tito('build --rpm --output=%s --no-cleanup' % self.output_dir)
|
||||
self.assertTrue(os.path.exists(
|
||||
os.path.join(self.output_dir, 'extsrc-0.0.1-1.fc20.src.rpm')))
|
||||
self.assertTrue(os.path.exists(
|
||||
os.path.join(self.output_dir, 'noarch/extsrc-0.0.1-1.fc20.noarch.rpm')))
|
||||
|
||||
# test_tag_rejected
|
||||
|
||||
|
||||
class MultiProjectTests(TitoGitTestFixture):
|
||||
|
||||
def setUp(self):
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
# in this software or its documentation.
|
||||
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from tito.common import *
|
||||
from fixture import TitoGitTestFixture, tito
|
||||
|
||||
|
@ -30,10 +28,6 @@ class SingleProjectTests(TitoGitTestFixture):
|
|||
self.create_project(PKG_NAME)
|
||||
os.chdir(self.repo_dir)
|
||||
|
||||
def tearDown(self):
|
||||
shutil.rmtree(self.repo_dir)
|
||||
pass
|
||||
|
||||
def test_init_worked(self):
|
||||
# Not actually running init here, just making sure it worked when
|
||||
# run during setup.
|
||||
|
|
32
test/functional/specs/extsrc.spec
Normal file
32
test/functional/specs/extsrc.spec
Normal file
|
@ -0,0 +1,32 @@
|
|||
%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
|
||||
|
||||
Name: extsrc
|
||||
Version: 0.0.1
|
||||
Release: 1%{?dist}
|
||||
Summary: tito test package for the external source builder
|
||||
URL: https://example.com
|
||||
Group: Applications/Internet
|
||||
License: GPLv2
|
||||
BuildRoot: %{_tmppath}/%{name}-root-%(%{__id_u} -n)
|
||||
BuildArch: noarch
|
||||
Source0: %{name}-%{version}.tar.gz
|
||||
|
||||
%description
|
||||
Nobody cares.
|
||||
|
||||
%prep
|
||||
|
||||
%build
|
||||
|
||||
%install
|
||||
rm -rf %{buildroot}
|
||||
|
||||
%clean
|
||||
rm -rf %{buildroot}
|
||||
|
||||
%files
|
||||
%defattr(-,root,root)
|
||||
#%dir %{python_sitelib}/%{name}
|
||||
#%{python_sitelib}/%{name}-*.egg-info
|
||||
|
||||
%changelog
|
Loading…
Add table
Reference in a new issue