77 } catch (IOException ex) { 78 Log.verbose(ex); 79 throw new PackagerException(ex); 80 } 81 } 82 83 private static final String hdiutil = "/usr/bin/hdiutil"; 84 85 private void prepareDMGSetupScript(String volumeName, 86 Map<String, ? super Object> params) throws IOException { 87 File dmgSetup = getConfig_VolumeScript(params); 88 Log.verbose(MessageFormat.format( 89 I18N.getString("message.preparing-dmg-setup"), 90 dmgSetup.getAbsolutePath())); 91 92 //prepare config for exe 93 Map<String, String> data = new HashMap<>(); 94 data.put("DEPLOY_ACTUAL_VOLUME_NAME", volumeName); 95 data.put("DEPLOY_APPLICATION_NAME", APP_NAME.fetchFrom(params)); 96 97 data.put("DEPLOY_INSTALL_LOCATION", "(path to desktop folder)"); 98 data.put("DEPLOY_INSTALL_NAME", "Desktop"); 99 100 try (Writer w = Files.newBufferedWriter(dmgSetup.toPath())) { 101 w.write(preprocessTextResource(dmgSetup.getName(), 102 I18N.getString("resource.dmg-setup-script"), 103 DEFAULT_DMG_SETUP_SCRIPT, data, VERBOSE.fetchFrom(params), 104 RESOURCE_DIR.fetchFrom(params))); 105 } 106 } 107 108 private File getConfig_VolumeScript(Map<String, ? super Object> params) { 109 return new File(CONFIG_ROOT.fetchFrom(params), 110 APP_NAME.fetchFrom(params) + "-dmg-setup.scpt"); 111 } 112 113 private File getConfig_VolumeBackground( 114 Map<String, ? super Object> params) { 115 return new File(CONFIG_ROOT.fetchFrom(params), 116 APP_NAME.fetchFrom(params) + "-background.png"); 117 } 118 302 hdiUtilVerbosityFlag, 303 "-srcfolder", srcFolder.getAbsolutePath(), 304 "-volname", APP_NAME.fetchFrom(params), 305 "-ov", protoDMG.getAbsolutePath(), 306 "-fs", "HFS+", 307 "-format", "UDRW"); 308 IOUtils.exec(pb); 309 310 // mount temp image 311 pb = new ProcessBuilder( 312 hdiutil, 313 "attach", 314 protoDMG.getAbsolutePath(), 315 hdiUtilVerbosityFlag, 316 "-mountroot", imagesRoot.getAbsolutePath()); 317 IOUtils.exec(pb); 318 319 File mountedRoot = new File(imagesRoot.getAbsolutePath(), 320 APP_NAME.fetchFrom(params)); 321 322 // volume icon 323 File volumeIconFile = new File(mountedRoot, ".VolumeIcon.icns"); 324 IOUtils.copyFile(getConfig_VolumeIcon(params), 325 volumeIconFile); 326 327 pb = new ProcessBuilder("osascript", 328 getConfig_VolumeScript(params).getAbsolutePath()); 329 IOUtils.exec(pb); 330 331 // Indicate that we want a custom icon 332 // NB: attributes of the root directory are ignored 333 // when creating the volume 334 // Therefore we have to do this after we mount image 335 String setFileUtility = findSetFileUtility(); 336 if (setFileUtility != null) { 337 //can not find utility => keep going without icon 338 try { 339 volumeIconFile.setWritable(true); 340 // The "creator" attribute on a file is a legacy attribute 341 // but it seems Finder excepts these bytes to be 342 // "icnC" for the volume icon 343 // http://endrift.com/blog/2010/06/14/dmg-files-volume-icons-cli 344 // (might not work on Mac 10.13 with old XCode) 345 pb = new ProcessBuilder( 346 setFileUtility, 347 "-c", "icnC", 348 volumeIconFile.getAbsolutePath()); 349 IOUtils.exec(pb); 350 volumeIconFile.setReadOnly(); 351 352 pb = new ProcessBuilder( 353 setFileUtility, 354 "-a", "C", 355 mountedRoot.getAbsolutePath()); 356 IOUtils.exec(pb); 357 } catch (IOException ex) { 358 Log.error(ex.getMessage()); 359 Log.verbose("Cannot enable custom icon using SetFile utility"); 360 } 361 } else { 362 Log.verbose(I18N.getString("message.setfile.dmg")); 363 } 364 365 // Detach the temporary image 366 pb = new ProcessBuilder( 367 hdiutil, 368 "detach", 369 "-force", 370 hdiUtilVerbosityFlag, 371 mountedRoot.getAbsolutePath()); 372 IOUtils.exec(pb); 373 374 // Compress it to a new image 375 pb = new ProcessBuilder( 376 hdiutil, 377 "convert", 378 protoDMG.getAbsolutePath(), 379 hdiUtilVerbosityFlag, 380 "-format", "UDZO", 381 "-o", finalDMG.getAbsolutePath()); 382 IOUtils.exec(pb); 383 384 //add license if needed 385 if (getConfig_LicenseFile(params).exists()) { 386 //hdiutil unflatten your_image_file.dmg 387 pb = new ProcessBuilder( 388 hdiutil, 389 "unflatten", 390 finalDMG.getAbsolutePath() 391 ); 392 IOUtils.exec(pb); | 77 } catch (IOException ex) { 78 Log.verbose(ex); 79 throw new PackagerException(ex); 80 } 81 } 82 83 private static final String hdiutil = "/usr/bin/hdiutil"; 84 85 private void prepareDMGSetupScript(String volumeName, 86 Map<String, ? super Object> params) throws IOException { 87 File dmgSetup = getConfig_VolumeScript(params); 88 Log.verbose(MessageFormat.format( 89 I18N.getString("message.preparing-dmg-setup"), 90 dmgSetup.getAbsolutePath())); 91 92 //prepare config for exe 93 Map<String, String> data = new HashMap<>(); 94 data.put("DEPLOY_ACTUAL_VOLUME_NAME", volumeName); 95 data.put("DEPLOY_APPLICATION_NAME", APP_NAME.fetchFrom(params)); 96 97 data.put("DEPLOY_INSTALL_LOCATION", "(path to applications folder)"); 98 data.put("DEPLOY_INSTALL_NAME", "Applications"); 99 100 try (Writer w = Files.newBufferedWriter(dmgSetup.toPath())) { 101 w.write(preprocessTextResource(dmgSetup.getName(), 102 I18N.getString("resource.dmg-setup-script"), 103 DEFAULT_DMG_SETUP_SCRIPT, data, VERBOSE.fetchFrom(params), 104 RESOURCE_DIR.fetchFrom(params))); 105 } 106 } 107 108 private File getConfig_VolumeScript(Map<String, ? super Object> params) { 109 return new File(CONFIG_ROOT.fetchFrom(params), 110 APP_NAME.fetchFrom(params) + "-dmg-setup.scpt"); 111 } 112 113 private File getConfig_VolumeBackground( 114 Map<String, ? super Object> params) { 115 return new File(CONFIG_ROOT.fetchFrom(params), 116 APP_NAME.fetchFrom(params) + "-background.png"); 117 } 118 302 hdiUtilVerbosityFlag, 303 "-srcfolder", srcFolder.getAbsolutePath(), 304 "-volname", APP_NAME.fetchFrom(params), 305 "-ov", protoDMG.getAbsolutePath(), 306 "-fs", "HFS+", 307 "-format", "UDRW"); 308 IOUtils.exec(pb); 309 310 // mount temp image 311 pb = new ProcessBuilder( 312 hdiutil, 313 "attach", 314 protoDMG.getAbsolutePath(), 315 hdiUtilVerbosityFlag, 316 "-mountroot", imagesRoot.getAbsolutePath()); 317 IOUtils.exec(pb); 318 319 File mountedRoot = new File(imagesRoot.getAbsolutePath(), 320 APP_NAME.fetchFrom(params)); 321 322 try { 323 // volume icon 324 File volumeIconFile = new File(mountedRoot, ".VolumeIcon.icns"); 325 IOUtils.copyFile(getConfig_VolumeIcon(params), 326 volumeIconFile); 327 328 // background image 329 File bgdir = new File(mountedRoot, ".background"); 330 bgdir.mkdirs(); 331 IOUtils.copyFile(getConfig_VolumeBackground(params), 332 new File(bgdir, "background.png")); 333 334 // Indicate that we want a custom icon 335 // NB: attributes of the root directory are ignored 336 // when creating the volume 337 // Therefore we have to do this after we mount image 338 String setFileUtility = findSetFileUtility(); 339 if (setFileUtility != null) { 340 //can not find utility => keep going without icon 341 try { 342 volumeIconFile.setWritable(true); 343 // The "creator" attribute on a file is a legacy attribute 344 // but it seems Finder excepts these bytes to be 345 // "icnC" for the volume icon 346 // http://endrift.com/blog/2010/06/14/dmg-files-volume-icons-cli 347 // (might not work on Mac 10.13 with old XCode) 348 pb = new ProcessBuilder( 349 setFileUtility, 350 "-c", "icnC", 351 volumeIconFile.getAbsolutePath()); 352 IOUtils.exec(pb); 353 volumeIconFile.setReadOnly(); 354 355 pb = new ProcessBuilder( 356 setFileUtility, 357 "-a", "C", 358 mountedRoot.getAbsolutePath()); 359 IOUtils.exec(pb); 360 } catch (IOException ex) { 361 Log.error(ex.getMessage()); 362 Log.verbose("Cannot enable custom icon using SetFile utility"); 363 } 364 } else { 365 Log.verbose(I18N.getString("message.setfile.dmg")); 366 } 367 368 // We will not consider setting background image and creating link to 369 // /Application folder in DMG as critical error, since it can fail in 370 // headless enviroment. 371 try { 372 pb = new ProcessBuilder("osascript", 373 getConfig_VolumeScript(params).getAbsolutePath()); 374 IOUtils.exec(pb); 375 } catch (IOException ex) { 376 Log.verbose(ex); 377 } 378 } finally { 379 // Detach the temporary image 380 pb = new ProcessBuilder( 381 hdiutil, 382 "detach", 383 "-force", 384 hdiUtilVerbosityFlag, 385 mountedRoot.getAbsolutePath()); 386 IOUtils.exec(pb); 387 } 388 389 // Compress it to a new image 390 pb = new ProcessBuilder( 391 hdiutil, 392 "convert", 393 protoDMG.getAbsolutePath(), 394 hdiUtilVerbosityFlag, 395 "-format", "UDZO", 396 "-o", finalDMG.getAbsolutePath()); 397 IOUtils.exec(pb); 398 399 //add license if needed 400 if (getConfig_LicenseFile(params).exists()) { 401 //hdiutil unflatten your_image_file.dmg 402 pb = new ProcessBuilder( 403 hdiutil, 404 "unflatten", 405 finalDMG.getAbsolutePath() 406 ); 407 IOUtils.exec(pb); |