Skip to content

Commit f5b5afb

Browse files
committed
implemented prepare-submission
1 parent 56a8e52 commit f5b5afb

File tree

88 files changed

+2701
-20
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

88 files changed

+2701
-20
lines changed

tmc-langs-cli/src/app.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,11 +79,37 @@ pub fn create_app() -> App<'static, 'static> {
7979
.takes_value(true)))
8080

8181
.subcommand(SubCommand::with_name("prepare-submission")
82-
.about("UNIMPLEMENTED. Prepares from submission and solution project for which the tests can be run in sandbox.")
82+
.about("Prepares from submission and solution project for which the tests can be run in sandbox.")
8383
.arg(Arg::with_name("submission-path")
8484
.help("Path to the zip archive to be submitted.")
8585
.long("submission-path")
8686
.required(true)
87+
.takes_value(true))
88+
.arg(Arg::with_name("output-path")
89+
.help("Path to the resulting archive.")
90+
.long("output-path")
91+
.required(true)
92+
.takes_value(true))
93+
.arg(Arg::with_name("tmc-param")
94+
.help("A key-value pair in the form key=value to be written into .tmcparams. If multiple pairs with the same key are given, the values are interpreted as an array.")
95+
.long("tmc-param")
96+
.takes_value(true)
97+
.multiple(true))
98+
.arg(Arg::with_name("clone-path")
99+
.help("Path to exercise's clone path, where the unmodified test files will be copied from.")
100+
.long("clone-path")
101+
.takes_value(true)
102+
.required(true))
103+
.arg(Arg::with_name("output-zip")
104+
.help("Packages the submission into a zip archive instead of a tar.")
105+
.long("output-zip"))
106+
.arg(Arg::with_name("top-level-dir-name")
107+
.help("If given, the contents in the resulting archive will be nested inside a directory with this name.")
108+
.long("top-level-dir-name")
109+
.takes_value(true))
110+
.arg(Arg::with_name("stub-zip-path")
111+
.help("If given, the tests will be copied from the stub zip instead, effectively ignoring hidden tests.")
112+
.long("stub-zip-path")
87113
.takes_value(true)))
88114

89115
.subcommand(SubCommand::with_name("run-tests")

tmc-langs-cli/src/main.rs

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,10 @@ use tmc_langs_core::oauth2::{
2020
};
2121
use tmc_langs_core::{FeedbackAnswer, TmcCore, Token};
2222
use tmc_langs_framework::io::submission_processing;
23-
use tmc_langs_util::{task_executor, Language};
23+
use tmc_langs_util::{
24+
task_executor::{self, TmcParams},
25+
Language,
26+
};
2427
use url::Url;
2528
use walkdir::WalkDir;
2629

@@ -132,12 +135,62 @@ fn run() -> Result<()> {
132135
exercise_path.display(),
133136
)
134137
})?;
135-
} else if let Some(_matches) = matches.subcommand_matches("prepare-submission") {
136-
Error::with_description(
137-
"This command is unimplemented.",
138-
ErrorKind::InvalidSubcommand,
139-
)
140-
.exit();
138+
} else if let Some(matches) = matches.subcommand_matches("prepare-submission") {
139+
let submission_path = matches.value_of("submission-path").unwrap();
140+
let submission_path = dbg!(Path::new(submission_path));
141+
142+
let output_path = matches.value_of("output-path").unwrap();
143+
let output_path = dbg!(Path::new(output_path));
144+
145+
let tmc_params_values = matches.values_of("tmc-param").unwrap_or_default();
146+
let mut tmc_params_grouped = HashMap::new();
147+
for value in tmc_params_values {
148+
let params: Vec<_> = value.split('=').collect();
149+
if params.len() != 2 {
150+
Error::with_description(
151+
"tmc-param values should contain a single '=' as a delimiter.",
152+
ErrorKind::ValueValidation,
153+
)
154+
.exit();
155+
}
156+
let key = params[0];
157+
let value = params[1];
158+
let entry = tmc_params_grouped.entry(key).or_insert_with(Vec::new);
159+
entry.push(value);
160+
}
161+
let mut tmc_params = TmcParams::new();
162+
for (key, values) in tmc_params_grouped {
163+
if values.len() == 1 {
164+
tmc_params
165+
.insert_string(key, values[0])
166+
.context("invalid tmc-param key-value pair")?;
167+
} else {
168+
tmc_params
169+
.insert_array(key, values)
170+
.context("invalid tmc-param key-value pair")?;
171+
}
172+
}
173+
174+
let clone_path = matches.value_of("clone-path").unwrap();
175+
let clone_path = dbg!(Path::new(clone_path));
176+
177+
let output_zip = dbg!(matches.is_present("output-zip"));
178+
179+
let top_level_dir_name = matches.value_of("top-level-dir-name");
180+
let top_level_dir_name = top_level_dir_name.map(str::to_string);
181+
182+
let stub_zip_path = matches.value_of("stub-zip-path");
183+
let stub_zip_path = stub_zip_path.map(Path::new);
184+
185+
task_executor::prepare_submission(
186+
submission_path,
187+
output_path,
188+
top_level_dir_name,
189+
tmc_params,
190+
clone_path,
191+
stub_zip_path,
192+
output_zip,
193+
)?;
141194
} else if let Some(matches) = matches.subcommand_matches("run-tests") {
142195
let exercise_path = matches.value_of("exercise-path").unwrap();
143196
let exercise_path = Path::new(exercise_path);

tmc-langs-framework/src/error.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::path::PathBuf;
44
use std::time::Duration;
55
use thiserror::Error;
66

7+
// todo: make util error type and move variants there
78
#[derive(Error, Debug)]
89
pub enum TmcError {
910
// IO
@@ -17,10 +18,14 @@ pub enum TmcError {
1718
CreateDir(PathBuf, #[source] std::io::Error),
1819
#[error("Failed to remove dir at {0}")]
1920
RemoveDir(PathBuf, #[source] std::io::Error),
21+
#[error("Failed to create temporary directory")]
22+
TempDir(#[source] std::io::Error),
2023
#[error("Failed to rename {0} to {1}")]
2124
Rename(PathBuf, PathBuf, #[source] std::io::Error),
2225
#[error("Failed to write to {0}")]
2326
Write(PathBuf, #[source] std::io::Error),
27+
#[error("Failed to read zip archive at {0}")]
28+
ZipRead(PathBuf, #[source] std::io::Error),
2429
#[error("Error appending to tar")]
2530
TarAppend(#[source] std::io::Error),
2631
#[error("Error finishing tar")]
@@ -37,6 +42,10 @@ pub enum TmcError {
3742
Canonicalize(PathBuf, #[source] std::io::Error),
3843
#[error("Error occurred in a child process")]
3944
Process(#[source] std::io::Error),
45+
#[error("Failed to set permissions for {0}")]
46+
SetPermissions(PathBuf, #[source] std::io::Error),
47+
#[error("Invalid parameter value: {0}")]
48+
InvalidParam(String),
4049

4150
#[error("Path {0} contained invalid UTF8")]
4251
UTF8(PathBuf),
@@ -62,4 +71,6 @@ pub enum TmcError {
6271
YamlDeserialization(#[from] serde_yaml::Error),
6372
#[error(transparent)]
6473
ZipError(#[from] zip::ZipError),
74+
#[error(transparent)]
75+
WalkDir(#[from] walkdir::Error),
6576
}

tmc-langs-java/src/ant.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use policy::AntStudentFilePolicy;
99
use std::env;
1010
use std::fs::{self, File};
1111
use std::io::Write;
12-
use std::path::Path;
12+
use std::path::{Path, PathBuf};
1313
use std::process::{Command, Stdio};
1414
use std::time::Duration;
1515
use tmc_langs_framework::{
@@ -145,6 +145,14 @@ impl LanguagePlugin for AntPlugin {
145145
.into())
146146
}
147147
}
148+
149+
fn get_default_student_file_paths(&self) -> Vec<PathBuf> {
150+
vec![PathBuf::from("src/main")]
151+
}
152+
153+
fn get_default_exercise_file_paths(&self) -> Vec<PathBuf> {
154+
vec![PathBuf::from("src/test")]
155+
}
148156
}
149157

150158
impl JavaPlugin for AntPlugin {

tmc-langs-java/src/error.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ pub enum JavaError {
4242
FileCopy(PathBuf, PathBuf, #[source] std::io::Error),
4343
#[error("Failed to find cache directory")]
4444
CacheDir,
45+
#[error("Failed to compile")]
46+
Compilation(Vec<u8>),
4547

4648
#[error(transparent)]
4749
Json(#[from] serde_json::Error),

tmc-langs-java/src/maven.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use policy::MavenStudentFilePolicy;
1010
use std::ffi::OsString;
1111
use std::fs;
1212
use std::io::Cursor;
13-
use std::path::Path;
13+
use std::path::{Path, PathBuf};
1414
use std::process::{Command, Stdio};
1515
use std::time::Duration;
1616
use tar::Archive;
@@ -128,6 +128,14 @@ impl LanguagePlugin for MavenPlugin {
128128

129129
Ok(())
130130
}
131+
132+
fn get_default_student_file_paths(&self) -> Vec<PathBuf> {
133+
vec![PathBuf::from("src/main")]
134+
}
135+
136+
fn get_default_exercise_file_paths(&self) -> Vec<PathBuf> {
137+
vec![PathBuf::from("src/test")]
138+
}
131139
}
132140

133141
impl JavaPlugin for MavenPlugin {

tmc-langs-java/src/plugin.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,8 +151,10 @@ pub(crate) trait JavaPlugin: LanguagePlugin {
151151
exercise_name: String,
152152
compile_result: CompileResult,
153153
) -> Result<ExerciseDesc, JavaError> {
154-
if !Self::is_exercise_type_correct(path) || !compile_result.status_code.success() {
154+
if !Self::is_exercise_type_correct(path) {
155155
return Err(JavaError::InvalidExercise(path.to_path_buf()));
156+
} else if !compile_result.status_code.success() {
157+
return Err(JavaError::Compilation(compile_result.stderr));
156158
}
157159

158160
let mut source_files = vec![];

tmc-langs-util/Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ tmc-langs-r = { path = "../tmc-langs-r" }
1616
log = "0.4"
1717
tar = "0.4"
1818
walkdir = "2"
19+
tempfile = "3"
20+
zip = "0.5"
21+
shellwords = "1"
1922

2023
[dev-dependencies]
2124
env_logger = "0.7"
22-
tempfile = "3"

tmc-langs-util/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
//! Contains the task executor
22
3-
mod tar;
43
pub mod task_executor;
54

65
pub use tmc_langs_abstraction::{Strategy, ValidationResult};

tmc-langs-util/src/task_executor.rs

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
//! Module for calling different tasks of TMC-langs language plug-ins.
22
3-
use super::{
4-
tar, ExerciseDesc, ExercisePackagingConfiguration, RunResult, TmcError, ValidationResult,
5-
};
3+
mod file_util;
4+
mod submission_packaging;
5+
mod tar_helper;
6+
7+
pub use submission_packaging::TmcParams;
8+
9+
use crate::{ExerciseDesc, ExercisePackagingConfiguration, RunResult, TmcError, ValidationResult};
610
use log::info;
711
use std::path::{Path, PathBuf};
812
use tmc_langs_csharp::CSharpPlugin;
913
use tmc_langs_framework::{
10-
io::{submission_processing, zip},
14+
domain::TmcProjectYml,
15+
io,
1116
plugin::{Language, LanguagePlugin},
1217
policy::NothingIsStudentFilePolicy,
1318
};
@@ -23,7 +28,7 @@ pub fn prepare_solutions<'a, I: IntoIterator<Item = &'a PathBuf>>(
2328
exercise_paths: I,
2429
dest_root: &Path,
2530
) -> Result<(), TmcError> {
26-
submission_processing::prepare_solutions(exercise_paths, dest_root)?;
31+
io::submission_processing::prepare_solutions(exercise_paths, dest_root)?;
2732
Ok(())
2833
}
2934

@@ -40,6 +45,28 @@ pub fn prepare_stubs<I: IntoIterator<Item = PathBuf>>(
4045
Ok(())
4146
}
4247

48+
/// Takes a submission zip and turns it into a tar suitable for processing
49+
/// by among other things resetting the test files
50+
pub fn prepare_submission(
51+
zip_path: &Path,
52+
target_path: &Path,
53+
toplevel_dir_name: Option<String>,
54+
tmc_params: TmcParams,
55+
clone_path: &Path,
56+
stub_zip_path: Option<&Path>,
57+
output_zip: bool,
58+
) -> Result<(), TmcError> {
59+
submission_packaging::prepare_submission(
60+
zip_path,
61+
target_path,
62+
toplevel_dir_name,
63+
tmc_params,
64+
clone_path,
65+
stub_zip_path,
66+
output_zip,
67+
)
68+
}
69+
4370
/// See `LanguagePlugin::check_code_style`.
4471
pub fn run_check_code_style(
4572
path: &Path,
@@ -84,7 +111,7 @@ pub fn extract_project_overwrite(
84111
compressed_project: &Path,
85112
target_location: &Path,
86113
) -> Result<(), TmcError> {
87-
zip::unzip(
114+
io::zip::unzip(
88115
NothingIsStudentFilePolicy {},
89116
compressed_project,
90117
target_location,
@@ -112,7 +139,7 @@ pub fn compress_tar_for_submitting(
112139
tmcrun: &Path,
113140
target_location: &Path,
114141
) -> Result<(), TmcError> {
115-
tar::create_tar_from_project(project_dir, tmc_langs, tmcrun, target_location)?;
142+
tar_helper::create_tar_from_project(project_dir, tmc_langs, tmcrun, target_location)?;
116143
Ok(())
117144
}
118145

0 commit comments

Comments
 (0)