Skip to content

Commit

Permalink
Added support for package codes to be embedded in the installer name …
Browse files Browse the repository at this point in the history
…so that, on mac, it can figure out which package to install.
shannah committed Jan 15, 2022
1 parent be9fbe3 commit 08e808f
Showing 17 changed files with 252 additions and 13 deletions.
1 change: 1 addition & 0 deletions cli/jdeploy-cli.iml
Original file line number Diff line number Diff line change
@@ -30,5 +30,6 @@
<orderEntry type="library" name="Maven: ca.weblite.jdeploy:jdeploy-installer-template-mac-amd64:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: ca.weblite.jdeploy:jdeploy-installer-template-linux-amd64:1.0-SNAPSHOT" level="project" />
<orderEntry type="library" name="Maven: net.lingala.zip4j:zip4j:2.9.1" level="project" />
<orderEntry type="library" name="Maven: org.json:json:20211205" level="project" />
</component>
</module>
9 changes: 8 additions & 1 deletion cli/pom.xml
Original file line number Diff line number Diff line change
@@ -66,8 +66,10 @@
<mkdir dir="bin"/>
<copy todir="bin">
<fileset dir="target" includes="jdeploy-cli-${project.version}.jar,libs/*.jar"/>
<fileset dir="src/main/javascript"/>
</copy>
<move file="bin/jdeploy-cli-${project.version}.jar" tofile="bin/JDeploy.jar"/>

</target>
</configuration>
<goals>
@@ -128,7 +130,12 @@
<artifactId>zip4j</artifactId>
<version>2.9.1</version>
</dependency>

<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20211205</version>
<scope>compile</scope>
</dependency>


</dependencies>
50 changes: 48 additions & 2 deletions cli/src/main/java/ca/weblite/jdeploy/JDeploy.java
Original file line number Diff line number Diff line change
@@ -8,6 +8,8 @@
import ca.weblite.jdeploy.app.AppInfo;
import ca.weblite.jdeploy.appbundler.Bundler;
import ca.weblite.tools.io.ArchiveUtil;
import ca.weblite.tools.io.IOUtil;
import ca.weblite.tools.io.URLUtil;
import ca.weblite.tools.io.XMLUtil;
import com.client4j.JCAXMLFile;
import com.codename1.io.JSONParser;
@@ -19,6 +21,7 @@
import java.net.URI;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLEncoder;
import java.nio.file.*;
import java.nio.file.attribute.PosixFilePermission;
import java.util.ArrayList;
@@ -53,6 +56,7 @@
import org.apache.commons.compress.archivers.zip.ZipExtraField;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.json.JSONObject;
import org.w3c.dom.Document;

/**
@@ -65,6 +69,19 @@ public class JDeploy {
private File packageJsonFile;
private Map packageJsonMap;
private Result packageJsonResult;

public static String JDEPLOY_REGISTRY = "https://www.jdeploy.com/";
static {
if (System.getenv("JDEPLOY_REGISTRY_URL") != null) {
JDEPLOY_REGISTRY = System.getenv("JDEPLOY_REGISTRY_URL");
if (!JDEPLOY_REGISTRY.startsWith("http://") && !JDEPLOY_REGISTRY.startsWith("https://")) {
throw new RuntimeException("INVALID_JDEPLOY_REGISTRY_URL environment variable. Expecting URL but found "+JDEPLOY_REGISTRY);
}
if (!JDEPLOY_REGISTRY.endsWith("/")) {
JDEPLOY_REGISTRY += "/";
}
}
}

public class CopyRule {
String dir;
@@ -1030,10 +1047,31 @@ private static String getenv(String key, String defaultValue) {
return value;
}

private void loadAppInfo(AppInfo appInfo) throws IOException {


private String fetchJdeployBundleCode(AppInfo appInfo) throws IOException {
if (appInfo.getNpmPackage() == null) {
throw new IllegalArgumentException("Cannot fetch jdeploy bundle code without package and version");
}
String url = JDEPLOY_REGISTRY+"register.php?package=" +
URLEncoder.encode(appInfo.getNpmPackage(), "UTF-8");

System.out.println("Connecting to "+url);
try (InputStream inputStream = URLUtil.openStream(new URL(url))) {
JSONObject jsonResponse = new JSONObject(IOUtil.readToString(inputStream));
return jsonResponse.getString("code");
} catch (Exception ex) {
System.err.println("Failed to connect to "+url);
throw ex;
}
}

private void loadAppInfo(AppInfo appInfo) throws IOException {
appInfo.setNpmPackage((String)m().get("name"));
appInfo.setNpmVersion(getString("version", "latest"));
if (appInfo.getNpmVersion() != null && appInfo.getNpmPackage() != null) {
appInfo.setJdeployBundleCode(fetchJdeployBundleCode(appInfo));
}
appInfo.setMacAppBundleId(getString("macAppBundleId", null));
appInfo.setTitle(getString("displayName", appInfo.getNpmPackage()));
appInfo.setNpmAllowPrerelease("true".equals(getenv("JDEPLOY_BUNDLE_PRERELEASE", getString("prerelease", "false"))));
@@ -1136,7 +1174,11 @@ public void bundle(String target) throws Exception {
public void installer(String target, String version) throws Exception {
AppInfo appInfo = new AppInfo();
loadAppInfo(appInfo);
String packageJSONVersion = (String)m().get("version");
appInfo.setNpmVersion(version);
if (packageJSONVersion != null) {
appInfo.setNpmVersion(packageJSONVersion);
}

File installerDir = new File("jdeploy" + File.separator + "installers");
installerDir.mkdirs();
@@ -1212,7 +1254,11 @@ public void installer(String target, String version) throws Exception {
}
installSplashBytes = FileUtils.readFileToByteArray(bundledSplashFile);
}
String newName = appInfo.getTitle() + " Installer";
String _newName = appInfo.getTitle() + " Installer";
if (appInfo.getJdeployBundleCode() != null) {
_newName += "-"+appInfo.getNpmVersion()+"_"+appInfo.getJdeployBundleCode();
}
final String newName = _newName;
ArchiveUtil.NameFilter filter = new ArchiveUtil.NameFilter() {


36 changes: 36 additions & 0 deletions cli/src/main/javascript/jdeploy.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
#! /usr/bin/env node
var shell = require("shelljs/global");
var userArgs = process.argv.slice(2);
var javaArgs = [];
var programArgs = [];
userArgs.forEach(function(arg) {
if (arg.startsWith('-D') || arg.startsWith('-X')) {
javaArgs.push(arg);
} else {
programArgs.push(arg);
}
});
var cmd = 'java';
javaArgs.forEach(function(arg) {
cmd += ' "'+arg+'"';
});
cmd += ' -jar "'+__dirname+'/JDeploy.jar" ';
programArgs.forEach(function(arg) {
cmd += ' "'+arg+'"';
});
var child = exec(cmd, {async: true});
process.stdin.setEncoding('utf8');

process.stdin.on('readable', () => {
var chunk = process.stdin.read();
if (chunk === null) {

return;
}
try {
child.stdin.write(chunk);
} catch(e){}
});
child.on('close', function(code) {
process.exit(code);
});
140 changes: 139 additions & 1 deletion installer/src/main/java/ca/weblite/jdeploy/installer/Main.java
Original file line number Diff line number Diff line change
@@ -6,8 +6,10 @@
import ca.weblite.jdeploy.installer.npm.NPMPackage;
import ca.weblite.jdeploy.installer.npm.NPMPackageVersion;
import ca.weblite.jdeploy.installer.npm.NPMRegistry;
import ca.weblite.tools.io.ArchiveUtil;
import ca.weblite.tools.io.FileUtil;
import ca.weblite.tools.io.IOUtil;
import ca.weblite.tools.io.URLUtil;
import ca.weblite.tools.platform.Platform;
import com.izforge.izpack.util.os.ShellLink;
import net.coobird.thumbnailator.Thumbnails;
@@ -24,10 +26,15 @@
import java.awt.event.ItemEvent;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.TimerTask;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import net.sf.image4j.codec.ico.ICOEncoder;

@@ -36,6 +43,18 @@

public class Main implements Runnable {

public static String JDEPLOY_REGISTRY = "https://www.jdeploy.com/";
static {
if (System.getenv("JDEPLOY_REGISTRY_URL") != null) {
JDEPLOY_REGISTRY = System.getenv("JDEPLOY_REGISTRY_URL");
if (!JDEPLOY_REGISTRY.startsWith("http://") && !JDEPLOY_REGISTRY.startsWith("https://")) {
throw new RuntimeException("INVALID_JDEPLOY_REGISTRY_URL environment variable. Expecting URL but found "+JDEPLOY_REGISTRY);
}
if (!JDEPLOY_REGISTRY.endsWith("/")) {
JDEPLOY_REGISTRY += "/";
}
}
}
private Document appXMLDocument;
private AppInfo appInfo;
private JFrame frame;
@@ -277,9 +296,127 @@ private File findInstallFilesDir() {
return findInstallFilesDir(new File(System.getProperty("user.dir")));
}

private File findAppBundle() {
File start = new File(System.getProperty("client4j.launcher.path"));
while (start != null && !start.getName().endsWith(".app")) {
start = start.getParentFile();
}
return start;
}

private static String extractVersionFromFileName(String fileName) {
int pos = fileName.lastIndexOf("_");
if (pos < 0) return null;

fileName = fileName.substring(0, pos);
Pattern p = Pattern.compile("\\-(\\d.*)$");
Matcher m = p.matcher(fileName);
if (m.matches()) {
return m.group(1);
}
return null;

}


private static String extractJDeployBundleCodeFromFileName(String fileName) {
int pos = fileName.lastIndexOf("_");
if (pos < 0) return null;
StringBuilder out = new StringBuilder();
char[] chars = fileName.substring(pos+1).toCharArray();
for (int i=0; i<chars.length; i++) {
char c = chars[i];
if (('0' <= c && '9' <= c) || ('A' <= c && 'Z' >= c)) {
out.append(c);
} else {
break;
}
}
if (out.length() == 0) return null;
return out.toString();

}

private static URL getJDeployBundleURLForCode(String code, String version) {
try {
return new URL(JDEPLOY_REGISTRY + "download.php?code=" + URLEncoder.encode(code, "UTF-8")+"&version="+URLEncoder.encode(version, "UTF-8"));
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("UTF-8 Encoding doesn't seem to be supported on this platform.", ex);
} catch (MalformedURLException e) {
throw new RuntimeException("Programming error. Malformed URL for bundle. ", e);
}
}

private static File findDirectoryByNameRecursive(File startDirectory, String name) {
if (startDirectory.isDirectory()) {
if (startDirectory.getName().equals(name)) return startDirectory;
for (File child : startDirectory.listFiles()) {
File result = findDirectoryByNameRecursive(child, name);
if (result != null) return result;
}
}
return null;
}

private static File downloadJDeployBundleForCode(String code, String version) throws IOException {
File destDirectory = File.createTempFile("jdeploy-files-download", ".tmp");
destDirectory.delete();
Runtime.getRuntime().addShutdownHook(new Thread(()->{
try {
FileUtils.deleteDirectory(destDirectory);
} catch (Exception ex){}
}));
File destFile = new File(destDirectory, "jdeploy-files.zip");
try (InputStream inputStream = URLUtil.openStream(getJDeployBundleURLForCode(code, version))) {
FileUtils.copyInputStreamToFile(inputStream, destFile);
}

ArchiveUtil.extract(destFile, destDirectory, "");
return findDirectoryByNameRecursive(destDirectory, ".jdeploy-files");
}



private File findInstallFilesDir(File startDir) {



System.out.println("findInstallFilesDir("+startDir+"):");
if (startDir == null) return null;

if (Platform.getSystemPlatform().isMac() && "AppTranslocation".equals(startDir.getName())) {
System.out.println("Detected that we are running inside Gatekeeper so we can't retrieve bundle info");
System.out.println("Attempting to download bundle info from network");
// Gatekeeper is running the app from a random location, so we won't be able to find the
// app.xml file the normal way.
// We need to be creative.
// Using the name of the installer,
// we can extract the package name and version
File appBundle = findAppBundle();
if (appBundle == null) {
System.err.println("Failed to find app bundle");
return null;
}
String code = extractJDeployBundleCodeFromFileName(appBundle.getName());
if (code == null) {
System.err.println("Cannot download bundle info from the network because no code was found in the app name: "+appBundle.getName());
return null;
}
String version = extractVersionFromFileName(appBundle.getName());
if (version == null) {
System.err.println("Cannot download bundle info from network because the version string was not found in the app name: "+appBundle.getName());
}
try {
return downloadJDeployBundleForCode(code, version);
} catch (IOException ex) {
System.err.println("Failed to download bundle from the network for code "+code+".");
ex.printStackTrace(System.err);
return null;
}


}

File candidate = new File(startDir, ".jdeploy-files");
System.out.println("Candidate: "+candidate);
if (candidate.exists() && candidate.isDirectory()) return candidate;
@@ -303,9 +440,10 @@ private File findAppXmlFile() {
System.out.println("app.xml: "+appXml);
return appXml;


}



@Override
public void run() {
try {
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -7,12 +7,12 @@
<snapshot>
<localCopy>true</localCopy>
</snapshot>
<lastUpdated>20220108135755</lastUpdated>
<lastUpdated>20220115143456</lastUpdated>
<snapshotVersions>
<snapshotVersion>
<extension>jar</extension>
<value>1.0-SNAPSHOT</value>
<updated>20220108135755</updated>
<updated>20220115143456</updated>
</snapshotVersion>
<snapshotVersion>
<extension>pom</extension>
Original file line number Diff line number Diff line change
@@ -6,6 +6,6 @@
<versions>
<version>1.0-SNAPSHOT</version>
</versions>
<lastUpdated>20220108135755</lastUpdated>
<lastUpdated>20220115143456</lastUpdated>
</versioning>
</metadata>
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -7,12 +7,12 @@
<snapshot>
<localCopy>true</localCopy>
</snapshot>
<lastUpdated>20220108135749</lastUpdated>
<lastUpdated>20220115143449</lastUpdated>
<snapshotVersions>
<snapshotVersion>
<extension>jar</extension>
<value>1.0-SNAPSHOT</value>
<updated>20220108135749</updated>
<updated>20220115143449</updated>
</snapshotVersion>
<snapshotVersion>
<extension>pom</extension>
Loading

0 comments on commit 08e808f

Please sign in to comment.