diff --git a/lib/Panda.pm b/lib/Panda.pm index 602bdcd..d5e7ea8 100644 --- a/lib/Panda.pm +++ b/lib/Panda.pm @@ -1,5 +1,6 @@ use v6; use Pies; +use JSON::Tiny; class Panda is Pies { use Panda::Ecosystem; @@ -7,11 +8,13 @@ class Panda is Pies { use Panda::Builder; use Panda::Tester; use Panda::Installer; + use Panda::Resources; has $!srcdir; has $!destdir; has $!statefile; has $!projectsfile; + has $!resources; submethod BUILD { callsame; # attribute initialization @@ -19,12 +22,13 @@ class Panda is Pies { statefile => $!statefile, projectsfile => $!projectsfile, ); - $!fetcher = Panda::Fetcher.new(srcdir => $!srcdir); - $!builder = Panda::Builder.new(srcdir => $!srcdir); - $!tester = Panda::Tester.new(srcdir => $!srcdir); + $!resources = Panda::Resources.new(srcdir => $!srcdir); + $!fetcher = Panda::Fetcher.new(resources => $!resources); + $!builder = Panda::Builder.new(resources => $!resources); + $!tester = Panda::Tester.new(resources => $!resources); $!installer = Panda::Installer.new( - srcdir => $!srcdir, - destdir => $!destdir + resources => $!resources, + destdir => $!destdir, ); } @@ -53,7 +57,26 @@ class Panda is Pies { } multi method announce('depends', Pair $p) { - self.announce: "{$p.key.name} depends on {$p.value.name}" + self.announce: "{$p.key.name} depends on {$p.value.join(", ")}" + } + + method resolve($proj as Str, Bool :$nodeps, Bool :$notests) { + if $proj.IO ~~ :d and "$proj/META.info".IO ~~ :f { + my $mod = from-json slurp "$proj/META.info"; + my $p = Pies::Project.new( + name => $mod, + version => $mod, + dependencies => $mod, + metainfo => $mod, + ); + if $.ecosystem.get-project($p.name) { + self.announce: "Installing {$p.name} " + ~ "from a local directory '$proj'"; + } + $.ecosystem.add-project($p); + nextwith($p.name, :$nodeps, :$notests); + } + nextsame; } } diff --git a/lib/Panda/Builder.pm b/lib/Panda/Builder.pm index 2ead1d8..254a983 100644 --- a/lib/Panda/Builder.pm +++ b/lib/Panda/Builder.pm @@ -4,7 +4,7 @@ use File::Find; use File::Mkdir; class Panda::Builder does Pies::Builder { - has $!srcdir; + has $!resources; method build-order(@list) { # TODO @@ -12,8 +12,9 @@ class Panda::Builder does Pies::Builder { } method build(Pies::Project $p) { - return unless "$!srcdir/{dirname $p.name}/lib".IO ~~ :d; - indir "$!srcdir/{dirname $p.name}", { + my $workdir = $!resources.workdir($p); + return unless "$workdir/lib".IO ~~ :d; + indir $workdir, { if "Configure.pl".IO ~~ :f { run 'perl6 Configure.pl' and die "Configure.pl failed"; } diff --git a/lib/Panda/Ecosystem.pm b/lib/Panda/Ecosystem.pm index f6be87c..0250cd4 100644 --- a/lib/Panda/Ecosystem.pm +++ b/lib/Panda/Ecosystem.pm @@ -30,7 +30,7 @@ class Panda::Ecosystem is Pies::Ecosystem { dependencies => $mod, metainfo => $mod, ); - %!projects{$mod} = $p; + self.add-project($p); } } @@ -47,7 +47,7 @@ class Panda::Ecosystem is Pies::Ecosystem { # Pies::Ecosystem methods method add-project(Pies::Project $p) { - %!projects.push($p.name, $p); + %!projects{$p.name} = $p; } method get-project($p as Str) { diff --git a/lib/Panda/Fetcher.pm b/lib/Panda/Fetcher.pm index 86e5658..d6951be 100644 --- a/lib/Panda/Fetcher.pm +++ b/lib/Panda/Fetcher.pm @@ -1,26 +1,41 @@ use Pies; use Panda::Common; +use Panda::Resources; +use File::Find; +use File::Mkdir; class Panda::Fetcher does Pies::Fetcher { - has $!srcdir; + has $!resources; method fetch (Pies::Project $p) { - my $dir = dirname($p.name); - unless $p.metainfo eq 'git' { - die "Failed fetching {$p.name}, " - ~ "sources other than git not yet supported" - } - my $url = $p.metainfo; - indir $!srcdir, { - if "{$!srcdir}/$dir".IO ~~ :d { - indir $dir, { - run 'git pull -q' + my $dest = $!resources.workdir($p); + my $url = $p.metainfo; + given $p.metainfo { + when 'git' { + if $dest.IO ~~ :d { + indir $dest, { + run 'git pull -q' and die "Failed updating the {$p.name} repo"; - }; - } else { - run "git clone -q $url $dir" - and die "Failed cloning the {$p.name} repo"; + }; + } else { + run "git clone -q $url $dest" + and die "Failed cloning the {$p.name} repo"; + } + } + when 'local' { + for find(dir => $url).list { + # that's sort of ugly, I know, but we need + # stripped + my $where = "$dest/{$_.dir.substr($url.chars)}"; + mkdir $where, :p; + next if $_.IO ~~ :d; + $_.IO.copy("$where/{$_.name}"); + } } - }; + default { + die "Failed fetching {$p.name}, " + ~ "repo-type $_ not supported"; + } + } # returns the directory where the module lies # return {$Settings::srcdir} ~ "/$name"; } diff --git a/lib/Panda/Installer.pm b/lib/Panda/Installer.pm index 3181c4c..64e0775 100644 --- a/lib/Panda/Installer.pm +++ b/lib/Panda/Installer.pm @@ -4,11 +4,11 @@ use File::Find; use File::Mkdir; class Panda::Installer does Pies::Installer { - has $!srcdir; + has $!resources; has $!destdir; method install(Pies::Project $p) { - indir "$!srcdir/{dirname $p.name}", { + indir $!resources.workdir($p), { if 'blib'.IO ~~ :d { for find(dir => 'blib', type => 'file').list -> $i { # .substr(5) to skip 'blib/' diff --git a/lib/Panda/Resources.pm b/lib/Panda/Resources.pm new file mode 100644 index 0000000..eef437e --- /dev/null +++ b/lib/Panda/Resources.pm @@ -0,0 +1,10 @@ +use Pies; + +class Panda::Resources { + has $!srcdir; + method workdir(Pies::Project $p) { + "$!srcdir/{$p.name.subst(':', '_', :g)}" + } +} + +# vim: ft=perl6 diff --git a/lib/Panda/Tester.pm b/lib/Panda/Tester.pm index 0a2c093..16d679c 100644 --- a/lib/Panda/Tester.pm +++ b/lib/Panda/Tester.pm @@ -2,10 +2,10 @@ use Pies; use Panda::Common; class Panda::Tester does Pies::Tester { - has $!srcdir; + has $!resources; method test(Pies::Project $p) { - indir "$!srcdir/{dirname $p.name}", { + indir $!resources.workdir($p), { if 'Makefile'.IO ~~ :f { run 'make test' and die "'make test' failed for {$p.name}"; diff --git a/lib/Pies.pm b/lib/Pies.pm index afb753b..7fe588d 100644 --- a/lib/Pies.pm +++ b/lib/Pies.pm @@ -46,35 +46,50 @@ class Pies { method announce(Str $what, $data) { } + method fetch-helper(Pies::Project $bone) { + self.announce('fetching', $bone); + $!fetcher.fetch($bone); + } + method build-helper(Pies::Project $bone) { + self.announce('building', $bone); + $!builder.build($bone); + } + method test-helper(Pies::Project $bone) { + self.announce('testing', $bone); + $!tester.test($bone); + } + method install-helper(Pies::Project $bone) { + self.announce('installing', $bone); + $!installer.install($bone); + } + method deps-helper(Pies::Project $bone) { + return unless $bone.dependencies[0]; + # return a list of projects to be installed + my @deps = $bone.dependencies.map: { + my $littlebone = $.ecosystem.get-project($_) + or die "{$bone.name} depends on $_, " + ~ "which was not found in the ecosystem"; + + next unless $.ecosystem.project-get-state($littlebone) + eq 'absent'; + $littlebone; + }; + self.announce('depends', $bone => @depsĀ».name) if +@deps; + return @deps; + } + method resolve-helper(Pies::Project $bone, $nodeps, $notests, $isdep as Bool) { unless $nodeps { - for $bone.dependencies -> $dep { - next unless $dep; - my $littlebone = $.ecosystem.get-project($dep); - unless $littlebone { - die "Dependency $dep not found in the ecosystem"; - } - next unless $.ecosystem.project-get-state($littlebone) - eq 'absent'; - self.announce('depends', $bone => $littlebone); - self.resolve-helper($littlebone, $nodeps, $notests, 1); + for self.deps-helper($bone) { + self.resolve-helper($_, $nodeps, $notests, 1); } } - self.announce('fetching', $bone); - $!fetcher.fetch: $bone; - - self.announce('building', $bone); - $!builder.build: $bone; - - unless $notests { - self.announce('testing', $bone); - $!tester.test: $bone; - } - - self.announce('installing', $bone); - $!installer.install: $bone; + self.fetch-helper($bone); + self.build-helper($bone); + self.test-helper($bone) unless $notests; + self.install-helper($bone); $.ecosystem.project-set-state($bone, $isdep ?? 'installed-dep' !! 'installed'); diff --git a/t/panda/builder.t b/t/panda/builder.t index aca63bc..d6da155 100644 --- a/t/panda/builder.t +++ b/t/panda/builder.t @@ -1,11 +1,13 @@ use Test; use Panda::Builder; +use Panda::Resources; plan 3; my $srcdir = 'testmodules'; -my $b = Panda::Builder.new(srcdir => $srcdir); +my $r = Panda::Resources.new(srcdir => $srcdir); +my $b = Panda::Builder.new(resources => $r); my $p = Pies::Project.new(name => 'dummymodule'); diff --git a/t/panda/fetcher.t b/t/panda/fetcher.t index 5931612..3fdca9a 100644 --- a/t/panda/fetcher.t +++ b/t/panda/fetcher.t @@ -1,9 +1,12 @@ use Test; use Panda::Fetcher; +use Panda::Resources; -plan 2; +plan 4; -my $f = Panda::Fetcher.new(srcdir => '/tmp/whatever'); +my $srcdir = 'REMOVEME'; +my $r = Panda::Resources.new(srcdir => $srcdir); +my $f = Panda::Fetcher.new(resources => $r); my $p = Pies::Project.new( name => 'foobar', @@ -19,6 +22,14 @@ ok $! ~~ /'Failed cloning'/, 'attempts to clone'; $p.metainfo = 'hg'; try { $f.fetch($p) } -ok $! ~~ /'other than git'/, 'checks repo-type'; +ok $! ~~ /'hg not supported'/, 'checks repo-type'; + +$p.metainfo = 'local'; +$p.metainfo = 'testmodules/dummymodule'; + +lives_ok { $f.fetch($p) }, 'can fetch a local project'; +ok "$srcdir/foobar/lib/foo.pm".IO ~~ :f, 'fetch ok'; + +run "rm -r $srcdir"; # vim: ft=perl6 diff --git a/t/panda/installer.t b/t/panda/installer.t index f1d9423..70ac72b 100644 --- a/t/panda/installer.t +++ b/t/panda/installer.t @@ -1,12 +1,14 @@ use Test; use Panda::Installer; +use Panda::Resources; plan 4; my $srcdir = 'testmodules'; my $destdir = "{cwd}/removeme"; -my $b = Panda::Installer.new(srcdir => $srcdir, destdir => $destdir); +my $r = Panda::Resources.new(srcdir => $srcdir); +my $b = Panda::Installer.new(resources => $r, destdir => $destdir); my $p = Pies::Project.new(name => 'compiledmodule'); diff --git a/t/panda/tester.t b/t/panda/tester.t index 57fcba8..8cfb105 100644 --- a/t/panda/tester.t +++ b/t/panda/tester.t @@ -1,11 +1,13 @@ use Test; use Panda::Tester; +use Panda::Resources; plan 2; my $srcdir = 'testmodules'; -my $b = Panda::Tester.new(srcdir => $srcdir); +my $r = Panda::Resources.new(srcdir => $srcdir); +my $b = Panda::Tester.new(resources => $r); my $p = Pies::Project.new(name => 'testme1'); diff --git a/t/stubs.t b/t/stubs.t index cee9420..05f2fd8 100644 --- a/t/stubs.t +++ b/t/stubs.t @@ -20,7 +20,7 @@ my $proj = Pies::Project.new( dependencies => , ); -role DummyEco does Pies::Ecosystem { +class DummyEco does Pies::Ecosystem { has %.projects; has %.states; @@ -41,25 +41,25 @@ role DummyEco does Pies::Ecosystem { } } -role DummyFetcher does Pies::Fetcher { +class DummyFetcher does Pies::Fetcher { method fetch(Pies::Project $a) { Bool::True } } -role DummyBuilder does Pies::Builder { +class DummyBuilder does Pies::Builder { method build(Pies::Project $a) { Bool::True } } -role DummyTester does Pies::Tester { +class DummyTester does Pies::Tester { method test(Pies::Project $a) { Bool::True } } -role DummyInstaller does Pies::Installer { +class DummyInstaller does Pies::Installer { method install(Pies::Project $a) { Bool::True } @@ -70,14 +70,10 @@ $eco.add-project($proj); $eco.add-project($dep); $eco.add-project($nesteddep); -class F does DummyFetcher {}; -class B does DummyBuilder {}; -class T does DummyTester {}; -class I does DummyInstaller {}; -my $f = mocked(F); -my $b = mocked(B); -my $t = mocked(T); -my $i = mocked(I); +my $f = mocked(DummyFetcher); +my $b = mocked(DummyBuilder); +my $t = mocked(DummyTester); +my $i = mocked(DummyInstaller); my $p = Pies.new( ecosystem => $eco,