#!/usr/bin/perl use strict; use warnings; use IPC::Open2; use URI; sub FindFactoryCommit { my ($package) = @_; # Execute osc cat and capture output my $osc_cmd = "osc cat openSUSE:Factory $package $package.changes"; open( my $osc_fh, "$osc_cmd |" ) or die "Failed to run osc: $!"; my $data = do { local $/; <$osc_fh> }; close($osc_fh); # Calculate size my $size = length($data); # Create blob header my $blob = "blob $size\0$data"; # Open a pipe to openssl to compute the hash my ( $reader, $writer ); my $pid = open2( $reader, $writer, "openssl sha256" ); # Send blob data print $writer $blob; close $writer; # Read the hash result and extract it my $hash_line = <$reader>; waitpid( $pid, 0 ); my ($hash) = $hash_line =~ /([a-fA-F0-9]{64})/; # Run git search command with the hash print("looking for hash: $hash\n"); my @hashes; my $git_cmd = "git -C $package rev-list --all pool/HEAD | while read commit; do git -C $package ls-tree \"\$commit\" | grep -q '^100644 blob $hash' && echo \"\$commit\"; done"; open( my $git_fh, "$git_cmd |" ) or die "Failed to run git search: $!"; while ( my $commit = <$git_fh> ) { chomp $commit; print "Found commit $commit\n"; push( @hashes, $commit ); } close($git_fh); return @hashes; } sub FactoryMd5 { my ($package) = @_; my $out = ""; if (system("osc ls openSUSE:Factory $package | grep -q build.specials.obscpio") == 0) { system("mkdir _extract") == 0 || die "_extract exists or can't make it. Aborting."; chdir("_extract") || die; system("osc cat openSUSE:Factory $package build.specials.obscpio | cpio -dium 2> /dev/null") == 0 || die; system("rm .* 2> /dev/null"); open( my $fh, "find -type f -exec /usr/bin/basename {} \\; | xargs md5sum | awk '{print \$1 FS \$2}' | grep -v d41d8cd98f00b204e9800998ecf8427e |") or die; while ( my $l = <$fh>) { $out = $out.$l; } close($fh); chdir("..") && system("rm -rf _extract") == 0 || die; } open( my $fh, "osc ls -v openSUSE:Factory $package | awk '{print \$1 FS \$7}' | grep -v -F '_scmsync.obsinfo\nbuild.specials.obscpio' |") or die; while (my $l = <$fh>) { $out = $out.$l; } close($fh); return $out; } # Read project from first argument sub Usage { die "Usage: $0 "; } my $project = shift or Usage(); my $pkg = shift; my $repo = shift; if (not defined($repo)) { Usage(); } my $meta_url = `osc meta pkg $project $pkg | grep scmsync | sed -e 's,\\s*\\s*,,g'`; chomp($meta_url); if ($meta_url ne $repo) { die "meta not equal to repo for $pkg: $meta_url != $repo"; } my $u = URI->new($meta_url); die "Only src.opensuse.org is supported" unless $u->scheme =~ /^https?$/ && $u->host eq 'src.opensuse.org'; my (undef, $org, $repo_path) = split('/', $u->path); my $branch = $u->fragment; die "Only src.opensuse.org is supported" unless $org; if ($org eq "pool") { print "Already a pool package. We are done.\n"; exit(0); } my %params = $u->query_form; delete $params{trackingbranch}; die "Unsupported query parameters: " . join(', ', keys %params) if keys %params; my @packages = ($pkg) if defined $pkg; if ( ! -e $org ) { mkdir($org); } chdir($org); my $super_user = $ENV{SUPER}; if (defined($super_user)) { $super_user = "-G $super_user"; } else { $super_user = ""; } for my $package ( sort(@packages) ) { print " ----- PROCESSING $package\n"; my $url = "https://src.opensuse.org/$org/$repo_path.git"; my $push_url = "gitea\@src.opensuse.org:pool/$package.git"; if ( not -e $package ) { print("cloning...\n"); system("git clone --origin pool $url $package") == 0 or die "Can't clone $org/$repo_path"; } else { print("adding remote...\n"); system("git -C $package remote rm pool > /dev/null"); system("git -C $package remote add pool $url") == 0 or die "Can't add pool for $package"; } system("git -C $package remote set-url pool --push $push_url") == 0 or die "Can't add push remote for $package"; print("fetching remote...\n"); system("git -C $package fetch pool") == 0 or die "Can't fetch pool for $package"; my @commits = FindFactoryCommit($package); my $Md5Hashes = FactoryMd5($package); my $c; my $match = 0; for my $commit (@commits) { if ( length($commit) != 64 ) { print("Failed to find factory commit. Aborting."); exit(1); } if ( system("git -C $package lfs fetch pool $commit") == 0 and system("git -C $package checkout -B factory $commit") == 0 and system("git -C $package lfs checkout") == 0 and chdir($package)) { open(my $fh, "|-", "md5sum -c --quiet") or die $!; print $fh $Md5Hashes; close $fh; if ($? >> 8 != 0) { chdir("..") || die; next; } open($fh, "|-", "awk '{print \$2}' | sort | bash -c \"diff <(ls -1 | sort) -\"") or die $!; print $fh $Md5Hashes; close $fh; my $ec = $? >> 8; chdir("..") || die; if ($ec == 0) { $c = $commit; $match = 1; last; } } } if ( !$match ) { die "Match not found. Aborting."; } system ("git -C $package push -f pool factory"); print "$package: $c\n"; }