…there really should be control over where to write them exactly
Unified · Split
| @@ -1,9 +1,12 @@ | ||
| 1 | 1 | use crate::{remote::refs::JsonRef, OutputFormat, Protocol}; |
| 2 | 2 | use git_features::progress::Progress; |
| 3 | −use git_object::owned; | |
| 3 | +use git_object::{bstr::ByteSlice, owned}; | |
| 4 | 4 | use git_odb::pack; |
| 5 | 5 | use git_protocol::fetch::{Action, Arguments, Ref, Response}; |
| 6 | −use std::{io, io::BufRead, path::PathBuf}; | |
| 6 | +use std::{ | |
| 7 | + io::{self, BufRead}, | |
| 8 | + path::PathBuf, | |
| 9 | +}; | |
| 7 | 10 | |
| 8 | 11 | pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3; |
| 9 | 12 | |
| @@ -16,6 +19,7 @@ pub struct Context<W: io::Write> { · 6 unmodified lines | ||
| 16 | 19 | struct CloneDelegate<W: io::Write> { |
| 17 | 20 | ctx: Context<W>, |
| 18 | 21 | directory: Option<PathBuf>, |
| 22 | + write_refs: bool, | |
| 19 | 23 | } |
| 20 | 24 | |
| 21 | 25 | impl<W: io::Write> git_protocol::fetch::Delegate for CloneDelegate<W> { |
| @@ -43,8 +47,30 @@ impl<W: io::Write> git_protocol::fetch::Delegate for CloneDelegate<W> { · 21 unmodified lines | ||
| 43 | 47 | index_kind: pack::index::Kind::V2, |
| 44 | 48 | iteration_mode: pack::data::iter::Mode::Verify, |
| 45 | 49 | }; |
| 46 | − let outcome = pack::bundle::Bundle::write_stream_to_directory(input, self.directory.take(), progress, options) | |
| 50 | + let outcome = pack::bundle::Bundle::write_stream_to_directory(input, self.directory.clone(), progress, options) | |
| 47 | 51 | .map_err(|err| io::Error::new(io::ErrorKind::Other, err))?; |
| 52 | + | |
| 53 | + if let Some(directory) = self.directory.take() { | |
| 54 | + let assure_dir = |path: &git_object::bstr::BString| { | |
| 55 | + assert!(!path.starts_with_str("/"), "no ref start with a /, they are relative"); | |
| 56 | + let path = directory.join(path.to_path_lossy()); | |
| 57 | + std::fs::create_dir_all(path.parent().expect("multi-component path")).map(|_| path) | |
| 58 | + }; | |
| 59 | + if self.write_refs { | |
| 60 | + for r in refs { | |
| 61 | + match r { | |
| 62 | + Ref::Symbolic { path, target, .. } => { | |
| 63 | + assure_dir(path).map(|path| (path, format!("ref: {}", target))) | |
| 64 | + } | |
| 65 | + Ref::Peeled { path, tag: object, .. } | Ref::Direct { path, object } => { | |
| 66 | + assure_dir(path).map(|path| (path, object.to_string())) | |
| 67 | + } | |
| 68 | + } | |
| 69 | + .and_then(|(path, content)| std::fs::write(path, content.as_bytes()))?; | |
| 70 | + } | |
| 71 | + } | |
| 72 | + } | |
| 73 | + | |
| 48 | 74 | match self.ctx.format { |
| 49 | 75 | OutputFormat::Human => drop(print(&mut self.ctx.out, outcome, refs)), |
| 50 | 76 | #[cfg(feature = "serde1")] |
| @@ -118,6 +144,7 @@ pub fn receive<P, W: io::Write>( · 67 unmodified lines | ||
| 118 | 144 | protocol: Option<Protocol>, |
| 119 | 145 | url: &str, |
| 120 | 146 | directory: Option<PathBuf>, |
| 147 | + write_refs: bool, | |
| 121 | 148 | progress: P, |
| 122 | 149 | ctx: Context<W>, |
| 123 | 150 | ) -> anyhow::Result<()> |
| @@ -127,7 +154,11 @@ where · 3 unmodified lines | ||
| 127 | 154 | <<P as Progress>::SubProgress as Progress>::SubProgress: Send, |
| 128 | 155 | { |
| 129 | 156 | let transport = git_protocol::git_transport::client::connect(url.as_bytes(), protocol.unwrap_or_default().into())?; |
| 130 | − let mut delegate = CloneDelegate { ctx, directory }; | |
| 157 | + let mut delegate = CloneDelegate { | |
| 158 | + ctx, | |
| 159 | + directory, | |
| 160 | + write_refs, | |
| 161 | + }; | |
| 131 | 162 | git_protocol::fetch(transport, &mut delegate, git_protocol::credentials::helper, progress)?; |
| 132 | 163 | Ok(()) |
| 133 | 164 | } |
| @@ -53,12 +53,14 @@ pub fn main() -> Result<()> { · 52 unmodified lines | ||
| 53 | 53 | protocol, |
| 54 | 54 | url, |
| 55 | 55 | directory, |
| 56 | + write_refs, | |
| 56 | 57 | }) => { |
| 57 | 58 | let (_handle, progress) = prepare(verbose, "pack-receive", core::pack::receive::PROGRESS_RANGE); |
| 58 | 59 | core::pack::receive( |
| 59 | 60 | protocol, |
| 60 | 61 | &url, |
| 61 | 62 | directory, |
| 63 | + write_refs, | |
| 62 | 64 | progress::DoOrDiscard::from(progress), |
| 63 | 65 | core::pack::receive::Context { |
| 64 | 66 | thread_limit, |
| @@ -92,6 +92,10 @@ pub struct PackReceive { · 91 unmodified lines | ||
| 92 | 92 | #[argh(option, short = 'p')] |
| 93 | 93 | pub protocol: Option<core::Protocol>, |
| 94 | 94 | |
| 95 | + /// write references to the given directory as well, right next to the pack and index file. | |
| 96 | + #[argh(switch, short = 'r')] | |
| 97 | + pub write_refs: bool, | |
| 98 | + | |
| 95 | 99 | /// the URLs or path from which to receive the pack. |
| 96 | 100 | /// |
| 97 | 101 | /// See here for a list of supported URLs: https://www.git-scm.com/docs/git-clone#_git_urls |
| @@ -127,6 +127,7 @@ pub fn main() -> Result<()> { · 126 unmodified lines | ||
| 127 | 127 | match cmd { |
| 128 | 128 | Subcommands::PackReceive { |
| 129 | 129 | protocol, |
| 130 | + write_refs, | |
| 130 | 131 | url, |
| 131 | 132 | directory, |
| 132 | 133 | } => prepare_and_run( |
| @@ -140,6 +141,7 @@ pub fn main() -> Result<()> { · 7 unmodified lines | ||
| 140 | 141 | protocol, |
| 141 | 142 | &url, |
| 142 | 143 | directory, |
| 144 | + write_refs, | |
| 143 | 145 | git_features::progress::DoOrDiscard::from(progress), |
| 144 | 146 | core::pack::receive::Context { |
| 145 | 147 | thread_limit, |
| @@ -49,6 +49,10 @@ pub enum Subcommands { · 48 unmodified lines | ||
| 49 | 49 | #[clap(long, short = "p")] |
| 50 | 50 | protocol: Option<core::Protocol>, |
| 51 | 51 | |
| 52 | + /// Write references to the given directory as well, right next to the pack and index file. | |
| 53 | + #[clap(long, short = "r")] | |
| 54 | + write_refs: bool, | |
| 55 | + | |
| 52 | 56 | /// The URLs or path from which to receive the pack. |
| 53 | 57 | /// |
| 54 | 58 | /// See here for a list of supported URLs: https://www.git-scm.com/docs/git-clone#_git_urls |
| @@ -0,0 +1 @@ | ||
| 1 | +ee3c97678e89db4eab7420b04aef51758359f152 | |
| @@ -0,0 +1 @@ | ||
| 1 | +3f72b39ad1600e6dac63430c15e0d875e9d3f9d6 | |
| @@ -0,0 +1 @@ | ||
| 1 | +feae03400632392a7f38e5b2775f98a439f5eaf5 | |
| @@ -0,0 +1 @@ | ||
| 1 | +efa596d621559707b2d221f10490959b2decbc6c | |
| @@ -106,6 +106,15 @@ snapshot="$snapshot/plumbing" · 105 unmodified lines | ||
| 106 | 106 | WITH_SNAPSHOT="$snapshot/ls-in-output-dir" \ |
| 107 | 107 | expect_run $SUCCESSFULLY ls out/ |
| 108 | 108 | } |
| 109 | + (with "--write-refs set" | |
| 110 | + it "generates the correct output" && { | |
| 111 | + WITH_SNAPSHOT="$snapshot/file-v-any-with-output" \ | |
| 112 | + expect_run $SUCCESSFULLY "$exe_plumbing" pack-receive -p 1 --write-refs .git out/ | |
| 113 | + } | |
| 114 | + it "writes references into the refs folder of the output directory" && { | |
| 115 | + expect_snapshot "$snapshot/repo-refs" out/refs | |
| 116 | + } | |
| 117 | + ) | |
| 109 | 118 | ) |
| 110 | 119 | if test "$kind" = "max"; then |
| 111 | 120 | (with "--format json" |