#!/usr/bin/perl
#Copyright (c) 2008, Zane C. Bowers
#All rights reserved.
#
#Redistribution and use in source and binary forms, with or without modification,
#are permitted provided that the following conditions are met:
#
#   * Redistributions of source code must retain the above copyright notice,
#    this list of conditions and the following disclaimer.
#   * 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.


use FreeBSD::Src;
use strict;
use warnings;
use Getopt::Std;
use File::Copy;

$Getopt::Std::STANDARD_HELP_VERSION = 1;

#version function
sub main::VERSION_MESSAGE {
	print "fbsdbuild 0.0.0\n";
}

#print help
sub main::HELP_MESSAGE {
	print("\n".
		  "-d <destdir>  The destination directory to use.\n".
		  "-s <srcdir>  The source directory to use.\n".
		  "-k <kernconf>  The kernel to use.\n".
		  "-m <makeconf>  The 'make.conf' to use.\n".
		  "-o <objdir>  The object dir to use.\n".
		  "-a <action>  The action to perform.\n".
		  "-l  List installed kernels.\n".
		  "-e  Edit kernel.\n".
		  "-b <base kernconf>  The base kernel to use for when creating a new kernel.\n".
		  "-p  Print the output upon failure.\n");
}

#gets the options
my %opts=();
getopts('d:s:k:m:o:a:leb:', \%opts);

#get what arch to use
my $arch=`uname -p`;
chomp($arch);

#we need to set, even if FreeBSD::Src will figure it out, we need to set it
#for use with -l, -e, and -b
if (!defined($opts{s})){
	$opts{s}='/usr/src/';
}

my $kernconfDir=$opts{s}."/sys/".$arch."/conf/";

if (!defined($opts{k})){
	$opts{k}="GENERIC";
}

#lists the installed kernel for the arch
if (defined($opts{l})){
	if (! -d $kernconfDir){
		warn("fbsdbuild:1: Kernel configuration dir, '".$kernconfDir."'".
			 "does not exist.");
		exit 1;
	}

	#reads the directory
	opendir(KERNELCONFDIR, $kernconfDir);
	my @direntries=readdir(KERNELCONFDIR);
	closedir(KERNELCONFDIR);

	#used for going through the list
	my $direntriesInt=0;
	while (defined($direntries[$direntriesInt])){
		my $print=1;#if still set to true later, it will be printed

		#makes sure it does not start with '.'
		if ($direntries[$direntriesInt] =~ /^\./) {
			$print=undef;
		}

		#make sure it is not equal to 'Makefile'
		if ($direntries[$direntriesInt] =~ /^Makefile$/) {
			$print=undef;
		}

		#makes sure it does not end in '.hints'
		if ($direntries[$direntriesInt] =~ /\.hints$/) {
			$print=undef;
		}

		if ($print){
			print $direntries[$direntriesInt]."\n";
		}

		$direntriesInt++;
	}

	exit 0;
}

#edits a specified kernel
if (defined($opts{e})){

	my $kernconf=$kernconfDir."/".$opts{k};

	#The base kernel to use for creating a new kernel.
	if (defined($opts{b})){
		#makes sure they are not the same
		if ($opts{b} eq $opts{k}){
			warn("fbsdbuild:2: The specified base KERNCONF and KERNCONF are the same");
			exit 2;
		}

		#copies the base KERNCONF to the KERNCONF
		if (!copy($kernconfDir."/".$opts{b}, $kernconf)){
			warn("fbsdbuild:3: Could not copy base KERNCONF, '".
				 $kernconfDir."/".$opts{b}."', to KERNCONF, '".
				 $kernconf.",");
			exit 3;
		}
	}

	#edit it
	exec($ENV{EDITOR}." ".$kernconf);
}

#if we get to this point, it means we need to create the FreeBSD::Src object
my $src=FreeBSD::Src->new({obj=>$opts{o}, src=>$opts{s},
						   kernel=>$opts{k}, makeconf=>$opts{m}});

#
if (defined($src->{error})){
	
}

#handles supplied action
if (defined($opts{a})){
	#builds the kernel
	if ($opts{a} eq "makekernel"){
		$src->makeBuildKernel;
		if (defined($src->{error})){
			if (defined($opts{p})){
				print $src->{returned};
			}
			warn("fbsdbuild:4: Building the kernel failed.");
			exit 4;
		}
	}

	#installs the kernel
	if ($opts{a} eq "installkernel"){
		$src->makeInstallKernel;
		if (defined($src->{error})){
			if (defined($opts{p})){
				print $src->{returned};
			}
			warn("fbsdbuild:5: Installing the kernel failed.");
			exit 5;
		}
	}

	#handles the kernel
	if ($opts{a} eq "kernel"){
		#builds the kernel
		$src->makeBuildKernel;
		if (defined($src->{error})){
			if (defined($opts{p})){
				print $src->{returned};
			}
			warn("fbsdbuild:4: Building the kernel failed.");
			exit 4;
		}

		#installs the kernel
		$src->makeInstallKernel;
		if (defined($src->{error})){
			if (defined($opts{p})){
				print $src->{returned};
			}
			warn("fbsdbuild:5: Installing the kernel failed.");
			exit 5;
		}
	}

	#builds the world
	if ($opts{a} eq "buildworld"){
		$src->makeBuildWorld;
		if (defined($src->{error})){
			if (defined($opts{p})){
				print $src->{returned};
			}
			warn("fbsdbuild:6: Building the world failed.");
			exit 6;
		}
	}

	#installs the world
	if ($opts{a} eq "installworld"){
		$src->makeInstallWorld;
		if (defined($src->{error})){
			if (defined($opts{p})){
				print $src->{returned};
			}
			warn("fbsdbuild:7: Installing the world failed.");
			exit 7;
		}
	}

	#handles the world
	if ($opts{a} eq "world"){
		#builds the world
		$src->makeBuildWorld;
		if (defined($src->{error})){
			if (defined($opts{p})){
				print $src->{returned};
			}
			warn("fbsdbuild:6: Building the world failed.");
			exit 6;
		}

		#installs the world
		$src->makeInstallWorld;
		if (defined($src->{error})){
			if (defined($opts{p})){
				print $src->{returned};
			}
			warn("fbsdbuild:7: Installing the world failed.");
			exit 7;
		}
	}
}



=head1 NAME

fbsdbuild - A tool for building FreeBSD from source.

=head1 SYNOPSIS

fbsdbuild B<-l> [B<-s> <srcdir>]

fbsdbuild B<-e> [B<-s> <srcdir>] [B<-k> <KERNCONF>] [B<-b> <base KERNCONF>]

fbsdbuild B<-a <action> <B<-s> <srcdir>> [B<-k> <KERNCONF>] [B<-o> <objdir>] [B<-p>] [B<-m> <make.conf>]

=head1 SWTICHES

=head2 -a <action>

The action to take. See the section ACTION for more information.

=head2 -b <base KERNCONF>

If this is defined, in addition to -e, this KERNCONF is copied to
the one specified by -k, before the editor is invoked.

=head2 -d <destination dir>

The destination directory to use.

=head2 -e

Edits a specified KERNCONF. The environmental variable 'EDITOR' is used
for determining what to use for a editor.

=head2 -k

The KERNCONF to use.

=head2 -l

Lists the KERNCONFs for the current architecture.

=head2 -m <make.conf>

The make.conf to use. The default is '/etc/make.conf'.

=head2 -o <object dir>

The object directory to use.

=head2 -p

Print the output if it failed.

=head2 -s <source dir>

The source dir to use. The default is '/usr/src'.

=head1 ERROR CODES

=head2 1

Kernel configuration directory does not exist.

=head2 2

The specified base KERNCONF is the same as the specified KERNCONF. -b and -k
can not be the same.

=head2 3

Could not copy the base KERNCONF to the KERNCONF.

=head2 4

Building the kernel failed.

=head2 5

Installing the kernel failed.

=head2 6

Building the world failed.

=head2 7

Installing the world failed.

=head1 AUTHOR

Copyright (c) 2008, Zame C. Bowers <vvelox@vvelox.net>

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

    * Redistributions of source code must retain the above copyright notice,
     this list of conditions and the following disclaimer.
    * 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 COPYRIGHT HOLDERS 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 COPYRIGHT OWNER 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.

=head1 Changelog

=head2 2008-06-29/16:00

Initial release.

=head1 SCRIPT CATEGORIES

UNIX/System_administration

=head1 OSNAMES

FreeBSD

=head1 README

fbsdbuild - A tool for building FreeBSD from source.

=cut