@@ -4,6 +4,7 @@ import java.nio.file.FileSystems
4
4
5
5
import scala .collection .mutable
6
6
import scala .util .control .NoStackTrace
7
+ import scala .util .matching .Regex
7
8
8
9
import bloop .cli .CommonOptions
9
10
import bloop .config .Config
@@ -21,7 +22,8 @@ final case class SourceGenerator(
21
22
sourcesGlobs : List [SourcesGlobs ],
22
23
outputDirectory : AbsolutePath ,
23
24
unmangedInputs : List [AbsolutePath ],
24
- command : List [String ]
25
+ command : List [String ],
26
+ commandTemplate : Option [List [String ]]
25
27
) {
26
28
27
29
/**
@@ -66,7 +68,14 @@ final case class SourceGenerator(
66
68
logger : Logger ,
67
69
opts : CommonOptions
68
70
): Task [SourceGenerator .Run ] = {
69
- val cmd = (command :+ outputDirectory.syntax) ++ inputs.keys.map(_.syntax)
71
+ val cmd =
72
+ buildCommand(
73
+ outputDirectory.syntax,
74
+ inputs.keys.map(_.syntax).toSeq,
75
+ unmangedInputs.keys.map(_.syntax).toSeq,
76
+ logger
77
+ )
78
+
70
79
logger.debug { () =>
71
80
cmd.mkString(s " Running source generator: ${System .lineSeparator()}$$ " , " " , " " )
72
81
}
@@ -79,6 +88,28 @@ final case class SourceGenerator(
79
88
}
80
89
}
81
90
91
+ private def buildCommand (
92
+ outputDirectory : String ,
93
+ inputs : Seq [String ],
94
+ unmangedInputs : Seq [String ],
95
+ logger : Logger
96
+ ): Seq [String ] =
97
+ commandTemplate match {
98
+ case None =>
99
+ (command :+ outputDirectory) ++ inputs
100
+ case Some (cmd) =>
101
+ val substs = Map [String , Seq [String ]](
102
+ SourceGenerator .Arg .Output -> Seq (outputDirectory),
103
+ SourceGenerator .Arg .Inputs -> inputs,
104
+ SourceGenerator .Arg .UnmanagedInputs -> unmangedInputs
105
+ ).withDefault { name =>
106
+ logger.warn(s " Couldn't find substitution for ` $name`, consider escaping it with a $$ . " )
107
+ Seq .empty[String ]
108
+ }
109
+
110
+ cmd.flatMap(SourceGenerator .Arg .substitute(substs)(_))
111
+ }
112
+
82
113
private def needsUpdate (previous : SourceGenerator .Run ): Task [SourceGenerator .Changes ] = {
83
114
previous match {
84
115
case SourceGenerator .NoRun =>
@@ -141,6 +172,33 @@ object SourceGenerator {
141
172
unamanagedInputs : Map [AbsolutePath , Int ]
142
173
) extends Changes
143
174
175
+ private object Arg {
176
+ private val Single : Regex = """ ((?:\$)+)\{([a-zA-Z]+)\}""" .r
177
+ private val Anywhere : Regex = Single .unanchored
178
+
179
+ // TODO: make these configurable in some way?
180
+ val Inputs = " inputs"
181
+ val Output = " output"
182
+ val UnmanagedInputs = " unmanaged"
183
+
184
+ def substitute (substs : Map [String , Seq [String ]])(s : String ): Seq [String ] =
185
+ s match {
186
+ case Single (" $" , name) => substs(name)
187
+ case _ =>
188
+ Seq (Anywhere .replaceAllIn(s, m => Regex .quoteReplacement(replace(m, substs))))
189
+ }
190
+
191
+ private def replace (mtch : Regex .Match , substs : Map [String , Seq [String ]]): String = {
192
+ val dollars = mtch.group(1 ).size
193
+ val name = mtch.group(2 )
194
+ val value =
195
+ if (dollars % 2 == 0 ) s " { $name} "
196
+ else substs(name).mkString(" " )
197
+
198
+ s " ${" $" * (dollars / 2 )}$value"
199
+ }
200
+ }
201
+
144
202
def fromConfig (cwd : AbsolutePath , generator : Config .SourceGenerator ): SourceGenerator = {
145
203
val sourcesGlobs = generator.sourcesGlobs.map {
146
204
case Config .SourcesGlobs (directory, depth, includes, excludes) =>
@@ -159,7 +217,9 @@ object SourceGenerator {
159
217
sourcesGlobs,
160
218
AbsolutePath (generator.outputDirectory),
161
219
generator.unmanagedInputs.map(AbsolutePath .apply),
162
- generator.command
220
+ generator.command,
221
+ // TODO: change to `generator.commandTemplate` after PR to bloop-config is merged
222
+ None
163
223
)
164
224
}
165
225
0 commit comments