Improves Gradle's ability to update browser addons

This commit is contained in:
Markil3
2021-09-14 10:53:01 -06:00
parent 91980aac75
commit 3eab100a08
5 changed files with 185 additions and 133 deletions

View File

@@ -10,10 +10,7 @@ configurations {
canBeConsumed = true canBeConsumed = true
canBeResolved = false canBeResolved = false
} }
nativeApp { nativeApp.extendsFrom runtime
canBeConsumed = false
canBeResolved = true
}
} }
/** /**
@@ -21,7 +18,9 @@ configurations {
*/ */
interface ExtensionData { interface ExtensionData {
Property<String> getName() Property<String> getName()
Property<String> getDescription() Property<String> getDescription()
Property<String> getId() Property<String> getId()
} }
@@ -30,14 +29,117 @@ extension.name = "universalmusic"
extension.description = "A link between the Universal Music Player and the web browser." extension.description = "A link between the Universal Music Player and the web browser."
extension.id = "universalmusic@regis.edu" extension.id = "universalmusic@regis.edu"
/**
* Creates an addon manifest for running
*/
abstract class BuildManifest extends DefaultTask {
@OutputFile
final abstract RegularFileProperty manifests = project.objects.fileProperty()
@TaskAction
void join() {
println "Making build directories!"
String addonName = project.extension.name.get(), addonDescription = project.extension.description.get(), extensionId = project.extension.id.get()
File manifest
File startupScript
for (Dependency dep : project.configurations.nativeApp.dependencies) {
File binFiles = new File(dep.dependencyProject.installDist.outputs.getFiles().getSingleFile(), "bin")
Stream<File> files = Arrays.stream(binFiles.listFiles())
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
startupScript = files.filter(file -> file.getName().endsWith(".bat")).findFirst().get()
} else if (Os.isFamily(Os.FAMILY_UNIX)) {
startupScript = files.filter(file -> !file.getName().endsWith(".sh")).findFirst().get()
} else {
throw new RuntimeException("Unknown OS family")
}
manifests.get().asFile.text = "{\n" +
" \"name\": \"$addonName\",\n" +
" \"description\": \"$addonDescription\",\n" +
" \"path\": \"" + startupScript.getAbsolutePath().replace("\\", "\\\\") + "\",\n" +
" \"type\": \"stdio\",\n" +
" \"allowed_extensions\": [\"$extensionId\"]\n" +
"}"
break
}
}
}
/**
*
*/
abstract class InstallAddon extends DefaultTask {
@InputFile
@SkipWhenEmpty
final abstract RegularFileProperty inputFile = project.objects.fileProperty()
@TaskAction
void join() {
File file = inputFile.get().asFile
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
String name = file.name.substring(0, file.name.lastIndexOf('.'))
Process p = Runtime.getRuntime()
.exec("REG DELETE HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /f ")
p.waitFor()
p = Runtime.getRuntime()
.exec("REG ADD HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /ve /d \""
+ file.getAbsolutePath() + "\" /f ")
p.waitFor()
} else if (Os.isFamily(Os.FAMILY_MAC)) {
Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), "Library/Application Support/Mozilla/NativeMessagingHosts", file.getName()), StandardCopyOption.REPLACE_EXISTING)
} else if (Os.isFamily(Os.FAMILY_UNIX)) {
Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), ".mozilla/native-messaging-hosts", file.getName()), StandardCopyOption.REPLACE_EXISTING)
}
}
}
dependencies {
nativeApp project(path: ":addonInter", configuration: 'nativeBuild')
}
tasks.register('buildManifest', BuildManifest) {
manifests = new File(buildDir, "${extension.name.get()}.json")
}
def installAddon = tasks.register('installAddon', InstallAddon) {
inputFile = buildManifest.manifests
}
/** /**
* Creates a packaged (albiet unsigned) Firefox addon from the src/main directory. * Creates a packaged (albiet unsigned) Firefox addon from the src/main directory.
*/ */
tasks.register('zipAddon', Zip) { tasks.register('zipAddon', Zip) {
dependsOn configurations.nativeApp
archiveName = "${extension.id.get()}.xpi" archiveName = "${extension.id.get()}.xpi"
destinationDir = file("$buildDir/lib") destinationDir = file("$buildDir/lib")
from("$projectDir/src/addon/javascript", "$projectDir/src/addon/resources") from("$projectDir/src/addon/javascript", "$projectDir/src/addon/resources")
doLast {
File profiles
File extention
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
profiles = new File(System.getenv("APPDATA"), "Mozilla\\Firefox\\Profiles")
} else if (Os.isFamily(Os.FAMILY_MAC)) {
profiles = new File(System.getProperty("user.home"), "Library/Application Support/Firefox/Profiles")
} else if (Os.isFamily(Os.FAMILY_UNIX)) {
profiles = new File(System.getProperty("user.home"), ".mozilla/firefox/")
} }
for (File profile: profiles.listFiles())
{
if (profile.isDirectory())
{
extention = new File(profile, "extensions/${extension.id.get()}.xpi")
if (extention.exists())
{
copy {
from(zipAddon.outputs)
into extention.getParentFile()
}
}
}
}
}
}
zipAddon.finalizedBy installAddon
tasks.register("clean", Delete) { tasks.register("clean", Delete) {
delete "$buildDir" delete "$buildDir"

View File

@@ -16,9 +16,9 @@ plugins {
} }
configurations { configurations {
addon { nativeBuild {
canBeConsumed = false canBeConsumed = true
canBeResolved = true canBeResolved = false
} }
} }
@@ -30,84 +30,6 @@ repositories {
} }
} }
/**
* Creates an addon manifest for running
*/
abstract class BuildManifest extends DefaultTask {
@InputDirectory
final abstract DirectoryProperty inputFile = project.objects.directoryProperty()
@OutputDirectory
final abstract DirectoryProperty manifestDir = project.objects.directoryProperty().convention(project.layout.buildDirectory.dir("manifests"))
@OutputFiles
final abstract FileCollection manifests = project.objects.fileCollection()
@TaskAction
void join() {
manifestDir.get().asFile.mkdir()
println "Making build directories!"
String addonName, addonDescription, extensionId
File manifest
File startupScript
File binFiles = new File(inputFile.get().asFile, "bin")
Stream<File> files = Arrays.stream(binFiles.listFiles())
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
startupScript = files.filter(file -> file.getName().endsWith(".bat")).findFirst().get()
} else if (Os.isFamily(Os.FAMILY_UNIX)) {
startupScript = files.filter(file -> !file.getName().endsWith(".sh")).findFirst().get()
} else {
throw new RuntimeException("Unknown OS family")
}
HashSet<File> manifestSet = new HashSet<>()
for (Dependency dep : project.configurations.addon.dependencies) {
addonName = dep.dependencyProject.extension.name.get()
addonDescription = dep.dependencyProject.extension.description.get()
extensionId = dep.dependencyProject.extension.id.get()
manifest = manifestDir.get().file("${addonName}.json").asFile
manifest.createNewFile()
println manifest
manifest.text = "{\n" +
" \"name\": \"$addonName\",\n" +
" \"description\": \"$addonDescription\",\n" +
" \"path\": \"" + startupScript.getAbsolutePath().replace("\\", "\\\\") + "\",\n" +
" \"type\": \"stdio\",\n" +
" \"allowed_extensions\": [\"$extensionId\"]\n" +
"}"
manifestSet.add(manifest)
}
manifests.setFrom(manifestSet)
println manifests.files
}
}
/**
*
*/
abstract class InstallAddon extends DefaultTask {
@InputDirectory
final abstract DirectoryProperty inputFile = project.objects.directoryProperty()
@TaskAction
void join() {
// File file = inputFile.get().asFile
for (File file: inputFile.asFileTree) {
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
String name = file.name.substring(0, file.name.lastIndexOf('.'))
Process p = Runtime.getRuntime()
.exec("REG DELETE HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /f ")
p.waitFor()
p = Runtime.getRuntime()
.exec("REG ADD HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /ve /d \""
+ file.getAbsolutePath() + "\" /f ")
p.waitFor()
} else if (Os.isFamily(Os.FAMILY_MAC)) {
Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), "Library/Application Support/Mozilla/NativeMessagingHosts", file.getName()), StandardCopyOption.REPLACE_EXISTING)
} else if (Os.isFamily(Os.FAMILY_UNIX)) {
Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), ".mozilla/native-messaging-hosts", file.getName()), StandardCopyOption.REPLACE_EXISTING)
}
}
}
}
// In this section you declare the dependencies for your production and test code // In this section you declare the dependencies for your production and test code
dependencies { dependencies {
implementation 'org.slf4j:slf4j-api:1.7.30' implementation 'org.slf4j:slf4j-api:1.7.30'
@@ -126,19 +48,13 @@ dependencies {
// testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add
// 'test.useTestNG()' to your build script. // 'test.useTestNG()' to your build script.
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
addon(project(":add-on"))
} }
tasks.register('buildManifest', BuildManifest) {
dependsOn installDist
inputFile = installDist.outputs.getFiles().getSingleFile()
}
tasks.register('installAddon', InstallAddon) {
inputFile = buildManifest.manifestDir
}
assemble.dependsOn(installAddon)
// Define the main class for the application // Define the main class for the application
mainClassName = defaultPackage + '.addon.Main' mainClassName = defaultPackage + '.addon.Main'
artifacts {
nativeBuild(installDist.destinationDir) {
builtBy installDist
}
}

View File

@@ -15,6 +15,9 @@
"Fingerprinting": true "Fingerprinting": true
}, },
"DontCheckDefaultBrowser": true, "DontCheckDefaultBrowser": true,
"ExtensionSettings": {
${preinstalled}
},
"Permissions": { "Permissions": {
"Camera": { "Camera": {
"BlockNewRequests": true "BlockNewRequests": true

View File

@@ -217,6 +217,22 @@ task movePolicies(type: Copy) {
dependsOn setupProfile dependsOn setupProfile
from files("browserConf") from files("browserConf")
into "$rootDir/firefox/" into "$rootDir/firefox/"
filesMatching('**/policies.json'){
def pre = ""
for (File addon: configurations.addon.resolve())
{
if (pre.length() > 0)
{
pre += ",\n"
}
pre += "\"" + addon.name.substring(0, addon.name.lastIndexOf('.')) + "\": {\n"
pre += "\"installation_mode\": \"forced_install\","
pre += "\"install_url\": \"" + addon.toURI().toString() + "\""
pre += "}"
}
println "Expanding ${pre}"
expand(preinstalled: pre)
}
doLast { doLast {
println "Making policies firefox!" println "Making policies firefox!"
} }

View File

@@ -8,7 +8,9 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
import java.io.PrintStream;
import java.net.ConnectException; import java.net.ConnectException;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.ServerSocket; import java.net.ServerSocket;
@@ -44,7 +46,8 @@ public class Browser extends MessageRunner
return INSTANCE; return INSTANCE;
} }
ServerSocket server = new ServerSocket(BrowserConstants.PORT, 50, InetAddress.getByName(null)); ServerSocket server = new ServerSocket(BrowserConstants.PORT, 50, InetAddress
.getByName(null));
logger.debug("Server started."); logger.debug("Server started.");
int startExit; int startExit;
@@ -58,7 +61,8 @@ public class Browser extends MessageRunner
if (startExit != 0) if (startExit != 0)
{ {
logger.error("Error in browser launch (exit code {})", startExit); logger.error("Error in browser launch (exit code {})", startExit);
try (Scanner scanner = new Scanner(browserProcess.getErrorStream())) try (Scanner scanner = new Scanner(browserProcess
.getErrorStream()))
{ {
while (scanner.hasNextLine()) while (scanner.hasNextLine())
{ {
@@ -105,7 +109,8 @@ public class Browser extends MessageRunner
private Browser(Socket socket, ServerSocket server, Process process) throws IOException private Browser(Socket socket, ServerSocket server, Process process) throws IOException
{ {
super("BrowserRunner", socket.getInputStream(), socket.getOutputStream()); super("BrowserRunner", socket.getInputStream(), socket
.getOutputStream());
this.socket = socket; this.socket = socket;
this.server = server; this.server = server;
this.process = process; this.process = process;
@@ -114,7 +119,8 @@ public class Browser extends MessageRunner
@Override @Override
protected boolean onRun() protected boolean onRun()
{ {
if (!socket.isConnected() || socket.isClosed() || socket.isInputShutdown() || socket.isOutputShutdown()) if (!socket.isConnected() || socket.isClosed() || socket
.isInputShutdown() || socket.isOutputShutdown())
{ {
logger.debug("Socket closed, shutting down"); logger.debug("Socket closed, shutting down");
return true; return true;
@@ -154,37 +160,46 @@ public class Browser extends MessageRunner
/** /**
* Utility method for launching a browser instance * Utility method for launching a browser instance
* *
* @throws IOException - Thrown if there is a problem launching the browser. * @throws IOException - Thrown if there is a problem launching the
* browser.
*/ */
private static Process launchBrowser() throws IOException private static Process launchBrowser() throws IOException, InterruptedException
{ {
Process process = null; Process process = null;
String os = System.getProperty("os.name").toLowerCase(); String os = System.getProperty("os.name").toLowerCase();
String arch = System.getProperty("os.arch").toLowerCase(); String arch = System.getProperty("os.arch").toLowerCase();
String args; String args;
File browserDir = new File(System.getProperty("user.dir"), "firefox"); File browserDir = new File(System.getProperty("user.dir"), "firefox");
File profileDir = new File(System.getProperty("user.dir"), "profile");
profileDir.mkdir();
if (!browserDir.isDirectory()) if (!browserDir.isDirectory())
{ {
/* browserDir = new File(new File(System.getProperty("user.dir"))
* For some reason, the above maps to the interface project module, rather than the root project. .getParent(), "firefox");
*/ }
browserDir = new File(new File(System.getProperty("user.dir")).getParent(), "firefox"); File profileDir = new File(System.getProperty("user.dir"), "profile");
if (!profileDir.exists())
{
profileDir.mkdir();
} }
// args = " -profile \"" + profileDir.getAbsolutePath() + "\""; // args = " -no-remote -profile \"" + profileDir.getAbsolutePath() + "\"";
args = ""; args = " -no-remote -P Universal";
System.out.println(profileDir);
logger.info("Running on {} {}", os, arch); logger.info("Running on {} {}", os, arch);
// System.getProperties().entrySet().stream().forEach(entry -> logger.info("{}: {}", entry.getKey(), entry.getValue())); // System.getProperties().entrySet().stream().forEach(entry -> logger.info("{}: {}", entry.getKey(), entry.getValue()));
File firefox = null;
if (os.contains("windows")) if (os.contains("windows"))
{ {
process = Runtime.getRuntime().exec(new File(browserDir, "firefox.exe").getAbsolutePath() + args); firefox = new File(browserDir, "firefox.exe");
} }
else if (os.contains("linux")) else if (os.contains("linux"))
{ {
process = Runtime.getRuntime().exec(new File(browserDir, "firefox").getAbsolutePath() + args); firefox = new File(browserDir, "firefox");
}
if (firefox != null)
{
firefox = firefox.getAbsoluteFile();
Runtime.getRuntime().exec(firefox + " -CreateProfile Universal").waitFor();
process = Runtime.getRuntime().exec(firefox
.getAbsolutePath() + args);
} }
if (process == null) if (process == null)
{ {