blob: ced107e28e464001627088a17874e98b5deeb4bd [file] [log] [blame]
package org.apache.netbeans.nbm;
/*
* 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 java.io.File;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.factory.ArtifactFactory;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.repository.DefaultArtifactRepository;
import org.apache.maven.artifact.repository.layout.ArtifactRepositoryLayout;
import org.apache.maven.artifact.resolver.ArtifactResolver;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugin.logging.Log;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.taskdefs.Copy;
import org.apache.tools.ant.types.FileSet;
import org.codehaus.plexus.PlexusConstants;
import org.codehaus.plexus.PlexusContainer;
import org.codehaus.plexus.archiver.gzip.GZipArchiver;
import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
import org.codehaus.plexus.context.Context;
import org.codehaus.plexus.context.ContextException;
import org.codehaus.plexus.personality.plexus.lifecycle.phase.Contextualizable;
import org.netbeans.nbbuild.MakeUpdateDesc;
/**
* Create the NetBeans auto update site definition.
*
* @author Milos Kleint
*
*/
@Mojo( name = "autoupdate",
defaultPhase = LifecyclePhase.PACKAGE,
aggregator = true,
requiresDependencyResolution = ResolutionScope.RUNTIME )
public class CreateUpdateSiteMojo
extends AbstractNbmMojo
implements Contextualizable
{
/**
* output directory.
*/
@Parameter( required = true, defaultValue = "${project.build.directory}" )
protected File outputDirectory;
/**
* autoupdate site xml file name.
*/
@Parameter( defaultValue = "updates.xml", property = "maven.nbm.updatesitexml" )
protected String fileName;
/**
* A custom distribution base for the nbms in the update site. If NOT defined, the update site will use a simple
* relative URL, which is generally what you want. Defining it as "auto" will pick up the distribution URL from each
* NBM, which is generally wrong. See <code>distributionUrl</code> in nbm mojo for what url will be used in that
* case.
* <p/>
* The value is either a direct http protocol based URL that points to the location under which all nbm files are
* located, or
* <p/>
* allows to create an update site based on maven repository content. The resulting autoupdate site document can be
* uploaded as tar.gz to repository as well as attached artifact to the 'nbm-application' project.
* <br/>
* Format: id::layout::url same as in maven-deploy-plugin
* <br/>
* with the 'default' and 'legacy' layouts. (maven2 vs maven1 layout)
* <br/>
* If the value doesn't contain :: characters, it's assumed to be the flat structure and the value is just the URL.
*
* @since 3.0 it's also possible to add remote repository as base
*/
@Parameter( defaultValue = ".", property = "maven.nbm.customDistBase" )
private String distBase;
/**
* The Maven Project.
*
*/
@Parameter( required = true, readonly = true, property = "project" )
private MavenProject project;
/**
* If the executed project is a reactor project, this will contains the full list of projects in the reactor.
*/
@Parameter( required = true, readonly = true, defaultValue = "${reactorProjects}" )
private List reactorProjects;
/**
* List of Ant style patterns on artifact GA (groupID:artifactID) that should be included in the update site. Eg.
* org.netbeans.* matches all artifacts with any groupID starting with 'org.netbeans.', org.*:api will match any
* artifact with artifactId of 'api' and groupId starting with 'org.'
*
* @since 3.14
*/
@Parameter
private List<String> updateSiteIncludes;
// <editor-fold defaultstate="collapsed" desc="Component parameters">
@Component
private ArtifactFactory artifactFactory;
/**
* Contextualized.
*/
private PlexusContainer container;
/**
* Used for attaching the artifact in the project
*
*/
@Component
private MavenProjectHelper projectHelper;
@Component
private ArtifactResolver artifactResolver;
/**
* Local maven repository.
*
*/
@Parameter( readonly = true, required = true, defaultValue = "${localRepository}" )
protected ArtifactRepository localRepository;
// </editor-fold>
public void execute()
throws MojoExecutionException, MojoFailureException
{
Project antProject = registerNbmAntTasks();
File nbmBuildDirFile = new File( outputDirectory, "netbeans_site" );
if ( !nbmBuildDirFile.exists() )
{
nbmBuildDirFile.mkdirs();
}
boolean isRepository = false;
if ( "auto".equals( distBase ) )
{
distBase = null;
}
ArtifactRepository distRepository = getDeploymentRepository( distBase, container, getLog() );
String oldDistBase = null;
if ( distRepository != null )
{
isRepository = true;
}
else
{
if ( distBase != null && !distBase.contains( "::" ) )
{
oldDistBase = distBase;
}
}
if ( "nbm-application".equals( project.getPackaging() ) )
{
@SuppressWarnings( "unchecked" )
Set<Artifact> artifacts = project.getArtifacts();
for ( Artifact art : artifacts )
{
if ( !matchesIncludes( art ) )
{
continue;
}
ArtifactResult res
= turnJarToNbmFile( art, artifactFactory, artifactResolver, project, localRepository );
if ( res.hasConvertedArtifact() )
{
art = res.getConvertedArtifact();
}
if ( art.getType().equals( "nbm-file" ) )
{
Copy copyTask = (Copy) antProject.createTask( "copy" );
copyTask.setOverwrite( true );
copyTask.setFile( art.getFile() );
if ( !isRepository )
{
copyTask.setFlatten( true );
copyTask.setTodir( nbmBuildDirFile );
}
else
{
String path = distRepository.pathOf( art );
File f = new File( nbmBuildDirFile, path.replace( '/', File.separatorChar ) );
copyTask.setTofile( f );
}
try
{
copyTask.execute();
}
catch ( BuildException ex )
{
throw new MojoExecutionException( "Cannot merge nbm files into autoupdate site", ex );
}
}
if ( res.isOSGiBundle() )
{
// TODO check for bundles
}
}
getLog().info( "Created NetBeans module cluster(s) at " + nbmBuildDirFile.getAbsoluteFile() );
}
else if ( reactorProjects != null && reactorProjects.size() > 0 )
{
Iterator it = reactorProjects.iterator();
while ( it.hasNext() )
{
MavenProject proj = (MavenProject) it.next();
File projOutputDirectory = new File( proj.getBuild().getDirectory() );
if ( projOutputDirectory != null && projOutputDirectory.exists() )
{
Copy copyTask = (Copy) antProject.createTask( "copy" );
if ( !isRepository )
{
FileSet fs = new FileSet();
fs.setDir( projOutputDirectory );
fs.createInclude().setName( "*.nbm" );
copyTask.addFileset( fs );
copyTask.setOverwrite( true );
copyTask.setFlatten( true );
copyTask.setTodir( nbmBuildDirFile );
}
else
{
boolean has = false;
File[] fls = projOutputDirectory.listFiles();
if ( fls != null )
{
for ( File fl : fls )
{
if ( fl.getName().endsWith( ".nbm" ) )
{
copyTask.setFile( fl );
has = true;
break;
}
}
}
if ( !has )
{
continue;
}
Artifact art
= artifactFactory.createArtifact( proj.getGroupId(), proj.getArtifactId(), proj.
getVersion(),
null, "nbm-file" );
String path = distRepository.pathOf( art );
File f = new File( nbmBuildDirFile, path.replace( '/', File.separatorChar ) );
copyTask.setTofile( f );
}
try
{
copyTask.execute();
}
catch ( BuildException ex )
{
throw new MojoExecutionException( "Cannot merge nbm files into autoupdate site", ex );
}
}
}
}
else
{
throw new MojoExecutionException(
"This goal only makes sense on reactor projects or project with 'nbm-application' packaging." );
}
MakeUpdateDesc descTask = (MakeUpdateDesc) antProject.createTask( "updatedist" );
File xmlFile = new File( nbmBuildDirFile, fileName );
descTask.setDesc( xmlFile );
if ( oldDistBase != null )
{
descTask.setDistBase( oldDistBase );
}
if ( distRepository != null )
{
descTask.setDistBase( distRepository.getUrl() );
}
FileSet fs = new FileSet();
fs.setDir( nbmBuildDirFile );
fs.createInclude().setName( "**/*.nbm" );
descTask.addFileset( fs );
try
{
descTask.execute();
}
catch ( BuildException ex )
{
throw new MojoExecutionException( "Cannot create autoupdate site xml file", ex );
}
getLog().info( "Generated autoupdate site content at " + nbmBuildDirFile.getAbsolutePath() );
try
{
GZipArchiver gz = new GZipArchiver();
gz.addFile( xmlFile, fileName );
File gzipped = new File( nbmBuildDirFile, fileName + ".gz" );
gz.setDestFile( gzipped );
gz.createArchive();
if ( "nbm-application".equals( project.getPackaging() ) )
{
projectHelper.attachArtifact( project, "xml.gz", "updatesite", gzipped );
}
}
catch ( Exception ex )
{
throw new MojoExecutionException( "Cannot create gzipped version of the update site xml file.", ex );
}
}
private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" );
static ArtifactRepository getDeploymentRepository( String distBase, PlexusContainer container, Log log )
throws MojoExecutionException, MojoFailureException
{
ArtifactRepository repo = null;
if ( distBase != null )
{
Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher( distBase );
if ( !matcher.matches() )
{
if ( !distBase.contains( "::" ) )
{
//backward compatibility gag.
return null;
}
throw new MojoFailureException( distBase,
"Invalid syntax for repository.",
"Invalid syntax for alternative repository. Use \"id::layout::url\"." );
}
else
{
String id = matcher.group( 1 ).trim();
String layout = matcher.group( 2 ).trim();
String url = matcher.group( 3 ).trim();
ArtifactRepositoryLayout repoLayout;
try
{
repoLayout = (ArtifactRepositoryLayout) container.lookup( ArtifactRepositoryLayout.ROLE, layout );
}
catch ( ComponentLookupException e )
{
throw new MojoExecutionException( "Cannot find repository layout: " + layout, e );
}
repo = new DefaultArtifactRepository( id, url, repoLayout );
}
}
return repo;
}
@Override
public void contextualize( Context context )
throws ContextException
{
this.container = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
}
private boolean matchesIncludes( Artifact art )
{
if ( updateSiteIncludes != null )
{
String s = art.getGroupId() + ":" + art.getArtifactId();
for ( String p : updateSiteIncludes )
{
//TODO optimize and only do once per execution.
p = p.replace( ".", "\\." ).replace( "*", ".*" );
Pattern patt = Pattern.compile( p );
if ( patt.matcher( s ).matches() )
{
return true;
}
}
return false;
}
return true;
}
}