diff --git a/src/commands/release.rs b/src/commands/release.rs index 56720e3..5d6ad45 100644 --- a/src/commands/release.rs +++ b/src/commands/release.rs @@ -214,10 +214,6 @@ fn add_directory_to_zip( ))); } - if count_files(src_dir, project_dir, ignore)? == 0 { - return Ok(()); - } - let options = SimpleFileOptions::default(); let mut buffer = Vec::new(); @@ -243,9 +239,7 @@ fn add_directory_to_zip( f.read_to_end(&mut buffer)?; zip.write_all(&buffer)?; buffer.clear(); - } else if !relative_path.as_os_str().is_empty() - && count_files(path, project_dir, ignore)? > 0 - { + } else if !relative_path.as_os_str().is_empty() { zip.add_directory(&path_str, options)?; } } @@ -329,7 +323,7 @@ fn add_with_package( if !is_dir { continue; } - // 当前目录未命中且无被包含的子孙时,无需写出目录条目。 + // 当前目录未命中,不写出目录条目;WalkDir 仍会继续遍历子孙。 continue; } @@ -343,9 +337,7 @@ fn add_with_package( .map_err(|e| file::io_error("读取打包文件", path, e))?; zip.write_all(&buffer)?; buffer.clear(); - } else if !relative_path.as_os_str().is_empty() - && dir_has_included_files(path, project_dir, package, ignore)? - { + } else if !relative_path.as_os_str().is_empty() { zip.add_directory(&path_str, options)?; } } @@ -353,57 +345,6 @@ fn add_with_package( Ok(()) } -fn dir_has_included_files( - dir: &Path, - project_dir: &Path, - package: &EmodPackage, - ignore: &EmodIgnore, -) -> Result { - for entry in walkdir::WalkDir::new(dir) { - let entry = entry?; - let path = entry.path(); - if !path.is_file() { - continue; - } - if path.display().to_string().ends_with(".gitkeep") { - continue; - } - let relative_path = path - .strip_prefix(project_dir) - .map_err(|e| crate::error::CliError::InvalidData(e.to_string()))?; - if ignore.is_ignored(relative_path, false) { - continue; - } - if !package.matches(relative_path, false) { - continue; - } - return Ok(true); - } - Ok(false) -} - -fn count_files(dir: &Path, project_dir: &Path, ignore: &EmodIgnore) -> Result { - let mut count = 0; - for entry in walkdir::WalkDir::new(dir) { - let entry = entry?; - let path = entry.path(); - if !path.is_file() { - continue; - } - - let relative_path = path - .strip_prefix(project_dir) - .map_err(|e| crate::error::CliError::InvalidData(e.to_string()))?; - - if !path.display().to_string().ends_with(".gitkeep") - && !ignore.is_ignored(relative_path, false) - { - count += 1; - } - } - Ok(count) -} - struct EmodIgnore { rules: Vec, } @@ -803,6 +744,68 @@ mod tests { fs::remove_dir_all(project_dir).unwrap(); } + #[test] + fn package_project_keeps_empty_subdirectory() { + let project_dir = temp_project_dir(); + let release_info = release_info(); + + fs::create_dir_all(project_dir.join("behavior_pack_abcdefgh/empty_dir")).unwrap(); + fs::create_dir_all(project_dir.join("resource_pack_ijklmnop")).unwrap(); + + let pack_dirs = pack_dirs(&project_dir, &release_info); + let zip_path = + package_project_with_artifacts_env_unset(&project_dir, &pack_dirs, "1.0.0").unwrap(); + let entries = zip_entries(&zip_path); + + assert!(entries.contains(&"behavior_pack_abcdefgh/empty_dir/".to_string())); + + fs::remove_dir_all(project_dir).unwrap(); + } + + #[test] + fn package_project_keeps_dir_with_only_gitkeep() { + let project_dir = temp_project_dir(); + let release_info = release_info(); + + write_file( + &project_dir.join("behavior_pack_abcdefgh/only_gitkeep/.gitkeep"), + "", + ); + fs::create_dir_all(project_dir.join("resource_pack_ijklmnop")).unwrap(); + + let pack_dirs = pack_dirs(&project_dir, &release_info); + let zip_path = + package_project_with_artifacts_env_unset(&project_dir, &pack_dirs, "1.0.0").unwrap(); + let entries = zip_entries(&zip_path); + + assert!(entries.contains(&"behavior_pack_abcdefgh/only_gitkeep/".to_string())); + assert!(!entries.contains(&"behavior_pack_abcdefgh/only_gitkeep/.gitkeep".to_string())); + + fs::remove_dir_all(project_dir).unwrap(); + } + + #[test] + fn emod_package_keeps_matched_empty_subdirectory() { + let project_dir = temp_project_dir(); + let release_info = release_info(); + + write_file( + &project_dir.join(".emod-package"), + "behavior_pack_abcdefgh/empty_dir/\n", + ); + fs::create_dir_all(project_dir.join("behavior_pack_abcdefgh/empty_dir")).unwrap(); + fs::create_dir_all(project_dir.join("resource_pack_ijklmnop")).unwrap(); + + let pack_dirs = pack_dirs(&project_dir, &release_info); + let zip_path = + package_project_with_artifacts_env_unset(&project_dir, &pack_dirs, "1.0.0").unwrap(); + let entries = zip_entries(&zip_path); + + assert!(entries.contains(&"behavior_pack_abcdefgh/empty_dir/".to_string())); + + fs::remove_dir_all(project_dir).unwrap(); + } + #[test] fn package_project_includes_world_pack_json_in_default_mode() { let project_dir = temp_project_dir();