///|
fn normalize_repo_path_internal(path : String) -> String {
let parts : Array[String] = []
for part_view in path.split("/") {
let part = part_view.to_owned()
if part == "" || part == "." {
continue
} else if part == ".." {
if parts.length() > 0 && parts[parts.length() - 1] != ".." {
let _ = parts.pop()
} else if !path.has_prefix("/") {
parts.push(part)
}
} else {
parts.push(part)
}
}
let result = parts.join("/")
if path.has_prefix("/") {
if result.length() == 0 {
"/"
} else {
"/" + result
}
} else if result.length() == 0 {
"."
} else {
result
}
}
///|
pub fn normalize_repo_path(path : String) -> String raise @bit.GitError {
let normalized = normalize_repo_path_internal(path)
let stripped = if normalized.has_prefix("/") && normalized.length() > 1 {
String::unsafe_substring(normalized, start=1, end=normalized.length())
} else {
normalized
}
if stripped == "." || stripped == "/" || stripped.length() == 0 {
raise @bit.GitError::InvalidObject("path required")
}
if stripped == ".." || stripped.has_prefix("../") {
raise @bit.GitError::InvalidObject(
"path must not traverse outside repository",
)
}
stripped
}
///|
fn split_path_parts(path : String) -> Array[String] {
path.split("/").filter(s => s.length() > 0).map(s => s.to_owned()).collect()
}
///|
pub fn find_tree_entry(
db : ObjectDb,
fs : &@bit.RepoFileSystem,
tree_id : @bit.ObjectId,
path : String,
) -> @bit.TreeEntry? raise @bit.GitError {
let parts = split_path_parts(path)
if parts.length() == 0 {
return None
}
let mut current = tree_id
for i in 0.. return None
Some(entry) =>
if i == parts.length() - 1 {
return Some(entry)
} else {
let is_tree = entry.mode == "40000" || entry.mode == "040000"
if !is_tree {
return None
}
current = entry.id
}
}
}
None
}