package org.codehaus.mojo.unix.deb; /* * 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.Function; import static fj.Function.*; import fj.data.*; import static fj.data.List.*; import static fj.data.List.join; import static fj.data.Option.*; import static fj.pre.Ord.*; import org.codehaus.mojo.unix.java.*; import static org.codehaus.mojo.unix.java.StringF.*; /** * @author <a href="mailto:trygvis@codehaus.org">Trygve Laugstøl</a> * @version $Id$ */ public class ControlFile { /** * Refers to the <code>Package</code> field, but "package" is a reserved keyword in Java. */ public final String packageName; public final Option<String> version; public final Option<String> description; public final Option<String> maintainer; public final Option<String> architecture; public final Option<String> priority; public final Option<String> section; public final List<String> depends; public final List<String> recommends; public final List<String> suggests; public final List<String> preDepends; public final List<String> provides; public final List<String> replaces; public final List<String> conflicts; public final TreeMap<String, String> extraFields; public ControlFile( String packageName ) { this( packageName, Option.<String>none(), Option.<String>none(), Option.<String>none(), Option.<String>none(), Option.<String>none(), Option.<String>none(), List.<String>nil(), List.<String>nil(), List.<String>nil(), List.<String>nil(), List.<String>nil(), List.<String>nil(), List.<String>nil(), TreeMap.<String, String>empty( stringOrd ) ); } public ControlFile( String packageName, Option<String> version, Option<String> description, Option<String> maintainer, Option<String> architecture, Option<String> priority, Option<String> section, List<String> depends, List<String> recommends, List<String> suggests, List<String> preDepends, List<String> provides, List<String> replaces, List<String> conflicts, TreeMap<String, String> extraFields ) { this.packageName = packageName; this.version = version; this.description = description; this.maintainer = maintainer; this.architecture = architecture; this.priority = priority; this.section = section; this.depends = depends; this.recommends = recommends; this.suggests = suggests; this.preDepends = preDepends; this.provides = provides; this.replaces = replaces; this.conflicts = conflicts; this.extraFields = extraFields; } public ControlFile version( Option<String> version ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile description( Option<String> description ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile maintainer( Option<String> maintainer ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile architecture( Option<String> architecture ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile priority( Option<String> priority ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile section( Option<String> section ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile depends( List<String> depends ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile recommends( List<String> recommends ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile suggests( List<String> suggests ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile preDepends( List<String> preDepends ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile provides( List<String> provides ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile replaces( List<String> replaces ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile conflicts( List<String> conflicts ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public ControlFile extraFields( TreeMap<String, String> extraFields ) { return new ControlFile( packageName, version, description, maintainer, architecture, priority, section, depends, recommends, suggests, preDepends, provides, replaces, conflicts, extraFields ); } public List<String> toList() { List<Option<String>> optionList = single( some( "Package: " + packageName ) ). cons( section.map( curry( concat, "Section: " ) ) ). cons( priority.map( curry( concat, "Priority: " ) ) ). cons( maintainer.map( curry( concat, "Maintainer: " ) ) ). cons( version.map( curry( concat, "Version: " ) ) ). cons( architecture.map( curry( concat, "Architecture: " ) ) ). cons( description.map( curry( concat, "Description: " ) ) ); F<List<String>, Boolean> isNotEmpty = isNotEmpty_(); List<Option<List<String>>> lists = List.<Option<List<String>>>nil(). cons( iif( isNotEmpty, this.depends ).map( transformList.f( "Depends" ) ) ). cons( iif( isNotEmpty, this.recommends ).map( transformList.f( "Recommends: " ) ) ). cons( iif( isNotEmpty, this.suggests ).map( transformList.f( "Suggests: " ) ) ). cons( iif( isNotEmpty, this.preDepends ).map( transformList.f( "Pre-Depends: " ) ) ). cons( iif( isNotEmpty, this.provides ).map( transformList.f( "Provides: " ) ) ). cons( iif( isNotEmpty, this.replaces ).map( transformList.f( "Replaces: " ) ) ). cons( iif( isNotEmpty, this.conflicts ).map( transformList.f( "Conflicts: " ) ) ); return somes( optionList ).reverse().append( join( somes( lists ) ) ); } F2<String, String, String> folder = new F2<String, String, String>() { public String f( String a, String b ) { return a + ", " + b; } }; F<String, F<List<String>, List<String>>> transformList = new F<String, F<List<String>, List<String>>>() { F<List<String>, String> foldLeft = List.<String, String>foldLeft().f( curry( folder ) ).f( "" ); public F<List<String>, List<String>> f( final String fieldName ) { return new F<List<String>, List<String>>() { public List<String> f( List<String> stringList ) { String head = fieldName + stringList.head(); return single( head ).append( stringList.tail() ); } }; } }; // public final F<String, List<String>> formatField = new F<String, List<String>>() // { // public List<String> f( String value ) // { // return formatField( value ); // } // }; // // public List<String> formatField( String value ) // { // System.out.println( "value = " + value ); // System.out.println( "value.length() = " + value.length() ); // // return List.unfold( new F<P2<String, Boolean>, Option<P2<String, P2<String, Boolean>>>>() // { // public Option<P2<String, P2<String, Boolean>>> f( P2<String, Boolean> state ) // { // String value = state._1(); // // if ( value.length() == 0 ) // { // return none(); // } // // int cut = value.indexOf( System.getProperty( "line.separator" ) ); // // // If a EOL is found before 77 chars, return it // if ( cut < 77 ) // { // return some( p( value.substring( 0, cut ), p( value.substring( cut ), false ) ) ); // } // // cut = value.lastIndexOf( ' ', cut ); // // String v = state._2() ? "" : " " + value.substring( 0, cut - 1 ).trim(); // // return some( p( v, p( value.substring( cut ), false ) ) ); // } // }, P.<String, Boolean>p( value, true ) ); // } // public static final F<String, List<String>> toList = new F<String, List<String>>() // { // public List<String> f( String value ) // { // return List.list( value.split( "," ) ); // } // }; public static final F<String, List<String>> toList = compose( List.<String, String>map_().f( StringF.trim ), Function.flip( StringF.split ).f( "," ) ); // public void streamTo( LineStreamWriter control ) // { // F2<String, String, String> folder = new F2<String, String, String>() // { // public String f( String a, String b ) // { // return a + ", " + b; // } // }; // // control. // add( "Section: " + UnixUtil.getField( "section", section ) ). // add( "Priority: " + priority.orSome( "standard" ) ). // add( "Maintainer: " + UnixUtil.getField( "maintainer", maintainer ) ). // add( "Package: " + packageName ). // add( "Version: " + version ). // add( "Architecture: " + UnixUtil.getField( "architecture", architecture ) ). // addIf( depends.isNotEmpty(), "Depends: " + depends.foldRight( folder, "" ) ). // addIf( recommends.isNotEmpty(), "Recommends: " + recommends.foldRight( folder, "" ) ). // addIf( suggests.isNotEmpty(), "Suggests: " + suggests.foldRight( folder, "" ) ). // addIf( preDepends.isNotEmpty(), "Pre-Depends: " + preDepends.foldRight( folder, "" ) ). // addIf( provides.isNotEmpty(), "Provides: " + provides.foldRight( folder, "" ) ). // addIf( replaces.isNotEmpty(), "Replaces: " + replaces.foldRight( folder, "" ) ). // add( "Description: " + description ); // } public static ControlFile controlFileFromList( List<P2<String, String>> values ) { TreeMap<String, String> map = values.foldLeft( new F2<TreeMap<String, String>, P2<String, String>, TreeMap<String, String>>() { public TreeMap<String, String> f( TreeMap<String, String> map, P2<String, String> p ) { return map.set( p._1(), p._2() ); } }, TreeMap.<String, String>empty( stringOrd ) ); Option<String> packageName = map.get( "Package" ); if ( packageName.isNone() ) { throw Bottom.error( "Could not find required field 'Package'." ); } ControlFile controlFile = new ControlFile( packageName.some() ); controlFile = controlFile.version( map.get( "Version" ) ); map = map.delete( "Version" ); controlFile = controlFile.description( map.get( "Description" ) ); map = map.delete( "Description" ); controlFile = controlFile.maintainer( map.get( "Maintainer" ) ); map = map.delete( "Maintainer" ); controlFile = controlFile.architecture( map.get( "Architecture" ) ); map = map.delete( "Architecture" ); controlFile = controlFile.priority( map.get( "Priority" ) ); map = map.delete( "Priority" ); controlFile = controlFile.section( map.get( "Section" ) ); map = map.delete( "Section" ); List<String> emptyList = List.nil(); controlFile = controlFile.depends( map.get( "Depends" ).map( toList ).orSome( emptyList ) ); map = map.delete( "Depends" ); controlFile = controlFile.recommends( map.get( "Recommends" ).map( toList ).orSome( emptyList ) ); map = map.delete( "Recommends" ); controlFile = controlFile.suggests( map.get( "Suggests" ).map( toList ).orSome( emptyList ) ); map = map.delete( "Suggests" ); controlFile = controlFile.preDepends( map.get( "PreDepends" ).map( toList ).orSome( emptyList ) ); map = map.delete( "PreDepends" ); controlFile = controlFile.provides( map.get( "Provides" ).map( toList ).orSome( emptyList ) ); map = map.delete( "Provides" ); controlFile = controlFile.replaces( map.get( "replaces" ).map( toList ).orSome( emptyList ) ); map = map.delete( "Replaces" ); controlFile = controlFile.conflicts( map.get( "conflicts" ).map( toList ).orSome( emptyList ) ); map = map.delete( "Conflicts" ); controlFile.extraFields( map ); return controlFile; } }