Skip to content

Commit

Permalink
Merge pull request #3124 from broadinstitute/ks_cwl_dir
Browse files Browse the repository at this point in the history
CWL updates to add directories and additional files.
  • Loading branch information
kshakir committed Jan 11, 2018
2 parents 063a451 + 1feb1e5 commit 796ad7f
Show file tree
Hide file tree
Showing 51 changed files with 1,802 additions and 641 deletions.
Empty file removed Running
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package cromwell.backend.io

import cats.instances.list._
import cats.syntax.traverse._
import cats.syntax.validated._
import common.validation.ErrorOr._
import common.validation.Validation._
import cromwell.backend.io.DirectoryFunctions._
import cromwell.core.path.{Path, PathFactory}
import wom.expression.IoFunctionSet
import wom.values.{WomFile, WomGlobFile, WomMaybeListedDirectory, WomMaybePopulatedFile, WomSingleFile, WomUnlistedDirectory}

import scala.concurrent.Future

trait DirectoryFunctions extends IoFunctionSet with PathFactory {
override def listAllFilesUnderDirectory(dirPath: String): Future[Seq[String]] = {
temporaryImplListPaths(dirPath)
}

// TODO: WOM: WOMFILE: This will likely use a Tuple2(tar file, dir list file) for each dirPath.
private final def temporaryImplListPaths(dirPath: String): Future[Seq[String]] = {
val errorOrPaths = for {
dir <- validate(buildPath(ensureSlashed(dirPath)))
files <- listFiles(dir)
} yield files.map(_.pathAsString)
Future.fromTry(errorOrPaths.toTry(s"Error listing files under $dirPath"))
}
}

object DirectoryFunctions {
def ensureSlashed(dir: String): String = if (dir.endsWith("/")) dir else s"$dir/"

def listFiles(path: Path): ErrorOr[List[Path]] = {
if (path.isDirectory) {
for {
pathListing <- validate(path.list.toList)
pathsPerListing <- pathListing.traverse(listFiles)
} yield pathsPerListing.flatten
} else {
List(path).valid
}
}

def listWomSingleFiles(womFile: WomFile, pathFactory: PathFactory, pathPatcher: String => String): ErrorOr[List[WomSingleFile]] = {
def listWomSingleFiles(womFile: WomFile): ErrorOr[List[WomSingleFile]] = {
womFile match {
case womSingleFile: WomSingleFile => List(womSingleFile).valid

case womUnlistedDirectory: WomUnlistedDirectory =>
val errorOrListPaths = listFiles(pathFactory.buildPath(ensureSlashed(pathPatcher(womUnlistedDirectory.value))))
errorOrListPaths.map(_.map(path => WomSingleFile(path.pathAsString)))

case womMaybePopulatedFile: WomMaybePopulatedFile =>
val allFiles: List[WomFile] =
womMaybePopulatedFile.valueOption.toList.map(WomSingleFile) ++ womMaybePopulatedFile.secondaryFiles
allFiles.traverse(listWomSingleFiles).map(_.flatten)

case w: WomMaybeListedDirectory =>
(w.valueOption, w.listingOption) match {
case (None, None) => Nil.valid
case (Some(value), None) => listWomSingleFiles(WomUnlistedDirectory(value))
case (None, Some(listing)) => listing.toList.traverse(listWomSingleFiles).map(_.flatten)
// TODO: WOM: WOMFILE: This is a special case where files from a different path are supposed to end up under the directory. If this implementation is correct, remove this TODO.
case (Some(_), Some(listing)) => listing.toList.traverse(listWomSingleFiles).map(_.flatten)
}
// TODO: WOM: WOMFILE: How did a glob get here? Should this link into glob functions to list the globs?

case _: WomGlobFile => s"Unexpected glob / unable to list glob files at this time: $womFile".invalidNel
}
}

listWomSingleFiles(womFile)
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cromwell.backend.standard

import akka.actor.ActorRef
import cromwell.backend.io.GlobFunctions
import cromwell.backend.io.{DirectoryFunctions, GlobFunctions}
import cromwell.backend.wdl.{ReadLikeFunctions, WriteFunctions}
import cromwell.core.CallContext
import cromwell.core.io.{AsyncIo, DefaultIoCommandBuilder, IoCommandBuilder}
Expand All @@ -17,7 +17,7 @@ trait StandardExpressionFunctionsParams {
def callContext: CallContext

def ioActorProxy: ActorRef

def executionContext: ExecutionContext
}

Expand All @@ -29,10 +29,10 @@ case class DefaultStandardExpressionFunctionsParams(override val pathBuilders: L

// TODO: Once we figure out premapping and postmapping, maybe we can standardize that behavior. Currently that's the most important feature that subclasses override.
class StandardExpressionFunctions(val standardParams: StandardExpressionFunctionsParams)
extends GlobFunctions with ReadLikeFunctions with WriteFunctions {
extends GlobFunctions with DirectoryFunctions with ReadLikeFunctions with WriteFunctions {

override lazy val ec = standardParams.executionContext

protected lazy val ioCommandBuilder: IoCommandBuilder = DefaultIoCommandBuilder

override lazy val asyncIo = new AsyncIo(standardParams.ioActorProxy, ioCommandBuilder)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,8 @@ class TestReadLikeFunctions(sizeResult: Try[Double]) extends IoFunctionSet {

override def glob(pattern: String): Future[Seq[String]] = ???

override def listAllFilesUnderDirectory(dirPath: String): Future[Seq[String]] = ???

override def size(params: Seq[Try[WomValue]]): Future[WomFloat] = Future.fromTry(sizeResult.map(WomFloat.apply))

override def copyFile(pathFrom: String, targetName: String): Future[WomSingleFile] = ???
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/scala/cromwell/core/NoIoFunctionSet.scala
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ case object NoIoFunctionSet extends IoFunctionSet {

override def glob(pattern: String): Future[Seq[String]] = throw new NotImplementedError("glob is not available here")

override def listAllFilesUnderDirectory(dirPath: String): Nothing =
throw new NotImplementedError("listAllFilesUnderDirectory is not available here")

override def size(params: Seq[Try[WomValue]]): Future[WomFloat] = Future.failed(new NotImplementedError("size is not available here"))
}
26 changes: 13 additions & 13 deletions core/src/test/scala/cromwell/util/SampleWdl.scala
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ object SampleWdl {
|workflow wf_hello {
| call hello
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

val Addressee = "wf_hello.hello.addressee"
val rawInputs = Map(Addressee -> "world")
Expand Down Expand Up @@ -172,7 +172,7 @@ object SampleWdl {
| goodbye.empty
| }
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

val rawInputs = Map.empty[String, Any]
val outputMap = Map(
Expand Down Expand Up @@ -470,7 +470,7 @@ object SampleWdl {
|workflow postfix {
| call hello
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)
}

object ZeroOrMorePostfixQuantifierWorkflowWithArrayInput extends ZeroOrMorePostfixQuantifier {
Expand Down Expand Up @@ -501,7 +501,7 @@ object SampleWdl {
|workflow postfix {
| call hello
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)
}

object OneOrMorePostfixQuantifierWorkflowWithArrayInput extends OneOrMorePostfixQuantifier {
Expand All @@ -528,7 +528,7 @@ object SampleWdl {
|workflow wf_whereami {
| call whereami
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

override val rawInputs: Map[String, Any] = Map.empty
}
Expand All @@ -553,7 +553,7 @@ object SampleWdl {
| input: strs = strings
| }
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)
override val rawInputs: Map[String, Any] = Map.empty
}

Expand Down Expand Up @@ -687,7 +687,7 @@ object SampleWdl {
| }
| call D {input: D_in = B.B_out}
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

override lazy val rawInputs = Map.empty[String, String]
}
Expand All @@ -708,7 +708,7 @@ object SampleWdl {
| }
| call D {input: D_in = B.B_out}
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

override lazy val rawInputs = Map.empty[String, String]
}
Expand Down Expand Up @@ -814,7 +814,7 @@ object SampleWdl {
| input: input_files = do_scatter.count_file
| }
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)
}

val contents =
Expand Down Expand Up @@ -877,7 +877,7 @@ object SampleWdl {
| call a {input: in = f}
| call a as b {input: in = a.out}
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

private val fileContents = s"foo bar baz"

Expand Down Expand Up @@ -921,7 +921,7 @@ object SampleWdl {
| call a {input: in = f}
| call a as b {input: in = a.out}
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

private val fileContents = s"foo bar baz"

Expand Down Expand Up @@ -972,7 +972,7 @@ object SampleWdl {
| map = in_map
| }
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

override val rawInputs = {
Map(
Expand Down Expand Up @@ -1048,7 +1048,7 @@ object SampleWdl {
|workflow w {
| call t
|}
""".stripMargin.replaceAll("RUNTIME", runtime)
""".stripMargin.replace("RUNTIME", runtime)

val tempDir = DefaultPathBuilder.createTempDirectory("CallCachingHashingWdl")
val cannedFile = createCannedFile(prefix = "canned", contents = "file contents", dir = Option(tempDir))
Expand Down
3 changes: 2 additions & 1 deletion cwl/src/main/scala-2.11/cwl/CwlExecutableValidation.scala
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ import wom.executable.Executable.{InputParsingFunction, ParsedInputMap}
// (ExecutableValidation.scala has more info on why this was necessary)
object CwlExecutableValidation {

implicit val f = implicitly[Decoder[File]]
implicit val fileDecoder = implicitly[Decoder[File]]
implicit val directoryDecoder = implicitly[Decoder[Directory]]

// Decodes the input file, and build the ParsedInputMap
private val inputCoercionFunction: InputParsingFunction =
Expand Down
14 changes: 6 additions & 8 deletions cwl/src/main/scala-2.12/cwl/CwlExecutableValidation.scala
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
package cwl

import io.circe._
import io.circe.Decoder
import io.circe.shapes._
import io.circe.generic.auto._
import io.circe.refined._
import io.circe.yaml
import io.circe.literal._
import common.Checked
import common.validation.Checked._
import common.validation.ErrorOr.ErrorOr
import io.circe.generic.auto._
import io.circe.literal._
import io.circe.shapes._
import io.circe.{Decoder, yaml}
import wom.callable.{CallableTaskDefinition, ExecutableCallable, ExecutableTaskDefinition}
import wom.executable.Executable
import wom.executable.Executable.{InputParsingFunction, ParsedInputMap}
Expand All @@ -19,7 +16,8 @@ import wom.executable.Executable.{InputParsingFunction, ParsedInputMap}
// (ExecutableValidation.scala has more info on why this was necessary)
object CwlExecutableValidation {

implicit val f = implicitly[Decoder[File]]
implicit val fileDecoder = implicitly[Decoder[File]]
implicit val directoryDecoder = implicitly[Decoder[Directory]]

// Decodes the input file, and build the ParsedInputMap
private val inputCoercionFunction: InputParsingFunction =
Expand Down
19 changes: 15 additions & 4 deletions cwl/src/main/scala/cwl/ArgumentToCommandPart.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,23 @@
package cwl

import shapeless._
import cwl.command.StringCommandPart
import shapeless._
import wom.CommandPart

object ArgumentToCommandPart extends Poly1 {
implicit def script = at[Expression] { CwlExpressionCommandPart.apply }
implicit def caseStringOrExpression: Case.Aux[StringOrExpression, CommandPart] = at {
_.fold(this)
}

implicit def caseExpression: Case.Aux[Expression, CommandPart] = at {
CwlExpressionCommandPart.apply
}

implicit def clb = at[CommandLineBinding] { CommandLineBindingCommandPart.apply }
implicit def caseString: Case.Aux[String, CommandPart] = at {
StringCommandPart.apply
}

implicit def string = at[String] { StringCommandPart.apply }
implicit def caseCommandLineBinding: Case.Aux[CommandLineBinding, CommandPart] = at {
CommandLineBindingCommandPart.apply
}
}

0 comments on commit 796ad7f

Please sign in to comment.