aboutsummaryrefslogtreecommitdiff
path: root/ports-mgmt
diff options
context:
space:
mode:
authorDag-Erling Smørgrav <des@FreeBSD.org>2000-09-19 19:25:04 +0000
committerDag-Erling Smørgrav <des@FreeBSD.org>2000-09-19 19:25:04 +0000
commitf7983e4e954556f81560255c9e716e658756c1aa (patch)
treebfe727ec92757e0647d9cae2af62533102b31775 /ports-mgmt
parentbd178865a8daa7d0ad19a1e26bab932e7f94cf28 (diff)
downloadports-f7983e4e954556f81560255c9e716e658756c1aa.tar.gz
ports-f7983e4e954556f81560255c9e716e658756c1aa.zip
A tool for fetching and building ports.
Notes
Notes: svn path=/head/; revision=32876
Diffstat (limited to 'ports-mgmt')
-rw-r--r--ports-mgmt/porteasy/Makefile33
-rw-r--r--ports-mgmt/porteasy/pkg-comment1
-rw-r--r--ports-mgmt/porteasy/pkg-descr22
-rw-r--r--ports-mgmt/porteasy/pkg-plist1
-rw-r--r--ports-mgmt/porteasy/src/porteasy.8221
-rw-r--r--ports-mgmt/porteasy/src/porteasy.pl643
6 files changed, 921 insertions, 0 deletions
diff --git a/ports-mgmt/porteasy/Makefile b/ports-mgmt/porteasy/Makefile
new file mode 100644
index 000000000000..14ba69544491
--- /dev/null
+++ b/ports-mgmt/porteasy/Makefile
@@ -0,0 +1,33 @@
+# New ports collection makefile for: porteasy
+# Date created: September 19th 2000
+# Whom: des
+#
+# $FreeBSD$
+#
+# This port is self contained in the src directory.
+#
+
+PORTNAME= porteasy
+PORTVERSION= 1.6
+CATEGORIES= misc
+MASTER_SITES= # none
+DISTFILES= # none
+
+MAINTAINER= des@FreeBSD.org
+
+NO_BUILD= yes
+NO_WRKSUBDIR= yes
+USE_PERL5= yes
+
+SRC= ${.CURDIR}/src
+
+MAN8= porteasy.8
+
+do-fetch:
+ @${DO_NADA}
+
+do-install:
+ @${INSTALL_SCRIPT} ${SRC}/porteasy.pl ${PREFIX}/bin/porteasy
+ @${INSTALL_MAN} ${SRC}/porteasy.8 ${PREFIX}/man/man8
+
+.include <bsd.port.mk>
diff --git a/ports-mgmt/porteasy/pkg-comment b/ports-mgmt/porteasy/pkg-comment
new file mode 100644
index 000000000000..b0b24b7f52b0
--- /dev/null
+++ b/ports-mgmt/porteasy/pkg-comment
@@ -0,0 +1 @@
+A tool for fetching and building ports
diff --git a/ports-mgmt/porteasy/pkg-descr b/ports-mgmt/porteasy/pkg-descr
new file mode 100644
index 000000000000..2a2391f38f59
--- /dev/null
+++ b/ports-mgmt/porteasy/pkg-descr
@@ -0,0 +1,22 @@
+Porteasy lets you install ports and build packages without maintaining
+a full ports tree. It achieves this by scanning the ports index for
+dependency information, and using CVS to update only the ports you
+requested and their dependencies.
+
+Here are some of the things porteasy does for you:
+
+ - automatically update the necessary files (and only the necessary
+ files) using CVS (including anoncvs support)
+
+ - list all of a port's dependencies, optionally hiding those that
+ are already installed
+
+ - fetch all the necessary distfiles right away, in a single batch,
+ so you don't have to wait for one dependency to build before
+ fetching the next one's distfile. Dialup users will love this.
+
+ - build and install arbitrary ports.
+
+ - build packages.
+
+ -- des@freebsd.org
diff --git a/ports-mgmt/porteasy/pkg-plist b/ports-mgmt/porteasy/pkg-plist
new file mode 100644
index 000000000000..6b52c1b30876
--- /dev/null
+++ b/ports-mgmt/porteasy/pkg-plist
@@ -0,0 +1 @@
+bin/porteasy
diff --git a/ports-mgmt/porteasy/src/porteasy.8 b/ports-mgmt/porteasy/src/porteasy.8
new file mode 100644
index 000000000000..8944b3a5cd0f
--- /dev/null
+++ b/ports-mgmt/porteasy/src/porteasy.8
@@ -0,0 +1,221 @@
+.\"-
+.\" Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
+.\" 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
+.\" in this position and unchanged.
+.\" 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.
+.\" 3. The name of the author may not be used to endorse or promote products
+.\" derived from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd September 19, 2000
+.Dt PORTLINT 8
+.Sh NAME
+.Nm porteasy
+.Nd fetch and build ports
+.Sh SYNOPSIS
+.Nm porteasy
+.Op Fl abcefhikluVv
+.Op Fl d Ar dir
+.Op Fl D Ar date
+.Op Fl p Ar dir
+.Op Fl r Ar dir
+.Op Fl t Ar tag
+.Op Ar port ...
+.Sh DESCRIPTION
+.Nm
+maintains an updated ports tree, and fetches and builds ports
+automatically, keeping track of dependencies.
+.Pp
+The following options are available:
+.Bl -tag -width Fl
+.It Fl a
+Use the FreeBSD project's anoncvs server as CVS root.
+.It Fl b
+Build the selected ports.
+.It Fl c
+Clean the selected ports.
+.It Fl D Ar date
+Specify a date to use for CVS operations.
+.It Fl d Ar dir
+Specify the package database directory (normally
+.Pa /var/db/pkg ).
+.It Fl e
+Deselect ports that are already installed.
+.It Fl f
+Fetch the selected ports.
+.It Fl h
+Show a summary of options and parameters.
+.It Fl i
+Describe the selected ports.
+.It Fl k
+Build packages for the selected ports.
+.It Fl l
+List the selected ports.
+.It Fl p Ar dir
+Specify the ports directory (normally
+.Pa /usr/ports ).
+.It Fl r Ar dir
+Specify the CVS root directory.
+.It Fl t Ar tag
+Specify a tag to use for CVS operations.
+.It Fl u
+Update all necessary files using CVS.
+.It Fl V
+Show the
+.Nm
+version number and exit.
+.It Fl v
+Verbose mode: show more information about what is being done.
+.El
+.Sh SEQUENCE
+This section describes the operations performed by
+.Nm
+and the order in which they are performed.
+.Ss Update index
+If the
+.Fl u
+option was specified, the index file is updated from CVS.
+.Ss Select ports
+The ports listed on the command line are looked up in the index, using
+simple heuristics to identify incompletely named ports.
+If a certain match is not found,
+.Nm
+prints a list of possible matches and exits.
+.Pp
+All direct and indirect dependencies of the ports listed on the
+command line are also selected and marked as dependencies.
+.Pp
+If the
+.Fl e
+option was specified,
+.Nm
+then checks to see if any of the required ports are already installed;
+those that are are deselected.
+.Pp
+Selected ports that were specified on the command line are marked as
+explicitly selected, while dependencies are marked as implicitly
+selected.
+.Ss List selected ports
+If the
+.Fl l
+option was specified, all selected ports are listed.
+Explicitly selected ports are indicated with a star.
+.Ss Update ports tree
+If the
+.Fl u
+option and at least one of the
+.Fl b ,
+.Fl f ,
+.Fl i
+or
+.Fl k
+options was specified, all selected ports are updated from CVS.
+.Ss Describe selected ports
+If the
+.Fl i
+option was specified,
+.Nm
+prints a description of each port that was specified on the command
+line.
+If no ports were specified,
+.Nm
+instead prints a list of all installed ports, with unknown ports (i.e.
+ports that are not in the index file, or are out of date) indicated
+with a question mark.
+.Ss Clean the tree
+If the
+.Fl c
+option was specified,
+.Nm
+runs the `clean' target on every selected port.
+If no ports were selected,
+.Nm
+runs the `clean' target on every known port that is present in the
+tree.
+.Ss Fetch ports
+If at least one of the
+.Fl b ,
+.Fl f
+or
+.Fl k
+options was specified,
+.Nm
+runs the `fetch' target on every selected port.
+.Ss Install ports
+If one or both of the
+.Fl f
+or
+.Fl k
+options were specified,
+.Nm
+runs the `install' target on every explicitly selected port.
+Dependencies are handled by the ports system.
+.Ss Fetch ports
+If the
+.Fl k
+option was specified,
+.Nm
+runs the `package' target on every explicitly selected port.
+Dependencies are handled by the ports system.
+.Ss Clean the tree (again)
+If one or both of the
+.Fl f
+or
+.Fl k
+options were specified,
+.Nm
+finally runs the `clean' target on every selected port once it's
+installed and (optionally) the package has been built.
+.Sh NOTES
+There may be a significant difference between what ports are selected
+(and listed if the
+.Fl l
+option is specified) and what ports are actually installed and/or have
+packages built for them, since:
+.Bl -bullet
+.It
+the index file lists all dependencies, including ones that are
+conditional on system configuration or build-time options.
+.It
+implicitly selected ports that are already installed, or somehow pass
+the dependency check (e.g. because an alternate, equivalent port has
+been installed) will be passed over by the ports system, as indeed
+they should.
+.El
+.Sh FILES
+.Nm
+maintains and operates on a ports tree, normally
+.Pa /usr/ports .
+Some information is gathered from the package database, normally
+located in
+.Pa /var/db/pkg .
+.Sh AUTHORS
+.Nm
+was written by
+.An Dag-Erling Smørgrav Aq des@FreeBSD.org .
+Several people contributed their comments and suggestions, most
+notably
+.An Eivind Eklund Aq eivind@FreeBSD.org .
+.Sh BUGS
+.Nm
+does not read your mind.
diff --git a/ports-mgmt/porteasy/src/porteasy.pl b/ports-mgmt/porteasy/src/porteasy.pl
new file mode 100644
index 000000000000..cfcba5eef9b4
--- /dev/null
+++ b/ports-mgmt/porteasy/src/porteasy.pl
@@ -0,0 +1,643 @@
+#!/usr/bin/perl -w
+#-
+# Copyright (c) 2000 Dag-Erling Coïdan Smørgrav
+# 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
+# in this position and unchanged.
+# 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.
+# 3. The name of the author may not be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 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.
+#
+# $FreeBSD$
+#
+
+use strict;
+use Data::Dumper;
+use Fcntl;
+use Getopt::Long;
+
+my $VERSION = "1.6";
+
+# Constants
+sub ANONCVS_ROOT { ":pserver:anoncvs\@anoncvs.FreeBSD.org:/home/ncvs" }
+sub REQ_EXPLICIT { 1 }
+sub REQ_IMPLICIT { 2 }
+
+# Global parameters
+my $cvs = "/usr/bin/cvs"; # CVS command
+my $dbdir = "/var/db/pkg"; # Package database directory
+my $index = undef; # Index file
+my $portsdir = "/usr/ports"; # Ports directory
+my $tag = undef; # cvs tag to use
+my $date = undef; # cvs date to use
+
+# Global flags
+my $anoncvs = 0; # Use anoncvs.FreeBSD.org
+my $clean = 0; # Clean ports
+my $cvsroot = 0; # CVS root directory
+my $exclude = 0; # Do not list installed ports
+my $fetch = 0; # Fetch ports
+my $help = 0; # Show help text
+my $info = 0; # Show port info
+my $packages = 0; # Build packages
+my $list = 0; # List ports
+my $build = 0; # Build ports
+my $update = 0; # Update ports tree from CVS
+my $verbose = 0; # Verbose mode
+my $version = 0; # Show version
+my $ecks = 0; # The undocumented option.
+
+# Global variables
+my %ports; # Maps ports to their directory.
+my %strop; # Inverse of the above map
+my %dependencies; # Maps ports to their dependency lists.
+my %reqd; # Ports that need to be installed
+
+#
+# Shortcut for 'print STDERR'
+#
+sub stderr(@) {
+ print(STDERR @_);
+}
+
+#
+# Similar to err(3)
+#
+sub err($$@) {
+ my $code = shift; # Return code
+ my $fmt = shift; # Format string
+ my @args = @_; # Arguments
+
+ my $msg; # Error message
+
+ $msg = sprintf($fmt, @args);
+ stderr("$msg: $!\n");
+ exit($code);
+}
+
+#
+# Similar to errx(3)
+#
+sub errx($$@) {
+ my $code = shift; # Return code
+ my $fmt = shift; # Format string
+ my @args = @_; # Arguments
+
+ my $msg; # Error message
+
+ $msg = sprintf($fmt, @args);
+ stderr("$msg\n");
+ exit($code);
+}
+
+#
+# Print an info message
+#
+sub info($) {
+ if ($verbose) {
+ chomp($_[0]);
+ stderr(">>> $_[0]\n");
+ }
+}
+
+#
+# Change working directory
+#
+sub cd($) {
+ my $dir = shift; # Directory to change to
+
+ info("cd $dir");
+ chdir($dir)
+ or err(1, "unable to chdir to %s", $dir);
+}
+
+#
+# Run a command using system()
+#
+sub cmd(@) {
+
+ info(join(" ", @_));
+ return (system(@_) == 0);
+}
+
+#
+# Run CVS
+#
+sub cvs($;@) {
+ my $cmd = shift; # CVS command
+
+ my @args; # Arguments to CVS
+
+ push(@args, "-f", "-z3", "-R",
+ $verbose ? "-q" : "-Q", $cmd, "-A");
+ if ($cmd eq "checkout") {
+ push(@args, "-P");
+ } elsif ($cmd eq "update") {
+ push(@args, "-P", "-d");
+ }
+ if ($tag) {
+ push(@args, "-r$tag");
+ }
+ if ($date) {
+ push(@args, "-D$date");
+ }
+ push(@args, @_);
+ return cmd($cvs, @args);
+}
+
+#
+# Run make
+#
+sub make($@) {
+ my $port = shift; # Port category/name
+ my @args = @_;
+
+ push(@args, "PORTSDIR=$portsdir")
+ unless ($portsdir eq "/usr/ports");
+ cd("$portsdir/$ports{$port}");
+ cmd("make", @args);
+}
+
+#
+# The undocumented command.
+#
+sub ecks() {
+
+ local *FILE; # File handle
+
+ sysopen(FILE, "/var/db/port.mkversion", O_RDWR|O_CREAT|O_TRUNC, 0644)
+ or err(1, "open()");
+ print(FILE "20380119\n");
+ close(FILE);
+}
+
+#
+# Update the index file
+#
+sub update_index() {
+
+ my $parent; # Parent directory
+
+ $parent = $portsdir;
+ $parent =~ s/\/*ports\/*$//;
+ cd($parent);
+ if (-f "ports/INDEX" || (-d "ports" && -d "ports/CVS")) {
+ cvs("update", "ports/INDEX")
+ or errx(1, "error updating the index file");
+ } else {
+ cvs("checkout", "-l", "ports")
+ or errx(1, "error checking out the index file");
+ }
+ cvs("update", "-l", "ports/Mk")
+ or errx(1, "error updating the Makefiles");
+}
+
+#
+# Read the ports index
+#
+sub read_index() {
+
+ local *INDEX; # File handle
+ my $line; # Line from file
+
+ sysopen(INDEX, $index, O_RDONLY)
+ or err(1, "can't open $index");
+ while ($line = <INDEX>) {
+ my @port; # Port info
+ my @depend; # Dependencies
+
+ @port = split(/\|/, $line);
+ $port[1] =~ s|^/usr/ports/*||;
+ $ports{$port[0]} = $port[1];
+ $strop{$port[1]} = $port[0];
+ @depend = split(' ', "$port[7] $port[8]");
+ $dependencies{$port[0]} = \@depend;
+ }
+ close(INDEX);
+ info(keys(%ports) . " ports in index");
+}
+
+#
+# Add a port to the list of required ports
+#
+sub add_port($$); # Prototype to silence warning
+sub add_port($$) {
+ my $port = shift; # Port to add
+ my $req = shift; # Requirement (explicit or implicit)
+
+ my $err = 0; # Error count
+
+ if (exists($reqd{$port})) {
+ $reqd{$port} |= $req;
+ return 0;
+ }
+ if (!exists($ports{$port})) {
+ my @suggest; # Suggestions
+
+ stderr("can't find required port '$port'");
+ @suggest = grep(/^$port/i, keys(%ports));
+ if (@suggest == 1 && $suggest[0] =~ m/^$port[0-9.-]/) {
+ $port = shift(@suggest);
+ stderr(", assuming you mean '$port'.\n");
+ } elsif (@suggest) {
+ stderr(", maybe you mean:\n " . (join("\n ", @suggest)) . "\n");
+ return 1;
+ } else {
+ stderr("\n");
+ return 1;
+ }
+ }
+ $reqd{$port} = $req;
+ foreach $port (@{$dependencies{$port}}) {
+ $err += add_port($port, &REQ_IMPLICIT);
+ }
+ return $err;
+}
+
+#
+# Find master directory for a port
+#
+sub find_master($$) {
+ my $category = shift; # Category
+ my $port = shift; # Port
+
+ local *FILE; # File handle
+ my $master; # Master directory
+
+ open(FILE, "$portsdir/$category/$port/Makefile")
+ or err(1, "unable to read Makefile for $category/$port");
+ while (<FILE>) {
+ if (/^MASTERDIR\s*=\s*(\S+)\s*$/) {
+ $master = $1;
+ $master =~ s/^\$\{.CURDIR\}//;
+ $master = "/$category/$port/$master";
+ $master =~ s|/+|/|g;
+ 1 while ($master =~ s|/[^\./]*/\.\./|/|);
+ $master =~ s|^/||;
+ close(FILE);
+ return $master;
+ }
+ }
+ close(FILE);
+ return undef;
+}
+
+#
+# Update all necessary files to build the specified ports
+#
+sub update_ports_tree(@) {
+ my @ports = @_; # Ports to update
+
+ my $port; # Port name
+ my $category; # Category name
+ my %updated; # Hash of updated ports
+ my %additional; # Additional dependencies
+ my $todo; # Have something to do
+
+ foreach $port (@ports) {
+ $additional{$ports{$port}} = 1;
+ }
+ for (;;) {
+ my %update_now; # Ports that need updating now
+ my $master; # Master port
+
+ foreach $port (keys(%additional)) {
+ ($category, $port) = split(/\//, $port);
+ if (!$updated{$category}->{$port}) {
+ $update_now{$category}->{$port} = 1;
+ $updated{$category}->{$port} = 1;
+ }
+ }
+ last unless keys(%update_now);
+ cd($portsdir);
+ cvs("update", "-l", keys(%update_now))
+ or errx(1, "error updating the category directories");
+ foreach $category (keys(%update_now)) {
+ cd("$portsdir/$category");
+ cvs("update", keys(%{$update_now{$category}}))
+ or errx(1, "error updating the '$category' category");
+ }
+ foreach $category (keys(%update_now)) {
+ foreach $port (keys(%{$update_now{$category}})) {
+ if ($master = find_master($category, $port)) {
+ $additional{$master} = 1;
+ }
+ }
+ }
+ }
+}
+
+#
+# Show port info
+#
+sub show_port_info($) {
+ my $port = shift; # Port to show info for
+
+ local *FILE; # File handle
+ my $info; # Port info
+
+ sysopen(FILE, "$portsdir/$ports{$port}/pkg/DESCR", O_RDONLY)
+ or err(1, "can't read description for $port");
+ $info = join("| ", <FILE>);
+ close(FILE);
+ print("+--- $port:\n| ${info}+---\n");
+}
+
+#
+# List installed ports
+#
+sub list_installed() {
+
+ local *DIR; # Directory handle
+ my $port; # Port name
+ my $unknown; # Unknown ports
+
+ opendir(DIR, $dbdir)
+ or err(1, "can't read database directory");
+ print("Installed ports:\n");
+ foreach $port (readdir(DIR)) {
+ next if ($port eq "." || $port eq ".." || ! -d "$dbdir/$port");
+ if (exists($ports{$port})) {
+ print(" $port\n");
+ } else {
+ print(" ? $port\n");
+ ++$unknown;
+ }
+ }
+ if ($unknown) {
+ print("Recommend you run pkg_version(1).\n");
+ }
+}
+
+#
+# Clean a port
+#
+sub clean_port($) {
+ my $port = shift; # Port to clean
+
+ make($port, "clean");
+}
+
+#
+# Clean the tree
+#
+sub clean_tree() {
+
+ my $port; # Port name
+
+ # We could just cd to $portsdir and 'make clean', but it'd
+ # be extremely noisy due to only having a partial tree
+ #errx(1, Dumper(\%strop));
+ foreach $port (keys(%ports)) {
+ if (-d "$portsdir/$ports{$port}") {
+ make($port, "clean", "NO_DEPENDS=yes");
+ }
+ }
+}
+
+#
+# Fetch a port
+#
+sub fetch_port($) {
+ my $port = shift; # Port to fetch
+
+ make($port, "fetch");
+}
+
+#
+# Build a port
+#
+sub build_port($) {
+ my $port = shift; # Port to build
+
+ make($port,
+ $packages ? ("package", "DEPENDS_TARGET=package") : "install",
+ "clean");
+}
+
+#
+# Print usage message and exit
+#
+sub usage() {
+
+ stderr("Usage: porteasy [-abcefhikluVv] [-d dir] [-D date]\n" .
+ " [-p dir] [-r dir] [-t tag] [port ...]\n");
+ exit(1);
+}
+
+#
+# Print version
+#
+sub version() {
+
+ stderr("porteasy $VERSION\n");
+ exit(1);
+}
+
+#
+# Print help text
+#
+sub help() {
+
+ stderr("porteasy $VERSION
+
+Options:
+ -a, --anoncvs Use the FreeBSD project's anoncvs server
+ -b, --build Build required ports
+ -c, --clean Clean the specified ports
+ -e, --exclude-installed Exclude installed ports
+ -f, --fetch Fetch distfiles
+ -h, --help Show this information
+ -i, --info Show info about specified ports
+ -k, --packages Build packages for the specified ports
+ -l, --list List required ports and their dependencies
+ -u, --update Update relevant portions of the ports tree
+ -V, --version Show version number
+ -v, --verbose Verbose mode
+
+Parameters:
+ -D, --date=DATE Specify CVS date
+ -d, --dbdir=DIR Specify package directory (default $dbdir)
+ -p, --portsdir=DIR Specify ports directory (default $portsdir)
+ -r, --cvsroot=DIR Specify CVS root
+ -t, --tag=TAG Specify CVS tag
+
+Report bugs to <des\@freebsd.org>.
+");
+ exit(1);
+}
+
+MAIN:{
+ my $port; # Port name
+ my $err = 0; # Error count
+
+ # Scan command line options
+ Getopt::Long::Configure("auto_abbrev", "bundling");
+ GetOptions(
+ "a|anoncvs" => \$anoncvs,
+ "b|build" => \$build,
+ "c|clean" => \$clean,
+ "D|date=s" => \$date,
+ "d|dbdir=s" => \$dbdir,
+ "e|exclude-installed" => \$exclude,
+ "f|fetch" => \$fetch,
+ "h|help" => \$help,
+ "i|info" => \$info,
+ "k|packages" => \$packages,
+ "l|list" => \$list,
+ "p|portsdir=s" => \$portsdir,
+ "r|cvsroot=s" => \$cvsroot,
+ "t|tag=s" => \$tag,
+ "u|update" => \$update,
+ "V|version" => \$version,
+ "v|verbose" => \$verbose,
+ "x|ecks" => \$ecks,
+ )
+ or usage();
+
+ if ($help) {
+ help();
+ }
+
+ if ($version) {
+ version();
+ }
+
+ if ($ecks) {
+ ecks();
+ }
+
+ if (!@ARGV && (!$clean && !$info || $build || $fetch)) {
+ usage();
+ }
+
+ if ($portsdir !~ m/^\//) {
+ $portsdir = `pwd` . $portsdir;
+ $portsdir =~ s/\n/\//s;
+ }
+
+ if ($portsdir !~ m/\/ports\/?$/) {
+ errx(1, "ports directory must be named 'ports'");
+ }
+
+ $index = "$portsdir/INDEX";
+
+ # 'package' implies 'build', which implies 'fetch'.
+ if ($packages) {
+ $build = 1;
+ }
+ if ($build) {
+ $fetch = 1;
+ }
+
+ # Set and check CVS root
+ if ($anoncvs) {
+ $cvsroot = &ANONCVS_ROOT;
+ }
+ if ($cvsroot) {
+ $ENV{'CVSROOT'} = $cvsroot;
+ }
+ if (!$ENV{'CVSROOT'}) {
+ errx(1, "No CVS root, please use the -r option or set \$CVSROOT");
+ }
+
+ # Read the ports index
+ if ($update) {
+ update_index();
+ }
+ read_index();
+
+ # Read list of explicitly required ports
+ foreach $port (@ARGV) {
+ $err += add_port($port, &REQ_EXPLICIT);
+ }
+ if ($err) {
+ errx(1, "some required ports were not found.");
+ }
+
+ # Deselect ports which are already installed
+ if ($exclude) {
+ foreach $port (keys(%reqd)) {
+ if (-d "$dbdir/$port") {
+ info("$port is already installed");
+ delete $reqd{$port};
+ }
+ }
+ }
+
+ # List required packages
+ if ($list) {
+ foreach $port (sort(keys(%reqd))) {
+ print((($reqd{$port} & &REQ_EXPLICIT) ? " * " : " "),
+ "$port\n");
+ }
+ }
+
+ # Update port directories
+ if ($update && ($build || $fetch || $info)) {
+ update_ports_tree(keys(%reqd));
+ }
+
+ # Show info
+ if ($info) {
+ if (@ARGV) {
+ list_installed();
+ }
+ foreach $port (keys(%reqd)) {
+ if ($reqd{$port} & &REQ_EXPLICIT) {
+ show_port_info($port);
+ }
+ }
+ }
+
+ # Clean
+ if ($clean) {
+ if (@ARGV) {
+ clean_tree();
+ }
+ foreach $port (keys(%reqd)) {
+ if (!($reqd{$port} & &REQ_IMPLICIT)) {
+ clean_port($port);
+ }
+ }
+ }
+
+ # Fetch ports
+ if ($fetch) {
+ foreach $port (keys(%reqd)) {
+ fetch_port($port);
+ }
+ }
+
+ # Build ports - only the explicitly required ones, since the
+ # 'already installed' test may give false negatives (most commonly
+ # XFree86)
+ if ($build || $packages) {
+ foreach $port (keys(%reqd)) {
+ if (!($reqd{$port} & &REQ_IMPLICIT)) {
+ build_port($port);
+ }
+ }
+ }
+
+ # Done!
+ exit(0);
+}