diff --git a/src/tito/builder.py b/src/tito/builder.py index 4acfe40..5d30c66 100644 --- a/src/tito/builder.py +++ b/src/tito/builder.py @@ -1116,12 +1116,17 @@ class ExternalSourceBuilder(ConfigObject, BuilderBase): user_config=user_config, args=args, **kwargs) # Project directory where we started this build: - self.pkg_dir = os.getcwd() + self.start_dir = os.getcwd() self.build_tag = '%s-%s' % (self.project_name, - get_spec_version_and_release(self.pkg_dir, + get_spec_version_and_release(self.start_dir, '%s.spec' % self.project_name)) + # Assuming we're still in the start directory, get the absolute path + # to all sources specified: + self.manual_sources = [os.path.abspath(s) for s in kwargs['sources']] + debug("Got sources: %s" % self.manual_sources) + def tgz(self): self.ran_tgz = True self._create_build_dirs() @@ -1133,24 +1138,66 @@ class ExternalSourceBuilder(ConfigObject, BuilderBase): 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), + os.path.join(self.start_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)) + i = 0 + replacements = [] + for s in self.manual_sources: + base_name = os.path.basename(s) + dest_filepath = os.path.join(self.rpmbuild_sourcedir, base_name) + shutil.copyfile(s, dest_filepath) + self.sources.append(dest_filepath) + + # Add a line to replace in the spec for each source: + source_regex = re.compile("^(source%s:\s*)(.+)$" % i, re.IGNORECASE) + new_line = "Source%s: %s" % (i, base_name) + replacements.append((source_regex, new_line)) + + # Replace version and release in spec: + version_regex = re.compile("^(version:\s*)(.+)$", re.IGNORECASE) + release_regex = re.compile("^(release:\s*)(.+)$", re.IGNORECASE) + + self.replace_in_spec(replacements) + # 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_sourcedir, x), result.split("\n")) - print(" Sources: %s" % self.sources) + #files_in_src_dir = [f for f in os.listdir(self.start_dir) \ + # if os.path.isfile(os.path.join(self.start_dir, f)) ] + #print files_in_src_dir + #for f in files_in_src_dir: + # shutil.copyfile(os.path.join(self.start_dir, f), + # os.path.join(self.rpmbuild_sourcedir, f)) + # TODO: extract version/release from filename? + # TODO: what filename? + #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_sourcedir, x), result.split("\n")) + + def replace_in_spec(self, replacements): + """ + Replace lines in the spec file using the given replacements. + + Replacements are a tuple of a regex to look for, and a new line to + substitute in when the regex matches. + + Replaces all lines with one pass through the file. + """ + in_f = open(self.spec_file, 'r') + out_f = open(self.spec_file + ".new", 'w') + for line in in_f.readlines(): + for line_regex, new_line in replacements: + match = re.match(line_regex, line) + if match: + line = new_line + out_f.write(line) + + in_f.close() + out_f.close() + shutil.move(self.spec_file + ".new", self.spec_file) def _get_rpmbuild_dir_options(self): return ('--define "_sourcedir %s" --define "_builddir %s" ' diff --git a/src/tito/cli.py b/src/tito/cli.py index d57580c..f4e4c95 100644 --- a/src/tito/cli.py +++ b/src/tito/cli.py @@ -362,6 +362,12 @@ class BuildModule(BaseCliModule): default='', metavar="COLLECTION", help="Build package for software collection.") + # TODO: this is specific to the external source builder, implement a way for builders + # to inject additional cli options if they are configured. + self.parser.add_option("--source", dest="sources", + action="append", metavar="SOURCE_FILE", + help="Manually specified source file to be replaced in spec during build.") + def main(self, argv): BaseCliModule.main(self, argv) @@ -384,6 +390,7 @@ class BuildModule(BaseCliModule): 'auto_install': self.options.auto_install, 'rpmbuild_options': self.options.rpmbuild_options, 'scl': self.options.scl, + 'sources': self.options.sources, } builder = create_builder(package_name, build_tag, diff --git a/test/functional/multiproject_tests.py b/test/functional/multiproject_tests.py index a453adc..c7f68bf 100644 --- a/test/functional/multiproject_tests.py +++ b/test/functional/multiproject_tests.py @@ -70,9 +70,12 @@ class ExternalSourceBuilderTests(TitoGitTestFixture): 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) + self.source_filename = 'extsrc-0.0.2.tar.gz' os.chdir(self.pkg_dir) + # Make a fake source file, do we need something more real? + run_command('touch %s' % self.source_filename) + self.output_dir = tempfile.mkdtemp("-titotestoutput") def tearDown(self): @@ -83,7 +86,8 @@ class ExternalSourceBuilderTests(TitoGitTestFixture): # 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) + tito('build --rpm --output=%s --no-cleanup --source=%s --debug' % + (self.output_dir, self.source_filename)) self.assertTrue(os.path.exists( os.path.join(self.output_dir, 'extsrc-0.0.1-1.fc20.src.rpm'))) self.assertTrue(os.path.exists(