package org.codehaus.mojo.unix.maven.sysvpkg; /* * The MIT License * * Copyright 2009 The Codehaus. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies * of the Software, and to permit persons to whom the Software is furnished to do * so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ import fj.*; import fj.data.List; import fj.data.*; import static fj.data.List.*; import static fj.data.Option.*; import org.apache.commons.vfs.*; import org.apache.commons.vfs.provider.local.*; import org.codehaus.mojo.unix.*; import static org.codehaus.mojo.unix.FileAttributes.*; import org.codehaus.mojo.unix.UnixFsObject.*; import static org.codehaus.mojo.unix.UnixFsObject.*; import org.codehaus.mojo.unix.sysvpkg.*; import org.codehaus.mojo.unix.sysvpkg.prototype.*; import org.codehaus.mojo.unix.util.*; import static org.codehaus.mojo.unix.util.RelativePath.*; import org.codehaus.mojo.unix.util.line.*; import static org.codehaus.mojo.unix.util.vfs.VfsUtil.*; import org.codehaus.plexus.util.*; import org.joda.time.*; import static org.joda.time.LocalDateTime.*; import java.io.*; import java.util.*; import java.util.concurrent.*; /** * @author <a href="mailto:trygvis@codehaus.org">Trygve Laugstøl</a> * @version $Id$ */ public class PkgUnixPackage extends UnixPackage { private FileObject workingDirectory; private FileObject prototype; private FileObject pkginfo; private boolean debug; private static final ScriptUtil scriptUtil = new ScriptUtil( "preinstall" , "postinstall" , "preremove" , "postremove" ). customScript( "depend" ). customScript( "checkinstall" ). customScript( "compver" ). customScript( "copyright" ). customScript( "request" ). customScript( "space" ); private PrototypeFile prototypeFile; private PkginfoFile pkginfoFile; private List<Callable> operations = nil(); private Option<String> classifier = none(); public PkgUnixPackage() { super( "pkg" ); } public UnixPackage parameters( PackageParameters parameters ) { this.classifier = parameters.classifier; pkginfoFile = new PkginfoFile( parameters.architecture.orSome( "all" ), "application", parameters.name, parameters.id, getPkgVersion( parameters.version ) ). desc( parameters.description ). email( parameters.contactEmail ). pstamp( some( parameters.version.timestamp ) ). email( parameters.contactEmail ); return this; } // ----------------------------------------------------------------------- // Common Settings // ----------------------------------------------------------------------- public UnixPackage workingDirectory( FileObject workingDirectory ) throws FileSystemException { this.workingDirectory = workingDirectory; return this; } public UnixPackage debug( boolean debug ) { this.debug = debug; return this; } public void beforeAssembly( FileAttributes defaultDirectoryAttributes ) throws IOException { prototype = workingDirectory.resolveFile( "prototype" ); pkginfo = workingDirectory.resolveFile( "pkginfo" ); Directory defaultDirectory = directory( BASE, fromDateFields( new Date( 0 ) ), defaultDirectoryAttributes ); DirectoryEntry directoryEntry = new DirectoryEntry( Option.<String>none(), defaultDirectory ); prototypeFile = new PrototypeFile( directoryEntry ); } // ----------------------------------------------------------------------- // Pkg Specific Settings // ----------------------------------------------------------------------- public PkgUnixPackage pkgParameters( List<String> classes, Option<String> category ) { pkginfoFile = pkginfoFile. category( category.orSome( pkginfoFile.category ) ). classes( classes ); return this; } public void packageToFile( File packageFile, ScriptUtil.Strategy strategy ) throws Exception { // ----------------------------------------------------------------------- // Validate that the prototype looks sane // ----------------------------------------------------------------------- // TODO: This should be more configurable RelativePath[] specialPaths = new RelativePath[]{ BASE, relativePath( "/etc" ), relativePath( "/etc/opt" ), relativePath( "/opt" ), relativePath( "/usr" ), relativePath( "/var" ), relativePath( "/var/opt" ), }; // TODO: This should use setDirectoryAttributes for ( RelativePath specialPath : specialPaths ) { if ( prototypeFile.hasPath( specialPath ) ) { // TODO: this should come from a common time object so that all "now" timestamps are the same prototypeFile.addDirectory( directory( specialPath, new LocalDateTime(), EMPTY ) ); } } // ----------------------------------------------------------------------- // The shit // ----------------------------------------------------------------------- File workingDirectoryF = asFile( workingDirectory ); File pkginfoF = asFile( pkginfo ); File prototypeF = asFile( prototype ); ScriptUtil.Result result = scriptUtil. createExecution( classifier.orSome( "default" ), "pkg", getScripts(), workingDirectoryF, strategy ). execute(); LineStreamUtil.toFile( pkginfoFile.toList(), pkginfoF ); String pkg = pkginfoFile.getPkgName( pkginfoF ); prototypeFile.addIFileIf( pkginfoF, "pkginfo" ); prototypeFile.addIFileIf( result.preInstall, "preinstall" ); prototypeFile.addIFileIf( result.postInstall, "postinstall" ); prototypeFile.addIFileIf( result.preRemove, "preremove" ); prototypeFile.addIFileIf( result.postRemove, "postremove" ); for ( File file : result.customScripts ) { prototypeFile.addIFileIf( file ); } workingDirectory.resolveFile( "assembly" ); // TODO: Replace this with an Actor-based execution for ( Callable operation : operations ) { operation.call(); } LineStreamUtil.toFile( prototypeFile, prototypeF ); new PkgmkCommand(). setDebug( debug ). setOverwrite( true ). setDevice( workingDirectoryF ). setPrototype( prototypeF ). execute(); new PkgtransCommand(). setDebug( debug ). setAsDatastream( true ). setOverwrite( true ). execute( workingDirectoryF, packageFile, pkg ); } public static String getPkgVersion( PackageVersion v ) { String version = v.version; if ( v.revision.isSome() ) { version += "-" + v.revision.some(); } if ( v.snapshot ) { version += "-" + v.timestamp; } return version; } public FileObject getRoot() { return workingDirectory; } public FileCollector addDirectory( UnixFsObject.Directory directory ) throws IOException { prototypeFile.addDirectory( directory ); return this; } public FileCollector addFile( FileObject fromFile, UnixFsObject.RegularFile file ) throws IOException { prototypeFile.addFile( fromFile( fromFile, file ), file ); return this; } public FileCollector addSymlink( UnixFsObject.Symlink symlink ) throws IOException { prototypeFile.addSymlink( symlink ); return this; } public void apply( F2<UnixFsObject, FileAttributes, FileAttributes> f ) { prototypeFile.apply( f ); } public static PkgUnixPackage cast( UnixPackage unixPackage ) { return PkgUnixPackage.class.cast( unixPackage ); } // ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- public FileObject fromFile( final FileObject fromFile, UnixFsObject.RegularFile file ) throws FileSystemException { // If it is a file on the local file system, just point the entry in the prototype file to it if ( fromFile.getFileSystem() instanceof LocalFileSystem ) { return fromFile; } // Creates a file under the working directory that should match the destination path final FileObject tmpFile = workingDirectory.resolveFile( file.path.string ); operations = operations.cons( new Callable() { public Object call() throws Exception { OutputStream outputStream = null; try { tmpFile.getParent().createFolder(); tmpFile.copyFrom( fromFile, Selectors.SELECT_ALL ); tmpFile.getContent().setLastModifiedTime( fromFile.getContent().getLastModifiedTime() ); } finally { IOUtil.close( outputStream ); } return Unit.unit(); } }); return tmpFile; } }