Carmel

 view release on metacpan or  search on metacpan

lib/Carmel/App.pm  view on Meta::CPAN

    my $code = 0;
    try {
        $self->$call(@args);
    } catch {
        warn $_;
        $code = 1;
    };

    return $code;
}

sub repository_base {
    my $self = shift;

    my $home = $ENV{HOME} || $ENV{HOMEPATH};
    Path::Tiny->new($ENV{PERL_CARMEL_REPO} || "$home/.carmel/" . $self->perl_arch);
}

sub repo {
    my $self = shift;
    $self->{repo} ||= $self->build_repo;
}

sub build_repo {
    my $self = shift;
    Carmel::Repository->new(path => $self->repository_base->child('builds'));
}

sub cmd_help {
    my $self = shift;
    print "Carmel version $Carmel::VERSION\n\n";
    Pod::Usage::pod2usage(1);
}

sub cmd_version {
    my $self = shift;
    print "Carmel version $Carmel::VERSION\n";
}

sub cmd_inject {
    my($self, @args) = @_;
    $self->builder->install("--reinstall", @args);
}

sub cmd_pin {
    my($self, @args) = @_;
    die "carmel pin is deprecated. Use `carmel update @args` instead\n";
}

sub cmd_update {
    my($self, @args) = @_;

    my $snapshot = $self->snapshot
      or die "Can't run carmel update without snapshot. Run `carmel install` first.\n";

    print "---> Checking updates...\n";

    $self->update_or_install($snapshot, @args);
}

sub update_or_install {
    my($self, $snapshot, @args) = @_;

    my $builder = $self->builder;
    my $requirements = $self->requirements;

    my $check = sub {
        my($module, $pathname, $in_args, $version) = @_;

        return if $module eq 'perl';

        my $dist = $builder->search_module($module, $version);
        unless ($dist) {
            if ($version) {
                die "Can't find $module ($version) on CPAN\n";
            } else {
                # workaround bad main package e.g. LWP => libwww::perl
                warn "Can't find $module on CPAN\n";
                return;
            }
        }

        if ($dist->pathname ne $pathname && $snapshot) {
            $snapshot->remove_distributions(sub {
                my $dist = shift;
                $dist->provides_module($module);
            });
        }

        if (defined $version) {
            try {
                $requirements->add_string_requirement($module, $version);
            } catch {
                my($err) = /illegal requirements(?: .*?): (.*) at/;
                my $old = $requirements->requirements_for_module($module);
                die "Requested version for $module '$version' conflicts with version required in cpanfile '$old': $err\n";
            };
        } else {
            my $want_ver = $dist->version_for($module);
            try {
                $requirements->add_string_requirement($module, $want_ver);
            } catch {
                # there's an update but it conflicts with specs in cpanfile, ignoring
                if ($in_args) {
                    my($err) = /illegal requirements(?: .*?): (.*) at/;
                    my $old = $requirements->requirements_for_module($module);
                    die "The update for $module '$want_ver' conflicts with version required in cpanfile '$old' $err\n";
                }
            };
        }
    };

    if (@args) {
        for my $arg (@args) {
            my($module, $version) = split '@', $arg, 2;
            my $dist = $snapshot ? $snapshot->find($module) : undef;
            if ($dist) {
                $check->($module, $dist->pathname, 1, $version ? "== $version" : undef);
            } elsif (defined $requirements->requirements_for_module($module)) {
                $check->($module, '', 1, $version ? "== $version" : undef);
            } else {
                die "$module is not found in cpanfile or cpanfile.snapshot\n";
            }
        }
    } else {
        my $missing = $requirements->clone;

        my @checks;
        my $resolver = $self->resolver(
            root     => $self->requirements->clone,
            snapshot => $snapshot,
            found    => sub {
                my $artifact = shift;
                for my $pkg (keys %{$artifact->provides}) {
                    $missing->clear_requirement($pkg);
                }
                push @checks, [ $artifact->package, $artifact->install->{pathname}, 0 ];
            },
            missing  => sub {
                my($module, $want_version) = @_;
                $missing->add_string_requirement($module => $want_version);
            },
        );
        $resolver->resolve;

        # snapshot not supplied (first carmel install), or
        # specified in cpanfile but not in snapshot, possibly core module
        for my $module ($missing->required_modules) {
            push @checks, [ $module, '', 0 ];
        }

        progress \@checks, sub { $check->(@{$_[0]}) };
    }

    # rebuild the snapshot
    $self->update_dependencies($requirements, $snapshot);
}

sub cmd_install {
    my($self, @args) = @_;

    die "Usage: carmel install\n" if @args;

    my $snapshot = $self->snapshot;
    if ($snapshot) {
        $self->update_dependencies($self->requirements, $snapshot);
    } else {
        print "---> Installing modules...\n";
        $self->update_or_install($snapshot);
    }
}

sub update_dependencies {
    my($self, $root_reqs, $snapshot) = @_;

    my @artifacts = $self->install($root_reqs, $snapshot);
    $self->dump_bootstrap(\@artifacts);
    $self->save_snapshot(\@artifacts);
}

sub resolve_dependencies {
    my($self, $root_reqs, $missing, $snapshot) = @_;

    my @artifacts;
    $self->resolver(
        root     => $root_reqs,
        snapshot => $snapshot,
        found    => sub {
            my $artifact = shift;
            printf "Using %s (%s)\n", $artifact->package, $artifact->version || '0';
            push @artifacts, $artifact;
        },
        missing  => sub {
            my($module, $want_version) = @_;
            $missing->add_string_requirement($module => $want_version);
        },
    )->resolve;

    return @artifacts;
}

sub is_identical_requirement {
    my($self, $old, $new) = @_;

    return unless $old;

    # not super accurate but enough
    join(',', sort $old->required_modules) eq join(',', sort $new->required_modules);
}

sub try_install {
    my($self, $root_reqs, $snapshot) = @_;

    my $prev;
    while (1) {
        my $missing = CPAN::Meta::Requirements->new;
        my @artifacts = $self->resolve_dependencies($root_reqs, $missing, $snapshot);

        if (!$missing->required_modules) {
            return @artifacts;
        }

        if ($self->is_identical_requirement($prev, $missing)) {
            my $prereqs = $missing->as_string_hash;
            my $requirements = join ", ", map "$_ => @{[ $prereqs->{$_} || '0' ]}", keys %$prereqs;
            die "Can't find an artifact for $requirements\n" .
              "You need to run `carmel install` first to get the modules installed and artifacts built.\n";
        }

        $prev = $missing;

        my $cpanfile = Module::CPANfile->from_prereqs({
            runtime => {



( run in 1.033 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )