mirror of
https://github.com/Twigpine/node.git
synced 2026-11-08 17:55:53 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f38e00e7fc | ||
|
|
227246fa11 | ||
|
|
c674f520ed |
+94
-8
@@ -80,14 +80,7 @@ pub async fn run(args: MirrorArgs) -> Result<()> {
|
||||
let _guard = TmpGuard(tmp_root);
|
||||
|
||||
println!("Cloning source (this may take a while for large repos)...");
|
||||
let clone_status = Command::new("git")
|
||||
.args(["clone", "--mirror", &source, mirror_path.to_str().unwrap()])
|
||||
.status()
|
||||
.context("failed to run git clone — is git installed?")?;
|
||||
|
||||
if !clone_status.success() {
|
||||
bail!("git clone --mirror failed\nCheck that the source URL is accessible: {source}");
|
||||
}
|
||||
clone_mirror(&source, &mirror_path)?;
|
||||
|
||||
// ── 4. Create the repo on gitlawb ─────────────────────────────────────
|
||||
println!("Creating repo on gitlawb node...");
|
||||
@@ -139,6 +132,25 @@ pub async fn run(args: MirrorArgs) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// `git clone --mirror <source> <dest>`. The destination is passed as an
|
||||
/// OS-native path so a non-UTF-8 temp dir (e.g. a TMPDIR with non-UTF-8 bytes)
|
||||
/// does not panic on a `to_str()` conversion.
|
||||
fn clone_mirror(source: &str, dest: &std::path::Path) -> Result<()> {
|
||||
// allow-unbounded-git: gl is the client CLI; this clone runs in the user's
|
||||
// terminal with no server-side permit or disconnect to survive. The
|
||||
// bounded-runner rule governs node request handlers. Same spawn as before,
|
||||
// only relocated into this helper.
|
||||
let status = Command::new("git")
|
||||
.args(["clone", "--mirror", source])
|
||||
.arg(dest)
|
||||
.status()
|
||||
.context("failed to run git clone — is git installed?")?;
|
||||
if !status.success() {
|
||||
bail!("git clone --mirror failed\nCheck that the source URL is accessible: {source}");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Extract the repo name from a git URL.
|
||||
/// - `https://github.com/owner/repo` → `"repo"`
|
||||
/// - `https://github.com/owner/repo.git` → `"repo"`
|
||||
@@ -221,6 +233,80 @@ mod tests {
|
||||
assert_eq!(extract_repo_name("https://example.com/.git"), None);
|
||||
}
|
||||
|
||||
// #417: a non-UTF-8 destination path must reach git as an OS-native arg, not
|
||||
// panic on a `to_str()` conversion.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_clone_mirror_non_utf8_dest() {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
let tmp = tempfile::TempDir::new().unwrap();
|
||||
let src = tmp.path().join("src.git");
|
||||
let st = Command::new("git")
|
||||
.args(["init", "--bare"])
|
||||
.arg(&src)
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(st.success());
|
||||
|
||||
let dest = tmp.path().join(OsStr::from_bytes(b"mirror-\xffdest"));
|
||||
clone_mirror(src.to_str().unwrap(), &dest).unwrap();
|
||||
assert!(dest.join("HEAD").exists());
|
||||
}
|
||||
|
||||
// #417 end-to-end: the real trigger is `std::env::temp_dir()` itself
|
||||
// returning a non-UTF-8 path (a TMPDIR with non-UTF-8 bytes), because the
|
||||
// mirror dest is built from it. Env is process-global, so this test
|
||||
// re-execs the test binary in a child with a non-UTF-8 TMPDIR rather than
|
||||
// mutating this process's env.
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_clone_mirror_under_non_utf8_tmpdir() {
|
||||
use std::ffi::OsStr;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
|
||||
if std::env::var_os("GL_MIRROR_NONUTF8_TMPDIR").is_none() {
|
||||
// Parent: a source repo under a normal path, a TMPDIR whose name
|
||||
// is not UTF-8, and a child run of this same test under that env.
|
||||
let parent = tempfile::TempDir::new().unwrap();
|
||||
let src = parent.path().join("src.git");
|
||||
let st = Command::new("git")
|
||||
.args(["init", "--bare"])
|
||||
.arg(&src)
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(st.success());
|
||||
let bad_tmp = parent.path().join(OsStr::from_bytes(b"tmp-\xff"));
|
||||
std::fs::create_dir_all(&bad_tmp).unwrap();
|
||||
|
||||
let status = Command::new(std::env::current_exe().unwrap())
|
||||
.args([
|
||||
"mirror::tests::test_clone_mirror_under_non_utf8_tmpdir",
|
||||
"--exact",
|
||||
])
|
||||
.env("GL_MIRROR_NONUTF8_TMPDIR", "1")
|
||||
.env("GL_MIRROR_SRC", &src)
|
||||
.env("TMPDIR", &bad_tmp)
|
||||
.status()
|
||||
.unwrap();
|
||||
assert!(status.success(), "child failed under non-UTF-8 TMPDIR");
|
||||
return;
|
||||
}
|
||||
|
||||
// Child: the same path shape run() computes — temp_dir() joined with
|
||||
// the mirror dest. It must be non-UTF-8 or the test proves nothing.
|
||||
let src = std::env::var("GL_MIRROR_SRC").unwrap();
|
||||
let tmp_root = std::env::temp_dir().join("gl-mirror-child");
|
||||
let dest = tmp_root.join("repo");
|
||||
assert!(
|
||||
dest.to_str().is_none(),
|
||||
"fixture broken: dest under a non-UTF-8 TMPDIR must be non-UTF-8"
|
||||
);
|
||||
clone_mirror(&src, &dest).unwrap();
|
||||
assert!(dest.join("HEAD").exists());
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_create_repo_conflict_error() {
|
||||
let mut server = mockito::Server::new_async().await;
|
||||
|
||||
Reference in new issue
Block a user