Repository: mitsuhiko/rye
File: rye/src/cli/run.rs (Rust)

Code before:
    /// List all commands
    #[arg(short, long)]
    list: bool,
    /// The command to run
    #[command(subcommand)]
    cmd: Option<Cmd>,
    /// Find pyproject from this directory
    #[arg(long)]
    pyproject_from: Option<PathBuf>,
}

#[derive(Parser, Debug)]
enum Cmd {
    #[command(external_subcommand)]
    External(Vec<OsString>),
}

pub fn execute(cmd: Args) -> Result<(), Error> {
    let pyproject = if let Some(pyproject_from) = cmd.pyproject_from {
        PyProject::discover_from_path(pyproject_from)?
    } else {
        PyProject::discover()?
    };

    // make sure we have the minimal virtualenv.
    sync(SyncOptions::python_only()).context("failed to sync ahead of run")?;

    if cmd.list || cmd.cmd.is_none() {
        return list_scripts(&pyproject);
    }
    let args = match cmd.cmd {
        Some(Cmd::External(args)) => args,
        None => unreachable!(),
    };

    invoke_script(&pyproject, args, true)?;
    unreachable!();
}

fn invoke_script(
    pyproject: &PyProject,
    mut args: Vec<OsString>,
    exec: bool,
) -> Result<ExitStatus, Error> {
    let venv_bin = pyproject.venv_bin_path();
    let mut env_overrides = None;

    match pyproject.get_script_cmd(&args[0].to_string_lossy()) {
        Some(Script::Cmd(script_args, env_vars)) => {
            if script_args.is_empty() {
                bail!("script has no arguments");

Review comment (suggestion):
Current revision of the PR doesn't always work correctly, because this sync call also uses PyProject::discover. The python_only machinery seems possible to work with, but updating all of sync to work with a "movable" pyproject.toml is not something I can do right now.  One sticking point there is that `.` is given as the input path to pip-tools, and from `.` they find the pyproject and dependences etc.

Code after:
    /// List all commands
    #[arg(short, long)]
    list: bool,
    /// The command to run
    #[command(subcommand)]
    cmd: Option<Cmd>,
    /// Use this pyproject.toml file
    #[arg(long, value_name = "PYPROJECT_TOML")]
    pyproject: Option<PathBuf>,
}

#[derive(Parser, Debug)]
enum Cmd {
    #[command(external_subcommand)]
    External(Vec<OsString>),
}

pub fn execute(cmd: Args) -> Result<(), Error> {
    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 cmd.list || cmd.cmd.is_none() {
        return list_scripts(&pyproject);
    }
    let args = match cmd.cmd {
        Some(Cmd::External(args)) => args,
        None => unreachable!(),
    };

    invoke_script(&pyproject, args, true)?;
    unreachable!();
}

fn invoke_script(
    pyproject: &PyProject,
    mut args: Vec<OsString>,
    exec: bool,
) -> Result<ExitStatus, Error> {
    let venv_bin = pyproject.venv_bin_path();
    let mut env_overrides = None;

    match pyproject.get_script_cmd(&args[0].to_string_lossy()) {
        Some(Script::Cmd(script_args, env_vars)) => {
            if script_args.is_empty() {
                bail!("script has no arguments");
            }
            env_overrides = Some(env_vars);
            let script_target = venv_bin.join(&script_args[0]);