Skip to content

Commit

Permalink
Merge #3
Browse files Browse the repository at this point in the history
3: Split the `retrieve testcases` command r=qryxip a=qryxip



Co-authored-by: Ryo Yamashita <qryxip@gmail.com>
  • Loading branch information
bors[bot] and qryxip authored Aug 3, 2020
2 parents d71b71e + 5aea1a1 commit 5a4df15
Show file tree
Hide file tree
Showing 14 changed files with 835 additions and 596 deletions.
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,10 @@

## [Unreleased]

- Fixed `package.repository` of this package.
### Changed

- Splitted the `download` command into `new`, `open`, and `download`. ([#3](https://github.com/qryxip/cargo-compete/pull/3))

### Fixed

- Fixed `package.repository` of this package. ([#2](https://github.com/qryxip/cargo-compete/pull/3))
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ termcolor = "1.1.0"
tokio = { version = "0.2.22", features = ["signal"] }
toml = "0.5.6"
toml_edit = "0.2.0"
url = "2.1.1"
url = { version = "2.1.1", features = ["serde"] }
which = "4.0.1"

[target.'cfg(windows)'.dependencies]
Expand Down
2 changes: 2 additions & 0 deletions README-ja.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ AtCoderを選択に入れる場合、

### `cargo compete download`

**インターフェイスがよろしくないのでv0.2.0で`new`, `open`, `download`の3つに分割する予定です。** ([#3](https://github.com/qryxip/cargo-compete/pull/3))

テストケースの取得を行います。

**workspace rootかworkspace memberのどちらかを対象に取ります。**
Expand Down
2 changes: 2 additions & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
pub(crate) mod init;
pub(crate) mod login;
pub(crate) mod new;
pub(crate) mod open;
pub(crate) mod participate;
pub(crate) mod retrieve_testcases;
pub(crate) mod submit;
Expand Down
209 changes: 209 additions & 0 deletions src/commands/new.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
use crate::{
project::{MetadataExt as _, WorkspaceMetadataCargoCompetePlatform},
shell::ColorChoice,
};
use anyhow::Context as _;
use snowchains_core::web::{
RetrieveTestCasesOutcome, RetrieveTestCasesOutcomeContest, RetrieveTestCasesOutcomeProblem,
};
use std::path::PathBuf;
use structopt::StructOpt;
use strum::VariantNames as _;
use url::Url;

#[derive(StructOpt, Debug)]
pub struct OptCompeteNew {
/// Retrieve system test cases
#[structopt(long)]
pub full: bool,

/// Open URLs and files
#[structopt(long)]
pub open: bool,

/// Retrieve only the problems
#[structopt(long, value_name("INDEX"))]
pub problems: Option<Vec<String>>,

/// Path to Cargo.toml
#[structopt(long, value_name("PATH"))]
pub manifest_path: Option<PathBuf>,

/// Coloring
#[structopt(
long,
value_name("WHEN"),
possible_values(ColorChoice::VARIANTS),
default_value("auto")
)]
pub color: ColorChoice,

/// Contest ID. Required for some platforms
pub contest: Option<String>,
}

pub fn run(opt: OptCompeteNew, ctx: crate::Context<'_>) -> anyhow::Result<()> {
let OptCompeteNew {
full,
open,
problems,
manifest_path,
color,
contest,
} = opt;

let crate::Context { cwd, shell } = ctx;

shell.set_color_choice(color);

let manifest_path = manifest_path
.map(Ok)
.unwrap_or_else(|| crate::project::locate_project(&cwd))?;
let metadata = crate::project::cargo_metadata(&manifest_path)?;
let workspace_metadata = metadata.read_workspace_metadata()?;

match workspace_metadata.platform {
WorkspaceMetadataCargoCompetePlatform::Atcoder { .. } => {
let contest = contest.with_context(|| "`contest` is required for AtCoder")?;
let problems = problems.map(|ps| ps.into_iter().collect());

let outcome =
crate::web::retrieve_testcases::dl_from_atcoder(&contest, problems, full, shell)?;

let package_name = outcome
.contest
.as_ref()
.map(|RetrieveTestCasesOutcomeContest { id, .. }| id)
.unwrap_or(&contest);

let problems = outcome
.problems
.iter()
.map(|RetrieveTestCasesOutcomeProblem { index, url, .. }| (&**index, url))
.collect();

let workspace_root = metadata.workspace_root.clone();
let pkg_manifest_dir = metadata.workspace_root.join(package_name);
let urls = urls(&outcome);

let file_paths = itertools::zip_eq(
metadata.add_member(package_name, &problems, false, shell)?,
crate::web::retrieve_testcases::save_test_cases(
&workspace_root,
&workspace_metadata.test_suite,
outcome,
shell,
)?,
)
.collect::<Vec<_>>();

if open {
crate::open::open(
&urls,
workspace_metadata.open,
&file_paths,
&pkg_manifest_dir,
&cwd,
shell,
)?;
}
}
WorkspaceMetadataCargoCompetePlatform::Codeforces => {
let contest = contest.with_context(|| "`contest` is required for Codeforces")?;
let problems = problems.map(|ps| ps.into_iter().collect());

let outcome =
crate::web::retrieve_testcases::dl_from_codeforces(&contest, problems, shell)?;

let package_name = outcome
.contest
.as_ref()
.map(|RetrieveTestCasesOutcomeContest { id, .. }| id)
.unwrap_or(&contest);

let problems = outcome
.problems
.iter()
.map(|RetrieveTestCasesOutcomeProblem { index, url, .. }| (&**index, url))
.collect();

let workspace_root = metadata.workspace_root.clone();
let pkg_manifest_dir = metadata.workspace_root.join(package_name);
let urls = urls(&outcome);

let file_paths = itertools::zip_eq(
metadata.add_member(package_name, &problems, false, shell)?,
crate::web::retrieve_testcases::save_test_cases(
&workspace_root,
&workspace_metadata.test_suite,
outcome,
shell,
)?,
)
.collect::<Vec<_>>();

if open {
crate::open::open(
&urls,
workspace_metadata.open,
&file_paths,
&pkg_manifest_dir,
&cwd,
shell,
)?;
}
}
WorkspaceMetadataCargoCompetePlatform::Yukicoder => {
let contest = contest.as_deref();
let problems = problems.map(|ps| ps.into_iter().collect());

let outcome =
crate::web::retrieve_testcases::dl_from_yukicoder(contest, problems, full, shell)?;

let package_name = outcome
.contest
.as_ref()
.map(|RetrieveTestCasesOutcomeContest { id, .. }| &**id)
.or(contest);
let is_no = package_name.is_none();
let package_name = package_name.unwrap_or("problems");

let problems = outcome
.problems
.iter()
.map(|RetrieveTestCasesOutcomeProblem { index, url, .. }| (&**index, url))
.collect();

let workspace_root = metadata.workspace_root.clone();
let pkg_manifest_dir = metadata.workspace_root.join(package_name);
let urls = urls(&outcome);

let file_paths = itertools::zip_eq(
metadata.add_member(package_name, &problems, is_no, shell)?,
crate::web::retrieve_testcases::save_test_cases(
&workspace_root,
&workspace_metadata.test_suite,
outcome,
shell,
)?,
)
.collect::<Vec<_>>();

if open {
crate::open::open(
&urls,
workspace_metadata.open,
&file_paths,
&pkg_manifest_dir,
&cwd,
shell,
)?;
}
}
}
Ok(())
}

fn urls(outcome: &RetrieveTestCasesOutcome) -> Vec<Url> {
outcome.problems.iter().map(|p| p.url.clone()).collect()
}
106 changes: 106 additions & 0 deletions src/commands/open.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
use crate::{
project::{MetadataExt as _, PackageExt as _, PackageMetadataCargoCompeteBin},
shell::ColorChoice,
};
use maplit::hashset;
use std::{collections::HashSet, path::PathBuf};
use structopt::StructOpt;
use strum::VariantNames as _;

#[derive(StructOpt, Debug)]
pub struct OptCompeteOpen {
/// Retrieves system test cases
#[structopt(long)]
pub full: bool,

/// Problem indexes
#[structopt(long)]
pub problems: Option<Vec<String>>,

/// Package (see `cargo help pkgid`)
#[structopt(short, long, value_name("SPEC"))]
pub package: Option<String>,

/// Path to Cargo.toml
#[structopt(long, value_name("PATH"))]
pub manifest_path: Option<PathBuf>,

/// Coloring
#[structopt(
long,
value_name("WHEN"),
possible_values(ColorChoice::VARIANTS),
default_value("auto")
)]
pub color: ColorChoice,
}

pub(crate) fn run(opt: OptCompeteOpen, ctx: crate::Context<'_>) -> anyhow::Result<()> {
let OptCompeteOpen {
full,
problems,
package,
manifest_path,
color,
} = opt;

let crate::Context { cwd, shell } = ctx;

shell.set_color_choice(color);

let problems = problems.map(|ps| ps.into_iter().collect::<HashSet<_>>());

let manifest_path = manifest_path
.map(Ok)
.unwrap_or_else(|| crate::project::locate_project(&cwd))?;
let metadata = crate::project::cargo_metadata(&manifest_path)?;
let workspace_metadata = metadata.read_workspace_metadata()?;

let member = metadata.query_for_member(package)?;

let package_metadata_bin = member.read_package_metadata()?.bin;

let mut urls = vec![];
let mut file_paths = vec![];
let mut missing = hashset!();

for (index, PackageMetadataCargoCompeteBin { name, problem, .. }) in &package_metadata_bin {
if problems.as_ref().map_or(true, |ps| ps.contains(index)) {
urls.extend(problem.url());

let test_suite_path = crate::testing::test_suite_path(
&metadata.workspace_root,
&workspace_metadata.test_suite,
&problem,
)?;

if !test_suite_path.exists() {
missing.insert(index.clone());
}

file_paths.push((&member.bin_target(&name)?.src_path, test_suite_path));
}
}

if !missing.is_empty() {
shell.status("Retrieving", "missing test cases")?;

crate::web::retrieve_testcases::dl_for_existing_package(
&package_metadata_bin,
Some(&missing),
full,
&metadata.workspace_root,
&workspace_metadata.test_suite,
shell,
)?;
}

crate::open::open(
&urls,
workspace_metadata.open,
&file_paths,
member.manifest_path.parent().unwrap(),
&cwd,
shell,
)
}
Loading

0 comments on commit 5a4df15

Please sign in to comment.