Skip to content

Commit

Permalink
Add autosync to run, OneOff sync mode
Browse files Browse the repository at this point in the history
  • Loading branch information
khvn26 committed Apr 9, 2024
1 parent 287170a commit 802171a
Show file tree
Hide file tree
Showing 9 changed files with 76 additions and 13 deletions.
5 changes: 5 additions & 0 deletions docs/guide/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ use-uv = false
# to `true` when uv is enabled and `false` otherwise.
autosync = true

# Enable or disable automatic `sync` ahead of `run` and `test`. This defaults
# to `true` when uv is enabled and `false` otherwise. Note that autosync invoked
# before `run` and `test` will never update your lockfiles.
autosync-before-run = true

# Marks the managed .venv in a way that cloud based synchronization systems
# like Dropbox and iCloud Files will not upload it. This defaults to true
# as a .venv in cloud storage typically does not make sense. Set this to
Expand Down
2 changes: 1 addition & 1 deletion rye/src/cli/add.rs
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
}

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

Ok(())
Expand Down
2 changes: 1 addition & 1 deletion rye/src/cli/remove.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,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, false)?;
}

Ok(())
Expand Down
28 changes: 23 additions & 5 deletions rye/src/cli/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@ use anyhow::{bail, Context, Error};
use clap::Parser;
use console::style;

use crate::config::Config;
use crate::pyproject::{PyProject, Script};
use crate::sync::{sync, SyncOptions};
use crate::sync::{autosync, sync, SyncOptions};
use crate::tui::redirect_to_stderr;
use crate::utils::{exec_spawn, get_venv_python_bin, success_status, IoPathContext};
use crate::utils::{exec_spawn, get_venv_python_bin, success_status, CommandOutput, IoPathContext};

/// Runs a command installed into this package.
#[derive(Parser, Debug)]
Expand All @@ -26,6 +27,18 @@ pub struct Args {
/// Use this pyproject.toml file
#[arg(long, value_name = "PYPROJECT_TOML")]
pyproject: Option<PathBuf>,
/// Runs `sync` even if auto-sync is disabled.
#[arg(long)]
sync: bool,
/// Does not run `sync` even if auto-sync is enabled.
#[arg(long, conflicts_with = "sync")]
no_sync: bool,
/// Enables verbose diagnostics.
#[arg(short, long)]
verbose: bool,
/// Turns off all output.
#[arg(short, long, conflicts_with = "verbose")]
quiet: bool,
}

#[derive(Parser, Debug)]
Expand All @@ -36,11 +49,16 @@ enum Cmd {

pub fn execute(cmd: Args) -> Result<(), Error> {
let _guard = redirect_to_stderr(true);
let output = CommandOutput::from_quiet_and_verbose(cmd.quiet, cmd.verbose);
let pyproject = PyProject::load_or_discover(cmd.pyproject.as_deref())?;

// make sure we have the minimal virtualenv.
sync(SyncOptions::python_only().pyproject(cmd.pyproject))
.context("failed to sync ahead of run")?;
if (Config::current().autosync_before_run() && !cmd.no_sync) || cmd.sync {
autosync(&pyproject, output, true)?;
} else {
// make sure we have the minimal virtualenv.
sync(SyncOptions::python_only().pyproject(cmd.pyproject))
.context("failed to sync ahead of run")?;
}

if cmd.list || cmd.cmd.is_none() {
return list_scripts(&pyproject);
Expand Down
10 changes: 8 additions & 2 deletions rye/src/cli/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ pub struct Args {
// Disable test output capture to stdout
#[arg(long = "no-capture", short = 's')]
no_capture: bool,
/// Runs `sync` even if auto-sync is disabled.
#[arg(long)]
sync: bool,
/// Does not run `sync` even if auto-sync is enabled.
#[arg(long, conflicts_with = "sync")]
no_sync: bool,
/// Enables verbose diagnostics.
#[arg(short, long)]
verbose: bool,
Expand Down Expand Up @@ -72,8 +78,8 @@ pub fn execute(cmd: Args) -> Result<(), Error> {
if !pytest.is_file() {
let has_pytest = has_pytest_dependency(&projects)?;
if has_pytest {
if Config::current().autosync() {
autosync(&projects[0], output)?;
if (Config::current().autosync_before_run() && !cmd.no_sync) || cmd.sync {
autosync(&projects[0], output, true)?;
} else {
bail!("pytest not installed but in dependencies. Run `rye sync`.")
}
Expand Down
11 changes: 10 additions & 1 deletion rye/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,14 +251,23 @@ impl Config {
Ok(rv)
}

/// Enable autosync.
/// Enable autosync for `add` and `remove`.
pub fn autosync(&self) -> bool {
self.doc
.get("behavior")
.and_then(|x| x.get("autosync"))
.and_then(|x| x.as_bool())
.unwrap_or_else(|| self.use_uv())
}

/// Enable autosync for `run` and `test`.
pub fn autosync_before_run(&self) -> bool {
self.doc
.get("behavior")
.and_then(|x| x.get("autosync-before-run"))
.and_then(|x| x.as_bool())
.unwrap_or_else(|| self.use_uv())
}

/// Indicates if uv should be used instead of pip-tools.
pub fn use_uv(&self) -> bool {
Expand Down
11 changes: 8 additions & 3 deletions rye/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ pub enum SyncMode {
Regular,
/// recreate everything
Full,
/// Recreate if no lock file present, otherwise install without updating
OneOff,
}

/// Updates the virtualenv based on the pyproject.toml
Expand Down Expand Up @@ -177,16 +179,19 @@ pub fn sync(mut cmd: SyncOptions) -> Result<(), Error> {
// hack to make this work for now. We basically sym-link pip itself
// into a folder all by itself and place a second file in there which we
// can pass to pip-sync to install the local package.
let has_lock = (if cmd.dev { &dev_lockfile } else { &lockfile }).is_file();
if recreate || cmd.mode != SyncMode::PythonOnly {
let sources = ExpandedSources::from_sources(&pyproject.sources()?)?;
if cmd.no_lock {
let lockfile = if cmd.dev { &dev_lockfile } else { &lockfile };
if !lockfile.is_file() {
if !has_lock {
bail!(
"Locking is disabled but lockfile '{}' does not exist",
lockfile.display()
);
}
} else if cmd.mode == SyncMode::OneOff && has_lock {
// do nothing
} else if let Some(workspace) = pyproject.workspace() {
// make sure we have an up-to-date lockfile
update_workspace_lockfile(
Expand Down Expand Up @@ -310,11 +315,11 @@ pub fn sync(mut cmd: SyncOptions) -> Result<(), Error> {
}

/// Performs an autosync.
pub fn autosync(pyproject: &PyProject, output: CommandOutput) -> Result<(), Error> {
pub fn autosync(pyproject: &PyProject, output: CommandOutput, one_off: bool) -> Result<(), Error> {
sync(SyncOptions {
output,
dev: true,
mode: SyncMode::Regular,
mode: if one_off {SyncMode::OneOff} else {SyncMode::Regular},
force: false,
no_lock: false,
lock_options: LockOptions::default(),
Expand Down
4 changes: 4 additions & 0 deletions rye/tests/test_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,5 +47,9 @@ fn test_dotenv() {
42 23
----- stderr -----
Reusing already existing virtualenv
Installing dependencies
Audited 1 package in [EXECUTION_TIME]
Done!
"###);
}
16 changes: 16 additions & 0 deletions rye/tests/test_init.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ fn test_init_lib() {
Hello from my-project!
----- stderr -----
Reusing already existing virtualenv
Installing dependencies
Audited 1 package in [EXECUTION_TIME]
Done!
"###);

assert!(
Expand Down Expand Up @@ -89,6 +93,10 @@ fn test_init_default() {
Hello from my-project!
----- stderr -----
Reusing already existing virtualenv
Installing dependencies
Audited 1 package in [EXECUTION_TIME]
Done!
"###);

assert!(
Expand Down Expand Up @@ -138,6 +146,10 @@ fn test_init_script() {
Hello from my-project!
----- stderr -----
Reusing already existing virtualenv
Installing dependencies
Audited 1 package in [EXECUTION_TIME]
Done!
"###);

rye_cmd_snapshot!(space.rye_cmd().arg("run").arg("python").arg("-mmy_project"), @r###"
Expand All @@ -147,6 +159,10 @@ fn test_init_script() {
Hello from my-project!
----- stderr -----
Reusing already existing virtualenv
Installing dependencies
Audited 1 package in [EXECUTION_TIME]
Done!
"###);
}

Expand Down

0 comments on commit 802171a

Please sign in to comment.