From 64fdac6c79e8036f4ac7a845e9d1296e09721fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miroslav=20Such=C3=BD?= Date: Thu, 25 Nov 2010 17:57:00 +0100 Subject: [PATCH] add new build class distributionbuilder --- bin/generate-patches.pl | 139 ++++++++++++++++++++++++++++++++ setup.py | 1 + src/tito/builder.py | 69 +++++++++------- src/tito/distributionbuilder.py | 43 ++++++++++ tito.spec | 1 + 5 files changed, 223 insertions(+), 30 deletions(-) create mode 100755 bin/generate-patches.pl create mode 100644 src/tito/distributionbuilder.py diff --git a/bin/generate-patches.pl b/bin/generate-patches.pl new file mode 100755 index 0000000..714ec19 --- /dev/null +++ b/bin/generate-patches.pl @@ -0,0 +1,139 @@ +#!/usr/bin/perl + +use strict; +use warnings FATAL => 'all'; + +use Getopt::Long (); +use IPC::Open3 (); + +my $target_directory; + +sub usage { + die "Usage: $0 -d target_directory package_name start_version_release end_version_release [commit_id]\n"; +} + +sub check_git_tag { + my $tag = join_tag_parts(@_); + my ($wtr, $rdr); + + my $pid = IPC::Open3::open3($wtr, $rdr, undef, 'git', 'tag', '-l', $tag); + close($wtr); + my $check = <$rdr>; + close($rdr); + if (waitpid($pid, 0) < 0) { + die "Error checking for tag [$tag], process died: $!\n"; + } + if (not defined $check) { + return; + } + chomp $check; + if ($check eq $tag) { + return 1; + } + return; +} + +sub split_version_to_parts { + my $version = shift; + my @parts1 = split /-/, $version; + my @parts2; + for my $p (@parts1) { + push @parts2, [ split /\./, $p ]; + } + return @parts2; +} + +sub join_tag_parts { + my @parts = @_; + for my $p (@parts) { + if (ref $p) { + $p = join '.', @$p; + } + } + return join '-', @parts; +} + +if (not Getopt::Long::GetOptions('dir=s' => \$target_directory)) { + usage(); +} + +if (not defined $target_directory) { + usage(); +} + +my ($package, $start_version, $end_version, $commit_id) = @ARGV; + +if (not defined $end_version) { + usage(); +} + +if (not -d $target_directory) { + die "The target directory [$target_directory] does not exist.\n"; +} + +if (not check_git_tag($package, $start_version)) { + die "Start tag [$package-$start_version] does not exist.\n"; +} +if (not check_git_tag($package, $end_version)) { + die "End tag [$package-$end_version] does not exist.\n"; +} + +my @start_version = split_version_to_parts($start_version); +my @end_version = split_version_to_parts($end_version); + +if (@start_version != 2) { + die "Start version needs to have two segments (version-release).\n"; +} +if ("@{$start_version[1]}" ne "1") { + die "The start second segment (release) has to be 1.\n"; +} +if (@end_version < @start_version) { + die "End version needs to have the same or more segments than the start version..\n"; +} +if ("@{$start_version[0]}" ne "@{$end_version[0]}") { + die "The first segment (version) has to match.\n"; +} + +my @path; + +unshift @path, join_tag_parts($package, @end_version); +while ("@{$end_version[1]}" ne "1") { + my @release = @{$end_version[1]}; + if ($release[-1] eq '0') { + splice @release, $#release; + } elsif ($release[-1] =~ /^[0-9]+$/) { + $release[-1] -= 1; + } else { + # drop non-numerical segment + splice @release, $#release; + } + $end_version[1] = \@release; + my $tag = join_tag_parts($package, @end_version); + if (check_git_tag($tag)) { + unshift @path, $tag; + } +} + +while (@end_version > @start_version) { + splice @end_version, $#end_version; + my $tag = join_tag_parts($package, @end_version); + if (check_git_tag($tag)) { + unshift @path, $tag; + } +} + +for (my $i = 0; $i < @path - 1; $i++) { + my $patch_name = "$path[$i]-to-$path[$i + 1].patch"; + system "git diff --relative $path[$i]..$path[$i + 1] > $target_directory/$patch_name"; + print "$patch_name\n"; +} + +if (defined $commit_id) { + my $patch_name = "$path[$#path]-to-$package-git-$commit_id.patch"; + system "git diff --relative $path[$#path]..$commit_id > $target_directory/$patch_name"; + if (-s "$target_directory/$patch_name") { + print "$patch_name\n"; + } else { + unlink "$target_directory/$patch_name"; + } +} diff --git a/setup.py b/setup.py index 0d8266b..c232de4 100755 --- a/setup.py +++ b/setup.py @@ -40,6 +40,7 @@ setup( 'bin/bump-version.pl', 'bin/tar-fixup-stamp-comment.pl', 'bin/test-setup-specfile.pl', + 'bin/generate-patches.pl' ], classifiers = [ diff --git a/src/tito/builder.py b/src/tito/builder.py index 7af721d..a654190 100644 --- a/src/tito/builder.py +++ b/src/tito/builder.py @@ -933,37 +933,10 @@ class UpstreamBuilder(NoTgzBuilder): self.patch_upstream() - def patch_upstream(self): + def _patch_upstream(self): + """ Insert patches into the spec file we'll be building + returns (patch_number, patch_insert_index, patch_apply_index, lines) """ - Generate patches for any differences between our tag and the - upstream tag, and apply them into an exported copy of the - spec file. - """ - patch_filename = "%s-to-%s-%s.patch" % (self.upstream_tag, - self.project_name, self.build_version) - patch_file = os.path.join(self.rpmbuild_gitcopy, - patch_filename) - patch_dir = self.git_root - if self.relative_project_dir != "/": - patch_dir = os.path.join(self.git_root, - self.relative_project_dir) - os.chdir(patch_dir) - debug("patch dir = %s" % patch_dir) - print("Generating patch [%s]" % patch_filename) - debug("Patch: %s" % patch_file) - patch_command = "git diff --relative %s..%s > %s" % \ - (self.upstream_tag, self.git_commit_id, - patch_file) - debug("Generating patch with: %s" % patch_command) - output = run_command(patch_command) - print(output) - # Creating two copies of the patch here in the temp build directories - # just out of laziness. Some builders need sources in SOURCES and - # others need them in the git copy. Being lazy here avoids one-off - # hacks and both copies get cleaned up anyhow. - run_command("cp %s %s" % (patch_file, self.rpmbuild_sourcedir)) - - # Insert patches into the spec file we'll be building: f = open(self.spec_file, 'r') lines = f.readlines() f.close() @@ -998,11 +971,47 @@ class UpstreamBuilder(NoTgzBuilder): debug("patch_apply_index = %s" % patch_apply_index) if patch_insert_index == 0 or patch_apply_index == 0: error_out("Unable to insert PatchX or %patchX lines in spec file") + return (patch_number, patch_insert_index, patch_apply_index, lines) + + def patch_upstream(self): + """ + Generate patches for any differences between our tag and the + upstream tag, and apply them into an exported copy of the + spec file. + """ + patch_filename = "%s-to-%s-%s.patch" % (self.upstream_tag, + self.project_name, self.build_version) + patch_file = os.path.join(self.rpmbuild_gitcopy, + patch_filename) + patch_dir = self.git_root + if self.relative_project_dir != "/": + patch_dir = os.path.join(self.git_root, + self.relative_project_dir) + os.chdir(patch_dir) + debug("patch dir = %s" % patch_dir) + print("Generating patch [%s]" % patch_filename) + debug("Patch: %s" % patch_file) + patch_command = "git diff --relative %s..%s > %s" % \ + (self.upstream_tag, self.git_commit_id, + patch_file) + debug("Generating patch with: %s" % patch_command) + output = run_command(patch_command) + print(output) + # Creating two copies of the patch here in the temp build directories + # just out of laziness. Some builders need sources in SOURCES and + # others need them in the git copy. Being lazy here avoids one-off + # hacks and both copies get cleaned up anyhow. + run_command("cp %s %s" % (patch_file, self.rpmbuild_sourcedir)) + + (patch_number, patch_insert_index, patch_apply_index, lines) = self._patch_upstream() lines.insert(patch_insert_index, "Patch%s: %s\n" % (patch_number, patch_filename)) lines.insert(patch_apply_index, "%%patch%s -p1\n" % (patch_number)) + self._write_spec(lines) + def _write_spec(self, lines): + """ Write 'lines' to self.spec_file """ # Now write out the modified lines to the spec file copy: f = open(self.spec_file, 'w') for line in lines: diff --git a/src/tito/distributionbuilder.py b/src/tito/distributionbuilder.py new file mode 100644 index 0000000..ed2b996 --- /dev/null +++ b/src/tito/distributionbuilder.py @@ -0,0 +1,43 @@ +import os + +from tito.builder import UpstreamBuilder +from tito.common import debug, run_command + +class DistributionBuilder(UpstreamBuilder): + """ This class is used for building packages for distributions. + Parent class UpstreamBuilder build one big patch from upstream and create e.g.: + Patch0: foo-1.2.13-1-to-foo-1.2.13-3-sat.patch + This class create one patch per each release. E.g.: + Patch0: foo-1.2.13-1-to-foo-1.2.13-2-sat.patch + Patch1: foo-1.2.13-2-to-foo-1.2.13-3-sat.patch + """ + def __init__(self, name=None, version=None, tag=None, build_dir=None, + pkg_config=None, global_config=None, user_config=None, dist=None, + test=False, offline=False, auto_install=False, + rpmbuild_options=None): + UpstreamBuilder.__init__(self, name, version, tag, build_dir, pkg_config, + global_config, user_config, dist, test, offline, auto_install, rpmbuild_options) + self.patch_files = [] + + def patch_upstream(self): + """ Create one patch per each release """ + os.chdir(os.path.join(self.git_root, self.relative_project_dir)) + debug("Running /usr/bin/generate-patches.pl -d %s %s %s-1 %s %s" \ + % self.rpmbuild_gitcopy, self.project_name, self.upstream_version, self.build_version, self.git_commit_id) + output = run_command("/usr/bin/generate-patches.pl -d %s %s %s-1 %s %s" \ + % self.rpmbuild_gitcopy, self.project_name, self.upstream_version, self.build_version, self.git_commit_id) + self.patch_files = output.split("\n") + for p_file in self.patch_files: + run_command("cp %s/%s %s" % (self.rpmbuild_gitcopy, p_file, self.rpmbuild_sourcedir)) + + (patch_number, patch_insert_index, patch_apply_index, lines) = self._patch_upstream() + + for patch in self.patch_files: + lines.insert(patch_insert_index, "Patch%s: %s\n" % (patch_number, patch)) + lines.insert(patch_apply_index, "%%patch%s -p1\n" % (patch_number)) + patch_number += 1 + patch_insert_index += 1 + patch_apply_index += 2 + self._write_spec(lines) + + diff --git a/tito.spec b/tito.spec index 7bd36aa..cd8b58b 100644 --- a/tito.spec +++ b/tito.spec @@ -60,6 +60,7 @@ rm -rf $RPM_BUILD_ROOT %{_bindir}/bump-version.pl %{_bindir}/tar-fixup-stamp-comment.pl %{_bindir}/test-setup-specfile.pl +%{_bindir}/generate-patches.pl %dir %{python_sitelib}/tito %{python_sitelib}/tito/* %{python_sitelib}/tito-*.egg-info