Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/yurique/embedded-files
An sbt plugin to generate Scala objects containing the contents of glob-specified files as strings or byte-arrays.
https://github.com/yurique/embedded-files
sbt sbt-plugin scala scalajs source-gen source-generation
Last synced: 6 days ago
JSON representation
An sbt plugin to generate Scala objects containing the contents of glob-specified files as strings or byte-arrays.
- Host: GitHub
- URL: https://github.com/yurique/embedded-files
- Owner: yurique
- License: mit
- Created: 2021-01-02T00:28:03.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2023-02-24T18:33:58.000Z (over 1 year ago)
- Last Synced: 2023-03-01T03:02:20.516Z (over 1 year ago)
- Topics: sbt, sbt-plugin, scala, scalajs, source-gen, source-generation
- Language: Scala
- Homepage:
- Size: 114 KB
- Stars: 7
- Watchers: 1
- Forks: 2
- Open Issues: 4
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE.md
Awesome Lists containing this project
README
# embedded-files
An sbt plugin to generate Scala objects containing the contents of glob-specified files as strings or byte-arrays.
The accompanying macro allowing to access those objects more easily: [embedded-files-macro](https://github.com/yurique/embedded-files-macro).
## Installation
### `plugins.sbt`
```scala
addSbtPlugin("com.yurique" % "sbt-embedded-files" % "0.4.0")
```### `build.sbt`
```scala
libraryDependencies += "com.yurique" %%% "embedded-files-macro" % "{embedded-files-macro-version}"
```## Example usage
Put a file into `src/main/resources/docs/test.txt`:
```
I'm a test text.
```Add `embedFiles` to the `Compile / sourceGenerators`:
```scala
project
// ...
.enablePlugins(EmbeddedFilesPlugin)
// ...
.settings(
(Compile / sourceGenerators) += embedFiles
)
```In the code:
```scala
import com.yurique.embedded.FileAsStringval testTxtContents = FileAsString("/docs/test.txt") // "I'm a test text."
```## Configuration
The sbt plugin has the following configuration keys:
```scala
project
// ...
.settings(
// default is __embedded_files, which is assumed by the macro
// the generated objects and classes are put into this package (and sub-packages)
embedRootPackage := "custom_root_package",// a list of directories to look for files to embed in
// default is (Compile / unmanagedResourceDirectories)
embedDirectories ++= (Compile / unmanagedSourceDirectories).value,// a list of globs for text files
// default is Seq("**/*.txt")
embedTextGlobs := Seq("**/*.txt", "**/*.md"),// a list of globs for binary files
// default is Seq.empty
embedBinGlobs := Seq("**/*.bin"),// whether or not to generate a EmbeddedFilesIndex object containing references to all embedded files
// default is false
embedGenerateIndex := true,// the intended usage is to use the output of the embedFiles task as generated sources
(Compile / sourceGenerators) += embedFiles
)
```## Generated files
### Interfaces
The `embedFiles` always generates these two abstract classes:
```scala
package ${embedRootPackage.value}abstract class EmbeddedTextFile {
def path: String
def content: String
}```
and
```scala
package ${embedRootPackage.value}abstract class EmbeddedBinFile {
def path: String
def content: Array[Byte]
}
```### Text files
For each file in the `embedDirectories` that matches any of the `embedTextGlobs` a file like the following is generated:
```scala
package ${embedRootPackage.value}.${subPackage}object ${className} extends __embedded_files.EmbeddedTextFile {
val path: String = """path/to/the/file/filename.txt"""
val content: String = """the content of the file"""
}
```### Binary files
For each file in the `embedDirectories` that matches any of the `embedBinGlobs` a file like the following is generated:
```scala
package ${embedRootPackage.value}.${subPackage}object ${className} extends __embedded_files.EmbeddedBinFile {
val path: String = """path/to/the/file/filename.bin"""
val content: Array[Byte] = Array(
// example bytes
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
)}
```### Package- and class-names
For each file, its path is taken relative to the one of the `embedDirectories` and converted into the package name and the class name.
For example, if the file was `/home/user/.../.../project/src/main/resources/some-dir/1 some sub dir/some things & other things.txt`:
- a relative path is `some-dir/1 some sub dir/some things & other things.txt` (relative to `Compile / unmanagedSourceDirectories` in this example)
- the dirname is `some-dir/1 some sub dir`, it is split by `/`, every part is converted to a valid Scala ID (by replacing non alpha-numerics by `_` and prepending `_` is the path starts with a digit)
- the resulting package name is `some_dir._1_some_sub_dir`
- the class name is derived from the file name: `some_things_other_things`## Index file
if `embedGenerateIndex` is set to `true`, the index file is generated like the following:
```scala
package ${embedRootPackage.value}object EmbeddedFilesIndex {
val textFiles: Seq[(String, EmbeddedTextFile)] = Seq(
"test/test-resource.txt" -> __embedded_files.test.test_resource_txt,
"com/company/test_file_1.txt" -> __embedded_files.com.company.test_file_1_txt
)
val binFiles: Seq[(String, EmbeddedBinFile)] = Seq(
"test/test-bin-resource.bin" -> __embedded_files.test.test_bin_resource_bin,
"com/company/test_bin_file_1.bin" -> __embedded_files.com.company.test_bin_file_1_bin
)
}
```## Transforming text
It is possible to configure a basic `String => String` transformation for text files.
```scala
project
// ...
.settings(
embedDirectories ++= (Compile / unmanagedSourceDirectories).value,
embedTextGlobs := Seq("**/*.md"),
embedTransform := Seq(
TransformConfig(
when = _.getFileName.toString.endsWith(".md"),
transform = _.toUpperCase
)
),
(Compile / sourceGenerators) += embedFiles
)
```For each text file, the `.transform` function of the first of the `TransformConfig`-s that matches the path (`.when` returns `true`)
will be applied to the contents of the file.If none of the configuration matches - the file contents will be used as is.
If more than one configuration matches, only the first one will be used.
## macros
Assuming the `embedFiles` is used as a source generator with the default root package, you can use the macros provided by the `embedded-files-macro` library to get the string/byte-array content of the files like this:
```scala
import com.yurique.embedded._
val s: String = FileAsString("/docs/test.txt")
val b: Array[Byte] = FileAsByteArray("/bins/test.bin")
```If the path passed to the macros starts with a slash, it is used as is.
If it doesn't start with a slash, the macro does the following:
`/home/user/.../project/src/main/scala/com/company/MyClass.scala`
```scala
package com.company.MyClassobject MyClass {
val s: String = FileAsString("dir/data.txt")
}
```Here, the file name doesn't start with a `/` – `dir/data.txt`.
The calling site is in the `/home/user/.../project/src/main/scala/com/company/` directory.
The requested file name is appended to this directory, resulting in `/home/user/.../project/src/main/scala/com/company/dir/data.txt`.
This file is taken relative to the first `scala` directory in the path, resulting in `/com/company/dir/data.txt`.
## Missing embedded files
The macros are not currently doing any checks for whether the embedded files exist. If they don't, `scalac` will just fail to compile.