[gradle] Add gradle-local subpackage

Mikolaj Izdebski mizdebsk at fedoraproject.org
Tue Nov 18 20:13:40 UTC 2014


commit 16ee7bb26dc776dd473612363a4dcc2c3ec92639
Author: Mikolaj Izdebski <mizdebsk at redhat.com>
Date:   Thu Nov 13 14:23:00 2014 +0100

    Add gradle-local subpackage

 GradleResolver.java |  374 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gradle.spec         |   34 +++++-
 2 files changed, 407 insertions(+), 1 deletions(-)
---
diff --git a/GradleResolver.java b/GradleResolver.java
new file mode 100644
index 0000000..0b6e00b
--- /dev/null
+++ b/GradleResolver.java
@@ -0,0 +1,374 @@
+/*-
+ * Copyright (c) 2014 Red Hat, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.fedoraproject.xmvn.connector.gradle;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.fedoraproject.xmvn.artifact.Artifact;
+import org.fedoraproject.xmvn.artifact.DefaultArtifact;
+import org.fedoraproject.xmvn.locator.IsolatedXMvnServiceLocator;
+import org.fedoraproject.xmvn.locator.XMvnHomeClassLoader;
+import org.fedoraproject.xmvn.resolver.ResolutionRequest;
+import org.fedoraproject.xmvn.resolver.ResolutionResult;
+import org.fedoraproject.xmvn.resolver.Resolver;
+import org.gradle.api.artifacts.ModuleVersionIdentifier;
+import org.gradle.api.artifacts.component.ModuleComponentIdentifier;
+import org.gradle.api.artifacts.repositories.ArtifactRepository;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ConfiguredModuleComponentRepository;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.ModuleComponentRepositoryAccess;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.DescriptorParseContext;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.GradlePomModuleDescriptorParser;
+import org.gradle.api.internal.artifacts.ivyservice.ivyresolve.parser.MetaDataParser;
+import org.gradle.api.internal.artifacts.repositories.ResolutionAwareRepository;
+import org.gradle.api.internal.component.ArtifactType;
+import org.gradle.internal.component.external.model.DefaultMavenModuleResolveMetaData;
+import org.gradle.internal.component.external.model.DefaultModuleComponentArtifactMetaData;
+import org.gradle.internal.component.external.model.ModuleComponentResolveMetaData;
+import org.gradle.internal.component.external.model.MutableModuleComponentResolveMetaData;
+import org.gradle.internal.component.model.ComponentArtifactMetaData;
+import org.gradle.internal.component.model.ComponentResolveMetaData;
+import org.gradle.internal.component.model.ComponentUsage;
+import org.gradle.internal.component.model.DefaultIvyArtifactName;
+import org.gradle.internal.component.model.DependencyMetaData;
+import org.gradle.internal.component.model.IvyArtifactName;
+import org.gradle.internal.component.model.ModuleSource;
+import org.gradle.internal.resolve.ArtifactResolveException;
+import org.gradle.internal.resolve.ModuleVersionResolveException;
+import org.gradle.internal.resolve.result.BuildableArtifactResolveResult;
+import org.gradle.internal.resolve.result.BuildableArtifactSetResolveResult;
+import org.gradle.internal.resolve.result.BuildableModuleComponentMetaDataResolveResult;
+import org.gradle.internal.resolve.result.BuildableModuleComponentVersionSelectionResolveResult;
+import org.gradle.internal.resource.DefaultLocallyAvailableExternalResource;
+import org.gradle.internal.resource.LocallyAvailableExternalResource;
+import org.gradle.internal.resource.local.DefaultLocallyAvailableResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+/**
+ * @author Mikolaj Izdebski
+ */
+public class GradleResolver
+    implements ArtifactRepository, ResolutionAwareRepository, ConfiguredModuleComponentRepository,
+    ModuleComponentRepositoryAccess, DescriptorParseContext
+{
+    private final Logger logger = LoggerFactory.getLogger( GradleResolver.class );
+
+    static class LazyLocatorProvider
+    {
+        static final IsolatedXMvnServiceLocator locator;
+
+        static
+        {
+            XMvnHomeClassLoader realm = new XMvnHomeClassLoader( LazyLocatorProvider.class.getClassLoader() );
+            realm.importAllPackages( "org.slf4j" );
+            realm.importAllPackages( "org.gradle.api.logging" );
+            locator = new IsolatedXMvnServiceLocator( realm );
+        }
+    }
+
+    static class LazyResolverProvider
+    {
+        static final Resolver resolver = LazyLocatorProvider.locator.getService( Resolver.class );
+    }
+
+    private Path resolve( Artifact artifact )
+    {
+        logger.debug( "Trying to resolve artifact {}", artifact );
+        ResolutionRequest request = new ResolutionRequest( artifact );
+        Resolver resolver = LazyResolverProvider.resolver;
+        ResolutionResult result = resolver.resolve( request );
+        return result.getArtifactPath();
+    }
+
+    private String name;
+
+    @Override
+    public String getName()
+    {
+        return name;
+    }
+
+    @Override
+    public void setName( String name )
+    {
+        this.name = name;
+    }
+
+    @Override
+    public ConfiguredModuleComponentRepository createResolver()
+    {
+        return this;
+    }
+
+    @Override
+    public String getId()
+    {
+        return "XMvn";
+    }
+
+    @Override
+    public ModuleComponentRepositoryAccess getLocalAccess()
+    {
+        return this;
+    }
+
+    @Override
+    public ModuleComponentRepositoryAccess getRemoteAccess()
+    {
+        return this;
+    }
+
+    @Override
+    public boolean isDynamicResolveMode()
+    {
+        return false;
+    }
+
+    @Override
+    public boolean isLocal()
+    {
+        return true;
+    }
+
+    @Override
+    public void listModuleVersions( DependencyMetaData arg0, BuildableModuleComponentVersionSelectionResolveResult arg1 )
+    {
+        logger.debug( "listModuleVersions() called, but it is NOT IMPLEMENTED" );
+    }
+
+    @Override
+    public void resolveArtifact( ComponentArtifactMetaData artifact, ModuleSource module,
+                                 BuildableArtifactResolveResult result )
+    {
+
+        ModuleVersionIdentifier moduleId =
+            ( (DefaultModuleComponentArtifactMetaData) artifact ).toArtifactIdentifier().getModuleVersionIdentifier();
+        String groupId = moduleId.getGroup();
+        String artifactId = artifact.getName().getName();
+        String extension = artifact.getName().getExtension();
+        String classifier = artifact.getName().getClassifier();
+        String version = moduleId.getVersion();
+
+        Artifact artifact2 = new DefaultArtifact( groupId, artifactId, extension, classifier, version );
+        Path path = resolve( artifact2 );
+
+        if ( path == null )
+        {
+            logger.debug( "Unable to resolve artifact {}", artifact2 );
+            result.failed( new ArtifactResolveException( artifact.getId(), "XMvn was unable to resolve artifact "
+                + artifact2 ) );
+            return;
+        }
+
+        // Gradle expects resolved file to be named like in Maven/Ivy repo...
+        try
+        {
+            Path dir = Files.createTempDirectory( "xmvn-gradle-" );
+            String baseName =
+                artifact2.getArtifactId() + "-" + artifact2.getVersion()
+                    + ( artifact2.getClassifier().isEmpty() ? "" : "-" + artifact2.getClassifier() ) + "."
+                    + artifact2.getExtension();
+            Path origpPath = path;
+            path = dir.resolve( baseName );
+            Files.createSymbolicLink( path, origpPath );
+        }
+        catch ( IOException e )
+        {
+            throw new RuntimeException( e );
+        }
+
+        logger.debug( "Artifact {} was resolved to {}", artifact2, path );
+        result.resolved( path.toFile() );
+    }
+
+    @Override
+    public void resolveComponentMetaData( DependencyMetaData dependency, ModuleComponentIdentifier id,
+                                          BuildableModuleComponentMetaDataResolveResult result )
+    {
+        logger.debug( "Trying to resolve model for {}:{}:{}", id.getGroup(), id.getModule(), id.getVersion() );
+
+        Artifact artifact2 = new DefaultArtifact( id.getGroup(), id.getModule(), "pom", id.getVersion() );
+        Path pomPath = resolve( artifact2 );
+
+        if ( pomPath != null )
+        {
+            logger.debug( "Found Maven POM: {}", pomPath );
+            Path fakePom = fakePom( pomPath, id );
+            logger.debug( "Created fake POM: {}", fakePom );
+
+            MetaDataParser parser = new GradlePomModuleDescriptorParser();
+            MutableModuleComponentResolveMetaData metaData = parser.parseMetaData( this, fakePom.toFile() );
+
+            result.resolved( metaData );
+            return;
+        }
+        else
+        {
+            logger.debug( "POM not found, trying non-POM artifacts" );
+            for ( IvyArtifactName artifact : getDependencyArtifactNames( dependency ) )
+            {
+                String groupId = id.getGroup();
+                String artifactId = artifact.getName();
+                String extension = artifact.getExtension();
+                String classifier = artifact.getClassifier();
+                String version = id.getVersion();
+
+                Artifact artifact3 = new DefaultArtifact( groupId, artifactId, extension, classifier, version );
+                Path path = resolve( artifact3 );
+
+                if ( path != null )
+                {
+                    logger.debug( "Artifact {} found, returning minimal model", artifact3 );
+                    MutableModuleComponentResolveMetaData metaData = new DefaultMavenModuleResolveMetaData( dependency );
+                    result.resolved( metaData );
+                    return;
+                }
+            }
+        }
+
+        logger.debug( "No POM and no artifact found, failing" );
+        result.failed( new ModuleVersionResolveException( id, "XMvn was unable to resolve artifact " + artifact2 ) );
+    }
+
+    private Set<IvyArtifactName> getDependencyArtifactNames( DependencyMetaData dependency )
+    {
+        String moduleName = dependency.getRequested().getName();
+        Set<IvyArtifactName> artifactSet = new LinkedHashSet<>();
+        artifactSet.addAll( dependency.getArtifacts() );
+
+        if ( artifactSet.isEmpty() )
+        {
+            artifactSet.add( new DefaultIvyArtifactName( moduleName, "jar", "jar",
+                                                         Collections.<String, String> emptyMap() ) );
+        }
+
+        return artifactSet;
+    }
+
+    private static void setElement( Document doc, String name, String value )
+    {
+        NodeList childreen = doc.getDocumentElement().getChildNodes();
+        for ( int i = 0; i < childreen.getLength(); i++ )
+        {
+            Node child = childreen.item( i );
+            if ( child.getNodeName().equals( name ) )
+            {
+                child.setTextContent( value );
+                return;
+            }
+        }
+
+        Node child = doc.createElement( name );
+        child.setTextContent( value );
+        doc.getDocumentElement().appendChild( child );
+    }
+
+    private static Path fakePom( Path pom, ModuleComponentIdentifier moduleVersionIdentifier )
+    {
+        try
+        {
+            DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
+            Document doc = domFactory.newDocumentBuilder().parse( pom.toFile() );
+            setElement( doc, "groupId", moduleVersionIdentifier.getGroup() );
+            setElement( doc, "artifactId", moduleVersionIdentifier.getModule() );
+            setElement( doc, "version", moduleVersionIdentifier.getVersion() );
+
+            NodeList dependencies = doc.getElementsByTagName( "dependency" );
+            outer: for ( int i = 0; i < dependencies.getLength(); i++ )
+            {
+                Node dependency = dependencies.item( i );
+                NodeList childreen = dependency.getChildNodes();
+                for ( int j = 0; j < childreen.getLength(); j++ )
+                {
+                    Node child = childreen.item( j );
+                    if ( child.getNodeName().equals( "version" ) )
+                        continue outer;
+                }
+
+                Node child = doc.createElement( "version" );
+                child.setTextContent( "SYSTEM" );
+                dependency.appendChild( child );
+            }
+
+            TransformerFactory transformerFactory = TransformerFactory.newInstance();
+            Transformer transformer = transformerFactory.newTransformer();
+            transformer.setOutputProperty( OutputKeys.INDENT, "yes" );
+            DOMSource source = new DOMSource( doc );
+
+            Path fakePom = Files.createTempFile( "xmvn-", ".gradle.pom" );
+            StreamResult file = new StreamResult( fakePom.toFile() );
+            transformer.transform( source, file );
+            return fakePom;
+        }
+        catch ( Exception e )
+        {
+            throw new RuntimeException( e );
+        }
+    }
+
+    @Override
+    public void resolveModuleArtifacts( ComponentResolveMetaData component, ComponentUsage usage,
+                                        BuildableArtifactSetResolveResult result )
+    {
+        result.resolved( Collections.singleton( ( (ModuleComponentResolveMetaData) component ).artifact( "jar", "jar",
+                                                                                                         null ) ) );
+    }
+
+    @Override
+    public void resolveModuleArtifacts( ComponentResolveMetaData component, ArtifactType type,
+                                        BuildableArtifactSetResolveResult result )
+    {
+        if ( type != ArtifactType.MAVEN_POM )
+        {
+            logger.debug( "resolveModuleArtifacts() called for artifact type {}", type );
+            result.failed( new ArtifactResolveException( "resolveModuleArtifacts() is implemended only for Maven POMs" ) );
+            return;
+        }
+
+        ModuleComponentResolveMetaData metaData = (ModuleComponentResolveMetaData) component;
+        ModuleComponentIdentifier id = metaData.getComponentId();
+        DefaultIvyArtifactName name = new DefaultIvyArtifactName( id.getModule(), "pom", "pom" );
+        DefaultModuleComponentArtifactMetaData resolvedMetaData = new DefaultModuleComponentArtifactMetaData( id, name );
+        result.resolved( Collections.singleton( resolvedMetaData ) );
+    }
+
+    @Override
+    public LocallyAvailableExternalResource getMetaDataArtifact( ModuleVersionIdentifier id, ArtifactType type )
+    {
+        Path pomPath = resolve( new DefaultArtifact( id.getGroup(), id.getName(), "pom", id.getVersion() ) );
+
+        if ( pomPath == null )
+            return null;
+
+        return new DefaultLocallyAvailableExternalResource( pomPath.toUri(),
+                                                            new DefaultLocallyAvailableResource( pomPath.toFile() ) );
+    }
+}
diff --git a/gradle.spec b/gradle.spec
index 35a38ba..bf7e47b 100644
--- a/gradle.spec
+++ b/gradle.spec
@@ -1,6 +1,6 @@
 Name:           gradle
 Version:        2.2
-Release:        0.39%{?dist}
+Release:        0.40%{?dist}
 Summary:        Build automation tool
 # Some examples and integration tests are under GNU LGPL and Boost
 # Software License, but are not used to create binary package.
@@ -14,6 +14,7 @@ Source2:        gradle-font-metadata.xml
 Source3:        gradle-jquery-metadata.xml
 Source4:        gradle-launcher.sh
 Source5:        gradle.desktop
+Source6:        GradleResolver.java
 
 Patch0:         0001-Gradle-local-mode.patch
 Patch1:         0002-Use-Maven-Wagon-2.8.patch
@@ -152,6 +153,10 @@ BuildRequires:  lato-fonts
 BuildRequires:  liberation-mono-fonts
 BuildRequires:  js-jquery
 
+# for gradle-local
+BuildRequires:  xmvn-api
+BuildRequires:  xmvn-launcher
+
 Requires:       javapackages-tools
 Requires:       java-devel
 Requires:       bash
@@ -298,6 +303,17 @@ sensible defaults. Gradle is quickly becoming the build system of
 choice for many open source projects, leading edge enterprises and
 legacy automation challenges.
 
+%package local
+Summary:        XMvn connector for Gradle
+Requires:       %{name} = %{version}-%{release}
+Requires:       apache-ivy
+Requires:       slf4j
+Requires:       xmvn-api
+Requires:       xmvn-launcher
+
+%description local
+This package provides XMvn connector for Gradle, which allows Gradle
+to resolve artifacts from system artifact repository.
 
 %prep
 %setup -q
@@ -322,6 +338,13 @@ cp %{SOURCE1} build/all-released-versions.json
 %build
 gradle -x docs:distDocs --offline -s install -Pgradle_installPath=$PWD/inst
 
+# Build and assemble local connector
+mkdir -p local/org/fedoraproject/xmvn/connector/gradle
+cd ./local
+cp %{SOURCE6} org/fedoraproject/xmvn/connector/gradle/
+javac -cp $(echo ../subprojects/core/build/libs/gradle-core-%{version}*.jar):$(echo ../subprojects/dependency-management/build/libs/gradle-dependency-management-%{version}*.jar):$(echo ../subprojects/resources/build/libs/gradle-resources-%{version}*.jar):$(echo ../subprojects/base-services/build/libs/gradle-base-services-%{version}*.jar):$(build-classpath xmvn/xmvn-api xmvn/xmvn-launcher slf4j/api ivy) $(find -name *.java)
+jar cf xmvn-connector-gradle.jar org
+
 %install
 repo=$HOME/.m2/repository
 
@@ -363,6 +386,10 @@ do
     ln -sf %{_javadir}/%{name}/$mod.jar %{buildroot}%{_datadir}/%{name}/lib/$f-%{version}*.jar
 done
 
+%mvn_artifact org.fedoraproject.xmvn:xmvn-connector-gradle:2.1.0-SNAPSHOT local/xmvn-connector-gradle.jar
+%mvn_package ":xmvn*" local
+%mvn_file ":{xmvn*}" xmvn/@1
+
 %mvn_install
 
 install -d -m 755 %{buildroot}%{_bindir}/
@@ -399,7 +426,12 @@ gtk-update-icon-cache %{_datadir}/icons/hicolor &>/dev/null || :
 %doc changelog.txt
 %doc LICENSE NOTICE
 
+%files local -f .mfiles-local
+
 %changelog
+* Thu Nov 13 2014 Mikolaj Izdebski <mizdebsk at redhat.com> - 2.2-0.40
+- Add gradle-local subpackage
+
 * Wed Nov 12 2014 Mikolaj Izdebski <mizdebsk at redhat.com> - 2.2-0.39
 - Rebuild with gradle 2.2
 


More information about the scm-commits mailing list