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 8 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
1 change: 0 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

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("qux >=1.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
36 changes: 30 additions & 6 deletions src/cli/add.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use clap::Parser;
use indexmap::IndexMap;
use miette::IntoDiagnostic;
use pixi_manifest::FeatureName;
use pixi_manifest::{FeatureName, SpecType};
use pixi_spec::{GitSpec, SourceSpec};
use rattler_conda_types::{MatchSpec, PackageName};

use super::has_specs::HasSpecs;
use crate::{
Expand Down Expand Up @@ -98,24 +100,45 @@ pub async fn execute(args: Args) -> miette::Result<()> {
.manifest
.add_platforms(dependency_config.platforms.iter(), &FeatureName::Default)?;

let (match_specs, pypi_deps) = match dependency_config.dependency_type() {
let (match_specs, source_specs, pypi_deps) = match dependency_config.dependency_type() {
DependencyType::CondaDependency(spec_type) => {
let match_specs = dependency_config
// if user passed some git configuration
// we will use it to create pixi source specs
let passed_specs: IndexMap<PackageName, (MatchSpec, SpecType)> = dependency_config
.specs()?
.into_iter()
.map(|(name, spec)| (name, (spec, spec_type)))
.collect();
let pypi_deps = IndexMap::default();
(match_specs, pypi_deps)

if let Some(git) = &dependency_config.git {
let source_specs = passed_specs
.iter()
.map(|(name, (_spec, spec_type))| {
let git_reference =
dependency_config.rev.clone().unwrap_or_default().into();

let git_spec = GitSpec {
git: git.clone(),
rev: Some(git_reference),
subdirectory: dependency_config.subdir.clone(),
};
(name.clone(), (SourceSpec::Git(git_spec), *spec_type))
})
.collect();
(IndexMap::default(), source_specs, IndexMap::default())
} else {
(passed_specs, IndexMap::default(), IndexMap::default())
}
}
DependencyType::PypiDependency => {
let match_specs = IndexMap::default();
let source_specs = IndexMap::default();
let pypi_deps = dependency_config
.pypi_deps(&project)?
.into_iter()
.map(|(name, req)| (name, (req, None)))
.collect();
(match_specs, pypi_deps)
(match_specs, source_specs, pypi_deps)
}
};
// TODO: add dry_run logic to add
Expand All @@ -129,6 +152,7 @@ pub async fn execute(args: Args) -> miette::Result<()> {
.update_dependencies(
match_specs,
pypi_deps,
source_specs,
prefix_update_config,
&args.dependency_config.feature,
&args.dependency_config.platforms,
Expand Down
Loading
Loading