package org.codehaus.mojo.mockrepo; /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.factory.ArtifactFactory; import org.apache.maven.artifact.repository.metadata.Metadata; import org.apache.maven.artifact.repository.metadata.Plugin; import org.apache.maven.artifact.repository.metadata.Versioning; import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.apache.maven.model.Build; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.codehaus.mojo.mockrepo.utils.MockRepoUtils; import org.codehaus.plexus.util.ReaderFactory; import org.codehaus.plexus.util.StringUtils; import org.codehaus.plexus.util.xml.XmlStreamReader; import org.codehaus.plexus.util.xml.Xpp3Dom; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import java.io.IOException; import java.io.InputStream; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; import java.util.TreeSet; /** * Locally hosted repository. * @since 1.0-alpha-1 * @author Stephen Connolly */ public class HostedRepository implements Repository { private Map/*<String,Metadata>*/ metadata = new HashMap(); private SortedMap/*<String,Content>*/ content = new TreeMap(); private final Object lock = new Object(); public Metadata getMetadata( String path ) { synchronized ( lock ) { return (Metadata) metadata.get( path ); } } public Content getContent( String path ) { synchronized ( lock ) { return (Content) content.get( path ); } } public List getChildPaths( String path ) { System.out.println("ls " + path); if ( path.length() > 0 && !path.endsWith( "/" ) ) { System.out.println("a file"); return Collections.EMPTY_LIST; } Set results = new TreeSet(); synchronized ( lock ) { if ( content.containsKey( path ) ) { System.out.println("really a file"); return Collections.EMPTY_LIST; } final Iterator i = content.tailMap( path ).keySet().iterator(); while ( i.hasNext() ) { String s = (String) i.next(); if ( !s.startsWith( path ) ) { break; } s = s.substring( path.length() ); int index = s.indexOf( '/' ); if ( index == -1 ) { results.add( s ); } else { results.add( s.substring( 0, index+1 ) ); } } } return Collections.unmodifiableList( new ArrayList( results ) ); } public Model deployPom( Content content ) throws IOException { MavenXpp3Reader reader = new MavenXpp3Reader(); XmlStreamReader fileReader = null; try { fileReader = ReaderFactory.newXmlReader( content.getInputStream() ); final Model model = reader.read( fileReader ); String groupId = MockRepoUtils.getGroupId( model ); String artifactId = MockRepoUtils.getArtifactId( model ); String version = MockRepoUtils.getVersion( model ); String packaging = model.getPackaging() == null ? "jar" : model.getPackaging(); final String basePath = MockRepoUtils.getGAVPathName( groupId, artifactId, version ); deploy( basePath + ".pom", content ); updateVersionMetadata( groupId, artifactId, version ); if ( "maven-plugin".equals( packaging ) ) { updatePluginMetadata( model, groupId, artifactId ); } return model; } catch ( XmlPullParserException e ) { IOException ioe = new IOException( "Unable to parse pom" ); ioe.initCause( e ); throw ioe; } finally { if ( fileReader != null ) { try { fileReader.close(); } catch ( IOException e ) { // ignore } } } } public void deploy( String path, Content content ) throws IOException { InputStream is = content.getInputStream(); try { MessageDigest md5Digest = MessageDigest.getInstance( "MD5" ); MessageDigest sha1Digest = MessageDigest.getInstance( "SHA1" ); md5Digest.reset(); sha1Digest.reset(); byte[] buffer = new byte[8192]; int read; while ( ( read = is.read( buffer ) ) > 0 ) { md5Digest.update( buffer, 0, read ); sha1Digest.update( buffer, 0, read ); } final String md5 = StringUtils.leftPad( new BigInteger( 1, md5Digest.digest() ).toString( 16 ), 32, "0" ); final String sha1 = StringUtils.leftPad( new BigInteger( 1, sha1Digest.digest() ).toString( 16 ), 40, "0" ); synchronized ( lock ) { this.content.put( path, content ); this.content.put( path + ".md5", new ByteArrayContent( md5.getBytes(), content.getLastModified() ) ); this.content.put( path + ".sha1", new ByteArrayContent( sha1.getBytes(), content.getLastModified() ) ); } } catch ( NoSuchAlgorithmException e ) { IOException ioe = new IOException( "Unable to calculate hashes" ); ioe.initCause( e ); throw ioe; } finally { try { is.close(); } catch ( IOException e ) { // ignore } } } private void updatePluginMetadata( Model model, String groupId, String artifactId ) { synchronized ( lock ) { Metadata metadata = (Metadata) this.metadata.get( MockRepoUtils.getGAVPath( groupId, null, null ) ); if ( metadata == null ) { metadata = new Metadata(); this.metadata.put( MockRepoUtils.getGAVPath( groupId, null, null ), metadata ); } boolean found = false; Iterator k = metadata.getPlugins().iterator(); while ( !found && k.hasNext() ) { found = StringUtils.equals( artifactId, ( (Plugin) k.next() ).getArtifactId() ); } if ( !found ) { Plugin plugin = new Plugin(); plugin.setArtifactId( artifactId ); plugin.setName( model.getName() ); // TODO proper goal-prefix determination // ugh! this is incredibly hacky and does not handle some fool that sets the goal prefix in // a parent pom... ok unlikely, but stupid is as stupid does boolean havePrefix = false; final Build build = model.getBuild(); if ( build != null && build.getPlugins() != null ) { havePrefix = setPluginGoalPrefixFromConfiguration( plugin, build.getPlugins() ); } if ( !havePrefix && build != null && build.getPluginManagement() != null && build.getPluginManagement().getPlugins() != null ) { havePrefix = setPluginGoalPrefixFromConfiguration( plugin, build.getPluginManagement().getPlugins() ); } if ( !havePrefix && artifactId.startsWith( "maven-" ) && artifactId.endsWith( "-plugin" ) ) { plugin.setPrefix( StringUtils.chompLast( artifactId, "-plugin" ).substring( "maven-".length() ) ); havePrefix = true; } if ( !havePrefix && artifactId.endsWith( "-maven-plugin" ) ) { plugin.setPrefix( StringUtils.chompLast( artifactId, "-maven-plugin" ) ); havePrefix = true; } if ( !havePrefix ) { plugin.setPrefix( artifactId ); } metadata.addPlugin( plugin ); } } } private boolean setPluginGoalPrefixFromConfiguration( Plugin plugin, List plugins ) { Iterator iterator = plugins.iterator(); while ( iterator.hasNext() ) { org.apache.maven.model.Plugin def = (org.apache.maven.model.Plugin) iterator.next(); if ( ( def.getGroupId() == null || StringUtils.equals( "org.apache.maven.plugins", def.getGroupId() ) ) && StringUtils.equals( "maven-plugin-plugin", def.getArtifactId() ) ) { Xpp3Dom configuration = (Xpp3Dom) def.getConfiguration(); if ( configuration != null ) { final Xpp3Dom goalPrefix = configuration.getChild( "goalPrefix" ); if ( goalPrefix != null ) { plugin.setPrefix( goalPrefix.getValue() ); return true; } } break; } } return false; } private void updateVersionMetadata( String groupId, String artifactId, String version ) { synchronized ( lock ) { Metadata metadata = (Metadata) this.metadata.get( MockRepoUtils.getGAVPath( groupId, artifactId, null ) ); if ( metadata == null ) { metadata = new Metadata(); metadata.setGroupId( groupId ); metadata.setArtifactId( artifactId ); this.metadata.put( MockRepoUtils.getGAVPath( groupId, artifactId, null ), metadata ); } if ( metadata.getArtifactId() == null ) { // might be a plugin at localhost.foo and an artifact foo at localhost metadata.setArtifactId( artifactId ); } if ( metadata.getVersioning() == null ) { metadata.setVersioning( new Versioning() ); metadata.getVersioning().setLastUpdatedTimestamp( new Date() ); } metadata.getVersioning().addVersion( version ); if ( metadata.getVersion() == null || new DefaultArtifactVersion( metadata.getVersion() ).compareTo( new DefaultArtifactVersion( version ) ) < 0 ) { metadata.setVersion( version ); } } } }