Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add flox envs command #1264

Merged
merged 5 commits into from
Apr 23, 2024
Merged
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
39 changes: 39 additions & 0 deletions cli/flox-rust-sdk/src/data/canonical_path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use std::path::{Path, PathBuf};

use serde::Serialize;
use thiserror::Error;

/// A path that is guaranteed to be canonicalized
///
/// [`ManagedEnvironment`] uses this to refer to the path of its `.flox` directory.
/// [`ManagedEnvironment::encode`] is used to uniquely identify the environment
/// by encoding the canonicalized path.
/// This encoding is used to create a unique branch name in the floxmeta repository.
/// Thus, rather than canonicalizing the path every time we need to encode it,
/// we store the path as a [`CanonicalPath`].
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, derive_more::Deref, derive_more::AsRef)]
#[deref(forward)]
#[as_ref(forward)]
pub struct CanonicalPath(PathBuf);

#[derive(Debug, Error)]
#[error("couldn't canonicalize path {path:?}: {err}")]
pub struct CanonicalizeError {
pub path: PathBuf,
#[source]
pub err: std::io::Error,
}

impl CanonicalPath {
pub fn new(path: impl AsRef<Path>) -> Result<Self, CanonicalizeError> {
let canonicalized = std::fs::canonicalize(&path).map_err(|e| CanonicalizeError {
path: path.as_ref().to_path_buf(),
err: e,
})?;
Ok(Self(canonicalized))
}

pub fn into_path_buf(self) -> PathBuf {
self.0
}
}
2 changes: 2 additions & 0 deletions cli/flox-rust-sdk/src/data/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
mod canonical_path;
mod version;

pub use canonical_path::{CanonicalPath, CanonicalizeError};
pub use version::Version;
pub type System = String;
2 changes: 1 addition & 1 deletion cli/flox-rust-sdk/src/data/version.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::fmt::Debug;
use serde::{Deserialize, Serialize};
use thiserror::Error;

#[derive(Clone, PartialEq)]
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct Version<const V: u8>;

Expand Down
4 changes: 2 additions & 2 deletions cli/flox-rust-sdk/src/models/env_registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ use fslock::LockFile;
use serde::{Deserialize, Serialize};
use tracing::debug;

use super::environment::{path_hash, CanonicalPath, EnvironmentPointer};
use crate::data::Version;
use super::environment::{path_hash, EnvironmentPointer};
use crate::data::{CanonicalPath, Version};
use crate::flox::Flox;
use crate::utils::traceable_path;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@ use super::{
LOCKFILE_FILENAME,
MANIFEST_FILENAME,
};
use crate::data::CanonicalPath;
use crate::flox::Flox;
use crate::models::container_builder::ContainerBuilder;
use crate::models::environment::{call_pkgdb, global_manifest_path, CanonicalPath};
use crate::models::environment::{call_pkgdb, global_manifest_path};
use crate::models::lockfile::{LockedManifest, LockedManifestError};
use crate::models::manifest::{
insert_packages,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use super::path_environment::PathEnvironment;
use super::{
gcroots_dir,
path_hash,
CanonicalPath,
CanonicalizeError,
CoreEnvironmentError,
EditResult,
Expand All @@ -26,7 +25,7 @@ use super::{
ENVIRONMENT_POINTER_FILENAME,
N_HASH_CHARS,
};
use crate::data::Version;
use crate::data::{CanonicalPath, Version};
use crate::flox::{EnvironmentRef, Flox};
use crate::models::container_builder::ContainerBuilder;
use crate::models::env_registry::{
Expand Down Expand Up @@ -1875,7 +1874,7 @@ mod test {
floxmeta,
&flox,
test_pointer,
CanonicalPath(dot_flox_path),
CanonicalPath::new(dot_flox_path).unwrap(),
flox.temp_dir.join("out_link"),
)
.unwrap();
Expand Down Expand Up @@ -1915,7 +1914,7 @@ mod test {
floxmeta,
&flox,
test_pointer,
CanonicalPath(dot_flox_path),
CanonicalPath::new(dot_flox_path).unwrap(),
flox.temp_dir.join("out_link"),
)
.unwrap();
Expand Down
58 changes: 9 additions & 49 deletions cli/flox-rust-sdk/src/models/environment/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use super::environment_ref::{EnvironmentName, EnvironmentOwner};
use super::lockfile::LockedManifest;
use super::manifest::PackageToInstall;
use super::pkgdb::UpgradeResult;
use crate::data::Version;
use crate::data::{CanonicalPath, CanonicalizeError, Version};
use crate::flox::{Flox, Floxhub};
use crate::models::pkgdb::call_pkgdb;
use crate::providers::git::{
Expand Down Expand Up @@ -74,45 +74,6 @@ pub struct UpdateResult {
pub store_path: Option<PathBuf>,
}

/// A path that is guaranteed to be canonicalized
///
/// [`ManagedEnvironment`] uses this to refer to the path of its `.flox` directory.
/// [`ManagedEnvironment::encode`] is used to uniquely identify the environment
/// by encoding the canonicalized path.
/// This encoding is used to create a unique branch name in the floxmeta repository.
/// Thus, rather than canonicalizing the path every time we need to encode it,
/// we store the path as a [`CanonicalPath`].
#[derive(Debug, Clone, derive_more::Deref, derive_more::AsRef)]
#[deref(forward)]
#[as_ref(forward)]
pub struct CanonicalPath(PathBuf);

#[derive(Debug, Error)]
#[error("couldn't canonicalize path {path:?}: {err}")]
pub struct CanonicalizeError {
pub path: PathBuf,
#[source]
pub err: std::io::Error,
}

impl CanonicalPath {
pub fn new(path: impl AsRef<Path>) -> Result<Self, CanonicalizeError> {
let canonicalized = std::fs::canonicalize(&path).map_err(|e| CanonicalizeError {
path: path.as_ref().to_path_buf(),
err: e,
})?;
Ok(Self(canonicalized))
}

pub fn path(&self) -> PathBuf {
self.0.clone()
}

pub fn into_path_buf(self) -> PathBuf {
self.0
}
}

/// The result of an installation attempt that contains the new manifest contents
/// along with whether each package was already installed
#[derive(Debug)]
Expand Down Expand Up @@ -237,7 +198,9 @@ pub trait Environment: Send {
/// A pointer to an environment, either managed or path.
/// This is used to determine the type of an environment at a given path.
/// See [EnvironmentPointer::open].
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, derive_more::From)]
#[derive(
Clone, Debug, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord, derive_more::From,
)]
#[serde(untagged)]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub enum EnvironmentPointer {
Expand All @@ -250,7 +213,7 @@ pub enum EnvironmentPointer {
/// The identifier for a project environment.
///
/// This is serialized to `env.json` inside the `.flox` directory
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct PathPointer {
pub name: EnvironmentName,
Expand All @@ -271,7 +234,7 @@ impl PathPointer {
/// points to an environment owner and the name of the environment.
///
/// This is serialized to an `env.json` inside the `.flox` directory.
#[derive(Debug, Serialize, Clone, Deserialize, PartialEq)]
#[derive(Debug, Serialize, Clone, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
pub struct ManagedPointer {
pub owner: EnvironmentOwner,
Expand Down Expand Up @@ -358,7 +321,7 @@ impl EnvironmentPointer {
/// However, this type does not perform any validation of the referenced environment.
/// Opening the environment with [ManagedEnvironment::open] or
/// [PathEnvironment::open], could still fail.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Eq, PartialOrd, Ord)]
pub struct DotFlox {
pub path: PathBuf,
pub pointer: EnvironmentPointer,
Expand Down Expand Up @@ -474,11 +437,8 @@ pub enum EnvironmentError {
#[error("could not get current directory")]
GetCurrentDir(#[source] std::io::Error),

#[error("failed to get canonical path for '.flox' directory: {path}")]
CanonicalDotFlox {
err: CanonicalizeError,
path: PathBuf,
},
#[error("failed to get canonical path for '.flox' directory")]
CanonicalDotFlox(#[source] CanonicalizeError),

#[error("failed to access the environment registry")]
Registry(#[from] EnvRegistryError),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ use log::debug;

use super::core_environment::CoreEnvironment;
use super::{
CanonicalPath,
CanonicalizeError,
EditResult,
Environment,
Expand All @@ -39,7 +38,7 @@ use super::{
GCROOTS_DIR_NAME,
LOCKFILE_FILENAME,
};
use crate::data::System;
use crate::data::{CanonicalPath, System};
use crate::flox::Flox;
use crate::models::container_builder::ContainerBuilder;
use crate::models::env_registry::{deregister, ensure_registered};
Expand Down Expand Up @@ -365,10 +364,8 @@ impl PathEnvironment {
}

let canonical_dot_flox =
CanonicalPath::new(&dot_flox_path).map_err(|e| EnvironmentError::CanonicalDotFlox {
err: e,
path: dot_flox_path.as_ref().to_path_buf(),
})?;
CanonicalPath::new(&dot_flox_path).map_err(EnvironmentError::CanonicalDotFlox)?;

ensure_registered(
flox,
&canonical_dot_flox,
Expand Down
25 changes: 23 additions & 2 deletions cli/flox-rust-sdk/src/models/environment_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,18 @@ pub static DEFAULT_NAME: &str = "default";
pub static DEFAULT_OWNER: &str = "local";

#[derive(
Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref, Display, DeserializeFromStr, SerializeDisplay,
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
AsRef,
Deref,
Display,
DeserializeFromStr,
SerializeDisplay,
)]
pub struct EnvironmentOwner(String);

Expand All @@ -28,7 +39,17 @@ impl FromStr for EnvironmentOwner {
}

#[derive(
Debug, Clone, PartialEq, Eq, Hash, AsRef, Display, DeserializeFromStr, SerializeDisplay,
Debug,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
AsRef,
Display,
DeserializeFromStr,
SerializeDisplay,
)]
pub struct EnvironmentName(String);

Expand Down
10 changes: 3 additions & 7 deletions cli/flox-rust-sdk/src/models/lockfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,11 @@ use log::debug;
use thiserror::Error;

use super::container_builder::ContainerBuilder;
use super::environment::{CanonicalizeError, UpdateResult};
use super::environment::UpdateResult;
use super::pkgdb::CallPkgDbError;
use crate::data::{System, Version};
use crate::data::{CanonicalPath, CanonicalizeError, System, Version};
use crate::flox::Flox;
use crate::models::environment::{
global_manifest_lockfile_path,
global_manifest_path,
CanonicalPath,
};
use crate::models::environment::{global_manifest_lockfile_path, global_manifest_path};
use crate::models::pkgdb::{call_pkgdb, BuildEnvResult, PKGDB_BIN};
use crate::utils::CommandExt;

Expand Down
51 changes: 51 additions & 0 deletions cli/flox/doc/flox-envs.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
---
title: FLOX-ENVS
section: 1
header: "Flox User Manuals"
...

# NAME

flox-envs - show active and available environments

# SYNOPSIS

```
flox [<general options>] envs
[--active]
[--json]
```

# DESCRIPTION

This command can be used to list available environments on the local machine.
When one or more environments are active,
the last activated environment will be listed first and printed in **bold**.

Whenever an environment is used with any `flox` command
it is registered to a user specific global registry.
`flox envs` will list all environments known to it through the registry.
Environments that are present on the local system may not show up
until they are used the first time.
Similarly, if an environment is changed
(e.g. deleted and replaced by an environment with different metadata),
the change may not show until the new environment is used.

# OPTIONS

## Edit Options

`--active`
: Show only active environments

`--json`
: Format the output as JSON

```{.include}
./include/general-options.md
```

# SEE ALSO
[`flox-init(1)`](./flox-init.md),
[`flox-pull(1)`](./flox-pull.md),
[`flox-activate(1)`](./flox-activate.md)
Loading
Loading