Skip to content

Commit 0f7324c

Browse files
authored
Merge pull request #150 from rage/submission-format
Submission format
2 parents e086f45 + b5e2549 commit 0f7324c

Some content is hidden

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

49 files changed

+82
-42
lines changed

tmc-langs/src/error.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,8 @@ pub enum LangsError {
1414
TempDir(#[source] std::io::Error),
1515
#[error("Invalid parameter key/value: {0}")]
1616
InvalidParam(String, #[source] ParamError),
17-
#[error("Error compressing file at {0} with zstd")]
18-
Zstd(PathBuf, #[source] std::io::Error),
17+
#[error("Error compressing data with zstd")]
18+
Zstd(#[source] std::io::Error),
1919
#[error("Error retrieving file handle from tar builder")]
2020
TarIntoInner(#[source] std::io::Error),
2121
#[error("Error finishing tar")]

tmc-langs/src/submission_packaging.rs

Lines changed: 80 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use super::TmcProjectYml;
44
use crate::data::{OutputFormat, TmcParams};
55
use crate::error::LangsError;
66
use std::ffi::OsStr;
7-
use std::io::Write;
7+
use std::io::{Cursor, Write};
88
use std::path::Path;
99
use std::path::PathBuf;
1010
use tmc_langs_plugins::Plugin;
@@ -17,6 +17,8 @@ lazy_static::lazy_static! {
1717
}
1818

1919
/// Note: Used by tmc-server. Prepares a submission for further processing.
20+
/// The clone path is assumed to be a directory with the exercise name as the directory name,
21+
/// and the course name as its parent, ex. "anything/some_course/some_exercise"
2022
pub fn prepare_submission(
2123
zip_path: &Path,
2224
target_path: &Path,
@@ -243,10 +245,27 @@ pub fn prepare_submission(
243245

244246
// make archive
245247
log::debug!("creating submission archive");
246-
let prefix = toplevel_dir_name
247-
.as_ref()
248-
.map(Path::new)
249-
.unwrap_or_else(|| Path::new(""));
248+
249+
let exercise_name = clone_path.file_name();
250+
let course_name = clone_path.parent().and_then(Path::file_name);
251+
let prefix = match (toplevel_dir_name, course_name, exercise_name) {
252+
(Some(toplevel_dir_name), Some(course_name), Some(exercise_name)) => {
253+
Path::new(&toplevel_dir_name)
254+
.join(course_name)
255+
.join(exercise_name)
256+
}
257+
(None, Some(course_name), Some(exercise_name)) => {
258+
Path::new(course_name).join(exercise_name)
259+
}
260+
_ => {
261+
log::warn!(
262+
"was not able to find exercise and/or course name from clone path {}",
263+
clone_path.display()
264+
);
265+
PathBuf::from("")
266+
}
267+
};
268+
250269
let archive_file = file_util::create_file(target_path)?;
251270
match output_format {
252271
OutputFormat::Tar => {
@@ -287,9 +306,8 @@ pub fn prepare_submission(
287306
archive.finish()?;
288307
}
289308
OutputFormat::TarZstd => {
290-
// create temporary tar file
291-
let temp = tempfile::NamedTempFile::new().map_err(LangsError::TempFile)?;
292-
let mut archive = tar::Builder::new(temp);
309+
let buf = Cursor::new(vec![]);
310+
let mut archive = tar::Builder::new(buf);
293311
log::debug!(
294312
"appending \"{}\" at \"{}\"",
295313
dest.display(),
@@ -299,11 +317,9 @@ pub fn prepare_submission(
299317
.append_dir_all(prefix, &dest)
300318
.map_err(|e| LangsError::TarAppend(dest, e))?;
301319
archive.finish().map_err(LangsError::TarFinish)?;
302-
let tar = archive.into_inner().map_err(LangsError::TarIntoInner)?;
303-
// the existing file handle has been read to the end and is now empty, so we reopen it
304-
let reopened = file_util::open_file(tar.path())?;
305-
zstd::stream::copy_encode(reopened, archive_file, 0)
306-
.map_err(|e| LangsError::Zstd(tar.path().to_path_buf(), e))?;
320+
let mut tar = archive.into_inner().map_err(LangsError::TarIntoInner)?;
321+
tar.set_position(0); // reset the cursor
322+
zstd::stream::copy_encode(tar, archive_file, 0).map_err(LangsError::Zstd)?;
307323
}
308324
}
309325
Ok(())
@@ -365,13 +381,13 @@ mod test {
365381
use tempfile::TempDir;
366382
use walkdir::WalkDir;
367383

368-
const MAVEN_CLONE: &str = "tests/data/MavenExercise";
384+
const MAVEN_CLONE: &str = "tests/data/some_course/MavenExercise";
369385
const MAVEN_ZIP: &str = "tests/data/MavenExercise.zip";
370386

371-
const MAKE_CLONE: &str = "tests/data/MakeExercise";
387+
const MAKE_CLONE: &str = "tests/data/some_course/MakeExercise";
372388
const MAKE_ZIP: &str = "tests/data/MakeExercise.zip";
373389

374-
const PYTHON_CLONE: &str = "tests/data/PythonExercise";
390+
const PYTHON_CLONE: &str = "tests/data/some_course/PythonExercise";
375391
const PYTHON_ZIP: &str = "tests/data/PythonExercise.zip";
376392

377393
fn init() {
@@ -420,10 +436,16 @@ mod test {
420436
init();
421437
let (_temp, output) = generic_submission(MAVEN_CLONE, MAVEN_ZIP);
422438
// expected files
423-
assert!(output.join("src/main/java/SimpleStuff.java").exists());
424-
assert!(output.join("src/test/java/SimpleTest.java").exists());
425-
assert!(output.join("src/test/java/SimpleHiddenTest.java").exists());
426-
assert!(output.join("pom.xml").exists());
439+
assert!(output
440+
.join("some_course/MavenExercise/src/main/java/SimpleStuff.java")
441+
.exists());
442+
assert!(output
443+
.join("some_course/MavenExercise/src/test/java/SimpleTest.java")
444+
.exists());
445+
assert!(output
446+
.join("some_course/MavenExercise/src/test/java/SimpleHiddenTest.java")
447+
.exists());
448+
assert!(output.join("some_course/MavenExercise/pom.xml").exists());
427449
}
428450

429451
#[test]
@@ -432,8 +454,10 @@ mod test {
432454
let (_temp, output) = generic_submission(MAVEN_CLONE, MAVEN_ZIP);
433455

434456
// files that should not be included
435-
assert!(!output.join("__MACOSX").exists());
436-
assert!(!output.join("src/test/java/MadeUpTest.java").exists());
457+
assert!(!output.join("some_course/MavenExercise/__MACOSX").exists());
458+
assert!(!output
459+
.join("some_course/MavenExercise/src/test/java/MadeUpTest.java")
460+
.exists());
437461
}
438462

439463
#[test]
@@ -452,8 +476,10 @@ mod test {
452476
let contents = String::from_utf8(writer).unwrap();
453477
assert!(contents.contains("MODIFIED"));
454478
// the text should not be in the package
455-
let test_file =
456-
fs::read_to_string(dbg!(output.join("src/test/java/SimpleTest.java"))).unwrap();
479+
let test_file = fs::read_to_string(dbg!(
480+
output.join("some_course/MavenExercise/src/test/java/SimpleTest.java")
481+
))
482+
.unwrap();
457483
assert!(!test_file.contains("MODIFIED"));
458484
}
459485

@@ -462,7 +488,7 @@ mod test {
462488
init();
463489
let (_temp, output) = generic_submission(MAVEN_CLONE, MAVEN_ZIP);
464490

465-
let param_file = output.join(".tmcparams");
491+
let param_file = output.join("some_course/MavenExercise/.tmcparams");
466492
assert!(param_file.exists());
467493
let conts = fs::read_to_string(param_file).unwrap();
468494
log::debug!("tmcparams {}", conts);
@@ -500,9 +526,11 @@ mod test {
500526
log::debug!("{}", entry.unwrap().path().display());
501527
}
502528
assert!(output
503-
.join("toplevel/src/test/java/SimpleHiddenTest.java")
529+
.join("toplevel/some_course/MavenExercise/src/test/java/SimpleHiddenTest.java")
530+
.exists());
531+
assert!(output
532+
.join("toplevel/some_course/MavenExercise/pom.xml")
504533
.exists());
505-
assert!(output.join("toplevel/pom.xml").exists());
506534
}
507535

508536
#[test]
@@ -533,8 +561,10 @@ mod test {
533561
for entry in WalkDir::new(temp.path()) {
534562
log::debug!("{}", entry.unwrap().path().display());
535563
}
536-
assert!(output.join("src/test/java/SimpleHiddenTest.java").exists());
537-
assert!(output.join("pom.xml").exists());
564+
assert!(output
565+
.join("some_course/MavenExercise/src/test/java/SimpleHiddenTest.java")
566+
.exists());
567+
assert!(output.join("some_course/MavenExercise/pom.xml").exists());
538568
}
539569

540570
#[test]
@@ -560,7 +590,7 @@ mod test {
560590
let output = file_util::open_file(output).unwrap();
561591
let mut archive = zip::ZipArchive::new(output).unwrap();
562592
archive
563-
.by_name("src/test/java/SimpleHiddenTest.java")
593+
.by_name("some_course/MavenExercise/src/test/java/SimpleHiddenTest.java")
564594
.unwrap();
565595
}
566596

@@ -587,9 +617,11 @@ mod test {
587617
let output = file_util::open_file(output).unwrap();
588618
let mut archive = zip::ZipArchive::new(output).unwrap();
589619
archive
590-
.by_name("toplevel/src/test/java/SimpleHiddenTest.java")
620+
.by_name("toplevel/some_course/MavenExercise/src/test/java/SimpleHiddenTest.java")
621+
.unwrap();
622+
archive
623+
.by_name("toplevel/some_course/MavenExercise/pom.xml")
591624
.unwrap();
592-
archive.by_name("toplevel/pom.xml").unwrap();
593625
}
594626

595627
#[test]
@@ -622,10 +654,10 @@ mod test {
622654

623655
// visible tests included, hidden test isn't
624656
assert!(output_extracted
625-
.join("src/test/java/SimpleTest.java")
657+
.join("some_course/MavenExercise/src/test/java/SimpleTest.java")
626658
.exists());
627659
assert!(!output_extracted
628-
.join("src/test/java/SimpleHiddenTest.java")
660+
.join("some_course/MavenExercise/src/test/java/SimpleHiddenTest.java")
629661
.exists());
630662
}
631663

@@ -635,9 +667,11 @@ mod test {
635667
let (_temp, output) = generic_submission(MAKE_CLONE, MAKE_ZIP);
636668

637669
// expected files
638-
assert!(output.join("src/main.c").exists());
639-
assert!(output.join("test/test_source.c").exists());
640-
assert!(output.join("Makefile").exists());
670+
assert!(output.join("some_course/MakeExercise/src/main.c").exists());
671+
assert!(output
672+
.join("some_course/MakeExercise/test/test_source.c")
673+
.exists());
674+
assert!(output.join("some_course/MakeExercise/Makefile").exists());
641675
}
642676

643677
#[test]
@@ -646,9 +680,15 @@ mod test {
646680
let (_temp, output) = generic_submission(PYTHON_CLONE, PYTHON_ZIP);
647681

648682
// expected files
649-
assert!(output.join("src/__main__.py").exists());
650-
assert!(output.join("test/test_greeter.py").exists());
683+
assert!(output
684+
.join("some_course/PythonExercise/src/__main__.py")
685+
.exists());
686+
assert!(output
687+
.join("some_course/PythonExercise/test/test_greeter.py")
688+
.exists());
651689
// assert!(output.join("tmc/points.py").exists()); // not included?
652-
assert!(output.join("__init__.py").exists());
690+
assert!(output
691+
.join("some_course/PythonExercise/__init__.py")
692+
.exists());
653693
}
654694
}

0 commit comments

Comments
 (0)