Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:akselmo
obs-service-generator_pom
pom2spec
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File pom2spec of Package obs-service-generator_pom
#!/usr/bin/perl # vim: ai:ts=4:sw=4:et # # Pulls metadata from a Maven2 POM file on Maven Central # to generate a .spec file (on STDOUT) that merely warps # the .jar file(s) into noarch RPM files. # # Note that it does *NOT* create a .spec file that builds # the upstream sources, that would just be too much awesome # magic. # # Copyright 2011 Pascal Bleser <pascal.bleser@opensuse.org> # # This file is licensed under the # GNU Lesser General Public License version 2.1 or later: # http://www.gnu.org/licenses/lgpl-2.1.html # use strict; use warnings; use LWP::UserAgent; use XML::LibXML; use Cwd; use File::Basename; use Carp; # These are the very few configuration options: my $repourl = "http://repo1.maven.org/maven2"; my $include_requires_as_buildrequires = 1; my $agent = "pom2spec/1.0"; my $email = 'pascal.bleser@opensuse.org'; my $max_redirect = 2; my $timeout = 20; # in seconds # Now some helper functions to reduce verbosity: # Returns either the content of the file that is specified # as parameter or undef if the file does not exist. sub r($) { my $filename = shift; if (-e $filename) { open(my $fh, '<', $filename) or croak "failed to read existing file $filename: $!"; chomp(my $content = do { local $/; <$fh>; }); close($fh); return $content; } else { return undef; } } # "ue" = "unique element": seeks out a unique child element # under a node ($p) with a given tag name ($n) and, when # found, returns its chomped text content. # Croaks out when no matching element could be found, or when # more than one matching element could be found. sub ue($$) { my $p = shift; my $n = shift; my @results = $p->getChildrenByTagName($n); croak "invalid metadata: has more than one <${n}/> element" if scalar(@results) > 1; croak "invalid metadata: has no <${n}/> element" if scalar(@results) < 1; chomp(my $t = $results[0]->textContent); return $t; } # Same as "ue", but when no matching element is found, it returns # a fallback value ($alt) instead of croaking. sub uec($$$) { my $p = shift; my $n = shift; my $alt = shift; my @results = $p->getChildrenByTagName($n); croak "invalid metadata: has more than one <${n}/> element" if scalar(@results) > 1; return $alt if scalar(@results) < 1; chomp(my $t = $results[0]->textContent); return $t; } # Conditionally puts a match (see ue() and uec() above) into a hash. sub ueh($$$$) { my $p = shift; my $n = shift; my $h = shift; my $k = shift; my @results = $p->getChildrenByTagName($n); croak "invalid metadata: has more than one <${n}/> element" if scalar(@results) > 1; return undef if scalar(@results) < 1; chomp(my $t = $results[0]->textContent); $h->{$k} = $t if defined $t; return $t; } # Simple and naive transliteration (replaces ${...} placeholders by # their value in a hash). sub trl($$) { my $text = shift; return $text unless defined $text; my $dict = shift; while ($text =~ /^(.*?)\$\{(.+?)\}(.*)$/) { croak "unresolvable placeholder \${$2}" unless exists $dict->{$2}; $text = $1 . $dict->{$2} . $3; } return $text; } my $group; my $name; my $version; my $pgroup; my $path; { if (scalar(@ARGV) == 0 or scalar(@ARGV) == 1) { my $d = basename(cwd()); ($group, $name, $version) = $d =~ /^(.+)\.([^\.]+)(?:-(\d.?))?$/; die "when groupId and artifactId are not specified as parameters, the current directory must reflect groupId.artifactId" unless defined $group and defined $name; my $versionOverride = shift; if (defined($versionOverride)) { die "version is already specified in the name of the current working directory ($d -> $version)" if defined $version; $version = $versionOverride; } } elsif (scalar(@ARGV) == 2 or scalar(@ARGV) == 3) { $group = shift; $name = shift; $version = shift; $group =~ s/\//./g; } # $version might and may be undefined at this point ($pgroup = $group) =~ s/\./\//g; $path = $pgroup.'/'.$name; } my $ua; { $ua = LWP::UserAgent->new; $ua->agent($agent); $ua->timeout($timeout); $ua->max_redirect($max_redirect); $ua->from($email); } my $groupId; my $artifactId; my @versions; my $defaultVersion; { my $url = "${repourl}/${path}/maven-metadata.xml"; my $req = HTTP::Request->new(GET => $url); $req->content_type('text/xml'); my $res = $ua->request($req); unless ($res->is_success) { die "failed to get $url (".$res->status_line.")"; } my $parser = XML::LibXML->new; $parser->validation(0); $parser->no_network(1); $parser->load_ext_dtd(0); my $doc = $parser->parse_string($res->content); my $metadata = $doc->getDocumentElement(); $groupId = ue($metadata, 'groupId'); warn "WARNING: groupId in maven-metadata.xml file is \"$groupId\"\n" if $groupId ne $group; $artifactId = ue($metadata, 'artifactId'); $defaultVersion = uec($metadata, 'version', undef); @versions = (); foreach my $versioning ($metadata->getChildrenByTagName('versioning')) { foreach my $versions ($versioning->getChildrenByTagName('versions')) { foreach my $ve ($versions->getChildrenByTagName('version')) { chomp(my $v = $ve->textContent); push(@versions, $v); } } } if (defined $version) { die "requested version ${version} is not in metadata" unless @versions // $version; } else { die "call again and specify the exact version, one of:\n".join("\n", map { " - ".$_ } @versions)."\n"; } } $name = "${groupId}.${artifactId}-${version}"; my $out = "${name}.spec"; sub resolve($$$$); # global because we load once and cache my %ignoredeps; { if (-e "_ignoredeps") { open(my $fh, "<", "_ignoredeps") or die "failed to open _ignoredeps: $!"; while (<$fh>) { chomp; s/#.+//; next if /^$/; croak "invalid line \"$_\" in _ignoredeps" unless /^(.+?):(.+)$/; $ignoredeps{$_} = 1; } close($fh); } else { %ignoredeps = (); } } sub resolve($$$$) { my $g = shift; my $a = shift; my $v = shift; my $is_parent = shift; my $r = {}; (my $p = $g) =~ s/\./\//g; my $url = "${repourl}/${p}/${a}/${v}/${a}-${v}.pom"; my $req = HTTP::Request->new(GET => $url); $req->content_type('text/xml'); my $res = $ua->request($req); unless ($res->is_success) { croak "failed to get $url (".$res->status_line.")"; } $r->{pomurl} = $url; my $parser = XML::LibXML->new; $parser->validation(0); $parser->no_network(1); $parser->load_ext_dtd(0); my $doc = $parser->parse_string($res->content); my $project = $doc->getDocumentElement(); my $parent; { my @parentElems = $project->getChildrenByTagName('parent'); croak "invalid metadata: has more than one <parent/> element" if scalar(@parentElems) > 1; if (scalar(@parentElems) > 0) { my $parentElem = $parentElems[0]; $parent = resolve(ue($parentElem, 'groupId'), ue($parentElem, 'artifactId'), uec($parentElem, 'version', $v), 1); } else { $parent = {}; } } $r->{artifactId} = uec($project, 'artifactId', $name); { my $nameOverride = $is_parent ? undef : r("_name.override"); if (defined $nameOverride) { $r->{name} = $nameOverride; } else { $r->{name} = $r->{artifactId}; } } { my $groupIdOverride = $is_parent ? undef : r("_groupId.override"); if (defined $groupIdOverride) { $r->{groupId} = $groupIdOverride; } else { $r->{groupId} = uec($project, 'groupId', $r->{artifactId}); warn "WARNING: groupId in pom file is \"$groupId\", was expecting \"$g\": $url\n" if $r->{groupId} ne $g; } } $r->{version} = uec($project, 'version', exists $parent->{version} ? $parent->{version} : $v); $r->{packaging} = uec($project, 'packaging', 'jar'); $r->{summary} = uec($project, 'name', r('_summary')); ueh($project, 'description', $r, 'description'); ueh($project, 'url', $r, 'url'); { my $license; { my @licenses; { my @l = (); foreach my $licenses ($project->getChildrenByTagName('licenses')) { foreach my $licenseElem ($licenses->getChildrenByTagName('license')) { chomp(my $name = ue($licenseElem, 'name')); push(@l, $name); } } if (scalar(@l) > 0) { @licenses = @l; } elsif (exists $parent->{license}) { @licenses = ($parent->{license}); } else { @licenses = (); } } if (scalar(@licenses) > 1) { $license = join(", ", @licenses); } elsif (scalar(@licenses) > 0) { $license = $licenses[0]; } else { $license = undef; } } if (defined $license) { $r->{license} = $license; warn "WARNING: unnecessary (and unused) file _license\n" if -e "_license" and $is_parent; } else { if (-e "_license") { $r->{license} = ''; open(my $lf, '<', "_license") or croak "failed to open _license: $!"; while (<$lf>) { chomp; $r->{license} .= $_; } close($lf); } else { warn "WARNING: no license specified for ".join(":", map { $r->{$_} } qw(groupId artifactId version))."\n"; } } } { my @dependencies; { my $props; { $props = {}; while (my ($k, $v) = each(%{$r})) { $props->{"project.${k}"} = $v; } foreach my $properties ($project->getChildrenByTagName('properties')) { foreach my $prop (grep { $_->nodeType == XML_ELEMENT_NODE } $properties->childNodes()) { chomp(my $k = $prop->nodeName); chomp(my $v = $prop->textContent); $props->{$k} = $v; } } } if (exists $parent->{dependencies}) { @dependencies = @{$parent->{dependencies}}; } else { @dependencies = (); } foreach my $dependency ($project->getChildrenByTagName('dependencies')) { foreach my $dependency ($dependency->getChildrenByTagName('dependency')) { my $scope = uec($dependency, 'scope', 'runtime'); next if $scope ne 'runtime'; my $dg = trl(ue($dependency, 'groupId'), $props); my $da = trl(ue($dependency, 'artifactId'), $props); my $dv = trl(uec($dependency, 'version', undef), $props); if (exists $ignoredeps{"$dg:$da"}) { warn "ignoring dependency $dg:$da\n"; next; } my $d = { groupId => $dg, artifactId => $da, }; $d->{version} = $dv if defined $dv; push(@dependencies, $d); } } } $r->{dependencies} = \@dependencies; } { my $sources_url = "${repourl}/${p}/${a}/${v}/${a}-${v}-sources.jar"; my $head = HTTP::Request->new(HEAD => $sources_url); $head->content_type('application/java-archive'); my $res = $ua->request($head); $r->{sources} = $sources_url if $res->is_success and $res->code == 200; } if (0) { # not sufficiently implemented, would actually need to explode the javadoc jar # and strip off the package directory from it to properly install it # under %{_javadocdir} in the spec file my $javadoc_url = "${repourl}/${p}/${a}/${v}${a}-${v}-javadoc.jar"; my $head = HTTP::Request->new(HEAD => $javadoc_url); $head->content_type('application/java-archive'); my $res = $ua->request($head); $r->{javadoc} = $javadoc_url if $res->is_success; } return $r; } my %x = %{resolve($groupId, $artifactId, $version, 0)}; { my $tty; { open($tty, '>>', '/dev/tty') or $tty = undef; } if (defined $tty) { say $tty "name: $x{name}"; say $tty "groupId: $x{groupId}"; say $tty "artifactId: $x{artifactId}"; say $tty "version: $x{version}"; say $tty "license: $x{license}" if exists $x{license}; say $tty "packaging: $x{packaging}"; say $tty "summary: $x{summary}" if exists $x{summary}; say $tty "url: $x{url}" if exists $x{url}; say $tty "description: $x{description}" if exists $x{description}; if (scalar(@{$x{dependencies}}) > 0) { say $tty "dependencies:"; foreach my $d (@{$x{dependencies}}) { say $tty " $d->{groupId}:$d->{artifactId}" . (exists $d->{version} ? ":".$d->{version} : ""); } } } } (my $uversion = $x{version}) =~ s/\./_/g; my $summary = exists $x{summary} ? $x{summary} : $x{groupId}; my $description = exists $x{description} ? $x{description} : $summary; open(my $outfd, '>', $out) or die "failed to create $out: $!"; my $oldselectfd = select $outfd; print<<EOF; # vim: set sw=4 ts=4 et: # POM: $x{pomurl} # groupId: $x{groupId} # artifactId: $x{artifactId} Name: ${name} %define uname %{name}-${uversion} Version: $x{version} Release: 0 Summary: ${summary} Source0: ${repourl}/${path}/${version}/$x{artifactId}-$x{version}.jar EOF if (exists $x{sources}) { print<<EOF; Source1: $x{sources} EOF } if (exists $x{url}) { print<<EOF; URL: $x{url} EOF } print<<EOF; Group: Development/Libraries/Java EOF if (exists $x{license}) { print<<EOF; License: $x{license} EOF } print<<EOF; BuildRoot: %{_tmppath}/build-%{name}-%{version} BuildArch: noarch Requires: %{uname} = %{version} EOF if ($include_requires_as_buildrequires) { foreach my $d (@{$x{dependencies}}) { my $version_text = exists $d->{version} ? " = ".$d->{version} : ""; print<<EOF; BuildRequires: java($d->{groupId}:$d->{artifactId})${version_text} EOF } } print<<EOF; %description ${description} %package -n %{uname} Summary: ${summary} Group: Development/Libraries/Java Provides: java($x{groupId}:$x{artifactId}) = $x{version} EOF foreach my $d (@{$x{dependencies}}) { my $version_text = exists $d->{version} ? " = ".$d->{version} : ""; print<<EOF; Requires: java($d->{groupId}:$d->{artifactId})${version_text} EOF } print<<EOF; %description -n %{uname} ${description} EOF if (exists $x{sources}) { print<<EOF; %package -n %{name}-sources Summary: Sources for %{name} Group: Development/Libraries/Java Requires: %{uname}-sources = %{version} %description -n %{name}-sources This package contains the source bundle for %{name}. %package -n %{uname}-sources Summary: Sources for %{uname} Group: Development/Libraries/Java Requires: %{uname} = %{version} %description -n %{uname}-sources This package contains the source bundle for %{uname}. EOF } print<<EOF; %prep %setup -q -T -c "%{name}-%{version}" %build %install %__install -D -m0644 "%{SOURCE0}" "%{buildroot}%{_javadir}/%{name}-%{version}.jar" %__ln_s "%{name}-%{version}.jar" "%{buildroot}%{_javadir}/%{name}.jar" cat<<EOCP > "%{buildroot}%{_javadir}/%{name}-%{version}.classpath" EOF print join(":", map { "%{_javadir}/$_->{artifactId}".(exists $_->{version} ? "-$_->{version}" : "").".jar" } @{$x{dependencies}}), "\n"; print<<EOF; EOCP %__ln_s "%{name}-%{version}.classpath" "%{buildroot}%{_javadir}/%{name}.classpath" EOF if (exists $x{sources}) { print<<EOF; %__install -m0644 "%{SOURCE1}" "%{buildroot}%{_javadir}/%{name}-%{version}-sources.jar" %__ln_s "%{name}-%{version}-sources.jar" "%{buildroot}%{_javadir}/%{name}-sources.jar" EOF } print<<EOF; %clean %{?buildroot:%__rm -rf "%{buildroot}"} %files %defattr(-,root,root) %{_javadir}/%{name}.jar %{_javadir}/%{name}.classpath %files -n %{uname} %defattr(-,root,root) %{_javadir}/%{name}-%{version}.jar %{_javadir}/%{name}-%{version}.classpath EOF if (exists $x{sources}) { print<<EOF; %files -n %{name}-sources %defattr(-,root,root) %{_javadir}/%{name}-sources.jar %files -n %{uname}-sources %defattr(-,root,root) %{_javadir}/%{name}-%{version}-sources.jar EOF } print<<EOF; EOF select $oldselectfd;
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor