Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
3 changes: 2 additions & 1 deletion src/commands/artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,11 @@ use std::io::Write;
use crate::client::read_artifact;
use crate::error::require_credentials;
use crate::error::{anyhow, Result};
use crate::local::resolve::resolve_run;

pub async fn run(args: crate::ArtifactArgs) -> Result<()> {
let store = crate::store::Store::open()?;
if crate::local::local_run(&store, &args.run_id)?.is_some() {
if resolve_run(&store, &args.run_id)?.is_local() {
return Err(crate::local::unsupported("artifact"));
}
let creds = require_credentials().await;
Expand Down
3 changes: 2 additions & 1 deletion src/commands/artifacts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,12 @@
use crate::client::list_artifacts;
use crate::error::require_credentials;
use crate::error::Result;
use crate::local::resolve::resolve_run;
use crate::output::print_table;

pub async fn run(args: crate::ArtifactsArgs) -> Result<()> {
let store = crate::store::Store::open()?;
if crate::local::local_run(&store, &args.run_id)?.is_some() {
if resolve_run(&store, &args.run_id)?.is_local() {
return Err(crate::local::unsupported("artifacts"));
}
let creds = require_credentials().await;
Expand Down
3 changes: 2 additions & 1 deletion src/commands/chart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use std::path::PathBuf;

use crate::client::{render_wandb_chart, WandbChartBody, WandbChartResult, WandbRunSpec};
use crate::error::{require_credentials, Result};
use crate::local::resolve::resolve_project;

const USAGE: &str = "Usage: orx chart wandb <projectId> --metric \"<key>\" --run <runId>[:label] [--run ...] [--smoothing <0-0.99>] [--out <dir>]";

Expand Down Expand Up @@ -171,7 +172,7 @@ pub async fn run(args: crate::ChartArgs) -> Result<()> {
}

let store = crate::store::Store::open()?;
if store.get_local_project(&args.project_id)?.is_some() {
if resolve_project(&store, &args.project_id)?.is_local() {
return Err(crate::local::unsupported("chart"));
}
let creds = require_credentials().await;
Expand Down
37 changes: 22 additions & 15 deletions src/commands/create_experiment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@ use crate::client::{
CreateChildBody, Experiment,
};
use crate::error::{anyhow, require_credentials, Result};
use crate::local::resolve::{resolve_project, ProjectRef};
use crate::store::Store;

const USAGE: &str = "Usage: orx create-experiment <projectId> --title \"<title>\" [--parent <experimentId>] [--description \"<text>\"] [--run-command \"<cmd>\"]";

pub async fn run(args: crate::CreateExperimentArgs) -> Result<()> {
let title = match args.title {
pub async fn run(mut args: crate::CreateExperimentArgs) -> Result<()> {
let title = match args.title.take() {
Some(t) => t,
None => {
eprintln!("{}", USAGE);
Expand All @@ -34,21 +35,27 @@ pub async fn run(args: crate::CreateExperimentArgs) -> Result<()> {

// Local project (orx up): create the row + branch locally, no api.
let store = Store::open()?;
if let Some(project) = store.get_local_project(&args.project_id)? {
run_local(
&store,
&project,
title,
args.parent,
args.baseline,
args.description,
args.run_command,
)?;
// Key event, fired only on success. Coarse props only — no ids/names.
crate::telemetry::capture_experiment_started("create", true, None);
return Ok(());
match resolve_project(&store, &args.project_id)? {
ProjectRef::Local(project) => {
run_local(
&store,
&project,
title,
args.parent,
args.baseline,
args.description,
args.run_command,
)?;
// Key event, fired only on success. Coarse props only — no ids/names.
crate::telemetry::capture_experiment_started("create", true, None);
Ok(())
}
ProjectRef::Server(_) => run_server(args, title).await,
}
}

/// Server-mode create via the api.
async fn run_server(args: crate::CreateExperimentArgs, title: String) -> Result<()> {
// The server child-create API carries no run command field — refuse rather
// than silently drop it. (The baseline create below does accept one.)
if args.run_command.is_some() && args.parent.is_some() {
Expand Down
3 changes: 2 additions & 1 deletion src/commands/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

use crate::client::list_env_var_names;
use crate::error::{require_credentials, Result};
use crate::local::resolve::resolve_project;

/// Lists a project's effective env var names, grouped by source.
pub async fn run(args: crate::EnvArgs) -> Result<()> {
let store = crate::store::Store::open()?;
if store.get_local_project(&args.project_id)?.is_some() {
if resolve_project(&store, &args.project_id)?.is_local() {
return Err(crate::local::unsupported("env"));
}
let creds = require_credentials().await;
Expand Down
87 changes: 47 additions & 40 deletions src/commands/exp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ use crate::client::{
use crate::error::{anyhow, require_credentials, Result};
use crate::jobs::{huggingface as hf, BackendDescriptor};
use crate::local::model::LocalExperiment;
use crate::local::resolve::{resolve_experiment, resolve_project, ExperimentRef, ProjectRef};
use crate::output::{format_duration, run_failure_detail};
use crate::store::{now_ms, Store, StoredRun};
use crate::{ExpCommand, ExpRunArgs};
Expand All @@ -30,42 +31,44 @@ pub async fn run(args: crate::ExpArgs) -> Result<()> {
// user may never have logged in).
let store = Store::open()?;
match args.command {
ExpCommand::Status { exp_id } => {
if let Some(exp) = store.get_local_experiment(&exp_id)? {
return local_status(&store, &exp);
ExpCommand::Status { exp_id } => match resolve_experiment(&store, &exp_id)? {
ExperimentRef::Local(exp) => local_status(&store, &exp),
ExperimentRef::Server(exp_id) => {
let creds = require_credentials().await;
status(&creds, &exp_id).await
}
let creds = require_credentials().await;
status(&creds, &exp_id).await
}
ExpCommand::Cmd { exp_id, set } => {
if store.get_local_experiment(&exp_id)?.is_some() {
return Err(crate::local::unsupported("exp cmd"));
},
ExpCommand::Cmd { exp_id, set } => match resolve_experiment(&store, &exp_id)? {
ExperimentRef::Local(_) => Err(crate::local::unsupported("exp cmd")),
ExperimentRef::Server(exp_id) => {
let creds = require_credentials().await;
cmd(&creds, &exp_id, set).await
}
let creds = require_credentials().await;
cmd(&creds, &exp_id, set).await
}
ExpCommand::Desc { exp_id, set, stdin } => {
if let Some(exp) = store.get_local_experiment(&exp_id)? {
return local_desc(&store, exp, set, stdin).await;
},
ExpCommand::Desc { exp_id, set, stdin } => match resolve_experiment(&store, &exp_id)? {
ExperimentRef::Local(exp) => local_desc(&store, *exp, set, stdin).await,
ExperimentRef::Server(exp_id) => {
let creds = require_credentials().await;
desc(&creds, &exp_id, set, stdin).await
}
let creds = require_credentials().await;
desc(&creds, &exp_id, set, stdin).await
}
},
ExpCommand::Run(run_args) => {
let run_args = *run_args;
if store.get_local_experiment(&run_args.exp_id)?.is_some() {
return local_launch(run_args).await;
match resolve_experiment(&store, &run_args.exp_id)? {
ExperimentRef::Local(_) => local_launch(run_args).await,
ExperimentRef::Server(_) => {
let creds = require_credentials().await;
launch(&creds, run_args).await
}
}
let creds = require_credentials().await;
launch(&creds, run_args).await
}
ExpCommand::Cancel { exp_id } => {
if let Some(exp) = store.get_local_experiment(&exp_id)? {
return local_cancel(&store, &exp);
ExpCommand::Cancel { exp_id } => match resolve_experiment(&store, &exp_id)? {
ExperimentRef::Local(exp) => local_cancel(&store, &exp),
ExperimentRef::Server(exp_id) => {
let creds = require_credentials().await;
cancel(&creds, &exp_id).await
}
let creds = require_credentials().await;
cancel(&creds, &exp_id).await
}
},
ExpCommand::Wait {
exp_id,
project,
Expand Down Expand Up @@ -104,20 +107,24 @@ async fn wait(
"Specify what to wait on: `orx exp wait <expId>` (one run) or \
`orx exp wait --project <projectId>` (any run in a project)."
)),
(Some(exp_id), None) => {
if store.get_local_experiment(&exp_id)?.is_some() {
return local_wait_experiment(store, &exp_id, interval, deadline).await;
(Some(exp_id), None) => match resolve_experiment(store, &exp_id)? {
ExperimentRef::Local(_) => {
local_wait_experiment(store, &exp_id, interval, deadline).await
}
let creds = require_credentials().await;
wait_experiment(&creds, &exp_id, interval, deadline).await
}
(None, Some(project_id)) => {
if store.get_local_project(&project_id)?.is_some() {
return local_wait_project(store, &project_id, interval, deadline).await;
ExperimentRef::Server(exp_id) => {
let creds = require_credentials().await;
wait_experiment(&creds, &exp_id, interval, deadline).await
}
let creds = require_credentials().await;
wait_project(&creds, &project_id, interval, deadline).await
}
},
(None, Some(project_id)) => match resolve_project(store, &project_id)? {
ProjectRef::Local(_) => {
local_wait_project(store, &project_id, interval, deadline).await
}
ProjectRef::Server(project_id) => {
let creds = require_credentials().await;
wait_project(&creds, &project_id, interval, deadline).await
}
},
}
}

Expand Down
3 changes: 2 additions & 1 deletion src/commands/experiments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ use std::collections::{HashMap, HashSet};

use crate::client::{list_experiments, Experiment};
use crate::error::{require_credentials, Result};
use crate::local::resolve::resolve_project;

/// Lists a project's experiments as an indented tree (by parentExperimentId).
pub async fn run(args: crate::ExperimentsArgs) -> Result<()> {
let store = crate::store::Store::open()?;
if store.get_local_project(&args.project_id)?.is_some() {
if resolve_project(&store, &args.project_id)?.is_local() {
return Err(crate::local::unsupported("experiments"));
}
let creds = require_credentials().await;
Expand Down
25 changes: 14 additions & 11 deletions src/commands/logs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::io::{Read as _, Seek as _, Write};
use crate::client::read_run_log;
use crate::error::require_credentials;
use crate::error::Result;
use crate::local::resolve::{resolve_run, RunRef};
use crate::store::{log_path, Store};

/// Parses a string the way JS `Number(s)` does for our purposes and returns it
Expand Down Expand Up @@ -61,21 +62,23 @@ pub async fn run(args: crate::LogsArgs) -> Result<()> {
// Local run (orx up): the log is a plain file beside the store — read it
// directly, no api / login needed.
let store = Store::open()?;
if crate::local::local_run(&store, &args.run_id)?.is_some() {
return run_local(&args.run_id, mode, max_bytes, start_byte, end_byte);
match resolve_run(&store, &args.run_id)? {
RunRef::Local(_) => run_local(&args.run_id, mode, max_bytes, start_byte, end_byte),
RunRef::Server(_) => run_server(&args.run_id, mode, max_bytes, start_byte, end_byte).await,
}
}

/// Server-mode log read via the api.
async fn run_server(
run_id: &str,
mode: &str,
max_bytes: Option<i64>,
start_byte: Option<i64>,
end_byte: Option<i64>,
) -> Result<()> {
let creds = require_credentials().await;

let log = read_run_log(
&creds,
&args.run_id,
Some(mode),
max_bytes,
start_byte,
end_byte,
)
.await?;
let log = read_run_log(&creds, run_id, Some(mode), max_bytes, start_byte, end_byte).await?;

// The log itself goes to stdout (pipe-friendly); metadata to stderr so it
// doesn't pollute a `| grep` or a redirect.
Expand Down
14 changes: 10 additions & 4 deletions src/commands/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,16 @@ use crate::client::{
};
use crate::commands::experiments::print_tree;
use crate::error::{anyhow, require_credentials, Result};
use crate::local::resolve::{resolve_project, ProjectRef};
use crate::ProjectCommand;

pub async fn run(args: crate::ProjectArgs) -> Result<()> {
let project_id = match &args.command {
ProjectCommand::View { project_id } | ProjectCommand::Edit { project_id, .. } => project_id,
};
let store = crate::store::Store::open()?;
if let Some(project) = store.get_local_project(project_id)? {
return match args.command {
match resolve_project(&store, project_id)? {
ProjectRef::Local(project) => match args.command {
ProjectCommand::View { .. } => view_local(&store, &project),
ProjectCommand::Edit {
name,
Expand All @@ -37,10 +38,15 @@ pub async fn run(args: crate::ProjectArgs) -> Result<()> {
"Local projects support --name and --run-command only."
));
}
edit_local(&store, project, name, run_command)
edit_local(&store, *project, name, run_command)
}
};
},
ProjectRef::Server(_) => run_server(args).await,
}
}

/// Server-mode `orx project` via the api.
async fn run_server(args: crate::ProjectArgs) -> Result<()> {
// The server project PATCH carries no run command field — refuse before
// even asking for credentials.
if let ProjectCommand::Edit {
Expand Down
3 changes: 2 additions & 1 deletion src/commands/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::client::{query_project, SyncStatus};
use crate::error::{require_credentials, Result};
use crate::local::resolve::resolve_project;
use crate::output::{cell, print_table};

/// Renders the wire form of a sync status (matches the TS `"ready" | ...` union).
Expand All @@ -17,7 +18,7 @@ pub async fn run(args: crate::QueryArgs) -> Result<()> {
// clap enforces the required positionals, so the TS `if (!projectId || !sql)`
// usage guard is unnecessary here.
let store = crate::store::Store::open()?;
if store.get_local_project(&args.project_id)?.is_some() {
if resolve_project(&store, &args.project_id)?.is_local() {
return Err(crate::local::unsupported("query"));
}
let creds = require_credentials().await;
Expand Down
10 changes: 8 additions & 2 deletions src/commands/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use crate::client::{
};
use crate::config::Credentials;
use crate::error::{anyhow, require_credentials, Result};
use crate::local::resolve::{resolve_project, ProjectRef};

pub async fn run(args: crate::ReportArgs) -> Result<()> {
let project_id = match &args.command {
Expand All @@ -23,9 +24,14 @@ pub async fn run(args: crate::ReportArgs) -> Result<()> {
| crate::ReportCommand::Download { project_id, .. } => project_id,
};
let store = crate::store::Store::open()?;
if let Some(project) = store.get_local_project(project_id)? {
return local_guidance(&project);
match resolve_project(&store, project_id)? {
ProjectRef::Local(project) => local_guidance(&project),
ProjectRef::Server(_) => run_server(args).await,
}
}

/// Server-mode `orx report` via the api.
async fn run_server(args: crate::ReportArgs) -> Result<()> {
match args.command {
crate::ReportCommand::Upload {
project_id,
Expand Down
9 changes: 7 additions & 2 deletions src/commands/runs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,22 @@ use std::collections::HashMap;

use crate::client::{list_experiments, list_runs};
use crate::error::{require_credentials, Result};
use crate::local::resolve::{resolve_project, ProjectRef};
use crate::output::{format_duration, print_table, run_failure_detail};
use crate::store::Store;

/// Lists a project's runs as a table, newest first.
pub async fn run(args: crate::RunsArgs) -> Result<()> {
// Local project (orx up): the store is the truth, no api / login needed.
let store = Store::open()?;
if store.get_local_project(&args.project_id)?.is_some() {
return run_local(&store, &args);
match resolve_project(&store, &args.project_id)? {
ProjectRef::Local(_) => run_local(&store, &args),
ProjectRef::Server(_) => run_server(&args).await,
}
}

/// Server-mode listing from the api.
async fn run_server(args: &crate::RunsArgs) -> Result<()> {
let creds = require_credentials().await;

// Fetch experiments too, so we can label each run with its experiment title
Expand Down
Loading
Loading