Skip to content

Commit

Permalink
add template command
Browse files Browse the repository at this point in the history
  • Loading branch information
jpopesculian committed Feb 14, 2024
1 parent 989e3d0 commit c2dc39c
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 44 deletions.
48 changes: 4 additions & 44 deletions src/commands/install.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
use crate::{
cache::{needs_update, set_last_update_time},
compress::decompress,
dirs::{
init_venv, project_config_dir, project_data_dir, project_use_case_toml_path, read_pyproject,
},
download::download_tar_gz,
error::{self, Result},
graphql_client::{custom_scalars::*, GraphQLClient},
python::pip_install,
Expand All @@ -14,7 +14,7 @@ use clap::Args;
use futures::prelude::*;
use graphql_client::GraphQLQuery;
use indicatif::{MultiProgress, ProgressBar};
use std::path::{Path, PathBuf};
use std::path::PathBuf;
use url::Url;

#[derive(GraphQLQuery)]
Expand All @@ -25,46 +25,6 @@ use url::Url;
)]
pub struct GetCompetitionUseCase;

async fn download_use_case_data(dir: impl AsRef<Path>, url: Url) -> Result<()> {
tokio::fs::create_dir_all(&dir).await.map_err(|e| {
error::user(
&format!("Failed to create use case data directory: {e}"),
"Please make sure you have permission to create directories in this directory",
)
})?;
let client = reqwest::Client::new();
let mut byte_stream = client
.get(url)
.send()
.await
.map_err(|e| {
error::user(
&format!("Failed to download use case data: {e}"),
"Check your internet connection and try again",
)
})?
.error_for_status()
.map_err(|e| error::system(&format!("Failed to download use case data: {e}"), ""))?
.bytes_stream();
let tempfile = tempfile::NamedTempFile::new().map_err(|e| {
error::user(
&format!("Failed to create temporary file: {e}"),
"Please make sure you have permission to create files in this directory",
)
})?;
let mut tar_file = tokio::fs::File::create(tempfile.path()).await?;
while let Some(item) = byte_stream.next().await {
tokio::io::copy(&mut item?.as_ref(), &mut tar_file).await?;
}
decompress(tempfile.path(), &dir).await.map_err(|e| {
error::user(
&format!("Failed to decompress use case data: {e}"),
"Please make sure you have permission to create files in this directory",
)
})?;
Ok(())
}

#[derive(Args, Debug)]
#[command(author, version, about)]
pub struct Install {
Expand Down Expand Up @@ -206,9 +166,9 @@ pub async fn install_submission(args: Install, project: PyProject) -> Result<()>
.download_url
.clone();

let download_fut = download_use_case_data(
project_data_dir(&args.project_dir, "data"),
let download_fut = download_tar_gz(
use_case_data_url,
project_data_dir(&args.project_dir, "data"),
)
.map(move |res| {
if res.is_ok() {
Expand Down
4 changes: 4 additions & 0 deletions src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod install;
mod login;
mod python;
mod shell;
mod template;
mod test;
mod upload;
mod version;
Expand All @@ -10,6 +11,7 @@ use install::{install, Install};
use login::{login, Login};
use python::{python, Python};
use shell::{shell, Shell};
use template::{template, Template};
use test::{test, Test};
use upload::{upload, Upload};

Expand All @@ -24,6 +26,7 @@ pub enum Cli {
Shell(Shell),
Test(Test),
Upload(Upload),
Template(Template),
}

impl Cli {
Expand All @@ -35,6 +38,7 @@ impl Cli {
Cli::Shell(args) => shell(args).await,
Cli::Test(args) => test(args).await,
Cli::Upload(args) => upload(args).await,
Cli::Template(args) => template(args).await,
}
}
}
104 changes: 104 additions & 0 deletions src/commands/template.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
use crate::{
download::download_tar_gz,
error::{self, Result},
graphql_client::GraphQLClient,
};
use clap::Args;
use graphql_client::GraphQLQuery;
use indicatif::{MultiProgress, ProgressBar};
use std::path::PathBuf;
use url::Url;

#[derive(GraphQLQuery)]
#[graphql(
query_path = "src/graphql/get_competition_template.graphql",
schema_path = "src/graphql/schema.graphql",
response_derives = "Debug"
)]
pub struct GetCompetitionTemplate;

#[derive(Args, Debug)]
#[command(author, version, about)]
pub struct Template {
#[arg(short, long, default_value = "https://app.aqora.io")]
pub url: String,
pub competition: String,
pub destination: Option<PathBuf>,
}

pub async fn template(args: Template) -> Result<()> {
let client = GraphQLClient::new(args.url.parse()?).await?;

let destination = args
.destination
.unwrap_or_else(|| PathBuf::from(args.competition.clone()));

if destination.exists()
&& (destination.is_file()
|| destination.is_symlink()
|| tokio::fs::read_dir(&destination)
.await?
.next_entry()
.await?
.is_some())
{
return Err(error::user(
&format!("Destination '{}' already exists", destination.display()),
"Please specify a different destination",
));
}

let m = MultiProgress::new();
let mut pb = ProgressBar::new_spinner().with_message("Fetching competition...");
pb.enable_steady_tick(std::time::Duration::from_millis(100));
pb = m.add(pb);

let use_case = client
.send::<GetCompetitionTemplate>(get_competition_template::Variables {
slug: args.competition.clone(),
})
.await?
.competition_by_slug
.ok_or_else(|| {
error::user(
&format!("Competition '{}' not found", &args.competition),
"Please make sure the competition exists",
)
})?
.use_case
.latest
.ok_or_else(|| {
error::system(
"No use case found",
"Please contact the competition organizer",
)
})?;

let download_url = use_case
.files
.into_iter()
.find(|file| {
matches!(
file.kind,
get_competition_template::ProjectVersionFileKind::TEMPLATE
)
})
.ok_or_else(|| {
error::system(
"No template found",
"Please contact the competition organizer",
)
})?
.download_url;

pb.set_message("Downloading competition template...");

download_tar_gz(download_url, &destination).await?;

pb.finish_with_message(format!(
"Competition template downloaded to {}",
destination.display()
));

Ok(())
}
51 changes: 51 additions & 0 deletions src/download.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
use crate::{
compress::decompress,
error::{self, Result},
};
use futures::prelude::*;
use std::path::Path;
use url::Url;

pub async fn download_tar_gz(url: Url, dir: impl AsRef<Path>) -> Result<()> {
tokio::fs::create_dir_all(&dir).await.map_err(|e| {
error::user(
&format!(
"Failed to create directory {}: {}",
dir.as_ref().display(),
e
),
"Please make sure you have permission to create directories in this directory",
)
})?;
let client = reqwest::Client::new();
let mut byte_stream = client
.get(url)
.send()
.await
.map_err(|e| {
error::user(
&format!("Failed to download data: {e}"),
"Check your internet connection and try again",
)
})?
.error_for_status()
.map_err(|e| error::system(&format!("Failed to download data: {e}"), ""))?
.bytes_stream();
let tempfile = tempfile::NamedTempFile::new().map_err(|e| {
error::user(
&format!("Failed to create temporary file: {e}"),
"Please make sure you have permission to create files in this directory",
)
})?;
let mut tar_file = tokio::fs::File::create(tempfile.path()).await?;
while let Some(item) = byte_stream.next().await {
tokio::io::copy(&mut item?.as_ref(), &mut tar_file).await?;
}
decompress(tempfile.path(), &dir).await.map_err(|e| {
error::user(
&format!("Failed to decompress data: {e}"),
"Please make sure you have permission to create files in this directory",
)
})?;
Ok(())
}
13 changes: 13 additions & 0 deletions src/graphql/get_competition_template.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
query GetCompetitionTemplate($slug: String!) {
competitionBySlug(slug: $slug) {
id
useCase {
latest {
files {
kind
downloadUrl
}
}
}
}
}
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod commands;
mod compress;
mod credentials;
mod dirs;
mod download;
mod error;
mod graphql_client;
mod id;
Expand Down

0 comments on commit c2dc39c

Please sign in to comment.