Skip to content

Commit

Permalink
Merge pull request #134 from shannah/dedicated-jre
Browse files Browse the repository at this point in the history
Dedicated jre for Java8 on windows
  • Loading branch information
shannah authored Jul 15, 2024
2 parents 68d68f7 + 2e6bdc6 commit 3966840
Show file tree
Hide file tree
Showing 35 changed files with 1,154 additions and 255 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ installer/jdeploy-bundle
cli/bin
tests/projects/*/jdeploy
./jdeploy
#./installer/tests/*/mock_launcher*
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,12 @@ public File findInstallFilesDir() {
}

System.out.println("Found client4.launcher.path property: "+launcherPath);
cachedInstallFilesDir = findInstallFilesDir(new File(launcherPath));
if (System.getProperty("client4j.appxml.path") != null) {
cachedInstallFilesDir = findInstallFilesDir(new File(System.getProperty("client4j.appxml.path")).getParentFile());
} else {
cachedInstallFilesDir = findInstallFilesDir(new File(launcherPath));
}

return cachedInstallFilesDir;
} else {
System.out.println("client4j.launcher.path is not set");
Expand Down Expand Up @@ -261,6 +266,9 @@ private String getDefaultWebsiteUrl(String packageName, String source) throws Un


public File findAppXml() {
if (System.getProperty("client4j.appxml.path") != null) {
return new File(System.getProperty("client4j.appxml.path"));
}
File installFilesDir = findInstallFilesDir();
if (installFilesDir == null) {
return null;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package ca.weblite.jdeploy.installer;

import ca.weblite.jdeploy.installer.models.InstallationSettings;

public class HeadlessInstallationSettings extends InstallationSettings {

}
307 changes: 72 additions & 235 deletions installer/src/main/java/ca/weblite/jdeploy/installer/Main.java

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import java.util.ArrayList;

public class NPMPackageVersion {
private static final String DEFAULT_JAVA_VERSION = "11";
private final NPMPackage npmPackage;
private final String version;
private final JSONObject packageJson;
Expand Down Expand Up @@ -36,7 +37,12 @@ public String getVersion() {
return version;
}


public String getJavaVersion() {
if (jdeploy().has("javaVersion")) {
return jdeploy().getString("javaVersion");
}
return DEFAULT_JAVA_VERSION;
}

private JSONObject jdeploy() {
return packageJson.getJSONObject("jdeploy");
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
package ca.weblite.jdeploy.installer.win;

import ca.weblite.jdeploy.app.AppInfo;
import ca.weblite.jdeploy.installer.InstallationContext;
import ca.weblite.jdeploy.installer.Main;
import ca.weblite.jdeploy.installer.models.InstallationSettings;
import ca.weblite.tools.io.FileUtil;
import com.izforge.izpack.util.os.ShellLink;
import net.coobird.thumbnailator.Thumbnails;
import net.sf.image4j.codec.ico.ICOEncoder;
import org.apache.commons.io.FileUtils;

import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;

import static ca.weblite.tools.io.IOUtil.copyResourceToFile;

public class InstallWindows {

public File install(
InstallationContext context,
InstallationSettings installationSettings,
String fullyQualifiedPackageName,
File tmpBundles
) throws Exception {
AppInfo appInfo = installationSettings.getAppInfo();
File tmpExePath = findTmpExeFile(tmpBundles);
File appXmlFile = context.findAppXml();
File userHome = new File(System.getProperty("user.home"));
File jdeployHome = new File(userHome, ".jdeploy");
File appsDir = new File(jdeployHome, "apps");
File appDir = new File(appsDir, fullyQualifiedPackageName);
appDir.mkdirs();
String nameSuffix = "";

if (appInfo.getNpmVersion().startsWith("0.0.0-")) {
nameSuffix = " " +
appInfo.getNpmVersion().substring(appInfo.getNpmVersion().indexOf("-") + 1)
.trim();
}

String exeName = appInfo.getTitle() + nameSuffix + ".exe";
File exePath = new File(appDir, exeName);
if (appInfo.isUsePrivateJVM()) {
File appBinDir = new File(appDir, "bin");
appBinDir.mkdirs();
exePath = new File(appBinDir, exeName);
}

FileUtil.copy(tmpExePath, exePath);
exePath.setExecutable(true, false);

// Copy the icon.png if it is present
File bundleIcon = new File(appXmlFile.getParentFile(), "icon.png");
File iconPath = new File(appDir, "icon.png");
File icoPath = new File(appDir, "icon.ico");

if (Files.exists(bundleIcon.toPath())) {
FileUtil.copy(bundleIcon, iconPath);
}
installWindowsLinks(
appInfo,
installationSettings,
exePath,
appDir,
appInfo.getTitle() + nameSuffix
);

File registryBackupLogs = new File(appDir, "registry-backup-logs");

if (!registryBackupLogs.exists()) {
registryBackupLogs.mkdirs();
}
int nextLogIndex = 0;
for (File child : registryBackupLogs.listFiles()) {
if (child.getName().endsWith(".reg")) {
String logIndex = child.getName().substring(0, child.getName().lastIndexOf("."));
try {
int logIndexInt = Integer.parseInt(logIndex);
if (logIndexInt >= nextLogIndex) {
nextLogIndex = logIndexInt+1;
}
} catch (Exception ex) {}
}
}
File registryBackupLog = new File(registryBackupLogs, nextLogIndex+".reg");
try (FileOutputStream fos = new FileOutputStream(registryBackupLog)) {
InstallWindowsRegistry registryInstaller = new InstallWindowsRegistry(appInfo, exePath, icoPath, fos);
registryInstaller.register();

//Try to copy the uninstaller
File uninstallerPath = registryInstaller.getUninstallerPath();
uninstallerPath.getParentFile().mkdirs();
File installerExePath = new File(System.getProperty("client4j.launcher.path"));
if (uninstallerPath.exists()) {
if (!uninstallerPath.canWrite()) {
uninstallerPath.setWritable(true, false);
try {
// Give windows time to update its cache
Thread.sleep(1000L);
} catch (InterruptedException interruptedException) {
// Ignore
}
}
if (!uninstallerPath.delete()) {
throw new IOException("Failed to delete uninstaller: "+uninstallerPath);
}

try {
// Give Windows time to update its cache
Thread.sleep(1000L);
} catch (InterruptedException interruptedException) {
// Ignore
}
}
FileUtils.copyFile(installerExePath, uninstallerPath);
uninstallerPath.setExecutable(true, false);
FileUtils.copyDirectory(
context.findInstallFilesDir(),
new File(
uninstallerPath.getParentFile(),
context.findInstallFilesDir().getName()
)
);

return exePath;

} catch (Exception ex) {
// restore
try {
InstallWindowsRegistry.rollback(registryBackupLog);
} catch (Exception rollbackException) {
throw new RuntimeException(
"Failed to roll back registry after failed installation.",
rollbackException
);
}
// Since we rolled back the changes, we'll delete the backup log so that it doesn't get rolled back again.
registryBackupLog.delete();
ex.printStackTrace(System.err);
throw new RuntimeException("Failed to update registry. Rolling back changes.", ex);

}
}

private void installWindowsLink(
AppInfo appInfo,
int type,
File exePath,
File iconPath,
String appTitle
) throws Exception {
ShellLink link = new ShellLink(type, appTitle);
link.setUserType(ShellLink.CURRENT_USER);
if (appInfo.getDescription() == null) {
link.setDescription("Windows application");
} else {
link.setDescription(appInfo.getDescription());
}
String iconPathString = iconPath.getCanonicalFile().getAbsolutePath();
link.setIconLocation(iconPathString, 0);
String exePathString = exePath.getCanonicalFile().getAbsolutePath();
link.setTargetPath(exePathString);
link.save();
}

private void installWindowsLinks(
AppInfo appInfo,
InstallationSettings installationSettings,
File exePath,
File appDir,
String appTitle
) throws Exception {
File pngIconPath = new File(appDir, "icon.png");
File icoPath = new File(appDir.getCanonicalFile(), "icon.ico");

if (!Files.exists(pngIconPath.toPath())) {
copyResourceToFile(Main.class, "icon.png", pngIconPath);
}
if (!Files.exists(pngIconPath.toPath())) {
throw new IOException("Failed to create the .ico file for some reason. "+icoPath);
}
convertWindowsIcon(pngIconPath.getCanonicalFile(), icoPath);


if (installationSettings.isAddToDesktop()) {
try {
installWindowsLink(appInfo, ShellLink.DESKTOP, exePath, icoPath, appTitle);
} catch (Exception ex) {
throw new RuntimeException("Failed to install desktop shortcut", ex);

}
}
if (installationSettings.isAddToPrograms()) {
try {
installWindowsLink(appInfo, ShellLink.PROGRAM_MENU, exePath, icoPath, appTitle);
} catch (Exception ex) {
throw new RuntimeException("Failed to install program menu shortcut", ex);

}
}
if (installationSettings.isAddToStartMenu()) {
try {
installWindowsLink(appInfo, ShellLink.START_MENU, exePath, icoPath, appTitle);
} catch (Exception ex) {
throw new RuntimeException("Failed to install start menu shortcut", ex);

}
}
}

private void convertWindowsIcon(File srcPng, File destIco) throws IOException {
List<BufferedImage> images = new ArrayList<>();
List<Integer> bppList = new ArrayList<>();
for (int i : new int[]{16, 24, 32, 48, 64, 128, 256}) {
BufferedImage img = Thumbnails.of(srcPng).size(i, i).asBufferedImage();
images.add(img);
bppList.add(32);
if (i <= 48) {
images.add(img);
bppList.add(8);
images.add(img);
bppList.add(4);
}
}
int[] bppArray = bppList.stream().mapToInt(i->i).toArray();
try (FileOutputStream fileOutputStream = new FileOutputStream(destIco)) {
ICOEncoder.write(images,bppArray, fileOutputStream);
}
}

private File findTmpExeFile(File tmpBundles) {
File tmpExePath = null;
for (File exeCandidate : new File(tmpBundles, "windows").listFiles()) {
if (exeCandidate.getName().endsWith(".exe")) {
tmpExePath = exeCandidate;
}
}
if (tmpExePath == null) {
throw new RuntimeException("Failed to find exe file after creation. Something must have gone wrong in generation process");
}

return tmpExePath;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package ca.weblite.jdeploy.installer.win;

import ca.weblite.jdeploy.app.AppInfo;
import ca.weblite.jdeploy.installer.models.InstallationSettings;
import ca.weblite.tools.io.MD5;
import org.apache.commons.io.FileUtils;

Expand Down Expand Up @@ -190,7 +191,12 @@ public String getFullRegistryPath() {

}

public InstallWindowsRegistry(AppInfo appInfo, File exe, File icon, OutputStream backupLog) {
public InstallWindowsRegistry(
AppInfo appInfo,
File exe,
File icon,
OutputStream backupLog
) {
this.appInfo = appInfo;
this.exe = exe;
this.icon = icon;
Expand Down Expand Up @@ -371,7 +377,13 @@ private void registerFileExtension(String ext) {
if (mimetype != null) {
registrySetStringValue(HKEY_CURRENT_USER, key, "ContentType", mimetype);
if (mimetype.contains("/")) {
registrySetStringValue(HKEY_CURRENT_USER, key, "PerceivedType", mimetype.substring(0, mimetype.indexOf("/")));
registrySetStringValue(
HKEY_CURRENT_USER,
key,
"PerceivedType",
mimetype.substring(0, mimetype.indexOf("/")
)
);
}
}
}
Expand Down Expand Up @@ -452,7 +464,8 @@ public static void rollback(File backupLog) throws IOException {
Scanner scanner = new Scanner(backupLog, "UTF-8");
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
// If we added a key, we wrote them to the log file as comments of the form ;CREATE key where key is like Software\Classes\...
// If we added a key, we wrote them to the log file as comments of the form
// ;CREATE key where key is like Software\Classes\...
if (line.startsWith(";CREATE ")) {
deleteKeyRecursive(line.substring(line.indexOf(" ")+1));
}
Expand Down Expand Up @@ -661,7 +674,12 @@ public void register() throws IOException {
}

// Register the application
registrySetStringValue(HKEY_CURRENT_USER, "Software\\RegisteredApplications", getRegisteredAppName(), getCapabilitiesPath());
registrySetStringValue(
HKEY_CURRENT_USER,
"Software\\RegisteredApplications",
getRegisteredAppName(),
getCapabilitiesPath()
);

// Now to register the uninstaller

Expand All @@ -673,7 +691,12 @@ public void register() throws IOException {
registrySetStringValue(HKEY_CURRENT_USER, getUninstallKey(), "DisplayVersion", appInfo.getVersion());
registrySetLongValue(HKEY_CURRENT_USER, getUninstallKey(), 1);
registrySetStringValue(HKEY_CURRENT_USER, getUninstallKey(), "Publisher", appInfo.getVendor());
registrySetStringValue(HKEY_CURRENT_USER, getUninstallKey(), "UninstallString", "\""+getUninstallerPath().getAbsolutePath()+"\" uninstall");
registrySetStringValue(
HKEY_CURRENT_USER,
getUninstallKey(),
"UninstallString",
"\"" + getUninstallerPath().getAbsolutePath() + "\" uninstall"
);

String installerPath = System.getProperty("client4j.launcher.path");
if (installerPath == null) {
Expand Down
Loading

0 comments on commit 3966840

Please sign in to comment.