diff --git a/src/v2/context.in.rs b/src/v2/context.in.rs index 7974524..87ac67b 100644 --- a/src/v2/context.in.rs +++ b/src/v2/context.in.rs @@ -32,6 +32,17 @@ impl Context { Context::Dir(Path::new(&s_ref).to_owned()) } } + + /// Returns a new Context which is the same as the + /// this one, but without any subdirectory part + pub fn without_subdirectory(&self) -> Context { + match self { + &Context::Dir(_) => self.clone(), + &Context::GitUrl(ref git_url) => { + Context::GitUrl(git_url.without_subdirectory()) + }, + } + } } impl_interpolatable_value!(Context); @@ -80,3 +91,19 @@ fn context_may_contain_dir_paths() { assert_eq!(context.to_string(), path); } } + +#[test] +fn without_subdirectory_removes_the_optional_subdir() { + let dir: Context = FromStr::from_str("./foo").unwrap(); + let plain_repo: Context = FromStr::from_str("git@github.com:docker/docker.git").unwrap(); + let repo_with_branch: Context = FromStr::from_str("git@github.com:docker/docker.git#somebranch").unwrap(); + let repo_with_subdir: Context = FromStr::from_str("git@github.com:docker/docker.git#:somedir").unwrap(); + let repo_with_branch_and_subdir: Context = FromStr::from_str("git@github.com:docker/docker.git#somebranch:somedir").unwrap(); + + assert_eq!(dir, dir.without_subdirectory()); + assert_eq!(plain_repo, plain_repo.without_subdirectory()); + assert_eq!(repo_with_branch, repo_with_branch.without_subdirectory()); + + assert_eq!(plain_repo, repo_with_subdir.without_subdirectory()); + assert_eq!(repo_with_branch, repo_with_branch_and_subdir.without_subdirectory()); +} diff --git a/src/v2/git_url.rs b/src/v2/git_url.rs index ba6f38d..0ab89d4 100644 --- a/src/v2/git_url.rs +++ b/src/v2/git_url.rs @@ -71,6 +71,44 @@ impl GitUrl { } } } + + /// Returns a new GitUrl which is the same as the + /// this one, but without any subdirectory part + pub fn without_subdirectory(&self) -> GitUrl { + let (repository, branch, _) = self.parse_parts(); + let branch_str = match branch { + Some(branch) => format!("#{}", branch), + None => String::new(), + }; + GitUrl { url: format!("{}{}", repository, branch_str) } + } + + /// Extract the repository part of the URL + pub fn repository(&self) -> String { + self.parse_parts().0 + } + + /// Extract the optional branch part of the git URL + pub fn branch(&self) -> Option { + self.parse_parts().1 + } + + /// Extract the optional subdirectory part of the git URL + pub fn subdirectory(&self) -> Option { + self.parse_parts().2 + } + + fn parse_parts(&self) -> (String, Option, Option) { + lazy_static! { + static ref URL_PARSE: Regex = Regex::new(r#"^([^#]+)(#([^:]+)?(:(.+))?)?$"#).unwrap(); + } + let captures = URL_PARSE.captures(&self.url).unwrap(); + ( + captures.at(1).unwrap().to_string(), + captures.at(3).map(|branch| branch.to_string()), + captures.at(5).map(|branch| branch.to_string()), + ) + } } impl fmt::Display for GitUrl { @@ -134,3 +172,39 @@ fn to_url_converts_git_urls_to_real_ones() { assert!(GitUrl::new(url).is_err()); } } + +#[test] +fn it_can_extract_its_repo_branch_and_subdir_parts() { + let urls = &[ + "git://github.com/docker/docker", + "https://github.com/docker/docker.git", + "http://github.com/docker/docker.git", + "git@github.com:docker/docker.git", + "git@bitbucket.org:atlassianlabs/atlassian-docker.git", + "github.com/docker/docker.git", + ]; + + // Refs/folders specified as per: + // https://docs.docker.com/engine/reference/commandline/build/#git-repositories + for &url in urls { + let plain = GitUrl::new(url).unwrap(); + assert_eq!(plain.repository(), url); + assert_eq!(plain.branch(), None); + assert_eq!(plain.subdirectory(), None); + + let with_ref = GitUrl::new(format!("{}{}", url, "#mybranch")).unwrap(); + assert_eq!(with_ref.repository(), url); + assert_eq!(with_ref.branch(), Some("mybranch".to_string())); + assert_eq!(with_ref.subdirectory(), None); + + let with_subdir = GitUrl::new(format!("{}{}", url, "#:myfolder")).unwrap(); + assert_eq!(with_subdir.repository(), url); + assert_eq!(with_subdir.branch(), None); + assert_eq!(with_subdir.subdirectory(), Some("myfolder".to_string())); + + let with_ref_and_subdir = GitUrl::new(format!("{}{}", url, "#mybranch:myfolder")).unwrap(); + assert_eq!(with_ref_and_subdir.repository(), url); + assert_eq!(with_ref_and_subdir.branch(), Some("mybranch".to_string())); + assert_eq!(with_ref_and_subdir.subdirectory(), Some("myfolder".to_string())); + } +}