From f373cb712e1e6bf8b86379f7368705d782d18f11 Mon Sep 17 00:00:00 2001 From: Daniel Date: Fri, 25 Oct 2019 20:01:33 +0200 Subject: [PATCH] Migrate launcher into separate chatoverflow-launcher repository --- .gitignore | 1 + ...kage_launcherProject_assembly_deploy_.xml} | 6 +- ...Generate_Bootstrap_Launcher_and_deploy.xml | 2 +- Makefile | 2 +- bootstrap/launcher/build.sbt | 27 -- .../launcher/src/main/scala/Bootstrap.scala | 117 ------- bootstrap/launcher/src/main/scala/CLI.scala | 35 -- .../src/main/scala/DependencyDownloader.scala | 70 ---- bootstrap/updater/build.sbt | 17 - bootstrap/updater/src/main/scala/CLI.scala | 40 --- .../updater/src/main/scala/Updater.scala | 306 ------------------ build.sbt | 9 +- .../build/deployment/DeploymentUtility.scala | 16 +- 13 files changed, 16 insertions(+), 632 deletions(-) rename .idea/runConfigurations/{Full_Deploy__sbt_clean_gui_package_bootstrapProject_assembly_deploy_.xml => Full_Deploy__sbt_clean_gui_package_launcherProject_assembly_deploy_.xml} (75%) delete mode 100644 bootstrap/launcher/build.sbt delete mode 100644 bootstrap/launcher/src/main/scala/Bootstrap.scala delete mode 100644 bootstrap/launcher/src/main/scala/CLI.scala delete mode 100644 bootstrap/launcher/src/main/scala/DependencyDownloader.scala delete mode 100644 bootstrap/updater/build.sbt delete mode 100644 bootstrap/updater/src/main/scala/CLI.scala delete mode 100644 bootstrap/updater/src/main/scala/Updater.scala diff --git a/.gitignore b/.gitignore index afefbd66..689c05b1 100644 --- a/.gitignore +++ b/.gitignore @@ -22,6 +22,7 @@ project/plugins/project/ /plugins-private/ /gui/ /setup/ +/launcher/ # Plugin Framework /plugins/ diff --git a/.idea/runConfigurations/Full_Deploy__sbt_clean_gui_package_bootstrapProject_assembly_deploy_.xml b/.idea/runConfigurations/Full_Deploy__sbt_clean_gui_package_launcherProject_assembly_deploy_.xml similarity index 75% rename from .idea/runConfigurations/Full_Deploy__sbt_clean_gui_package_bootstrapProject_assembly_deploy_.xml rename to .idea/runConfigurations/Full_Deploy__sbt_clean_gui_package_launcherProject_assembly_deploy_.xml index 5aadae48..b0e58225 100644 --- a/.idea/runConfigurations/Full_Deploy__sbt_clean_gui_package_bootstrapProject_assembly_deploy_.xml +++ b/.idea/runConfigurations/Full_Deploy__sbt_clean_gui_package_launcherProject_assembly_deploy_.xml @@ -1,14 +1,14 @@ - + - + \ No newline at end of file diff --git a/Makefile b/Makefile index 5b5bfaa0..51610052 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ simple_run: sbt package copy bootstrap_deploy: - sbt clean gui package bootstrapProject/assembly deploy + sbt clean gui package launcherProject/assembly deploy bootstrap_deploy_dev: sbt clean gui package buildProject/package deployDev diff --git a/bootstrap/launcher/build.sbt b/bootstrap/launcher/build.sbt deleted file mode 100644 index c8c5faed..00000000 --- a/bootstrap/launcher/build.sbt +++ /dev/null @@ -1,27 +0,0 @@ -name := "chatoverflow-bootstrap-launcher" -// s"$version-$versionSuffix" has to represent the tag name of the current release inorder for the Updater to know the current version. -version := "0.3" -lazy val versionSuffix = "prealpha" -assemblyJarName in assembly := "ChatOverflow-Launcher.jar" - -// Coursier is used to download the deps of the framework -// Excluding argonaut and it's dependencies because we don't use any json with Coursier and that way we are able -// to reduce the assembly jar file size from about 17MB (way too big) to only 8,8 MB, which is acceptable. -libraryDependencies += "io.get-coursier" %% "coursier" % "2.0.0-RC3-2" excludeAll( - ExclusionRule(organization = "org.scala-lang", name = "scala-reflect"), - ExclusionRule(organization = "io.argonaut", name = "argonaut_2.12"), - ExclusionRule(organization = "com.chuusai", name = "shapeless_2.12"), - ExclusionRule(organization = "com.github.alexarchambault", name = "argonaut-shapeless_6.2_2.12") -) - -// Command Line Parsing -libraryDependencies += "com.github.scopt" %% "scopt" % "3.5.0" - -fork := true - -packageBin / includePom := false - -Compile / compile := { - IO.write((Compile / classDirectory).value / "version.txt", version.value + "-" + versionSuffix) - (Compile / compile).value -} \ No newline at end of file diff --git a/bootstrap/launcher/src/main/scala/Bootstrap.scala b/bootstrap/launcher/src/main/scala/Bootstrap.scala deleted file mode 100644 index 8c80a967..00000000 --- a/bootstrap/launcher/src/main/scala/Bootstrap.scala +++ /dev/null @@ -1,117 +0,0 @@ -import java.io.File - -import CLI._ - -/** - * The bootstrap launcher downloads all required libraries and starts chat overflow with the correct parameters. - */ -object Bootstrap { - - // Java home path (jre installation folder) - private val javaHomePath: String = System.getProperty("java.home") - - // Chat Overflow Launcher / Main class (should not change anymore) - private val chatOverflowMainClass = "org.codeoverflow.chatoverflow.Launcher" - - /** - * Launcher entry point. - * Validates installation, downloads dependencies and start ChatOverflow. - * - * @param args the arguments, which are passed to ChatOverflow - */ - def main(args: Array[String]): Unit = { - val conf: Config = ArgsParser.parse(args, Config()) match { - case Some(value) => value - case None => System.exit(1); null - } - - if (testValidity(conf.directory)) { - println("Valid ChatOverflow installation. Checking libraries...") - - val deps = new DependencyDownloader(conf.directory).fetchDependencies().map(u => new File(u.getFile)) - if (deps.nonEmpty) { - val javaPath = createJavaPath() - if (javaPath.isDefined) { - println("Found java installation. Starting ChatOverflow...") - - // Start chat overflow! - val command = List(javaPath.get, "-cp", s"bin/*${deps.mkString(File.pathSeparator, File.pathSeparator, "")}", chatOverflowMainClass) ++ args - val processBuilder = new java.lang.ProcessBuilder(command: _*) - .inheritIO().directory(new File(conf.directory)) - - processBuilder.environment().put("CHATOVERFLOW_BOOTSTRAP", "true") - - val process = processBuilder.start() - - val exitCode = process.waitFor() - println(s"ChatOverflow stopped with exit code: $exitCode") - } else { - println("Unable to find java installation. Unable to start.") - } - } else { - println("Error: Problem with libraries. Unable to start.") - } - } else { - println("Error: Invalid ChatOverflow installation. Please extract all provided files properly. Unable to start.") - } - } - - /** - * Takes the java home path of the launcher and tries to find the java(.exe) - * - * @return the path to the java runtime or none, if the file was not found - */ - private def createJavaPath(): Option[String] = { - - // Check validity of java.home path first - if (!new File(javaHomePath).exists()) { - None - } else { - - // Check for windows and unix java versions - // This should work on current and older java JRE/JDK installations, - // see: https://stackoverflow.com/questions/52584888/how-to-use-jdk-without-jre-in-java-11 - val javaExePath = s"$javaHomePath/bin/java.exe" - val javaPath = s"$javaHomePath/bin/java" - - if (new File(javaExePath).exists()) { - Some(javaExePath) - } else if (new File(javaPath).exists()) { - Some(javaPath) - } else { - None - } - } - - } - - /** - * Checks, if the installation is valid - */ - private def testValidity(currentFolderPath: String): Boolean = { - // The first check is the existence of a bin folder - val binDir = new File(s"$currentFolderPath/bin") - check(binDir.exists() && binDir.isDirectory, "The bin directory doesn't exist") && { - // Next are the existence of a framework, api and gui jar - val jars = binDir.listFiles().filter(_.getName.endsWith(".jar")) - - check(jars.exists(_.getName.toLowerCase.startsWith("chatoverflow_")), "There is no api jar in the bin directory.") && - check(jars.exists(_.getName.toLowerCase.startsWith("chatoverflow-api")), "There is no api jar in the bin directory.") && - check(jars.exists(_.getName.toLowerCase.startsWith("chatoverflow-gui")), - "Note: No gui jar detected. The ChatOverflow gui won't be usable.", required = false) - } - } - - /** - * Helper method for [[Bootstrap.testValidity()]]. Checks condition, prints description if the condition is false and - * returns false if the condition is false and the check is required. - */ - private def check(condition: Boolean, description: String, required: Boolean = true): Boolean = { - if (condition) { - true - } else { - println(description) - !required - } - } -} diff --git a/bootstrap/launcher/src/main/scala/CLI.scala b/bootstrap/launcher/src/main/scala/CLI.scala deleted file mode 100644 index 4670faa7..00000000 --- a/bootstrap/launcher/src/main/scala/CLI.scala +++ /dev/null @@ -1,35 +0,0 @@ -import java.io.File -import java.nio.file.Paths - - -object CLI { - - /** - * Everything in here also has to be defined in the CLI class of the framework, because - * all arguments including bootstrap specific ones are passed through to the framework. - * Filtering these options out would be way too difficult, because you need to know if a option - * is a simple flag or is followed by a value. Scopt doesn't expose anything to get this so we would - * need to use reflect, which is very ugly. - * This, while not that elegant as I would like it to be, is just simple and works. - */ - object ArgsParser extends scopt.OptionParser[Config]("ChatOverflow Launcher") { - opt[File]("directory") - .action((x, c) => c.copy(directory = x.getAbsolutePath)) - .text("The directory in which ChatOverflow will be executed") - .validate(f => - if (!f.exists()) - Left("Directory doesn't exist") - else if (!f.isDirectory) - Left("Path isn't a directory") - else - Right() - ) - - override def errorOnUnknownArgument: Boolean = false - - override def reportWarning(msg: String): Unit = () - } - - case class Config(directory: String = Paths.get("").toAbsolutePath.toString) - -} diff --git a/bootstrap/launcher/src/main/scala/DependencyDownloader.scala b/bootstrap/launcher/src/main/scala/DependencyDownloader.scala deleted file mode 100644 index 1c455ab9..00000000 --- a/bootstrap/launcher/src/main/scala/DependencyDownloader.scala +++ /dev/null @@ -1,70 +0,0 @@ -import java.io.{File, InputStream} -import java.net.{URL, URLClassLoader} - -import coursier.Fetch -import coursier.cache.FileCache -import coursier.cache.loggers.{FileTypeRefreshDisplay, RefreshLogger} -import coursier.core.{Configuration, Dependency} -import coursier.maven.{MavenRepository, PomParser} - -import scala.io.Source - -class DependencyDownloader(directory: String) { - private val pomFile = "dependencies.pom" - private val logger = RefreshLogger.create(System.out, FileTypeRefreshDisplay.create()) - private val cache = FileCache().noCredentials.withLogger(logger) - - // Classloader containing all jars, used to get the dependencies from the framework jar - private val jarFiles = { - val jarsOpt = Option(new File(s"$directory/bin").listFiles()) - jarsOpt.getOrElse(Array()).filter(_.getName.endsWith(".jar")).map(_.toURI.toURL) - } - private val classloader = new URLClassLoader(jarFiles) - - private def getPomIs: InputStream = classloader.getResourceAsStream(pomFile) - - /** - * Parses the pom file of the framework jar and returns a seq of all dependencies that are required to run it. - * - * @return the seq of dependencies, if it is empty an error has occurred and logged. - */ - private def parsePom(): Seq[Dependency] = { - if (getPomIs == null) { - println("Couldn't find the pom containing all required dependencies for the framework in the jar.") - return Seq() - } - - val pomFile = Source.fromInputStream(getPomIs) - val parser = coursier.core.compatibility.xmlParseSax(pomFile.mkString, new PomParser) - parser.project match { - case Right(deps) => - deps.dependencies - .filterNot(_._1 == Configuration.provided) // Provided deps are... well provided and no download is required - .map(_._2) - .filter(_.module.name.value != "chatoverflow-api") // We already have the api locally inside the bin directory - case Left(errorMsg) => - println(s"Pom containing all required dependencies for the framework couldn't be parsed: $errorMsg") - Seq() - } - } - - /** - * Fetches all required dependencies for the framework using Coursier. - * - * @return a seq of urls of jar files that need to be included to the classpath. A empty seq signifies an error. - */ - def fetchDependencies(): Seq[URL] = { - val deps = parsePom() - if (deps.isEmpty) - return Seq() - - // IntelliJ may warn you that a implicit is missing. This is one of the many bugs in IntelliJ, the code compiles fine. - val jars: Seq[File] = Fetch() - .withCache(cache) - .addDependencies(deps: _*) - .addRepositories(MavenRepository("https://jcenter.bintray.com")) // JCenter is used for JDA (DiscordConnector) - .run - - jars.map(_.toURI.toURL) - } -} diff --git a/bootstrap/updater/build.sbt b/bootstrap/updater/build.sbt deleted file mode 100644 index 1194bfae..00000000 --- a/bootstrap/updater/build.sbt +++ /dev/null @@ -1,17 +0,0 @@ -name := "chatoverflow-bootstrap-updater" -version := "0.3" // Currently not used anywhere -assemblyJarName in assembly := "ChatOverflow.jar" - -// JSON Lib to read the json provided by GitHub Releases -libraryDependencies += "org.json4s" %% "json4s-jackson" % "3.5.2" - -// jansi is used to check if the application is running with a tty in a interactive session -libraryDependencies += "org.fusesource.jansi" % "jansi" % "1.18" - -// Progressbar is used to display progress of update zip download -libraryDependencies += "me.tongfei" % "progressbar" % "0.7.4" - -// Command Line Parsing -libraryDependencies += "com.github.scopt" %% "scopt" % "3.5.0" - -packageBin / includePom := false diff --git a/bootstrap/updater/src/main/scala/CLI.scala b/bootstrap/updater/src/main/scala/CLI.scala deleted file mode 100644 index f67ac780..00000000 --- a/bootstrap/updater/src/main/scala/CLI.scala +++ /dev/null @@ -1,40 +0,0 @@ -import java.io.File -import java.nio.file.Paths - -object CLI { - - /** - * Everything in here also has to be defined in the CLI class of the framework, because - * all arguments including bootstrap specific ones are passed through to the framework. - * Filtering these options out would be way too difficult, because you need to know if a option - * is a simple flag or is followed by a value. Scopt doesn't expose anything to get this so we would - * need to use reflect, which is very ugly. - * This, while not that elegant as I would like it to be, is just simple and works. - */ - object ArgsParser extends scopt.OptionParser[Config]("ChatOverflow Updater") { - opt[Unit]("ignore-updates") - .action((_, c) => c.copy(ignoreUpdates = true)) - .text("Ignores searching for updates and directly start ChatOverflow") - - opt[File]("directory") - .action((x, c) => c.copy(directory = x.getAbsolutePath)) - .text("The directory in which ChatOverflow will be executed") - .validate(f => - if (!f.exists()) - Left("Directory doesn't exist") - else if (!f.isDirectory) - Left("Path isn't a directory") - else - Right() - ) - - opt[Unit]("help").action((_, c) => c.copy(help = true)) - - override def errorOnUnknownArgument: Boolean = false - - override def reportWarning(msg: String): Unit = () - } - - case class Config(help: Boolean = false, directory: String = Paths.get("").toAbsolutePath.toString, ignoreUpdates: Boolean = false) - -} diff --git a/bootstrap/updater/src/main/scala/Updater.scala b/bootstrap/updater/src/main/scala/Updater.scala deleted file mode 100644 index e25a64e1..00000000 --- a/bootstrap/updater/src/main/scala/Updater.scala +++ /dev/null @@ -1,306 +0,0 @@ -import java.io.{BufferedInputStream, File, FileInputStream} -import java.net.{URL, URLClassLoader} -import java.nio.file.StandardCopyOption.REPLACE_EXISTING -import java.nio.file.{FileSystemException, Files, Paths} -import java.text.DecimalFormat -import java.util.Date -import java.util.zip.ZipFile - -import CLI._ -import me.tongfei.progressbar.{ProgressBar, ProgressBarBuilder, ProgressBarStyle} -import org.fusesource.jansi.internal.CLibrary -import org.json4s.jackson.JsonMethods.parse -import org.json4s.{DefaultFormats, Formats} - -import scala.collection.JavaConverters._ -import scala.io.{Source, StdIn} - -/** - * Contains all logic to update the local installation of ChatOverflow. - * Uses GitHub releases to find new versions and to download them. - */ -object Updater { - private val versionFileName = "version.txt" - private val launcherJar = "bin/ChatOverflow-Launcher.jar" - private val launcherMainClass = "Bootstrap" - private var classLoader: URLClassLoader = _ - private val ghBase = "https://api.github.com" - private val acceptHeader = "Accept" -> "application/vnd.github.v3+json" // ensures that we always get the GitHub v3 API - private implicit val jsonFormats: Formats = DefaultFormats - - private val repo = "codeoverflow-org/chatoverflow" // Can be changed for testing purposes - - /** - * Updater entry point. - * Checks for updates and if available and accepted by the user, installs it. - * Starts the Bootstrap Launcher - * - * @param args arguments for the launcher - */ - def main(args: Array[String]): Unit = { - println("Starting ChatOverflow Bootstrap Updater.") - - val conf: Config = ArgsParser.parse(args, Config()) match { - case Some(value) => value - case None => System.exit(1); null - } - classLoader = getLauncherLoader(conf) - - if (conf.help) { - // The user just wants to quickly get all available options, don't search for updates to not bother the user. - // Start the framework through the launcher and simply show the usage. - startLauncher(Array("--help"), conf) - return - } - - if (!conf.ignoreUpdates) { - println("Checking for updates...") - val update = Updater.searchForUpdates - if (update.isDefined) { - println("A new update is available!") - println(s"Current version: ${Updater.getCurrentVersion.get}") - println(s"Newest version: ${update.get.tag_name}") - - // Check if a tty is attached - if (CLibrary.isatty(CLibrary.STDIN_FILENO) == 1) { - print(s"Do you want to download and install the update? [y/N] ") - val in = StdIn.readLine - - if (in.toLowerCase == "y") { - val file = Updater.downloadUpdate(update.get) - if (file.isDefined) { - Updater.installUpdate(file.get, conf) - } - } - } else { - println("Currently running in a non-interactive session. Please run in an interactive session to auto-update\n" + - s"or download and install manually from ${update.get.html_url}") - } - } else { - println("No new update is available.") - } - } else { - println("Skipping update check.") - } - - startLauncher(args, conf) - } - - /** - * Searches for any updates that are newer than the local version. - * - * @return A release, if it is newer than the local version, otherwise None. - */ - def searchForUpdates: Option[Release] = { - val version = getCurrentVersion - if (version.isEmpty) { - println("Couldn't determine current ChatOverflow version. Skipping update check.") - return None - } - - val releases = getReleases - - if (releases.isEmpty || releases.get.isEmpty) { - println("Couldn't get releases on GitHub. Skipping update check.") - return None - } - - val current = releases.get.find(_.tag_name == version.get) - if (current.isEmpty) { - println(s"Couldn't find used release '${version.get}' on GitHub. Skipping update check.") - return None - } - - val latest = releases.get.maxBy(_.published_at.getTime) - - if (latest.published_at.after(current.get.published_at)) - Some(latest) - else - None - } - - /** - * Gets all releases from GitHub using the GitHub API. - * - * @return None, if something has failed. A list of all releases otherwise. - */ - def getReleases: Option[List[Release]] = { - val url = new URL(s"$ghBase/repos/$repo/releases") - val conn = url.openConnection() - - val (key, value) = acceptHeader - conn.setRequestProperty(key, value) - - try { - val body = Source.fromInputStream(conn.getInputStream).mkString - parse(body).extractOpt[List[Release]] - } catch { - case e: Throwable => - println(e) - None - } - } - - /** - * Tries to download the zip of the passed release to a temp file. - * - * @param update the release which should be downloaded - * @return None, if no zip file is attached to the release. When successful returns the temp file. - */ - def downloadUpdate(update: Release): Option[File] = { - val zipFile = update.assets.find(e => { - val n = e.name - n.endsWith(".zip") && !n.contains("plugin") && !n.contains("dev") // Tries to eliminate zips of the plugin dev environment - }) - if (zipFile.isEmpty) { - println("Release doesn't contain a zip file, seems invalid. Skipping update and starting with old version.") - return None - } - - println("Downloading update...") - - val url = new URL(zipFile.get.browser_download_url) - val temp = Files.createTempFile("ChatOverflow", update.tag_name).toFile - - val connection = url.openConnection() - val pbb = new ProgressBarBuilder() - .setStyle(ProgressBarStyle.ASCII) - .setUnit("MB", 1000 * 1000) - .setInitialMax(zipFile.get.size) - .showSpeed(new DecimalFormat("0.0")) - - val in = ProgressBar.wrap(connection.getInputStream, pbb) - try { - if (temp.exists()) - temp.delete() - - Files.copy(in, temp.toPath) - } finally { - in.close() - } - - println("Update successfully downloaded.") - Some(temp) - } - - /** - * Installs a update from the passed zip file. - * - * @param zipFile the zip containing the update - * @param conf the cli config, used to extract the new files into the correct installation directory - */ - def installUpdate(zipFile: File, conf: Config): Unit = { - println("Installing update...") - - val binFiles = new File(s"${conf.directory}/bin").listFiles.filter(_.getName.endsWith(".jar")) - binFiles.foreach(_.delete()) - - classLoader.close() // release locks of jars on windows - classLoader = null - - // Extract zip - val zip = new ZipFile(zipFile) - zip.entries().asScala - .foreach(entry => { - val is = zip.getInputStream(entry) - val out = new File(conf.directory, entry.getName) - - if (out.isDirectory) { - out.mkdirs() - } else { - try { - Files.copy(is, out.toPath, REPLACE_EXISTING) - } catch { - case _: FileSystemException if entry.getName == "ChatOverflow.jar" => - // Updater couldn't be updated, because Windows holds file locks on executing files including the updater. - // Skip update of it, it shouldn't change anyway. We can update it on *nix system in the case we reeeeealy need to. - // If it has changed and we can't auto-update, we do recommend the user to update the updater manually, but it is to the user to decide. - val currentIs = new BufferedInputStream(new FileInputStream(s"${conf.directory}/ChatOverflow.jar")) - val currentHash = Stream.continually(currentIs.read).takeWhile(_ != -1).map(_.toByte).hashCode() - val newIs = new BufferedInputStream(zip.getInputStream(entry)) - val newHash = Stream.continually(newIs.read).takeWhile(_ != -1).map(_.toByte).hashCode() - - if (currentHash != newHash) { - println("The ChatOverflow updater has been updated and we can't update it for you when running on Windows.\n" + - "It's highly recommended to override the 'ChatOverflow.jar' of your installation with the new version\n" + - s"that can be found in the zip file at $zipFile.\n ChatOverflow may still work fine with this version," + - "but we can't guarantee that.") - } - } - } - - is.close() - }) - - // Re-set the executable flag for *nix systems - new File(conf.directory).listFiles() - .filter(f => f.isFile && f.getName.startsWith("ChatOverflow.")) - .foreach(_.setExecutable(true)) - - // Reload all jar files, so that the launcher can be loaded - classLoader = getLauncherLoader(conf) - - println("Update installed.") - } - - /** - * Gets the local installed version, e.g. 0.3-prealpha. - * - * @return if successfully the version, otherwise None. - */ - def getCurrentVersion: Option[String] = { - val is = classLoader.getResourceAsStream(versionFileName) - if (is == null) - None - else - Some(Source.fromInputStream(is).getLines().mkString) - } - - /** - * Loads the class of the Launcher with the class loader and starts it. - * - * @param args the args to pass to the Bootstrap Launcher - * @param conf cli config, used to check the existence of the launcher jar - */ - def startLauncher(args: Array[String], conf: Config): Unit = { - try { - val cls = classLoader.loadClass(launcherMainClass) - val mainMethod = cls.getMethod("main", classOf[Array[String]]) - mainMethod.invoke(null, args) - } catch { - case _: ClassNotFoundException => - if (!new File(s"${conf.directory}/$launcherJar").exists) - println("Launcher jar is non existent. Seems like your installation is invalid.") - else - println(s"Main class of the launcher $launcherMainClass couldn't be found.") - case _: NoSuchMethodException => println(s"Launcher jar is invalid: couldn't get main method.") - case e: Throwable => println(s"Launcher jar is invalid: $e"); - } - } - - private def getLauncherLoader(conf: Config) = new URLClassLoader(Array( - Paths.get(s"${conf.directory}/$launcherJar").toUri.toURL - ), getClass.getClassLoader.getParent) - - /** - * Metadata about a release of ChatOverflow on GitHub. - * Note that the variables of this class don't represent all the metadata we get by the GitHub API, - * you can add more metadata by adding a variable with the name that the metadata has in the json object. - * - * @param tag_name the name of the git tag, which this release refers to - * @param html_url the url to the release on GitHub - * @param published_at the date, when this release was published - * @param assets all assets attached to this release - */ - case class Release(tag_name: String, html_url: String, published_at: Date, assets: List[ReleaseAsset]) - - /** - * A file asset of a release. - * - * @param name the name of the file - * @param browser_download_url the url, where it can be downloaded - * @param size the size of the file in bytes - */ - case class ReleaseAsset(name: String, browser_download_url: String, size: Int) - -} diff --git a/build.sbt b/build.sbt index abe10b03..b27af28a 100644 --- a/build.sbt +++ b/build.sbt @@ -36,13 +36,8 @@ inThisBuild(List( import org.codeoverflow.chatoverflow.build.BuildUtils javacOptions ++= BuildUtils.getJava8CrossOptions -// Link the bootstrap launcher -lazy val bootstrapLauncherProject = project in file("bootstrap/launcher") -lazy val bootstrapUpdaterProject = project in file("bootstrap/updater") -lazy val bootstrapProject = (project in file("bootstrap")) - .aggregate(bootstrapLauncherProject, bootstrapUpdaterProject).settings( - name := "chatoverflow-bootstrap" -) +// Link the launcher +lazy val launcherProject = project in file("launcher") // not actually used. Just required to say IntelliJ to mark the build directory as a sbt project, otherwise it wouldn't detect it. lazy val buildProject = project in file("build") diff --git a/build/src/main/scala/org/codeoverflow/chatoverflow/build/deployment/DeploymentUtility.scala b/build/src/main/scala/org/codeoverflow/chatoverflow/build/deployment/DeploymentUtility.scala index f4793dfb..992afdec 100644 --- a/build/src/main/scala/org/codeoverflow/chatoverflow/build/deployment/DeploymentUtility.scala +++ b/build/src/main/scala/org/codeoverflow/chatoverflow/build/deployment/DeploymentUtility.scala @@ -22,8 +22,8 @@ object DeploymentUtility { */ def prepareDeploymentTask(logger: ManagedLogger, scalaLibraryVersion: String): Unit = { // Assuming, before this: clean, gui, bs, bootstrapProject/assembly, package - // Assuming: Hardcoded "bin/" and "deploy/" folders - // Assuming: A folder called "deployment-files/end-user/" with all additional files (license, bat, etc.) + // Assuming: Hardcoded "bin/", "launcher/" and "deploy/" folders + // Assuming: A folder called "launcher/deployment-files/end-user/" with all additional files (license, bat, etc.) withTaskInfo("PREPARE DEPLOYMENT", logger) { @@ -37,12 +37,12 @@ object DeploymentUtility { prepareBinDirectories(logger, targetJarDirectories, scalaLibraryVersion, copyApi = true) // Third step: Copy bootstrap launcher - copyJars(s"bootstrap/launcher/target/scala-$scalaLibraryVersion/", List("deploy/bin/"), logger) - copyJars(s"bootstrap/updater/target/scala-$scalaLibraryVersion/", List("deploy/"), logger) + copyJars(s"launcher/bootstrap/target/scala-$scalaLibraryVersion/", List("deploy/bin/"), logger) + copyJars(s"launcher/updater/target/scala-$scalaLibraryVersion/", List("deploy/"), logger) // Last step: Copy additional files logger info "Copying additional deployment files..." - val deploymentFiles = new File("deployment-files/end-user/") + val deploymentFiles = new File("launcher/deployment-files/end-user/") if (!deploymentFiles.exists()) { logger warn "Unable to find deployment files." } else { @@ -63,8 +63,8 @@ object DeploymentUtility { */ def prepareDevDeploymentTask(logger: ManagedLogger, scalaLibraryVersion: String, apiProjectPath: String, dependencies: List[ModuleID]): Unit = { // Assuming, before this: clean, gui, package and buildProject/package - // Assuming: Hardcoded "bin/", "deployDev/" and "build/" folders - // Assuming: A folder called "deployment-files/plugin-dev/" with more additional files for plugin developers + // Assuming: Hardcoded "bin/", "deployDev/", "launcher/" and "build/" folders + // Assuming: A folder called "launcher/deployment-files/plugin-dev/" with more additional files for plugin developers withTaskInfo("PREPARE DEV DEPLOYMENT", logger) { @@ -90,7 +90,7 @@ object DeploymentUtility { sbt.IO.write(new File("deployDev/dependencies.sbt"), depFile.toString) // Last step: Copy additional files - val devDeploymentFiles = new File("deployment-files/plugin-dev/") + val devDeploymentFiles = new File("launcher/deployment-files/plugin-dev/") if (!devDeploymentFiles.exists()) { logger warn "Unable to find dev deployment files." } else {