Is it possible to use wildcards in sbt IO.copy command - sbt

I have defined an sbt task to copy files from one directory to another:
val inDir = crossTarget.value / "inFolder
val outDir = file("jvm/target/outFolder")
val files = Seq("scrip1.js", "script2.js").map { p => (inDir / p, outDir / p) }
IO.copy(files, overwrite = true, preserveLastModified = false, preserveExecutable = false)
Is it possible to modify this just to copy all files with a .js extension?

Yes.
val files = (inDir * "*.js").pair(f => outDir / f.name).get
See https://www.scala-sbt.org/1.x/api/sbt/io/PathFinder.html

Related

How to add a private dependency to a manifest.toml file in Julia?

I am trying to commit my manifest.toml file for a private Julia project that has a private dependancy. In the manifest.toml file, it has a local path to the project for the private dependancy as follows:
[[Private_Package]]
deps = ["AbstractTrees", "D3Trees", "DataStructures", "Distributions", "LinearAlgebra", "POMDPs", "Parameters", "Printf", "Random", "StatsBase"]
path = "/Users/logankilpatrick/.julia/dev/Private_Package"
uuid = "rand-rand-rand"
version = "0.X.0"
How can I keep this in my manifest file but make sure it's not a local path so I can commit to the repo?
I ended up going with Pkg.add() per #kevbonham suggestion. It did the trick:
[[Private_Package]]
deps = ["AbstractTrees", "D3Trees", "DataStructures", "Distributions", "LinearAlgebra", "POMDPs", "Parameters", "Printf", "Random", "StatsBase"]
git-tree-sha1 = "x_x_x"
repo-rev = "master"
repo-url = "https://github.com/Private_Package/Private_Package.git"
uuid = "rand-rand-rand-rand-rand"
version = "0.2.0"
Thank you both #DavidVarela

Passing a project to an sbt dynamic task

I have a sbt project that includes code generation.
Part of the build.sbt is
lazy val generator = (project in file("generator")).
settings(mainClass := Some("com.example.Generator"))
lazy val generate = (project in file("generate")).
dependsOn(generator).
settings(runGeneration)
def runGeneration: SettingsDefinition = sourceGenerators in Compile += Def.taskDyn {
val cachedFun = FileFunction.cached(
streams.value.cacheDirectory / "generation"
) { (in: Set[File]) =>
val dir = (sourceManaged in Compile).value
(generator / run in Compile).toTask(" " + dir.getAbsolutePath).value
collectFiles(dir)
}
val dependentFiles = ((generator / fullClasspath in Compile) map { cp => cp.files }).taskValue.value
val genFiles = cachedFun(dependenctFiles).toSeq
Def.task {
genFiles
}
}.taskValue
This seems to work and only generate files when a dependency has changed. However, I expect to have multiple generators. Rather than copy the code, I attempted to pass the generator project to it:
lazy val generate = (project in file("generate")).
dependsOn(generator).
settings(runGeneration(generator))
def runGeneration(p: project): SettingsDefinition =
<same as before but with p instead of generator>
This results in an error parsing the build file:
build.sbt:155: error: Illegal dynamic reference: File
val dependentFiles = ((p / fullClasspath in Compile) map { cp => cp.files }).taskValue.value
^
[error] sbt.compiler.EvalException: Type error in expression
[error] sbt.compiler.EvalException: Type error in expression
I am guessing the problem is that it cannot figure out at compile time if there is a dependency loop, so it convervatively gives an error.
Is there a way to get this to work? Is there an entirely different construct that lets me know if running generator will produce a different result?
The underlying problem is that task definitions in sbt have two components, which look like they can be intermingled, but cannot. If you write code like
Def.task {
val doIt = checkIfShouldDoIt()
if (doIt) {
someTask.value
} else {
()
}
}
this naively looks like it will only run someTask if doIt is true. What actually happens is that someTask.value declares a dependency of this task on someTask and someTask is run before anything is done for this task. To write the above code in a way that more directly maps to what actually happens, one would write
Def.task {
val someTaskValue = someTask.value
val doIt = checkIfShouldDoIt()
if (doIt) {
someTaskValue
} else {
()
}
}
The attempt to run the task only when the dependencies had changed could not work in a single task.
My working solution does the following. I modified the generator to take an additional argument and do nothing if that argument was false. The two tasks were
// Task to check if we need to generate
def checkGeneration(p: Project) = Def.taskDyn {
var needToGenerate = false
val cachedFunction = FileFunction.cached(someDir) {
(in: Set[File]) =>
needToGenerate = ! in.isEmpty
Set()
}
val dependentFiles = ((p / fullClasspath in Compile) map { cp => cp.files }).taskValue
Def.task {
cachedFun(dependentFiles.value.toSet)
needToGenerate
}
}
// Task to run generation
def runGeneration(p: Project): SettingsDefinition = sourceGenerators in Compile += Def.taskDyn {
val needToGenerate = checkGeneration(p).value
Def.task {
// Run generator as before but pass needToGenerate as additional argument
...
// Used FileFunction.cached as before to find the generated files (but not run the generator)
...
}
}
It is possible that I have more dynamic tasks than I need, but this works.

Replace variable in text file with sbt

I have legacy SBT build file. As a part of build process I need to replace one specific string in text file.
Specifically in Play Framework application in public/index.html file I need to replace placeholder string to GA UUID code.
Actually an additional "in Compile" is missing from the confirmed solution (contributed by Aki):
resourceGenerators in Compile += Def.task {
val content = IO.read((resourceDirectory in Compile).value / "index.html")
val out = (resourceManaged in Compile).value / "index.html"
IO.write(out, content.replace("<build-time>", System.currentTimeMillis.toString))
Seq(out)
}
I would have added a comment but I don't have enough "reputation" :)
You can write a custom resource generator that reads your file, replaces the placeholder and writes it to a file.
resourceGenerators in Compile += Def.task {
val content = IO.read(resourceDirectory.value / "index.html")
val out = (resourceManaged in Compile).value / "index.html"
IO.write(out, content.replace("<build-time>", System.currentTimeMillis.toString))
Seq(out)
}

os.walk ignore directorys and its content

i'm trying to ignore some directory and the files in it in specific path and this is my code
x = open(wbCMD, 'a')
x.write('set path="C:\Program Files\WinRAR\";%path% c:/Program Files/WinRAR/\n')
x.write('Rar.exe a -r "Backup.rar" -m5 -ep1')
chkdict = {}
setdef = chkdict.setdefault
for root, dirs, files in os.walk(foldername):
if ignoreddirs in dirs:
continue
for file in files:
ext = path.splitext(file)[1]
if ext in ignored:
continue
if not ext in chkdict:
print("%s" % setdef(ext,ext))
x.write(" *%s" % setdef(ext,ext))
x.write(" *makefile *Depend *readme\npause")
x.close
del chkdict
ignoreddirs array looks like this
ignoreddirs = ["bin"]
dirs and ignoreddirs are both lists of strings. Therefore, dirs does not contain ignoreddirs. It may, however contain some of its elements. One way to check this would be to check their intersection:
if len(set(ignoreddirs).intersection(set(dirs))) > 0:
continue

Producing two separate jars for sources and resources with package in SBT?

Because of the large size of some resource files, I'd like sbt package to create 2 jar files at the same time, e.g. project-0.0.1.jar for the classes and project-0.0.1-res.jar for the resources.
Is this doable?
[SOLUTION] based on the answer below thanks to #gilad-hoch
1) unmanagedResources in Compile := Seq()
Now it's just classes in the default jar.
2)
val packageRes = taskKey[File]("Produces a jar containing only the resources folder")
packageRes := {
val jarFile = new File("target/scala-2.10/" + name.value + "_" + "2.10" + "-" + version.value + "-res.jar")
sbt.IO.jar(files2TupleRec("", file("src/main/resources")), jarFile, new java.util.jar.Manifest)
jarFile
}
def files2TupleRec(pathPrefix: String, dir: File): Seq[Tuple2[File, String]] = {
sbt.IO.listFiles(dir) flatMap {
f => {
if (f.isFile) Seq((f, s"${pathPrefix}${f.getName}"))
else files2TupleRec(s"${pathPrefix}${f.getName}/", f)
}
}
}
(packageBin in Compile) <<= (packageBin in Compile) dependsOn (packageRes)
Now when I do "sbt package", both the default jar and a resource jar are produced at the same time.
to not include the resources in the main jar, you could simply add the following line:
unmanagedResources in Compile := Seq()
to add another jar, you could define a new task. it would generally be something like that:
use sbt.IO jar method to create the jar.
you could use something like:
def files2TupleRec(pathPrefix: String, dir: File): Seq[Tuple2[File,String]] = {
sbt.IO.listFiles(dir) flatMap {
f => {
if(f.isFile) Seq((f,s"${pathPrefix}${f.getName}"))
else files2TupleRec(s"${pathPrefix}${f.getName}/",f)
}
}
}
files2TupleRec("",file("path/to/resources/dir")) //usually src/main/resources
or use the built-in methods from Path to create the sources: Traversable[(File, String)] required by the jar method.
that's basically the whole deal...

Resources