#!perl -lw
# pipe find lib/ghc-*/package.conf.d
#typical usage is boot= and plain=
while (defined($file=<STDIN>)){
    chomp$file;
    #next if $file eq 'package.cache';
    #next if $file =~ /^base-noprelude-[0-9.]+-/;
    #next if $file eq 'Cabal-1.24.0.0.conf'; #1.24.2.0 installed over
    #next if $file eq 'haskeline-0.7.2.3.conf';
    die $file unless $file=~m!([^/]+)(-[0-9.]+)?(-[^-]+)?\.conf$!;
    #$mini=$1;
    open FI,$file or die;
    undef$sigil;
    undef$key;
    while(<FI>){
        chomp;
        last if(/^exposed\s*:\s*False\s*$/);
        if(/^key\s*:\s*(.*)/){
            die if defined$key;
            $key=$1;
            die if $key=~/\s/;
        }
        if($sigil){
            if(/^\S/){
                last;
            } else {
                s/^\s*//;
                die unless defined($key);
                $a{$key}.=' ' if defined$a{$key};
                $a{$key}.=$_;
            }
        } else {
            if (/^\s*exposed-modules:/){
                die unless /^exposed-modules:$/;
                $sigil=1
            }
        }
    }
    close FI;
}
for$j(keys%a){
    for($a{$j}){
        unless(/,/){
            for(split){
                push @{$ii{$_}},$j;
            }
        }else{
            for(split /\s*,\s*/){
                if (/^(\S+) from (.*):(.*)$/){
                    push @{$ii{$1}},$j
                } elsif (/^\S+$/){
                    push @{$ii{$_}},$j
                } else {
                    die $_;
                }
            }
        }
    }
}
unless (defined$ARGV[0]){
    for$m(sort keys %ii){
        next unless (@{$ii{$m}}>1);
        $line="$m: ".scalar@{$ii{$m}};
        for(@{$ii{$m}}){
            if (/^(.+-[0-9.]+-)([0-9A-Za-z]+)$/){
                $_=$1
            }
            $line.=" $_";
        }
        print$line;
    }
} elsif ($ARGV[0]eq'grouped'){
    for$m(sort keys %ii){
        next unless (@{$ii{$m}}>1);
        $collision_group='';
        for(sort@{$ii{$m}}){
            if (/^(.+-[0-9.]+-)([0-9A-Za-z]+)$/){
                $_=$1
            }
            $collision_group.=" $_";
        }
        s/^ // for($collision_group);
        push @{$cc{$collision_group}},$m;
    }
    for(sort keys %cc){
        print;
        for(@{$cc{$_}}){
            print"  $_";
        }
    }
} elsif (($fn)=$ARGV[0]=~/plain=(.*)/){
    # modules whose names are not hierarchical
    if(defined($fn)){
        open FI,$fn or die;
        die unless defined($_=<FI>);
        die unless /package\.conf\.d$/;
        $emptycount=0;
        while(<FI>){
            chomp;
            if(/^\s*$/){
                $emptycount++;
                next;
            }
            next if /^\s+\(\S+\)$/; #hidden
            die unless /^\s+(.+)-[0-9.]+$/;
            $boots{$1}=1;
        }
        die unless $emptycount==1;# at the end of the file
    }
    for$m(sort keys %ii){
        next if $m =~ /\./;
        for(@{$ii{$m}}){
            ($canonical=$_)=~s/-[0-9.]+(-[0-9A-Za-z]+)?$//;
            #if (/^(.+-[0-9.]+-)([0-9A-Za-z]+)$/){                $_=$1            }
            if($boots{$canonical}){
                print STDERR "INFO boot not hierarchical $m $_";
            } else {
                print STDERR "INFO not hierarchical $m $_";
                print"$canonical"
            }
        }
    }
} elsif ($ARGV[0]eq'base'){
    #modules which overlap with base
    # you actually probably want boot-collisions below
    for$m(sort keys %ii){
        next unless (@{$ii{$m}}>1);
        $bfound=0;
        for(@{$ii{$m}}){
            $bfound++ if /^base-[0-9.]+(-[0-9A-Za-z]+)?$/;
        }
        next unless $bfound;
        die unless $bfound==1;
        for(@{$ii{$m}}){
            next if /^base-[0-9.]+(-[0-9A-Za-z]+)?$/;
            print "$_ $m";
        }

    }
} elsif (($fn)=$ARGV[0]=~/^boot=(.*)/){
    #modules which overlap with boot packages
    #fn is the output of ghc-pkg before running any package installs
    if(defined($fn)){
        open FI,$fn or die;
        die unless defined($_=<FI>);
        die unless /package\.conf\.d$/;
        $emptycount=0;
        while(<FI>){
            chomp;
            if(/^\s*$/){
                $emptycount++;
                next;
            }
            next if /^\s+\(\S+\)$/; #hidden
            die unless /^\s+(.+)-[0-9.]+$/;
            $boots{$1}=1;
        }
        die unless $emptycount==1;# at the end of the file
    }
    for$m(sort keys %ii){
        next unless (@{$ii{$m}}>1);
        $bfound=0;
        $notb=0;
        for$p(@{$ii{$m}}){
            #print "eval $p";
            ($_=$p)=~s/-[0-9.]+(-[0-9A-Za-z]+)?$//;
            if($boots{$_}){
                $bfound++;
            }else{
                $notb++;
            }
        }
        next unless $bfound and $notb;
        for(@{$ii{$m}}){
            ($canonical=$_)=~s/-[0-9.]+(-[0-9A-Za-z]+)?$//;
            if($boots{$canonical}){
                print STDERR "INFO $m boot=$_";
            }else{
                print STDERR "INFO $m $_";
                print $canonical
            }

        }
    }
}
