#!/usr/bin/perl

use strict;
use warnings;

use Cwd;
use File::Basename;

use Source::Shared::CLI 0.006;
use DistroMap 0.33;
use RPM::Source::Editor 0.900;
use RPM::Source::Tools::PackageFilter;
use RPM::Source::Tools::BuildReqStorage 0.096;
use Source::Bundle::Factory;
use RPM::Source::Dependency::Analyzer;
our @ISA=qw/Source::Shared::CLI/;

$DistroMap::Repository::opt_check_distrodb=7; # days
my $branch='sisyphus';
my $verbose=0;
my ($specfile,$update,$rpmbuild_bp,$rpmbuild_force,$to_file);
my $spec;
my @IN;
#$RPM::Source::Dependency::Analyzer::Resolver::verbose=2;
#$RPM::Source::Dependency::Analyzer::Resolver::SingleType::verbose=2;

sub cli_container_ref {['RPM::Source::Dependency::Analyzer','DistroMap::Repository']};
our @LONGOPT=(
    'b|branch=s' => \$branch,
    'bp' => \$rpmbuild_bp,
    'force' => \$rpmbuild_force,
    'spec=s'   => \$specfile,
    'to-file|to_file=s'   => \$to_file,
    'verbose+' => \$verbose,
    'q|quiet'  => sub {$verbose=0},
    'update'   => \$update,
    );
our @LONGOPT_POD2USAGE;
__PACKAGE__->get_and_process_cli_options();

$specfile=shift @ARGV if $ARGV[0] and $ARGV[0] =~ /\.spec$/;
if (not @ARGV and not ($specfile and $rpmbuild_bp)) {
    __PACKAGE__->usage();
    exit (1);
}

push @IN, @ARGV;
if (defined $specfile and -e $specfile) {
    $spec=RPM::Source::Editor->new(
	SPECFILE=>$specfile,
	);
    ### TODO! get hint from package name sub (shared with Convert)
    my $name=$spec->main_section->get_tag('Name');
    if (not $RPM::Source::Dependency::Analyzer::Collector::opt_hint) {
	$RPM::Source::Dependency::Analyzer::Collector::opt_hint=$1 if $name =~ /^(octave|perl)-/;
    }
    #### end TODO #######################

    if ($rpmbuild_bp) {
	my $builddir=$spec->macros->macro_subst('%_builddir');
	die "Oops! can't find \%_builddir" unless $builddir;
	system('rm','-rf',$builddir);
	if (system('rpmbuild','-bp','--nodeps',$specfile)!=0) {
	    if ($rpmbuild_force) {
		warn "WARNING: rpmbuild -bp --nodeps $specfile failed.\n";
	    } else {
		die "Oops! rpmbuild -bp --nodeps $specfile failed. Use --force to proceed.\n";
	    }
	}
	unshift @IN, $builddir;
    }
}

# to set ignore_buildreq to be altlinux-specific
$DistroMap::default_destrepo='altlinux';
my $distro_sisyphus=DistroMap::Repository->new(-repo=>'altlinux', -branch=>$branch);
my $buildreq=RPM::Source::Tools::BuildReqStorage->new();

my $storage=RPM::Source::Dependency::Analyzer::Storage->new();
my $collector=RPM::Source::Dependency::Analyzer::Collector->new(
    -verbose => $verbose,
    -scan_configure_for_broken_cpp_check => 1,
    );

map {&analyze($storage,$_)} @IN;
warn "WARNING: input is empty (neither source tarballs or source directories are specified, nor -bp option is used.\n" if not @IN;

my $resolver=RPM::Source::Dependency::Analyzer::Resolver->new();
$resolver->resolve(
    -verbose => $verbose,
    -spec => $spec,
    -distroinfo => $distro_sisyphus,
    -storage => $storage,
    -buildreq => $buildreq,
    );

my $nodep_msg=$spec ? "buildreq-src: $specfile already contains all found dependencies\n" : 
    "buildreq-src: nothing found.\n";
my $spec_current_state=$buildreq->collect_spec_current_deps_and_sourcedep_entry($spec);
my $entry=$buildreq->get_entry($spec_current_state);
if ($update and $spec) {
    print $entry ? $entry : $nodep_msg;
    if ($entry or $spec_current_state->{-has_sourcedep_entry}) {
	$buildreq->update_spec_entry($spec);
	$spec->write_spec($specfile);
	print STDERR "buildreq-src: updated $specfile\n";
    } else {
	print STDERR "buildreq-src: no need to update $specfile\n";
    }
} else {
    if ($to_file) {
	open (my $fn,'>>', $to_file) || die "Can't open $to_file:$!";
	print $fn $entry;
	close ($fn);
    } else {
	print $entry ? $entry : $nodep_msg;
    }
}

sub analyze {
    my ($storage,$file)=@_;
    if ($file=~/src\.rpm$/) {
	die "srpm should be installed for buildreq-src to work.\nrun rpm -i $file first.";
    } elsif ($file=~/\.rpm$/) {
	die "$file is rpm. Not a source tarball, dir or spec file.";
    }
    print STDERR '=== processing ',$file,"\n" if $verbose;
    my $bundle=Source::Bundle::Factory->create($file);
    $collector->collect_source_dependencies($storage,$bundle);
}

__END__

=head1	NAME

buildreq-src - a tool to deduce the Build Environment from Source files.

=head1	SYNOPSIS

B<buildreq-src>
[B<--help>] 
[B<-v, --verbose>]
[B<-bp>]
[B<--force>]
[[B<-s,--spec>] I<specfile>]
I<dir...> | I<tarball ...>

=head1	DESCRIPTION

buildreq-src is a tool to deduce the Build Environment from Source files.

Usage example:
print the dependencies of a tarball or sourcedir
buildreq-src ../SOURCES/Equalizer/Equalizer-1.2.1.tar.gz

add the dependencies of a tarball or sourcedir to spec file
buildreq-src --update Equalizer.spec

=head1	OPTIONS

=over

=item	B<-v, --verbose>, B<-q, --quiet>

Verbosity level. Multiple -v increase the verbosity level, -q sets it to 0.
Default is 1.

=item	B<-s, --spec> I<specfile>

Output directory.

=item	B<-bp> 

Execute rpmbuild -bp --nodeps on the spec file and add %_builddir to the list
of sources to analyze.

=item	B<--force> 

Used in conjunction with B<-bp>. Proceed even if 
rpmbuild -bp --nodeps returned bad exit code.

=item	B<--update> 

Update BuildRequires in given spec file.

=item	B<--sourcedep-*> 

Options that start with B<--sourcedep-*> are SourceAnalyzer specific options.
For current list of the options and their meaning run this program with --help.

=back

=head1	AUTHOR

Written by Igor Vlasenko <viy@altlinux.org>.

=head1	COPYING

Copyright (c) 2008-2017 Igor Vlasenko, ALT Linux Team.

This is free software; you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation;
either version 2 of the License, or (at your option) any later version.

=cut
