updated control access
This commit is contained in:
161
old code/tray/src/qz/installer/provision/ProvisionInstaller.java
Executable file
161
old code/tray/src/qz/installer/provision/ProvisionInstaller.java
Executable file
@@ -0,0 +1,161 @@
|
||||
package qz.installer.provision;
|
||||
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.codehaus.jettison.json.JSONArray;
|
||||
import org.codehaus.jettison.json.JSONException;
|
||||
import org.codehaus.jettison.json.JSONObject;
|
||||
import qz.build.provision.Step;
|
||||
import qz.build.provision.params.Os;
|
||||
import qz.build.provision.params.Phase;
|
||||
import qz.build.provision.params.types.Script;
|
||||
import qz.build.provision.params.types.Software;
|
||||
import qz.common.Constants;
|
||||
import qz.installer.provision.invoker.*;
|
||||
import qz.utils.ShellUtilities;
|
||||
import qz.utils.SystemUtilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import static qz.common.Constants.*;
|
||||
import static qz.utils.FileUtilities.*;
|
||||
|
||||
public class ProvisionInstaller {
|
||||
protected static final Logger log = LogManager.getLogger(ProvisionInstaller.class);
|
||||
private ArrayList<Step> steps;
|
||||
|
||||
static {
|
||||
// Populate variables for scripting environment
|
||||
ShellUtilities.addEnvp("APP_TITLE", ABOUT_TITLE,
|
||||
"APP_VERSION", VERSION,
|
||||
"APP_ABBREV", PROPS_FILE,
|
||||
"APP_VENDOR", ABOUT_COMPANY,
|
||||
"APP_VENDOR_ABBREV", DATA_DIR,
|
||||
"APP_ARCH", SystemUtilities.getArch(),
|
||||
"APP_OS", SystemUtilities.getOs(),
|
||||
"APP_DIR", SystemUtilities.getAppPath(),
|
||||
"APP_USER_DIR", USER_DIR,
|
||||
"APP_SHARED_DIR", SHARED_DIR);
|
||||
}
|
||||
|
||||
public ProvisionInstaller(Path relativePath) throws IOException, JSONException {
|
||||
this(relativePath, relativePath.resolve(Constants.PROVISION_FILE).toFile());
|
||||
}
|
||||
|
||||
public ProvisionInstaller(Path relativePath, File jsonFile) throws IOException, JSONException {
|
||||
if(!jsonFile.exists()) {
|
||||
log.info("Provision file not found '{}', skipping", jsonFile);
|
||||
this.steps = new ArrayList<>();
|
||||
return;
|
||||
}
|
||||
this.steps = parse(FileUtils.readFileToString(jsonFile, StandardCharsets.UTF_8), relativePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private for internal testing only
|
||||
* Assumes files located in ./resources/ subdirectory
|
||||
*/
|
||||
ProvisionInstaller(Class relativeClass, InputStream in) throws IOException, JSONException {
|
||||
this(relativeClass, IOUtils.toString(in, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
/**
|
||||
* Package private for internal testing only
|
||||
* Assumes files located in ./resources/ subdirectory
|
||||
*/
|
||||
ProvisionInstaller(Class relativeClass, String jsonData) throws JSONException {
|
||||
this.steps = parse(jsonData, relativeClass);
|
||||
}
|
||||
|
||||
public void invoke(Phase phase) {
|
||||
for(Step step : this.steps) {
|
||||
if(phase == null || step.getPhase() == phase) {
|
||||
try {
|
||||
invokeStep(step);
|
||||
}
|
||||
catch(Exception e) {
|
||||
log.error("[PROVISION] Provisioning step failed '{}'", step, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void invoke() {
|
||||
invoke(null);
|
||||
}
|
||||
|
||||
private static ArrayList<Step> parse(String jsonData, Object relativeObject) throws JSONException {
|
||||
return parse(new JSONArray(jsonData), relativeObject);
|
||||
}
|
||||
|
||||
private boolean invokeStep(Step step) throws Exception {
|
||||
if(Os.matchesHost(step.getOs())) {
|
||||
log.info("[PROVISION] Invoking step '{}'", step.toString());
|
||||
} else {
|
||||
log.info("[PROVISION] Skipping step for different OS '{}'", step.toString());
|
||||
return false;
|
||||
}
|
||||
|
||||
Invokable invoker;
|
||||
switch(step.getType()) {
|
||||
case CA:
|
||||
invoker = new CaInvoker(step, PropertyInvoker.getProperties(step));
|
||||
break;
|
||||
case CERT:
|
||||
invoker = new CertInvoker(step);
|
||||
break;
|
||||
case CONF:
|
||||
invoker = new ConfInvoker(step);
|
||||
break;
|
||||
case SCRIPT:
|
||||
invoker = new ScriptInvoker(step);
|
||||
break;
|
||||
case SOFTWARE:
|
||||
invoker = new SoftwareInvoker(step);
|
||||
break;
|
||||
case REMOVER:
|
||||
invoker = new RemoverInvoker(step);
|
||||
break;
|
||||
case RESOURCE:
|
||||
invoker = new ResourceInvoker(step);
|
||||
break;
|
||||
case PREFERENCE:
|
||||
invoker = new PropertyInvoker(step, PropertyInvoker.getPreferences(step));
|
||||
break;
|
||||
case PROPERTY:
|
||||
invoker = new PropertyInvoker(step, PropertyInvoker.getProperties(step));
|
||||
break;
|
||||
default:
|
||||
throw new UnsupportedOperationException("Type " + step.getType() + " is not yet supported.");
|
||||
}
|
||||
return invoker.invoke();
|
||||
}
|
||||
|
||||
public ArrayList<Step> getSteps() {
|
||||
return steps;
|
||||
}
|
||||
|
||||
private static ArrayList<Step> parse(JSONArray jsonArray, Object relativeObject) throws JSONException {
|
||||
ArrayList<Step> steps = new ArrayList<>();
|
||||
for(int i = 0; i < jsonArray.length(); i++) {
|
||||
JSONObject jsonStep = jsonArray.getJSONObject(i);
|
||||
try {
|
||||
steps.add(Step.parse(jsonStep, relativeObject));
|
||||
} catch(Exception e) {
|
||||
log.warn("[PROVISION] Unable to add step '{}'", jsonStep, e);
|
||||
}
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
|
||||
public static boolean shouldBeExecutable(Path path) {
|
||||
return Script.parse(path) != null || Software.parse(path) != Software.UNKNOWN;
|
||||
}
|
||||
}
|
||||
49
old code/tray/src/qz/installer/provision/invoker/CaInvoker.java
Executable file
49
old code/tray/src/qz/installer/provision/invoker/CaInvoker.java
Executable file
@@ -0,0 +1,49 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import qz.build.provision.Step;
|
||||
import qz.common.PropertyHelper;
|
||||
import qz.utils.ArgValue;
|
||||
import qz.utils.FileUtilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Combines ResourceInvoker and PropertyInvoker to deploy a file and set a property to its deployed path
|
||||
*/
|
||||
public class CaInvoker extends InvokableResource {
|
||||
Step step;
|
||||
PropertyHelper properties;
|
||||
|
||||
public CaInvoker(Step step, PropertyHelper properties) {
|
||||
this.step = step;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean invoke() throws IOException {
|
||||
// First, write our cert file
|
||||
File caCert = dataToFile(step);
|
||||
if(caCert == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Next, handle our property step
|
||||
Step propsStep = step.clone();
|
||||
|
||||
// If the property already exists, snag it
|
||||
String key = ArgValue.AUTHCERT_OVERRIDE.getMatch();
|
||||
String value = caCert.getPath();
|
||||
if (properties.containsKey(key)) {
|
||||
value = properties.getProperty(key) + FileUtilities.FILE_SEPARATOR + value;
|
||||
}
|
||||
|
||||
propsStep.setData(String.format("%s=%s", key, value));
|
||||
|
||||
if (new PropertyInvoker(propsStep, properties).invoke()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
26
old code/tray/src/qz/installer/provision/invoker/CertInvoker.java
Executable file
26
old code/tray/src/qz/installer/provision/invoker/CertInvoker.java
Executable file
@@ -0,0 +1,26 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import qz.build.provision.Step;
|
||||
import qz.common.Constants;
|
||||
import qz.utils.FileUtilities;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import static qz.utils.ArgParser.ExitStatus.*;
|
||||
|
||||
public class CertInvoker extends InvokableResource {
|
||||
private Step step;
|
||||
|
||||
public CertInvoker(Step step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean invoke() throws Exception {
|
||||
File cert = dataToFile(step);
|
||||
if(cert == null) {
|
||||
return false;
|
||||
}
|
||||
return FileUtilities.addToCertList(Constants.ALLOW_FILE, cert) == SUCCESS;
|
||||
}
|
||||
}
|
||||
46
old code/tray/src/qz/installer/provision/invoker/ConfInvoker.java
Executable file
46
old code/tray/src/qz/installer/provision/invoker/ConfInvoker.java
Executable file
@@ -0,0 +1,46 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import qz.build.provision.Step;
|
||||
import qz.common.PropertyHelper;
|
||||
import qz.utils.SystemUtilities;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
|
||||
public class ConfInvoker extends PropertyInvoker {
|
||||
public ConfInvoker(Step step) {
|
||||
super(step, new PropertyHelper(calculateConfPath(step)));
|
||||
}
|
||||
|
||||
public static String calculateConfPath(Step step) {
|
||||
String relativePath = step.getArgs().get(0);
|
||||
if(SystemUtilities.isMac()) {
|
||||
return SystemUtilities.getJarParentPath().
|
||||
resolve("../PlugIns/Java.runtime/Contents/Home/conf").
|
||||
resolve(relativePath).
|
||||
normalize()
|
||||
.toString();
|
||||
} else {
|
||||
return SystemUtilities.getJarParentPath()
|
||||
.resolve("runtime/conf")
|
||||
.resolve(relativePath)
|
||||
.normalize()
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean invoke() {
|
||||
Step step = getStep();
|
||||
// Java uses the same "|" delimiter as we do, only parse one property at a time
|
||||
AbstractMap.SimpleEntry<String, String> pair = parsePropertyPair(step, step.getData());
|
||||
if (!pair.getValue().isEmpty()) {
|
||||
properties.setProperty(pair);
|
||||
if (properties.save()) {
|
||||
log.info("Successfully provisioned '1' '{}'", step.getType());
|
||||
return true;
|
||||
}
|
||||
log.error("An error occurred saving properties '{}' to file", step.getData());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
10
old code/tray/src/qz/installer/provision/invoker/Invokable.java
Executable file
10
old code/tray/src/qz/installer/provision/invoker/Invokable.java
Executable file
@@ -0,0 +1,10 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public interface Invokable {
|
||||
Logger log = LogManager.getLogger(Invokable.class);
|
||||
|
||||
boolean invoke() throws Exception;
|
||||
}
|
||||
63
old code/tray/src/qz/installer/provision/invoker/InvokableResource.java
Executable file
63
old code/tray/src/qz/installer/provision/invoker/InvokableResource.java
Executable file
@@ -0,0 +1,63 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import qz.build.provision.Step;
|
||||
import qz.build.provision.params.Type;
|
||||
import qz.common.Constants;
|
||||
import qz.utils.SystemUtilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
public abstract class InvokableResource implements Invokable {
|
||||
static final Logger log = LogManager.getLogger(InvokableResource.class);
|
||||
|
||||
public static File dataToFile(Step step) throws IOException {
|
||||
Path resourcePath = Paths.get(step.getData());
|
||||
if(resourcePath.isAbsolute() || step.usingPath()) {
|
||||
return pathResourceToFile(step);
|
||||
}
|
||||
if(step.usingClass()) {
|
||||
return classResourceToFile(step);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the resource directly from file
|
||||
*/
|
||||
private static File pathResourceToFile(Step step) {
|
||||
String resourcePath = step.getData();
|
||||
Path dataPath = Paths.get(resourcePath);
|
||||
return dataPath.isAbsolute() ? dataPath.toFile() : step.getRelativePath().resolve(resourcePath).toFile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies resource from JAR to a temp file for use in installation
|
||||
*/
|
||||
private static File classResourceToFile(Step step) throws IOException {
|
||||
// Resource may be inside the jar
|
||||
InputStream in = step.getRelativeClass().getResourceAsStream("resources/" + step.getData());
|
||||
if(in == null) {
|
||||
log.warn("Resource '{}' is missing, skipping step", step.getData());
|
||||
return null;
|
||||
}
|
||||
String suffix = "_" + Paths.get(step.getData()).getFileName().toString();
|
||||
File destination = File.createTempFile(Constants.DATA_DIR + "_provision_", suffix);
|
||||
Files.copy(in, destination.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
IOUtils.closeQuietly(in);
|
||||
|
||||
// Set scripts executable
|
||||
if(step.getType() == Type.SCRIPT && !SystemUtilities.isWindows()) {
|
||||
destination.setExecutable(true, false);
|
||||
}
|
||||
return destination;
|
||||
}
|
||||
}
|
||||
99
old code/tray/src/qz/installer/provision/invoker/PropertyInvoker.java
Executable file
99
old code/tray/src/qz/installer/provision/invoker/PropertyInvoker.java
Executable file
@@ -0,0 +1,99 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import qz.build.provision.Step;
|
||||
import qz.common.Constants;
|
||||
import qz.common.PropertyHelper;
|
||||
import qz.utils.FileUtilities;
|
||||
import qz.utils.SystemUtilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.AbstractMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class PropertyInvoker implements Invokable {
|
||||
private Step step;
|
||||
PropertyHelper properties;
|
||||
|
||||
public PropertyInvoker(Step step, PropertyHelper properties) {
|
||||
this.step = step;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public boolean invoke() {
|
||||
HashMap<String, String> pairs = parsePropertyPairs(step);
|
||||
if (!pairs.isEmpty()) {
|
||||
for(Map.Entry<String, String> pair : pairs.entrySet()) {
|
||||
properties.setProperty(pair);
|
||||
}
|
||||
if (properties.save()) {
|
||||
log.info("Successfully provisioned '{}' '{}'", pairs.size(), step.getType());
|
||||
return true;
|
||||
}
|
||||
log.error("An error occurred saving properties '{}' to file", step.getData());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static PropertyHelper getProperties(Step step) {
|
||||
File propertiesFile;
|
||||
if(step.getRelativePath() != null) {
|
||||
// Assume qz-tray.properties is one directory up from provision folder
|
||||
// required to prevent installing to payload
|
||||
propertiesFile = step.getRelativePath().getParent().resolve(Constants.PROPS_FILE + ".properties").toFile();
|
||||
} else {
|
||||
// If relative path isn't set, fallback to the jar's parent path
|
||||
propertiesFile = SystemUtilities.getJarParentPath(".").resolve(Constants.PROPS_FILE + ".properties").toFile();
|
||||
}
|
||||
log.info("Provisioning '{}' to properties file: '{}'", step.getData(), propertiesFile);
|
||||
return new PropertyHelper(propertiesFile);
|
||||
}
|
||||
|
||||
public static PropertyHelper getPreferences(Step step) {
|
||||
return new PropertyHelper(FileUtilities.USER_DIR + File.separator + Constants.PREFS_FILE + ".properties");
|
||||
}
|
||||
|
||||
public static HashMap<String, String> parsePropertyPairs(Step step) {
|
||||
HashMap<String, String> pairs = new HashMap<>();
|
||||
if(step.getData() != null && !step.getData().trim().isEmpty()) {
|
||||
String[] props = step.getData().split("\\|");
|
||||
for(String prop : props) {
|
||||
AbstractMap.SimpleEntry<String,String> pair = parsePropertyPair(step, prop);
|
||||
if (pair != null) {
|
||||
if(pairs.get(pair.getKey()) != null) {
|
||||
log.warn("Property {} already exists, replacing [before: {}, after: {}] ",
|
||||
pair.getKey(), pairs.get(pair.getKey()), pair.getValue());
|
||||
}
|
||||
pairs.put(pair.getKey(), pair.getValue());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
log.error("Skipping Step '{}', Data is null or empty", step.getType());
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
|
||||
|
||||
public static AbstractMap.SimpleEntry<String, String> parsePropertyPair(Step step, String prop) {
|
||||
if(prop.contains("=")) {
|
||||
String[] pair = prop.split("=", 2);
|
||||
if (!pair[0].trim().isEmpty()) {
|
||||
if (!pair[1].trim().isEmpty()) {
|
||||
return new AbstractMap.SimpleEntry<>(pair[0], pair[1]);
|
||||
} else {
|
||||
log.warn("Skipping '{}' '{}', property value is malformed", step.getType(), prop);
|
||||
}
|
||||
} else {
|
||||
log.warn("Skipping '{}' '{}', property name is malformed", step.getType(), prop);
|
||||
}
|
||||
} else {
|
||||
log.warn("Skipping '{}' '{}', property is malformed", step.getType(), prop);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public Step getStep() {
|
||||
return step;
|
||||
}
|
||||
}
|
||||
100
old code/tray/src/qz/installer/provision/invoker/RemoverInvoker.java
Executable file
100
old code/tray/src/qz/installer/provision/invoker/RemoverInvoker.java
Executable file
@@ -0,0 +1,100 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import qz.build.provision.Step;
|
||||
import qz.build.provision.params.Os;
|
||||
import qz.build.provision.params.types.Remover;
|
||||
import qz.utils.ShellUtilities;
|
||||
import qz.utils.SystemUtilities;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class RemoverInvoker extends InvokableResource {
|
||||
private Step step;
|
||||
private String aboutTitle; // e.g. "QZ Tray"
|
||||
private String propsFile; // e.g. "qz-tray"
|
||||
private String dataDir; // e.g. "qz"
|
||||
|
||||
|
||||
public RemoverInvoker(Step step) {
|
||||
this.step = step;
|
||||
Remover remover = Remover.parse(step.getData());
|
||||
if(remover == Remover.CUSTOM) {
|
||||
// Fields are comma delimited in the data field
|
||||
parseCustomFromData(step.getData());
|
||||
} else {
|
||||
aboutTitle = remover.getAboutTitle();
|
||||
propsFile = remover.getPropsFile();
|
||||
dataDir = remover.getDataDir();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean invoke() throws Exception {
|
||||
ArrayList<String> command = getRemoveCommand();
|
||||
if(command.size() == 0) {
|
||||
log.info("An existing installation of '{}' was not found. Skipping.", aboutTitle);
|
||||
return true;
|
||||
}
|
||||
boolean success = ShellUtilities.execute(command.toArray(new String[command.size()]));
|
||||
if(!success) {
|
||||
log.error("An error occurred invoking [{}]", step.getData());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
public void parseCustomFromData(String data) {
|
||||
String[] parts = data.split(",");
|
||||
aboutTitle = parts[0].trim();
|
||||
propsFile = parts[1].trim();
|
||||
dataDir = parts[2].trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the installer command (including the installer itself and if needed, arguments) to
|
||||
* invoke the installer file
|
||||
*/
|
||||
public ArrayList<String> getRemoveCommand() {
|
||||
ArrayList<String> removeCmd = new ArrayList<>();
|
||||
Os os = SystemUtilities.getOs();
|
||||
switch(os) {
|
||||
case WINDOWS:
|
||||
Path win = Paths.get(System.getenv("PROGRAMFILES"))
|
||||
.resolve(aboutTitle)
|
||||
.resolve("uninstall.exe");
|
||||
|
||||
if(win.toFile().exists()) {
|
||||
removeCmd.add(win.toString());
|
||||
removeCmd.add("/S");
|
||||
break;
|
||||
}
|
||||
case MAC:
|
||||
Path legacy = Paths.get("/Applications")
|
||||
.resolve(aboutTitle + ".app")
|
||||
.resolve("Contents")
|
||||
.resolve("uninstall");
|
||||
|
||||
Path mac = Paths.get("/Applications")
|
||||
.resolve(aboutTitle + ".app")
|
||||
.resolve("Contents")
|
||||
.resolve("Resources")
|
||||
.resolve("uninstall");
|
||||
|
||||
if(legacy.toFile().exists()) {
|
||||
removeCmd.add(legacy.toString());
|
||||
} else if(mac.toFile().exists()) {
|
||||
removeCmd.add(mac.toString());
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Path linux = Paths.get("/opt")
|
||||
.resolve(propsFile)
|
||||
.resolve("uninstall");
|
||||
if(linux.toFile().exists()) {
|
||||
removeCmd.add(linux.toString());
|
||||
}
|
||||
}
|
||||
return removeCmd;
|
||||
}
|
||||
}
|
||||
19
old code/tray/src/qz/installer/provision/invoker/ResourceInvoker.java
Executable file
19
old code/tray/src/qz/installer/provision/invoker/ResourceInvoker.java
Executable file
@@ -0,0 +1,19 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import qz.build.provision.Step;
|
||||
|
||||
/**
|
||||
* Stub class for deploying an otherwise "action-less" resource, only to be used by other tasks
|
||||
*/
|
||||
public class ResourceInvoker extends InvokableResource {
|
||||
private Step step;
|
||||
|
||||
public ResourceInvoker(Step step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean invoke() throws Exception {
|
||||
return dataToFile(step) != null;
|
||||
}
|
||||
}
|
||||
77
old code/tray/src/qz/installer/provision/invoker/ScriptInvoker.java
Executable file
77
old code/tray/src/qz/installer/provision/invoker/ScriptInvoker.java
Executable file
@@ -0,0 +1,77 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import qz.build.provision.Step;
|
||||
import qz.build.provision.params.Os;
|
||||
import qz.build.provision.params.types.Script;
|
||||
import qz.utils.ShellUtilities;
|
||||
import qz.utils.SystemUtilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ScriptInvoker extends InvokableResource {
|
||||
private Step step;
|
||||
|
||||
public ScriptInvoker(Step step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean invoke() throws Exception {
|
||||
File script = dataToFile(step);
|
||||
if(script == null) {
|
||||
return false;
|
||||
}
|
||||
Script engine = Script.parse(step.getData());
|
||||
ArrayList<String> command = getInterpreter(engine);
|
||||
if(command.isEmpty() && SystemUtilities.isWindows()) {
|
||||
log.warn("No interpreter found for {}, skipping", step.getData());
|
||||
return false;
|
||||
}
|
||||
command.add(script.toString());
|
||||
boolean success = ShellUtilities.execute(command.toArray(new String[command.size()]));
|
||||
if(!success) {
|
||||
log.error("An error occurred invoking [{}]", step.getData());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the interpreter command (and if needed, arguments) to invoke the script file
|
||||
*
|
||||
* An empty array will fall back to Unix "shebang" notation, e.g. #!/usr/bin/python3
|
||||
* which will allow the OS to select the correct interpreter for the given file
|
||||
*
|
||||
* No special attention is given to "shebang", behavior may differ between OSs
|
||||
*/
|
||||
private static ArrayList<String> getInterpreter(Script engine) {
|
||||
ArrayList<String> interpreter = new ArrayList<>();
|
||||
Os osType = SystemUtilities.getOs();
|
||||
switch(engine) {
|
||||
case PS1:
|
||||
if(osType == Os.WINDOWS) {
|
||||
interpreter.add("powershell.exe");
|
||||
} else if(osType == Os.MAC) {
|
||||
interpreter.add("/usr/local/bin/pwsh");
|
||||
} else {
|
||||
interpreter.add("pwsh");
|
||||
}
|
||||
interpreter.add("-File");
|
||||
break;
|
||||
case PY:
|
||||
interpreter.add(osType == Os.WINDOWS ? "python3.exe" : "python3");
|
||||
break;
|
||||
case BAT:
|
||||
interpreter.add(osType == Os.WINDOWS ? "cmd.exe" : "wineconsole");
|
||||
break;
|
||||
case RB:
|
||||
interpreter.add(osType == Os.WINDOWS ? "ruby.exe" : "ruby");
|
||||
break;
|
||||
case SH:
|
||||
default:
|
||||
// Allow the environment to parse it from the shebang at invocation time
|
||||
}
|
||||
return interpreter;
|
||||
}
|
||||
}
|
||||
87
old code/tray/src/qz/installer/provision/invoker/SoftwareInvoker.java
Executable file
87
old code/tray/src/qz/installer/provision/invoker/SoftwareInvoker.java
Executable file
@@ -0,0 +1,87 @@
|
||||
package qz.installer.provision.invoker;
|
||||
|
||||
import qz.build.provision.Step;
|
||||
import qz.build.provision.params.Os;
|
||||
import qz.build.provision.params.types.Software;
|
||||
import qz.utils.ShellUtilities;
|
||||
import qz.utils.SystemUtilities;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class SoftwareInvoker extends InvokableResource {
|
||||
private Step step;
|
||||
|
||||
public SoftwareInvoker(Step step) {
|
||||
this.step = step;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean invoke() throws Exception {
|
||||
File payload = dataToFile(step);
|
||||
if(payload == null) {
|
||||
return false;
|
||||
}
|
||||
Software installer = Software.parse(step.getData());
|
||||
ArrayList<String> command = getInstallCommand(installer, step.getArgs(), payload);
|
||||
boolean success = ShellUtilities.execute(command.toArray(new String[command.size()]), payload.getParentFile());
|
||||
if(!success) {
|
||||
log.error("An error occurred invoking [{}]", step.getData());
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the installer command (including the installer itself and if needed, arguments) to
|
||||
* invoke the installer file
|
||||
*/
|
||||
public ArrayList<String> getInstallCommand(Software installer, List<String> args, File payload) {
|
||||
ArrayList<String> interpreter = new ArrayList<>();
|
||||
Os os = SystemUtilities.getOs();
|
||||
switch(installer) {
|
||||
case EXE:
|
||||
if(!SystemUtilities.isWindows()) {
|
||||
interpreter.add("wine");
|
||||
}
|
||||
// Executable on its own
|
||||
interpreter.add(payload.toString());
|
||||
interpreter.addAll(args); // Assume exe args come after payload
|
||||
break;
|
||||
case MSI:
|
||||
interpreter.add(os == Os.WINDOWS ? "msiexec.exe" : "msiexec");
|
||||
interpreter.add("/i"); // Assume standard install
|
||||
interpreter.add(payload.toString());
|
||||
interpreter.addAll(args); // Assume msiexec args come after payload
|
||||
break;
|
||||
case PKG:
|
||||
if(os == Os.MAC) {
|
||||
interpreter.add("installer");
|
||||
interpreter.addAll(args); // Assume installer args come before payload
|
||||
interpreter.add("-package");
|
||||
interpreter.add(payload.toString());
|
||||
interpreter.add("-target");
|
||||
interpreter.add("/"); // Assume we don't want this on a removable volume
|
||||
} else {
|
||||
throw new UnsupportedOperationException("PKG is not yet supported on this platform");
|
||||
}
|
||||
break;
|
||||
case DMG:
|
||||
// DMG requires "hdiutil attach", but the mount point is unknown
|
||||
throw new UnsupportedOperationException("DMG is not yet supported");
|
||||
case RUN:
|
||||
if(SystemUtilities.isWindows()) {
|
||||
interpreter.add("bash");
|
||||
interpreter.add("-c");
|
||||
}
|
||||
interpreter.add(payload.toString());
|
||||
interpreter.addAll(args); // Assume run args come after payload
|
||||
// Executable on its own
|
||||
break;
|
||||
default:
|
||||
// We'll try to parse it from the shebang just before invocation time
|
||||
}
|
||||
return interpreter;
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user