Skip to content

Commit 8401d70

Browse files
committed
Implemented extraction for zip/tar/tar.zstd
1 parent 2ed47d8 commit 8401d70

File tree

11 files changed

+52
-21
lines changed

11 files changed

+52
-21
lines changed

bindings/tmc-langs-node/jest/tmc.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ test("extracts project", async () => {
147147

148148
const dir = await tempdir();
149149
expect(fs.existsSync([dir, "setup.py"].join("/"))).toBeFalsy();
150-
tmc.extractProject("jest/python-exercise.zip", dir);
150+
tmc.extractProject("jest/python-exercise.zip", dir, "zip");
151151
expect(fs.existsSync([dir, "setup.py"].join("/"))).toBeTruthy();
152152
});
153153

bindings/tmc-langs-node/src/lib.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,20 @@ fn compress_project(mut cx: FunctionContext) -> JsResult<JsValue> {
110110
}
111111

112112
fn extract_project(mut cx: FunctionContext) -> JsResult<JsValue> {
113-
parse_args!(cx, archive_path: PathBuf, output_path: PathBuf);
113+
parse_args!(
114+
cx,
115+
archive_path: PathBuf,
116+
output_path: PathBuf,
117+
compression: Compression
118+
);
114119

115120
let mut archive =
116121
file_util::open_file_lock(archive_path).map_err(|e| convert_err(&mut cx, e))?;
117122
let mut guard = archive.write().expect("failed to lock file");
118123
let mut data = vec![];
119124
guard.read_to_end(&mut data).expect("failed to read data");
120125

121-
let res = tmc_langs::extract_project(Cursor::new(data), &output_path, false);
126+
let res = tmc_langs::extract_project(Cursor::new(data), &output_path, compression, false);
122127
convert_res(&mut cx, res)
123128
}
124129

bindings/tmc-langs-node/ts/functions.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export function checkstyle(
1515
): types.StyleValidationResult | null;
1616
export function clean(exercisePath: string): void;
1717
export function compressProject(exercisePath: string, outputPath: string, compression: Compression, naive: boolean): void;
18-
export function extractProject(archivePath: string, outputPath: string): void;
18+
export function extractProject(archivePath: string, outputPath: string, compression: Compression): void;
1919
export function fastAvailablePoints(exercisePath: string): Array<string>;
2020
export function findExercises(exercisePath: string): Array<string>;
2121
export function getExercisePackagingConfiguration(

bindings/tmc-langs-node/ts/generated.d.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export interface ExercisePackagingConfiguration { student_file_paths: Array<stri
88

99
export interface LocalExercise { exercise_slug: string, exercise_path: string, }
1010

11-
export type Compression = "Tar" | "Zip" | "TarZstd";
11+
export type Compression = "tar" | "zip" | "zstd";
1212

1313
export interface RefreshData { new_cache_path: string, course_options: object, exercises: Array<RefreshExercise>, }
1414

bindings/tmc-langs-node/ts/tmc.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@ export class Tmc {
4242
return tmc.compressProject(exercisePath, outputPath, compression, naive);
4343
}
4444

45-
extractProject(archivePath: string, outputPath: string): void {
46-
return tmc.extractProject(archivePath, outputPath);
45+
extractProject(archivePath: string, outputPath: string, compression: Compression): void {
46+
return tmc.extractProject(archivePath, outputPath, compression);
4747
}
4848

4949
fastAvailablePoints(exercisePath: string): Array<string> {

tmc-client/src/tmc_client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -586,7 +586,7 @@ impl TmcClient {
586586

587587
let mut buf = vec![];
588588
api_v8::core::download_exercise_solution(self, exercise_id, &mut buf)?;
589-
tmc_langs_plugins::extract_project(Cursor::new(buf), target, false)?;
589+
tmc_langs_plugins::extract_project(Cursor::new(buf), target, Compression::Zip, false)?;
590590
Ok(())
591591
}
592592

tmc-langs-cli/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -247,7 +247,7 @@ fn run_app(matches: Opt) -> Result<()> {
247247
let mut data = vec![];
248248
guard.read_to_end(&mut data)?;
249249

250-
tmc_langs::extract_project(Cursor::new(data), &output_path, true)?;
250+
tmc_langs::extract_project(Cursor::new(data), &output_path, compression, true)?;
251251

252252
OutputKind::finished(format!(
253253
"extracted project from {} to {}",

tmc-langs-framework/src/archive.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,14 @@ pub enum Archive<T: Read + Seek> {
1818
}
1919

2020
impl<T: Read + Seek> Archive<T> {
21+
pub fn new(archive: T, compression: Compression) -> Result<Self, TmcError> {
22+
match compression {
23+
Compression::Tar => Ok(Self::tar(archive)),
24+
Compression::TarZstd => Self::tar_zstd(archive),
25+
Compression::Zip => Self::zip(archive),
26+
}
27+
}
28+
2129
pub fn tar(archive: T) -> Self {
2230
let archive = tar::Archive::new(archive);
2331
Self::Tar(archive)

tmc-langs-framework/src/plugin.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
},
88
error::TmcError,
99
policy::StudentFilePolicy,
10-
Archive, TmcProjectYml,
10+
Archive, Compression, TmcProjectYml,
1111
};
1212
pub use isolang::Language;
1313
use nom::{branch, bytes, character, combinator, error::VerboseError, multi, sequence, IResult};
@@ -99,22 +99,23 @@ pub trait LanguagePlugin {
9999
fn extract_project(
100100
compressed_project: impl std::io::Read + std::io::Seek,
101101
target_location: &Path,
102+
compression: Compression,
102103
clean: bool,
103104
) -> Result<(), TmcError> {
104105
log::debug!("Unzipping to {}", target_location.display());
105106

106-
let mut zip_archive = Archive::zip(compressed_project)?;
107+
let mut archive = Archive::new(compressed_project, compression)?;
107108

108109
// find the exercise root directory inside the archive
109-
let project_dir = Self::find_project_dir_in_archive(&mut zip_archive)?;
110+
let project_dir = Self::find_project_dir_in_archive(&mut archive)?;
110111
log::debug!("Project dir in zip: {}", project_dir.display());
111112

112113
// extract config file if any
113114
let tmc_project_yml_path = project_dir.join(".tmcproject.yml");
114115
let tmc_project_yml_path_s = tmc_project_yml_path
115116
.to_str()
116117
.ok_or_else(|| TmcError::ProjectDirInvalidUtf8(project_dir.clone()))?;
117-
if let Ok(mut file) = zip_archive.by_path(tmc_project_yml_path_s) {
118+
if let Ok(mut file) = archive.by_path(tmc_project_yml_path_s) {
118119
let target_path = target_location.join(".tmcproject.yml");
119120
file_util::read_to_file(&mut file, target_path)?;
120121
}
@@ -123,7 +124,7 @@ pub trait LanguagePlugin {
123124
// used to clean non-student files not in the zip later
124125
let mut files_from_zip = HashSet::new();
125126

126-
let mut iter = zip_archive.iter()?;
127+
let mut iter = archive.iter()?;
127128
loop {
128129
let next = iter.with_next::<(), _>(|mut file| {
129130
let file_path = file.path()?;
@@ -860,6 +861,7 @@ def f():
860861
MockPlugin::extract_project(
861862
std::io::Cursor::new(zip),
862863
&temp.path().join("extracted"),
864+
Compression::Zip,
863865
false,
864866
)
865867
.unwrap();
@@ -893,6 +895,7 @@ def f():
893895
MockPlugin::extract_project(
894896
std::io::Cursor::new(zip),
895897
&temp.path().join("extracted"),
898+
Compression::Zip,
896899
false,
897900
)
898901
.unwrap();
@@ -934,6 +937,7 @@ force_update:
934937
MockPlugin::extract_project(
935938
std::io::Cursor::new(zip),
936939
&temp.path().join("extracted"),
940+
Compression::Zip,
937941
false,
938942
)
939943
.unwrap();
@@ -970,6 +974,7 @@ force_update:
970974
MockPlugin::extract_project(
971975
std::io::Cursor::new(zip),
972976
&temp.path().join("extracted"),
977+
Compression::Zip,
973978
false,
974979
)
975980
.unwrap();
@@ -999,6 +1004,7 @@ force_update:
9991004
MockPlugin::extract_project(
10001005
std::io::Cursor::new(zip),
10011006
&temp.path().join("extracted"),
1007+
Compression::Zip,
10021008
true,
10031009
)
10041010
.unwrap();

tmc-langs-plugins/src/lib.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,11 @@ pub use tmc_langs_r::RPlugin;
2727
pub fn extract_project(
2828
compressed_project: impl std::io::Read + std::io::Seek,
2929
target_location: &Path,
30+
compression: Compression,
3031
clean: bool,
3132
) -> Result<(), PluginError> {
3233
if let Ok(plugin) = get_language_plugin(target_location) {
33-
plugin.extract_project(compressed_project, target_location, clean)?;
34+
plugin.extract_project(compressed_project, target_location, compression, clean)?;
3435
} else {
3536
log::debug!(
3637
"no matching language plugin found for {}, overwriting",
@@ -98,7 +99,7 @@ pub fn compress_project(path: &Path, compression: Compression) -> Result<Vec<u8>
9899
#[impl_enum::with_methods(
99100
pub fn clean(&self, path: &Path) -> Result<(), TmcError> {}
100101
pub fn get_exercise_packaging_configuration(config: TmcProjectYml) -> Result<ExercisePackagingConfiguration, TmcError> {}
101-
pub fn extract_project(compressed_project: impl std::io::Read + std::io::Seek, target_location: &Path, clean: bool) -> Result<(), TmcError> {}
102+
pub fn extract_project(compressed_project: impl std::io::Read + std::io::Seek, target_location: &Path, compression: Compression, clean: bool) -> Result<(), TmcError> {}
102103
pub fn extract_student_files(compressed_project: impl std::io::Read + std::io::Seek, target_location: &Path) -> Result<(), TmcError> {}
103104
pub fn scan_exercise(&self, path: &Path, exercise_name: String) -> Result<ExerciseDesc, TmcError> {}
104105
pub fn run_tests(&self, path: &Path) -> Result<RunResult, TmcError> {}

tmc-langs/src/lib.rs

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -368,12 +368,22 @@ pub fn download_or_update_course_exercises(
368368
DownloadTargetKind::Template => {
369369
let mut buf = vec![];
370370
client.download_exercise(download_target.target.id, &mut buf)?;
371-
extract_project(Cursor::new(buf), &download_target.target.path, false)?;
371+
extract_project(
372+
Cursor::new(buf),
373+
&download_target.target.path,
374+
Compression::Zip,
375+
false,
376+
)?;
372377
}
373378
DownloadTargetKind::Submission { submission_id } => {
374379
let mut buf = vec![];
375380
client.download_exercise(download_target.target.id, &mut buf)?;
376-
extract_project(Cursor::new(buf), &download_target.target.path, false)?;
381+
extract_project(
382+
Cursor::new(buf),
383+
&download_target.target.path,
384+
Compression::Zip,
385+
false,
386+
)?;
377387

378388
let plugin = get_language_plugin(&download_target.target.path)?;
379389
let tmc_project_yml =
@@ -639,7 +649,7 @@ pub fn update_exercises(
639649
for exercise in &exercises_to_update {
640650
let mut buf = vec![];
641651
client.download_exercise(exercise.id, &mut buf)?;
642-
extract_project(Cursor::new(buf), &exercise.path, false)?;
652+
extract_project(Cursor::new(buf), &exercise.path, Compression::Zip, false)?;
643653
}
644654
for (course_name, exercise_names) in course_data {
645655
let mut exercises = BTreeMap::new();
@@ -779,14 +789,15 @@ pub fn reset(client: &TmcClient, exercise_id: u32, exercise_path: &Path) -> Resu
779789
}
780790
let mut buf = vec![];
781791
client.download_exercise(exercise_id, &mut buf)?;
782-
extract_project(Cursor::new(buf), exercise_path, false)?;
792+
extract_project(Cursor::new(buf), exercise_path, Compression::Zip, false)?;
783793
Ok(())
784794
}
785795

786796
/// Extracts the compressed project to the target location.
787797
pub fn extract_project(
788798
compressed_project: impl std::io::Read + std::io::Seek,
789799
target_location: &Path,
800+
compression: Compression,
790801
clean: bool,
791802
) -> Result<(), LangsError> {
792803
log::debug!(
@@ -795,7 +806,7 @@ pub fn extract_project(
795806
);
796807

797808
if let Ok(plugin) = tmc_langs_plugins::get_language_plugin(target_location) {
798-
plugin.extract_project(compressed_project, target_location, clean)?;
809+
plugin.extract_project(compressed_project, target_location, compression, clean)?;
799810
} else {
800811
log::debug!(
801812
"no matching language plugin found for {}, overwriting",

0 commit comments

Comments
 (0)