#!/usr/local/bin/perl

# Copyright (c) 2004-2012 Matthew Seaman. 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.

# @(#) $Id$
#
# Process the cached 'make describe' output to produce an INDEX file
# Should be a lot quicker than 'make index'.

use strict;
use warnings;

use FreeBSD::Portindex::Config qw(%Config read_config);
use FreeBSD::Portindex::Tree;

$0 =~ s@.*/@@;    # Script name for error messages

MAIN:
{
    my $tree;

    read_config('portindex');

    $tree = FreeBSD::Portindex::Tree->new(
        -Env           => { -Home => $Config{CacheDir}, },
        -CacheFilename => $Config{CacheFilename},
    );

    # Redirect STDOUT if required
    if ( $Config{Output} ne '-' ) {
        open STDOUT, '>', $Config{Output}
          or die "$0: Can't open output $Config{Output} -- $!\n";
    }

    # Unfreeze the cached ports data

    $tree->springtime();

    $tree->accumulate_dependencies();

    unless ( $Config{ShLibs} == 1 ) {
        $tree->print_index(*STDOUT);
    } else {
        $tree->print_shlibs(*STDOUT);
    }
}

__END__

=head1 NAME

portindex -- generate an INDEX file from cached data

=head1 SYNOPSIS

B<portindex> [B<-hvqwWL>] [B<-c> F<dir>] [B<-C> F<file>] [B<-T> F<file>] [B<-o> F<file>]

=head1 DESCRIPTION

B<portindex> processes the cached port description data into the
F<INDEX-7>, F<INDEX-8> or F<INDEX-9> files used by the ports system.
The cache contains a record of the one-line description of all ports
generated by C<make describe>, indexed by the port origin directory.
It also contains a record of the master-slave relationships between
some ports and of which Makefiles are included by the port's Makefile,
but that information is not used by B<portindex>.

The processing done by B<portindex> consists of two phases.  When
generating an F<INDEX>, in the first phase the various direct
dependencies listed in the raw C<make describe> output (FETCH_DEPENDS,
EXTRACT_DEPENDS, PATCH_DEPENDS, BUILD_DEPENDS, RUN_DEPENDS,
LIB_DEPENDS) are accumulated with the (previously accumulated)
RUN_DEPENDS list for each dependency target.  Thus, for example, the
final BUILD_DEPENDS dependency list will contain everything that the
port depends on directly to build itself, plus all of the dependencies
required for those build tools to run.

In the second phase the accumulated dependencies are converted from
lists of port origins to lists of package names, including version
numbers. The data is already sorted, by virtue of the way the Btree
cache files operate, so all that remains is to format it tidily and
print it out.

The processing done when generating a F<SHLIBS> file is very similar,
but in this case only the C<LIB_DEPENDS> variable is considered, and
library dependencies are accumulated and printed out as the list of
ports providing the shared libraries depended on.

=head2 Configuration Files

B<portindex> shares configuration files with B<cache-init>,
B<cache-update> and B<find-updated>.  Any configuration settings are
taken from the following locations, where the later items on this list
override the earlier:

=over 8

=item *

Built-in settings from the B<FreeBSD::Portindex::Config> perl module.

=item *

The system wide configuration file F</usr/local/etc/portindex.cfg>

=item *

The per-user configuration file F<${HOME}/.portindexrc> (ignored if
the program is being run by the superuser)

=item *

The local configuration file, found in the current working directory
of the B<cache-init> process F<./.portindexrc> (ignored if the program
is being run by the superuser)

=item *

The program command line.

=back

All of the configuration files are optional.  A summary of the
resultant configuration options including the effect of any command
line settings is printed as part of the help text when B<portindex> is
invoked with the C<-h> option.

=head1 OPTIONS

=over 8

=item B<-h>

=item B<--help>

Print a brief usage message and a summary of the configuration
settings after command line processing and then exit.

=item B<-v>

=item B<--verbose>

Turn on verbose output printed to C<STDERR>.  This is the default.

=item B<-w>

=item B<--warnings>

Turn on warning messages about duplicate ports and ports unreferenced
from their catergory F<Makefile>.  Default: off.

=item B<-nowarnings>

Turn off warning messages.  This is the default.

=item B<-q>

=item B<--quiet>

=item B<--noverbose>

Turn off verbose output to C<STDERR>.  Using both the B<-v> amd B<-q>
options together does not make any sense, but neither does it generate
an error.  The last mentioned of the two options will prevail.

=item B<-c> F<dir>

=item B<--cache-dir>=F<dir>

The location of the B<portindex> data cache, by default
F</var/db/portindex>.

=item B<-C> F<file>

=item B<--cache-file>=F<file>

Berkeley DB Btree file containing the cached and post-processed values
of a number of C<make> variables for all of the ports in the tree.
This file name will be relative to the cache directory (B<-c> option
above) unless an absolute path is given.  Defaults to
F<portindex-cache.db>.

=item B<-T> F<file>

=item B<--timestamp-file>=F<file>

A file within the cache directory whose modification time marks the
last time that data was modified in or added to the cache.  Defaults
to F<portindex-timestamp>

=item B<-o> F<file>

=item B<--output>=F<file>

Filename to write the generated ports INDEX file to.  Setting this to
F<-> means output to STDOUT, which is the default.

=item B<-W>

=item B<--crunch-whitespace>

Make the generated F<INDEX> closer to the output of C<make index> by
modifying the C<COMMENT> field so that any sequence of whitespace
characters is collapsed into a single space.  Default: off.
	
=item B<-L>

=item B<--shlibs>

Instead of the normal F<INDEX> file, generate an alternative F<SHLIBS>
index of the available ports.  The F<SHLIBS> file consists of three
columns separated by '|' characters.  The first two columns are the
same as in the F<INDEX> file: the package name and version, followed
by the directory containing the port.  The third column is a space
separated list of the cumulative C<LIB_DEPENDS> dependencies the port
has on other ports that provide shared libraries.  The use of this is
to identify the ports that would need to be reinstalled given an ABI
version bump in some dependency shared library. eg.

I<% grep databases/db46 SHLIBS | cut -d '|' -f 1>

	
=back

=head1 FILES

=over 16

=item F</usr/ports>

The default ports directory.

=item F</var/db/portindex>

The location of the data cache.

=item F<portindex-cache.db>

Btree file containing cached C<make describe> output.

=item F<__db.001>, F<__db.002>, F<__db.003>

Files used as part of the internal workings of BerkeleyDB, for memory
pool management and DB locking.  Will be recreated automatically if
deleted.

=item F<portindex-timestamp>

This file contains the last time and date that the cache was updated
or modified.

=item F</usr/local/etc/portindex.cfg>

System-wide configuration file.

=item F<${HOME}/.portindexrc>

Per-user configuration file

=item F<./.portindexrc>

Local configuration file

=back

=head1 SEE ALSO

L<cache-init(1)>, L<cache-update(1)>, L<find-updated(1)>, L<cvsup(1)>,
L<ports(7)>

=head1 BUGS

The F<INDEX> file produced by B<portindex> will not be identical to
the result of running C<make index> from the same ports tree.
However, the differences are mostly cosmetic and seem to have no
practical impact.

The sort order of the entries in the generated F<INDEX> file is
generated as a side effect of the way that BDB Btree files work.  It
is not eactly the same as produced by the sorting methods used in
C<make index>.  For example, in B<portindex>, C<x11-clocks>,
C<x11-fm>, C<x11-themes>, C<x11-toolkits> and C<x11-wm> will all sort
before C<x11>, whereas usually they would sort after.

B<portindex> uses the port origin as its unique key in the data cache.
C<make index> uses the package name.  Since certain ports modify their
package name depending on the local settings and conditions, this can
lead to package name collisions. Such collisions are weeded out of the
generated INDEX file by C<make index>, but not by B<portindex>.

Unless the C<--crunch-whitespace> option is given, B<portindex>
extracts the C<COMMENT> lines from the C<make describe> output exactly
as shown.  C<make index> collapses multiple spaces to single.

=cut

#
# That's All Folks!
#
