package org.apache.archiva.cli; /* * 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 com.sampullara.cli.Args; import com.sampullara.cli.Argument; import org.apache.archiva.admin.model.beans.ManagedRepository; import org.apache.archiva.consumers.ConsumerException; import org.apache.archiva.consumers.InvalidRepositoryContentConsumer; import org.apache.archiva.consumers.KnownRepositoryContentConsumer; import org.apache.archiva.consumers.RepositoryContentConsumer; import org.apache.archiva.converter.RepositoryConversionException; import org.apache.archiva.converter.legacy.LegacyRepositoryConverter; import org.apache.archiva.repository.scanner.RepositoryScanStatistics; import org.apache.archiva.repository.scanner.RepositoryScanner; import org.apache.archiva.repository.scanner.RepositoryScannerException; import org.apache.commons.lang.StringUtils; import org.springframework.context.support.ClassPathXmlApplicationContext; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; /** * ArchivaCli *

*

* TODO add back reading of archiva.xml from a given location */ public class ArchivaCli { // ---------------------------------------------------------------------------- // Properties controlling Repository conversion // ---------------------------------------------------------------------------- public static final String SOURCE_REPO_PATH = "sourceRepositoryPath"; public static final String TARGET_REPO_PATH = "targetRepositoryPath"; public static final String BLACKLISTED_PATTERNS = "blacklistPatterns"; public static final String POM_PROPERTIES = "/META-INF/maven/org.apache.archiva/archiva-cli/pom.properties"; private static String getVersion() throws IOException { try (InputStream pomStream = ArchivaCli.class.getResourceAsStream( POM_PROPERTIES )) { if ( pomStream == null ) { throw new IOException( "Failed to load " + POM_PROPERTIES ); } Properties properties = new Properties(); properties.load( pomStream ); return properties.getProperty( "version" ); } } private ClassPathXmlApplicationContext applicationContext; public ArchivaCli() { applicationContext = new ClassPathXmlApplicationContext( new String[]{ "classpath*:/META-INF/spring-context.xml" } ); } public static void main( String[] args ) throws Exception { Commands command = new Commands(); try { Args.parse( command, args ); } catch ( IllegalArgumentException e ) { System.err.println( e.getMessage() ); Args.usage( command ); return; } ArchivaCli cli = new ArchivaCli(); try { cli.execute( command ); } finally { cli.destroy(); } } private void destroy() { applicationContext.destroy(); } private void execute( Commands command ) throws Exception { if ( command.help ) { Args.usage( command ); } else if ( command.version ) { System.out.print( "Version: " + getVersion() ); } else if ( command.convert ) { doConversion( command.properties ); } else if ( command.scan ) { if ( command.repository == null ) { System.err.println( "The repository must be specified." ); Args.usage( command ); return; } doScan( command.repository, command.consumers.split( "," ) ); } else if ( command.listConsumers ) { dumpAvailableConsumers(); } else { Args.usage( command ); } } private void doScan( String path, String[] consumers ) throws ConsumerException, MalformedURLException { ManagedRepository repo = new ManagedRepository(); repo.setId( new File( path ).getName() ); repo.setName( "Archiva CLI Provided Repo" ); repo.setLocation( path ); List knownConsumerList = new ArrayList<>(); knownConsumerList.addAll( getConsumerList( consumers ) ); List invalidConsumerList = Collections.emptyList(); List ignoredContent = new ArrayList<>(); ignoredContent.addAll( Arrays.asList( RepositoryScanner.IGNORABLE_CONTENT ) ); RepositoryScanner scanner = applicationContext.getBean( RepositoryScanner.class ); try { RepositoryScanStatistics stats = scanner.scan( repo, knownConsumerList, invalidConsumerList, ignoredContent, RepositoryScanner.FRESH_SCAN ); System.out.println( "\n" + stats.toDump( repo ) ); } catch ( RepositoryScannerException e ) { e.printStackTrace( System.err ); } } private List getConsumerList( String[] consumers ) throws ConsumerException { List consumerList = new ArrayList<>(); Map availableConsumers = getConsumers(); for ( String specifiedConsumer : consumers ) { if ( !availableConsumers.containsKey( specifiedConsumer ) ) { System.err.println( "Specified consumer [" + specifiedConsumer + "] not found." ); dumpAvailableConsumers(); System.exit( 1 ); } consumerList.add( availableConsumers.get( specifiedConsumer ) ); } return consumerList; } private void dumpAvailableConsumers() { Map availableConsumers = getConsumers(); System.out.println( ".\\ Available Consumer List \\.______________________________" ); for ( Map.Entry entry : availableConsumers.entrySet() ) { String consumerHint = entry.getKey(); RepositoryContentConsumer consumer = entry.getValue(); System.out.println( " " + consumerHint + ": " + consumer.getDescription() + " (" + consumer.getClass().getName() + ")" ); } } @SuppressWarnings( "unchecked" ) private Map getConsumers() { Map beans = applicationContext.getBeansOfType( KnownRepositoryContentConsumer.class ); // we use a naming conventions knownRepositoryContentConsumer#hint // with plexus we used only hint so remove before# Map smallNames = new HashMap<>( beans.size() ); for ( Map.Entry entry : beans.entrySet() ) { smallNames.put( StringUtils.substringAfterLast( entry.getKey(), "#" ), entry.getValue() ); } return smallNames; } private void doConversion( String properties ) throws IOException, RepositoryConversionException { LegacyRepositoryConverter legacyRepositoryConverter = applicationContext.getBean( LegacyRepositoryConverter.class ); Properties p = new Properties(); try (InputStream fis = Files.newInputStream( Paths.get(properties))) { p.load( fis ); } File oldRepositoryPath = new File( p.getProperty( SOURCE_REPO_PATH ) ); File newRepositoryPath = new File( p.getProperty( TARGET_REPO_PATH ) ); System.out.println( "Converting " + oldRepositoryPath + " to " + newRepositoryPath ); List fileExclusionPatterns = null; String s = p.getProperty( BLACKLISTED_PATTERNS ); if ( s != null ) { fileExclusionPatterns = Arrays.asList( StringUtils.split( s, "," ) ); } legacyRepositoryConverter.convertLegacyRepository( oldRepositoryPath, newRepositoryPath, fileExclusionPatterns ); } private static class Commands { @Argument( description = "Display help information", value = "help", alias = "h" ) private boolean help; @Argument( description = "Display version information", value = "version", alias = "v" ) private boolean version; @Argument( description = "List available consumers", value = "listconsumers", alias = "l" ) private boolean listConsumers; @Argument( description = "The consumers to use (comma delimited)", value = "consumers", alias = "u" ) private String consumers = "count-artifacts"; @Argument( description = "Scan the specified repository", value = "scan", alias = "s" ) private boolean scan; @Argument( description = "Convert a legacy Maven 1.x repository to a Maven 2.x repository using a properties file to describe the conversion", value = "convert", alias = "c" ) private boolean convert; @Argument( description = "The properties file for the conversion", value = "properties" ) private String properties = "conversion.properties"; @Argument( description = "The repository to scan", value = "repository" ) private String repository; } }