#! /usr/bin/perl
# $OpenBSD: mksqlitedb,v 1.32 2011/04/10 18:01:13 jasper Exp $
#
# Copyright (c) 2006-2010 Marc Espie <espie@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

# example script that shows how to store all variable values into a
# database, using SQLite for that purpose.
#
# usage: cd /usr/ports && make dump-vars |mksqlitedb

use strict;
use warnings;
use FindBin;
use lib $FindBin::Bin;
use Getopt::Std;
use Column;
use Var;
use Inserter;
use DBI;


our ($opt_v, $opt_q, $opt_p);

sub parse_dump
{
	my ($inserter, $vars, $fd, $unknown) = @_;
	my $lastkey;
	while (<$fd>) {
		chomp;
		# kill noise
		if (s/^\=\=\=/---/) {
			print $_, "\n";
			next;
		}
		next unless m/^(.*?)\.([A-Z][A-Z_0-9]*)(?:\-([a-z0-9]+))?\=(.*)$/;

		my ($key, $var, $arch, $value) = ($1, $2, $3, $4);
		# strip extra quotes
		if ($value =~ m/^\"(.*)\"$/) {
			$value = $1;
		}

		if (!(defined $lastkey) || $key ne $lastkey) {
			if (defined $lastkey) {
				$inserter->finish_port;
			}
			$inserter->mark_done($key);
			if ($key =~ m/^(.*)\,\-main((?:\,.*)?)$/) {
				$inserter->mark_done("$1$2");
			}
			$inserter->set_newkey($key);
			$lastkey = $key;
		}
		if (defined $vars->{$var}) {
			$inserter->add_var($vars->{$var}->new($var, $value, $arch));
		} else {
			$unknown->{$var} //= $key;
		}
	}

	$inserter->finish_port;
	$inserter->commit_to_db;
}

sub dump_dirs
{
	my ($inserter, $vars, $unknown, $todo) = @_;
	my ($pid, $fd);
	unless (defined($pid = open($fd, "-|"))) {
		die "can't fork : $!";
	}
	if ($pid) {
		parse_dump($inserter, $vars, $fd, $unknown);
		close $fd || warn $!;
	} else {
		if (defined $todo) {
			$ENV{'SUBDIR'} = join(' ', keys %$todo);
		}
		if ($opt_p) {
			$ENV{'REPORT_PROBLEM'}= "touch $opt_p; exit 1";
		}
		$ENV{'NO_IGNORE'} = 'Yes';
		exec {'make'} ("make", "dump-vars");
		die $!;
	}
}

getopts('vq:p:');
my $dbname;
if (@ARGV > 0) {
	$dbname = shift;
} else {
	$dbname = 'sqlports';
}

my $inserter = InserterList->new;

my $db = DBI->connect("dbi:SQLite:dbname=$dbname", '', '', {AutoCommit => 0});
my $db2 = DBI->connect("dbi:SQLite:dbname=$dbname-compact", '', '',
    {AutoCommit => 0});
my $normal = NormalInserter->new($db, 1000, $opt_v);
$inserter->add($normal, CompactInserter->new($db2, 1000, $opt_v));


my $vars = {
    AUTOCONF_VERSION => 'AutoVersionVar',
    AUTOMAKE_VERSION => 'AutoVersionVar',
    BROKEN => 'BrokenVar',
    BUILD_DEPENDS => 'BuildDependsVar',
    CATEGORIES => 'CategoriesVar',
    COMES_WITH => 'DefinedVar',
    COMMENT => 'AnyVar',
    CONFIGURE_ARGS => 'ConfigureArgsVar',
    CONFIGURE_STYLE => 'ConfigureVar',
    DESCR => 'FileVar',
    DISTFILES => 'AnyVar',
    PATCHFILES => 'AnyVar',
    DISTNAME => 'AnyVar',
    DIST_SUBDIR => 'DefinedVar',
    EPOCH => 'AnyVar',
    FLAVORS => 'FlavorsVar',
    FULLPKGNAME => 'AnyVar',
    HOMEPAGE => 'AnyVar',
    IGNORE => 'DefinedVar',
    IS_INTERACTIVE => 'AnyVar',
    LIB_DEPENDS => 'LibDependsVar',
    MAINTAINER=> 'EmailVar',
    MASTER_SITES => 'MasterSitesVar',
    MASTER_SITES0 => 'MasterSitesVar',
    MASTER_SITES1 => 'MasterSitesVar',
    MASTER_SITES2 => 'MasterSitesVar',
    MASTER_SITES3 => 'MasterSitesVar',
    MASTER_SITES4=> 'MasterSitesVar',
    MASTER_SITES5 => 'MasterSitesVar',
    MASTER_SITES6 => 'MasterSitesVar',
    MASTER_SITES7 => 'MasterSitesVar',
    MASTER_SITES8 => 'MasterSitesVar',
    MASTER_SITES9=> 'MasterSitesVar',
    MODULES => 'ModulesVar',
    MULTI_PACKAGES => 'MultiVar',
    NO_BUILD => 'YesNoVar',
    NO_REGRESS => 'YesNoVar',
    NOT_FOR_ARCHS => 'NotForArchListVar',
    ONLY_FOR_ARCHS => 'OnlyForArchListVar',
    PERMIT_DISTFILES_CDROM => 'YesKeyVar',
    PERMIT_DISTFILES_FTP=> 'YesKeyVar',
    PERMIT_PACKAGE_CDROM => 'YesKeyVar',
    PERMIT_PACKAGE_FTP=> 'YesKeyVar',
    PKGNAME => 'AnyVar',
    PKGSPEC => 'AnyVar',
    PKG_ARCH => 'ArchKeyVar',
    PSEUDO_FLAVORS => 'PseudoFlavorsVar',
    REGRESS_DEPENDS => 'RegressDependsVar',
    REGRESS_IS_INTERACTIVE => 'AnyVar',
    REVISION => 'AnyVar',
    RUN_DEPENDS => 'RunDependsVar',
    SEPARATE_BUILD => 'YesKeyVar',
    SHARED_LIBS => 'SharedLibsVar',
    SHARED_ONLY => 'YesNoVar',
    SUBPACKAGE => 'DefinedVar',
    SUPDISTFILES => 'AnyVar',
    TARGETS => 'TargetsVar',
    USE_GMAKE => 'YesNoVar',
    USE_GROFF => 'YesNoVar',
    USE_LIBTOOL => 'YesNoGnuVar',
    WANTLIB => 'WantlibVar',
};

$inserter->create_tables($vars);

my $unknown = {};

dump_dirs($inserter, $vars, $unknown, undef);

while (1) {
	my $todo = {};
	my $stuff = 0;
	for my $v (keys %{$normal->{todo}}) {
		next if $normal->{done}{$v};
		$todo->{$v} = 1;
		$stuff = 1;

	}
	last if !$stuff;
	$normal->{todo} = {};
	print "Next pass\n";
	dump_dirs($inserter, $vars, $unknown, $todo);
	for my $v (keys %$todo) {
		if (!$normal->{done}{$v}) {
			$normal->{done}{$v} = 1;
		}
	}
}

while (my ($k, $v) = each %$unknown) {
	next if $k eq 'CHECKSUM_FILE';
	print STDERR "Unknown variable $k in $v\n";
}

if (defined $opt_q) {
	open(my $log, ">", $opt_q) or die $!;
	$inserter->write_log($log);
} else {
	$inserter->write_log(\*STDERR);
}
