Skip to content

Commit

Permalink
Improve package manager abstraction
Browse files Browse the repository at this point in the history
  • Loading branch information
ptrdom committed May 5, 2022
1 parent 0245694 commit 8dd72a1
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 79 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import java.io.File

import sbt._
import scalajsbundler.util.Commands
import scalajsbundler.util.JSON

/**
* Attempts to smoothen platform-specific differences when invoking commands.
*
* @param name Name of the command to run
*/
abstract class PackageManager(name: String, args: Seq[String]) {
abstract class PackageManager(val name: String, val args: Seq[String], val installCommand: String) {

/**
* Runs the command `cmd`
Expand All @@ -26,6 +27,61 @@ abstract class PackageManager(name: String, args: Seq[String]) {
case _ => Seq(name)
}

def install(baseDir: File,
installDir: File,
logger: Logger): Unit = {
this match {
case lfs: LockFileSupport =>
lfs.lockFileRead(baseDir, installDir, logger)
case _ =>
()
}

run(installCommand +: args: _*)(installDir, logger)

this match {
case lfs: LockFileSupport =>
lfs.lockFileWrite(baseDir, installDir, logger)
case _ =>
()
}
}

val packageJsonContents: Map[String, JSON]
}

trait AddPackagesSupport { this: PackageManager =>

val addPackagesCommand: String

/**
* Locally install NPM packages
*
* @param baseDir The (sub-)project directory which contains yarn.lock
* @param installDir The directory in which to install the packages
* @param logger sbt logger
* @param npmPackages Packages to install (e.g. "webpack", "[email protected]")
*/
def addPackages(baseDir: File,
installDir: File,
logger: Logger,
)(npmPackages: String*): Unit = {
this match {
case lfs: LockFileSupport =>
lfs.lockFileRead(baseDir, installDir, logger)
case _ =>
()
}

run(addPackagesCommand +: (args ++ npmPackages): _*)(installDir, logger)

this match {
case lfs: LockFileSupport =>
lfs.lockFileWrite(baseDir, installDir, logger)
case _ =>
()
}
}
}

trait LockFileSupport {
Expand Down Expand Up @@ -61,67 +117,23 @@ trait LockFileSupport {
}

case class Npm(
args: Seq[String] = Seq.empty,
lockFileName: String = "package-lock.json"
) extends PackageManager("npm", args)
lockFileName: String = "package-lock.json",
override val args: Seq[String] = Seq.empty,
addPackagesCommand: String = "install"
) extends PackageManager("npm", args, "install")
with LockFileSupport
with AddPackagesSupport {
override val packageJsonContents: Map[String, JSON] = Map.empty
}

case class Yarn(
args: Seq[String] = Yarn.DefaultArgs,
lockFileName: String = "yarn.lock"
) extends PackageManager("yarn", args)
with LockFileSupport
version: String,
lockFileName: String = "yarn.lock",
override val args: Seq[String] = Yarn.DefaultArgs,
addPackagesCommand: String = "add") extends PackageManager("yarn", args, "install")
with LockFileSupport with AddPackagesSupport {
override val packageJsonContents: Map[String, JSON] = Map("packageManager" -> JSON.str(s"yarn@$version"))
}
object Yarn {
val DefaultArgs: Seq[String] = Seq("--non-interactive", "--mutex", "network")
}

object PackageManager {

/**
* Locally install NPM packages
*
* @param baseDir The (sub-)project directory which contains yarn.lock
* @param installDir The directory in which to install the packages
* @param useYarn Whether to use yarn or npm
* @param logger sbt logger
* @param npmExtraArgs Additional arguments to pass to npm
* @param npmPackages Packages to install (e.g. "webpack", "[email protected]")
*/
def addPackages(baseDir: File,
installDir: File,
logger: Logger,
packageManager: PackageManager
)(npmPackages: String*): Unit = {
val maybeLockFileWrapper = packageManager match {
case lfs: LockFileSupport => () =>
case _ =>
}
if (useYarn) {
syncYarnLockfile(baseDir, installDir, logger) {
Yarn.run("add" +: (yarnOptions ++ yarnExtraArgs ++ npmPackages): _*)(
installDir,
logger)
}
} else {
syncNpmLockfile(baseDir, installDir, logger) {
Npm.run("install" +: (npmPackages ++ npmExtraArgs): _*)(installDir, logger)
}
}
}

def install(baseDir: File,
installDir: File,
logger: Logger,
npmExtraArgs: Seq[String],
yarnExtraArgs: Seq[String]): Unit =
if (useYarn) {
syncYarnLockfile(baseDir, installDir, logger) {
Yarn.run("install" +: (yarnOptions ++ yarnExtraArgs): _*)(installDir,
logger)
}
} else {
syncNpmLockfile(baseDir, installDir, logger) {
Npm.run("install" +: npmExtraArgs: _*)(installDir, logger)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ object PackageJson {
currentConfiguration: Configuration,
webpackVersion: String,
webpackDevServerVersion: String,
webpackCliVersion: String
webpackCliVersion: String,
packageManager: PackageManager
): Unit = {
val npmManifestDependencies = NpmDependencies.collectFromClasspath(fullClasspath)
val dependencies =
Expand Down Expand Up @@ -62,7 +63,7 @@ object PackageJson {
val packageJson =
JSON.obj(
(
additionalNpmConfig.toSeq :+
(additionalNpmConfig.toSeq ++ packageManager.packageJsonContents.toSeq) :+
"dependencies" -> JSON.objStr(resolveDependencies(dependencies, npmResolutions, log)) :+
"devDependencies" -> JSON.objStr(resolveDependencies(devDependencies, npmResolutions, log))
): _*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package scalajsbundler.sbtplugin

import java.nio.file.Path
import scalajsbundler.ExternalCommand

import sbt._
import scalajsbundler.PackageManager

object NpmUpdateTasks {

Expand All @@ -21,12 +22,10 @@ object NpmUpdateTasks {
def npmUpdate(baseDir: File,
targetDir: File,
packageJsonFile: File,
useYarn: Boolean,
jsResources: Seq[(String, Path)],
streams: Keys.TaskStreams,
npmExtraArgs: Seq[String],
yarnExtraArgs: Seq[String]): File = {
val dir = npmInstallDependencies(baseDir, targetDir, packageJsonFile, useYarn, streams, npmExtraArgs, yarnExtraArgs)
packageManager: PackageManager): File = {
val dir = npmInstallDependencies(baseDir, targetDir, packageJsonFile, streams, packageManager)
npmInstallJSResources(targetDir, jsResources, Seq.empty, streams)
dir
}
Expand All @@ -45,18 +44,16 @@ object NpmUpdateTasks {
def npmInstallDependencies(baseDir: File,
targetDir: File,
packageJsonFile: File,
useYarn: Boolean,
streams: Keys.TaskStreams,
npmExtraArgs: Seq[String],
yarnExtraArgs: Seq[String]): File = {
packageManager: PackageManager): File = {
val log = streams.log
val cachedActionFunction =
FileFunction.cached(
streams.cacheDirectory / "scalajsbundler-npm-install",
inStyle = FilesInfo.hash
) { _ =>
log.info("Updating NPM dependencies")
ExternalCommand.install(baseDir, targetDir, useYarn, log, npmExtraArgs, yarnExtraArgs)
packageManager.install(baseDir, targetDir, log)
Set.empty
}
cachedActionFunction(Set(packageJsonFile))
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package scalajsbundler.sbtplugin

import sbt._

import scalajsbundler.PackageManager
import scalajsbundler.{BundlerFile, PackageJson}
import scalajsbundler.util.{Caching, JSON}

Expand Down Expand Up @@ -31,7 +31,8 @@ object PackageJsonTasks {
webpackVersion: String,
webpackDevServerVersion: String,
webpackCliVersion: String,
streams: Keys.TaskStreams
streams: Keys.TaskStreams,
packageManager: PackageManager
): BundlerFile.PackageJson = {

val hash = Seq(
Expand Down Expand Up @@ -63,7 +64,8 @@ object PackageJsonTasks {
configuration,
webpackVersion,
webpackDevServerVersion,
webpackCliVersion
webpackCliVersion,
packageManager
)
()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import org.scalajs.sbtplugin.ScalaJSPlugin.autoImport._
import org.scalajs.sbtplugin.{ScalaJSPlugin, Stage}
import sbt.Keys._
import sbt.{Def, _}
import scalajsbundler.AddPackagesSupport
import scalajsbundler.{BundlerFile, NpmDependencies, Webpack, WebpackDevServer}
import scalajsbundler.ExternalCommand.addPackages
import scalajsbundler.Npm
import scalajsbundler.PackageManager
import scalajsbundler.Yarn
import scalajsbundler.util.{JSON, ScalaJSNativeLibraries}


Expand Down Expand Up @@ -578,7 +580,10 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
if (!jsdomDir.exists()) {
log.info(s"Installing jsdom in ${installDir.absolutePath}")
IO.createDirectory(installDir)
addPackages(baseDir, installDir, useYarn.value, log, npmExtraArgs.value, yarnExtraArgs.value)(s"jsdom@$jsdomVersion")
packageManager.value match {
case aps: AddPackagesSupport =>
aps.addPackages(baseDir, installDir, log)(s"jsdom@$jsdomVersion")
}
}
installDir
}
Expand Down Expand Up @@ -610,10 +615,7 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
baseDirectory.value,
(crossTarget in npmUpdate).value,
scalaJSBundlerPackageJson.value.file,
useYarn.value,
streams.value,
npmExtraArgs.value,
yarnExtraArgs.value),
streams.value, packageManager.value),

npmInstallJSResources := NpmUpdateTasks.npmInstallJSResources(
(crossTarget in npmUpdate).value,
Expand All @@ -633,7 +635,8 @@ object ScalaJSBundlerPlugin extends AutoPlugin {
(version in webpack).value,
(version in startWebpackDevServer).value,
webpackCliVersion.value,
streams.value
streams.value,
packageManager.value
),


Expand Down

0 comments on commit 8dd72a1

Please sign in to comment.