<commit_before>/*
 * Code Pulse: A real-time code coverage testing tool. For more information
 * see http://code-pulse.com
 *
 * Copyright (C) 2014 Applied Visions - http://securedecisions.avi.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import sbt._
import Keys._
import BuildKeys._

import com.earldouglas.xsbtwebplugin.PluginKeys._
import sbt.classpath.ClasspathUtilities
import Project.Initialize

import sbtassembly.Plugin.AssemblyKeys.assembly

import java.nio.file.{ Files, StandardCopyOption }

import com.avi.sbt.betterzip.BetterZip.{ Entry => ZipEntry, _ }

/** In charge of packaging up the node-webkit packages for distribution.
  * 
  * @author robertf
  */
object Distributor extends BuildExtra {

	import DependencyFetcher.Keys._

	object Keys {
		val Distribution = config("distribution")

		val rootZipFolder = SettingKey[String]("root-zip-folder")
		val webappFolder = SettingKey[String]("webapp-folder")
		
		val distCommon = SettingKey[File]("dist-common")
		val distJettyConf = SettingKey[File]("dist-jetty-conf")

		val warContents = TaskKey[Seq[(File, String)]]("webapp-war-contents")

		val webappClasses = TaskKey[Seq[(File, String)]]("webapp-classes", "Find all .class files in the generated webapp classes folder")
		val webappClassesJar = TaskKey[File]("webapp-war-jar", "Create a .jar file containing all of the webapp classes")

		val packageMappings = TaskKey[Seq[ZipEntry]]("package-zip-mappings")
	}

	import Keys._
	
	object Settings {

		/** Each task of this type generates a listing of File->Path, where the File is
		  * a file in the filesystem that will be packaged in a zip/war/jar, and the Path
		  * is that file's path once it is packaged.
		  */
		type FileMappingTask = Initialize[Task[Seq[(ZipEntry)]]]

		def embeddedWar(conf: Configuration): FileMappingTask = (packageWar in conf, webappFolder in Distribution) map { (war, path) =>
			Seq(war -> (path + "webapps/root.war"))
		}

		def webappClassesTask: Initialize[Task[Seq[(File, String)]]] = (warContents in Distribution) map { (contents) =>
			val classPath = """WEB-INF[\\/]classes[\\/](.*)""".r

			contents flatMap {
				case (f, p) =>
					p match {
						case classPath(relPath) => Some((f, relPath))
						case _ => None
					}
			}
		}

		def buildJarTask: Initialize[Task[File]] = (webappClasses in Distribution, crossTarget, name, version) map { (classes, ct, name, version) =>
			val jarToMake = ct / (name + '-' + version + "-webapp-classes.jar")
			IO.jar(classes, jarToMake, new java.util.jar.Manifest)
			jarToMake
		}

		def embeddedWebApp(conf: Configuration, platform: String): FileMappingTask = (warContents in Distribution, rootZipFolder in Distribution, webappFolder in Distribution, webappClasses in Distribution, webappClassesJar in Distribution) map { (warContents, rootZipFolder, path, classes, jar) =>
			val appFolder = path + "webapps/root/"

			val classSet = classes.map(_._1).toSet
			val filteredContents = warContents.filterNot { case (file, _) => classSet contains file }
			var jarRec = (jar, ("WEB-INF/lib/" + jar.getName))

			appResource(platform, rootZipFolder, (filteredContents ++ Seq(jarRec)) map {
				case (file, path) => (file, (appFolder + path.replace('\\', '/')))
			})
		}

		def jettyDist(platform: String): FileMappingTask = (jetty in Dependencies, distJettyConf in Distribution, rootZipFolder in Distribution, webappFolder in Distribution) map { (jetty, confDir, rootZipFolder, webappFolder) => 
			if (!jetty.exists)
				sys.error("Missing jetty. Please run `fetch-package-dependencies` or download and place in " + jetty + ".")

			val jettyExclusions = List(
				"demo-base/", "etc/", "start.d/", "start.ini"
			).map(webappFolder + _)

			val jettyFiles = jetty.*** x rebase(jetty, webappFolder) map {
				// replace \ in paths with /, for easier matching below
				case (src, dest) => (src, dest.replace('\\', '/'))
			} filter {
				case (_, path) if jettyExclusions exists { path startsWith _ } => println("Excluding " + path); false
				case _ => true
			}

			val jettyConf = confDir.*** x rebase(confDir, webappFolder)

			appResource(platform, rootZipFolder, jettyFiles ++ jettyConf)
		}

		def embeddedAppFiles(platform: String): FileMappingTask = (distCommon in Distribution, rootZipFolder in Distribution) map { (appFolder, rootZipFolder) =>
			appResource(platform, rootZipFolder, appFolder.*** x rebase(appFolder, rootZipFolder))
		}

		def nodeWebkitRuntime(platform: String, nwkKey: SettingKey[File]): FileMappingTask = (nwkKey in Dependencies, resourcer in Dependencies, rootZipFolder in Distribution, distCommon in Distribution, target, version) map { (nwk, resourcer, rootZipFolder, appFolder, target, version) =>
			if (!nwk.exists)
				sys.error("Missing node-webkit for " + platform + ". Please run `fetch-package-dependencies` or download and place in " + nwk + ".")

			val nwkFiles: Seq[ZipEntry] = nwk.*** x rebase(nwk, rootZipFolder) map {
				// replace \ in paths with /, for easier matching below
				case (src, dest) => (src, dest.replace('\\', '/'))
			}

			platform match {
				case "win32" =>
					// on windows, we need nw.pak, icudt.dll, rename nw.exe -> codepulse.exe, libEGL/libGLES and the d3d DLLs
					val inclusions = List(
						"icudt.dll", "libEGL.dll", "libGLESv2.dll", "nw.pak"
					).map(rootZipFolder + _).toSet

					nwkFiles flatMap {
						case ZipEntry(file, path, mode) if path == "codepulse/nw.exe" =>
							// prepare our own copy of nw.exe with appropriately modified icon
							val customizedFile = target / "node-webkit" / "win32" / "codepulse.exe"
							customizedFile.getParentFile.mkdirs
							Files.copy(file.toPath, customizedFile.toPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)

							{
								import scala.sys.process._

								val ico = appFolder / "app" / "icon.ico"

								val args = List(
									resourcer.getCanonicalPath,
									"-op:upd",
									"-src:" + customizedFile.getCanonicalPath,<commit_msg>Fix resourcer execution during packaging process.<commit_after>/*
 * Code Pulse: A real-time code coverage testing tool. For more information
 * see http://code-pulse.com
 *
 * Copyright (C) 2014 Applied Visions - http://securedecisions.avi.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import sbt._
import Keys._
import BuildKeys._

import com.earldouglas.xsbtwebplugin.PluginKeys._
import sbt.classpath.ClasspathUtilities
import Project.Initialize

import sbtassembly.Plugin.AssemblyKeys.assembly

import java.nio.file.{ Files, StandardCopyOption }

import com.avi.sbt.betterzip.BetterZip.{ Entry => ZipEntry, _ }

/** In charge of packaging up the node-webkit packages for distribution.
  * 
  * @author robertf
  */
object Distributor extends BuildExtra {

	import DependencyFetcher.Keys._

	object Keys {
		val Distribution = config("distribution")

		val rootZipFolder = SettingKey[String]("root-zip-folder")
		val webappFolder = SettingKey[String]("webapp-folder")
		
		val distCommon = SettingKey[File]("dist-common")
		val distJettyConf = SettingKey[File]("dist-jetty-conf")

		val warContents = TaskKey[Seq[(File, String)]]("webapp-war-contents")

		val webappClasses = TaskKey[Seq[(File, String)]]("webapp-classes", "Find all .class files in the generated webapp classes folder")
		val webappClassesJar = TaskKey[File]("webapp-war-jar", "Create a .jar file containing all of the webapp classes")

		val packageMappings = TaskKey[Seq[ZipEntry]]("package-zip-mappings")
	}

	import Keys._
	
	object Settings {

		/** Each task of this type generates a listing of File->Path, where the File is
		  * a file in the filesystem that will be packaged in a zip/war/jar, and the Path
		  * is that file's path once it is packaged.
		  */
		type FileMappingTask = Initialize[Task[Seq[(ZipEntry)]]]

		def embeddedWar(conf: Configuration): FileMappingTask = (packageWar in conf, webappFolder in Distribution) map { (war, path) =>
			Seq(war -> (path + "webapps/root.war"))
		}

		def webappClassesTask: Initialize[Task[Seq[(File, String)]]] = (warContents in Distribution) map { (contents) =>
			val classPath = """WEB-INF[\\/]classes[\\/](.*)""".r

			contents flatMap {
				case (f, p) =>
					p match {
						case classPath(relPath) => Some((f, relPath))
						case _ => None
					}
			}
		}

		def buildJarTask: Initialize[Task[File]] = (webappClasses in Distribution, crossTarget, name, version) map { (classes, ct, name, version) =>
			val jarToMake = ct / (name + '-' + version + "-webapp-classes.jar")
			IO.jar(classes, jarToMake, new java.util.jar.Manifest)
			jarToMake
		}

		def embeddedWebApp(conf: Configuration, platform: String): FileMappingTask = (warContents in Distribution, rootZipFolder in Distribution, webappFolder in Distribution, webappClasses in Distribution, webappClassesJar in Distribution) map { (warContents, rootZipFolder, path, classes, jar) =>
			val appFolder = path + "webapps/root/"

			val classSet = classes.map(_._1).toSet
			val filteredContents = warContents.filterNot { case (file, _) => classSet contains file }
			var jarRec = (jar, ("WEB-INF/lib/" + jar.getName))

			appResource(platform, rootZipFolder, (filteredContents ++ Seq(jarRec)) map {
				case (file, path) => (file, (appFolder + path.replace('\\', '/')))
			})
		}

		def jettyDist(platform: String): FileMappingTask = (jetty in Dependencies, distJettyConf in Distribution, rootZipFolder in Distribution, webappFolder in Distribution) map { (jetty, confDir, rootZipFolder, webappFolder) => 
			if (!jetty.exists)
				sys.error("Missing jetty. Please run `fetch-package-dependencies` or download and place in " + jetty + ".")

			val jettyExclusions = List(
				"demo-base/", "etc/", "start.d/", "start.ini"
			).map(webappFolder + _)

			val jettyFiles = jetty.*** x rebase(jetty, webappFolder) map {
				// replace \ in paths with /, for easier matching below
				case (src, dest) => (src, dest.replace('\\', '/'))
			} filter {
				case (_, path) if jettyExclusions exists { path startsWith _ } => println("Excluding " + path); false
				case _ => true
			}

			val jettyConf = confDir.*** x rebase(confDir, webappFolder)

			appResource(platform, rootZipFolder, jettyFiles ++ jettyConf)
		}

		def embeddedAppFiles(platform: String): FileMappingTask = (distCommon in Distribution, rootZipFolder in Distribution) map { (appFolder, rootZipFolder) =>
			appResource(platform, rootZipFolder, appFolder.*** x rebase(appFolder, rootZipFolder))
		}

		def nodeWebkitRuntime(platform: String, nwkKey: SettingKey[File]): FileMappingTask = (nwkKey in Dependencies, resourcer in Dependencies, rootZipFolder in Distribution, distCommon in Distribution, target, version) map { (nwk, resourcer, rootZipFolder, appFolder, target, version) =>
			if (!nwk.exists)
				sys.error("Missing node-webkit for " + platform + ". Please run `fetch-package-dependencies` or download and place in " + nwk + ".")

			val nwkFiles: Seq[ZipEntry] = nwk.*** x rebase(nwk, rootZipFolder) map {
				// replace \ in paths with /, for easier matching below
				case (src, dest) => (src, dest.replace('\\', '/'))
			}

			platform match {
				case "win32" =>
					// on windows, we need nw.pak, icudt.dll, rename nw.exe -> codepulse.exe, libEGL/libGLES and the d3d DLLs
					val inclusions = List(
						"icudt.dll", "libEGL.dll", "libGLESv2.dll", "nw.pak"
					).map(rootZipFolder + _).toSet

					nwkFiles flatMap {
						case ZipEntry(file, path, mode) if path == "codepulse/nw.exe" =>
							// prepare our own copy of nw.exe with appropriately modified icon
							val customizedFile = target / "node-webkit" / "win32" / "codepulse.exe"
							customizedFile.getParentFile.mkdirs
							Files.copy(file.toPath, customizedFile.toPath, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES)

							{
								import scala.sys.process._

								val ico = appFolder / "app" / "icon.ico"

								val args = List(
									(resourcer / "Resourcer.exe").getCanonicalPath,
									"-op:upd",
									"-src:" + customizedFile.getCanonicalPath,
{'fraction_non_alphanumeric': 0.12277879901960784, 'fraction_numerical': 0.002297794117647059, 'mean_word_length': 3.8127534095097677, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 47, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5906342', 'n_tokens_mistral': 4641, 'n_tokens_neox': 3927, 'n_words': 1195}