Skip to content

Commit

Permalink
[feat] support conda platforms (#31)
Browse files Browse the repository at this point in the history
* [feat] support conda platforms

Support specifying conda platforms (e.g. from conda-lock):

 For example
```
   - conda:
     channels:
       - conda-forge
       - bioconda
     requirements:
       - samtools
       - fgbio=1.1.0
     platforms:
       - linux-32
       - osx-arm64
       - win32
```

* Apply suggestions from code review
  • Loading branch information
nh13 authored Mar 1, 2023
1 parent 534950b commit 68660e3
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
package com.github.condaincubator.condaenvbuilder.api

import CondaStep.Channel
import com.github.condaincubator.condaenvbuilder.api.CondaStep.Channel
import com.github.condaincubator.condaenvbuilder.api.Platform.Platform
import io.circe.Decoder.Result
import io.circe.syntax._
import io.circe.{Decoder, Encoder, HCursor, Json}

import scala.collection.mutable.ArrayBuffer

/** Specifies the conda channels and requirements for a conda environment.
*
* @param channels the conda channels, in priority order
* @param requirements the package requirements.
*/
case class CondaStep(channels: Seq[Channel]=Seq.empty, requirements: Seq[Requirement]=Seq.empty) extends StepWithDefaults {
case class CondaStep(channels: Seq[Channel]=Seq.empty, requirements: Seq[Requirement]=IndexedSeq.empty, platforms: Seq[Platform]=IndexedSeq.empty) extends StepWithDefaults {

/** Inherit (in-order) channels and requirements from the given step(s).
*
Expand All @@ -23,6 +26,7 @@ case class CondaStep(channels: Seq[Channel]=Seq.empty, requirements: Seq[Require
this.copy(
channels = (steps.flatMap(_.channels) ++ this.channels).distinct,
requirements = Requirement.join(parent=steps.flatMap(_.requirements), child=requirements),
platforms = (steps.flatMap(_.platforms) ++ this.platforms).distinct,
)
}

Expand All @@ -36,6 +40,7 @@ case class CondaStep(channels: Seq[Channel]=Seq.empty, requirements: Seq[Require
this.copy(
channels = (this.channels ++ _defaults.channels).distinct,
requirements = Requirement.withDefaults(requirements=this.requirements, defaults=_defaults.requirements),
platforms = (this.platforms ++ _defaults.platforms).distinct,
)
case _ => this
}
Expand All @@ -50,6 +55,10 @@ case class CondaStep(channels: Seq[Channel]=Seq.empty, requirements: Seq[Require
* requirements:
* - samtools
* - fgbio=1.1.0
* platforms:
* - linux-32
* - osx-arm64
* - win32
* }}}
*
* Both `channels` and `requirements` are optional.
Expand All @@ -63,10 +72,13 @@ object CondaStep {

/** Returns an YAML encoder for [[CondaStep]] */
def encoder: Encoder[CondaStep] = new Encoder[CondaStep] {
final def apply(step: CondaStep): Json = Json.obj(
("channels", Json.fromValues(step.channels.map(_.asJson))),
("requirements", Json.fromValues(step.requirements.map(_.asJson)))
)
final def apply(step: CondaStep): Json = {
val fields = ArrayBuffer[(String, Json)]()
fields.append(("channels", Json.fromValues(step.channels.map(_.asJson))))
fields.append(("requirements", Json.fromValues(step.requirements.map(_.asJson))))
if (step.platforms.nonEmpty) fields.append(("platforms", Json.fromValues(step.platforms.map(_.asJson))))
Json.obj(fields.toSeq:_*)
}
}

/** Returns a YAML decoder for [[CondaStep]] */
Expand All @@ -86,11 +98,17 @@ object CondaStep {
else Right(Seq.empty)
}

val platformResults: Result[Seq[Platform]] = {
if (keys.contains("platforms")) c.downField("platforms").as[Seq[Platform]]
else Right(Seq.empty)
}

for {
channels <- channelsResults
requirements <- requirementsResults
platforms <- platformResults
} yield {
CondaStep(channels=channels, requirements=requirements)
CondaStep(channels=channels, requirements=requirements, platforms=platforms)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.github.condaincubator.condaenvbuilder.api

/** The name of the platform (e.g. linux-32, linux-armv7l, win-64, osx-arm64) */
object Platform {
type Platform = String
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,22 @@ object CondaStepTest extends UnitSpec {
| ]
|}""".stripMargin
}),
// one channel, one requirement
(api.CondaStep(channels=Seq("some channel"), requirements=Seq("a==1").reqs), {
// one channel, one requirement, one platform
(api.CondaStep(channels=Seq("some channel"), requirements=Seq("a==1").reqs, platforms=Seq("linux-32")), {
"""{
| "channels" : [
| "some channel"
| ],
| "requirements" : [
| "a==1"
| ],
| "platforms" : [
| "linux-32"
| ]
|}""".stripMargin
}),
// multiple channels and requirements
(api.CondaStep(channels=Seq("channel 1", "channel 2"), requirements=Seq("a==1", "b==2").reqs), {
// multiple channels, requirements, and platforms
(api.CondaStep(channels=Seq("channel 1", "channel 2"), requirements=Seq("a==1", "b==2").reqs, platforms=Seq("linux-32", "win-32")), {
"""{
| "channels" : [
| "channel 1",
Expand All @@ -36,11 +39,15 @@ object CondaStepTest extends UnitSpec {
| "requirements" : [
| "a==1",
| "b==2"
| ],
| "platforms" : [
| "linux-32",
| "win-32"
| ]
|}""".stripMargin
}),
// empty requirements, empty channels
(CondaStep(channels=Seq.empty, requirements=Seq.empty), {
(CondaStep(channels=Seq.empty, requirements=Seq.empty, platforms=Seq.empty), {
"""{
| "channels" : [
| ],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ class ToolsTest extends UnitSpec {
| - python=3.6.10
| - samtools=1.10
| - yaml=0.1.7
| platforms:
| - linux-32
| - pip:
| requirements:
| - defopt==5.1.0
Expand Down Expand Up @@ -81,6 +83,8 @@ class ToolsTest extends UnitSpec {
| requirements:
| - pybedtools=0.8.1
| - yaml=0.1.7
| platforms:
| - linux-32
| - pip:
| args: []
| requirements:
Expand All @@ -101,6 +105,8 @@ class ToolsTest extends UnitSpec {
| requirements:
| - samtools=1.9
| - hisat2=2.2.0
| platforms:
| - linux-32
| bwa:
| group: alignment
| steps:
Expand All @@ -111,6 +117,8 @@ class ToolsTest extends UnitSpec {
| requirements:
| - samtools=1.9
| - bwa=0.7.17
| platforms:
| - linux-32
| samtools:
| group: alignment
| steps:
Expand All @@ -119,7 +127,9 @@ class ToolsTest extends UnitSpec {
| - conda-forge
| - bioconda
| requirements:
| - samtools=1.9""".stripMargin
| - samtools=1.9
| platforms:
| - linux-32""".stripMargin
}

val tabulatedString: String = {
Expand Down Expand Up @@ -150,6 +160,8 @@ class ToolsTest extends UnitSpec {
| - bioconda
| requirements:
| - samtools=1.9
| platforms:
| - linux-32
| bwa:
| group: alignment
| steps:
Expand All @@ -160,6 +172,8 @@ class ToolsTest extends UnitSpec {
| requirements:
| - samtools=1.9
| - bwa=0.7.17
| platforms:
| - linux-32
| hisat2:
| group: alignment
| steps:
Expand All @@ -170,6 +184,8 @@ class ToolsTest extends UnitSpec {
| requirements:
| - samtools=1.9
| - hisat2=2.2.0
| platforms:
| - linux-32
| conda-env-builder:
| group: conda-env-builder
| steps:
Expand All @@ -181,6 +197,8 @@ class ToolsTest extends UnitSpec {
| - pybedtools=0.8.1
| - yaml=0.1.7
| - pip==default
| platforms:
| - linux-32
| - pip:
| args: []
| requirements:
Expand All @@ -206,6 +224,8 @@ class ToolsTest extends UnitSpec {
| - bioconda
| requirements:
| - samtools=1.9
| platforms:
| - linux-32
| bwa:
| group: alignment
| steps:
Expand All @@ -216,6 +236,8 @@ class ToolsTest extends UnitSpec {
| requirements:
| - samtools=1.9
| - bwa=0.7.17
| platforms:
| - linux-32
| hisat2:
| group: alignment
| steps:
Expand All @@ -226,6 +248,8 @@ class ToolsTest extends UnitSpec {
| requirements:
| - samtools=1.9
| - hisat2=2.2.0
| platforms:
| - linux-32
| conda-env-builder:
| group: conda-env-builder
| steps:
Expand All @@ -236,6 +260,8 @@ class ToolsTest extends UnitSpec {
| requirements:
| - pybedtools=0.8.1
| - yaml=0.1.7
| platforms:
| - linux-32
| - pip:
| args: []
| requirements:
Expand Down

0 comments on commit 68660e3

Please sign in to comment.