///| Helpers for compatObjectFormat repositories.
///|
fn compat_hash_algorithm_name(algo : @object.HashAlgorithm) -> String {
match algo {
@object.HashAlgorithm::Sha1 => "sha1"
@object.HashAlgorithm::Sha256 => "sha256"
}
}
///|
pub fn repo_hash_algorithm(
rfs : &@bit.RepoFileSystem,
git_dir : String,
) -> @object.HashAlgorithm {
match
read_config_value(rfs, git_dir + "/config", "extensions", "objectformat") {
Some(raw) =>
if config_strip_quotes(raw).to_lower() == "sha256" {
@object.HashAlgorithm::Sha256
} else {
@object.HashAlgorithm::Sha1
}
None => @object.HashAlgorithm::Sha1
}
}
///|
pub fn repo_compat_hash_algorithm(
rfs : &@bit.RepoFileSystem,
git_dir : String,
) -> @object.HashAlgorithm? {
let storage_algo = repo_hash_algorithm(rfs, git_dir)
match
read_config_value(
rfs,
git_dir + "/config",
"extensions",
"compatobjectformat",
) {
Some(raw) => {
let normalized = config_strip_quotes(raw).to_lower()
if normalized.length() == 0 ||
normalized == compat_hash_algorithm_name(storage_algo) {
None
} else if normalized == "sha256" {
Some(@object.HashAlgorithm::Sha256)
} else if normalized == "sha1" {
Some(@object.HashAlgorithm::Sha1)
} else {
None
}
}
None => None
}
}
///|
pub fn compat_lookup_loose_object_idx(
rfs : &@bit.RepoFileSystem,
git_dir : String,
spec : String,
) -> String? {
let idx_path = git_dir + "/objects/loose-object-idx"
if !rfs.is_file(idx_path) {
return None
}
let text = @utf8.decode_lossy(
rfs.read_file(idx_path) catch {
_ => return None
},
)
for line_view in text.split("\n") {
let line = line_view.to_owned().trim().to_owned()
if line.length() == 0 || line.has_prefix("#") {
continue
}
let cols : Array[String] = []
for col_view in line.split(" ") {
let col = col_view.to_owned().trim().to_owned()
if col.length() > 0 {
cols.push(col)
}
}
if cols.length() < 2 {
continue
}
let a = cols[0]
let b = cols[1]
if spec == a {
return Some(b)
}
if spec == b {
return Some(a)
}
}
None
}
///|
pub fn compat_lookup_object_id(
rfs : &@bit.RepoFileSystem,
git_dir : String,
id : @bit.ObjectId,
) -> @bit.ObjectId? {
match compat_lookup_loose_object_idx(rfs, git_dir, id.to_hex()) {
Some(mapped_hex) =>
Some(@bit.ObjectId::from_hex(mapped_hex)) catch {
_ => None
}
None => None
}
}
///|
pub fn compat_append_loose_object_idx(
fs : &@bit.FileSystem,
rfs : &@bit.RepoFileSystem,
git_dir : String,
storage_id : @bit.ObjectId,
compat_id : @bit.ObjectId,
) -> Unit raise @bit.GitError {
let storage_hex = storage_id.to_hex()
let compat_hex = compat_id.to_hex()
if storage_hex == compat_hex {
return
}
match compat_lookup_loose_object_idx(rfs, git_dir, storage_hex) {
Some(mapped) if mapped == compat_hex => return
_ => ()
}
let idx_path = git_dir + "/objects/loose-object-idx"
let mut text = if rfs.is_file(idx_path) {
@utf8.decode_lossy(rfs.read_file(idx_path) catch { _ => @utf8.encode("") })
} else {
"# loose-object-idx\n"
}
if text.length() == 0 {
text = "# loose-object-idx\n"
} else if !text.has_suffix("\n") {
text = text + "\n"
}
text += "\{storage_hex} \{compat_hex}\n"
fs.mkdir_p(git_dir + "/objects")
fs.write_file(idx_path, @utf8.encode(text))
}
///|
pub fn compat_record_blob_mapping(
fs : &@bit.FileSystem,
rfs : &@bit.RepoFileSystem,
git_dir : String,
storage_id : @bit.ObjectId,
content : Bytes,
) -> Unit raise @bit.GitError {
guard repo_compat_hash_algorithm(rfs, git_dir) is Some(compat_algo) else {
return
}
let compat_id = @object.hash_object_content_with_algo(
compat_algo,
@bit.ObjectType::Blob,
content,
)
compat_append_loose_object_idx(fs, rfs, git_dir, storage_id, compat_id)
}
///|
pub fn compat_record_tree_mapping(
fs : &@bit.FileSystem,
rfs : &@bit.RepoFileSystem,
git_dir : String,
storage_id : @bit.ObjectId,
entries : Array[@bit.TreeEntry],
) -> Unit raise @bit.GitError {
guard repo_compat_hash_algorithm(rfs, git_dir) is Some(compat_algo) else {
return
}
let compat_entries : Array[@bit.TreeEntry] = []
for entry in entries {
guard compat_lookup_object_id(rfs, git_dir, entry.id) is Some(mapped_id) else {
return
}
compat_entries.push(@bit.TreeEntry::new(entry.mode, entry.name, mapped_id))
}
let (compat_id, _) = @object.create_tree_with_algo(
compat_algo, compat_entries,
)
compat_append_loose_object_idx(fs, rfs, git_dir, storage_id, compat_id)
}
///|
pub fn compat_record_commit_mapping(
fs : &@bit.FileSystem,
rfs : &@bit.RepoFileSystem,
git_dir : String,
storage_id : @bit.ObjectId,
commit : @bit.Commit,
) -> Unit raise @bit.GitError {
guard repo_compat_hash_algorithm(rfs, git_dir) is Some(compat_algo) else {
return
}
guard compat_lookup_object_id(rfs, git_dir, commit.tree) is Some(compat_tree) else {
return
}
let compat_parents : Array[@bit.ObjectId] = []
for parent in commit.parents {
guard compat_lookup_object_id(rfs, git_dir, parent) is Some(mapped_parent) else {
return
}
compat_parents.push(mapped_parent)
}
let compat_commit = @bit.Commit::new(
compat_tree,
compat_parents,
commit.author,
commit.author_time,
commit.author_tz,
commit.committer,
commit.commit_time,
commit.committer_tz,
commit.message,
encoding=commit.encoding,
verbatim_message=commit.verbatim_message,
)
let (compat_id, _) = @object.create_commit_with_algo(
compat_algo, compat_commit,
)
compat_append_loose_object_idx(fs, rfs, git_dir, storage_id, compat_id)
}
///|
pub fn compat_record_annotated_tag_mapping(
fs : &@bit.FileSystem,
rfs : &@bit.RepoFileSystem,
git_dir : String,
storage_id : @bit.ObjectId,
target : @bit.ObjectId,
target_type : String,
name : String,
message : String,
tagger : String,
timestamp : Int64,
timezone : String,
) -> Unit raise @bit.GitError {
guard repo_compat_hash_algorithm(rfs, git_dir) is Some(compat_algo) else {
return
}
guard compat_lookup_object_id(rfs, git_dir, target) is Some(compat_target) else {
return
}
let tag_content = if message.length() == 0 {
"object \{compat_target.to_hex()}\ntype \{target_type}\ntag \{name}\ntagger \{tagger} \{timestamp} \{timezone}\n\n"
} else {
"object \{compat_target.to_hex()}\ntype \{target_type}\ntag \{name}\ntagger \{tagger} \{timestamp} \{timezone}\n\n\{message}\n"
}
let (compat_id, _) = @object.create_object_with_algo(
compat_algo,
@bit.ObjectType::Tag,
@utf8.encode(tag_content),
)
compat_append_loose_object_idx(fs, rfs, git_dir, storage_id, compat_id)
}