diff --git a/BuildUtils.pm b/BuildUtils.pm index c76200adc..fe3f3e2fd 100644 --- a/BuildUtils.pm +++ b/BuildUtils.pm @@ -32,7 +32,7 @@ our @EXPORT_OK = qw( sh_quote clean_debian_residue git_revision backup_file restore_file sh usage - read_file write_file rewrite_file + read_file write_file rewrite_file write_script buildinfo_text ); @@ -84,6 +84,17 @@ sub write_file { return; } +# Write a helper script and make it executable. Both builders ship a +# mklocalrepo.sh beside the packages they publish; a script written without the +# executable bit is published broken, so the mode is not left to the caller to +# remember. +sub write_script { + my ($path, $content) = @_; + write_file($path, $content); + chmod 0775, $path or die "Cannot chmod $path: $!\n"; + return; +} + # Read a file, pass its contents through $transform, write the result back. # A file that is not there is left alone, which is what every caller wanted. sub rewrite_file { diff --git a/builddebs.pl b/builddebs.pl index e4da5aaf5..c3a7d8637 100755 --- a/builddebs.pl +++ b/builddebs.pl @@ -36,7 +36,7 @@ use BuildUtils qw( pin_control_version rewrite_changelog_header reprepro_distributions reprepro_options lock_id_for take_build_lock sh_quote - sh usage read_file write_file rewrite_file buildinfo_text + sh usage read_file write_file rewrite_file write_script buildinfo_text ); # The xcat-core packages that ship as debs. xCAT-openbmc-py, xCAT-rmc and xCAT-release @@ -323,8 +323,7 @@ sub write_repo_metadata { my ($repodir) = @_; # Point apt at this directory, for a locally built repo. - open my $m, '>', "$repodir/mklocalrepo.sh" or die "Cannot write mklocalrepo.sh: $!\n"; - print {$m} <<'SCRIPT'; + write_script("$repodir/mklocalrepo.sh", <<'SCRIPT'); . /etc/lsb-release cd `dirname $0` host_arch=`uname -m` @@ -335,8 +334,6 @@ else fi echo deb [arch=$host_arch] file://"`pwd`" $DISTRIB_CODENAME main > /etc/apt/sources.list.d/xcat-core.list SCRIPT - close $m; - chmod 0775, "$repodir/mklocalrepo.sh"; write_file("$repodir/buildinfo", buildinfo_text( version => $VERSION, release => $RELEASE, epoch => $EPOCH, diff --git a/buildrpms.pl b/buildrpms.pl index 519d2f3a0..ed856c54d 100755 --- a/buildrpms.pl +++ b/buildrpms.pl @@ -43,7 +43,7 @@ use File::Slurper qw(read_text write_text); use File::Temp qw(tempdir tempfile); use FindBin qw($Bin); use lib $Bin; -use BuildUtils qw(git_revision source_date_epoch sh usage buildinfo_text); +use BuildUtils qw(git_revision source_date_epoch sh usage buildinfo_text write_script); use Fcntl qw(:flock); # per-target build lock (concurrency guard; see main()) use Getopt::Long qw(GetOptions); use POSIX qw(strftime); @@ -787,7 +787,7 @@ gpgcheck=$gpgcheck $gpgkey_line EOF - write_text("$repodir/mklocalrepo.sh", <<'EOF2'); + write_script("$repodir/mklocalrepo.sh", <<'EOF2'); #!/bin/sh cd `dirname $0` REPOFILE=`basename xcat-*.repo` @@ -808,7 +808,6 @@ if [ -f "$DIRECTORY/xCAT-core.repo" ]; then fi cd - EOF2 - chmod 0775, "$repodir/mklocalrepo.sh"; # BUILD_TIME from SOURCE_DATE_EPOCH keeps buildinfo reproducible across rebuilds. write_text("$repodir/buildinfo.txt", buildinfo_text( diff --git a/xCAT-test/unit/build_utils.t b/xCAT-test/unit/build_utils.t index 35a86d111..1d1a53609 100644 --- a/xCAT-test/unit/build_utils.t +++ b/xCAT-test/unit/build_utils.t @@ -358,6 +358,23 @@ isnt( git_revision( git => sub { '' }, read_file => sub { '' } ), '', 'reading a missing file names the file it could not read' ); } +# ------------------------------------------------- the published helper script -- +# Both builders ship a mklocalrepo.sh next to the packages they publish, and each +# used to write it and chmod it as two separate steps. A copy that is written but +# left non-executable is published broken, so the mode is asserted here rather +# than trusted to each caller. +{ + my $dir = tempdir(CLEANUP => 1); + my $path = File::Spec->catfile($dir, 'mklocalrepo.sh'); + + BuildUtils::write_script($path, "#!/bin/sh\necho hello\n"); + is( BuildUtils::read_file($path), "#!/bin/sh\necho hello\n", + 'a helper script keeps the exact text it was given' ); + ok( -x $path, 'and is executable, which is the point of writing it this way' ); + is( (stat $path)[2] & 07777, 0775, + 'with the mode both builders published before' ); +} + # ---------------------------------------------------------------- sh() -- # system() returns the raw wait status, which is the exit code times 256. The # two builders disagreed about shifting it, so a caller comparing sh() against