diff --git a/add-on/build.gradle b/add-on/build.gradle new file mode 100644 index 0000000..1a0f8de --- /dev/null +++ b/add-on/build.gradle @@ -0,0 +1,49 @@ +import org.apache.tools.ant.taskdefs.condition.Os + +import java.nio.file.Files +import java.nio.file.Paths +import java.nio.file.StandardCopyOption +import java.util.stream.Stream + +configurations { + addonBuild { + canBeConsumed = true + canBeResolved = false + } + nativeApp { + canBeConsumed = false + canBeResolved = true + } +} + +/** + * Contains information on the extension being made + */ +interface ExtensionData { + Property getName() + Property getDescription() + Property getId() +} + +def extension = project.extensions.create('extension', ExtensionData) +extension.name = "universalmusic" +extension.description = "A link between the Universal Music Player and the web browser." +extension.id = "universalmusic@regis.edu" + +/** + * Creates a packaged (albiet unsigned) Firefox addon from the src/main directory. + */ +tasks.register('zipAddon', Zip) { + archiveName = "${extension.id.get()}.xpi" + destinationDir = file("$buildDir/lib") + from("$projectDir/src/addon/javascript", "$projectDir/src/addon/resources") +} + +tasks.register("clean", Delete) { + delete "$buildDir" + followSymlinks = false +} + +artifacts { + addonBuild(zipAddon) +} diff --git a/add-on/background.js b/add-on/src/addon/javascript/background.js similarity index 100% rename from add-on/background.js rename to add-on/src/addon/javascript/background.js diff --git a/add-on/foreground.js b/add-on/src/addon/javascript/foreground.js similarity index 100% rename from add-on/foreground.js rename to add-on/src/addon/javascript/foreground.js diff --git a/add-on/youtube.js b/add-on/src/addon/javascript/youtube.js similarity index 100% rename from add-on/youtube.js rename to add-on/src/addon/javascript/youtube.js diff --git a/add-on/icon.svg b/add-on/src/addon/resources/icon.svg similarity index 100% rename from add-on/icon.svg rename to add-on/src/addon/resources/icon.svg diff --git a/add-on/manifest.json b/add-on/src/addon/resources/manifest.json similarity index 100% rename from add-on/manifest.json rename to add-on/src/addon/resources/manifest.json diff --git a/addonInter/build.gradle b/addonInter/build.gradle index 93d036c..f41a1e4 100644 --- a/addonInter/build.gradle +++ b/addonInter/build.gradle @@ -1,20 +1,25 @@ -/* - * Copyright (c) 2021 William Hubbard. All Rights Reserved. - */ - - -import java.nio.file.CopyOption -import java.nio.file.Files -import java.nio.file.Path import org.apache.tools.ant.taskdefs.condition.Os +import java.lang.reflect.Method +import java.nio.file.Files import java.nio.file.Paths import java.nio.file.StandardCopyOption import java.util.stream.Stream +/* + * Copyright (c) 2021 William Hubbard. All Rights Reserved. + */ plugins { id 'java' id 'application' +// id 'regis.browser-addon' +} + +configurations { + addon { + canBeConsumed = false + canBeResolved = true + } } // In this section you declare where to find the dependencies of your project @@ -25,6 +30,84 @@ 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 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 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 dependencies { implementation 'org.slf4j:slf4j-api:1.7.30' @@ -43,76 +126,19 @@ dependencies { // testCompile dependency to testCompile 'org.testng:testng:6.8.1' and add // 'test.useTestNG()' to your build script. testImplementation 'junit:junit:4.12' + + addon(project(":add-on")) } -abstract class BuildManifest extends DefaultTask { - @InputDirectory - final abstract DirectoryProperty inputFile = project.objects.directoryProperty() - @OutputFile - final abstract RegularFileProperty outputFile = project.objects.fileProperty().convention(project.layout.buildDirectory.file("universalmusic.json")) - - @TaskAction - void join() { - File startupScript - File binFiles = new File(inputFile.get().asFile, "bin") - print binFiles - Stream 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") - } - outputFile.get().asFile.text = "{\n" + - " \"name\": \"universalmusic\",\n" + - " \"description\": \"A link between the Universal Music Player and the web browser.\",\n" + - " \"path\": \"" + startupScript.getAbsolutePath().replace("\\", "\\\\") + "\",\n" + - " \"type\": \"stdio\",\n" + - " \"allowed_extensions\": [\"universalmusic@regis.edu\"]\n" + - "}" - } +tasks.register('buildManifest', BuildManifest) { + dependsOn installDist + inputFile = installDist.outputs.getFiles().getSingleFile() } -TaskProvider buildManifestP = tasks.register("buildManifest", BuildManifest) { - inputFile = tasks.named("installDist", Sync).get().destinationDir +tasks.register('installAddon', InstallAddon) { + inputFile = buildManifest.manifestDir } - -buildManifest.dependsOn(installDist) - -abstract class InstallAddon extends DefaultTask { - @InputFile - final abstract RegularFileProperty inputFile = project.objects.fileProperty() - - @TaskAction - void join() { - if (Os.isFamily(Os.FAMILY_WINDOWS)) { - Process p = Runtime.getRuntime() - .exec("REG DELETE HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\universalmusic /f ") - p.waitFor() - p = Runtime.getRuntime() - .exec("REG ADD HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\universalmusic /ve /d \"" - + inputFile.get().asFile.getAbsolutePath() + "\" /f ") - p.waitFor() - } - else if (Os.isFamily(Os.FAMILY_MAC)) { - Files.copy(inputFile.get().asFile.toPath(), Paths.get(System.getProperty("user.home"), "Library/Application Support/Mozilla/NativeMessagingHosts", inputFile.get().asFile.getName())) - } - else if (Os.isFamily(Os.FAMILY_UNIX)) { - Files.copy(inputFile.get().asFile.toPath(), Paths.get(System.getProperty("user.home"), ".mozilla/native-messaging-hosts", inputFile.get().asFile.getName())) - } - } -} - -TaskProvider installAddonP = tasks.register("installAddon", InstallAddon) { - inputFile = buildManifestP.get().outputFile -} - -installAddon.dependsOn(buildManifest) - -run.dependsOn(installAddon) +assemble.dependsOn(installAddon) // Define the main class for the application mainClassName = defaultPackage + '.addon.Main' diff --git a/browser/build.gradle b/browser/build.gradle index a765789..b292ad5 100644 --- a/browser/build.gradle +++ b/browser/build.gradle @@ -4,11 +4,20 @@ import org.apache.tools.ant.taskdefs.condition.Os +import java.util.stream.Stream + plugins { id 'java' id "de.undercouch.download" version "4.1.2" } +configurations { + addon { + canBeConsumed = false + canBeResolved = true + } +} + // In this section you declare where to find the dependencies of your project repositories { mavenCentral() @@ -36,39 +45,21 @@ repositories { } } -abstract class WriteBat extends DefaultTask { - @Input - final abstract Property command = project.objects.property(String) - @OutputFile - final abstract RegularFileProperty outputFile = project.objects.fileProperty().convention(project.layout.buildDirectory.file('install.bat')) - - @TaskAction - void join() { - outputFile.get().asFile.text = command.get() - } -} - def firefox_module = "devedition" def firefox_revision = "92.0b7" -task bundleAddOn(type: Zip) { - setArchiveName "universalmusic@regis.edu.xpi" - setDestinationDir file("$rootDir/firefox/distribution/extensions") - from (files("$rootDir/add-on")) +abstract class InstallBrowserTask extends DefaultTask { + @OutputFile + final abstract DirectoryProperty installation = project.objects.directoryProperty() } -task movePolicies(type: Copy) { - from files("browserConf") - into "$rootDir/firefox/" -} - -task setupProfile { - doFirst { - mkdir "$rootDir/firefox/distribution" - mkdir "$rootDir/firefox/distribution/extensions" - } - finalizedBy movePolicies - finalizedBy bundleAddOn +dependencies { + implementation 'org.slf4j:slf4j-api:1.7.30' + implementation 'org.apache.logging.log4j:log4j-api:2.13.3' + implementation 'org.apache.logging.log4j:log4j-core:2.13.3' + implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.13.3' + implementation project(":browserCommands") + addon project(path: ":add-on", configuration: 'addonBuild') } task downloadWindows_x86_64(type: Download) { @@ -102,24 +93,22 @@ task downloadLinux_i686(type: Download) { task installWindows_x86_64(dependsOn: downloadWindows_x86_64, type: Exec) { workingDir layout.buildDirectory commandLine 'msiexec', '/i', '"' + downloadWindows_x86_64.dest + '"', '/li', '"install.log"', '/qb', "INSTALL_DIRECTORY_PATH=\"$rootDir\\firefox\"", 'TASKBAR_SHORTCUT=false', 'DESKTOP_SHORTCUT=false', 'INSTALL_MAINTENANCE_SERVICE=false' - outputs.file("$rootDir\\firefox\\firefox.exe") + it.outputs.dir("$rootDir\\firefox") } //installWindows_x86_64.onlyIf { !layout.buildDirectory.file("browser/firefox.exe").get().asFile.exists() } installWindows_x86_64.doFirst { println "Administrator privileges needed for installing Firefox. Please confirm on the popup." } -installWindows_x86_64.finalizedBy setupProfile task installWindows_x86(dependsOn: downloadWindows_x86, type: Exec) { workingDir layout.buildDirectory commandLine 'msiexec', '/i', '"' + downloadWindows_x86.dest + '"', '/li', '"install.log"', '/qb', "INSTALL_DIRECTORY_PATH=\"$rootDir/firefox\"", 'TASKBAR_SHORTCUT=false', 'DESKTOP_SHORTCUT=false', 'INSTALL_MAINTENANCE_SERVICE=false' - outputs.file("$rootDir\\firefox\\firefox.exe") + it.outputs.dir("$rootDir\\firefox") } //installWindows_x86.onlyIf { !layout.buildDirectory.file("browser/firefox.exe").get().asFile.exists() } installWindows_x86.doFirst { println "Administrator privileges needed for installing Firefox. Please confirm on the popup." } -installWindows_x86.finalizedBy setupProfile task deleteFirefoxWindows(type: Delete) { delete "$rootDir/firefox" @@ -136,71 +125,117 @@ uninstallFirefoxWindows.doFirst { uninstallFirefoxWindows.finalizedBy deleteFirefoxWindows task installLinux_x86_64(dependsOn: downloadLinux_x86_64, type: Copy) { - from tarTree(downloadLinux_x86_64.dest) + from(tarTree(downloadLinux_x86_64.dest)) { + include "firefox/**" + eachFile { fcd -> + fcd.relativePath = new RelativePath(true, fcd.relativePath.segments.drop(1)) + } + } into "$rootDir/firefox" +// outputs.dir(new File(rootDir, "firefox")) } -installLinux_x86_64.finalizedBy setupProfile task installLinux_i686(dependsOn: downloadLinux_i686, type: Copy) { - from tarTree(downloadLinux_i686.dest) + from(tarTree(downloadLinux_i686.dest)) { + include "firefox/**" + eachFile { fcd -> + fcd.relativePath = new RelativePath(true, fcd.relativePath.segments.drop(1)) + } + } into "$rootDir/firefox" + outputs.dir("$rootDir/firefox") +} + +task installFirefox() { + if (Os.isFamily(Os.FAMILY_WINDOWS)) + { + if (Os.isArch("x86_64") || Os.isArch("amd64")) + { + print("Windows x86_64") + dependsOn installWindows_x86_64 + outputs.dir(installWindows_x86_64.getOutputs()) + } + else if (Os.isArch("x86") || Os.isArch("i386") || Os.isArch("i686")) + { + print("Windows x86") + dependsOn installWindows_x86 + outputs.dir(installWindows_x86.getOutputs()) + } + else + { + printf("Unknown windows architecture %s!\n", System.getProperty("os.arch")) + } + } + else if (Os.isFamily(Os.FAMILY_MAC)) + { + print("Mac") + processResources.finalizedBy { + api "firefox:devedition:92.0b7:mac@dmg" + } + } + else if (Os.isFamily(Os.FAMILY_UNIX)) + { + if (Os.isArch("x86_64") || Os.isArch("amd64")) + { + dependsOn installLinux_x86_64 + outputs.dir(installLinux_x86_64.getOutputs().getFiles().getSingleFile()) + } + else if (Os.isArch("x86") || Os.isArch("i386") || Os.isArch("i686")) + { + dependsOn installLinux_i686 + outputs.dir(installLinux_i686.getOutputs()) + } + else + { + printf("Unknown Linux architecture %s!\n", System.getProperty("os.arch")) + } + } + else + { + printf("Unknown operating system %s!\n", System.getProperty("os.name")) + } + onlyIf { + return !new File(rootDir, 'firefox').isDirectory() + } +} + +task setupProfile { + dependsOn installFirefox + doFirst { + for (File file : installFirefox.getOutputs().getFiles().getFiles()) { + println file + } + mkdir "${installFirefox.getOutputs().getFiles().getSingleFile()}/distribution" + mkdir "${installFirefox.getOutputs().getFiles().getSingleFile()}/distribution/extensions" + } + doLast { + println "Setting up profile!" + } +} + +task movePolicies(type: Copy) { + dependsOn setupProfile + from files("browserConf") + into "$rootDir/firefox/" + doLast { + println "Making policies firefox!" + } +} + +task installAddons(type: Copy) { + dependsOn setupProfile + dependsOn configurations.addon + from configurations.addon.resolve() + into "${installFirefox.getOutputs().getFiles().getSingleFile()}/distribution/extensions" + doFirst { + println "Installing addons!" + } } -installLinux_i686.finalizedBy setupProfile tasks.named('clean') { dependsOn uninstallFirefoxWindows } +println configurations.getNames() -dependencies { - implementation 'org.slf4j:slf4j-api:1.7.30' - implementation 'org.apache.logging.log4j:log4j-api:2.13.3' - implementation 'org.apache.logging.log4j:log4j-core:2.13.3' - implementation 'org.apache.logging.log4j:log4j-slf4j-impl:2.13.3' - implementation project(":browserCommands") -} - -// In this section you declare the dependencies for your production and test code -if (Os.isFamily(Os.FAMILY_WINDOWS)) -{ - if (Os.isArch("x86_64") || Os.isArch("amd64")) - { - print("Windows x86_64") - processResources.finalizedBy installWindows_x86_64 - } - else if (Os.isArch("x86") || Os.isArch("i386") || Os.isArch("i686")) - { - print("Windows x86") - processResources.finalizedBy installWindows_x86 - } - else - { - printf("Unknown windows architecture %s!\n", System.getProperty("os.arch")) - } -} -else if (Os.isFamily(Os.FAMILY_MAC)) -{ - print("Mac") - processResources.finalizedBy { - api "firefox:devedition:92.0b7:mac@dmg" - } -} -else if (Os.isFamily(Os.FAMILY_UNIX)) -{ - if (Os.isArch("x86_64") || Os.isArch("amd64")) - { - processResources.finalizedBy installLinux_x86_64 - } - else if (Os.isArch("x86") || Os.isArch("i386") || Os.isArch("i686")) - { - processResources.finalizedBy installLinux_i686 - } - else - { - printf("Unknown Linux architecture %s!\n", System.getProperty("os.arch")) - } -} -else -{ - printf("Unknown operating system %s!\n", System.getProperty("os.name")) -} - +compileJava.dependsOn installAddons +compileJava.dependsOn movePolicies diff --git a/browser/src/main/java/edu/regis/universeplayer/browser/Browser.java b/browser/src/main/java/edu/regis/universeplayer/browser/Browser.java index 6b4001d..3695384 100644 --- a/browser/src/main/java/edu/regis/universeplayer/browser/Browser.java +++ b/browser/src/main/java/edu/regis/universeplayer/browser/Browser.java @@ -4,8 +4,6 @@ package edu.regis.universeplayer.browser; -import edu.regis.universeplayer.browserCommands.BrowserConstants; -import edu.regis.universeplayer.browserCommands.MessageRunner; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -18,6 +16,9 @@ import java.net.Socket; import java.util.Scanner; import java.util.concurrent.atomic.AtomicBoolean; +import edu.regis.universeplayer.browserCommands.BrowserConstants; +import edu.regis.universeplayer.browserCommands.MessageRunner; + public class Browser extends MessageRunner { private static final Logger logger = LoggerFactory.getLogger(Browser.class); @@ -51,18 +52,21 @@ public class Browser extends MessageRunner /* * Wait for the browser to fully start. */ - startExit = browserProcess.waitFor(); - if (startExit != 0) + if (!browserProcess.isAlive()) { - logger.error("Error in browser launch (exit code {})", startExit); - try (Scanner scanner = new Scanner(browserProcess.getErrorStream())) + startExit = browserProcess.exitValue(); + if (startExit != 0) { - while (scanner.hasNextLine()) + logger.error("Error in browser launch (exit code {})", startExit); + try (Scanner scanner = new Scanner(browserProcess.getErrorStream())) { - logger.error(scanner.nextLine()); + while (scanner.hasNextLine()) + { + logger.error(scanner.nextLine()); + } } + throw new IOException("Error in browser launch (exit code " + startExit + ")"); } - throw new IOException("Error in browser launch (exit code " + startExit + ")"); } logger.debug("Browser started."); @@ -159,8 +163,19 @@ public class Browser extends MessageRunner String arch = System.getProperty("os.arch").toLowerCase(); String args; File browserDir = new File(System.getProperty("user.dir"), "firefox"); + File profileDir = new File(System.getProperty("user.dir"), "profile"); + profileDir.mkdir(); + if (!browserDir.isDirectory()) + { + /* + * For some reason, the above maps to the interface project module, rather than the root project. + */ + browserDir = new File(new File(System.getProperty("user.dir")).getParent(), "firefox"); + } - args = " -profile \"" + System.getProperty("user.dir") + "/profile\""; +// args = " -profile \"" + profileDir.getAbsolutePath() + "\""; + args = ""; + System.out.println(profileDir); logger.info("Running on {} {}", os, arch); // System.getProperties().entrySet().stream().forEach(entry -> logger.info("{}: {}", entry.getKey(), entry.getValue())); if (os.contains("windows")) diff --git a/gradlew b/gradlew old mode 100644 new mode 100755 diff --git a/interface/build.gradle b/interface/build.gradle index dc12c2f..e81fec9 100644 --- a/interface/build.gradle +++ b/interface/build.gradle @@ -46,5 +46,3 @@ targetCompatibility = JavaVersion.VERSION_16 // Define the main class for the application mainClassName = defaultPackage + '.player.Interface' //mainClassName = defaultPackage + '.localPlayer.Player' - -compileJava.dependsOn ':addonInter:installAddon' \ No newline at end of file