Skip to content

Commit

Permalink
Merge branch 'astral-sh:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
CharlesChen0823 authored May 11, 2024
2 parents e23a5df + 2f59957 commit 4b768f3
Show file tree
Hide file tree
Showing 12 changed files with 129 additions and 19 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion rye/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ git-testament = "0.2.4"
globset = "0.4.10"
indicatif = "0.17.3"
license = { version = "3.1.1", features = ["offline"] }
minijinja = { version = "1.0.0", features = ["json"] }
minijinja = { version = "2.0.1", features = ["json"] }
once_cell = "1.17.1"
pathdiff = "0.2.1"
pep440_rs = "0.4.0"
Expand Down
34 changes: 26 additions & 8 deletions rye/src/cli/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use url::Url;
use crate::bootstrap::ensure_self_venv;
use crate::config::Config;
use crate::consts::VENV_BIN;
use crate::lock::KeyringProvider;
use crate::pyproject::{BuildSystem, DependencyKind, ExpandedSources, PyProject};
use crate::sources::py::PythonVersion;
use crate::sync::{autosync, sync, SyncOptions};
Expand Down Expand Up @@ -137,7 +138,7 @@ impl ReqExtras {
};
req.version_or_url = match req.version_or_url {
Some(_) => bail!("requirement already has a version marker"),
None => Some(pep508_rs::VersionOrUrl::Url(
None => Some(VersionOrUrl::Url(
format!("git+{}{}", git, suffix).parse().with_context(|| {
format!("unable to interpret '{}{}' as git reference", git, suffix)
})?,
Expand All @@ -146,10 +147,11 @@ impl ReqExtras {
} else if let Some(ref url) = self.url {
req.version_or_url = match req.version_or_url {
Some(_) => bail!("requirement already has a version marker"),
None => Some(pep508_rs::VersionOrUrl::Url(
url.parse()
.with_context(|| format!("unable to parse '{}' as url", url))?,
)),
None => {
Some(VersionOrUrl::Url(url.parse().with_context(|| {
format!("unable to parse '{}' as url", url)
})?))
}
};
} else if let Some(ref path) = self.path {
// For hatchling build backend, it use {root:uri} for file relative path,
Expand All @@ -175,7 +177,7 @@ impl ReqExtras {
};
req.version_or_url = match req.version_or_url {
Some(_) => bail!("requirement already has a version marker"),
None => Some(pep508_rs::VersionOrUrl::Url(file_url)),
None => Some(VersionOrUrl::Url(file_url)),
};
}
for feature in self.features.iter().flat_map(|x| x.split(',')) {
Expand Down Expand Up @@ -212,6 +214,9 @@ pub struct Args {
/// Overrides the pin operator
#[arg(long)]
pin: Option<Pin>,
/// Attempt to use `keyring` for authentication for index URLs.
#[arg(long, value_enum, default_value_t)]
keyring_provider: KeyringProvider,
/// Runs `sync` even if auto-sync is disabled.
#[arg(long)]
sync: bool,
Expand Down Expand Up @@ -259,6 +264,8 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
requirements.push(requirement);
}

let keyring_provider = cmd.keyring_provider;

if !cmd.excluded {
if cfg.use_uv() {
sync(SyncOptions::python_only().pyproject(None))
Expand All @@ -270,8 +277,12 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
cmd.pre,
output,
&default_operator,
keyring_provider,
)?;
} else {
if keyring_provider != KeyringProvider::Disabled {
bail!("`--keyring-provider` option requires the uv backend");
}
for requirement in &mut requirements {
resolve_requirements_with_unearth(
&pyproject_toml,
Expand Down Expand Up @@ -303,7 +314,7 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
}

if (cfg.autosync() && !cmd.no_sync) || cmd.sync {
autosync(&pyproject_toml, output)?;
autosync(&pyproject_toml, output, keyring_provider)?;
}

Ok(())
Expand Down Expand Up @@ -448,6 +459,7 @@ fn resolve_requirements_with_uv(
pre: bool,
output: CommandOutput,
default_operator: &Operator,
keyring_provider: KeyringProvider,
) -> Result<(), Error> {
let venv_path = pyproject_toml.venv_path();
let py_bin = get_venv_python_bin(&venv_path);
Expand All @@ -460,7 +472,13 @@ fn resolve_requirements_with_uv(
.venv(&venv_path, &py_bin, py_ver, None)?;

for req in requirements {
let mut new_req = uv.resolve(py_ver, req, pre, env::var("__RYE_UV_EXCLUDE_NEWER").ok())?;
let mut new_req = uv.resolve(
py_ver,
req,
pre,
env::var("__RYE_UV_EXCLUDE_NEWER").ok(),
keyring_provider,
)?;

// if a version or URL is already provided we just use the normalized package name but
// retain all old information.
Expand Down
2 changes: 1 addition & 1 deletion rye/src/cli/init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
}
if metadata.author.is_none() {
is_metadata_author_none = true;
metadata.author = author.clone();
metadata.author.clone_from(&author);
}
if metadata.requires_python.is_none() {
metadata.requires_python = Some(requires_python);
Expand Down
10 changes: 9 additions & 1 deletion rye/src/cli/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::path::PathBuf;
use anyhow::Error;
use clap::Parser;

use crate::lock::LockOptions;
use crate::lock::{KeyringProvider, LockOptions};
use crate::sync::{sync, SyncMode, SyncOptions};
use crate::utils::CommandOutput;

Expand Down Expand Up @@ -34,12 +34,18 @@ pub struct Args {
/// Set to true to lock with sources in the lockfile.
#[arg(long)]
with_sources: bool,
/// Attempt to use `keyring` for authentication for index URLs.
#[arg(long, value_enum, default_value_t)]
keyring_provider: KeyringProvider,
/// Reset prior lock options.
#[arg(long)]
reset: bool,
/// Use this pyproject.toml file
#[arg(long, value_name = "PYPROJECT_TOML")]
pyproject: Option<PathBuf>,
/// Set to true to lock with hashes in the lockfile.
#[arg(long)]
generate_hashes: bool,
}

pub fn execute(cmd: Args) -> Result<(), Error> {
Expand All @@ -55,8 +61,10 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
all_features: cmd.all_features,
with_sources: cmd.with_sources,
reset: cmd.reset,
generate_hashes: cmd.generate_hashes,
},
pyproject: cmd.pyproject,
keyring_provider: cmd.keyring_provider,
..SyncOptions::default()
})?;
Ok(())
Expand Down
6 changes: 5 additions & 1 deletion rye/src/cli/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use clap::Parser;
use pep508_rs::Requirement;

use crate::config::Config;
use crate::lock::KeyringProvider;
use crate::pyproject::{DependencyKind, PyProject};
use crate::sync::autosync;
use crate::utils::{format_requirement, CommandOutput};
Expand All @@ -27,6 +28,9 @@ pub struct Args {
/// Does not run `sync` even if auto-sync is enabled.
#[arg(long, conflicts_with = "sync")]
no_sync: bool,
/// Attempt to use `keyring` for authentication for index URLs.
#[arg(long, value_enum, default_value_t)]
keyring_provider: KeyringProvider,
/// Enables verbose diagnostics.
#[arg(short, long)]
verbose: bool,
Expand Down Expand Up @@ -65,7 +69,7 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
}

if (Config::current().autosync() && !cmd.no_sync) || cmd.sync {
autosync(&pyproject_toml, output)?;
autosync(&pyproject_toml, output, cmd.keyring_provider)?;
}

Ok(())
Expand Down
10 changes: 9 additions & 1 deletion rye/src/cli/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use std::path::PathBuf;
use anyhow::Error;
use clap::Parser;

use crate::lock::LockOptions;
use crate::lock::{KeyringProvider, LockOptions};
use crate::sync::{sync, SyncMode, SyncOptions};
use crate::utils::CommandOutput;

Expand Down Expand Up @@ -43,12 +43,18 @@ pub struct Args {
/// Set to true to lock with sources in the lockfile.
#[arg(long)]
with_sources: bool,
/// Attempt to use `keyring` for authentication for index URLs.
#[arg(long, value_enum, default_value_t)]
keyring_provider: KeyringProvider,
/// Use this pyproject.toml file
#[arg(long, value_name = "PYPROJECT_TOML")]
pyproject: Option<PathBuf>,
/// Do not reuse (reset) prior lock options.
#[arg(long)]
reset: bool,
/// Set to true to lock with hashes in the lockfile.
#[arg(long)]
generate_hashes: bool,
}

pub fn execute(cmd: Args) -> Result<(), Error> {
Expand All @@ -71,7 +77,9 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
all_features: cmd.all_features,
with_sources: cmd.with_sources,
reset: cmd.reset,
generate_hashes: cmd.generate_hashes,
},
keyring_provider: cmd.keyring_provider,
pyproject: cmd.pyproject,
})?;
Ok(())
Expand Down
6 changes: 5 additions & 1 deletion rye/src/cli/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use same_file::is_same_file;

use crate::config::Config;
use crate::consts::VENV_BIN;
use crate::lock::KeyringProvider;
use crate::pyproject::{locate_projects, normalize_package_name, DependencyKind, PyProject};
use crate::sync::autosync;
use crate::utils::{CommandOutput, QuietExit};
Expand All @@ -28,6 +29,9 @@ pub struct Args {
/// Use this pyproject.toml file
#[arg(long, value_name = "PYPROJECT_TOML")]
pyproject: Option<PathBuf>,
/// Attempt to use `keyring` for authentication for index URLs.
#[arg(long, value_enum, default_value_t)]
keyring_provider: KeyringProvider,
// Disable test output capture to stdout
#[arg(long = "no-capture", short = 's')]
no_capture: bool,
Expand Down Expand Up @@ -73,7 +77,7 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
let has_pytest = has_pytest_dependency(&projects)?;
if has_pytest {
if Config::current().autosync() {
autosync(&projects[0], output)?;
autosync(&projects[0], output, cmd.keyring_provider)?;
} else {
bail!("pytest not installed but in dependencies. Run `rye sync`.")
}
Expand Down
32 changes: 32 additions & 0 deletions rye/src/lock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use std::sync::Arc;
use std::{env, fmt, fs};

use anyhow::{anyhow, bail, Context, Error};
use clap::ValueEnum;
use minijinja::render;
use once_cell::sync::Lazy;
use pep508_rs::Requirement;
Expand Down Expand Up @@ -35,6 +36,7 @@ static REQUIREMENTS_HEADER: &str = r#"# generated by rye
# features: {{ lock_options.features|tojson }}
# all-features: {{ lock_options.all_features|tojson }}
# with-sources: {{ lock_options.with_sources|tojson }}
# generate-hashes: {{ lock_options.generate_hashes|tojson }}
"#;
static PARAM_RE: Lazy<Regex> =
Expand All @@ -59,6 +61,18 @@ impl fmt::Display for LockMode {
}
}

/// Keyring provider type to use for credential lookup.
#[derive(ValueEnum, Copy, Clone, Serialize, Debug, Default, PartialEq)]
#[value(rename_all = "snake_case")]
#[serde(rename_all = "snake_case")]
pub enum KeyringProvider {
/// Do not use keyring for credential lookup.
#[default]
Disabled,
/// Use the `keyring` command for credential lookup.
Subprocess,
}

/// Controls how locking should work.
#[derive(Debug, Clone, Default, Serialize)]
pub struct LockOptions {
Expand All @@ -76,6 +90,8 @@ pub struct LockOptions {
pub with_sources: bool,
/// Do not reuse (reset) prior lock options.
pub reset: bool,
/// Generate hashes in the lock file.
pub generate_hashes: bool,
}

impl LockOptions {
Expand Down Expand Up @@ -128,6 +144,7 @@ impl LockOptions {
}

/// Creates lockfiles for all projects in the workspace.
#[allow(clippy::too_many_arguments)]
pub fn update_workspace_lockfile(
py_ver: &PythonVersion,
workspace: &Arc<Workspace>,
Expand All @@ -136,6 +153,7 @@ pub fn update_workspace_lockfile(
output: CommandOutput,
sources: &ExpandedSources,
lock_options: &LockOptions,
keyring_provider: KeyringProvider,
) -> Result<(), Error> {
echo!(if output, "Generating {} lockfile: {}", lock_mode, lockfile.display());

Expand Down Expand Up @@ -189,6 +207,7 @@ pub fn update_workspace_lockfile(
&lock_options,
&exclusions,
true,
keyring_provider,
)?;

Ok(())
Expand Down Expand Up @@ -308,6 +327,7 @@ fn dump_dependencies(
}

/// Updates the lockfile of the current project.
#[allow(clippy::too_many_arguments)]
pub fn update_single_project_lockfile(
py_ver: &PythonVersion,
pyproject: &PyProject,
Expand All @@ -316,6 +336,7 @@ pub fn update_single_project_lockfile(
output: CommandOutput,
sources: &ExpandedSources,
lock_options: &LockOptions,
keyring_provider: KeyringProvider,
) -> Result<(), Error> {
echo!(if output, "Generating {} lockfile: {}", lock_mode, lockfile.display());

Expand Down Expand Up @@ -356,6 +377,7 @@ pub fn update_single_project_lockfile(
&lock_options,
&exclusions,
false,
keyring_provider,
)?;

Ok(())
Expand All @@ -372,6 +394,7 @@ fn generate_lockfile(
lock_options: &LockOptions,
exclusions: &HashSet<Requirement>,
no_deps: bool,
keyring_provider: KeyringProvider,
) -> Result<(), Error> {
let use_uv = Config::current().use_uv();
let scratch = tempfile::tempdir()?;
Expand Down Expand Up @@ -409,8 +432,13 @@ fn generate_lockfile(
lock_options.pre,
env::var("__RYE_UV_EXCLUDE_NEWER").ok(),
upgrade,
keyring_provider,
lock_options.generate_hashes,
)?;
} else {
if keyring_provider != KeyringProvider::Disabled {
bail!("`--keyring-provider` option requires the uv backend");
}
let mut cmd = Command::new(get_pip_compile(py_ver, output)?);
// legacy pip tools requires some extra parameters
if get_pip_tools_version(py_ver) == PipToolsVersion::Legacy {
Expand All @@ -431,6 +459,10 @@ fn generate_lockfile(
if lock_options.pre {
cmd.arg("--pre");
}
if lock_options.generate_hashes {
cmd.arg("--generate-hashes");
cmd.arg("--reuse-hashes");
}

cmd.arg(if output == CommandOutput::Verbose {
"--verbose"
Expand Down
Loading

0 comments on commit 4b768f3

Please sign in to comment.