소스 검색

Utilities: Add the 'files' argument to the unzip utility

serenitydev 3 년 전
부모
커밋
083b58fd89
2개의 변경된 파일34개의 추가작업 그리고 2개의 파일을 삭제
  1. 10 1
      Base/usr/share/man/man1/unzip.md
  2. 24 1
      Userland/Utilities/unzip.cpp

+ 10 - 1
Base/usr/share/man/man1/unzip.md

@@ -5,7 +5,7 @@ unzip - extract files from a ZIP archive
 ## Synopsis
 
 ```**sh
-$ unzip file.zip
+$ unzip file.zip [files...]
 ```
 
 ## Description
@@ -14,6 +14,8 @@ unzip will extract files from a zip archive to the current directory.
 
 The program is compatible with the PKZIP file format specification.
 
+The optional [files] argument can be used to only extract specific files within the archive (using wildcards) during the unzip process. A `_` can be used as a single-character wildcard, and  `*` can be used as a variable-length wildcard.
+
 ## Examples
 
 ```sh
@@ -23,3 +25,10 @@ Archive: archive.zip
  extracting: file1.txt
  extracting: file2.png
 ```
+
+```sh
+# Unzip select files from archive.zip, according to a filter
+$ unzip archive.zip "*.tx_"
+Archive: archive.unzip
+ extracting: file1.txt
+```

+ 24 - 1
Userland/Utilities/unzip.cpp

@@ -6,6 +6,7 @@
 
 #include <AK/Assertions.h>
 #include <AK/NumberFormat.h>
+#include <AK/StringUtils.h>
 #include <LibArchive/Zip.h>
 #include <LibCompress/Deflate.h>
 #include <LibCore/ArgsParser.h>
@@ -78,12 +79,14 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     int map_size_limit = 32 * MiB;
     bool quiet { false };
     String output_directory_path;
+    Vector<StringView> file_filters;
 
     Core::ArgsParser args_parser;
     args_parser.add_option(map_size_limit, "Maximum chunk size to map", "map-size-limit", 0, "size");
     args_parser.add_option(output_directory_path, "Directory to receive the archive content", "output-directory", 'd', "path");
     args_parser.add_option(quiet, "Be less verbose", "quiet", 'q');
     args_parser.add_positional_argument(path, "File to unzip", "path", Core::ArgsParser::Required::Yes);
+    args_parser.add_positional_argument(file_filters, "Files or filters in the archive to extract", "files", Core::ArgsParser::Required::No);
     args_parser.parse(arguments);
 
     String zip_file_path { path };
@@ -124,7 +127,27 @@ ErrorOr<int> serenity_main(Main::Arguments arguments)
     }
 
     auto success = zip_file->for_each_member([&](auto zip_member) {
-        return unpack_zip_member(zip_member, quiet) ? IterationDecision::Continue : IterationDecision::Break;
+        bool keep_file = false;
+
+        if (!file_filters.is_empty()) {
+            for (auto& filter : file_filters) {
+                // Convert underscore wildcards (usual unzip convention) to question marks (as used by StringUtils)
+                auto string_filter = filter.replace("_", "?", true);
+                if (zip_member.name.matches(string_filter, CaseSensitivity::CaseSensitive)) {
+                    keep_file = true;
+                    break;
+                }
+            }
+        } else {
+            keep_file = true;
+        }
+
+        if (keep_file) {
+            if (!unpack_zip_member(zip_member, quiet))
+                return IterationDecision::Break;
+        }
+
+        return IterationDecision::Continue;
     });
 
     return success ? 0 : 1;