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: pixi add git source dependency #2858

Merged
merged 25 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
49592e5
feat: move cli params separatly
nichmor Jan 8, 2025
ece11c6
misc: remove funcs and add some docstrings
nichmor Jan 8, 2025
7cc3635
misc: remove unused dep
nichmor Jan 8, 2025
e79276f
Merge branch 'main' into feat/pixi-add-git-spec
nichmor Jan 8, 2025
c720898
misc: remove unused dep
nichmor Jan 8, 2025
1d75bb3
misc: add conflicts_with_all for GitRev
nichmor Jan 8, 2025
a66f5a6
misc: remove pixi_utils
nichmor Jan 8, 2025
f97bf3f
misc: update failing tests and snapshots
nichmor Jan 8, 2025
ae8160a
misc: add pypi implementation
nichmor Jan 9, 2025
a6b302d
misc: add cli docs
nichmor Jan 9, 2025
7608031
misc: add unit tests for vcs reqs
nichmor Jan 9, 2025
7933675
misc: fix conflict
nichmor Jan 9, 2025
bba2eea
misc: update snapshot
nichmor Jan 9, 2025
9575001
misc: make tests more stable by using only one platform
nichmor Jan 9, 2025
7afa629
misc: update snapshots
nichmor Jan 9, 2025
b355b86
misc: configure git user
nichmor Jan 10, 2025
e28e476
Merge branch 'main' into feat/pixi-add-git-spec
nichmor Jan 10, 2025
e0d4619
misc: use global configuration
nichmor Jan 10, 2025
735c8a6
Merge branch 'feat/pixi-add-git-spec' of github.com:nichmor/pixi into…
nichmor Jan 10, 2025
13b94fa
misc: add git user configuraiton for tests
nichmor Jan 10, 2025
c90d7d3
misc: comment out cred tests
nichmor Jan 10, 2025
3f6077f
misc: do not update lockfileupdate on lock
nichmor Jan 10, 2025
1d88d5d
misc: enable snapshot back
nichmor Jan 10, 2025
301abc2
Merge branch 'main' into feat/pixi-add-git-spec
nichmor Jan 10, 2025
373a1e9
misc: remove git configuration
nichmor Jan 10, 2025
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
412 changes: 249 additions & 163 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion crates/pixi_manifest/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ pep508_rs = { workspace = true }
pixi_consts = { workspace = true }
pixi_spec = { workspace = true }
pixi_toml = { workspace = true }
pixi_utils = { workspace = true }
regex = { workspace = true }
serde = { workspace = true }
serde-value = { workspace = true }
Expand Down
64 changes: 40 additions & 24 deletions crates/pixi_manifest/src/manifests/manifest.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use indexmap::{Equivalent, IndexSet};
use itertools::Itertools;
use miette::{miette, IntoDiagnostic, NamedSource, Report, WrapErr};
use pixi_spec::PixiSpec;
use rattler_conda_types::{ChannelConfig, MatchSpec, PackageName, Platform, Version};
use rattler_conda_types::{PackageName, Platform, Version};
use toml_edit::{DocumentMut, Value};

use crate::toml::FromTomlStr;
Expand Down Expand Up @@ -372,34 +372,26 @@ impl Manifest {
Ok(())
}

/// Add a matchspec to the manifest
/// Add a pixi spec to the manifest
pub fn add_dependency(
&mut self,
spec: &MatchSpec,
name: &PackageName,
spec: &PixiSpec,
spec_type: SpecType,
platforms: &[Platform],
feature_name: &FeatureName,
overwrite_behavior: DependencyOverwriteBehavior,
channel_config: &ChannelConfig,
) -> miette::Result<bool> {
// Determine the name of the package to add
let (Some(name), spec) = spec.clone().into_nameless() else {
miette::bail!(
"{} does not support wildcard dependencies",
pixi_utils::executable_name()
);
};
let spec = PixiSpec::from_nameless_matchspec(spec, channel_config);
let mut any_added = false;
for platform in to_options(platforms) {
// Add the dependency to the manifest
match self
.get_or_insert_target_mut(platform, Some(feature_name))
.try_add_dependency(&name, &spec, spec_type, overwrite_behavior)
.try_add_dependency(name, spec, spec_type, overwrite_behavior)
{
Ok(true) => {
self.source
.add_dependency(&name, &spec, spec_type, platform, feature_name)?;
.add_dependency(name, spec, spec_type, platform, feature_name)?;
any_added = true;
}
Ok(false) => {}
Expand Down Expand Up @@ -813,8 +805,8 @@ mod tests {
use insta::assert_snapshot;
use miette::NarratableReportHandler;
use rattler_conda_types::{
NamedChannelOrUrl, ParseStrictness,
ParseStrictness::{Lenient, Strict},
MatchSpec, NamedChannelOrUrl,
ParseStrictness::{self, Lenient, Strict},
VersionSpec,
};
use rstest::*;
Expand Down Expand Up @@ -2062,14 +2054,22 @@ bar = "*"
"#;
let channel_config = default_channel_config();
let mut manifest = Manifest::from_str(Path::new("pixi.toml"), file_contents).unwrap();
// Determine the name of the package to add
let spec = &MatchSpec::from_str("baz >=1.2.3", Strict).unwrap();

let (name, spec) = spec.clone().into_nameless();
let name = name.unwrap();

let spec = PixiSpec::from_nameless_matchspec(spec, &channel_config);

manifest
.add_dependency(
&MatchSpec::from_str("baz >=1.2.3", Strict).unwrap(),
&name,
&spec,
SpecType::Run,
&[],
&FeatureName::Default,
DependencyOverwriteBehavior::Overwrite,
&channel_config,
)
.unwrap();
assert_eq!(
Expand All @@ -2085,14 +2085,20 @@ bar = "*"
.as_version_spec(),
Some(&VersionSpec::from_str(">=1.2.3", Strict).unwrap())
);

let (name, spec) = MatchSpec::from_str("bal >=2.3", Strict)
.unwrap()
.into_nameless();
let pixi_spec = PixiSpec::from_nameless_matchspec(spec, &channel_config);

manifest
.add_dependency(
&MatchSpec::from_str(" bal >=2.3", Strict).unwrap(),
&name.unwrap(),
&pixi_spec,
SpecType::Run,
&[],
&FeatureName::Named("test".to_string()),
DependencyOverwriteBehavior::Overwrite,
&channel_config,
)
.unwrap();

Expand All @@ -2113,14 +2119,19 @@ bar = "*"
">=2.3".to_string()
);

let (package_name, nameless) = MatchSpec::from_str(" boef >=2.3", Strict)
.unwrap()
.into_nameless();
let pixi_spec = PixiSpec::from_nameless_matchspec(nameless, &channel_config);

manifest
.add_dependency(
&MatchSpec::from_str(" boef >=2.3", Strict).unwrap(),
&package_name.unwrap(),
&pixi_spec,
SpecType::Run,
&[Platform::Linux64],
&FeatureName::Named("extra".to_string()),
DependencyOverwriteBehavior::Overwrite,
&channel_config,
)
.unwrap();

Expand All @@ -2142,14 +2153,19 @@ bar = "*"
">=2.3".to_string()
);

let matchspec = MatchSpec::from_str(" cmake >=2.3", ParseStrictness::Strict).unwrap();
let (package_name, nameless) = matchspec.into_nameless();

let pixi_spec = PixiSpec::from_nameless_matchspec(nameless, &channel_config);

manifest
.add_dependency(
&MatchSpec::from_str(" cmake >=2.3", ParseStrictness::Strict).unwrap(),
&package_name.unwrap(),
&pixi_spec,
SpecType::Build,
&[Platform::Linux64],
&FeatureName::Named("build".to_string()),
DependencyOverwriteBehavior::Overwrite,
&channel_config,
)
.unwrap();

Expand Down
59 changes: 55 additions & 4 deletions crates/pixi_spec/src/git.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::fmt::Display;

use pixi_git::git::GitReference;
use serde::{Serialize, Serializer};
use thiserror::Error;
use url::Url;

Expand All @@ -12,7 +13,7 @@ pub struct GitSpec {
pub git: Url,

/// The git revision of the package
#[serde(skip_serializing_if = "Option::is_none", flatten)]
#[serde(skip_serializing_if = "Reference::is_default_branch", flatten)]
pub rev: Option<Reference>,

/// The git subdirectory of the package
Expand All @@ -21,9 +22,7 @@ pub struct GitSpec {
}

/// A reference to a specific commit in a git repository.
#[derive(
Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, ::serde::Serialize, ::serde::Deserialize,
)]
#[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord, ::serde::Deserialize)]
#[serde(rename_all = "kebab-case")]
pub enum Reference {
/// The HEAD commit of a branch.
Expand All @@ -39,6 +38,16 @@ pub enum Reference {
DefaultBranch,
}

impl Reference {
/// Returns the reference as a string.
pub fn is_default_branch(reference: &Option<Reference>) -> bool {
reference.is_none()
|| reference
.as_ref()
.is_some_and(|reference| matches!(reference, Reference::DefaultBranch))
}
}

impl Display for Reference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand All @@ -65,6 +74,48 @@ impl From<GitReference> for Reference {
}
}

impl Serialize for Reference {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
#[derive(Serialize)]
struct RawReference<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
tag: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
branch: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
rev: Option<&'a str>,
}

let ser = match self {
Reference::Branch(name) => RawReference {
branch: Some(name),
tag: None,
rev: None,
},
Reference::Tag(name) => RawReference {
branch: None,
tag: Some(name),
rev: None,
},
Reference::Rev(name) => RawReference {
branch: None,
tag: None,
rev: Some(name),
},
Reference::DefaultBranch => RawReference {
branch: None,
tag: None,
rev: None,
},
};

ser.serialize(serializer)
}
}

#[derive(Error, Debug)]
pub enum GitReferenceError {
#[error("The commit string is invalid: \"{0}\"")]
Expand Down
44 changes: 30 additions & 14 deletions docs/reference/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ These dependencies will be read by pixi as if they had been added to the pixi `p
- `--pypi`: Specifies a PyPI dependency, not a conda package.
Parses dependencies as [PEP508](https://peps.python.org/pep-0508/) requirements, supporting extras and versions.
See [configuration](pixi_manifest.md) for details.
- `--git`: Specifies a git dependency, the package will be installed from the git repository.
The `--git` flag can be used with the following options:
- `--branch <BRANCH>`: The branch to use when installing the package.
- `--tag <TAG>`: The tag to use when installing the package.
- `--rev <REV>`: The revision to use when installing the package.
- `--subdir <SUBDIR>`: The subdirectory to use when installing the package.
- `--no-install`: Don't install the package to the environment, only add the package to the lock-file.
- `--no-lockfile-update`: Don't update the lock-file, implies the `--no-install` flag.
- `--platform <PLATFORM> (-p)`: The platform for which the dependency should be added. (Allowed to be used more than once)
Expand All @@ -98,15 +104,20 @@ pixi add --platform osx-64 clang # (7)!
pixi add --no-install numpy # (8)!
pixi add --no-lockfile-update numpy # (9)!
pixi add --feature featurex numpy # (10)!
pixi add --git https://github.com/wolfv/pixi-build-examples boost-check # (11)!
ruben-arts marked this conversation as resolved.
Show resolved Hide resolved
pixi add --git https://github.com/wolfv/pixi-build-examples --branch main --subdir boost-check boost-check # (12)!
pixi add --git https://github.com/wolfv/pixi-build-examples --tag v0.1.0 boost-check # (13)!
pixi add --git https://github.com/wolfv/pixi-build-examples --rev e50d4a1 boost-check # (14)!

# Add a pypi dependency
pixi add --pypi requests[security] # (11)!
pixi add --pypi Django==5.1rc1 # (12)!
pixi add --pypi "boltons>=24.0.0" --feature lint # (13)!
pixi add --pypi "boltons @ https://files.pythonhosted.org/packages/46/35/e50d4a115f93e2a3fbf52438435bb2efcf14c11d4fcd6bdcd77a6fc399c9/boltons-24.0.0-py3-none-any.whl" # (14)!
pixi add --pypi "exchangelib @ git+https://github.com/ecederstrand/exchangelib" # (15)!
pixi add --pypi "project @ file:///absolute/path/to/project" # (16)!
pixi add --pypi "project@file:///absolute/path/to/project" --editable # (17)!
pixi add --pypi requests[security] # (15)!
pixi add --pypi Django==5.1rc1 # (16)!
pixi add --pypi "boltons>=24.0.0" --feature lint # (17)!
pixi add --pypi "boltons @ https://files.pythonhosted.org/packages/46/35/e50d4a115f93e2a3fbf52438435bb2efcf14c11d4fcd6bdcd77a6fc399c9/boltons-24.0.0-py3-none-any.whl" # (18)!
pixi add --pypi "exchangelib @ git+https://github.com/ecederstrand/exchangelib" # (19)!
pixi add --pypi "project @ file:///absolute/path/to/project" # (20)!
pixi add --pypi "project@file:///absolute/path/to/project" --editable # (21)!
pixi add --git https://github.com/mahmoud/boltons.git boltons --pypi # (22)!
```

1. This will add the `numpy` package to the project with the latest available for the solved environment.
Expand All @@ -119,13 +130,18 @@ pixi add --pypi "project@file:///absolute/path/to/project" --editable # (17)!
8. This will add the `numpy` package to the manifest and lockfile, without installing it in an environment.
9. This will add the `numpy` package to the manifest without updating the lockfile or installing it in the environment.
10. This will add the `numpy` package in the feature `featurex`.
11. This will add the `requests` package as `pypi` dependency with the `security` extra.
12. This will add the `pre-release` version of `Django` to the project as a `pypi` dependency.
13. This will add the `boltons` package in the feature `lint` as `pypi` dependency.
14. This will add the `boltons` package with the given `url` as `pypi` dependency.
15. This will add the `exchangelib` package with the given `git` url as `pypi` dependency.
16. This will add the `project` package with the given `file` url as `pypi` dependency.
17. This will add the `project` package with the given `file` url as an `editable` package as `pypi` dependency.
11. This will add the `boost-check` source package to the dependencies from the git repository.
12. This will add the `boost-check` source package to the dependencies from the git repository using `main` branch and the `boost-check` folder in the repository.
13. This will add the `boost-check` source package to the dependencies from the git repository using `v0.1.0` tag.
14. This will add the `boost-check` source package to the dependencies from the git repository using `e50d4a1` revision.
15. This will add the `requests` package as `pypi` dependency with the `security` extra.
16. This will add the `pre-release` version of `Django` to the project as a `pypi` dependency.
17. This will add the `boltons` package in the feature `lint` as `pypi` dependency.
18. This will add the `boltons` package with the given `url` as `pypi` dependency.
19. This will add the `exchangelib` package with the given `git` url as `pypi` dependency.
20. This will add the `project` package with the given `file` url as `pypi` dependency.
21. This will add the `project` package with the given `file` url as an `editable` package as `pypi` dependency.
22. This will add the `boltons` package with the given `git` url as `pypi` dependency. `branch`, `tag`, and `rev` are not yet supported.

!!! tip
If you want to use a non default pinning strategy, you can set it using [pixi's configuration](./pixi_configuration.md#pinning-strategy).
Expand Down
Loading
Loading