Home Code Other Software

Table of Contents

Introduction

sbt-editsource is a text substitution plugin for SBT 0.13.x and greater. In a way, it’s a poor man’s sed(1), for SBT. It provides the ability to apply line-by-line substitutions to a source text file, producing an edited output file. It supports two kinds of edits:

Each of these capabilities is explained in more detail, below.

Getting the Plugin

Within your SBT project, create project/plugins/build.sbt (if it doesn’t already exist) and add the following:

addSbtPlugin("org.clapper" % "sbt-editsource" % "1.0.0")

The plugin is cross-built for both SBT 0.13.x and 1.0.x.

Settings and Tasks

The plugin provides the following new settings and tasks.

Note: sbt-editsource uses predefined SBT settings, where possible (e.g., sources). Of course, that’s not always possible. To be sure you’re updating the correct setting, always use the form:

settingName in EditSource

For instance:

flatten in EditSource := false

Settings

The plugin provides the following new settings.

sources

The source files to be edited. For instance, suppose you want to edit all files under “src” ending in “.txt”. To do so, use:

sources in EditSource ++= (baseDirectory.value / "src" * "*.txt").get

If you also want to apply the edits to all files ending in “.md”, use either:

sources in EditSource ++= (baseDirectory.value / "src" * "*.txt").get
sources in EditSource ++= (baseDirectory.value / "src" * "*.md").get

or, more succinctly:

sources in EditSource ++= (baseDirectory.value / "src" * "*.txt").get ++
                          (baseDirectory.value / "src" * "*.md").get

targetDirectory

The directory to which to write the edited versions of the source files. For example:

targetDirectory in EditSource := baseDirectory.value / "target"

See also flatten, below.

flatten

If flatten is true, then the edited files will all be placed directly in targetDirectory; if there are name clashes, then some files will be overwritten. If flatten is false, then the partial path to each source file is preserved in the target directory.

An example will help clarify. Consider the following file tree:

Directory tree

Let’s assume you’re editing all the files ending in “.md”, into the target directory.

sources in EditSource ++= (baseDirectory.value / "src" * "*.md").get
targetDirectory in EditSource := baseDirectory.value / "target"

With

flatten in EditSource := false

(which is the default), you’ll end up with the following edited versions:

However, if you set:

flatten in EditSource := true

the edit operation will put all the edited versions of all three files directly in the target directory, yielding:

variables

variables is a sequence of (variableName, value) pairs. Let’s take a look at some examples. We’re going to define substitutions for three keys:

variables in EditSource += "projectName" -> name.value
variables in EditSource += "version" -> version.value
variables in EditSource += "author" -> "Brian Clapper"

Once you’ve defined those variables, you’re free to substitute them in your files.

Predefined variables

Editsource provides some predefined variables for you:

Using Variables in your Source Files

Inside a source file to be edited, variable references are of the form ${varname}, as in the Unix shell. A shortened $varname is also support. The ${} long form also supports a default syntax: ${varname?default}. If the reference variable has no value, then the default value is supplied, instead. (The ?default syntax is not supported for the short form reference.)

With the above definitions in place, when the source files are edited, any reference to ${projectName} is replaced with “my-project”, and any reference to ${author} is replaced with “Brian Clapper”.

You can define any number of variables. If the edit logic encounters a variable that isn’t defined, it simply replaces the variable reference with an empty string (like bash does).

In addition to the variables you define in your build file, the sbt-editsource also honors the following special variable prefixes:

substitutions

substitutions is a sequence of regular expression edits, of the form:

sub(regex, replacement)
sub(regex, replacement, flags)

There’s only one (optional) flag right now:

Additional flags can be specified inline, as indicated in the documentation for the java.util.regex.Pattern class.

For example, to replace the first occurrence of the word “test” in each line with “TEST”, without regard to case, you might use:

substitutions in EditSource += sub("""(?i)\btest\b""".r, "TEST")

The “(?i)” is the embedded option sequence that tells the regular expression parser to use case-blind comparison.

Similarly, to replace all occurrences of the word “test”, with regard to case, you might use:

substitutions in EditSource += sub("""\btest\b""".r, "TEST", SubAll)

You can specify multiple substitutions, of course:

substitutions in EditSource ++= Seq(
    sub("""^#""".r, "//"),
    sub("""\b(?i)simple build tool\b""".r, "Scalable Build Tool", SubAll)
)

Also, regular expression capturing groups are supported, so you can use more complex regular expression substitutions like this:

// Remove everything up to, but not including the word "foo", but save
// the "foo" and everything after.

sub("""^.*(foo.*)$""".r, "$1")

NOTE: Regular expression substitutions are run after variable substitutions.

Tasks

The plugin provides two new SBT tasks.

Hooking the edit task into the compile phase

If you want the run editsource:edit every time you run compile, just add this line to your build.sbt:

compile in Compile := ((compile in Compile) dependsOn (edit in EditSource)).value

Restrictions

Change log

The change log for all releases is here.

Author

Brian M. Clapper, bmc@clapper.org

Copyright and License

This software is copyright © 2010-2018 Brian M. Clapper and is released under a BSD License.

Patches

I gladly accept patches from their original authors. Feel free to email patches to me or to fork the GitHub repository and send me a pull request. Along with any patch you send: