001 /* 002 * Jpkg - Java library and tools for operating system package creation. 003 * 004 * Copyright (c) 2007 Three Rings Design, Inc. 005 * All rights reserved. 006 * 007 * Redistribution and use in source and binary forms, with or without 008 * modification, are permitted provided that the following conditions 009 * are met: 010 * 1. Redistributions of source code must retain the above copyright 011 * notice, this list of conditions and the following disclaimer. 012 * 2. Redistributions in binary form must reproduce the above copyright 013 * notice, this list of conditions and the following disclaimer in the 014 * documentation and/or other materials provided with the distribution. 015 * 3. Neither the name of the copyright owner nor the names of contributors 016 * may be used to endorse or promote products derived from this software 017 * without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 020 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 021 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 022 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 023 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 024 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 025 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 026 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 027 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 028 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 029 * POSSIBILITY OF SUCH DAMAGE. 030 */ 031 package com.threerings.jpkg.ant.dpkg; 032 033 import java.io.File; 034 import java.io.IOException; 035 import java.util.ArrayList; 036 import java.util.List; 037 import java.util.Map.Entry; 038 039 import org.apache.commons.io.IOUtils; 040 import org.apache.tools.ant.BuildException; 041 import org.apache.tools.ant.Project; 042 043 import com.threerings.antidote.field.BaseField; 044 import com.threerings.antidote.field.OptionalField; 045 import com.threerings.antidote.field.RequiredField; 046 import com.threerings.antidote.property.FileProperty; 047 import com.threerings.antidote.property.StringProperty; 048 import com.threerings.jpkg.PathPermissions; 049 import com.threerings.jpkg.PermissionsMap; 050 import com.threerings.jpkg.ant.dpkg.dependencies.BaseDependency; 051 import com.threerings.jpkg.ant.dpkg.dependencies.Dependencies; 052 import com.threerings.jpkg.ant.dpkg.dependencies.PackageInfoDependency; 053 import com.threerings.jpkg.ant.dpkg.info.Info; 054 import com.threerings.jpkg.ant.dpkg.permissions.Permissions; 055 import com.threerings.jpkg.ant.dpkg.scripts.Scripts; 056 import com.threerings.jpkg.ant.dpkg.scripts.runner.PackageScript; 057 import com.threerings.jpkg.ant.dpkg.scripts.runner.ScriptRunner; 058 import com.threerings.jpkg.ant.dpkg.scripts.runner.UnexpectedScriptTypeException; 059 import com.threerings.jpkg.debian.PackageInfo; 060 import com.threerings.jpkg.debian.MaintainerScript.Type; 061 062 import static com.threerings.antidote.MutabilityHelper.requiresValidation; 063 064 /** 065 * The <dpkg> task <package> field. Holds all information needed to generate a given package. 066 */ 067 public class Package extends BaseField 068 { 069 // from Field 070 public String getFieldName () 071 { 072 return "package"; 073 } 074 075 /** 076 * Ant adder field: Set the package meta information. 077 */ 078 public void addInfo (Info info) 079 { 080 _info.setField(info); 081 } 082 083 /** 084 * Ant adder field: Set the list of maintainer scripts. 085 */ 086 public void addScripts (Scripts scripts) 087 { 088 _scripts.setField(scripts); 089 } 090 091 /** 092 * Ant adder field: Set the list of path permissions. 093 */ 094 public void addPermissions (Permissions permissions) 095 { 096 _permissions.setField(permissions); 097 } 098 099 /** 100 * Ant adder field: Set the list of package dependencies. 101 */ 102 public void addDependencies (Dependencies dependencies) 103 { 104 _dependencies.setField(dependencies); 105 } 106 107 /** 108 * Ant setter field: destroot. The directory where the root of the package starts. 109 */ 110 public void setDestroot (String value) 111 { 112 _destroot.setValue(value); 113 } 114 115 /** 116 * Ant setter field: filename. Optionally set the filename of the package output. 117 */ 118 public void setFilename (String value) 119 { 120 _filenameProp.setValue(value); 121 } 122 123 /** 124 * Returns the user data converted into a {@link PackageInfo} object. Cannot be called before validate(). 125 */ 126 public PackageInfo createPackageInfo (String distribution, String prefix) 127 { 128 final Info info = _info.getField(); 129 final DpkgData data = new DpkgData(info.getPackageNameAsString(), info.getVersionAsString(), 130 distribution, prefix); 131 final PackageInfo packageInfo = info.getPackageInfo(); 132 133 if (_scripts.isSet()) { 134 appendPackageScripts(_scripts.getField().getPackageScripts(), packageInfo, data); 135 } 136 137 if (_permissions.isSet()) { 138 appendPermissionsMap(_permissions.getField().getPermissionsMap(prefix), packageInfo); 139 } 140 141 if (_dependencies.isSet()) { 142 appendDependencies(_dependencies.getField().getDependencies(), packageInfo); 143 } 144 145 // log the fully populated package info data to the verbose log. 146 log(packageInfo.toString(), Project.MSG_VERBOSE); 147 148 return packageInfo; 149 } 150 151 /** 152 * Returns the destroot to use for this package. Cannot be called before validate(). 153 */ 154 public File getDestroot () 155 { 156 return _destroot.getValue(); 157 } 158 159 /** 160 * Returns the filename to use for this package. Cannot be called before validate(). 161 */ 162 public String getFilename () 163 { 164 requiresValidation(_filename); 165 return _filename; 166 } 167 168 @Override // from BaseComponent 169 protected void validateField () 170 { 171 // validate the fields 172 switch (validateChildFields(_info, _scripts, _permissions, _dependencies)) { 173 case ALL_INVALID: 174 case SOME_INVALID: 175 return; 176 177 case ALL_VALID: 178 break; 179 } 180 181 // validate the required properties 182 switch (validateProperties(_destroot)) { 183 case ALL_INVALID: 184 case SOME_INVALID: 185 return; 186 187 case ALL_VALID: 188 break; 189 } 190 191 // validate the optional properties 192 switch (validateOptionalProperties(_filenameProp)) { 193 case ALL_INVALID: 194 case SOME_INVALID: 195 return; 196 197 case ALL_VALID: 198 break; 199 } 200 201 _filename = generateFilename(_info.getField()); 202 } 203 204 /** 205 * Add any defined PackageScripts to ScriptRunners and add them to the PackageInfo. 206 */ 207 private void appendPackageScripts (List<PackageScript> scripts, PackageInfo packageInfo, DpkgData data) 208 { 209 // write all the script source out to the debug log 210 printScriptsDebugging(scripts, data); 211 212 // for each script type, encode all scripts of that type into a ScriptRunner 213 // and add that runner to the PackageInfo object. 214 for (final Type scriptType : Type.values()) { 215 final List<PackageScript> foundScripts = new ArrayList<PackageScript>(); 216 for (final PackageScript script : scripts) { 217 if (script.getTypes().contains(scriptType)) { 218 foundScripts.add(script); 219 } 220 } 221 222 if (foundScripts.size() > 0) { 223 try { 224 final ScriptRunner runner = new ScriptRunner(scriptType, foundScripts, data); 225 packageInfo.setMaintainerScript(runner); 226 227 // write the runner source out to the debug log 228 printRunnerDebugging(runner); 229 230 } catch (final IOException e) { 231 throw new BuildException(e); 232 233 } catch (final UnexpectedScriptTypeException uste) { 234 throw new BuildException(uste); 235 } 236 } 237 } 238 } 239 240 /** 241 * Add the PermissionsMap to the PackageInfo. 242 */ 243 private void appendPermissionsMap (PermissionsMap permissionsMap, PackageInfo packageInfo) 244 { 245 // write the permissions map to the debug log 246 log("Defined path permissions:\n", Project.MSG_VERBOSE); 247 log(permissionsMap.toString(), Project.MSG_VERBOSE); 248 249 for (final Entry<String, PathPermissions> entry : permissionsMap.getPermissions()) { 250 packageInfo.addPathPermissions(entry.getKey(), entry.getValue()); 251 252 } 253 } 254 255 /** 256 * Add a list of {@link BaseDependency} objects to the {@link PackageInfo} object. 257 */ 258 private void appendDependencies (List<PackageInfoDependency> dependencies, PackageInfo packageInfo) 259 { 260 for (final PackageInfoDependency dependency : dependencies) { 261 dependency.addToPackageInfo(packageInfo); 262 } 263 } 264 265 /** 266 * Print a list of PackageScripts to the debug log. 267 */ 268 private void printScriptsDebugging (List<PackageScript> scripts, DpkgData data) 269 { 270 for (final PackageScript script : scripts) { 271 try { 272 log("Defined PackageScript: name=[" + script.getFriendlyName() + "] " + 273 "type=[" + script.getTypes() + "], source=[" + 274 IOUtils.toString(script.getSource(data)) + "].", Project.MSG_VERBOSE); 275 276 } catch (final Exception e) { 277 throw new BuildException(e); 278 } 279 } 280 } 281 282 /** 283 * Print the ScriptRunner to the debug log. 284 */ 285 private void printRunnerDebugging (ScriptRunner runner) 286 throws IOException 287 { 288 log("Defined Script Runner for type " + runner.getType() + " :", Project.MSG_VERBOSE); 289 log(IOUtils.toString(runner.getStream()), Project.MSG_VERBOSE); 290 } 291 292 /** 293 * Set the filename for this package field. Use the user supplied string if set, otherwise use 294 * a default. 295 */ 296 private String generateFilename (Info info) 297 { 298 String filename; 299 if (_filenameProp.isSet()) { 300 filename = _filenameProp.getValue(); 301 302 } else { 303 filename = info.getPackageNameAsString() + "_" + info.getVersionAsString() + EXTENSION; 304 } 305 return filename; 306 } 307 308 /** The default file extension for the package output file. */ 309 private static final String EXTENSION = ".dpkg"; 310 311 /** The filename, either from the user property or a default. */ 312 private String _filename; 313 314 /** Ant adder/setter fields. */ 315 private final RequiredField<Info> _info = new RequiredField<Info>(Info.class, this); 316 private final OptionalField<Scripts> _scripts = new OptionalField<Scripts>(Scripts.class, this); 317 private final OptionalField<Permissions> _permissions = new OptionalField<Permissions>(Permissions.class, this); 318 private final OptionalField<Dependencies> _dependencies = new OptionalField<Dependencies>(Dependencies.class, this); 319 private final FileProperty _destroot = new FileProperty("destroot", this); 320 private final StringProperty _filenameProp = new StringProperty("filename", this); 321 }