Import portgen.

OK many
This commit is contained in:
tsg 2016-01-18 18:08:19 +00:00
parent e2fa1576ef
commit affd2dee1b
7 changed files with 1250 additions and 0 deletions

View File

@ -0,0 +1,120 @@
# $OpenBSD: Dependency.pm,v 1.1.1.1 2016/01/18 18:08:19 tsg Exp $
#
# Copyright (c) 2015 Giannis Tsaraias <tsg@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package OpenBSD::PortGen::Dependency;
use 5.012;
use warnings;
sub new
{
my $class = shift;
my $self = bless {}, $class;
return $self;
}
sub add_build
{
my $self = shift;
$self->_add_dep( 'build', @_ );
}
sub add_run
{
my $self = shift;
$self->_add_dep( 'run', @_ );
}
sub add_test
{
my $self = shift;
$self->_add_dep( 'test', @_ );
}
sub _add_dep
{
my ( $self, $type, $port, $reqs ) = @_;
# '>=0' is redundant, remove it
if ( defined $reqs and $reqs eq '>=0' ) {
$reqs = '';
}
$self->{deps}{$type}{$port} = $reqs;
}
# from perlfaq4
sub _arr_equal
{
my ( $self, $fst, $snd ) = @_;
no warnings;
return 0 unless @$fst and @$snd;
return 0 unless @$fst == @$snd;
for ( my $i = 0 ; $i < @$fst ; $i++ ) {
return 0 if $fst->[$i] ne $snd->[$i];
}
return 1;
}
sub format
{
my $self = shift;
my %fmt;
return unless $self->{deps};
for my $type (qw/ build run test/) {
# might not have dependencies of this type
next unless exists $self->{deps}{$type};
my @deps;
while ( my ( $name, $ver_reqs ) =
each %{ $self->{deps}{$type} } )
{
push @deps, $ver_reqs ? $name . $ver_reqs : $name;
}
@{ $fmt{$type} } = sort @deps;
}
my ( $build_ref, $run_ref, $test_ref ) =
( \@{ $fmt{'build'} }, \@{ $fmt{'run'} }, \@{ $fmt{'test'} } );
if ( $self->_arr_equal( $build_ref, $run_ref ) ) {
@{ $fmt{'run'} } = '${BUILD_DEPENDS}';
}
if ( $self->_arr_equal( $test_ref, $build_ref ) ) {
@{ $fmt{'test'} } = '${BUILD_DEPENDS}';
} elsif ( $self->_arr_equal( $test_ref, $run_ref ) ) {
@{ $fmt{'test'} } = '${RUN_DEPENDS}';
}
for my $type ( keys %fmt ) {
$fmt{$type} = ( join " \\\n\t\t\t", @{ $fmt{$type} } ) || undef;
}
return \%fmt;
}
1;

View File

@ -0,0 +1,83 @@
# $OpenBSD: License.pm,v 1.1.1.1 2016/01/18 18:08:19 tsg Exp $
#
# Copyright (c) 2015 Giannis Tsaraias <tsg@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package OpenBSD::PortGen::License;
use 5.012;
use warnings;
use parent qw( Exporter );
our @EXPORT_OK = qw(
is_good
pretty_license
);
# Add licenses not recognized here.
# Lowercase of what API returns as the key
# and printable string as the value.
my %good_licenses = (
agpl_3 => 'AGPL 3',
apache_1_1 => 'Apache 1.1',
apache_2_0 => 'Apache 2.0',
artistic_1 => 'Artistic 1.0',
artistic_2 => 'Artistic 2.0',
bsd => 'BSD',
freebsd => 'FreeBSD',
gpl_2 => 'GPLv2',
gpl_2_0 => 'GPLv2',
gpl_3 => 'GPLv3',
lgpl => 'LGPL',
lgpl_2_1 => 'LGPL v2.1',
'lgpl_2_1+' => 'LGPL v2.1',
mit => 'MIT',
perl_5 => 'Perl',
ruby => 'Ruby',
qpl_1_0 => 'QPLv1',
zlib => 'zlib',
);
sub is_good
{
my $license = shift;
return unless $license;
return defined $good_licenses{ _munge($license) };
}
sub pretty_license
{
my $raw = shift;
return "license field not set, consider bugging module's author"
if !$raw or $raw eq 'UNKNOWN';
return $good_licenses{ _munge($raw) } || "unknown license -> '$raw'";
}
sub _munge
{
my $license = shift;
$license = lc $license;
$license =~ s/[,-\.\s]/_/g;
$license =~ s/_license//;
$license =~ s/_version//;
$license =~ s/_{2,}/_/g;
return $license;
}
1;

View File

@ -0,0 +1,415 @@
# $OpenBSD: Port.pm,v 1.1.1.1 2016/01/18 18:08:19 tsg Exp $
#
# Copyright (c) 2015 Giannis Tsaraias <tsg@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package OpenBSD::PortGen::Port;
use 5.012;
use warnings;
use Cwd;
use File::Path qw( make_path );
use JSON::PP;
use Text::Wrap;
use OpenBSD::PortGen::License qw( is_good pretty_license );
use OpenBSD::PortGen::Utils qw( add_to_new_ports base_dir fetch ports_dir );
sub new
{
my ( $class, %args ) = @_;
my $self = bless {%args}, $class;
return $self;
}
sub get
{
return fetch( shift->base_url() . shift );
}
sub get_json
{
return decode_json( shift->get(shift) );
}
sub get_json_file
{
my ( $self, $file ) = @_;
open my $h, '<', $file or die $!;
my $data = do { local $/ = undef; <$h> };
return decode_json $data;
}
sub set_descr
{
my ( $self, $text ) = @_;
$self->{descr} = $self->_format_descr($text);
}
sub write_descr
{
my $self = shift;
my $text = $self->{descr};
if ( not -d 'pkg' ) {
mkdir 'pkg' or die $!;
}
open my $descr, '>', 'pkg/DESCR'
or die $!;
say $descr $text;
}
sub _format_descr
{
my ( $self, $text ) = @_;
return 'No description available for this module.'
if not $text or $text =~ /^\s*$/;
$text =~ s/^ *//mg;
$text =~ s/^\s*|\s*$//g;
my $lines = split /\n/, $text;
if ( $lines > 5 ) {
my @paragraphs = split /\n\n/, $text;
$text = $paragraphs[0];
}
local $Text::Wrap::columns = 80;
return Text::Wrap::wrap( '', '', $text );
}
sub set_comment
{
my ( $self, $comment ) = @_;
unless ($comment) {
$self->{COMMENT} = 'no comment available';
return;
}
$comment =~ s/\n/ /g;
$self->{full_comment} = $comment if length $comment > 60;
$self->{COMMENT} = $self->_format_comment($comment);
}
sub set_distname
{
my ( $self, $distname ) = @_;
my $prefix = $self->ecosystem_prefix();
# use foo-bar instead of foo-foo-bar as PKGNAME
if ( $distname =~ /^$prefix/ ) {
$self->{PKGNAME} = ( $distname =~ s/^$prefix//r );
$self->{DISTNAME} = $prefix . '${PKGNAME}';
} else {
$self->{DISTNAME} = $distname;
}
}
sub set_license
{
my ( $self, $license ) = @_;
if ( is_good($license) ) {
$self->{PERMIT_PACKAGE_CDROM} = 'Yes';
} else {
$self->{PERMIT_PACKAGE_CDROM} = 'unknown license';
$self->{PERMIT_PACKAGE_FTP} = 'unknown license';
$self->{PERMIT_DISTFILES_FTP} = 'unknown license';
}
$self->{license} = pretty_license($license);
}
sub set_modules
{
my ( $self, $modules ) = @_;
$self->{MODULES} = $modules;
}
sub set_categories
{
my ( $self, $categories ) = @_;
$self->{CATEGORIES} = $categories;
}
sub set_build_deps
{
my ( $self, $build_deps ) = @_;
# Makefile.template is missing a tab for BUILD_DEPENDS
# and we want the port to be pretty, so add one
$self->{BUILD_DEPENDS} = "\t" . $build_deps if $build_deps;
}
sub set_run_deps
{
my ( $self, $run_deps ) = @_;
$self->{RUN_DEPENDS} = $run_deps;
}
sub set_test_deps
{
my ( $self, $test_deps ) = @_;
$self->{TEST_DEPENDS} = $test_deps;
}
sub set_other
{
my ( $self, $var, $value ) = @_;
$self->{$var} = $value;
}
sub get_other
{
my ( $self, $var ) = @_;
return $self->{$var};
}
sub write_makefile
{
my $self = shift;
open my $tmpl, '<',
ports_dir() . '/infrastructure/templates/Makefile.template'
or die $!;
open my $mk, '>', 'Makefile' or die $!;
my $output = '# $OpenBSD: Port.pm,v 1.1.1.1 2016/01/18 18:08:19 tsg Exp $' . "\n";
my %vars_found;
# such a mess, should fix
while ( defined( my $line = <$tmpl> ) ) {
my ( $value, $other_stuff );
# copy MAINTAINER line as is
if ( $line =~ /^MAINTAINER/ ) {
$output .= $line and next;
}
if ( $line =~ /(^#?([A-Z_]+)\s+\??=\s+)/ ) {
next unless defined $self->{$2};
$vars_found{$2} = 1;
( $value, $other_stuff ) = ( $self->{$2}, $1 );
$other_stuff =~ s/^#//;
$other_stuff =~ s/(\?\?\?|$)/$value\n/;
if ( $other_stuff =~ /^PERMIT_PACKAGE_CDROM/ ) {
$output .= "# $self->{license}\n";
} elsif ( $other_stuff =~ /_DEPENDS/ ) {
$other_stuff = "\n" . $other_stuff;
} elsif ( $other_stuff =~ /^COMMENT/ ) {
$output .= "# original: $self->{full_comment}\n"
if $self->{full_comment};
}
$output .= $other_stuff;
}
$output .= $line if $line =~ /^\s+$/;
}
# also write variables not found in the template
my @unwritten_vars;
for my $var ( keys %{$self} ) {
next unless $self->{$var};
next unless $var eq uc $var;
push @unwritten_vars, $var unless $vars_found{$var};
}
# the ordering should be consistent between runs
@unwritten_vars = sort @unwritten_vars;
for my $var (@unwritten_vars) {
# temp fix, should make saner
my $tabs = length $var > 11 ? "\t" : "\t\t";
$output .= "\n$var =$tabs$self->{$var}\n";
}
$output .= "\n.include <bsd.port.mk>\n";
$output =~ s/\n{2,}/\n\n/g;
print $mk $output;
}
sub _format_comment
{
my ( $self, $text ) = @_;
return unless $text;
$text =~ s/^(a|an) //i;
$text =~ s/\n/ /g;
$text =~ s/\.$//;
$text =~ s/\s+$//;
# Max comment length is 60. Try to cut it, but print full
# version in Makefile for the porter to edit as needed.
$text =~ s/ \S+$// while length $text > 60;
return $text;
}
sub _make
{
my $self = shift;
system( 'make', @_ );
return $? >> 8;
}
sub make_clean
{
my $self = shift;
return $self->_make('clean');
}
sub make_fetch
{
my $self = shift;
return $self->_make('fetch-all');
}
sub make_makesum
{
shift->_make('makesum');
}
sub make_checksum
{
shift->_make('checksum');
}
sub make_extract
{
shift->_make('extract');
}
sub make_configure
{
shift->_make('configure');
}
sub make_fake
{
shift->_make('fake');
}
sub make_plist
{
shift->_make('plist');
}
sub make_show
{
my ( $self, $var ) = @_;
chomp( my $output = qx{ make show=$var } );
return $output;
}
sub make_portdir
{
my ( $self, $name ) = @_;
my $portdir = base_dir() . "/$name";
make_path($portdir) unless -e $portdir;
return $portdir;
}
sub make_port
{
my ( $self, $di, $vi ) = @_;
my $old_cwd = getcwd();
my $portname = $self->name_new_port($di);
my $portdir = $self->make_portdir($portname);
chdir $portdir or die "couldn't chdir to $portdir: $!";
$self->fill_in_makefile( $di, $vi );
$self->write_makefile();
$self->make_fetch();
$self->make_makesum();
$self->make_checksum();
$self->make_extract();
my $wrksrc = $self->make_show('WRKSRC');
# children can override this to set any variables
# that require extracted distfiles
$self->postextract( $di, $wrksrc );
$self->set_other( 'CONFIGURE_STYLE',
$self->get_config_style( $di, $wrksrc ) );
$self->write_makefile();
$self->make_configure();
my $deps = $self->get_deps( $di, $wrksrc );
$self->set_build_deps( $deps->{build} );
$self->set_run_deps( $deps->{run} );
$self->set_test_deps( $deps->{test} );
$self->write_makefile();
# sometimes a make_fake() is not enough, need to run it more than
# once to figure out which CONFIGURE_STYLE actually works
$self->try_building();
$self->make_plist();
$self->write_descr();
chdir $old_cwd or die "couldn't chdir to $old_cwd: $!";
return add_to_new_ports($portdir);
}
sub port
{
my ( $self, $module ) = @_;
my $di = eval { $self->get_dist_info($module) };
unless ($di) {
warn "couldn't find dist for $module";
return;
}
my $vi = eval { $self->get_ver_info($module) };
unless ($vi) {
warn "couldn't get version info for $module";
return;
}
return $self->make_port( $di, $vi );
}
1;

View File

@ -0,0 +1,271 @@
# $OpenBSD: CPAN.pm,v 1.1.1.1 2016/01/18 18:08:20 tsg Exp $
#
# Copyright (c) 2015 Giannis Tsaraias <tsg@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package OpenBSD::PortGen::Port::CPAN;
use 5.012;
use warnings;
use parent 'OpenBSD::PortGen::Port';
use File::Find qw( find );
use OpenBSD::PortGen::Dependency;
use OpenBSD::PortGen::Utils qw( fetch module_in_ports );
sub ecosystem_prefix
{
my $self = shift;
return 'p5-';
}
sub base_url
{
my $self = shift;
return 'https://api.metacpan.org/v0/';
}
sub get_dist_info
{
my ( $self, $module ) = @_;
my $dist = $self->get_dist_for_module($module);
return $self->get_json("release/$dist");
}
sub get_ver_info
{
return 1;
}
sub get_dist_for_module
{
my ( $self, $module ) = @_;
return $self->get_json("module/$module?fields=distribution")
->{distribution};
}
sub name_new_port
{
my ( $self, $di ) = @_;
my $name = ref $di ? $di->{metadata}->{name} : $di;
$name = "p5-$name";
$name =~ s/::/-/g;
return "cpan/$name";
}
sub needs_author
{
my ( $self, $di ) = @_;
my $mirror = 'http://www.cpan.org';
# one module used 'src/foo.tar.gz', we only need foo.tar.gz
my ($file) = $di->{archive} =~ /([^\/]+)$/;
$file = "$1/$file" if $file =~ /^(\w+)-/;
return !fetch("$mirror/modules/by-module/$file");
}
sub get_config_style
{
my ( $self, $di, $wrksrc ) = @_;
if ( $di->{metadata}->{generated_by} =~ /Module::Install/
|| -e "$wrksrc/inc/Module/Install.pm" )
{
return 'modinst';
}
for my $dep ( @{ $di->{dependency} } ) {
if ( $dep->{module} eq 'Module::Build' )
{
return 'modbuild';
}
}
return;
}
sub get_deps
{
my ( $self, $di, $wrksrc ) = @_;
my $deps = OpenBSD::PortGen::Dependency->new();
if ( -e "$wrksrc/MYMETA.json" ) {
my $meta = $self->get_json_file("$wrksrc/MYMETA.json");
$di = $meta if defined $meta;
} else {
$di = $di->{metadata};
}
for my $phase (qw/ build runtime configure test /) {
next unless $di->{prereqs}{$phase};
for my $relation (qw/ requires recommends /) {
next if $relation eq 'recommends' and $phase ne 'test';
while ( my ( $module, $req ) =
each %{ $di->{prereqs}{$phase}{$relation} } )
{
next if $self->is_in_base($module);
my $dist = $self->get_dist_for_module($module);
my $port = module_in_ports( $dist, 'p5-' )
|| $self->name_new_port($dist);
$req =~ s/^v//;
$req =~ s/0+$/0/;
if ( $phase eq 'configure'
|| $phase eq 'build' )
{
$deps->add_build( $port, ">=$req" );
} elsif ( $phase eq 'runtime' ) {
$deps->add_run( $port, ">=$req" );
} elsif ( $phase eq 'test' ) {
$deps->add_test( $port, ">=$req" );
}
# don't have it in tree, port it
if ( $port =~ m{^cpan/} ) {
my $o =
OpenBSD::PortGen::Port::CPAN->new();
$o->port($module);
}
}
}
}
return $deps->format();
}
sub read_descr
{
my ( $self, $path ) = @_;
open my $readme, '<', "$path/README" or return;
my $descr = do { local $/ = undef; <$readme> };
if ( $descr =~ /^DESCRIPTION\n(.+?)^[A-Z]+/ms ) {
return $1 unless $1 =~ /^\s+$/;
}
if ( $descr =~ /^SYNOPSIS\n(.+?)^[A-Z]+/ms ) {
return $1 unless $1 =~ /^\s+$/;
}
return;
}
sub fill_in_makefile
{
my ( $self, $di, $vi ) = @_;
$self->set_comment( $di->{abstract} );
$self->set_distname( $di->{name} );
$self->set_license(
$di->{metadata}->{license}[0] eq 'unknown'
? ''
: $di->{metadata}->{license}[0]
);
$self->set_modules('cpan');
$self->set_categories('cpan');
$self->set_other( 'CPAN_AUTHOR', $di->{author} )
if $self->needs_author($di);
my ($sufx) = $di->{archive} =~ /(\.[\.A-Za-z]+)$/;
if ( defined $sufx and $sufx ne '.tar.gz' ) {
$self->set_other( 'EXTRACT_SUFX', $sufx );
}
}
sub postextract
{
my ( $self, $di, $wrksrc ) = @_;
$self->set_descr( $self->read_descr($wrksrc) || $di->{abstract} );
$self->_find_hidden_test_deps($wrksrc);
}
sub try_building
{
my $self = shift;
if ( $self->make_fake() and $self->get_other('CONFIGURE_STYLE') ) {
warn
"* * * Warning: failed to build with CONFIGURE_STYLE, trying without * * *";
$self->set_other( 'CONFIGURE_STYLE', undef );
$self->write_makefile();
$self->make_clean();
!$self->make_fake() or die 'cannot build port';
}
}
sub is_in_base
{
my ( $self, $module ) = @_;
return 1 if $module eq 'perl';
$module .= '.pm';
$module =~ s{::}{/}g;
for (@INC) {
next unless m{/usr/libdata/};
return 1 if -e "$_/$module";
}
return;
}
# Some testfiles skip tests because the required modules are not
# available. Those modules are not always listed as dependencies, so
# manually check if there are testfiles skipping tests and warn the
# porter about them.
sub _find_hidden_test_deps
{
my ( $self, $path ) = @_;
return unless -d "$path/t";
find( sub { $self->_test_skips($File::Find::name) }, "$path/t" );
}
sub _test_skips
{
my ( $self, $file ) = @_;
# not a testfile
return unless $file =~ /\.t$/;
open my $fh, '<', $file or die $!;
while (<$fh>) {
if (/plan skip_all/) {
warn "Possible hidden test dependency in: $file\n";
return;
}
}
}
1;

View File

@ -0,0 +1,103 @@
# $OpenBSD: PyPI.pm,v 1.1.1.1 2016/01/18 18:08:20 tsg Exp $
#
# Copyright (c) 2015 Giannis Tsaraias <tsg@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package OpenBSD::PortGen::Port::PyPI;
use 5.012;
use warnings;
use parent 'OpenBSD::PortGen::Port';
use OpenBSD::PortGen::Dependency;
sub ecosystem_prefix
{
my $self = shift;
return 'py-';
}
sub base_url
{
my $self = shift;
return 'https://pypi.python.org/pypi/';
}
sub get_dist_info
{
my ( $self, $module ) = @_;
return $self->get_json( $module . '/json' );
}
sub get_ver_info
{
return 1;
}
sub name_new_port
{
my ( $self, $di ) = @_;
my $name = $di->{info}{name};
$name = "py-$name" unless $name =~ /^py-/;
return "pypi/$name";
}
sub fill_in_makefile
{
my ( $self, $di, $vi ) = @_;
$self->set_other( 'MODPY_PI', 'Yes' );
$self->set_other( 'MODPY_SETUPTOOLS', 'Yes' );
$self->set_comment( $di->{info}{summary} );
$self->set_other( 'MODPY_EGG_VERSION', $di->{info}{version} );
$self->set_distname( "$di->{info}{name}" . '-${MODPY_EGG_VERSION}' );
$self->set_other( 'PKGNAME', 'py-${DISTNAME}' );
$self->set_modules('lang/python');
$self->set_categories('pypi');
$self->set_other( 'HOMEPAGE', $di->{info}{home_page} );
$self->set_license( $di->{info}{license} );
$self->set_descr( $di->{info}{summary} );
for ( @{ $di->{info}{classifiers} } ) {
if (/^Programming Language :: Python :: 3/) {
$self->set_other( 'FLAVORS', 'python3' );
$self->set_other( 'FLAVOR', '' );
last;
}
}
}
sub try_building
{
my $self = shift;
$self->make_fake();
}
sub postextract
{
}
sub get_deps
{
}
sub get_config_style
{
}
1;

View File

@ -0,0 +1,146 @@
# $OpenBSD: Ruby.pm,v 1.1.1.1 2016/01/18 18:08:20 tsg Exp $
#
# Copyright (c) 2015 Giannis Tsaraias <tsg@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package OpenBSD::PortGen::Port::Ruby;
use 5.012;
use warnings;
use parent 'OpenBSD::PortGen::Port';
use OpenBSD::PortGen::Dependency;
use OpenBSD::PortGen::Utils qw( module_in_ports );
sub ecosystem_prefix
{
my $self = shift;
return 'ruby-';
}
sub postextract
{
}
sub base_url
{
my $self = shift;
return 'https://rubygems.org/api/v1/';
}
sub get_dist_info
{
my ( $self, $module ) = @_;
return $self->get_json("gems/$module.json");
}
sub get_ver_info
{
my ( $self, $module ) = @_;
return @{ $self->get_json("versions/$module.json") }[0];
}
sub name_new_port
{
my ( $self, $di ) = @_;
my $name = ref $di ? $di->{name} : $di;
$name = "ruby-$name" unless $name =~ /^ruby-/;
return "ruby/$name";
}
sub fill_in_makefile
{
my ( $self, $di, $vi ) = @_;
$self->set_comment( $vi->{summary} );
$self->set_distname("$di->{name}-$di->{version}");
$self->set_modules('lang/ruby');
$self->set_categories('ruby');
$self->set_other( 'HOMEPAGE', $di->{homepage_uri} );
$self->set_license( @{ $vi->{licenses} }[0] );
$self->set_other( 'CONFIGURE_STYLE', "ruby gem" );
$self->set_descr( $di->{info} || $vi->{summary} );
}
sub try_building
{
my $self = shift;
$self->make_fake();
}
sub get_deps
{
my ( $self, $di ) = @_;
my $deps = OpenBSD::PortGen::Dependency->new();
return unless $di->{dependencies};
for my $dep ( @{ $di->{dependencies}->{runtime} } ) {
my ( $name, $req ) = ( $dep->{name}, $dep->{requirements} );
next if $self->is_standard_module($name);
my $port = module_in_ports( $name, 'ruby-' )
|| $self->name_new_port($name);
$req =~ s/ //g;
# support pessimistic version requirement:
# turn ~> 3.0.3 into >=3.0.3,<3.1.0
# and ~> 1.1 into >=1.1,<2.0
if ( $req =~ /~>([\d\.]+)/ ) {
my $ver = $1;
$req =~ s/~>/>=/;
$ver =~ s/(\d)\.\d$/($1+1).".0"/e;
$req .= ",<$ver";
}
$deps->add_run( $port . ',${MODRUBY_FLAVOR}', $req );
# gems only understand runtime and development deps
$deps->add_build('${RUN_DEPENDS}');
# don't have this one, port it
if ( $port =~ m{^ruby/} ) {
my $o = OpenBSD::PortGen::Port::Ruby->new();
$o->port($name);
}
}
return $deps->format();
}
sub is_standard_module
{
my ( $self, $module, $ruby_ver ) = @_;
$ruby_ver //= '2.2';
return -e "/usr/local/lib/ruby/$ruby_ver/$module.rb";
}
sub get_config_style
{
my ( $self, $di, $wrksrc ) = @_;
if ( -d "$wrksrc/ext" ) {
return "ruby gem ext";
}
return "ruby gem";
}
1;

View File

@ -0,0 +1,112 @@
# $OpenBSD: Utils.pm,v 1.1.1.1 2016/01/18 18:08:19 tsg Exp $
#
# Copyright (c) 2015 Giannis Tsaraias <tsg@openbsd.org>
#
# Permission to use, copy, modify, and distribute this software for any
# purpose with or without fee is hereby granted, provided that the above
# copyright notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package OpenBSD::PortGen::Utils;
use 5.012;
use warnings;
use DBI;
use parent qw( Exporter );
our @EXPORT_OK = qw(
add_to_new_ports
base_dir
fetch
module_in_ports
ports_dir
);
sub _fetch_cmd { qw( ftp -V -o- ) }
sub fetch
{
my $url = shift;
for ( 0 .. 1 ) {
open my $fh, '-|', _fetch_cmd(), $url or die $!;
my $content = do { local $/ = undef; <$fh> };
return $content if $content;
sleep 2 * $_;
}
}
sub ports_dir { $ENV{PORTSDIR} || '/usr/ports' }
sub base_dir { ports_dir() . '/mystuff' }
sub module_in_ports
{
my ( $module, $prefix ) = @_;
return unless $module and $prefix;
my $dbpath = '/usr/local/share';
my $dbfile;
if ( -e "$dbpath/sqlports-compact" ) {
$dbfile = 'sqlports-compact';
} elsif ( -e "$dbpath/sqlports" ) {
$dbfile = 'sqlports';
} else {
die "install databases/sqlports-compact or databases/sqlports";
}
my $dbh = DBI->connect( "dbi:SQLite:dbname=$dbpath/$dbfile", "", "" )
or die "failed to connect to database: $DBI::errstr";
my $stmt;
$stmt =
$dbfile =~ /compact/
? "SELECT FULLPKGPATH FROM Paths WHERE ID IN ( SELECT FULLPKGPATH FROM Ports WHERE DISTNAME LIKE '$module%' )"
: "SELECT FULLPKGPATH FROM Ports WHERE DISTNAME LIKE '$module%'";
my $pr = $dbh->prepare($stmt);
$pr->execute();
my @results;
while ( my @pkgpaths = $pr->fetchrow_array ) {
push @results, $pkgpaths[0];
}
$dbh->disconnect();
# don't need flavors, should find a cleaner way to do this
s/,\w+$// for @results;
# just returning the shortest one that's a module of the same ecosystem
# this should be improved
@results = sort { length $a <=> length $b } @results;
# this works well enough in practice, but can't rely on it
# see devel/perltidy
for (@results) {
return $_ if /\/$prefix/;
}
return;
}
# i know, i know...
sub add_to_new_ports
{
state @new_ports;
push @new_ports, shift;
return @new_ports;
}
1;