forked from eikek/docspell
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Extend config for external commands (eikek#2536)
Allows to configure external commands and provide different arguments based on runtime values, like language. It extends the current config of a command to allow a `arg-mappings` section. An example for ocrmypdf: ```conf ocrmypdf = { enabled = true command = { program = "ocrmypdf" ### new arg-mappings arg-mappings = { "mylang" = { value = "{{lang}}" mappings = [ { matches = "deu" args = [ "-l", "deu", "--pdf-renderer", "sandwich" ] }, { matches = ".*" args = [ "-l", "{{lang}}" ] } ] } } #### end new arg-mappings args = [ ### will be replaced with corresponding args from "mylang" mapping "{{mylang}}", "--skip-text", "--deskew", "-j", "1", "{{infile}}", "{{outfile}}" ] timeout = "5 minutes" } working-dir = ${java.io.tmpdir}"/docspell-convert" } ``` The whole section will be first processed to replace all `{{…}}` patterns with corresponding values. Then `arg-mappings` will be looked at and the first match (value == matches) in its `mappings` array is used to replace its name in the arguments to the command.
- Loading branch information
Showing
21 changed files
with
368 additions
and
357 deletions.
There are no files selected for viewing
212 changes: 0 additions & 212 deletions
212
modules/common/src/main/scala/docspell/common/SystemCommand.scala
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
89 changes: 89 additions & 0 deletions
89
modules/common/src/main/scala/docspell/common/exec/ExternalCommand.scala
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
* Copyright 2020 Eike K. & Contributors | ||
* | ||
* SPDX-License-Identifier: AGPL-3.0-or-later | ||
*/ | ||
|
||
package docspell.common.exec | ||
|
||
import docspell.common.Duration | ||
import docspell.common.Ident | ||
import docspell.common.exec.Env | ||
import docspell.common.exec.ExternalCommand.ArgMapping | ||
import docspell.common.exec.SysCmd | ||
|
||
final case class ExternalCommand( | ||
program: String, | ||
args: Seq[String], | ||
timeout: Duration, | ||
env: Map[String, String] = Map.empty, | ||
argMappings: Map[Ident, ArgMapping] = Map.empty | ||
) { | ||
def withVars(vars: Map[String, String]): ExternalCommand.WithVars = | ||
ExternalCommand.WithVars(this, vars) | ||
|
||
import ExternalCommand.pattern | ||
|
||
def resolve(vars: Map[String, String]): SysCmd = { | ||
val replace = ExternalCommand.replaceString(vars) _ | ||
val resolvedArgMappings = | ||
argMappings.view.mapValues(_.resolve(replace).firstMatch).toMap | ||
val resolvedArgs = args.map(replace).flatMap { arg => | ||
resolvedArgMappings | ||
.find(e => pattern(e._1.id) == arg) | ||
.map(_._2) | ||
.getOrElse(List(arg)) | ||
} | ||
|
||
SysCmd(replace(program), resolvedArgs: _*) | ||
.withTimeout(timeout) | ||
.withEnv(_ => Env(env).modifyValue(replace)) | ||
} | ||
} | ||
|
||
object ExternalCommand { | ||
private val openPattern = "{{" | ||
private val closePattern = "}}" | ||
|
||
private def pattern(s: String): String = s"${openPattern}${s}${closePattern}" | ||
|
||
def apply(program: String, args: Seq[String], timeout: Duration): ExternalCommand = | ||
ExternalCommand(program, args, timeout, Map.empty, Map.empty) | ||
|
||
final case class ArgMapping( | ||
value: String, | ||
mappings: List[ArgMatch] | ||
) { | ||
private[exec] def resolve(replace: String => String): ArgMapping = | ||
ArgMapping(replace(value), mappings.map(_.resolve(replace))) | ||
|
||
def firstMatch: List[String] = | ||
mappings.find(am => value.matches(am.matches)).map(_.args).getOrElse(Nil) | ||
} | ||
|
||
final case class ArgMatch( | ||
matches: String, | ||
args: List[String] | ||
) { | ||
private[exec] def resolve(replace: String => String): ArgMatch = | ||
ArgMatch(replace(matches), args.map(replace)) | ||
} | ||
|
||
private def replaceString(vars: Map[String, String])(in: String): String = | ||
vars.foldLeft(in) { case (result, (name, value)) => | ||
val key = s"{{$name}}" | ||
result.replace(key, value) | ||
} | ||
|
||
final case class WithVars(cmd: ExternalCommand, vars: Map[String, String]) { | ||
def resolved: SysCmd = cmd.resolve(vars) | ||
def append(more: (String, String)*): WithVars = | ||
WithVars(cmd, vars ++ more.toMap) | ||
|
||
def withVar(key: String, value: String): WithVars = | ||
WithVars(cmd, vars.updated(key, value)) | ||
|
||
def withVarOption(key: String, value: Option[String]): WithVars = | ||
value.map(withVar(key, _)).getOrElse(this) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.