15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.tools.packager.bundlers; 27 28 import com.oracle.bundlers.AbstractBundler; 29 import com.oracle.bundlers.BundlerParamInfo; 30 import com.oracle.bundlers.StandardBundlerParam; 31 import com.sun.javafx.tools.packager.Log; 32 import com.sun.javafx.tools.resource.linux.LinuxResources; 33 34 import java.io.*; 35 import java.text.MessageFormat; 36 import java.util.*; 37 import java.util.regex.Matcher; 38 import java.util.regex.Pattern; 39 40 import static com.oracle.bundlers.StandardBundlerParam.*; 41 42 public class LinuxRPMBundler extends AbstractBundler { 43 44 private static final ResourceBundle I18N = 45 ResourceBundle.getBundle("com.oracle.bundlers.linux.LinuxRpmBundler"); 46 47 public static final BundlerParamInfo<LinuxAppBundler> APP_BUNDLER = new StandardBundlerParam<>( 48 I18N.getString("param.app-bundler.name"), 49 I18N.getString("param.app-bundler.description"), 50 "linuxAppBundler", //KEY 51 LinuxAppBundler.class, null, params -> new LinuxAppBundler(), false, null); 52 53 public static final BundlerParamInfo<File> IMAGE_DIR = new StandardBundlerParam<>( 54 I18N.getString("param.image-dir.name"), 55 I18N.getString("param.image-dir.description"), 56 "imageDir", //KEY 57 File.class, null, params -> { 58 File imagesRoot = IMAGES_ROOT.fetchFrom(params); 59 return new File(imagesRoot, "linux-rpm.image"); 60 }, false, File::new); 61 62 public static final BundlerParamInfo<File> CONFIG_ROOT = new StandardBundlerParam<>( 63 I18N.getString("param.config-root.name"), 64 I18N.getString("param.config-root.description"), 65 "configRoot", //KEY 66 File.class, null, params -> new File(BUILD_ROOT.fetchFrom(params), "linux"), 67 false, File::new); 68 69 public static final BundlerParamInfo<String> BUNDLE_NAME = new StandardBundlerParam<> ( 70 I18N.getString("param.bundle-name.name"), 71 I18N.getString("param.bundle-name.description"), 72 "bundleName", //KEY 73 String.class, null, params -> { 74 String nm = APP_NAME.fetchFrom(params); 75 if (nm == null) return null; 76 77 //spaces are not allowed in RPM package names 78 nm = nm.replaceAll(" ", ""); 79 return nm; 80 }, false, s -> s); 81 82 private final static String DEFAULT_ICON = "javalogo_white_32.png"; 83 private final static String DEFAULT_SPEC_TEMPLATE = "template.spec"; 84 private final static String DEFAULT_DESKTOP_FILE_TEMPLATE = "template.desktop"; 85 86 public final static String TOOL_RPMBUILD = "rpmbuild"; 87 public final static double TOOL_RPMBUILD_MIN_VERSION = 4.0d; 88 89 public LinuxRPMBundler() { 90 super(); 91 baseResourceLoader = LinuxResources.class; 92 } 93 94 public static boolean testTool(String toolName, double minVersion) { 95 try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos)) { 96 ProcessBuilder pb = new ProcessBuilder( 97 toolName, 98 "--version"); 99 100 IOUtils.exec(pb, Log.isDebug(), false, ps); //not interested in the output 101 102 //TODO: Version is ignored; need to extract version string and compare! 103 String content = new String(baos.toByteArray()); 104 Pattern pattern = Pattern.compile("RPM version (\\d+\\.\\d+)"); 105 Matcher matcher = pattern.matcher(content); 106 if (matcher.find()) { 107 String v = matcher.group(1); 108 double version = new Double(v); 109 return minVersion <= version; 110 } else { 111 return false; 112 } 113 } catch (Exception e) { 114 Log.verbose(MessageFormat.format(I18N.getString("message.test-for-tool"), toolName, e.getMessage())); 115 return false; 116 } 117 } 118 119 @Override 120 public boolean validate(Map<String, ? super Object> p) throws UnsupportedPlatformException, ConfigException { 121 if (p == null) throw new ConfigException( 122 I18N.getString("error.parameters-null"), 123 I18N.getString("error.parameters-null.advice")); 124 125 //run basic validation to ensure requirements are met 126 //we are not interested in return code, only possible exception 127 APP_BUNDLER.fetchFrom(p).doValidate(p); 128 129 //TODO: validate presense of required tools? 130 if (!testTool(TOOL_RPMBUILD, TOOL_RPMBUILD_MIN_VERSION)){ 131 throw new ConfigException( 132 I18N.getString(MessageFormat.format("error.cannot-find-rpmbuild", TOOL_RPMBUILD_MIN_VERSION)), 133 I18N.getString(MessageFormat.format("error.cannot-find-rpmbuild.advice", TOOL_RPMBUILD_MIN_VERSION))); 134 } 135 136 return true; 137 } 138 139 private boolean prepareProto(Map<String, ? super Object> params) { 140 File imageDir = IMAGE_DIR.fetchFrom(params); 141 File appDir = APP_BUNDLER.fetchFrom(params).doBundle(params, imageDir, true); 142 return appDir != null; 143 } 144 145 public File bundle(Map<String, ? super Object> p, File outdir) { 146 File imageDir = IMAGE_DIR.fetchFrom(p); 147 try { 148 149 imageDir.mkdirs(); 150 151 boolean menuShortcut = MENU_HINT.fetchFrom(p); 152 boolean desktopShortcut = SHORTCUT_HINT.fetchFrom(p); 153 if (!menuShortcut && !desktopShortcut) { 154 //both can not be false - user will not find the app 155 Log.verbose(I18N.getString("message.one-shortcut-required")); 156 p.put(MENU_HINT.getID(), true); 157 } 158 159 if (prepareProto(p) && prepareProjectConfig(p)) { 160 return buildRPM(p, outdir); 161 } 162 return null; 163 } catch (IOException ex) { 164 ex.printStackTrace(); 165 return null; 166 } finally { 167 try { 168 if (verbose) { 169 saveConfigFiles(p); 170 } 171 if (imageDir != null && !Log.isDebug()) { 172 IOUtils.deleteRecursive(imageDir); 173 } else if (imageDir != null) { 174 Log.info(MessageFormat.format(I18N.getString("message.debug-working-directory"), imageDir.getAbsolutePath())); 175 } 176 } catch (FileNotFoundException ex) { 177 //noinspection ReturnInsideFinallyBlock 178 return null; 179 } 180 } 181 } 182 183 protected void saveConfigFiles(Map<String, ? super Object> params) { 184 try { 185 File configRoot = CONFIG_ROOT.fetchFrom(params); 186 if (getConfig_SpecFile(params).exists()) { 187 IOUtils.copyFile(getConfig_SpecFile(params), 188 new File(configRoot, getConfig_SpecFile(params).getName())); 189 } 190 if (getConfig_DesktopShortcutFile(params).exists()) { 191 IOUtils.copyFile(getConfig_DesktopShortcutFile(params), 192 new File(configRoot, getConfig_DesktopShortcutFile(params).getName())); 193 } 194 if (getConfig_IconFile(params).exists()) { 195 IOUtils.copyFile(getConfig_IconFile(params), 196 new File(configRoot, getConfig_IconFile(params).getName())); 197 } 198 Log.info(MessageFormat.format(I18N.getString("message.config-save-location"), configRoot.getAbsolutePath())); 199 } catch (IOException ioe) { 200 ioe.printStackTrace(); 201 } 202 } 203 204 @Override 205 public String toString() { 206 return getName(); 207 } 208 209 private String getLicenseFileString(Map<String, ? super Object> params) { 210 StringBuilder sb = new StringBuilder(); 211 for (String f: LICENSE_FILES.fetchFrom(params)) { 212 if (sb.length() != 0) { 213 sb.append("\n"); 214 } 215 sb.append("%doc /opt/"); 216 sb.append(BUNDLE_NAME.fetchFrom(params)); 217 sb.append("/app/"); 218 sb.append(f); 219 } 220 return sb.toString(); 221 } 222 223 private boolean prepareProjectConfig(Map<String, ? super Object> params) throws IOException { 224 Map<String, String> data = new HashMap<>(); 225 226 data.put("APPLICATION_NAME", BUNDLE_NAME.fetchFrom(params)); 227 data.put("APPLICATION_VENDOR", VENDOR.fetchFrom(params)); 228 data.put("APPLICATION_VERSION", VERSION.fetchFrom(params)); 229 data.put("APPLICATION_LAUNCHER_FILENAME", 230 LinuxAppBundler.getLauncher(IMAGE_DIR.fetchFrom(params), params).getName()); 231 data.put("APPLICATION_DESKTOP_SHORTCUT", SHORTCUT_HINT.fetchFrom(params) ? "returnTrue" : "returnFalse"); 232 data.put("APPLICATION_MENU_SHORTCUT", MENU_HINT.fetchFrom(params) ? "returnTrue" : "returnFalse"); 233 data.put("DEPLOY_BUNDLE_CATEGORY", CATEGORY.fetchFrom(params)); //TODO rpm categories 234 data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params)); 235 data.put("APPLICATION_SUMMARY", TITLE.fetchFrom(params)); 236 data.put("APPLICATION_LICENSE_TYPE", LICENSE_TYPE.fetchFrom(params)); 237 data.put("APPLICATION_LICENSE_FILE", getLicenseFileString(params)); 238 239 //prepare spec file 240 Writer w = new BufferedWriter(new FileWriter(getConfig_SpecFile(params))); 241 String content = preprocessTextResource( 242 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_SpecFile(params).getName(), 243 I18N.getString("resource.rpm-spec-file"), DEFAULT_SPEC_TEMPLATE, data); 244 w.write(content); 245 w.close(); 246 247 //prepare desktop shortcut 248 w = new BufferedWriter(new FileWriter(getConfig_DesktopShortcutFile(params))); 249 content = preprocessTextResource( 250 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_DesktopShortcutFile(params).getName(), 251 I18N.getString("resource.menu-shortcut-descriptor"), DEFAULT_DESKTOP_FILE_TEMPLATE, data); 252 w.write(content); 253 w.close(); 254 255 //prepare installer icon 256 File iconTarget = getConfig_IconFile(params); 257 File icon = ICON.fetchFrom(params); 258 if (icon == null || !icon.exists()) { 259 fetchResource(LinuxAppBundler.LINUX_BUNDLER_PREFIX + iconTarget.getName(), 260 I18N.getString("resource.menu-icon"), 261 DEFAULT_ICON, 262 iconTarget); 263 } else { 264 fetchResource(LinuxAppBundler.LINUX_BUNDLER_PREFIX + iconTarget.getName(), 265 I18N.getString("resource.menu-icon"), 266 icon, 267 iconTarget); 268 } 269 270 return true; 271 } 272 273 private File getConfig_DesktopShortcutFile(Map<String, ? super Object> params) { 274 return new File(LinuxAppBundler.getLauncher(IMAGE_DIR.fetchFrom(params), params).getParentFile(), 275 BUNDLE_NAME.fetchFrom(params) + ".desktop"); 276 } 277 278 private File getConfig_IconFile(Map<String, ? super Object> params) { 279 return new File(LinuxAppBundler.getLauncher(IMAGE_DIR.fetchFrom(params), params).getParentFile(), 280 BUNDLE_NAME.fetchFrom(params) + ".png"); 281 } 282 283 private File getConfig_SpecFile(Map<String, ? super Object> params) { 284 return new File(IMAGE_DIR.fetchFrom(params), 285 BUNDLE_NAME.fetchFrom(params) + ".spec"); 286 } 287 288 private File buildRPM(Map<String, ? super Object> params, File outdir) throws IOException { 289 Log.verbose(MessageFormat.format(I18N.getString("message.outputting-bundle-location"), outdir.getAbsolutePath())); 290 291 File broot = new File(BUILD_ROOT.fetchFrom(params), "rmpbuildroot"); 292 293 outdir.mkdirs(); 294 295 //run rpmbuild 296 ProcessBuilder pb = new ProcessBuilder( 297 TOOL_RPMBUILD, 298 "-bb", getConfig_SpecFile(params).getAbsolutePath(), 299 // "--define", "%__jar_repack %{nil}", //debug: improves build time (but will require unpack to install?) 300 "--define", "%_sourcedir "+IMAGE_DIR.fetchFrom(params).getAbsolutePath(), 301 "--define", "%_rpmdir " + outdir.getAbsolutePath(), //save result to output dir 302 "--define", "%_topdir " + broot.getAbsolutePath() //do not use other system directories to build as current user 303 ); 304 pb = pb.directory(IMAGE_DIR.fetchFrom(params)); 305 IOUtils.exec(pb, verbose); 306 307 IOUtils.deleteRecursive(broot); 308 309 Log.info(MessageFormat.format(I18N.getString("message.output-bundle-location"), outdir.getAbsolutePath())); 310 311 //todo look for added files and returnt hat added file. 312 return outdir; 313 } 314 315 @Override 316 public String getName() { 317 return I18N.getString("bundler.name"); 318 } 319 320 @Override 321 public String getDescription() { 322 return I18N.getString("bundler.description"); 323 } 324 325 @Override 326 public String getID() { 327 return "rpm"; //KEY 328 } 329 330 @Override 331 public BundleType getBundleType() { 332 return BundleType.INSTALLER; 333 } 334 335 @Override 336 public Collection<BundlerParamInfo<?>> getBundleParameters() { 337 Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>(); 338 results.addAll(LinuxAppBundler.getAppBundleParameters()); 339 results.addAll(getRpmBundleParameters()); 340 return results; 341 } 342 343 public static Collection<BundlerParamInfo<?>> getRpmBundleParameters() { 344 return Arrays.asList( 345 APP_BUNDLER, 346 APP_NAME, 347 BUILD_ROOT, 348 BUNDLE_NAME, 349 CONFIG_ROOT, 350 CATEGORY, 351 DESCRIPTION, 352 ICON, 353 IMAGE_DIR, 354 IMAGES_ROOT, 355 LICENSE_FILES, 356 LICENSE_TYPE, 357 MENU_HINT, 358 SHORTCUT_HINT, 359 TITLE, 360 VENDOR, 361 VERSION 362 ); 363 } 364 365 @Override 366 public File execute(Map<String, ? super Object> params, File outputParentDir) { 367 return bundle(params, outputParentDir); 368 } 369 } | 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.tools.packager.bundlers; 27 28 import com.oracle.bundlers.AbstractBundler; 29 import com.oracle.bundlers.BundlerParamInfo; 30 import com.oracle.bundlers.StandardBundlerParam; 31 import com.sun.javafx.tools.packager.Log; 32 import com.sun.javafx.tools.resource.linux.LinuxResources; 33 34 import java.io.*; 35 import java.nio.file.Files; 36 import java.nio.file.attribute.PosixFilePermission; 37 import java.nio.file.attribute.PosixFilePermissions; 38 import java.text.MessageFormat; 39 import java.util.*; 40 import java.util.logging.Level; 41 import java.util.logging.Logger; 42 import java.util.regex.Matcher; 43 import java.util.regex.Pattern; 44 45 import static com.oracle.bundlers.StandardBundlerParam.*; 46 47 public class LinuxRPMBundler extends AbstractBundler { 48 49 private static final ResourceBundle I18N = 50 ResourceBundle.getBundle("com.oracle.bundlers.linux.LinuxRpmBundler"); 51 52 public static final BundlerParamInfo<LinuxAppBundler> APP_BUNDLER = new StandardBundlerParam<>( 53 I18N.getString("param.app-bundler.name"), 54 I18N.getString("param.app-bundler.description"), 55 "linux.app.bundler", 56 LinuxAppBundler.class, null, params -> new LinuxAppBundler(), false, null); 57 58 public static final BundlerParamInfo<File> RPM_IMAGE_DIR = new StandardBundlerParam<>( 59 I18N.getString("param.image-dir.name"), 60 I18N.getString("param.image-dir.description"), 61 "linux.rpm.imageDir", 62 File.class, null, params -> { 63 File imagesRoot = IMAGES_ROOT.fetchFrom(params); 64 if (!imagesRoot.exists()) imagesRoot.mkdirs(); 65 return new File(imagesRoot, "linux-rpm.image"); 66 }, false, (s, p) -> new File(s)); 67 68 public static final BundlerParamInfo<File> CONFIG_ROOT = new StandardBundlerParam<>( 69 I18N.getString("param.config-root.name"), 70 I18N.getString("param.config-root.description"), 71 "configRoot", 72 File.class, null, params -> new File(BUILD_ROOT.fetchFrom(params), "linux"), 73 false, (s, p) -> new File(s)); 74 75 public static final BundlerParamInfo<String> BUNDLE_NAME = new StandardBundlerParam<> ( 76 I18N.getString("param.bundle-name.name"), 77 I18N.getString("param.bundle-name.description"), 78 "linux.bundleName", 79 String.class, null, params -> { 80 String nm = APP_NAME.fetchFrom(params); 81 if (nm == null) return null; 82 83 //spaces are not allowed in RPM package names 84 nm = nm.replaceAll(" ", ""); 85 return nm; 86 }, false, (s, p) -> s); 87 88 private final static String DEFAULT_ICON = "javalogo_white_32.png"; 89 private final static String DEFAULT_SPEC_TEMPLATE = "template.spec"; 90 private final static String DEFAULT_DESKTOP_FILE_TEMPLATE = "template.desktop"; 91 private final static String DEFAULT_INIT_SCRIPT_TEMPLATE = "template.rpm.init.script"; 92 93 public final static String TOOL_RPMBUILD = "rpmbuild"; 94 public final static double TOOL_RPMBUILD_MIN_VERSION = 4.0d; 95 96 public LinuxRPMBundler() { 97 super(); 98 baseResourceLoader = LinuxResources.class; 99 } 100 101 public static boolean testTool(String toolName, double minVersion) { 102 try (ByteArrayOutputStream baos = new ByteArrayOutputStream(); PrintStream ps = new PrintStream(baos)) { 103 ProcessBuilder pb = new ProcessBuilder( 104 toolName, 105 "--version"); 106 107 IOUtils.exec(pb, Log.isDebug(), false, ps); //not interested in the output 108 109 //TODO: Version is ignored; need to extract version string and compare! 110 String content = new String(baos.toByteArray()); 111 Pattern pattern = Pattern.compile("RPM version (\\d+\\.\\d+)"); 112 Matcher matcher = pattern.matcher(content); 113 if (matcher.find()) { 114 String v = matcher.group(1); 115 double version = new Double(v); 116 return minVersion <= version; 117 } else { 118 return false; 119 } 120 } catch (Exception e) { 121 Log.verbose(MessageFormat.format(I18N.getString("message.test-for-tool"), toolName, e.getMessage())); 122 return false; 123 } 124 } 125 126 @Override 127 public boolean validate(Map<String, ? super Object> p) throws UnsupportedPlatformException, ConfigException { 128 try { 129 if (p == null) throw new ConfigException( 130 I18N.getString("error.parameters-null"), 131 I18N.getString("error.parameters-null.advice")); 132 133 //run basic validation to ensure requirements are met 134 //we are not interested in return code, only possible exception 135 APP_BUNDLER.fetchFrom(p).doValidate(p); 136 137 //TODO: validate presense of required tools? 138 if (!testTool(TOOL_RPMBUILD, TOOL_RPMBUILD_MIN_VERSION)){ 139 throw new ConfigException( 140 I18N.getString(MessageFormat.format("error.cannot-find-rpmbuild", TOOL_RPMBUILD_MIN_VERSION)), 141 I18N.getString(MessageFormat.format("error.cannot-find-rpmbuild.advice", TOOL_RPMBUILD_MIN_VERSION))); 142 } 143 144 return true; 145 } catch (RuntimeException re) { 146 throw new ConfigException(re); 147 } 148 } 149 150 private boolean prepareProto(Map<String, ? super Object> params) { 151 File imageDir = RPM_IMAGE_DIR.fetchFrom(params); 152 File appDir = APP_BUNDLER.fetchFrom(params).doBundle(params, imageDir, true); 153 return appDir != null; 154 } 155 156 public File bundle(Map<String, ? super Object> p, File outdir) { 157 File imageDir = RPM_IMAGE_DIR.fetchFrom(p); 158 try { 159 160 imageDir.mkdirs(); 161 162 boolean menuShortcut = MENU_HINT.fetchFrom(p); 163 boolean desktopShortcut = SHORTCUT_HINT.fetchFrom(p); 164 if (!menuShortcut && !desktopShortcut) { 165 //both can not be false - user will not find the app 166 Log.verbose(I18N.getString("message.one-shortcut-required")); 167 p.put(MENU_HINT.getID(), true); 168 } 169 170 if (prepareProto(p) && prepareProjectConfig(p)) { 171 return buildRPM(p, outdir); 172 } 173 return null; 174 } catch (IOException ex) { 175 ex.printStackTrace(); 176 return null; 177 } finally { 178 try { 179 if (VERBOSE.fetchFrom(p)) { 180 saveConfigFiles(p); 181 } 182 if (imageDir != null && !Log.isDebug()) { 183 IOUtils.deleteRecursive(imageDir); 184 } else if (imageDir != null) { 185 Log.info(MessageFormat.format(I18N.getString("message.debug-working-directory"), imageDir.getAbsolutePath())); 186 } 187 } catch (FileNotFoundException ex) { 188 //noinspection ReturnInsideFinallyBlock 189 return null; 190 } 191 } 192 } 193 194 /* 195 * set permissions with a string like "rwxr-xr-x" 196 * 197 * This cannot be directly backport to 22u which is unfortunately built with 1.6 198 */ 199 private void setPermissions(File file, String permissions) { 200 Set<PosixFilePermission> filePermissions = PosixFilePermissions.fromString(permissions); 201 try { 202 if (file.exists()) { 203 Files.setPosixFilePermissions(file.toPath(), filePermissions); 204 } 205 } catch (IOException ex) { 206 Logger.getLogger(LinuxDebBundler.class.getName()).log(Level.SEVERE, null, ex); 207 } 208 } 209 210 protected void saveConfigFiles(Map<String, ? super Object> params) { 211 try { 212 File configRoot = CONFIG_ROOT.fetchFrom(params); 213 if (getConfig_SpecFile(params).exists()) { 214 IOUtils.copyFile(getConfig_SpecFile(params), 215 new File(configRoot, getConfig_SpecFile(params).getName())); 216 } 217 if (getConfig_DesktopShortcutFile(params).exists()) { 218 IOUtils.copyFile(getConfig_DesktopShortcutFile(params), 219 new File(configRoot, getConfig_DesktopShortcutFile(params).getName())); 220 } 221 if (getConfig_IconFile(params).exists()) { 222 IOUtils.copyFile(getConfig_IconFile(params), 223 new File(configRoot, getConfig_IconFile(params).getName())); 224 } 225 if (SERVICE_HINT.fetchFrom(params)) { 226 if (getConfig_InitScriptFile(params).exists()) { 227 IOUtils.copyFile(getConfig_InitScriptFile(params), 228 new File(configRoot, getConfig_InitScriptFile(params).getName())); 229 } 230 } 231 Log.info(MessageFormat.format(I18N.getString("message.config-save-location"), configRoot.getAbsolutePath())); 232 } catch (IOException ioe) { 233 ioe.printStackTrace(); 234 } 235 } 236 237 @Override 238 public String toString() { 239 return getName(); 240 } 241 242 private String getLicenseFileString(Map<String, ? super Object> params) { 243 StringBuilder sb = new StringBuilder(); 244 for (String f: LICENSE_FILES.fetchFrom(params)) { 245 if (sb.length() != 0) { 246 sb.append("\n"); 247 } 248 sb.append("%doc /opt/"); 249 sb.append(BUNDLE_NAME.fetchFrom(params)); 250 sb.append("/app/"); 251 sb.append(f); 252 } 253 return sb.toString(); 254 } 255 256 private boolean prepareProjectConfig(Map<String, ? super Object> params) throws IOException { 257 Map<String, String> data = new HashMap<>(); 258 259 data.put("APPLICATION_NAME", BUNDLE_NAME.fetchFrom(params)); 260 data.put("APPLICATION_PACKAGE", BUNDLE_NAME.fetchFrom(params).toLowerCase()); 261 data.put("APPLICATION_VENDOR", VENDOR.fetchFrom(params)); 262 data.put("APPLICATION_VERSION", VERSION.fetchFrom(params)); 263 data.put("APPLICATION_LAUNCHER_FILENAME", 264 LinuxAppBundler.getLauncher(RPM_IMAGE_DIR.fetchFrom(params), params).getName()); 265 data.put("APPLICATION_DESKTOP_SHORTCUT", SHORTCUT_HINT.fetchFrom(params) ? "returnTrue" : "returnFalse"); 266 data.put("APPLICATION_MENU_SHORTCUT", MENU_HINT.fetchFrom(params) ? "returnTrue" : "returnFalse"); 267 data.put("DEPLOY_BUNDLE_CATEGORY", CATEGORY.fetchFrom(params)); //TODO rpm categories 268 data.put("APPLICATION_DESCRIPTION", DESCRIPTION.fetchFrom(params)); 269 data.put("APPLICATION_SUMMARY", TITLE.fetchFrom(params)); 270 data.put("APPLICATION_LICENSE_TYPE", LICENSE_TYPE.fetchFrom(params)); 271 data.put("APPLICATION_LICENSE_FILE", getLicenseFileString(params)); 272 data.put("SERVICE_HINT", String.valueOf(SERVICE_HINT.fetchFrom(params))); 273 data.put("START_ON_INSTALL", String.valueOf(START_ON_INSTALL.fetchFrom(params))); 274 data.put("STOP_ON_UNINSTALL", String.valueOf(STOP_ON_UNINSTALL.fetchFrom(params))); 275 data.put("RUN_AT_STARTUP", String.valueOf(RUN_AT_STARTUP.fetchFrom(params))); 276 277 //prepare spec file 278 Writer w = new BufferedWriter(new FileWriter(getConfig_SpecFile(params))); 279 String content = preprocessTextResource( 280 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_SpecFile(params).getName(), 281 I18N.getString("resource.rpm-spec-file"), DEFAULT_SPEC_TEMPLATE, data, 282 VERBOSE.fetchFrom(params)); 283 w.write(content); 284 w.close(); 285 286 //prepare desktop shortcut 287 w = new BufferedWriter(new FileWriter(getConfig_DesktopShortcutFile(params))); 288 content = preprocessTextResource( 289 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_DesktopShortcutFile(params).getName(), 290 I18N.getString("resource.menu-shortcut-descriptor"), DEFAULT_DESKTOP_FILE_TEMPLATE, data, 291 VERBOSE.fetchFrom(params)); 292 w.write(content); 293 w.close(); 294 295 //prepare installer icon 296 File iconTarget = getConfig_IconFile(params); 297 File icon = ICON.fetchFrom(params); 298 if (icon == null || !icon.exists()) { 299 fetchResource(LinuxAppBundler.LINUX_BUNDLER_PREFIX + iconTarget.getName(), 300 I18N.getString("resource.menu-icon"), 301 DEFAULT_ICON, 302 iconTarget, 303 VERBOSE.fetchFrom(params)); 304 } else { 305 fetchResource(LinuxAppBundler.LINUX_BUNDLER_PREFIX + iconTarget.getName(), 306 I18N.getString("resource.menu-icon"), 307 icon, 308 iconTarget, 309 VERBOSE.fetchFrom(params)); 310 } 311 312 if (SERVICE_HINT.fetchFrom(params)) { 313 //prepare init script 314 w = new BufferedWriter(new FileWriter(getConfig_InitScriptFile(params))); 315 content = preprocessTextResource( 316 LinuxAppBundler.LINUX_BUNDLER_PREFIX + getConfig_InitScriptFile(params).getName(), 317 I18N.getString("resource.rpm-init-script"), 318 DEFAULT_INIT_SCRIPT_TEMPLATE, 319 data, 320 VERBOSE.fetchFrom(params)); 321 w.write(content); 322 w.close(); 323 setPermissions(getConfig_InitScriptFile(params), "rwxr-xr-x"); 324 } 325 326 return true; 327 } 328 329 private File getConfig_DesktopShortcutFile(Map<String, ? super Object> params) { 330 return new File(LinuxAppBundler.getLauncher(RPM_IMAGE_DIR.fetchFrom(params), params).getParentFile(), 331 BUNDLE_NAME.fetchFrom(params) + ".desktop"); 332 } 333 334 private File getConfig_IconFile(Map<String, ? super Object> params) { 335 return new File(LinuxAppBundler.getLauncher(RPM_IMAGE_DIR.fetchFrom(params), params).getParentFile(), 336 BUNDLE_NAME.fetchFrom(params) + ".png"); 337 } 338 339 private File getConfig_InitScriptFile(Map<String, ? super Object> params) { 340 return new File(LinuxAppBundler.getLauncher(RPM_IMAGE_DIR.fetchFrom(params), params).getParentFile(), 341 BUNDLE_NAME.fetchFrom(params) + ".init"); 342 } 343 344 private File getConfig_SpecFile(Map<String, ? super Object> params) { 345 return new File(RPM_IMAGE_DIR.fetchFrom(params), 346 BUNDLE_NAME.fetchFrom(params) + ".spec"); 347 } 348 349 private File buildRPM(Map<String, ? super Object> params, File outdir) throws IOException { 350 Log.verbose(MessageFormat.format(I18N.getString("message.outputting-bundle-location"), outdir.getAbsolutePath())); 351 352 File broot = new File(BUILD_ROOT.fetchFrom(params), "rmpbuildroot"); 353 354 outdir.mkdirs(); 355 356 //run rpmbuild 357 ProcessBuilder pb = new ProcessBuilder( 358 TOOL_RPMBUILD, 359 "-bb", getConfig_SpecFile(params).getAbsolutePath(), 360 // "--define", "%__jar_repack %{nil}", //debug: improves build time (but will require unpack to install?) 361 "--define", "%_sourcedir "+ RPM_IMAGE_DIR.fetchFrom(params).getAbsolutePath(), 362 "--define", "%_rpmdir " + outdir.getAbsolutePath(), //save result to output dir 363 "--define", "%_topdir " + broot.getAbsolutePath() //do not use other system directories to build as current user 364 ); 365 pb = pb.directory(RPM_IMAGE_DIR.fetchFrom(params)); 366 IOUtils.exec(pb, VERBOSE.fetchFrom(params)); 367 368 IOUtils.deleteRecursive(broot); 369 370 Log.info(MessageFormat.format(I18N.getString("message.output-bundle-location"), outdir.getAbsolutePath())); 371 372 // presume the result is the ".rpm" file with the newest modified time 373 // not the best solution, but it is the most reliable 374 File result = null; 375 long lastModified = 0; 376 File[] list = outdir.listFiles(); 377 if (list != null) { 378 for (File f : list) { 379 if (f.getName().endsWith(".rpm") && f.lastModified() > lastModified) { 380 result = f; 381 lastModified = f.lastModified(); 382 } 383 } 384 } 385 386 return result; 387 } 388 389 @Override 390 public String getName() { 391 return I18N.getString("bundler.name"); 392 } 393 394 @Override 395 public String getDescription() { 396 return I18N.getString("bundler.description"); 397 } 398 399 @Override 400 public String getID() { 401 return "rpm"; 402 } 403 404 @Override 405 public BundleType getBundleType() { 406 return BundleType.INSTALLER; 407 } 408 409 @Override 410 public Collection<BundlerParamInfo<?>> getBundleParameters() { 411 Collection<BundlerParamInfo<?>> results = new LinkedHashSet<>(); 412 results.addAll(LinuxAppBundler.getAppBundleParameters()); 413 results.addAll(getRpmBundleParameters()); 414 return results; 415 } 416 417 public static Collection<BundlerParamInfo<?>> getRpmBundleParameters() { 418 return Arrays.asList( 419 APP_BUNDLER, 420 APP_NAME, 421 BUILD_ROOT, 422 BUNDLE_NAME, 423 CONFIG_ROOT, 424 CATEGORY, 425 DESCRIPTION, 426 ICON, 427 RPM_IMAGE_DIR, 428 IMAGES_ROOT, 429 LICENSE_FILES, 430 LICENSE_TYPE, 431 MENU_HINT, 432 SHORTCUT_HINT, 433 TITLE, 434 VENDOR, 435 VERSION 436 ); 437 } 438 439 @Override 440 public File execute(Map<String, ? super Object> params, File outputParentDir) { 441 return bundle(params, outputParentDir); 442 } 443 } |