-
Notifications
You must be signed in to change notification settings - Fork 326
/
Copy pathStdBits.scala
154 lines (144 loc) · 5.55 KB
/
StdBits.scala
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import LibraryManifestGenerator.BundledLibrary
import sbt.Keys._
import sbt._
import sbt.internal.util.ManagedLogger
import sbt.io.IO
import sbt.librarymanagement.{ConfigurationFilter, DependencyFilter}
import java.io.File
import scala.sys.process.Process
object StdBits {
/** Discovers dependencies of a project and copies them into the destination
* directory.
*
* @param destination location where to put the dependencies
* @param baseJarName name of the base generated JAR (if any); unexpected
* (old) files are removed, so this task needs to know
* this file's name to avoid removing it
* @param ignoreScalaLibrary whether to ignore Scala dependencies that are
* added by default be SBT and are not relevant in
* pure-Java projects
*/
def copyDependencies(
destination: File,
baseJarName: Option[String],
ignoreScalaLibrary: Boolean,
unpackedDeps: Set[String] = Set()
): Def.Initialize[Task[Unit]] =
Def.task {
val libraryUpdates = (Compile / update).value
val log = streams.value.log
val baseFilter: NameFilter = new ExactFilter(Configurations.Runtime.name)
val validConfig =
if (ignoreScalaLibrary) baseFilter - new ExactFilter(Configurations.ScalaTool.name)
else baseFilter
val configFilter: ConfigurationFilter =
DependencyFilter.configurationFilter(name = validConfig)
val graalOrg = new ExactFilter("org.graalvm.sdk")
val relevantFiles =
libraryUpdates
.select(
configuration = configFilter,
module = DependencyFilter.moduleFilter(organization = -graalOrg),
artifact = DependencyFilter.artifactFilter()
)
val dependencyStore =
streams.value.cacheStoreFactory.make("std-bits-dependencies")
Tracked.diffInputs(dependencyStore, FileInfo.hash)(relevantFiles.toSet) {
report =>
val expectedFileNames =
report.checked.map(
getDestinationFileName(_, unpackedDeps)
) ++ baseJarName.toSeq
for (existing <- IO.listFiles(destination)) {
if (!expectedFileNames.contains(existing.getName)) {
log.info(
s"Removing outdated std-bits dependency ${existing.getName}."
)
IO.delete(existing)
}
}
for (changed <- report.modified -- report.removed) {
log.info(
s"Updating changed std-bits dependency ${changed.getName}."
)
updateDependency(changed, unpackedDeps, destination, log)
}
for (file <- report.unmodified) {
val dest = destination / getDestinationFileName(file, unpackedDeps)
if (!dest.exists()) {
log.info(s"Adding missing std-bits dependency ${file.getName}.")
updateDependency(file, unpackedDeps, destination, log)
}
}
}
}
private def shouldUnpack(jar: File, unpacked: Set[String]): Boolean = {
// Maven stores dependencies like this:
// .../repo1.maven.org/maven2/org/apache/xmlbeans/xmlbeans/5.0.1/xmlbeans-5.0.1.jar
// therefore, the parent of the parent of the jar file is the directory
// named with the un-versioned library name.
unpacked.contains(jar.getParentFile.getParentFile.getName)
}
private def updateDependency(
jar: File,
unpacked: Set[String],
destinationDir: File,
logger: ManagedLogger
): Unit = {
val destination = destinationDir / getDestinationFileName(jar, unpacked)
if (shouldUnpack(jar, unpacked)) {
destination.mkdirs()
val exitCode = Process(s"jar xf ${jar.getAbsolutePath}", destination).!
if (exitCode != 0) {
logger.err(s"Could not unpack a dependency jar: $jar.")
throw new RuntimeException(s"Could not unpack a dependency jar: $jar.")
}
} else {
IO.copyFile(jar, destination)
}
}
private def getDestinationFileName(
file: File,
unpacked: Set[String]
): String = {
if (shouldUnpack(file, unpacked)) {
val name = file.getName
name.stripSuffix(".jar")
} else file.getName
}
/**
* Builds a single standard library package `name`. Should only be used
* in tasks used in local development.
*
* @param name name of the package, see `stdBitsProjects` in build.sbt
* @param root top directory where distribution is being built
* @param cache used for persisting the cached information
* @param log logger used in the task
* @param defaultDevEnsoVersion default `dev` version
*/
def buildStdLibPackage(
name: String,
root: File,
cacheFactory: sbt.util.CacheStoreFactory,
log: sbt.Logger,
defaultDevEnsoVersion: String
) = {
log.info(s"Building standard library package for '$name'")
val prefix = "Standard"
val targetPkgRoot = root / "lib" / prefix / name / defaultDevEnsoVersion
val sourceDir = file(s"distribution/lib/$prefix/$name/$defaultDevEnsoVersion")
if (!sourceDir.exists) {
throw new RuntimeException("Invalid standard library package " + name)
}
val result = DistributionPackage.copyDirectoryIncremental(
source = file(s"distribution/lib/$prefix/$name/$defaultDevEnsoVersion"),
destination = targetPkgRoot,
cache = cacheFactory.sub("engine-libraries").make(s"$prefix.$name"),
)
if (result) {
log.info(s"Package '$name' has been updated")
} else {
log.info(s"No changes detected for '$name' package")
}
}
}