Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dof/_src/checkpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ def from_prefix(cls, prefix: str, uuid: str, tags: List[str] = []):
build_number=prefix_record.build_number,
subdir=prefix_record.subdir,
conda_channel=prefix_record.channel.url(),
sha256=prefix_record.sha256,
md5=prefix_record.md5,
# TODO
arch="",
# not sure here
Expand Down
4 changes: 2 additions & 2 deletions dof/_src/lock.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from rattler import solve, Platform

from dof._src.models.environment import CondaEnvironmentSpec, EnvironmentSpec, EnvironmentMetadata
from dof._src.models.package import UrlCondaPackage
from dof._src.models.package import UrlPackage
from dof._src.utils import hash_string


Expand All @@ -23,7 +23,7 @@ def lock_environment(path: str, target_platform: str | None = None) -> Environme

url_packages = []
for pkg in solution_packages:
url_packages.append(UrlCondaPackage(url = pkg.url))
url_packages.append(UrlPackage(url = pkg.url))

env_metadata = EnvironmentMetadata(
platform = str(target_platform),
Expand Down
26 changes: 26 additions & 0 deletions dof/_src/models/conda_lock.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
from typing import Any, Optional

from pydantic import BaseModel


class CondaLockMetadata(BaseModel):
channels: list[dict[str, Any]]
content_hash: dict[str, str]
platforms: list[str]
sources: list[str]

class CondaLockPackage(BaseModel):
category: str
name: str
version: str
dependencies: dict[str, str]
hash: dict[str, str]
manager: str
optional: bool
platform: str
url: Optional[str] = None

class CondaLockFile(BaseModel):
metadata: CondaLockMetadata
package: list[CondaLockPackage]
version: int
21 changes: 21 additions & 0 deletions dof/_src/models/environment.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from pydantic import BaseModel, Field

from dof._src.models import package
from dof._src.models import conda_lock


class CondaEnvironmentSpec(BaseModel):
Expand Down Expand Up @@ -32,6 +33,26 @@ class EnvironmentSpec(BaseModel):
packages: List[package.Package]
env_vars: Optional[Dict[str, str]] = None

def to_conda_lock_file(self) -> str:
channels = [{"url": chn} for chn in self.metadata.channels]
packages = [
pkg.to_conda_lock_package(self.metadata.platform)
for pkg in self.packages
]
return conda_lock.CondaLockFile(
metadata = conda_lock.CondaLockMetadata(
channels = channels,
platforms = [self.metadata.platform],
sources = ["prefixdata"],
content_hash = {}
),
package = packages,
version = 1,
)

def to_pixi_lock_file(self) -> str:
return "pixi lockfile"


class EnvironmentCheckpoint(BaseModel):
"""An environment at a point in time
Expand Down
58 changes: 46 additions & 12 deletions dof/_src/models/package.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from rattler import RepoDataRecord, PackageRecord
from pydantic import BaseModel

from dof._src.models import conda_lock

class CondaPackage(BaseModel):
name: str
Expand All @@ -14,6 +15,16 @@ class CondaPackage(BaseModel):
arch: str
platform: str
url: str
sha256: Optional[str] = None
md5: Optional[str] = None

def __str__(self):
return f"conda: {self.name} - {self.version}"

def __eq__(self, other):
if isinstance(other, CondaPackage):
return self.url == other.url
return False

def to_repodata_record(self):
"""Converts a url package into a rattler compatible repodata record."""
Expand All @@ -28,23 +39,30 @@ def to_repodata_record(self):
channel=self.conda_channel,
url=self.url
)


def __str__(self):
return f"conda: {self.name} - {self.version}"

def __eq__(self, other):
if isinstance(other, CondaPackage):
return self.url == other.url
return False
def to_conda_lock_package(self, platform):
return conda_lock.CondaLockPackage(
category = "main",
name = self.name,
version = self.version,
dependencies = {},
hash = {
"sha256": self.sha256,
"md5": self.md5,
},
manager = "conda",
optional = False,
platform = platform,
url = self.url,
)


class PipPackage(BaseModel):
name: str
version: str
build: str
url: Optional[str] = None

def __str__(self):
return f"pip: {self.name} - {self.version}"

Expand All @@ -58,15 +76,31 @@ def to_repodata_record(self):
# no-op
pass

def to_conda_lock_package(self, platform):
return conda_lock.CondaLockPackage(
category = "main",
name = self.name,
version = self.version,
manager = "pip",
optional = False,
platform = platform,
dependencies = {},
hash = {},
url = self.url,
)

class UrlCondaPackage(BaseModel):
class UrlPackage(BaseModel):
url: str

def manager(self) -> str:
"""Returns the package manager for this package."""
return "None"

def __str__(self):
package = self.url.split("/")[-1]
version = package.split("-")[-2]
name = "-".join(package.split("-")[:-2])
return f"conda: {name} - {version}"
return f"url: {name} - {version}"


Package = Union[CondaPackage, PipPackage, UrlCondaPackage]
Package = Union[CondaPackage, PipPackage, UrlPackage]
28 changes: 27 additions & 1 deletion dof/cli/checkpoint.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import typer
import yaml
from typing import List

from rich.table import Table
Expand Down Expand Up @@ -126,4 +127,29 @@ def show(
prefix = os.environ.get("CONDA_PREFIX")
chck = Checkpoint.from_uuid(prefix=prefix, uuid=rev)
for pkg in chck.list_packages():
print(pkg)
print(pkg)


@checkpoint_command.command()
def export(
ctx: typer.Context,
rev: str = typer.Option(
help="uuid of the revision to list packages for"
),
conda: bool = typer.Option(
False, help="export as a conda environment lock file"
),
pixi: bool = typer.Option(
False, help="export as a pixi environment lock file"
),
):
"""Export a checkpoint as a conda or pixi environment lock file"""
prefix = os.environ.get("CONDA_PREFIX")
chck = Checkpoint.from_uuid(prefix=prefix, uuid=rev)
if conda:
conda_lock_repr = chck.env_checkpoint.environment.to_conda_lock_file()
conda_lock_yaml = yaml.dump(conda_lock_repr.model_dump())
with open("./conda-lock.yml", "w") as f:
f.write(conda_lock_yaml)
if pixi:
print(chck.env_checkpoint.environment.to_pixi_lock_file())