forked from zio/zio-cli
-
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.
Add support for reading command-line options from file(s) (zio#191)
- Loading branch information
1 parent
1d8058f
commit 042fe3b
Showing
12 changed files
with
371 additions
and
50 deletions.
There are no files selected for viewing
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
5 changes: 5 additions & 0 deletions
5
zio-cli/js/src/main/scala/zio/cli/FileArgsPlatformSpecific.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,5 @@ | ||
package zio.cli | ||
|
||
trait FileArgsPlatformSpecific { | ||
val default: FileArgs = FileArgs.Noop | ||
} |
5 changes: 5 additions & 0 deletions
5
zio-cli/jvm/src/main/scala/zio/cli/FileArgsPlatformSpecific.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,5 @@ | ||
package zio.cli | ||
|
||
trait FileArgsPlatformSpecific { | ||
val default: FileArgs = FileArgs.Live | ||
} |
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,82 @@ | ||
package zio.cli | ||
|
||
import zio._ | ||
import zio.internal.stacktracer.SourceLocation | ||
import zio.test._ | ||
|
||
import java.nio.file.{Files, Path} | ||
|
||
object LiveFileArgsSpec extends ZIOSpecDefault { | ||
|
||
private val createTempDirectory: RIO[Scope, Path] = | ||
for { | ||
random <- Random.nextUUID | ||
path <- | ||
ZIO.attempt(Files.createTempDirectory(random.toString)).withFinalizer(f => ZIO.attempt(f.toFile.delete()).orDie) | ||
} yield path | ||
|
||
private def resolvePath(path: Path, paths: List[String]): Path = | ||
if (paths.nonEmpty) path.resolve(paths.mkString("/")) | ||
else path | ||
|
||
private def makeTest(name: String)(cwd: List[String], home: List[String])( | ||
writeFiles: (List[String], String)* | ||
)( | ||
exp: (List[String], List[String])* | ||
)(implicit loc: SourceLocation): Spec[Scope, Throwable] = | ||
test(name) { | ||
for { | ||
// setup | ||
dir <- createTempDirectory | ||
_ <- TestSystem.putProperty("user.dir", resolvePath(dir, cwd).toString) | ||
_ <- TestSystem.putProperty("user.home", resolvePath(dir, home).toString) | ||
_ <- ZIO.foreachDiscard(writeFiles) { case (paths, contents) => | ||
val writePath = resolvePath(dir, paths :+ s".$cmd") | ||
val parentFile = writePath.getParent.toFile | ||
ZIO.attempt(parentFile.mkdirs()).unlessZIO(ZIO.attempt(parentFile.exists())) *> | ||
ZIO.writeFile(writePath, contents) | ||
} | ||
|
||
// test | ||
result <- FileArgs.Live.getArgsFromFile(cmd) | ||
resolvedExp = exp.toList.map { case (paths, args) => | ||
FileArgs.ArgsFromFile(resolvePath(dir, paths :+ s".$cmd").toString, args) | ||
} | ||
|
||
} yield assertTrue(result == resolvedExp) | ||
} | ||
|
||
private val cmd: String = "command" | ||
|
||
override def spec: Spec[TestEnvironment with Scope, Any] = | ||
suite("FileArgsSpec")( | ||
makeTest("empty")(List("abc", "home"), List("abc", "home"))()(), | ||
makeTest("home in cwd parent path")(List("abc", "home", "d", "e", "f"), List("abc", "home"))( | ||
List("abc", "home", "d") -> "d\nd\n\n", | ||
List("abc", "home", "d", "e") -> "e\ne\n\n", | ||
List("abc", "home", "d", "e", "f") -> "f\nf\n\n", | ||
List("abc", "home") -> "_home_" | ||
)( | ||
List("abc", "home", "d", "e", "f") -> List("f", "f"), | ||
List("abc", "home", "d", "e") -> List("e", "e"), | ||
List("abc", "home", "d") -> List("d", "d"), | ||
List("abc", "home") -> List("_home_") // only appears once | ||
), | ||
makeTest("home not in cwd parent path")(List("abc", "cwd", "d", "e", "f"), List("abc", "home"))( | ||
List("abc", "cwd", "d") -> "d\nd\n\n", | ||
List("abc", "cwd", "d", "e") -> "e\ne\n\n", | ||
List("abc", "cwd", "d", "e", "f") -> "f\nf\n\n", | ||
List("abc", "home") -> "_home_" | ||
)( | ||
List("abc", "cwd", "d", "e", "f") -> List("f", "f"), | ||
List("abc", "cwd", "d", "e") -> List("e", "e"), | ||
List("abc", "cwd", "d") -> List("d", "d"), | ||
List("abc", "home") -> List("_home_") | ||
), | ||
makeTest("parent dirs of home are not searched")(Nil, List("abc", "home"))( | ||
List("abc") -> "a\nb" | ||
)( | ||
) | ||
) @@ TestAspect.withLiveRandom | ||
|
||
} |
5 changes: 5 additions & 0 deletions
5
zio-cli/native/src/main/scala/zio/cli/FileArgsPlatformSpecific.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,5 @@ | ||
package zio.cli | ||
|
||
trait FileArgsPlatformSpecific { | ||
val default: FileArgs = FileArgs.Live | ||
} |
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
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
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,61 @@ | ||
package zio.cli | ||
|
||
import zio._ | ||
import java.nio.file.Path | ||
|
||
trait FileArgs { | ||
def getArgsFromFile(command: String): UIO[List[FileArgs.ArgsFromFile]] | ||
} | ||
object FileArgs extends FileArgsPlatformSpecific { | ||
|
||
final case class ArgsFromFile(path: String, args: List[String]) | ||
|
||
case object Noop extends FileArgs { | ||
override def getArgsFromFile(command: String): UIO[List[ArgsFromFile]] = ZIO.succeed(Nil) | ||
} | ||
|
||
case object Live extends FileArgs { | ||
|
||
private def optReadPath(path: Path): UIO[Option[FileArgs.ArgsFromFile]] = | ||
(for { | ||
exists <- ZIO.attempt(path.toFile.exists()) | ||
pathString = path.toString | ||
optContents <- | ||
ZIO | ||
.readFile(pathString) | ||
.map(c => FileArgs.ArgsFromFile(pathString, c.split('\n').map(_.trim).filter(_.nonEmpty).toList)) | ||
.when(exists) | ||
} yield optContents) | ||
.catchAllCause(ZIO.logErrorCause(s"Error reading options from file '$path', skipping...", _).as(None)) | ||
|
||
private def getPathAndParents(path: Path): Task[List[Path]] = | ||
for { | ||
parentPath <- ZIO.attempt(Option(path.getParent)) | ||
parents <- parentPath match { | ||
case Some(parentPath) => getPathAndParents(parentPath) | ||
case None => ZIO.succeed(Nil) | ||
} | ||
} yield path :: parents | ||
|
||
override def getArgsFromFile(command: String): UIO[List[ArgsFromFile]] = | ||
(for { | ||
cwd <- System.property("user.dir") | ||
home <- System.property("user.home") | ||
commandFile = s".$command" | ||
|
||
pathsFromCWD <- cwd match { | ||
case Some(cwd) => ZIO.attempt(Path.of(cwd)).flatMap(getPathAndParents) | ||
case None => ZIO.succeed(Nil) | ||
} | ||
homePath <- ZIO.foreach(home)(p => ZIO.attempt(Path.of(p))) | ||
allPaths = (pathsFromCWD ::: homePath.toList).distinct | ||
|
||
argsFromFiles <- ZIO.foreach(allPaths) { path => | ||
ZIO.attempt(path.resolve(commandFile)).flatMap(optReadPath) | ||
} | ||
} yield argsFromFiles.flatten) | ||
.catchAllCause(ZIO.logErrorCause(s"Error reading options from files, skipping...", _).as(Nil)) | ||
|
||
} | ||
|
||
} |
Oops, something went wrong.