71c4172171
Submitted by: eivind
481 lines
15 KiB
Perl
Executable File
481 lines
15 KiB
Perl
Executable File
#!/usr/bin/perl
|
|
#
|
|
# addport - perl script that adds new ports to the
|
|
# FreeBSD Ports Collection. Replaces easy-import.
|
|
#
|
|
# Copyright (c) 2000 Will Andrews and Michael Haro
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without
|
|
# modification, are permitted provided that the following conditions
|
|
# are met:
|
|
# 1. Redistributions of source code must retain the above copyright
|
|
# notice, this list of conditions and the following disclaimer.
|
|
# 2. Redistributions in binary form must reproduce the above copyright
|
|
# notice, this list of conditions and the following disclaimer in the
|
|
# documentation and/or other materials provided with the distribution.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
|
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
|
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
# SUCH DAMAGE.
|
|
#
|
|
# Original shell script & idea: Will Andrews <will@FreeBSD.org>
|
|
# Original conversion to Perl : Michael Haro <mharo@FreeBSD.org>
|
|
#
|
|
# Id: addport,v 1.2 2000/04/02 06:21:13 will Exp (original shell script)
|
|
# Id: addport,v 1.5 2000/04/22 22:19:43 mharo Exp (perl conversion)
|
|
# $FreeBSD$
|
|
#
|
|
# MAINTAINER= will@FreeBSD.org
|
|
#
|
|
|
|
use Cwd "abs_path";
|
|
use Getopt::Std;
|
|
use Sys::Hostname;
|
|
use locale;
|
|
use strict;
|
|
|
|
my %opts;
|
|
|
|
getopts('ac:d:fgh:il:mns:tu:', \%opts);
|
|
|
|
my $autofill = $opts{'l'};
|
|
my $c = $opts{'c'} if ($opts{'c'} ne "");
|
|
my $nomodules = $opts{'g'};
|
|
my $distdir = $opts{'s'} if ($opts{'s'} ne "");
|
|
my $dir = $opts{'d'};
|
|
my $h = "freefall.FreeBSD.org";
|
|
$h = $opts{'h'} if ($opts{'h'} ne "");
|
|
my $n = ""; $n = "-n" if $opts{'n'};
|
|
my $u = $ENV{USER};
|
|
$u = $opts{'u'} if ($opts{'u'} ne "");
|
|
my $more_testing = $opts{'t'};
|
|
my $interactive = $opts{'i'};
|
|
my $nomkdir = $opts{'m'};
|
|
my $addlchk = $opts{'a'};
|
|
my $nofetch = $opts{'f'};
|
|
my $currentdir = abs_path(".");
|
|
|
|
my $tmpdir;
|
|
my $repo;
|
|
my $ssh;
|
|
if( !defined $ENV{"CVS_RSH"} ) {
|
|
$ENV{CVS_RSH} = "ssh";
|
|
}
|
|
my $make = "make";
|
|
my $portlint = `which portlint`; chomp $portlint;
|
|
my $plint_args = "-N -a -c -t";
|
|
my $perl = "perl";
|
|
my $cp = "cp";
|
|
my $mv = "mv";
|
|
my $rm = "rm";
|
|
# vars required for commitfile
|
|
my $descr; my $portversion; my $pkgcomment;
|
|
my $tmp; my $pkgcommentlen; my $comment; my $orig;
|
|
my $tmp2; my $offset; my $commitfile = "";
|
|
$tmp = $tmp2 = $offset = 0;
|
|
|
|
chomp(my $myhost = lc(hostname()));
|
|
if ($myhost ne lc($h)) {
|
|
$ssh = "$ENV{CVS_RSH} $h -l $u";
|
|
$repo = "$u\@$h:/home/ncvs" if !$ENV{ADDPCVSROOT};
|
|
} else {
|
|
$ssh = "";
|
|
$repo = "/home/ncvs" if !$ENV{ADDPCVSROOT};
|
|
}
|
|
$repo = "$ENV{ADDPCVSROOT}" if $ENV{ADDPCVSROOT};
|
|
my $cvs = "cvs -d $repo";
|
|
|
|
# Check the editor.
|
|
my $edit = "/usr/bin/vi";
|
|
$edit = $ENV{EDITOR} if ($ENV{EDITOR} ne "");
|
|
|
|
# stuff that always happens when we start
|
|
BEGIN {
|
|
$tmpdir=`mktemp -d -t ap`;
|
|
chomp $tmpdir;
|
|
if ($tmpdir eq "") {
|
|
errx(1,"making random tmpdir didn't work, aborting.");
|
|
}
|
|
}
|
|
|
|
# stuff that always happens when we exit
|
|
END {
|
|
# only remove $tmpdir if it points to something in /tmp
|
|
# this is a silly little security thing
|
|
if (defined($rm) && defined($tmpdir)) {
|
|
system("$rm -rf $tmpdir") if ($tmpdir =~ m,/tmp/,);
|
|
}
|
|
}
|
|
|
|
# setup the list of commands to run on the new port(s).
|
|
my @commands;
|
|
my $passenv = "";
|
|
if ($addlchk && -f $portlint) {
|
|
$passenv = "DISTDIR=\"$distdir\"" if -d $distdir && $myhost ne "freefall.freebsd.org";
|
|
$passenv = "DISTDIR=\"$tmpdir\"" if $myhost eq "freefall.freebsd.org";
|
|
$passenv = $passenv . " PORTSDIR=\"$tmpdir\"" if !$nomkdir;
|
|
push(@commands, "$make $passenv clean check-categories");
|
|
push(@commands, "$portlint $plint_args");
|
|
push(@commands, "$make $passenv FETCH_BEFORE_ARGS='-btA' checksum") if !$nofetch;
|
|
if ($more_testing) {
|
|
push(@commands, "$make $passenv distclean");
|
|
push(@commands, "$make $passenv build");
|
|
push(@commands, "$make $passenv distclean");
|
|
}
|
|
if (!$nomkdir) {
|
|
chdir $tmpdir;
|
|
print "Checking out Mk directory to ensure portlint correctness.\n";
|
|
system("$cvs co ports/Mk") && errx(1, "Could not checkout Mk directory");
|
|
system("mv ports/Mk Mk") && errx(1, "Could not set up Mk directory");
|
|
chdir $currentdir;
|
|
}
|
|
}
|
|
|
|
if ($dir eq "") {
|
|
warnx("Need to specify a directory with -d argument!");
|
|
usage();
|
|
exit 1;
|
|
}
|
|
|
|
# make sure we're in the right place.
|
|
chdir $currentdir;
|
|
my @dirs = split(/\,/, $dir);
|
|
foreach my $i (@dirs) { $i = abs_path($i); }
|
|
my $portname; my $module;
|
|
foreach my $thisdir (@dirs) {
|
|
# make double sure where we are..
|
|
chdir $thisdir;
|
|
# do some dir sanity checking first
|
|
errx(1, "Please specify valid directories to import new ports from.") if $thisdir eq "";
|
|
errx(1, "$thisdir is either not a directory or does not exist.") if (! -d $thisdir);
|
|
|
|
print "Working with port directory $thisdir.\n";
|
|
|
|
$portname = `basename $thisdir`; # avoid problems with dirs containing `/' in cvs
|
|
chomp $portname;
|
|
if ($interactive) {
|
|
if (prompt("Port directory name will be $portname in CVS Repo. OK? ")) {
|
|
do {
|
|
$portname = query("Preferred name for port directory? ");
|
|
} while (prompt("Is the new name $portname OK? "));
|
|
}
|
|
}
|
|
|
|
chdir $thisdir or err(1, "$thisdir");
|
|
|
|
# now run the tests on this baby.
|
|
for (@commands) {
|
|
system("$_") && errx(1, "'$_' had problems. aborting.");
|
|
}
|
|
|
|
# Get the category name and make it suitable for use with cvs
|
|
my $category;
|
|
$_ = `grep CATEGORIES Makefile`;
|
|
m/\w+\W+([\w-]+)/;
|
|
$category = $1;
|
|
chomp $category;
|
|
if ($interactive) {
|
|
if (prompt("Port $portname will be put in category $category. OK? " )) {
|
|
do {
|
|
$category = query("Preferred category for $portname? ");
|
|
} while (prompt("Is the new category $category OK? "));
|
|
}
|
|
}
|
|
chomp(my $cvs_category = $category);
|
|
$cvs_category =~ s/-/_/g;
|
|
|
|
$module = $portname;
|
|
if ($interactive) {
|
|
if (prompt("Port will be added as module $portname. OK? ")) {
|
|
do {
|
|
$module = query("Preferred module name for $module? ");
|
|
} while (prompt("Is the new module name $module OK? "));
|
|
}
|
|
}
|
|
|
|
# Do commitfile checking but only if the user did not request automatic filling.
|
|
if (!$autofill) {
|
|
if (-f $c) {
|
|
system("$mv $c $tmpdir/commitfile") or errx(1, "Oops, can't move commitfile!");
|
|
$commitfile = "EDITOR=\"cp $tmpdir/commitfile\"";
|
|
print "\nRemember, you asked to use a commit file to read for the commit log.\n";
|
|
print "This means you'll get a message saying the log message was unchanged or\n";
|
|
print "not specified. Just tell it to continue and it will be committed.\n\n";
|
|
}
|
|
} else {
|
|
## Set up the autofill file.
|
|
# Read COMMENT for part of the commit message.
|
|
open(COMMENT, "pkg-comment") or die("Can't open pkg-comment for reading: $!");
|
|
$pkgcomment = <COMMENT>;
|
|
close(COMMENT);
|
|
chomp $pkgcomment;
|
|
# Change the first character to lowercase to make it fit with the
|
|
# rest of the commit message.
|
|
$pkgcomment =~ s/(^.)/\l$1/;
|
|
# Read Makefile to find necessary variables.
|
|
open(MAKEFILE, "Makefile") or die("Can't open Makefile for reading: $!");
|
|
while(<MAKEFILE>) {
|
|
chomp;
|
|
($orig) = (m/^# Whom:\s+(\w.*)$/) if (/^# Whom:/);
|
|
($portversion) = (m/^PORTVERSION=\s+(\w.*)$/) if (/^PORTVERSION=/);
|
|
}
|
|
close(MAKEFILE);
|
|
# Obtain length of the current string so we can figure out where to
|
|
# insert the \n. This is necessary to keep the commitfile under the
|
|
# limit for commit messages and such.
|
|
$tmp = length($portversion) + length($portname) + 10;
|
|
$offset = 72 - $tmp;
|
|
# If the comment string is longer than we have space for it, insert
|
|
# the \n after the last word that doesn't exceed the limit.
|
|
if (length($pkgcomment) > $offset) {
|
|
my @commentArr = split(/\s+/, $pkgcomment);
|
|
$tmp = 0;
|
|
# Until we reach the offset, record the number of words.
|
|
while ($tmp < $offset) {
|
|
$tmp += length($commentArr[$tmp2]) + 1;
|
|
$tmp2++;
|
|
}
|
|
$tmp2--;
|
|
$tmp = 0; $pkgcomment = "";
|
|
# Now reassemble the comment string.
|
|
while ($commentArr[$tmp]) {
|
|
if ($tmp == $tmp2 || $tmp == 0) {
|
|
$pkgcomment = $pkgcomment . "\n";
|
|
$pkgcomment = join("", $pkgcomment, $commentArr[$tmp]);
|
|
} else {
|
|
$pkgcomment = join(" ", $pkgcomment, $commentArr[$tmp]);
|
|
}
|
|
$tmp++;
|
|
}
|
|
}
|
|
chomp $pkgcomment;
|
|
$pkgcomment = $pkgcomment . ".";
|
|
$pkgcomment = $pkgcomment . "\n\n" if ($autofill != -1);
|
|
# Write out the data to the comment file.
|
|
open(AUTOFILL, "> $tmpdir/commitfile") or die("Can't open $tmpdir/commitfile for writing: $!");
|
|
print AUTOFILL "Add $portname $portversion, $pkgcomment";
|
|
print AUTOFILL "PR: $autofill\n" if ($autofill != -1);
|
|
print AUTOFILL "Submitted by: $orig" if ($autofill != -1);
|
|
close(AUTOFILL);
|
|
print "Okay, a commit log message was automatically generated for you.\n";
|
|
print "Now you will have a chance to edit it to make sure it's OK to use.\n";
|
|
print "Here's the contents of the file:\n--start--\n";
|
|
open(AUTOFILL, "$tmpdir/commitfile") or die("Can't open $tmpdir/commitfile for reading: $!");
|
|
print while (<AUTOFILL>);
|
|
close(AUTOFILL);
|
|
$tmp = prompt("\n--end--\nDo you wish to edit the file before continuing? ");
|
|
system("$edit $tmpdir/commitfile") if ($tmp == 0);
|
|
print "\nRemember, you asked to use a commit file to read for the commit log.\n";
|
|
print "This means you'll get a message saying the log message was unchanged or\n";
|
|
print "not specified. Just tell it to continue and it will be committed.\n\n";
|
|
$commitfile = "EDITOR=\"cp $tmpdir/commitfile\"";
|
|
}
|
|
|
|
print "We're ready to commit.\n";
|
|
print "Source directory: $thisdir\n";
|
|
print "Target CVS Repo directory: ports/$category/$portname\n";
|
|
print "Modules entry: $module --> ports/$category/$portname\n";
|
|
prompt("Adding port $portname to $category OK? ") && errx(1, "user abort requested");
|
|
|
|
chdir $tmpdir or err(1, "$tmpdir");
|
|
|
|
# let's get our hands dirty.
|
|
if (! -d $category) {
|
|
system("$cvs co -l ports_$cvs_category") && errx(1, "can't get temporary category directory, aborting.");
|
|
system("$mv ports_$cvs_category $category");
|
|
}
|
|
chdir $category or err(1,"$category");
|
|
system("$cp -PRp $thisdir .");
|
|
system("$cvs $n add `find $portname -type d | grep -v CVS`") && errx(1, "cvs add for dirs failed, aborting.");
|
|
system("$cvs $n add `find $portname -type f | grep -v CVS`") && errx(1, "cvs add for files failed, aborting.");
|
|
|
|
# figure out where the port name belongs in category Makefile
|
|
my @ports = &lsports;
|
|
errx(1, "Error: $portname already exists in $category\'s Makefile") if (&contains($portname, @ports));
|
|
my $port = "";
|
|
foreach my $tmp (sort(@ports)) {
|
|
if ($tmp gt $portname) {
|
|
$port = $tmp;
|
|
last;
|
|
}
|
|
}
|
|
|
|
# now let's insert it
|
|
my $cmd;
|
|
if ($port eq "") {
|
|
# there were no previous SUBDIR += lines, so we're going to
|
|
# put ourselves after the last comment (we can't be after a
|
|
# .include <bsd.port.subdir.mk> for example).
|
|
my $lastcommentnum = &lastcomment;
|
|
$cmd = "$lastcommentnum\n+\ni\n";
|
|
} else {
|
|
# OK, append ourselves in the right place, so things *stay* sorted.
|
|
$cmd = "/^ SUBDIR += $port/\ni\n";
|
|
}
|
|
print "Inserting new port into $category/Makefile...\n";
|
|
open(ED, "|ed Makefile") || die "Cannot start ed to actually insert module\n";
|
|
print ED "$cmd SUBDIR += $portname\n.\nw\nq\n";
|
|
close(ED);
|
|
|
|
# commit the actual port.
|
|
chdir "$tmpdir/$category" or err(1, "$tmpdir/$category");
|
|
system("$commitfile $cvs $n ci Makefile $portname") && errx(1, "cvs commit failed, aborting.");
|
|
if (!$nomodules && ($n ne "-n")) {
|
|
system("$ssh $perl /usr/local/bin/modulesupdate $module ports/$category/$portname") && errx(1, "adding port to modules failed, aborting.");
|
|
}
|
|
}
|
|
|
|
print <<EOF;
|
|
You're done! The new port $portname has been completely imported in
|
|
the tree. Don't forget to add the creator's name and email address to
|
|
the Contributors' List if they are not already there.
|
|
EOF
|
|
|
|
sub warnx {
|
|
my ($msg) = @_;
|
|
print STDERR $0 . ": " . $msg . "\n";
|
|
}
|
|
|
|
sub err {
|
|
my ($ex, $msg) = @_;
|
|
|
|
warnx("WARNING: err called incorrectly") if (($ex !~ m/^\d+/) || ($msg eq ""));
|
|
print STDERR $0 . ": " . $msg . ": $!\n";
|
|
exit $ex;
|
|
}
|
|
|
|
sub errx {
|
|
my ($ex,$msg) = @_;
|
|
|
|
warnx("WARNING: errx called incorrectly") if (($ex !~ m/^\d+/) || ($msg eq ""));
|
|
print STDERR $0 . ": " . $msg . "\n";
|
|
exit $ex;
|
|
}
|
|
|
|
sub prompt {
|
|
my ($msg) = @_;
|
|
my $reply = query($msg);
|
|
return 0 if ($reply =~ m/^[Yy]/);
|
|
return 1 if ($reply =~ m/^[Nn]/);
|
|
}
|
|
|
|
sub query {
|
|
my ($msg) = @_;
|
|
|
|
print "$msg";
|
|
my $reply = <>;
|
|
chomp $reply;
|
|
return $reply;
|
|
}
|
|
|
|
sub usage {
|
|
#addport,v \$Revision: 1.21 $
|
|
print <<EOF;
|
|
authors: <will\@FreeBSD.org>, <mharo\@FreeBSD.org>
|
|
|
|
SYNOPSIS
|
|
$0 [-c commitfile] [-h host] [-l PR number] [-s distdir] [-s distdir]
|
|
[-afgimnt] -d directory
|
|
|
|
Where "directory" contains the comma-delimited list
|
|
of root directories of new ports that you wish to
|
|
add to the Ports Collection. The name of this directory
|
|
*WILL* matter in regards to the repository!
|
|
|
|
OPTIONS
|
|
-a Perform checks on the port to make sure
|
|
there are no problems. Recommended.
|
|
-c file Use file in place of normal log message.
|
|
-f Do not fetch the distfile.
|
|
-g Do not commit to CVSROOT/modules.
|
|
-h host Use a cvshost besides freefall.FreeBSD.org.
|
|
-i Interactive mode; allow more control over
|
|
where things are placed. This is required in
|
|
order to change things like module names etc.
|
|
-l PR# Attempts to autogenerate a commit message by
|
|
reading the Makefile/pkg-comment files. The
|
|
PR number must be passed to -l. If there is
|
|
no PR (i.e., self-created or submitted in
|
|
private email), use PR# -1.
|
|
-m Do not checkout ports/Mk (needed for support
|
|
of portlinting etc).
|
|
-n Do not actually commit anything.
|
|
-s distdir Use a different directory besides the default,
|
|
for downloading distfiles. This defaults to the
|
|
temporary directory set up on freefall.
|
|
-t Do more port testing. Requires -a.
|
|
-u user Use a different username (default: $u).
|
|
|
|
ENVIRONMENT VARIABLES
|
|
$0 supports the following environment variables:
|
|
|
|
CVS_RSH - Command to use when connecting to CVS host.
|
|
ADDPCVSROOT - Location of CVS repository.
|
|
USER - Username of user invoking $0.
|
|
|
|
EXAMPLES
|
|
% addport -n -d greatgame,helpfuldev,shoot
|
|
Will show what happens but not actually commit ports
|
|
named "greatgame", "helpfuldev", and "shoot".
|
|
|
|
% addport
|
|
Displays this message. :-)
|
|
|
|
EOF
|
|
}
|
|
|
|
sub contains {
|
|
# look if the first parameter is contained in the list following it
|
|
my ($item, @list) = @_;
|
|
|
|
foreach my $i (@list) {
|
|
return 1 if $i eq $item;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
sub lsports {
|
|
my @rv = ();
|
|
|
|
open(F, "Makefile") || die "can't open Makefile: $!";
|
|
while(<F>) {
|
|
chomp;
|
|
chomp;
|
|
next if $_ !~ m/SUBDIR/;
|
|
s/^[ \t]+SUBDIR[ \t]+\+?=[\ \t]+//;
|
|
push(@rv, $_);
|
|
}
|
|
close(F);
|
|
|
|
return @rv;
|
|
}
|
|
|
|
# this finds the last comment in the Makefile
|
|
sub lastcomment {
|
|
my $num = 0;
|
|
my $diff = 0;
|
|
|
|
open(F, "Makefile");
|
|
while(<F>) {
|
|
chomp;
|
|
if ($_ =~ m/^#/) {
|
|
$num += $diff;
|
|
$num++;
|
|
$diff = 0;
|
|
} else {
|
|
$diff += 1;
|
|
}
|
|
next;
|
|
}
|
|
return $num;
|
|
}
|