com.carrotgarden.maven.scalor.scalajs.EnvJS.scala Maven / Gradle / Ivy
package com.carrotgarden.maven.scalor.scalajs
import java.io.File
import java.net.URLClassLoader
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import org.apache.maven.plugins.annotations.Parameter
import org.webjars.WebJarExtractor
import com.carrotgarden.maven.scalor.base
import com.carrotgarden.maven.scalor.util
import com.carrotgarden.maven.tools.Description
import org.apache.maven.project.MavenProject
/**
* Common Scala.js VM environment configuration.
*/
trait EnvConfAny extends AnyRef
with base.ParamsAny {
@Description( """
Enable to log provided JS-VM environment configuration.
Use to review actual settings used to create tesing JS-VM instance:
- full path to the executable
- process launch arguments
- process environment variables
- webjars scripts settings
- runtime.js module settings
- etc.
""" )
@Parameter(
property = "scalor.envconfLogConfig",
defaultValue = "false"
)
var envconfLogConfig : Boolean = _
@Description( """
System properties injected during environment configuration invocation.
Normally includes settings for scala-js-junit-tools
.
Separator parameter: commonSequenceSeparator.
Mapping parameter: commonMappingPattern.
""" )
@Parameter(
property = "scalor.envconfSystemProperties",
defaultValue = """
basedir = ${project.basedir} ★
"""
)
var envconfSystemProperties : String = _
@Description( """
Scala.js testing module script used to run tests inside JavaScript VM environment.
Normally testing module script path should point to the result of Scala.js linker invocation.
""" )
@Parameter(
property = "scalor.envconfModulePath",
defaultValue = "${project.build.testOutputDirectory}/META-INF/resources/webjars/${project.artifactId}/${project.version}/runtime-test.js"
)
var envconfModulePath : File = _
@Description( """
Folder with extracted webjars resources.
Specific scripts should be activated in JavaScript VM via parameter:
envconfWebjarsScriptList
Normally webjars folder should point to the extraction result of the webjars provisioning invocation.
Absolute path.
""" )
@Parameter(
property = "scalor.envconfWebjarsFolder",
defaultValue = "${project.basedir}/test-tool/webjars"
)
var envconfWebjarsFolder : File = _
@Description( """
List of scripts which should be activated inside JavaScript VM during tests.
These scripts must be provided inside the provisioning folder:
envconfWebjarsFolder.
Separator parameter: commonSequenceSeparator.
Relative path.
""" )
@Parameter(
property = "scalor.envconfWebjarsScriptList",
defaultValue = """
"""
)
var envconfWebjarsScriptList : String = _
import com.carrotgarden.sjs.junit._
def paramExec : File
def paramArgs : String
def paramVars : String
def paramType : String
def configurationFile : File = {
Context.configLocation.getCanonicalFile
}
/**
* Report Scala.js JavaScript VM execution environment configuration.
*/
def configurationReport : String = {
import com.carrotgarden.sjs.junit.Config._
val config = Context.configExtract()
Config.configUnparse( config )
}
/**
* Persist Scala.js JavaScript VM execution environment configuration.
*/
def configureEnvironment() : Unit = {
import com.carrotgarden.sjs.junit.Config._
// JS-VM settings.
val envExec = paramExec.getCanonicalPath
val envArgs = parseCommonList( paramArgs ).toList
val envVars = parseCommonMapping( paramVars )
val envType = paramType
val envConf = EnvConf(
envExec = envExec,
envArgs = envArgs,
envVars = envVars,
envType = envType
)
// Webjars resources.
val webjarsDir = envconfWebjarsFolder.getCanonicalPath
val scriptList = parseCommonList( envconfWebjarsScriptList ).toList
val webConf = WebConf(
webjarsDir = webjarsDir,
scriptList = scriptList
)
// Generated runtime.js
val path = envconfModulePath.getCanonicalPath
val module = Config.Module(
path = path
)
// Final configuration.
val config = Config(
envConf = envConf,
webConf = webConf,
module = module
)
// Publish to default location.
Context.configPersist( config )
}
}
/**
* Node.js Scala.js VM environment configuration.
*/
trait EnvConfNodejs extends EnvConfAny {
@Description( """
Absolute path to the Node.js JavaScript VM executable.
Normally should point to the provisioning extraction result.
""" )
@Parameter(
property = "scalor.envconfNodejsExec",
defaultValue = "${project.basedir}/test-tool/node/node"
)
var envconfNodejsExec : File = _
@Description( """
Arguments for the Node.js JavaScript VM executable.
Separator parameter: commonSequenceSeparator.
""" )
@Parameter(
property = "scalor.envconfNodejsArgs",
defaultValue = """
"""
)
var envconfNodejsArgs : String = _
@Description( """
Environment variables for the Node.js JavaScript VM executable.
Normally should define NODE_PATH
to point to the Node.js modules provisioning result.
Separator parameter: commonSequenceSeparator.
Mapping parameter: commonMappingPattern.
Some Node.js environment variables:
NODE_MODULE_CONTEXTS - set to 0 to disable inter-module isolation via sandboxing
NODE_DEBUG - set to comma-separated list of module names to enable logging
NODE_PATH - set to absolute path to the provisioned node_modules folder
""" )
@Parameter(
property = "scalor.envconfNodejsVars",
defaultValue = """
NODE_MODULE_CONTEXTS=0 ★
NODE_PATH=${project.basedir}/test-tool/node/node_modules ★
"""
)
var envconfNodejsVars : String = _
@Description( """
Select JS-VM type.
Available Node.js JavaScript VM environment types:
nodejs-basic - basic Node.js, for non-UI testing, does not expect any node modules
nodejs-jsdom - Node.js with JSdom.js, for broswer-UI testing, must provision 'jsdom' module
""" )
@Parameter(
property = "scalor.envconfNodejsType",
defaultValue = "nodejs-jsdom"
)
var envconfNodejsType : String = _
override def paramExec = envconfNodejsExec
override def paramArgs = envconfNodejsArgs
override def paramVars = envconfNodejsVars
override def paramType = envconfNodejsType
}
/**
* Phantom.js Scala.js VM environment configuration.
*/
trait EnvConfPhantomjs extends EnvConfAny {
@Description( """
Absolute path to the Phantom.js JavaScript VM executable.
Normally should point to the provisioning extraction result.
""" )
@Parameter(
property = "scalor.envconfPhantomjsExec",
defaultValue = "${project.basedir}/test-tool/phantomjs/phantomjs"
)
var envconfPhantomjsExec : File = _
@Description( """
Arguments for the Phantom.js JavaScript VM executable.
Separator parameter: commonSequenceSeparator.
""" )
@Parameter(
property = "scalor.envconfPhantomjsArgs",
defaultValue = """
"""
)
var envconfPhantomjsArgs : String = _
@Description( """
Environment variables for the Phantom.js JavaScript VM executable.
Separator parameter: commonSequenceSeparator.
""" )
@Parameter(
property = "scalor.envconfPhantomjsVars",
defaultValue = """
"""
)
var envconfPhantomjsVars : String = _
@Description( """
Select JS-VM type.
Available Phantom.js JavaScript VM environment types:
phantomjs-basic - basic Phantom.js, for broswer-UI testing
""" )
@Parameter(
property = "scalor.envconfPhantomjsType",
defaultValue = "phantomjs-basic"
)
var envconfPhantomjsType : String = _
override def paramExec = envconfPhantomjsExec
override def paramArgs = envconfPhantomjsArgs
override def paramVars = envconfPhantomjsVars
override def paramType = envconfPhantomjsType
}
/**
* Shared external mojo execution parameters.
*/
trait EnvProvAny extends AnyRef
with base.ParamsAny {
@Description( """
Scala.js test-tool installaton folder used for testing.
Contains provisioned Node.js, Phantom.js, Webjars, etc.
Normally this folder should be excluded from source control
and should not be a part of any clean
execution.
Absolute path.
When changing, make sure to replace test-tool references elsewhere.
""" )
@Parameter(
property = "scalor.envprovTestToolFolder",
defaultValue = "${project.basedir}/test-tool"
)
var envprovTestToolFolder : File = _
def folderTestTool : String = {
val folder = envprovTestToolFolder.getCanonicalFile
folder.mkdirs
folder.getCanonicalPath
}
def hasDetectExecutable( file : File ) = {
file.exists() && file.isFile() && file.canRead() && file.canExecute()
}
}
/**
* Execute external plugin Mojo.
*
* https://github.com/eirslett/frontend-maven-plugin
*/
trait EnvProvNodejs extends EnvProvAny {
self : base.Params =>
@Description( """
A folder inside
envprovTestToolFolder
which contains extracted Node.js.
Relative path.
""" )
@Parameter(
property = "scalor.envprovNodejsFolder",
defaultValue = "node"
)
var envprovNodejsFolder : String = _
@Description( """
Node.js version used to provision node installation.
Select from availabe versions.
""" )
@Parameter(
property = "scalor.envprovNodejsVersion",
defaultValue = "10.0.0"
)
var envprovNodejsVersion : String = _
@Description( """
List of Node.js NPM modules configured for provisioning.
Uses format: module@version.
Separator parameter: commonSequenceSeparator.
Used by npm install.
""" )
@Parameter(
property = "scalor.envprovRnpmjsModules",
defaultValue = """
[email protected] ★
[email protected] ★
[email protected] ★
"""
)
var envprovRnpmjsModules : String = _
@Description( """
List of additional NPM invocation options.
Separator parameter: commonSequenceSeparator.
Used by npm install.
""" )
@Parameter(
property = "scalor.envprovRnpmjsOptions",
defaultValue = """
--save ★
--silent ★
"""
)
var envprovRnpmjsOptions : String = _
@Description( """
URL of the Node.js distribution download.
""" )
@Parameter(
property = "scalor.envprovNodejsURL",
defaultValue = "http://nodejs.org/dist"
)
var envprovNodejsURL : String = _
@Description( """
URL of the Node.js NPM module registry.
Used by npm install.
""" )
@Parameter(
property = "scalor.envprovRnpmjsURL",
defaultValue = "http://registry.npmjs.org"
)
var envprovRnpmjsURL : String = _
def npmModuleList = parseCommonList( envprovRnpmjsModules )
def npmInstallOptions = parseCommonList( envprovRnpmjsOptions )
def folderTestToolNodejs : String = {
val folder = new File( envprovTestToolFolder, envprovNodejsFolder )
folder.mkdirs()
folder.getCanonicalPath
}
def folderTestToolModules : String = {
val folder = new File( folderTestToolNodejs, "node_modules" )
folder.mkdirs()
folder.getCanonicalPath
}
def folderWorkDir : String = {
val folder = project.getBasedir
folder.mkdirs()
folder.getCanonicalPath
}
def provideNodeVersion = {
if ( envprovNodejsVersion.startsWith( "v" ) ) {
envprovNodejsVersion
} else {
s"v${envprovNodejsVersion}"
}
}
val nodeModuleRegex = """([^@]+)(@[.\d]+)?""".r
def parseModuleName( entry : String ) = {
entry match {
case nodeModuleRegex( name, _ ) => name
}
}
/**
* Expected location of executable.
*/
def extractedNodejs : File = {
def hasFile( file : File ) = file.isFile() && file.exists()
val folder = folderTestToolNodejs
val fileNix = new File( folder, "node" )
val fileWin = new File( folder, "node.exe" )
val file =
if ( hasFile( fileNix ) ) {
fileNix
} else if ( hasFile( fileWin ) ) {
fileWin
} else {
util.Error.Throw( s"Missing extracted Node.js executable in ${folder}" )
}
file.getCanonicalFile
}
def configuredNodejs : File = {
val folder = folderTestToolNodejs
val exec = "node" // Node.js convention.
val file = new File( folder, exec )
file.getCanonicalFile
}
def provisionedModuleList : List[ File ] = {
val folder = folderTestToolModules
npmModuleList
.map( entry => parseModuleName( entry ) )
.map( name => new File( folder, name ) )
.toList
}
/**
* Verify if configured Node.js binary is present.
*/
def hasDetectNodejs = {
hasDetectExecutable( configuredNodejs )
}
/**
* Verify if configured NPM modules are present.
*/
def hasDetectModules = {
provisionedModuleList.forall( file => file.exists )
}
/**
* Install Node.js binary.
*/
def provisionNodejs() : Unit = {
import org.twdata.maven.mojoexecutor.MojoExecutor._
val nodeVersion = provideNodeVersion
//
executeMojo( //
plugin( //
groupId( "com.github.eirslett" ), //
artifactId( "frontend-maven-plugin" ), //
version( "1.6" ) //
), //
goal( "install-node-and-npm" ), //
configuration( //
element( "nodeVersion", nodeVersion ), //
element( "nodeDownloadRoot", envprovNodejsURL ), //
element( "workingDirectory", folderWorkDir ), //
element( "installDirectory", folderTestTool ) //
), //
executionEnvironment( project, session, buildManager ) //
)
//
val source = extractedNodejs
val target = configuredNodejs
Files.copy( source.toPath, target.toPath, StandardCopyOption.REPLACE_EXISTING )
target.setReadable( true )
target.setExecutable( true )
}
/**
* Invoke "npm install" to provision node_modules.
*/
def provisionModules() : Unit = {
import org.twdata.maven.mojoexecutor.MojoExecutor._
val modules = npmModuleList.mkString( " " )
val options = npmInstallOptions.mkString( " " )
val prefix = s"--prefix ${folderTestToolNodejs}"
val arguments = s"install ${modules} ${prefix} ${options}"
//
executeMojo( //
plugin( //
groupId( "com.github.eirslett" ), //
artifactId( "frontend-maven-plugin" ), //
version( "1.6" ) //
), //
goal( "npm" ), //
configuration( //
element( "arguments", arguments ), //
element( "npmRegistryURL", envprovRnpmjsURL ), //
element( "workingDirectory", folderWorkDir ), //
element( "installDirectory", folderTestTool ) //
), //
executionEnvironment( project, session, buildManager ) //
)
}
}
/**
* Execute external plugin Mojo.
*
* https://github.com/klieber/phantomjs-maven-plugin
*/
trait EnvProvPhantomjs extends EnvProvAny {
self : base.Params =>
@Description( """
Phantom.js distribution version.
Must be present on Maven Central.
""" )
@Parameter(
property = "scalor.envprovPhantomjsVersion",
defaultValue = "2.1.1"
)
var envprovPhantomjsVersion : String = _
@Description( """
A folder inside
envprovTestToolFolder
which contains extracted Phantom.js.
Relative path.
""" )
@Parameter(
property = "scalor.envprovPhantomjsFolder",
defaultValue = "phantomjs"
)
var envprovPhantomjsFolder : String = _
def folderTestToolPhantomjs : String = {
val folder = new File( envprovTestToolFolder, envprovPhantomjsFolder )
folder.mkdirs()
folder.getCanonicalPath
}
def configuredPhantomjs : File = {
val folder = folderTestToolPhantomjs
val exec = "phantomjs" // Phantom.js convention.
val file = new File( folder, exec )
file.getCanonicalFile
}
/**
* Verify if configured Phantom.js binary is present.
*/
def hasDetectPhantomjs = {
hasDetectExecutable( configuredPhantomjs )
}
/**
* Phantom.js executable extraction path.
*/
val phantomExtractKey = "phantomjs.binary"
/**
* Expected location of executable.
*/
def extractedPhantomjs = {
new File( project.getProperties.getProperty( phantomExtractKey ) )
}
/**
* Install Phantom.js binary.
*/
def provisionPhantomjs() : Unit = {
import org.twdata.maven.mojoexecutor.MojoExecutor._
//
executeMojo( //
plugin( //
groupId( "com.github.klieber" ), //
artifactId( "phantomjs-maven-plugin" ), //
version( "0.7" ) //
), //
goal( "install" ), //
configuration( //
element( "version", envprovPhantomjsVersion ), //
element( "propertyName", phantomExtractKey ), //
element( "outputDirectory", folderTestToolPhantomjs ) //
), //
executionEnvironment( project, session, buildManager ) //
)
//
val source = extractedPhantomjs
val target = configuredPhantomjs
Files.copy( source.toPath, target.toPath, StandardCopyOption.REPLACE_EXISTING )
target.setReadable( true )
target.setExecutable( true )
}
}
/**
* Provision discovered webjars resources.
*/
trait EnvProvWebjars extends EnvProvAny {
self : base.Params =>
@Description( """
A folder inside
envprovTestToolFolder
which contains extracted Webjars.
Relative path.
""" )
@Parameter(
property = "scalor.envprovWebjarsFolder",
defaultValue = "webjars"
)
var envprovWebjarsFolder : String = _
/**
* Webjars extraction folder.
*/
def configuredWebjars : File = {
val folder = new File( folderTestTool, envprovWebjarsFolder )
folder.mkdirs()
folder.getCanonicalFile
}
/**
* Webjars discovery class path.
*/
def webjarsClassLoader : URLClassLoader = {
val entryList = projectClassPath().map( _.toURI.toURL )
new URLClassLoader( entryList )
}
/**
* Provision discovered webjars resources.
*/
def provisionWebjarsResources() : Unit = {
val cache = new WebJarExtractor.MemoryCache()
val loader = webjarsClassLoader
val extractor = new WebJarExtractor( cache, loader )
extractor.extractAllWebJarsTo( configuredWebjars )
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy