The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
package CPAN::Packager::ConflictionChecker;
use Mouse;
use Config;
use Module::CoreList;
use FileHandle;
use Log::Log4perl qw(:easy);
use CPAN::Packager::ListUtil qw(uniq any);
use CPAN::Packager::DualLivedList;
use File::Spec;

has 'checked_duallived_modules' => (
    is      => 'rw',
    default => sub {
        [];
    }
);

sub check_conflict {
    my ( $self, $module_name ) = @_;

    return unless scalar @{ $self->checked_duallived_modules };

    if ( my $error_message = $self->check_install_settings_conflicted() ) {
        my @checked_duallived_modules
            = uniq @{ $self->checked_duallived_modules };
        my @module_may_conflicts = ();
        foreach my $duallived (@checked_duallived_modules) {

            # We emit warnings for only really installing the module modules
            # Those other modules were already installed via RPM in the past
            # must be ignored
            if ( $self->is_privlib_installed($duallived)
                && !$self->is_vendor_installed($duallived) )
            {
                push @module_may_conflicts, $duallived;
            }
        }
        my $module_names = join ",", @module_may_conflicts;
        return $self->emit_confliction_warnings( $module_names,
            $error_message );
    }
}

sub is_dual_lived_module {
    my ( $self, $module_name ) = @_;

    my $dual_lived_list = CPAN::Packager::DualLivedList->new;
    if ( $dual_lived_list->is_duallived_module($module_name) ) {
        push @{ $self->checked_duallived_modules }, $module_name;
        return 1;
    }
    else {
        return 0;
    }
}

# This checks modules which may conflict with the given dual-lived module
sub is_privlib_installed {
    my ( $self, $module ) = @_;

    my $file = File::Spec->catfile( split /(?:\'|::)/, $module ) . '.pm';
    my $is_privlib_installed;
    if (   -e File::Spec->catfile( $Config{installprivlib}, $file )
        || -e File::Spec->catfile( $Config{installarchlib}, $file ) )
    {
        $is_privlib_installed = 1;
    }
    else {
        $is_privlib_installed = 0;
    }

    DEBUG(
        "Is this module( $module ) installed at privlib or archlib?: $is_privlib_installed"
    );
    return $is_privlib_installed;
}

# This checks modules which are already installed
sub is_vendor_installed {
    my ( $self, $module ) = @_;

    my $file = File::Spec->catfile( split /(?:\'|::)/, $module ) . '.pm';
    my $is_vendor_installed;
    if (   -e File::Spec->catfile( $Config{installvendorlib}, $file )
        || -e File::Spec->catfile( $Config{installvendorarch}, $file ) )
    {
        $is_vendor_installed = 1;
    }
    else {
        $is_vendor_installed = 0;
    }

    DEBUG(
        "Is this module( $module ) installed at vendorlib or vendorarch?: $is_vendor_installed"
    );
    return $is_vendor_installed;
}

sub check_install_settings_conflicted {
    my @error_messages = ();

    if ( $Config{installman1dir} eq $Config{installvendorman1dir} ) {
        push @error_messages,
            "!! - installman1dir and installvendorman1dir is same value.";
    }

    if ( $Config{installman3dir} eq $Config{installvendorman3dir} ) {
        push @error_messages,
            "!! - installman3dir and installvendorman3dir is same value.";
    }

    if ( $Config{installbin} eq $Config{installvendorbin} ) {
        push @error_messages,
            "!! - installbin and installvendorbin is same value";
    }

    if ( $Config{installprivlib} eq $Config{installvendorlib} ) {
        push @error_messages,
            "!! - installprivlib and installvendorlib is same value";
    }

    if ( $Config{installscript} eq $Config{installvendorscript} ) {
        push @error_messages,
            "!! - installscript and installvendorscript is same value";
    }

    if ( $Config{installarchlib} eq $Config{installvendorarch} ) {
        push @error_messages,
            "!! - installarchliba and installvendorarch is same value";
    }

    if (@error_messages) {
        return join "\n", @error_messages;
    }
    else {
        return 0;
    }
}

sub _create_confliction_warnings {
    my ( $self, $module_names, $error_message ) = @_;

    my $warning_message = <<"EOS";
WARNINGS 
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! The following modules that are being installed may conflict 
!! with existing modules on the system: 
!!
!!   $module_names
!!
!! Causes:
$error_message
!!
!! Solution:
!!    It is possible for a CPAN::Packager user to explicitly specify
!!    installation locations for a distribution's libraries, documentation,
!!    man pages, binaries, and scripts. Setting both of the below environment
!!    variables, for example, will accomplish this.
!!
!!     PERL_MM_OPT="INSTALLVENDORMAN1DIR=/usr/local/share/man/man1
!!     INSTALLVENDORMAN3DIR=/usr/local/share/man/man3
!!     INSTALLVENDORBIN=/usr/local/bin INSTALLVENDORSCRIPT=/usr/local/bin"
!!
!!     PERL_MB_OPT="--config installvendorman1dir=/usr/local/share/man/man1
!!     --config installvendorman3dir=/usr/local/share/man/man3 --config
!!     installvendorbin=/usr/local/bin --config installvendorscript=/usr/local/bin"
!! 
!!    You can see the current installation setting with:
!!
!!     perl '-V:install.*'
!!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
EOS

    return $warning_message;
}

sub emit_confliction_warnings {
    my ( $self, $module_names, $error_message ) = @_;
    my $warning_message = $self->_create_confliction_warnings( $module_names,
        $error_message );
    WARN($warning_message);
    return $warning_message;
}

1;

__END__

=head1 NAME

CPAN::Packager::ConflictionChecker - check confliction 

=head1 SYNOPSIS

=head1 DESCRIPTION

=head1 LICENSE

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut