Break up GitSource
authorYehuda Katz <wycats@gmail.com>
Fri, 30 May 2014 03:35:09 +0000 (20:35 -0700)
committerYehuda Katz <wycats@gmail.com>
Fri, 30 May 2014 03:35:09 +0000 (20:35 -0700)
src/cargo/sources/git.rs [deleted file]
src/cargo/sources/git/mod.rs [new file with mode: 0644]
src/cargo/sources/git/source.rs [new file with mode: 0644]
src/cargo/sources/git/utils.rs [new file with mode: 0644]

diff --git a/src/cargo/sources/git.rs b/src/cargo/sources/git.rs
deleted file mode 100644 (file)
index f2bc69f..0000000
+++ /dev/null
@@ -1,337 +0,0 @@
-#![allow(dead_code)]
-
-use url::Url;
-use util::{CargoResult,ProcessBuilder,io_error,human_error,process};
-use std::fmt;
-use std::fmt::{Show,Formatter};
-use std::str;
-use std::io::{UserDir,AllPermissions};
-use std::io::fs::{mkdir_recursive,rmdir_recursive,chmod};
-use serialize::{Encodable,Encoder};
-use core::source::Source;
-use core::{NameVer,Package,Summary};
-use ops;
-
-#[deriving(Eq,Clone,Encodable)]
-enum GitReference {
-    Master,
-    Other(String)
-}
-
-impl GitReference {
-    pub fn for_str<S: Str>(string: S) -> GitReference {
-        if string.as_slice() == "master" {
-            Master
-        } else {
-            Other(string.as_slice().to_str())
-        }
-    }
-}
-
-impl Str for GitReference {
-    fn as_slice<'a>(&'a self) -> &'a str {
-        match *self {
-            Master => "master",
-            Other(ref string) => string.as_slice()
-        }
-    }
-}
-
-impl Show for GitReference {
-    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
-        self.as_slice().fmt(f)
-    }
-}
-
-pub struct GitSource {
-    remote: GitRemote,
-    reference: GitReference,
-    db_path: Path,
-    checkout_path: Path,
-    verbose: bool
-}
-
-impl GitSource {
-    pub fn new(remote: GitRemote, reference: String, db: Path, checkout: Path, verbose: bool) -> GitSource {
-        GitSource { remote: remote, reference: GitReference::for_str(reference), db_path: db, checkout_path: checkout, verbose: verbose }
-    }
-}
-
-impl Show for GitSource {
-    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
-        try!(write!(f, "git repo at {}", self.remote.url));
-
-        match self.reference {
-            Master => Ok(()),
-            Other(ref reference) => write!(f, " ({})", reference)
-        }
-    }
-}
-
-impl Source for GitSource {
-    fn update(&self) -> CargoResult<()> {
-        let repo = try!(self.remote.checkout(&self.db_path));
-        try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path));
-
-        Ok(())
-    }
-
-    fn list(&self) -> CargoResult<Vec<Summary>> {
-        let pkg = try!(read_manifest(&self.checkout_path));
-        Ok(vec!(pkg.get_summary().clone()))
-    }
-
-    fn download(&self, _: &[NameVer]) -> CargoResult<()> {
-        Ok(())
-    }
-
-    fn get(&self, packages: &[NameVer]) -> CargoResult<Vec<Package>> {
-        let pkg = try!(read_manifest(&self.checkout_path));
-
-        if packages.iter().any(|nv| pkg.is_for_name_ver(nv)) {
-            Ok(vec!(pkg))
-        } else {
-            Ok(vec!())
-        }
-    }
-}
-
-macro_rules! git(
-    ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => (
-        try!(git_inherit(&$config, $verbose, format!($str, $($rest),*)))
-    );
-
-    ($config:expr, $verbose:expr, $str:expr) => (
-        try!(git_inherit(&$config, $verbose, format!($str)))
-    );
-)
-
-macro_rules! git_output(
-    ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => (
-        try!(git_output(&$config, $verbose, format!($str, $($rest),*)))
-    );
-
-    ($config:expr, $verbose:expr, $str:expr) => (
-        try!(git_output(&$config, $verbose, format!($str)))
-    );
-)
-
-macro_rules! errln(
-    ($($arg:tt)*) => (let _ = writeln!(::std::io::stdio::stderr(), $($arg)*))
-)
-
-/**
- * GitRemote represents a remote repository. It gets cloned into a local GitDatabase.
- */
-
-#[deriving(Eq,Clone)]
-pub struct GitRemote {
-    url: Url,
-    verbose: bool
-}
-
-#[deriving(Eq,Clone,Encodable)]
-struct EncodableGitRemote {
-    url: String
-}
-
-impl<E, S: Encoder<E>> Encodable<S, E> for GitRemote {
-    fn encode(&self, s: &mut S) -> Result<(), E> {
-        EncodableGitRemote {
-            url: self.url.to_str()
-        }.encode(s)
-    }
-}
-
-/**
- * GitDatabase is a local clone of a remote repository's database. Multiple GitCheckouts
- * can be cloned from this GitDatabase.
- */
-
-#[deriving(Eq,Clone)]
-pub struct GitDatabase {
-    remote: GitRemote,
-    path: Path,
-    verbose: bool
-}
-
-#[deriving(Encodable)]
-pub struct EncodableGitDatabase {
-    remote: GitRemote,
-    path: String
-}
-
-impl<E, S: Encoder<E>> Encodable<S, E> for GitDatabase {
-    fn encode(&self, s: &mut S) -> Result<(), E> {
-        EncodableGitDatabase {
-            remote: self.remote.clone(),
-            path: self.path.display().to_str()
-        }.encode(s)
-    }
-}
-
-/**
- * GitCheckout is a local checkout of a particular revision. Calling `clone_into` with
- * a reference will resolve the reference into a revision, and return a CargoError
- * if no revision for that reference was found.
- */
-
-pub struct GitCheckout {
-    database: GitDatabase,
-    location: Path,
-    reference: GitReference,
-    revision: String,
-    verbose: bool
-}
-
-#[deriving(Encodable)]
-pub struct EncodableGitCheckout {
-    database: GitDatabase,
-    location: String,
-    reference: String,
-    revision: String
-}
-
-impl<E, S: Encoder<E>> Encodable<S, E> for GitCheckout {
-    fn encode(&self, s: &mut S) -> Result<(), E> {
-        EncodableGitCheckout {
-            database: self.database.clone(),
-            location: self.location.display().to_str(),
-            reference: self.reference.to_str(),
-            revision: self.revision.to_str()
-        }.encode(s)
-    }
-}
-
-/**
- * Implementations
- */
-
-impl GitRemote {
-    pub fn new(url: Url, verbose: bool) -> GitRemote {
-        GitRemote { url: url, verbose: verbose }
-    }
-
-    pub fn checkout(&self, into: &Path) -> CargoResult<GitDatabase> {
-        if into.exists() {
-            // TODO: If the revision we have is a rev, avoid unnecessarily fetching if we have the rev already
-            try!(self.fetch_into(into));
-        } else {
-            try!(self.clone_into(into));
-        }
-
-        Ok(GitDatabase { remote: self.clone(), path: into.clone(), verbose: self.verbose })
-    }
-
-    fn fetch_into(&self, path: &Path) -> CargoResult<()> {
-        Ok(git!(*path, self.verbose, "fetch --force --quiet --tags {} refs/heads/*:refs/heads/*", self.url))
-    }
-
-    fn clone_into(&self, path: &Path) -> CargoResult<()> {
-        let dirname = Path::new(path.dirname());
-
-        try!(mkdir_recursive(path, UserDir).map_err(|err|
-            human_error(format!("Couldn't recursively create `{}`", dirname.display()), format!("path={}", dirname.display()), io_error(err))));
-
-        Ok(git!(dirname, self.verbose, "clone {} {} --bare --no-hardlinks --quiet", self.url, path.display()))
-    }
-}
-
-impl GitDatabase {
-    fn get_path<'a>(&'a self) -> &'a Path {
-        &self.path
-    }
-
-    pub fn copy_to<S: Str>(&self, reference: S, dest: &Path) -> CargoResult<GitCheckout> {
-        let verbose = self.verbose;
-        let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice()), verbose));
-
-        try!(checkout.fetch());
-        try!(checkout.update_submodules());
-
-        Ok(checkout)
-    }
-
-    pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<String> {
-        Ok(git_output!(self.path, self.verbose, "rev-parse {}", reference.as_slice()))
-    }
-
-}
-
-impl GitCheckout {
-    fn clone_into(into: &Path, database: GitDatabase, reference: GitReference, verbose: bool) -> CargoResult<GitCheckout> {
-        let revision = try!(database.rev_for(reference.as_slice()));
-        let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision, verbose: verbose };
-
-        // If the git checkout already exists, we don't need to clone it again
-        if !checkout.location.join(".git").exists() {
-            try!(checkout.clone_repo());
-        }
-
-        Ok(checkout)
-    }
-
-    fn get_source<'a>(&'a self) -> &'a Path {
-        self.database.get_path()
-    }
-
-    fn clone_repo(&self) -> CargoResult<()> {
-        let dirname = Path::new(self.location.dirname());
-
-        try!(mkdir_recursive(&dirname, UserDir).map_err(|e|
-            human_error(format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display()), None::<&str>, io_error(e))));
-
-        if self.location.exists() {
-            try!(rmdir_recursive(&self.location).map_err(|e|
-                human_error(format!("Couldn't rmdir {}", Path::new(&self.location).display()), None::<&str>, io_error(e))));
-        }
-
-        git!(dirname, self.verbose, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display());
-        try!(chmod(&self.location, AllPermissions).map_err(io_error));
-
-        Ok(())
-    }
-
-    fn fetch(&self) -> CargoResult<()> {
-        git!(self.location, self.verbose, "fetch --force --quiet --tags {}", self.get_source().display());
-        try!(self.reset(self.revision.as_slice()));
-        Ok(())
-    }
-
-    fn reset<T: Show>(&self, revision: T) -> CargoResult<()> {
-        Ok(git!(self.location, self.verbose, "reset -q --hard {}", revision))
-    }
-
-    fn update_submodules(&self) -> CargoResult<()> {
-        Ok(git!(self.location, self.verbose, "submodule update --init --recursive --quiet"))
-    }
-}
-
-fn git(path: &Path, verbose: bool, str: &str) -> ProcessBuilder {
-    if verbose {
-        errln!("Executing git {} @ {}", str, path.display());
-    }
-
-    process("git").args(str.split(' ').collect::<Vec<&str>>().as_slice()).cwd(path.clone())
-}
-
-fn git_inherit(path: &Path, verbose: bool, str: String) -> CargoResult<()> {
-    git(path, verbose, str.as_slice()).exec().map_err(|err|
-        human_error(format!("Executing `git {}` failed: {}", str, err), None::<&str>, err))
-}
-
-fn git_output(path: &Path, verbose: bool, str: String) -> CargoResult<String> {
-    let output = try!(git(path, verbose, str.as_slice()).exec_with_output().map_err(|err|
-        human_error(format!("Executing `git {}` failed", str), None::<&str>, err)));
-
-    Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str())
-}
-
-fn to_str(vec: &[u8]) -> String {
-    str::from_utf8_lossy(vec).to_str()
-}
-
-fn read_manifest(path: &Path) -> CargoResult<Package> {
-    let joined = path.join("Cargo.toml");
-    ops::read_manifest(joined.as_str().unwrap())
-}
diff --git a/src/cargo/sources/git/mod.rs b/src/cargo/sources/git/mod.rs
new file mode 100644 (file)
index 0000000..f44594a
--- /dev/null
@@ -0,0 +1,4 @@
+pub use self::utils::{GitRemote,GitDatabase,GitCheckout};
+pub use self::source::{GitSource};
+mod utils;
+mod source;
diff --git a/src/cargo/sources/git/source.rs b/src/cargo/sources/git/source.rs
new file mode 100644 (file)
index 0000000..f1c5db2
--- /dev/null
@@ -0,0 +1,65 @@
+use ops;
+use core::source::Source;
+use core::{NameVer,Package,Summary};
+use util::CargoResult;
+use sources::git::utils::{GitReference,GitRemote,Master,Other};
+use std::fmt;
+use std::fmt::{Show,Formatter};
+
+pub struct GitSource {
+    remote: GitRemote,
+    reference: GitReference,
+    db_path: Path,
+    checkout_path: Path,
+    verbose: bool
+}
+
+impl GitSource {
+    pub fn new(remote: GitRemote, reference: String, db: Path, checkout: Path, verbose: bool) -> GitSource {
+        GitSource { remote: remote, reference: GitReference::for_str(reference), db_path: db, checkout_path: checkout, verbose: verbose }
+    }
+}
+
+impl Show for GitSource {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        try!(write!(f, "git repo at {}", self.remote.get_url()));
+
+        match self.reference {
+            Master => Ok(()),
+            Other(ref reference) => write!(f, " ({})", reference)
+        }
+    }
+}
+
+impl Source for GitSource {
+    fn update(&self) -> CargoResult<()> {
+        let repo = try!(self.remote.checkout(&self.db_path));
+        try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path));
+
+        Ok(())
+    }
+
+    fn list(&self) -> CargoResult<Vec<Summary>> {
+        let pkg = try!(read_manifest(&self.checkout_path));
+        Ok(vec!(pkg.get_summary().clone()))
+    }
+
+    fn download(&self, _: &[NameVer]) -> CargoResult<()> {
+        Ok(())
+    }
+
+    fn get(&self, packages: &[NameVer]) -> CargoResult<Vec<Package>> {
+        let pkg = try!(read_manifest(&self.checkout_path));
+
+        if packages.iter().any(|nv| pkg.is_for_name_ver(nv)) {
+            Ok(vec!(pkg))
+        } else {
+            Ok(vec!())
+        }
+    }
+}
+
+fn read_manifest(path: &Path) -> CargoResult<Package> {
+    let joined = path.join("Cargo.toml");
+    ops::read_manifest(joined.as_str().unwrap())
+}
diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs
new file mode 100644 (file)
index 0000000..50a3c7c
--- /dev/null
@@ -0,0 +1,279 @@
+use url::Url;
+use util::{CargoResult,ProcessBuilder,io_error,human_error,process};
+use std::fmt;
+use std::fmt::{Show,Formatter};
+use std::str;
+use std::io::{UserDir,AllPermissions};
+use std::io::fs::{mkdir_recursive,rmdir_recursive,chmod};
+use serialize::{Encodable,Encoder};
+
+#[deriving(Eq,Clone,Encodable)]
+pub enum GitReference {
+    Master,
+    Other(String)
+}
+
+impl GitReference {
+    pub fn for_str<S: Str>(string: S) -> GitReference {
+        if string.as_slice() == "master" {
+            Master
+        } else {
+            Other(string.as_slice().to_str())
+        }
+    }
+}
+
+impl Str for GitReference {
+    fn as_slice<'a>(&'a self) -> &'a str {
+        match *self {
+            Master => "master",
+            Other(ref string) => string.as_slice()
+        }
+    }
+}
+
+impl Show for GitReference {
+    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
+        self.as_slice().fmt(f)
+    }
+}
+
+
+macro_rules! git(
+    ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => (
+        try!(git_inherit(&$config, $verbose, format!($str, $($rest),*)))
+    );
+
+    ($config:expr, $verbose:expr, $str:expr) => (
+        try!(git_inherit(&$config, $verbose, format!($str)))
+    );
+)
+
+macro_rules! git_output(
+    ($config:expr, $verbose:expr, $str:expr, $($rest:expr),*) => (
+        try!(git_output(&$config, $verbose, format!($str, $($rest),*)))
+    );
+
+    ($config:expr, $verbose:expr, $str:expr) => (
+        try!(git_output(&$config, $verbose, format!($str)))
+    );
+)
+
+macro_rules! errln(
+    ($($arg:tt)*) => (let _ = writeln!(::std::io::stdio::stderr(), $($arg)*))
+)
+
+/**
+ * GitRemote represents a remote repository. It gets cloned into a local GitDatabase.
+ */
+
+#[deriving(Eq,Clone)]
+pub struct GitRemote {
+    url: Url,
+    verbose: bool
+}
+
+#[deriving(Eq,Clone,Encodable)]
+struct EncodableGitRemote {
+    url: String
+}
+
+impl<E, S: Encoder<E>> Encodable<S, E> for GitRemote {
+    fn encode(&self, s: &mut S) -> Result<(), E> {
+        EncodableGitRemote {
+            url: self.url.to_str()
+        }.encode(s)
+    }
+}
+
+/**
+ * GitDatabase is a local clone of a remote repository's database. Multiple GitCheckouts
+ * can be cloned from this GitDatabase.
+ */
+
+#[deriving(Eq,Clone)]
+pub struct GitDatabase {
+    remote: GitRemote,
+    path: Path,
+    verbose: bool
+}
+
+#[deriving(Encodable)]
+pub struct EncodableGitDatabase {
+    remote: GitRemote,
+    path: String
+}
+
+impl<E, S: Encoder<E>> Encodable<S, E> for GitDatabase {
+    fn encode(&self, s: &mut S) -> Result<(), E> {
+        EncodableGitDatabase {
+            remote: self.remote.clone(),
+            path: self.path.display().to_str()
+        }.encode(s)
+    }
+}
+
+/**
+ * GitCheckout is a local checkout of a particular revision. Calling `clone_into` with
+ * a reference will resolve the reference into a revision, and return a CargoError
+ * if no revision for that reference was found.
+ */
+
+pub struct GitCheckout {
+    database: GitDatabase,
+    location: Path,
+    reference: GitReference,
+    revision: String,
+    verbose: bool
+}
+
+#[deriving(Encodable)]
+pub struct EncodableGitCheckout {
+    database: GitDatabase,
+    location: String,
+    reference: String,
+    revision: String
+}
+
+impl<E, S: Encoder<E>> Encodable<S, E> for GitCheckout {
+    fn encode(&self, s: &mut S) -> Result<(), E> {
+        EncodableGitCheckout {
+            database: self.database.clone(),
+            location: self.location.display().to_str(),
+            reference: self.reference.to_str(),
+            revision: self.revision.to_str()
+        }.encode(s)
+    }
+}
+
+/**
+ * Implementations
+ */
+
+impl GitRemote {
+    pub fn new(url: Url, verbose: bool) -> GitRemote {
+        GitRemote { url: url, verbose: verbose }
+    }
+
+    pub fn get_url<'a>(&'a self) -> &'a Url {
+        &self.url
+    }
+
+    pub fn checkout(&self, into: &Path) -> CargoResult<GitDatabase> {
+        if into.exists() {
+            try!(self.fetch_into(into));
+        } else {
+            try!(self.clone_into(into));
+        }
+
+        Ok(GitDatabase { remote: self.clone(), path: into.clone(), verbose: self.verbose })
+    }
+
+    fn fetch_into(&self, path: &Path) -> CargoResult<()> {
+        Ok(git!(*path, self.verbose, "fetch --force --quiet --tags {} refs/heads/*:refs/heads/*", self.url))
+    }
+
+    fn clone_into(&self, path: &Path) -> CargoResult<()> {
+        let dirname = Path::new(path.dirname());
+
+        try!(mkdir_recursive(path, UserDir).map_err(|err|
+            human_error(format!("Couldn't recursively create `{}`", dirname.display()), format!("path={}", dirname.display()), io_error(err))));
+
+        Ok(git!(dirname, self.verbose, "clone {} {} --bare --no-hardlinks --quiet", self.url, path.display()))
+    }
+}
+
+impl GitDatabase {
+    fn get_path<'a>(&'a self) -> &'a Path {
+        &self.path
+    }
+
+    pub fn copy_to<S: Str>(&self, reference: S, dest: &Path) -> CargoResult<GitCheckout> {
+        let verbose = self.verbose;
+        let checkout = try!(GitCheckout::clone_into(dest, self.clone(), GitReference::for_str(reference.as_slice()), verbose));
+
+        try!(checkout.fetch());
+        try!(checkout.update_submodules());
+
+        Ok(checkout)
+    }
+
+    pub fn rev_for<S: Str>(&self, reference: S) -> CargoResult<String> {
+        Ok(git_output!(self.path, self.verbose, "rev-parse {}", reference.as_slice()))
+    }
+
+}
+
+impl GitCheckout {
+    fn clone_into(into: &Path, database: GitDatabase, reference: GitReference, verbose: bool) -> CargoResult<GitCheckout> {
+        let revision = try!(database.rev_for(reference.as_slice()));
+        let checkout = GitCheckout { location: into.clone(), database: database, reference: reference, revision: revision, verbose: verbose };
+
+        // If the git checkout already exists, we don't need to clone it again
+        if !checkout.location.join(".git").exists() {
+            try!(checkout.clone_repo());
+        }
+
+        Ok(checkout)
+    }
+
+    fn get_source<'a>(&'a self) -> &'a Path {
+        self.database.get_path()
+    }
+
+    fn clone_repo(&self) -> CargoResult<()> {
+        let dirname = Path::new(self.location.dirname());
+
+        try!(mkdir_recursive(&dirname, UserDir).map_err(|e|
+            human_error(format!("Couldn't mkdir {}", Path::new(self.location.dirname()).display()), None::<&str>, io_error(e))));
+
+        if self.location.exists() {
+            try!(rmdir_recursive(&self.location).map_err(|e|
+                human_error(format!("Couldn't rmdir {}", Path::new(&self.location).display()), None::<&str>, io_error(e))));
+        }
+
+        git!(dirname, self.verbose, "clone --no-checkout --quiet {} {}", self.get_source().display(), self.location.display());
+        try!(chmod(&self.location, AllPermissions).map_err(io_error));
+
+        Ok(())
+    }
+
+    fn fetch(&self) -> CargoResult<()> {
+        git!(self.location, self.verbose, "fetch --force --quiet --tags {}", self.get_source().display());
+        try!(self.reset(self.revision.as_slice()));
+        Ok(())
+    }
+
+    fn reset<T: Show>(&self, revision: T) -> CargoResult<()> {
+        Ok(git!(self.location, self.verbose, "reset -q --hard {}", revision))
+    }
+
+    fn update_submodules(&self) -> CargoResult<()> {
+        Ok(git!(self.location, self.verbose, "submodule update --init --recursive --quiet"))
+    }
+}
+
+fn git(path: &Path, verbose: bool, str: &str) -> ProcessBuilder {
+    if verbose {
+        errln!("Executing git {} @ {}", str, path.display());
+    }
+
+    process("git").args(str.split(' ').collect::<Vec<&str>>().as_slice()).cwd(path.clone())
+}
+
+fn git_inherit(path: &Path, verbose: bool, str: String) -> CargoResult<()> {
+    git(path, verbose, str.as_slice()).exec().map_err(|err|
+        human_error(format!("Executing `git {}` failed: {}", str, err), None::<&str>, err))
+}
+
+fn git_output(path: &Path, verbose: bool, str: String) -> CargoResult<String> {
+    let output = try!(git(path, verbose, str.as_slice()).exec_with_output().map_err(|err|
+        human_error(format!("Executing `git {}` failed", str), None::<&str>, err)));
+
+    Ok(to_str(output.output.as_slice()).as_slice().trim_right().to_str())
+}
+
+fn to_str(vec: &[u8]) -> String {
+    str::from_utf8_lossy(vec).to_str()
+}
+