package org.codehaus.mojo.unix.rpm; /* * 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 static fj.Bottom.*; import fj.*; import static fj.Function.*; import fj.data.List; import fj.data.*; import static fj.data.Option.*; import org.codehaus.mojo.unix.*; import static org.codehaus.mojo.unix.FileAttributes.*; import static org.codehaus.mojo.unix.PackageFileSystem.*; import org.codehaus.mojo.unix.UnixFsObject.*; import static org.codehaus.mojo.unix.java.FileF.*; import static org.codehaus.mojo.unix.java.StringF.*; import static org.codehaus.mojo.unix.util.RelativePath.*; import org.codehaus.mojo.unix.util.*; import org.codehaus.mojo.unix.util.line.*; import static org.codehaus.mojo.unix.util.line.LineStreamUtil.*; import org.codehaus.plexus.util.*; import static org.joda.time.LocalDateTime.*; import org.joda.time.*; import java.io.*; import java.util.*; /** * TODO: Split this file into two parts; a part which has all the meta data and one that has all the file data. * * A purely meta data one is useful for parts of the code that just create SPEC files and testing. * * @author <a href="mailto:trygvis@codehaus.org">Trygve Laugstøl</a> * @version $Id$ */ public class SpecFile implements LineProducer { public String version; public String release; // Will be generated if not set public String name; public String summary; public String license; public String distribution; public File icon; public String vendor; public String url; public String group; public String packager; public List<String> defineStatements = List.nil(); public List<String> provides = List.nil(); public List<String> requires = List.nil(); public List<String> conflicts = List.nil(); public String prefix; public File buildRoot; public String description; public boolean dump; // Create a default default file system for testing private final UnixFsObject DEFAULT_FS_ROOT = UnixFsObject.directory( RelativePath.BASE, LocalDateTime.fromDateFields( new Date() ), EMPTY ); private final UnixFsObject DEFAULT_DEFAULT = UnixFsObject.directory( RelativePath.BASE, LocalDateTime.fromDateFields( new Date() ), EMPTY ); private PackageFileSystem<Object> fileSystem = create( new PlainPackageFileSystemObject( DEFAULT_FS_ROOT ), new PlainPackageFileSystemObject( DEFAULT_DEFAULT ) ); public Option<File> includePre = none(); public Option<File> includePost = none(); public Option<File> includePreun = none(); public Option<File> includePostun = none(); public void beforeAssembly( Directory defaultDirectory ) { Validate.validateNotNull( defaultDirectory ); Directory root = UnixFsObject.directory( BASE, fromDateFields( new Date( 0 ) ), EMPTY ); fileSystem = create( new PlainPackageFileSystemObject( root ), new PlainPackageFileSystemObject( defaultDirectory ) ); } public void addFile( UnixFsObject.RegularFile file ) { fileSystem = fileSystem.addFile( new PlainPackageFileSystemObject( file ) ); } public void addDirectory( UnixFsObject.Directory directory ) { fileSystem = fileSystem.addDirectory( new PlainPackageFileSystemObject( directory ) ); } public void addSymlink( UnixFsObject.Symlink symlink ) { fileSystem = fileSystem.addSymlink( new PlainPackageFileSystemObject( symlink ) ); } public PackageFileSystem<Object> getFileSystem() { return fileSystem; } public void apply( F2<UnixFsObject, FileAttributes, FileAttributes> f ) { fileSystem = fileSystem.apply( f ); } public void streamTo( LineStreamWriter spec ) { for ( String defineStatement : defineStatements ) { spec.add( "%define " + defineStatement ); } UnixUtil.assertField( "version", version ); UnixUtil.assertField( "release", release ); spec. add( "Name: " + name ). add( "Version: " + version ). add( "Release: " + release ). add( "Summary: " + UnixUtil.getField( "summary", summary ) ). add( "License: " + UnixUtil.getField( "license", license ) ). addIfNotEmpty( "Distribution: ", distribution ). add( "Group: " + UnixUtil.getField( "group", group ) ). addIfNotEmpty( "Packager", packager ). addAllLines( prefix( provides, "Provides" ) ). addAllLines( prefix( requires, "Requires" ) ). addAllLines( prefix( conflicts, "Conflicts" ) ). addIfNotEmpty( fromNull( buildRoot ).map( compose( curry( concat, "BuildRoot: " ), getAbsolutePath ) ).orSome( "" ) ). add(); // The %description tag is required even if it is empty. spec. add( "%description" ). addIf( StringUtils.isNotEmpty( description ), description ). add(); spec. add( "%files" ). addAllLines( fileSystem.prettify().toList().filter( excludePaths ).map( SpecFile.showUnixFsObject() ) ); spec.addIf( includePre.isSome() || includePost.isSome() || includePreun.isSome() || includePostun.isSome(), "" ); if ( includePre.isSome() ) { spec.add( "%pre" ); spec.add( "%include " + includePre.map( getAbsolutePath ).some() ); } if ( includePost.isSome() ) { spec.add( "%post" ); spec.add( "%include " + includePost.map( getAbsolutePath ).some() ); } if ( includePreun.isSome() ) { spec.add( "%preun" ); spec.add( "%include " + includePreun.map( getAbsolutePath ).some() ); } if ( includePostun.isSome() ) { spec.add( "%postun" ); spec.add( "%include " + includePostun.map( getAbsolutePath ).some() ); } spec.addIf( dump, "%dump" ); } // ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- private static <A extends UnixFsObject> F<PackageFileSystemObject<Object>, String> showUnixFsObject() { return new F<PackageFileSystemObject<Object>, String>() { public String f( PackageFileSystemObject p2 ) { @SuppressWarnings({"unchecked"}) UnixFsObject<A> unixFsObject = p2.getUnixFsObject(); Option<FileAttributes> attributes = unixFsObject.attributes; String s = ""; s += unixFsObject.attributes.map( tagsF ).bind( formatTags ).orSome( "" ); s += "%attr(" + attributes.bind( FileAttributes.modeF ).map( UnixFileMode.showOcalString ).orSome( "-" ) + "," + attributes.bind( FileAttributes.userF ).orSome( "-" ) + "," + attributes.bind( FileAttributes.groupF ).orSome( "-" ) + ") "; s += unixFsObject.path.asAbsolutePath( "/" ); if ( unixFsObject instanceof UnixFsObject.RegularFile || unixFsObject instanceof UnixFsObject.Symlink ) { return s; } else if ( unixFsObject instanceof UnixFsObject.Directory ) { return "%dir " + s; } throw error( "Unknown type UnixFsObject type: " + unixFsObject ); } }; } private static final F<PackageFileSystemObject<Object>, Boolean> excludePaths = new F<PackageFileSystemObject<Object>, Boolean>() { public Boolean f( PackageFileSystemObject object ) { return !object.getUnixFsObject().path.isBase(); } }; private static final F<List<String>, Option<String>> formatTags = new F<List<String>, Option<String>>() { public Option<String> f( List<String> tags ) { if ( tags.find( curry( equals, "config" ) ).isSome() ) { return some( "%config " ); } if ( tags.find( curry( equals, "rpm:noreplace" ) ).isSome() ) { return some( "%config(noreplace) " ); } if ( tags.find( curry( equals, "rpm:missingok" ) ).isSome() ) { return some( "%config(missingok) " ); } if ( tags.find( curry( equals, "doc" ) ).isSome() ) { return some( "%doc " ); } if ( tags.find( curry( equals, "rpm:ghost" ) ).isSome() ) { return some( "%ghost " ); } return none(); } }; }