Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@ugexe
Last active October 14, 2017 00:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ugexe/10a1bf67f8849323bc855408e3577b2a to your computer and use it in GitHub Desktop.
Save ugexe/10a1bf67f8849323bc855408e3577b2a to your computer and use it in GitHub Desktop.
Perl 6 module metadata microservice that uses installed modules as the data source
#!/usr/bin/env perl6
use v6;
use Cro::HTTP::Server;
use Cro::HTTP::Router;
use Cro::HTTP::BodyParser;
# View all available distributions
# curl http://localhost:3000/installed
# View the best match from various sources for a given distribution query (name must be exact match to query name)
# curl -H "Content-Type: application/json" -X POST -d '{ "name" : "Zef" }' http://localhost:3000/resolve
# View all matching distributions from various sources (name only needs start with query name)
# See: https://github.com/rakudo/rakudo/pull/1125 for CUR interface proposal
# curl -H "Content-Type: application/json" -X POST -d '{ "name" : "Zef" }' http://localhost:3000/candidates
# curl -H "Content-Type: application/json" -X POST -d '{ "name" : "Z" }' http://localhost:3000/candidates
# curl -H "Content-Type: application/json" -X POST -d '{ "name" : "Z", "ver" : "0.1.0+" }' http://localhost:3000/candidates
sub MAIN(:$host = 'localhost', :$port = 3000) {
my $zef-meta-service = Cro::HTTP::Server.new(
host => $host,
port => $port,
body-parsers => [Cro::HTTP::BodyParser::JSON],
application => route {
# TODO: user submission via CUR interface
# get -> 'install' {
# # code to add the distribution to database/source
# }
# Get a hash where the keys are sources and values are distributions found in that source.
get -> 'installed' {
my $repo-dists :=
grep { .value.values.grep(*.so) },
map { $_ => $_.installed.grep(*.defined).map(*.meta.hash) },
grep { $_ ~~ CompUnit::Repository::Installable },
$*REPO.repo-chain;
content 'application/json', $repo-dists.hash;
}
# Get a hash where the keys are sources and values are distributions found in that source.
# The distributions will contain the single best matching candidates, e.g. what `use Foo` decides to choose from.
post -> 'resolve' {
request-body -> %spec (
:$name!,
:$auth,
:$api,
:ver(:$version),
) {
my $cur-spec = CompUnit::DependencySpecification.new(
short-name => $name,
auth-matcher => $auth // True,
api-matcher => $api // True,
version-matcher => $version // True,
);
my $repo-dists :=
grep { .value.values.grep(*.so) },
map { $_.name => $_.resolve($cur-spec).map(*.distribution.meta.hash).cache },
grep { $_ ~~ CompUnit::Repository::Installable },
$*REPO.repo-chain;
content 'application/json', $repo-dists.hash;
}
}
# Get a hash where the keys are sources and values are distributions found in that source.
# The distributions will contain all matching candidates.
post -> 'candidates' {
request-body -> %spec (
:$name!,
:$auth,
:$api,
:ver(:$version),
) {
# TODO: rakudo PR https://github.com/rakudo/rakudo/pull/1125
# replaces the following block with a single a call to CURI.candidates
my &candidates := -> $cur, $cu-spec {
my $version-matcher = ($cu-spec.version-matcher ~~ Bool)
?? $cu-spec.version-matcher
!! Version.new($cu-spec.version-matcher);
my $api-matcher = ($cu-spec.api-matcher ~~ Bool)
?? $cu-spec.api-matcher
!! Version.new($cu-spec.api-matcher);
my sub parse-value($str-or-kv) {
do given $str-or-kv {
when Str { $_ }
when Hash { $_.keys[0] }
when Pair { $_.key }
}
}
my $matching-dists := $cur.installed.grep(*.defined).grep: {
my @names = (.meta<name>, .meta<provides>.keys.Slip).unique;
my @files = (.meta<provides>.values.map(*.&parse-value).Slip, .meta<files>.hash.keys.Slip);
my &name-matcher := { (@names.Slip, @files.Slip).first(*.starts-with($^a)) }
so &name-matcher($cu-spec.short-name)
and ($_.meta<auth> // '') ~~ $cu-spec.auth-matcher
and Version.new($_.meta<ver> // 0) ~~ $version-matcher
and Version.new($_.meta<api> // 0) ~~ $api-matcher
}
$matching-dists.list;
}
my $cur-spec = CompUnit::DependencySpecification.new(
short-name => $name,
auth-matcher => $auth // True,
api-matcher => $api // True,
version-matcher => $version // True,
);
my $repo-dists :=
grep { .value.values },
map { $_.name => candidates($_, $cur-spec).map(*.meta.hash).cache },
grep { $_ ~~ CompUnit::Repository::Installable },
$*REPO.repo-chain;
content 'application/json', $repo-dists.hash;
}
}
},
) andthen *.start;
react {
whenever signal(SIGINT) {
$zef-meta-service.stop;
exit;
}
}
}
BEGIN die "Run `zef install Cro --/test` first\n" if (try require ::("Cro::HTTP::Server")) ~~ Nil;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment