#!/usr/bin/perl -w

use strict;

if (@ARGV != 1) {
	print STDERR "Usage: freebsd-cleanup.pl <workdir>\n";
	exit 1;
}

my $workdir = $ARGV[0];

mkdir $workdir unless -d($workdir);

build_fullworld();
build_customworld();

install_fullworld();
install_customworld();

compare_worlds();
edit_list();
cleanup();

sub build_fullworld {
	return if -f("$workdir/done-full_obj");

	print STDERR "==> Building full world...\n";

	system "rm -rf $workdir/full_obj";
	mkdir "$workdir/full_obj";
	$ENV{MAKEOBJDIRPREFIX} = "$workdir/full_obj";
	$ENV{__MAKE_CONF} = "/nonexistant";
	chdir "/usr/src";
	unless (system "make buildworld") {
		touch("$workdir/done-full_obj");
	} else {
		die "Failed to build full world";
	}
}

sub build_customworld {
	return if -f("$workdir/done-custom_obj");

	print STDERR "==> Building custom world...\n";

	system "rm -rf $workdir/custom_obj";
	mkdir "$workdir/custom_obj";
	$ENV{MAKEOBJDIRPREFIX} = "$workdir/custom_obj";
	delete $ENV{__MAKE_CONF};
	chdir "/usr/src";
	unless (system "make buildworld") {
		touch("$workdir/done-custom_obj");
	} else {
		die "Failed to build custom world";
	}
}

sub install_fullworld {
	return if -f("$workdir/done-full_inst");

	print STDERR "==> Installing full world...\n";

	system "rm -rf $workdir/full_inst";
	mkdir "$workdir/full_inst";
	$ENV{MAKEOBJDIRPREFIX} = "$workdir/full_obj";
	$ENV{__MAKE_CONF} = "/nonexistant";
	chdir "/usr/src";
	unless (system "make installworld DESTDIR=$workdir/full_inst") {
		touch("$workdir/done-full_inst");
	} else {
		die "Failed to install full world";
	}
}

sub install_customworld {
	return if -f("$workdir/done-custom_inst");

	print STDERR "==> Installing custom world...\n";

	system "rm -rf $workdir/custom_inst";
	mkdir "$workdir/custom_inst";
	$ENV{MAKEOBJDIRPREFIX} = "$workdir/custom_obj";
	delete $ENV{__MAKE_CONF};
	chdir "/usr/src";
	unless (system "make installworld DESTDIR=$workdir/custom_inst") {
		touch("$workdir/done-custom_inst");
	} else {
		die "Failed to install custom world";
	}
}

sub compare_worlds {
	print "==> Comparing worlds\n";

	my @full_files = map {substr($_, length("$workdir/full_inst"))} `find $workdir/full_inst -type f`;
	my %custom_files = map {substr($_, length("$workdir/custom_inst")) => 1} `find $workdir/custom_inst -type f`;

	my @bad_files = ();

	for my $full (@full_files) {
		push @bad_files, $full unless exists $custom_files{$full};
	}

	open (FILE, ">$workdir/badfiles.txt") or die "Couldn't open $workdir/badfiles.txt for writing: $!";
	print FILE @bad_files;
	close FILE;
}

sub edit_list {
	system "vi $workdir/badfiles.txt";
}

sub cleanup {
	print STDERR "Should I delete the selected files now? ";
	my $answer = <STDIN>;
	if ($answer =~ /^y/i) {
		print STDERR "==> Deleting files...\n";
		open (FILE, "$workdir/badfiles.txt") or die "Couldn't open $workdir/badfiles.txt for reading: $!";
		my @files = <FILE>;
		close FILE;
		chomp @files;

		my $count = 0;
		for my $file (@files) {
			if (-f($file)) {
				$count++;

				system "chflags noschg '$file'";
				unlink $file;
			}
		}
		print STDERR "$count files deleted\n";
	}
}

sub touch {
	my ($file) = @_;

	open (FILE, ">$file") or die "Couldn't open $file for writing: $!";
	close FILE;
}
