#!/usr/bin/perl use v5.012; use strict; use warnings; use Cwd 'abs_path'; use POSIX ':sys_wait_h'; sub find_ports($); sub process_port($ $ $); MAIN: { my ($base, $tgt) = ('.', '/usr/ports'); my @ports = find_ports $base; say '===> Processing '.scalar(@ports)." ports:". join '', map "\n $_", sort @ports; process_port $_, $base, $tgt for @ports; } sub find_ports($) { my ($base) = @_; my @res; opendir my $db, $base or die "opendir($base): $!\n"; while (my $d = readdir $db) { next if $d eq '.' || $d eq '..'; chdir $db or die "chdir($base): $!\n"; next unless -d $d; opendir my $ds, $d or die "opendir($base/$d): $!\n"; while (my $p = readdir $ds) { next if $p eq '.' || $p eq '..'; chdir $ds or die "chdir($base/$d): $!\n"; next unless -d $p && -f "$p/Makefile" && -f "$p/pkg-plist"; push @res, "$d/$p"; } closedir $ds or die "closedir($base/$d): $!\n"; } closedir $db or die "closedir($base): $!\n"; return @res; } sub process_port($ $ $) { my ($port, $base, $tgt) = @_; my ($basename, $tgtname) = ("$base/$port", "$tgt/$port"); my $baseabs = abs_path($basename); say "\n===> $port: $basename -> $tgtname"; if (-l $tgtname) { my $lname = readlink $tgtname or die "readlink($tgtname): $!\n"; if (abs_path($lname) ne $baseabs) { die "FIXME: remove $tgtname to be replaced by a symlink to $baseabs"; } else { say "just fine: $tgtname is a symlink to $baseabs"; } } elsif (-d $tgtname) { my @cmd = ('rsync', '-av', '--delete', '--', "$baseabs/", "$tgtname/"); my $res = system { $cmd[0] } @cmd; if (!WIFEXITED($res) || WEXITSTATUS($res) != 0) { die "@cmd failed\n"; } say "just fine: rsynced $baseabs to $tgtname successfully"; } elsif (-e $tgtname) { unlink $tgtname or die "unlink($tgtname): $!\n"; } if (! -e $tgtname) { say "creating a symlink: $baseabs -> $tgtname"; symlink $baseabs, $tgtname or die "symlink($baseabs, $tgtname): $!\n"; } }