mirror of
https://github.com/openbsd/ports.git
synced 2026-06-17 23:13:55 +02:00
Add cabal port update tool
Add update-cabal-port to help maintain cabal ports. The Perl script uses cabal database to fetch versions and generates cabal.inc files with dependency manifests. OK kn@
This commit is contained in:
Executable
+170
@@ -0,0 +1,170 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
# Update a cabal port to a new version
|
||||
#
|
||||
# Usage: update-cabal-port.pl <port-directory> [options]
|
||||
#
|
||||
# Options:
|
||||
# --version <ver> Update to specific version (default: latest from Hackage)
|
||||
# --package Run 'make package' after update
|
||||
# --help Show this help message
|
||||
#
|
||||
|
||||
use v5.36;
|
||||
use Getopt::Long qw(:config no_ignore_case);
|
||||
|
||||
sub usage($exit_code = 0) {
|
||||
open my $fh, '<', $0 or die "Cannot read $0: $!\n";
|
||||
while (<$fh>) {
|
||||
last if /^$/;
|
||||
next unless s/^# ?//;
|
||||
print;
|
||||
}
|
||||
exit $exit_code;
|
||||
}
|
||||
|
||||
my %opt = (version => '', package => 0, help => 0);
|
||||
|
||||
GetOptions(
|
||||
'version=s' => \$opt{version},
|
||||
'package' => \$opt{package},
|
||||
'help|h' => \$opt{help},
|
||||
) or usage(1);
|
||||
|
||||
usage(0) if $opt{help};
|
||||
|
||||
my $port_dir = shift @ARGV or do { say STDERR "Error: Port directory required"; usage(1) };
|
||||
|
||||
chdir $port_dir or die "Cannot chdir to $port_dir: $!\n";
|
||||
|
||||
# Extract configuration via make show=
|
||||
my $stem = make_show('MODCABAL_STEM') or die "MODCABAL_STEM not set\n";
|
||||
my $current_version = make_show('MODCABAL_VERSION');
|
||||
my $executables = make_show('MODCABAL_EXECUTABLES');
|
||||
|
||||
# Determine target version
|
||||
my $target_version = $opt{version} || get_latest_version($stem);
|
||||
die "Error: Could not determine version for $stem\n" unless $target_version;
|
||||
|
||||
if ($current_version && $current_version eq $target_version) {
|
||||
say "==> $port_dir: already at $target_version";
|
||||
exit 0;
|
||||
}
|
||||
|
||||
say "==> $port_dir: $current_version -> $target_version";
|
||||
|
||||
# Build cabal-bundler command
|
||||
my @bundler_args = ('--openbsd', "$stem-$target_version");
|
||||
if ($executables) {
|
||||
my $exec = $executables =~ s/\$\{[^}]+\}//gr;
|
||||
$exec =~ s/^\s+|\s+$//g;
|
||||
if ($exec) {
|
||||
push @bundler_args, '--executable', $_ for split /\s+/, $exec;
|
||||
}
|
||||
}
|
||||
|
||||
my $bundler_cmd = "cabal-bundler " . join(' ', @bundler_args);
|
||||
my $output = `$bundler_cmd 2>&1`;
|
||||
die "$bundler_cmd failed:\n$output\n" if $?;
|
||||
|
||||
# Parse cabal-bundler output for MODCABAL_MANIFEST and MODCABAL_REVISION
|
||||
my (@deps, $revision);
|
||||
my $in_manifest = 0;
|
||||
for (split /\n/, $output) {
|
||||
if (/^MODCABAL_REVISION\s*=\s*(\d+)/) {
|
||||
$revision = $1;
|
||||
} elsif (/^MODCABAL_MANIFEST\s*=\s*(.*)/) {
|
||||
$in_manifest = 1;
|
||||
push @deps, extract_deps($1);
|
||||
} elsif ($in_manifest && /^\s+(.*)/) {
|
||||
push @deps, extract_deps($1);
|
||||
$in_manifest = 0 unless /\\$/;
|
||||
} else {
|
||||
$in_manifest = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (@deps) {
|
||||
open my $fh, '>', 'cabal.inc' or die "Cannot write cabal.inc: $!\n";
|
||||
say $fh "MODCABAL_MANIFEST\t= \\";
|
||||
while (@deps >= 3) {
|
||||
my ($pkg, $ver, $rev) = splice(@deps, 0, 3);
|
||||
if (@deps) {
|
||||
say $fh "\t$pkg\t$ver\t$rev\t\\";
|
||||
} else {
|
||||
say $fh "\t$pkg\t$ver\t$rev";
|
||||
}
|
||||
}
|
||||
close $fh;
|
||||
}
|
||||
|
||||
# Update Makefile: set MODCABAL_VERSION, MODCABAL_REVISION, remove REVISION
|
||||
open my $in, '<', 'Makefile' or die "Cannot read Makefile: $!\n";
|
||||
my @lines = <$in>;
|
||||
close $in;
|
||||
|
||||
my $found_version = 0;
|
||||
my $found_revision = 0;
|
||||
for (@lines) {
|
||||
if (/^MODCABAL_VERSION\s*=/) {
|
||||
$_ = "MODCABAL_VERSION =\t$target_version\n";
|
||||
$found_version = 1;
|
||||
} elsif (/^MODCABAL_REVISION\s*=/) {
|
||||
if (defined $revision) {
|
||||
$_ = "MODCABAL_REVISION =\t$revision\n";
|
||||
} else {
|
||||
$_ = ''; # Remove if no revision in new version
|
||||
}
|
||||
$found_revision = 1;
|
||||
} elsif (/^REVISION\s*=/) {
|
||||
$_ = ''; # Remove REVISION on update
|
||||
}
|
||||
}
|
||||
|
||||
# Add MODCABAL_REVISION after MODCABAL_VERSION if needed
|
||||
if (defined $revision && !$found_revision) {
|
||||
for my $i (0..$#lines) {
|
||||
if ($lines[$i] =~ /^MODCABAL_VERSION\s*=/) {
|
||||
splice @lines, $i+1, 0, "MODCABAL_REVISION =\t$revision\n";
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open my $out, '>', 'Makefile' or die "Cannot write Makefile: $!\n";
|
||||
print $out grep { $_ ne '' } @lines;
|
||||
close $out;
|
||||
|
||||
# Run make makesum
|
||||
system('make', 'makesum') == 0 or die "make makesum failed\n";
|
||||
|
||||
# Run make package
|
||||
if ($opt{package}) {
|
||||
system('make', 'clean=all') == 0 or warn "make clean failed\n";
|
||||
system('make', 'package') == 0 or warn "make package failed\n";
|
||||
}
|
||||
|
||||
#
|
||||
# Helpers
|
||||
#
|
||||
|
||||
sub make_show($var) {
|
||||
my $val = `make show=$var`;
|
||||
die "make show=$var failed\n" if $?;
|
||||
chomp $val;
|
||||
return $val eq '' ? undef : $val;
|
||||
}
|
||||
|
||||
sub get_latest_version($package) {
|
||||
my $output = `cabal list --simple-output '^$package\$' 2>/dev/null`;
|
||||
return unless $? == 0 && $output;
|
||||
|
||||
my @lines = split /\n/, $output;
|
||||
return $1 if @lines && $lines[-1] =~ /^\Q$package\E\s+(\S+)$/i;
|
||||
return;
|
||||
}
|
||||
|
||||
sub extract_deps($line) {
|
||||
$line =~ s/\s*\\$//;
|
||||
return split /\s+/, $line;
|
||||
}
|
||||
Reference in New Issue
Block a user