History

'pack' with its own sub-commands (#289)

Sebastian Thiel committed 4 years ago

Commit fb64af41 parent 8677f7e38 files · +754 −721Browse files

Unified · Split

38 files
  1. src/plumbing/main.rs +196 −192
  2. src/plumbing/options.rs +207 −187
  3. tests/journey/gix.sh +339 −332
  4. tests/snapshots/plumbing/pack-receive/pack-receive-no-networking-in-small-failure +0 −10
  5. tests/snapshots/plumbing/pack/explode/broken-delete-pack-to-sink-failure +0 −0
  6. tests/snapshots/plumbing/pack/explode/broken-delete-pack-to-sink-skip-checks-success +0 −0
  7. tests/snapshots/plumbing/pack/explode/broken-with-objects-dir-skip-checks-success-tree-miniz-oxide +0 −0
  8. tests/snapshots/plumbing/pack/explode/broken-with-objects-dir-skip-checks-success-tree-zlib-ng +0 −0
  9. tests/snapshots/plumbing/pack/explode/missing-objects-dir-fail +0 −0
  10. tests/snapshots/plumbing/pack/explode/to-sink-delete-pack-success +0 −0
  11. tests/snapshots/plumbing/pack/explode/to-sink-success +0 −0
  12. tests/snapshots/plumbing/pack/explode/with-objects-dir-success +0 −0
  13. tests/snapshots/plumbing/pack/explode/with-objects-dir-success-tree +0 −0
  14. tests/snapshots/plumbing/pack/index-from-data/no-output-dir-as-json-success +0 −0
  15. tests/snapshots/plumbing/pack/index-from-data/no-output-dir-success +0 −0
  16. tests/snapshots/plumbing/pack/index-from-data/output-dir-content +0 −0
  17. tests/snapshots/plumbing/pack/index-from-data/output-dir-restore-as-json-success +0 −0
  18. tests/snapshots/plumbing/pack/index-from-data/output-dir-restore-success +0 −0
  19. tests/snapshots/plumbing/pack/index-from-data/output-dir-success +0 −0
  20. tests/snapshots/plumbing/pack/receive/file-v-any-no-output +0 −0
  21. tests/snapshots/plumbing/pack/receive/file-v-any-no-output-json +0 −0
  22. tests/snapshots/plumbing/pack/receive/file-v-any-no-output-non-existing-single-ref +0 −0
  23. tests/snapshots/plumbing/pack/receive/file-v-any-no-output-single-ref +0 −0
  24. tests/snapshots/plumbing/pack/receive/file-v-any-no-output-wanted-ref-p1 +0 −0
  25. tests/snapshots/plumbing/pack/receive/file-v-any-with-output +0 −0
  26. tests/snapshots/plumbing/pack/receive/ls-in-output-dir +0 −0
  27. tests/snapshots/plumbing/pack/receive/pack receive-no-networking-in-small-failure +6 −0
  28. tests/snapshots/plumbing/pack/receive/repo-refs/HEAD +0 −0
  29. tests/snapshots/plumbing/pack/receive/repo-refs/refs/heads/dev +0 −0
  30. tests/snapshots/plumbing/pack/receive/repo-refs/refs/heads/main +0 −0
  31. tests/snapshots/plumbing/pack/receive/repo-refs/refs/tags/annotated +0 −0
  32. tests/snapshots/plumbing/pack/receive/repo-refs/refs/tags/unannotated +0 −0
  33. tests/snapshots/plumbing/pack/verify/index-failure +0 −0
  34. tests/snapshots/plumbing/pack/verify/index-success +0 −0
  35. tests/snapshots/plumbing/pack/verify/index-with-statistics-json-success +0 −0
  36. tests/snapshots/plumbing/pack/verify/index-with-statistics-success +0 −0
  37. tests/snapshots/plumbing/pack/verify/success +0 −0
  38. tests/snapshots/plumbing/remote/ref-list/remote ref-list-no-networking-in-small-failure +6 −0
src/plumbing/main.rs+196−192
@@ -15,7 +15,7 @@ use gitoxide_core::pack::verify; · 14 unmodified lines
15#[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]15#[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]
16use crate::plumbing::options::remote;16use crate::plumbing::options::remote;
17use crate::{17use crate::{
18 plumbing::options::{commitgraph, Args, Subcommands},18 plumbing::options::{commitgraph, pack, Args, Subcommands},
19 shared::pretty::prepare_and_run,19 shared::pretty::prepare_and_run,
20};20};
21 21
@@ -72,111 +72,215 @@ pub fn main() -> Result<()> { · 50 unmodified lines
72 })?;72 })?;
73 73
74 match cmd {74 match cmd {
75 Subcommands::PackCreate {75 Subcommands::Pack(subcommands) => match subcommands {
76 repository,76 pack::Subcommands::Create {
77 expansion,77 repository,
78 thin,78 expansion,
79 statistics,79 thin,
80 nondeterministic_count,80 statistics,
81 tips,81 nondeterministic_count,
82 pack_cache_size_mb,82 tips,
83 object_cache_size_mb,83 pack_cache_size_mb,
84 output_directory,84 object_cache_size_mb,
85 } => {85 output_directory,
86 let has_tips = !tips.is_empty();86 } => {
87 prepare_and_run(87 let has_tips = !tips.is_empty();
88 "pack-create",88 prepare_and_run(
89 verbose,89 "pack-create",
90 progress,90 verbose,
91 progress_keep_open,91 progress,
92 core::pack::create::PROGRESS_RANGE,92 progress_keep_open,
93 move |progress, out, _err| {93 core::pack::create::PROGRESS_RANGE,
94 let input = if has_tips {94 move |progress, out, _err| {
95 None95 let input = if has_tips {
96 } else {96 None
97 if atty::is(atty::Stream::Stdin) {
98 anyhow::bail!(
99 "Refusing to read from standard input as no path is given, but it's a terminal."
100 )
101 }
102 Some(BufReader::new(stdin()))
103 };
104 let repository = repository.unwrap_or_else(|| PathBuf::from("."));
105 let context = core::pack::create::Context {
106 thread_limit,
107 thin,
108 nondeterministic_count,
109 pack_cache_size_in_bytes: pack_cache_size_mb.unwrap_or(0) * 1_000_000,
110 object_cache_size_in_bytes: object_cache_size_mb.unwrap_or(0) * 1_000_000,
111 statistics: if statistics { Some(format) } else { None },
112 out,
113 expansion: expansion.unwrap_or(if has_tips {
114 core::pack::create::ObjectExpansion::TreeTraversal
115 } else {97 } else {
116 core::pack::create::ObjectExpansion::None98 if atty::is(atty::Stream::Stdin) {
117 }),99 anyhow::bail!(
118 };100 "Refusing to read from standard input as no path is given, but it's a terminal."
119 core::pack::create(repository, tips, input, output_directory, progress, context)101 )
120 },102 }
121 )103 Some(BufReader::new(stdin()))
122 }104 };
123 #[cfg(feature = "gitoxide-core-async-client")]105 let repository = repository.unwrap_or_else(|| PathBuf::from("."));
124 Subcommands::PackReceive {106 let context = core::pack::create::Context {
125 protocol,107 thread_limit,
126 url,108 thin,
127 directory,109 nondeterministic_count,
128 refs,110 pack_cache_size_in_bytes: pack_cache_size_mb.unwrap_or(0) * 1_000_000,
129 refs_directory,111 object_cache_size_in_bytes: object_cache_size_mb.unwrap_or(0) * 1_000_000,
130 } => {112 statistics: if statistics { Some(format) } else { None },
131 let (_handle, progress) = async_util::prepare(verbose, "pack-receive", core::pack::receive::PROGRESS_RANGE);113 out,
132 let fut = core::pack::receive(114 expansion: expansion.unwrap_or(if has_tips {
115 core::pack::create::ObjectExpansion::TreeTraversal
116 } else {
117 core::pack::create::ObjectExpansion::None
118 }),
119 };
120 core::pack::create(repository, tips, input, output_directory, progress, context)
121 },
122 )
123 }
124 #[cfg(feature = "gitoxide-core-async-client")]
125 pack::Subcommands::Receive {
133 protocol,126 protocol,
134 &url,127 url,
135 directory,128 directory,
129 refs,
136 refs_directory,130 refs_directory,
137 refs.into_iter().map(|s| s.into()).collect(),131 } => {
138 git_features::progress::DoOrDiscard::from(progress),132 let (_handle, progress) =
139 core::pack::receive::Context {133 async_util::prepare(verbose, "pack-receive", core::pack::receive::PROGRESS_RANGE);
140 thread_limit,134 let fut = core::pack::receive(
141 format,
142 out: std::io::stdout(),
143 should_interrupt,
144 },
145 );
146 return futures_lite::future::block_on(fut);
147 }
148 #[cfg(feature = "gitoxide-core-blocking-client")]
149 Subcommands::PackReceive {
150 protocol,
151 url,
152 directory,
153 refs,
154 refs_directory,
155 } => prepare_and_run(
156 "pack-receive",
157 verbose,
158 progress,
159 progress_keep_open,
160 core::pack::receive::PROGRESS_RANGE,
161 move |progress, out, _err| {
162 core::pack::receive(
163 protocol,135 protocol,
164 &url,136 &url,
165 directory,137 directory,
166 refs_directory,138 refs_directory,
167 refs.into_iter().map(|r| r.into()).collect(),139 refs.into_iter().map(|s| s.into()).collect(),
168 git_features::progress::DoOrDiscard::from(progress),140 git_features::progress::DoOrDiscard::from(progress),
169 core::pack::receive::Context {141 core::pack::receive::Context {
170 thread_limit,142 thread_limit,
171 format,143 format,
144 out: std::io::stdout(),
172 should_interrupt,145 should_interrupt,
173 out,
174 },146 },
175 )147 );
176 },148 return futures_lite::future::block_on(fut);
177 ),149 }
178 #[cfg(feature = "gitoxide-core-async-client")]150 #[cfg(feature = "gitoxide-core-blocking-client")]
151 pack::Subcommands::Receive {
152 protocol,
153 url,
154 directory,
155 refs,
156 refs_directory,
157 } => prepare_and_run(
158 "pack-receive",
159 verbose,
160 progress,
161 progress_keep_open,
162 core::pack::receive::PROGRESS_RANGE,
163 move |progress, out, _err| {
164 core::pack::receive(
165 protocol,
166 &url,
167 directory,
168 refs_directory,
169 refs.into_iter().map(|r| r.into()).collect(),
170 git_features::progress::DoOrDiscard::from(progress),
171 core::pack::receive::Context {
172 thread_limit,
173 format,
174 should_interrupt,
175 out,
176 },
177 )
178 },
179 ),
180 pack::Subcommands::IndexFromData {
181 iteration_mode,
182 pack_path,
183 directory,
184 } => prepare_and_run(
185 "pack-index-from-data",
186 verbose,
187 progress,
188 progress_keep_open,
189 core::pack::index::PROGRESS_RANGE,
190 move |progress, out, _err| {
191 use gitoxide_core::pack::index::PathOrRead;
192 let input = if let Some(path) = pack_path {
193 PathOrRead::Path(path)
194 } else {
195 if atty::is(atty::Stream::Stdin) {
196 anyhow::bail!(
197 "Refusing to read from standard input as no path is given, but it's a terminal."
198 )
199 }
200 PathOrRead::Read(Box::new(std::io::stdin()))
201 };
202 core::pack::index::from_pack(
203 input,
204 directory,
205 progress,
206 core::pack::index::Context {
207 thread_limit,
208 iteration_mode,
209 format,
210 out,
211 should_interrupt: &git_repository::interrupt::IS_INTERRUPTED,
212 },
213 )
214 },
215 ),
216 pack::Subcommands::Explode {
217 check,
218 sink_compress,
219 delete_pack,
220 pack_path,
221 object_path,
222 verify,
223 } => prepare_and_run(
224 "pack-explode",
225 verbose,
226 progress,
227 progress_keep_open,
228 None,
229 move |progress, _out, _err| {
230 core::pack::explode::pack_or_pack_index(
231 pack_path,
232 object_path,
233 check,
234 progress,
235 core::pack::explode::Context {
236 thread_limit,
237 delete_pack,
238 sink_compress,
239 verify,
240 should_interrupt,
241 },
242 )
243 },
244 ),
245 pack::Subcommands::Verify {
246 path,
247 algorithm,
248 decode,
249 re_encode,
250 statistics,
251 } => prepare_and_run(
252 "pack-verify",
253 verbose,
254 progress,
255 progress_keep_open,
256 verify::PROGRESS_RANGE,
257 move |progress, out, err| {
258 let mode = match (decode, re_encode) {
259 (true, false) => verify::Mode::HashCrc32Decode,
260 (true, true) | (false, true) => verify::Mode::HashCrc32DecodeEncode,
261 (false, false) => verify::Mode::HashCrc32,
262 };
263 let output_statistics = if statistics { Some(format) } else { None };
264 verify::pack_or_pack_index(
265 path,
266 progress,
267 verify::Context {
268 output_statistics,
269 out,
270 err,
271 thread_limit,
272 mode,
273 algorithm,
274 should_interrupt: &should_interrupt,
275 },
276 )
277 },
278 )
279 .map(|_| ()),
280 },
281 #[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]
179 Subcommands::Remote(subcommands) => match subcommands {282 Subcommands::Remote(subcommands) => match subcommands {
283 #[cfg(feature = "gitoxide-core-async-client")]
180 remote::Subcommands::RefList { protocol, url } => {284 remote::Subcommands::RefList { protocol, url } => {
181 let (_handle, progress) =285 let (_handle, progress) =
182 async_util::prepare(verbose, "remote-ref-list", Some(core::remote::refs::PROGRESS_RANGE));286 async_util::prepare(verbose, "remote-ref-list", Some(core::remote::refs::PROGRESS_RANGE));
@@ -192,9 +296,7 @@ pub fn main() -> Result<()> { · 9 unmodified lines
192 );296 );
193 return futures_lite::future::block_on(fut);297 return futures_lite::future::block_on(fut);
194 }298 }
195 },299 #[cfg(feature = "gitoxide-core-blocking-client")]
196 #[cfg(feature = "gitoxide-core-blocking-client")]
197 Subcommands::Remote(subcommands) => match subcommands {
198 remote::Subcommands::RefList { protocol, url } => prepare_and_run(300 remote::Subcommands::RefList { protocol, url } => prepare_and_run(
199 "remote-ref-list",301 "remote-ref-list",
200 verbose,302 verbose,
@@ -215,104 +317,6 @@ pub fn main() -> Result<()> { · 14 unmodified lines
215 },317 },
216 ),318 ),
217 },319 },
218 Subcommands::PackIndexFromData {
219 iteration_mode,
220 pack_path,
221 directory,
222 } => prepare_and_run(
223 "pack-index-from-data",
224 verbose,
225 progress,
226 progress_keep_open,
227 core::pack::index::PROGRESS_RANGE,
228 move |progress, out, _err| {
229 use gitoxide_core::pack::index::PathOrRead;
230 let input = if let Some(path) = pack_path {
231 PathOrRead::Path(path)
232 } else {
233 if atty::is(atty::Stream::Stdin) {
234 anyhow::bail!("Refusing to read from standard input as no path is given, but it's a terminal.")
235 }
236 PathOrRead::Read(Box::new(std::io::stdin()))
237 };
238 core::pack::index::from_pack(
239 input,
240 directory,
241 progress,
242 core::pack::index::Context {
243 thread_limit,
244 iteration_mode,
245 format,
246 out,
247 should_interrupt: &git_repository::interrupt::IS_INTERRUPTED,
248 },
249 )
250 },
251 ),
252 Subcommands::PackExplode {
253 check,
254 sink_compress,
255 delete_pack,
256 pack_path,
257 object_path,
258 verify,
259 } => prepare_and_run(
260 "pack-explode",
261 verbose,
262 progress,
263 progress_keep_open,
264 None,
265 move |progress, _out, _err| {
266 core::pack::explode::pack_or_pack_index(
267 pack_path,
268 object_path,
269 check,
270 progress,
271 core::pack::explode::Context {
272 thread_limit,
273 delete_pack,
274 sink_compress,
275 verify,
276 should_interrupt,
277 },
278 )
279 },
280 ),
281 Subcommands::PackVerify {
282 path,
283 algorithm,
284 decode,
285 re_encode,
286 statistics,
287 } => prepare_and_run(
288 "pack-verify",
289 verbose,
290 progress,
291 progress_keep_open,
292 verify::PROGRESS_RANGE,
293 move |progress, out, err| {
294 let mode = match (decode, re_encode) {
295 (true, false) => verify::Mode::HashCrc32Decode,
296 (true, true) | (false, true) => verify::Mode::HashCrc32DecodeEncode,
297 (false, false) => verify::Mode::HashCrc32,
298 };
299 let output_statistics = if statistics { Some(format) } else { None };
300 verify::pack_or_pack_index(
301 path,
302 progress,
303 verify::Context {
304 output_statistics,
305 out,
306 err,
307 thread_limit,
308 mode,
309 algorithm,
310 should_interrupt: &should_interrupt,
311 },
312 )
313 },
314 )
315 .map(|_| ()),
316 Subcommands::Commitgraph(subcommands) => match subcommands {320 Subcommands::Commitgraph(subcommands) => match subcommands {
317 commitgraph::Subcommands::Verify { path, statistics } => prepare_and_run(321 commitgraph::Subcommands::Verify { path, statistics } => prepare_and_run(
318 "commit-graph-verify",322 "commit-graph-verify",
src/plumbing/options.rs+207−187
@@ -1,5 +1,3 @@
1use std::{ffi::OsString, path::PathBuf};
2
3use clap::AppSettings;1use clap::AppSettings;
4use gitoxide_core as core;2use gitoxide_core as core;
5 3
@@ -44,203 +42,225 @@ pub struct Args { · 38 unmodified lines
44 42
45#[derive(Debug, clap::Parser)]43#[derive(Debug, clap::Parser)]
46pub enum Subcommands {44pub enum Subcommands {
47 #[clap(setting = AppSettings::DisableVersionFlag)]45 /// Subcommands for interacting with packs and their indices.
48 PackCreate {46 #[clap(subcommand)]
49 #[clap(long, short = 'r')]47 Pack(pack::Subcommands),
50 /// the directory containing the '.git' repository from which objects should be read.48 /// Subcommands for interacting with git remotes, e.g. git repositories hosted on servers.
51 repository: Option<PathBuf>,49 #[clap(subcommand)]
52 50 #[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]
53 #[clap(long, short = 'e', possible_values(core::pack::create::ObjectExpansion::variants()))]51 Remote(remote::Subcommands),
54 /// the way objects are expanded. They differ in costs.52 /// Subcommands for interacting with commitgraphs
55 ///53 #[clap(subcommand)]
56 /// Possible values are "none" and "tree-traversal". Default is "none".54 Commitgraph(commitgraph::Subcommands),
57 expansion: Option<core::pack::create::ObjectExpansion>,55}
58 56
59 #[clap(long)]57///
60 /// if set, the counting phase may be accelerated using multithreading.58pub mod pack {
61 ///59 use clap::AppSettings;
62 /// On the flip side, however, one will loose deterministic counting results which affects the60 use gitoxide_core as core;
63 /// way the resulting pack is structured.61 use std::ffi::OsString;
64 nondeterministic_count: bool,62 use std::path::PathBuf;
65
66 #[clap(long, short = 's')]
67 /// If set statistical information will be presented to inform about pack creation details.
68 /// It's a form of instrumentation for developers to help improve pack generation.
69 statistics: bool,
70
71 #[clap(long)]
72 /// The size in megabytes for a cache to speed up pack access for packs with long delta chains.
73 /// It is shared among all threads, so 4 threads would use their own cache 1/4th of the size.
74 ///
75 /// If unset, no cache will be used.
76 pack_cache_size_mb: Option<usize>,
77 63
78 #[clap(long)]64 #[derive(Debug, clap::Parser)]
79 /// The size in megabytes for a cache to speed up accessing entire objects, bypassing object database access when hit.65 pub enum Subcommands {
80 /// It is shared among all threads, so 4 threads would use their own cache 1/4th of the size.66 /// Create a new pack with a set of objects.
81 ///67 #[clap(setting = AppSettings::DisableVersionFlag)]
82 /// This cache type is currently only effective when using the 'diff-tree' object expansion.68 Create {
83 ///69 #[clap(long, short = 'r')]
84 /// If unset, no cache will be used.70 /// the directory containing the '.git' repository from which objects should be read.
85 object_cache_size_mb: Option<usize>,71 repository: Option<PathBuf>,
86 72
87 #[clap(long)]73 #[clap(long, short = 'e', possible_values(core::pack::create::ObjectExpansion::variants()))]
88 /// if set, delta-objects whose base object wouldn't be in the pack will not be recompressed as base object, but instead74 /// the way objects are expanded. They differ in costs.
89 /// refer to its base object using its object id.75 ///
90 ///76 /// Possible values are "none" and "tree-traversal". Default is "none".
91 /// This allows for smaller packs but requires the receiver of the pack to resolve these ids before storing the pack.77 expansion: Option<core::pack::create::ObjectExpansion>,
92 /// Packs produced with this option enabled are only valid in transit, but not at rest.
93 thin: bool,
94 78
95 /// The directory into which to write the pack file.79 #[clap(long)]
96 #[clap(long, short = 'o')]80 /// if set, the counting phase may be accelerated using multithreading.
97 output_directory: Option<PathBuf>,81 ///
82 /// On the flip side, however, one will loose deterministic counting results which affects the
83 /// way the resulting pack is structured.
84 nondeterministic_count: bool,
98 85
99 /// The tips from which to start the commit graph iteration, either as fully qualified commit hashes86 #[clap(long, short = 's')]
100 /// or as branch names.87 /// If set statistical information will be presented to inform about pack creation details.
101 ///88 /// It's a form of instrumentation for developers to help improve pack generation.
102 /// If empty, we expect to read objects on stdin and default to 'none' as expansion mode.89 statistics: bool,
103 /// Otherwise the expansion mode is 'tree-traversal' by default.
104 tips: Vec<OsString>,
105 },
106 #[clap(setting = AppSettings::DisableVersionFlag)]
107 #[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]
108 PackReceive {
109 /// The protocol version to use. Valid values are 1 and 2
110 #[clap(long, short = 'p')]
111 protocol: Option<core::net::Protocol>,
112 90
113 /// the directory into which to write references. Existing files will be overwritten.91 #[clap(long)]
114 ///92 /// The size in megabytes for a cache to speed up pack access for packs with long delta chains.
115 /// Note that the directory will be created if needed.93 /// It is shared among all threads, so 4 threads would use their own cache 1/4th of the size.
116 #[clap(long, short = 'd')]94 ///
117 refs_directory: Option<PathBuf>,95 /// If unset, no cache will be used.
96 pack_cache_size_mb: Option<usize>,
118 97
119 /// The URLs or path from which to receive the pack.98 #[clap(long)]
120 ///99 /// The size in megabytes for a cache to speed up accessing entire objects, bypassing object database access when hit.
121 /// See here for a list of supported URLs: <https://www.git-scm.com/docs/git-clone#_git_urls>100 /// It is shared among all threads, so 4 threads would use their own cache 1/4th of the size.
122 url: String,101 ///
102 /// This cache type is currently only effective when using the 'diff-tree' object expansion.
103 ///
104 /// If unset, no cache will be used.
105 object_cache_size_mb: Option<usize>,
123 106
124 /// If set once or more times, these references will be fetched instead of all advertised ones.107 #[clap(long)]
125 ///108 /// if set, delta-objects whose base object wouldn't be in the pack will not be recompressed as base object, but instead
126 /// Note that this requires a reasonably modern git server.109 /// refer to its base object using its object id.
127 #[clap(long = "reference", short = 'r')]110 ///
128 refs: Vec<String>,111 /// This allows for smaller packs but requires the receiver of the pack to resolve these ids before storing the pack.
112 /// Packs produced with this option enabled are only valid in transit, but not at rest.
113 thin: bool,
129 114
130 /// The directory into which to write the received pack and index.115 /// The directory into which to write the pack file.
131 ///116 #[clap(long, short = 'o')]
132 /// If unset, they will be discarded.117 output_directory: Option<PathBuf>,
133 directory: Option<PathBuf>,
134 },
135 /// Subcommands for interacting with git remotes, e.g. git repositories hosted on servers.
136 #[clap(subcommand)]
137 #[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]
138 Remote(remote::Subcommands),
139 #[clap(setting = AppSettings::DisableVersionFlag)]
140 PackIndexFromData {
141 /// Specify how to iterate the pack, defaults to 'verify'
142 ///
143 /// Valid values are
144 ///
145 /// **as-is** do not do anything and expect the pack file to be valid as per the trailing hash,
146 /// **verify** the input ourselves and validate that it matches with the hash provided in the pack,
147 /// **restore** hash the input ourselves and ignore failing entries, instead finish the pack with the hash we computed
148 #[clap(
149 long,
150 short = 'i',
151 default_value = "verify",
152 possible_values(core::pack::index::IterationMode::variants())
153 )]
154 iteration_mode: core::pack::index::IterationMode,
155
156 /// Path to the pack file to read (with .pack extension).
157 ///
158 /// If unset, the pack file is expected on stdin.
159 #[clap(long, short = 'p')]
160 pack_path: Option<PathBuf>,
161 118
162 /// The folder into which to place the pack and the generated index file119 /// The tips from which to start the commit graph iteration, either as fully qualified commit hashes
163 ///120 /// or as branch names.
164 /// If unset, only informational output will be provided to standard output.121 ///
165 #[clap(parse(from_os_str))]122 /// If empty, we expect to read objects on stdin and default to 'none' as expansion mode.
166 directory: Option<PathBuf>,123 /// Otherwise the expansion mode is 'tree-traversal' by default.
167 },124 tips: Vec<OsString>,
168 /// Verify the integrity of a pack or index file125 },
169 #[clap(setting = AppSettings::DisableVersionFlag)]126 /// Use the git-protocol to receive a pack, emulating a clone.
170 PackExplode {127 #[clap(setting = AppSettings::DisableVersionFlag)]
171 #[clap(long)]128 #[cfg(any(feature = "gitoxide-core-async-client", feature = "gitoxide-core-blocking-client"))]
172 /// Read written objects back and assert they match their source. Fail the operation otherwise.129 Receive {
173 ///130 /// The protocol version to use. Valid values are 1 and 2
174 /// Only relevant if an object directory is set.131 #[clap(long, short = 'p')]
175 verify: bool,132 protocol: Option<core::net::Protocol>,
176 133
177 /// delete the pack and index file after the operation is successful134 /// the directory into which to write references. Existing files will be overwritten.
178 #[clap(long)]135 ///
179 delete_pack: bool,136 /// Note that the directory will be created if needed.
180 137 #[clap(long, short = 'd')]
181 /// The amount of checks to run138 refs_directory: Option<PathBuf>,
182 #[clap(139
183 long,140 /// The URLs or path from which to receive the pack.
184 short = 'c',141 ///
185 default_value = "all",142 /// See here for a list of supported URLs: <https://www.git-scm.com/docs/git-clone#_git_urls>
186 possible_values(core::pack::explode::SafetyCheck::variants())143 url: String,
187 )]144
188 check: core::pack::explode::SafetyCheck,145 /// If set once or more times, these references will be fetched instead of all advertised ones.
189 146 ///
190 /// Compress bytes even when using the sink, i.e. no object directory is specified147 /// Note that this requires a reasonably modern git server.
191 ///148 #[clap(long = "reference", short = 'r')]
192 /// This helps to determine overhead related to compression. If unset, the sink will149 refs: Vec<String>,
193 /// only create hashes from bytes, which is usually limited by the speed at which input150
194 /// can be obtained.151 /// The directory into which to write the received pack and index.
195 #[clap(long)]152 ///
196 sink_compress: bool,153 /// If unset, they will be discarded.
197 154 directory: Option<PathBuf>,
198 /// The '.pack' or '.idx' file to explode into loose objects155 },
199 #[clap(parse(from_os_str))]156 /// create a pack index from a pack data file.
200 pack_path: PathBuf,157 #[clap(setting = AppSettings::DisableVersionFlag)]
201 158 IndexFromData {
202 /// The path into which all objects should be written. Commonly '.git/objects'159 /// Specify how to iterate the pack, defaults to 'verify'
203 #[clap(parse(from_os_str))]160 ///
204 object_path: Option<PathBuf>,161 /// Valid values are
205 },162 ///
206 /// Verify the integrity of a pack or index file163 /// **as-is** do not do anything and expect the pack file to be valid as per the trailing hash,
207 #[clap(setting = AppSettings::DisableVersionFlag)]164 /// **verify** the input ourselves and validate that it matches with the hash provided in the pack,
208 PackVerify {165 /// **restore** hash the input ourselves and ignore failing entries, instead finish the pack with the hash we computed
209 /// output statistical information about the pack166 /// to keep as many objects as possible.
210 #[clap(long, short = 's')]167 #[clap(
211 statistics: bool,168 long,
212 /// The algorithm used to verify the pack. They differ in costs.169 short = 'i',
213 #[clap(170 default_value = "verify",
214 long,171 possible_values(core::pack::index::IterationMode::variants())
215 short = 'a',172 )]
216 default_value = "less-time",173 iteration_mode: core::pack::index::IterationMode,
217 possible_values(core::pack::verify::Algorithm::variants())174
218 )]175 /// Path to the pack file to read (with .pack extension).
219 algorithm: core::pack::verify::Algorithm,176 ///
220 177 /// If unset, the pack file is expected on stdin.
221 #[clap(long, conflicts_with("re-encode"))]178 #[clap(long, short = 'p')]
222 /// Decode and parse tags, commits and trees to validate their correctness beyond hashing correctly.179 pack_path: Option<PathBuf>,
223 ///
224 /// Malformed objects should not usually occur, but could be injected on purpose or accident.
225 /// This will reduce overall performance.
226 decode: bool,
227 180
228 #[clap(long)]181 /// The folder into which to place the pack and the generated index file
229 /// Decode and parse tags, commits and trees to validate their correctness, and re-encode them.182 ///
183 /// If unset, only informational output will be provided to standard output.
184 #[clap(parse(from_os_str))]
185 directory: Option<PathBuf>,
186 },
187 /// Dissolve a pack into its loose objects.
230 ///188 ///
231 /// This flag is primarily to test the implementation of encoding, and requires to decode the object first.189 /// Note that this effectively removes delta compression for an average compression of 2x, creating one file per object in the process.
232 /// Encoding an object after decoding it should yield exactly the same bytes.190 /// Thus this should only be done to dissolve small packs after a fetch.
233 /// This will reduce overall performance even more, as re-encoding requires to transform zero-copy objects into191 #[clap(setting = AppSettings::DisableVersionFlag)]
234 /// owned objects, causing plenty of allocation to occour.192 Explode {
235 re_encode: bool,193 #[clap(long)]
236 194 /// Read written objects back and assert they match their source. Fail the operation otherwise.
237 /// The '.pack' or '.idx' file whose checksum to validate.195 ///
238 #[clap(parse(from_os_str))]196 /// Only relevant if an object directory is set.
239 path: PathBuf,197 verify: bool,
240 },198
241 /// Subcommands for interacting with commitgraphs199 /// delete the pack and index file after the operation is successful
242 #[clap(subcommand)]200 #[clap(long)]
243 Commitgraph(commitgraph::Subcommands),201 delete_pack: bool,
202
203 /// The amount of checks to run
204 #[clap(
205 long,
206 short = 'c',
207 default_value = "all",
208 possible_values(core::pack::explode::SafetyCheck::variants())
209 )]
210 check: core::pack::explode::SafetyCheck,
211
212 /// Compress bytes even when using the sink, i.e. no object directory is specified
213 ///
214 /// This helps to determine overhead related to compression. If unset, the sink will
215 /// only create hashes from bytes, which is usually limited by the speed at which input
216 /// can be obtained.
217 #[clap(long)]
218 sink_compress: bool,
219
220 /// The '.pack' or '.idx' file to explode into loose objects
221 #[clap(parse(from_os_str))]
222 pack_path: PathBuf,
223
224 /// The path into which all objects should be written. Commonly '.git/objects'
225 #[clap(parse(from_os_str))]
226 object_path: Option<PathBuf>,
227 },
228 /// Verify the integrity of a pack, index or multi-index file
229 #[clap(setting = AppSettings::DisableVersionFlag)]
230 Verify {
231 /// output statistical information about the pack
232 #[clap(long, short = 's')]
233 statistics: bool,
234 /// The algorithm used to verify the pack. They differ in costs.
235 #[clap(
236 long,
237 short = 'a',
238 default_value = "less-time",
239 possible_values(core::pack::verify::Algorithm::variants())
240 )]
241 algorithm: core::pack::verify::Algorithm,
242
243 #[clap(long, conflicts_with("re-encode"))]
244 /// Decode and parse tags, commits and trees to validate their correctness beyond hashing correctly.
245 ///
246 /// Malformed objects should not usually occur, but could be injected on purpose or accident.
247 /// This will reduce overall performance.
248 decode: bool,
249
250 #[clap(long)]
251 /// Decode and parse tags, commits and trees to validate their correctness, and re-encode them.
252 ///
253 /// This flag is primarily to test the implementation of encoding, and requires to decode the object first.
254 /// Encoding an object after decoding it should yield exactly the same bytes.
255 /// This will reduce overall performance even more, as re-encoding requires to transform zero-copy objects into
256 /// owned objects, causing plenty of allocation to occour.
257 re_encode: bool,
258
259 /// The '.pack' or '.idx' file whose checksum to validate.
260 #[clap(parse(from_os_str))]
261 path: PathBuf,
262 },
263 }
244}264}
245 265
246///266///
tests/journey/gix.sh+339−332
@@ -39,157 +39,384 @@ title "git-tempfile crate" · 38 unmodified lines
39 )39 )
40)40)
41 41
42title "gix pack-receive"42title "gix pack"
43(when "running 'pack-receive'"43(when "running 'pack'"
44 snapshot="$snapshot/pack-receive"44 snapshot="$snapshot/pack"
45 (small-repo-in-sandbox45
46 if [[ "$kind" != 'small' ]]; then46 title "gix pack receive"
47 (with "the 'receive' sub-command"
48 snapshot="$snapshot/receive"
49 (small-repo-in-sandbox
50 if [[ "$kind" != 'small' ]]; then
47 51
48 if [[ "$kind" != 'async' ]]; then52 if [[ "$kind" != 'async' ]]; then
49 (with "file:// protocol"53 (with "file:// protocol"
50 (with "version 1"54 (with "version 1"
51 (with "NO output directory"55 (with "NO output directory"
52 it "generates the correct output" && {56 it "generates the correct output" && {
53 WITH_SNAPSHOT="$snapshot/file-v-any-no-output" \57 WITH_SNAPSHOT="$snapshot/file-v-any-no-output" \
54 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 1 .git58 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 1 .git
55 }59 }
60 )
61 (with "output directory"
62 mkdir out
63 it "generates the correct output" && {
64 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \
65 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 1 .git out/
66 }
67 it "creates an index and a pack in the output directory" && {
68 WITH_SNAPSHOT="$snapshot/ls-in-output-dir" \
69 expect_run $SUCCESSFULLY ls out/
70 }
71 (with "--write-refs set"
72 it "generates the correct output" && {
73 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \
74 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 1 --refs-directory out/all-refs .git out/
75 }
76 it "writes references into the refs folder of the output directory" && {
77 expect_snapshot "$snapshot/repo-refs" out/all-refs
78 }
79 )
80 rm -Rf out
81 )
82 if test "$kind" = "max"; then
83 (with "--format json"
84 it "generates the correct output in JSON format" && {
85 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-json" \
86 expect_run $SUCCESSFULLY "$exe_plumbing" --format json pack receive --protocol 1 .git
87 }
88 )
89 fi
56 )90 )
57 (with "output directory"91 (with "version 2"
58 mkdir out92 (with "NO output directory"
59 it "generates the correct output" && {93 it "generates the correct output" && {
60 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \94 WITH_SNAPSHOT="$snapshot/file-v-any-no-output" \
61 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 1 .git out/95 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 2 .git
62 }96 }
63 it "creates an index and a pack in the output directory" && {97 )
64 WITH_SNAPSHOT="$snapshot/ls-in-output-dir" \98 (with "output directory"
65 expect_run $SUCCESSFULLY ls out/99 mkdir out/
66 }100 it "generates the correct output" && {
67 (with "--write-refs set"101 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \
102 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive .git out/
103 }
104 it "creates an index and a pack in the output directory" && {
105 WITH_SNAPSHOT="$snapshot/ls-in-output-dir" \
106 expect_run $SUCCESSFULLY ls out/
107 }
108 rm -Rf out
109 )
110 if test "$kind" = "max"; then
111 (with "--format json"
112 it "generates the correct output in JSON format" && {
113 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-json" \
114 expect_run $SUCCESSFULLY "$exe_plumbing" --format json pack receive --protocol 2 .git
115 }
116 )
117 fi
118 )
119 )
120 fi
121 (with "git:// protocol"
122 launch-git-daemon
123 (with "version 1"
124 (with "NO output directory"
125 (with "no wanted refs"
126 it "generates the correct output" && {
127 WITH_SNAPSHOT="$snapshot/file-v-any-no-output" \
128 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 1 git://localhost/
129 }
130 )
131 (with "wanted refs"
132 it "generates the correct output" && {
133 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-wanted-ref-p1" \
134 expect_run $WITH_FAILURE "$exe_plumbing" pack receive -p 1 git://localhost/ -r =refs/heads/main
135 }
136 )
137 )
138 (with "output directory"
139 mkdir out
68 it "generates the correct output" && {140 it "generates the correct output" && {
69 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \141 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \
70 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 1 --refs-directory out/all-refs .git out/142 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 1 git://localhost/ out/
71 }143 }
72 it "writes references into the refs folder of the output directory" && {144 )
73 expect_snapshot "$snapshot/repo-refs" out/all-refs145 )
146 (with "version 2"
147 (with "NO output directory"
148 (with "NO wanted refs"
149 it "generates the correct output" && {
150 WITH_SNAPSHOT="$snapshot/file-v-any-no-output" \
151 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 2 git://localhost/
152 }
153 )
154 (with "wanted refs"
155 it "generates the correct output" && {
156 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-single-ref" \
157 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 2 git://localhost/ -r refs/heads/main
158 }
159 (when "ref does not exist"
160 it "fails with a detailed error message including what the server said" && {
161 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-non-existing-single-ref" \
162 expect_run $WITH_FAILURE "$exe_plumbing" pack receive -p 2 git://localhost/ -r refs/heads/does-not-exist
163 }
164 )
165 )
166 )
167 (with "output directory"
168 it "generates the correct output" && {
169 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \
170 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive git://localhost/ out/
74 }171 }
75 )172 )
76 rm -Rf out
77 )173 )
174 )
175 (on_ci
78 if test "$kind" = "max"; then176 if test "$kind" = "max"; then
79 (with "--format json"177 (with "https:// protocol"
80 it "generates the correct output in JSON format" && {178 (with "version 1"
81 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-json" \179 it "works" && {
82 expect_run $SUCCESSFULLY "$exe_plumbing" --format json pack-receive --protocol 1 .git180 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 1 https://github.com/byron/gitoxide
83 }181 }
182 )
183 (with "version 2"
184 it "works" && {
185 expect_run $SUCCESSFULLY "$exe_plumbing" pack receive -p 2 https://github.com/byron/gitoxide
186 }
187 )
84 )188 )
85 fi189 fi
86 )190 )
87 (with "version 2"191 elif [[ "$kind" = "small" ]]; then
88 (with "NO output directory"192 it "fails as the CLI doesn't have networking in 'small' mode" && {
89 it "generates the correct output" && {193 WITH_SNAPSHOT="$snapshot/pack receive-no-networking-in-small-failure" \
90 WITH_SNAPSHOT="$snapshot/file-v-any-no-output" \194 expect_run 2 "$exe_plumbing" pack receive -p 1 .git
91 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 2 .git195 }
196 fi
197 )
198 )
199 title "gix pack index-from-data"
200 (with "the 'index-from-data' sub-command"
201 snapshot="$snapshot/index-from-data"
202 PACK_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack"
203 (with "a valid and complete pack file"
204 (with "NO output directory specified"
205 (with "pack file passed as file"
206 it "generates an index into a sink and outputs pack and index information" && {
207 WITH_SNAPSHOT="$snapshot/no-output-dir-success" \
208 expect_run $SUCCESSFULLY "$exe_plumbing" pack index-from-data -p "$PACK_FILE"
92 }209 }
93 )210 )
94 (with "output directory"211 (with "pack file passed from stdin"
95 mkdir out/212 it "generates an index into a sink and outputs pack and index information" && {
96 it "generates the correct output" && {213 WITH_SNAPSHOT="$snapshot/no-output-dir-success" \
97 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \214 expect_run $SUCCESSFULLY "$exe_plumbing" pack index-from-data < "$PACK_FILE"
98 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive .git out/
99 }215 }
100 it "creates an index and a pack in the output directory" && {216 if test "$kind" = "max"; then
101 WITH_SNAPSHOT="$snapshot/ls-in-output-dir" \217 (with "--format json"
102 expect_run $SUCCESSFULLY ls out/218 it "generates the index into a sink and outputs information as JSON" && {
219 WITH_SNAPSHOT="$snapshot/no-output-dir-as-json-success" \
220 expect_run $SUCCESSFULLY "$exe_plumbing" --format json pack index-from-data < "$PACK_FILE"
221 }
222 )
223 fi
224 )
225 )
226 (sandbox
227 (with "with an output directory specified"
228 it "generates an index and outputs information" && {
229 WITH_SNAPSHOT="$snapshot/output-dir-success" \
230 expect_run $SUCCESSFULLY "$exe_plumbing" pack index-from-data -p "$PACK_FILE" "$PWD"
231 }
232 it "writes the index and pack into the directory (they have the same names, different suffixes)" && {
233 WITH_SNAPSHOT="$snapshot/output-dir-content" \
234 expect_run $SUCCESSFULLY ls
103 }235 }
104 rm -Rf out
105 )236 )
237 )
238 )
239 (with "'restore' iteration mode"
240 (sandbox
241 cp "${PACK_FILE}" .
242 PACK_FILE="${PACK_FILE##*/}"
243 "$jtt" mess-in-the-middle "${PACK_FILE}"
244
245 it "generates an index and outputs information (instead of failing)" && {
246 WITH_SNAPSHOT="$snapshot/output-dir-restore-success" \
247 expect_run $SUCCESSFULLY "$exe_plumbing" pack index-from-data -i restore -p "$PACK_FILE" "$PWD"
248 }
249
106 if test "$kind" = "max"; then250 if test "$kind" = "max"; then
107 (with "--format json"251 (with "--format json and the very same output directory"
108 it "generates the correct output in JSON format" && {252 it "generates the index, overwriting existing files, and outputs information as JSON" && {
109 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-json" \253 WITH_SNAPSHOT="$snapshot/output-dir-restore-as-json-success" \
110 expect_run $SUCCESSFULLY "$exe_plumbing" --format json pack-receive --protocol 2 .git254 SNAPSHOT_FILTER=remove-paths \
255 expect_run $SUCCESSFULLY "$exe_plumbing" --format json pack index-from-data -i restore $PWD < "$PACK_FILE"
111 }256 }
112 )257 )
113 fi258 fi
114 )259 )
115 )260 )
116 fi261 )
117 (with "git:// protocol"262
118 launch-git-daemon263 title "gix pack explode"
119 (with "version 1"264 (with "the 'explode' sub-command"
120 (with "NO output directory"265 snapshot="$snapshot/explode"
121 (with "no wanted refs"266 PACK_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2"
122 it "generates the correct output" && {267 (with "no objects directory specified"
123 WITH_SNAPSHOT="$snapshot/file-v-any-no-output" \268 it "explodes the pack successfully and with desired output" && {
124 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 1 git://localhost/269 WITH_SNAPSHOT="$snapshot/to-sink-success" \
125 }270 expect_run $SUCCESSFULLY "$exe_plumbing" pack explode "${PACK_FILE}.idx"
126 )271 }
127 (with "wanted refs"272
128 it "generates the correct output" && {273 (when "using the --delete-pack flag"
129 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-wanted-ref-p1" \274 (sandbox
130 expect_run $WITH_FAILURE "$exe_plumbing" pack-receive -p 1 git://localhost/ -r =refs/heads/main275 (with "a valid pack"
276 cp "${PACK_FILE}".idx "${PACK_FILE}".pack .
277 PACK_FILE="${PACK_FILE##*/}"
278 it "explodes the pack successfully and deletes the original pack and index" && {
279 WITH_SNAPSHOT="$snapshot/to-sink-delete-pack-success" \
280 expect_run $SUCCESSFULLY "$exe_plumbing" pack explode --check skip-file-checksum --delete-pack "${PACK_FILE}.pack"
131 }281 }
132 )282 it "removes the original files" && {
133 )283 expect_run $WITH_FAILURE test -e "${PACK_FILE}".pack
134 (with "output directory"284 expect_run $WITH_FAILURE test -e "${PACK_FILE}".idx
135 mkdir out
136 it "generates the correct output" && {
137 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \
138 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 1 git://localhost/ out/
139 }
140 )
141 )
142 (with "version 2"
143 (with "NO output directory"
144 (with "NO wanted refs"
145 it "generates the correct output" && {
146 WITH_SNAPSHOT="$snapshot/file-v-any-no-output" \
147 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 2 git://localhost/
148 }285 }
149 )286 )
150 (with "wanted refs"287 (with "a pack file that is invalid somewhere"
151 it "generates the correct output" && {288 cp ${PACK_FILE}.idx ${PACK_FILE}.pack .
152 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-single-ref" \289 PACK_FILE="${PACK_FILE##*/}"
153 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 2 git://localhost/ -r refs/heads/main290 "$jtt" mess-in-the-middle "${PACK_FILE}".pack
154 }291
155 (when "ref does not exist"292 (with "and all safety checks"
156 it "fails with a detailed error message including what the server said" && {293 it "does not explode the file at all" && {
157 WITH_SNAPSHOT="$snapshot/file-v-any-no-output-non-existing-single-ref" \294 WITH_SNAPSHOT="$snapshot/broken-delete-pack-to-sink-failure" \
158 expect_run $WITH_FAILURE "$exe_plumbing" pack-receive -p 2 git://localhost/ -r refs/heads/does-not-exist295 expect_run $WITH_FAILURE "$exe_plumbing" pack explode --sink-compress --check all --delete-pack "${PACK_FILE}.pack"
296 }
297
298 it "did not touch index or pack file" && {
299 expect_exists "${PACK_FILE}".pack
300 expect_exists "${PACK_FILE}".idx
159 }301 }
160 )302 )
303
304 (with "and no safety checks at all (and an output directory)"
305 it "does explode the file" && {
306 WITH_SNAPSHOT="$snapshot/broken-delete-pack-to-sink-skip-checks-success" \
307 expect_run $SUCCESSFULLY "$exe_plumbing" pack explode --verify --check skip-file-and-object-checksum-and-no-abort-on-decode \
308 --delete-pack "${PACK_FILE}.pack" .
309 }
310
311 it "removes the original files" && {
312 expect_run $WITH_FAILURE test -e "${PACK_FILE}".pack
313 expect_run $WITH_FAILURE test -e "${PACK_FILE}".idx
314 }
315
316 (with_program tree
317
318 if test "$kind" = "small"; then
319 suffix=miniz-oxide
320 else
321 suffix=zlib-ng
322 fi
323 it "creates all pack objects, but the broken ones" && {
324 WITH_SNAPSHOT="$snapshot/broken-with-objects-dir-skip-checks-success-tree-$suffix" \
325 expect_run $SUCCESSFULLY tree
326 }
327 )
328 )
161 )329 )
162 )330 )
163 (with "output directory"
164 it "generates the correct output" && {
165 WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \
166 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive git://localhost/ out/
167 }
168 )
169 )331 )
170 )332 )
171 (on_ci333 (with "a non-existing directory specified"
172 if test "$kind" = "max"; then334 it "fails with a helpful error message" && {
173 (with "https:// protocol"335 WITH_SNAPSHOT="$snapshot/missing-objects-dir-fail" \
174 (with "version 1"336 expect_run $WITH_FAILURE "$exe_plumbing" pack explode -c skip-file-and-object-checksum "${PACK_FILE}.idx" does-not-exist
175 it "works" && {337 }
176 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 1 https://github.com/byron/gitoxide338 )
339 (with "an existing directory specified"
340 (sandbox
341 it "succeeds" && {
342 WITH_SNAPSHOT="$snapshot/with-objects-dir-success" \
343 expect_run $SUCCESSFULLY "$exe_plumbing" pack explode -c skip-file-and-object-checksum-and-no-abort-on-decode \
344 "${PACK_FILE}.pack" .
345 }
346
347 (with_program tree
348 it "creates all pack objects" && {
349 WITH_SNAPSHOT="$snapshot/with-objects-dir-success-tree" \
350 expect_run $SUCCESSFULLY tree
177 }351 }
178 )352 )
179 (with "version 2"353 )
180 it "works" && {354 )
181 expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 2 https://github.com/byron/gitoxide355 )
356
357 title "gix pack verify"
358 (with "the 'verify' sub-command"
359 snapshot="$snapshot/verify"
360 (with "a valid pack file"
361 PACK_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack"
362 it "verifies the pack successfully and with desired output" && {
363 WITH_SNAPSHOT="$snapshot/success" \
364 expect_run $SUCCESSFULLY "$exe_plumbing" pack verify "$PACK_FILE"
365 }
366 )
367 (with "a valid pack INDEX file"
368 PACK_INDEX_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.idx"
369 (with "no statistics"
370 it "verifies the pack index successfully and with desired output" && {
371 WITH_SNAPSHOT="$snapshot/index-success" \
372 expect_run $SUCCESSFULLY "$exe_plumbing" pack verify "$PACK_INDEX_FILE"
373 }
374 )
375 (with "statistics"
376 it "verifies the pack index successfully and with desired output" && {
377 WITH_SNAPSHOT="$snapshot/index-with-statistics-success" \
378 expect_run $SUCCESSFULLY "$exe_plumbing" pack verify --statistics "$PACK_INDEX_FILE"
379 }
380
381 (with "and the less-memory algorithm"
382 it "verifies the pack index successfully and with desired output" && {
383 WITH_SNAPSHOT="$snapshot/index-with-statistics-success" \
384 expect_run $SUCCESSFULLY "$exe_plumbing" pack verify --algorithm less-memory --statistics "$PACK_INDEX_FILE"
182 }385 }
183 )386 )
184 )387 )
388 (with "decode"
389 it "verifies the pack index successfully and with desired output, and decodes all objects" && {
390 WITH_SNAPSHOT="$snapshot/index-success" \
391 expect_run $SUCCESSFULLY "$exe_plumbing" pack verify --algorithm less-memory --decode "$PACK_INDEX_FILE"
392 }
393 )
394 (with "re-encode"
395 it "verifies the pack index successfully and with desired output, and re-encodes all objects" && {
396 WITH_SNAPSHOT="$snapshot/index-success" \
397 expect_run $SUCCESSFULLY "$exe_plumbing" pack verify --algorithm less-time --re-encode "$PACK_INDEX_FILE"
398 }
399 )
400 if test "$kind" = "max"; then
401 (with "statistics (JSON)"
402 it "verifies the pack index successfully and with desired output" && {
403 WITH_SNAPSHOT="$snapshot/index-with-statistics-json-success" \
404 expect_run $SUCCESSFULLY "$exe_plumbing" --format json --threads 1 pack verify --statistics "$PACK_INDEX_FILE"
405 }
406 )
185 fi407 fi
186 )408 )
187 elif [[ "$kind" = "small" ]]; then409 (sandbox
188 it "fails as the CLI doesn't have networking in 'small' mode" && {410 (with "an INvalid pack INDEX file"
189 WITH_SNAPSHOT="$snapshot/pack-receive-no-networking-in-small-failure" \411 PACK_INDEX_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.idx"
190 expect_run 2 "$exe_plumbing" pack-receive -p 1 .git412 cp $PACK_INDEX_FILE index.idx
191 }413 echo $'\0' >> index.idx
192 fi414 it "fails to verify the pack index and with desired output" && {
415 WITH_SNAPSHOT="$snapshot/index-failure" \
416 expect_run $WITH_FAILURE "$exe_plumbing" pack verify index.idx
417 }
418 )
419 )
193 )420 )
194)421)
195 422
@@ -276,227 +503,7 @@ title "gix remote" · 80 unmodified lines
276 )503 )
277)504)
278 505
279title "gix pack-index-from-data"
280(when "running 'pack-index-from-data"
281 snapshot="$snapshot/pack-index-from-data"
282 PACK_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack"
283 (with "a valid and complete pack file"
284 (with "NO output directory specified"
285 (with "pack file passed as file"
286 it "generates an index into a sink and outputs pack and index information" && {
287 WITH_SNAPSHOT="$snapshot/no-output-dir-success" \
288 expect_run $SUCCESSFULLY "$exe_plumbing" pack-index-from-data -p "$PACK_FILE"
289 }
290 )
291 (with "pack file passed from stdin"
292 it "generates an index into a sink and outputs pack and index information" && {
293 WITH_SNAPSHOT="$snapshot/no-output-dir-success" \
294 expect_run $SUCCESSFULLY "$exe_plumbing" pack-index-from-data < "$PACK_FILE"
295 }
296 if test "$kind" = "max"; then
297 (with "--format json"
298 it "generates the index into a sink and outputs information as JSON" && {
299 WITH_SNAPSHOT="$snapshot/no-output-dir-as-json-success" \
300 expect_run $SUCCESSFULLY "$exe_plumbing" --format json pack-index-from-data < "$PACK_FILE"
301 }
302 )
303 fi
304 )
305 )
306 (sandbox
307 (with "with an output directory specified"
308 it "generates an index and outputs information" && {
309 WITH_SNAPSHOT="$snapshot/output-dir-success" \
310 expect_run $SUCCESSFULLY "$exe_plumbing" pack-index-from-data -p "$PACK_FILE" "$PWD"
311 }
312 it "writes the index and pack into the directory (they have the same names, different suffixes)" && {
313 WITH_SNAPSHOT="$snapshot/output-dir-content" \
314 expect_run $SUCCESSFULLY ls
315 }
316 )
317 )
318 )
319 (with "'restore' iteration mode"
320 (sandbox
321 cp "${PACK_FILE}" .
322 PACK_FILE="${PACK_FILE##*/}"
323 "$jtt" mess-in-the-middle "${PACK_FILE}"
324
325 it "generates an index and outputs information (instead of failing)" && {
326 WITH_SNAPSHOT="$snapshot/output-dir-restore-success" \
327 expect_run $SUCCESSFULLY "$exe_plumbing" pack-index-from-data -i restore -p "$PACK_FILE" "$PWD"
328 }
329 506
330 if test "$kind" = "max"; then
331 (with "--format json and the very same output directory"
332 it "generates the index, overwriting existing files, and outputs information as JSON" && {
333 WITH_SNAPSHOT="$snapshot/output-dir-restore-as-json-success" \
334 SNAPSHOT_FILTER=remove-paths \
335 expect_run $SUCCESSFULLY "$exe_plumbing" --format json pack-index-from-data -i restore $PWD < "$PACK_FILE"
336 }
337 )
338 fi
339 )
340 )
341)
342title "gix pack-explode"
343(when "running 'pack-explode"
344 snapshot="$snapshot/pack-explode"
345 PACK_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2"
346 (with "no objects directory specified"
347 it "explodes the pack successfully and with desired output" && {
348 WITH_SNAPSHOT="$snapshot/to-sink-success" \
349 expect_run $SUCCESSFULLY "$exe_plumbing" pack-explode "${PACK_FILE}.idx"
350 }
351
352 (when "using the --delete-pack flag"
353 (sandbox
354 (with "a valid pack"
355 cp "${PACK_FILE}".idx "${PACK_FILE}".pack .
356 PACK_FILE="${PACK_FILE##*/}"
357 it "explodes the pack successfully and deletes the original pack and index" && {
358 WITH_SNAPSHOT="$snapshot/to-sink-delete-pack-success" \
359 expect_run $SUCCESSFULLY "$exe_plumbing" pack-explode --check skip-file-checksum --delete-pack "${PACK_FILE}.pack"
360 }
361 it "removes the original files" && {
362 expect_run $WITH_FAILURE test -e "${PACK_FILE}".pack
363 expect_run $WITH_FAILURE test -e "${PACK_FILE}".idx
364 }
365 )
366 (with "a pack file that is invalid somewhere"
367 cp ${PACK_FILE}.idx ${PACK_FILE}.pack .
368 PACK_FILE="${PACK_FILE##*/}"
369 "$jtt" mess-in-the-middle "${PACK_FILE}".pack
370
371 (with "and all safety checks"
372 it "does not explode the file at all" && {
373 WITH_SNAPSHOT="$snapshot/broken-delete-pack-to-sink-failure" \
374 expect_run $WITH_FAILURE "$exe_plumbing" pack-explode --sink-compress --check all --delete-pack "${PACK_FILE}.pack"
375 }
376
377 it "did not touch index or pack file" && {
378 expect_exists "${PACK_FILE}".pack
379 expect_exists "${PACK_FILE}".idx
380 }
381 )
382
383 (with "and no safety checks at all (and an output directory)"
384 it "does explode the file" && {
385 WITH_SNAPSHOT="$snapshot/broken-delete-pack-to-sink-skip-checks-success" \
386 expect_run $SUCCESSFULLY "$exe_plumbing" pack-explode --verify --check skip-file-and-object-checksum-and-no-abort-on-decode \
387 --delete-pack "${PACK_FILE}.pack" .
388 }
389
390 it "removes the original files" && {
391 expect_run $WITH_FAILURE test -e "${PACK_FILE}".pack
392 expect_run $WITH_FAILURE test -e "${PACK_FILE}".idx
393 }
394
395 (with_program tree
396
397 if test "$kind" = "small"; then
398 suffix=miniz-oxide
399 else
400 suffix=zlib-ng
401 fi
402 it "creates all pack objects, but the broken ones" && {
403 WITH_SNAPSHOT="$snapshot/broken-with-objects-dir-skip-checks-success-tree-$suffix" \
404 expect_run $SUCCESSFULLY tree
405 }
406 )
407 )
408 )
409 )
410 )
411 )
412 (with "a non-existing directory specified"
413 it "fails with a helpful error message" && {
414 WITH_SNAPSHOT="$snapshot/missing-objects-dir-fail" \
415 expect_run $WITH_FAILURE "$exe_plumbing" pack-explode -c skip-file-and-object-checksum "${PACK_FILE}.idx" does-not-exist
416 }
417 )
418 (with "an existing directory specified"
419 (sandbox
420 it "succeeds" && {
421 WITH_SNAPSHOT="$snapshot/with-objects-dir-success" \
422 expect_run $SUCCESSFULLY "$exe_plumbing" pack-explode -c skip-file-and-object-checksum-and-no-abort-on-decode \
423 "${PACK_FILE}.pack" .
424 }
425
426 (with_program tree
427 it "creates all pack objects" && {
428 WITH_SNAPSHOT="$snapshot/with-objects-dir-success-tree" \
429 expect_run $SUCCESSFULLY tree
430 }
431 )
432 )
433 )
434)
435
436title "gix pack-verify"
437(when "running 'pack-verify"
438 snapshot="$snapshot/pack-verify"
439 (with "a valid pack file"
440 PACK_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.pack"
441 it "verifies the pack successfully and with desired output" && {
442 WITH_SNAPSHOT="$snapshot/success" \
443 expect_run $SUCCESSFULLY "$exe_plumbing" pack-verify "$PACK_FILE"
444 }
445 )
446 (with "a valid pack INDEX file"
447 PACK_INDEX_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.idx"
448 (with "no statistics"
449 it "verifies the pack index successfully and with desired output" && {
450 WITH_SNAPSHOT="$snapshot/index-success" \
451 expect_run $SUCCESSFULLY "$exe_plumbing" pack-verify "$PACK_INDEX_FILE"
452 }
453 )
454 (with "statistics"
455 it "verifies the pack index successfully and with desired output" && {
456 WITH_SNAPSHOT="$snapshot/index-with-statistics-success" \
457 expect_run $SUCCESSFULLY "$exe_plumbing" pack-verify --statistics "$PACK_INDEX_FILE"
458 }
459
460 (with "and the less-memory algorithm"
461 it "verifies the pack index successfully and with desired output" && {
462 WITH_SNAPSHOT="$snapshot/index-with-statistics-success" \
463 expect_run $SUCCESSFULLY "$exe_plumbing" pack-verify --algorithm less-memory --statistics "$PACK_INDEX_FILE"
464 }
465 )
466 )
467 (with "decode"
468 it "verifies the pack index successfully and with desired output, and decodes all objects" && {
469 WITH_SNAPSHOT="$snapshot/index-success" \
470 expect_run $SUCCESSFULLY "$exe_plumbing" pack-verify --algorithm less-memory --decode "$PACK_INDEX_FILE"
471 }
472 )
473 (with "re-encode"
474 it "verifies the pack index successfully and with desired output, and re-encodes all objects" && {
475 WITH_SNAPSHOT="$snapshot/index-success" \
476 expect_run $SUCCESSFULLY "$exe_plumbing" pack-verify --algorithm less-time --re-encode "$PACK_INDEX_FILE"
477 }
478 )
479 if test "$kind" = "max"; then
480 (with "statistics (JSON)"
481 it "verifies the pack index successfully and with desired output" && {
482 WITH_SNAPSHOT="$snapshot/index-with-statistics-json-success" \
483 expect_run $SUCCESSFULLY "$exe_plumbing" --format json --threads 1 pack-verify --statistics "$PACK_INDEX_FILE"
484 }
485 )
486 fi
487 )
488 (sandbox
489 (with "an INvalid pack INDEX file"
490 PACK_INDEX_FILE="$fixtures/packs/pack-11fdfa9e156ab73caae3b6da867192221f2089c2.idx"
491 cp $PACK_INDEX_FILE index.idx
492 echo $'\0' >> index.idx
493 it "fails to verify the pack index and with desired output" && {
494 WITH_SNAPSHOT="$snapshot/index-failure" \
495 expect_run $WITH_FAILURE "$exe_plumbing" pack-verify index.idx
496 }
497 )
498 )
499)
500 507
501title "gix commitgraph"508title "gix commitgraph"
502(when "running 'commitgraph'"509(when "running 'commitgraph'"
tests/snapshots/plumbing/pack-receive/pack-receive-no-networking-in-small-failure+0−10
@@ -1,10 +0,0 @@
1error: The subcommand 'pack-receive' wasn't recognized
2
3 Did you mean 'pack-index-from-data' or 'pack-explode' or 'pack-verify' or 'pack-create'?
4
5If you believe you received this message in error, try re-running with 'gix -- pack-receive'
6
7USAGE:
8 gix [OPTIONS] <SUBCOMMAND>
9
10For more information try --help
tests/snapshots/plumbing/pack/explode/broken-delete-pack-to-sink-failurerenamed from tests/snapshots/plumbing/pack-explode/broken-delete-pack-to-sink-failure+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/explode/broken-delete-pack-to-sink-skip-checks-successrenamed from tests/snapshots/plumbing/pack-explode/broken-delete-pack-to-sink-skip-checks-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/explode/broken-with-objects-dir-skip-checks-success-tree-miniz-oxiderenamed from tests/snapshots/plumbing/pack-explode/broken-with-objects-dir-skip-checks-success-tree-miniz-oxide+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/explode/broken-with-objects-dir-skip-checks-success-tree-zlib-ngrenamed from tests/snapshots/plumbing/pack-explode/broken-with-objects-dir-skip-checks-success-tree-zlib-ng+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/explode/missing-objects-dir-failrenamed from tests/snapshots/plumbing/pack-explode/missing-objects-dir-fail+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/explode/to-sink-delete-pack-successrenamed from tests/snapshots/plumbing/pack-explode/to-sink-delete-pack-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/explode/to-sink-successrenamed from tests/snapshots/plumbing/pack-explode/to-sink-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/explode/with-objects-dir-successrenamed from tests/snapshots/plumbing/pack-explode/with-objects-dir-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/explode/with-objects-dir-success-treerenamed from tests/snapshots/plumbing/pack-explode/with-objects-dir-success-tree+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/index-from-data/no-output-dir-as-json-successrenamed from tests/snapshots/plumbing/pack-index-from-data/no-output-dir-as-json-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/index-from-data/no-output-dir-successrenamed from tests/snapshots/plumbing/pack-index-from-data/no-output-dir-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/index-from-data/output-dir-contentrenamed from tests/snapshots/plumbing/pack-index-from-data/output-dir-content+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/index-from-data/output-dir-restore-as-json-successrenamed from tests/snapshots/plumbing/pack-index-from-data/output-dir-restore-as-json-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/index-from-data/output-dir-restore-successrenamed from tests/snapshots/plumbing/pack-index-from-data/output-dir-restore-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/index-from-data/output-dir-successrenamed from tests/snapshots/plumbing/pack-index-from-data/output-dir-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/file-v-any-no-outputrenamed from tests/snapshots/plumbing/pack-receive/file-v-any-no-output+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/file-v-any-no-output-jsonrenamed from tests/snapshots/plumbing/pack-receive/file-v-any-no-output-json+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/file-v-any-no-output-non-existing-single-refrenamed from tests/snapshots/plumbing/pack-receive/file-v-any-no-output-non-existing-single-ref+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/file-v-any-no-output-single-refrenamed from tests/snapshots/plumbing/pack-receive/file-v-any-no-output-single-ref+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/file-v-any-no-output-wanted-ref-p1renamed from tests/snapshots/plumbing/pack-receive/file-v-any-no-output-wanted-ref-p1+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/file-v-any-with-outputrenamed from tests/snapshots/plumbing/pack-receive/file-v-any-with-output+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/ls-in-output-dirrenamed from tests/snapshots/plumbing/pack-receive/ls-in-output-dir+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/pack receive-no-networking-in-small-failure+6−0
@@ -0,0 +1,6 @@
1error: Found argument 'receive' which wasn't expected, or isn't valid in this context
2
3USAGE:
4 gix pack <SUBCOMMAND>
5
6For more information try --help
tests/snapshots/plumbing/pack/receive/repo-refs/HEADrenamed from tests/snapshots/plumbing/pack-receive/repo-refs/HEAD+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/repo-refs/refs/heads/devrenamed from tests/snapshots/plumbing/pack-receive/repo-refs/refs/heads/dev+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/repo-refs/refs/heads/mainrenamed from tests/snapshots/plumbing/pack-receive/repo-refs/refs/heads/main+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/repo-refs/refs/tags/annotatedrenamed from tests/snapshots/plumbing/pack-receive/repo-refs/refs/tags/annotated+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/receive/repo-refs/refs/tags/unannotatedrenamed from tests/snapshots/plumbing/pack-receive/repo-refs/refs/tags/unannotated+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/verify/index-failurerenamed from tests/snapshots/plumbing/pack-verify/index-failure+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/verify/index-successrenamed from tests/snapshots/plumbing/pack-verify/index-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/verify/index-with-statistics-json-successrenamed from tests/snapshots/plumbing/pack-verify/index-with-statistics-json-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/verify/index-with-statistics-successrenamed from tests/snapshots/plumbing/pack-verify/index-with-statistics-success+0−0

File renamed without changes.

tests/snapshots/plumbing/pack/verify/successrenamed from tests/snapshots/plumbing/pack-verify/success+0−0

File renamed without changes.

tests/snapshots/plumbing/remote/ref-list/remote ref-list-no-networking-in-small-failure+6−0
@@ -0,0 +1,6 @@
1error: Found argument 'remote' which wasn't expected, or isn't valid in this context
2
3USAGE:
4 gix [OPTIONS] <SUBCOMMAND>
5
6For more information try --help