///|
fn hub_active_issues_path(git_dir : String) -> String {
git_dir + "/hub/active-issues"
}
///|
/// Parse newline-separated entries, skip blank lines.
fn parse_active_issues(content : String) -> Array[String] {
let result : Array[String] = []
if content.length() == 0 {
return result
}
for line_view in content.split("\n") {
let trimmed = line_view.to_owned().trim().to_owned()
if trimmed.length() > 0 {
result.push(trimmed)
}
}
result
}
///|
/// Join entries with newlines.
fn serialize_active_issues(entries : Array[String]) -> String {
let buf = StringBuilder()
for entry in entries {
buf.write_string(entry)
buf.write_char('\n')
}
buf.to_string()
}
///|
/// Add if not already present (no duplicates).
fn add_active_issue(
entries : Array[String],
issue_ref : String,
) -> Array[String] {
for entry in entries {
if entry == issue_ref {
return entries
}
}
let result = entries.copy()
result.push(issue_ref)
result
}
///|
/// Filter out matching entry.
fn remove_active_issue(
entries : Array[String],
issue_ref : String,
) -> Array[String] {
entries.filter(fn(entry) { entry != issue_ref })
}
///|
/// Load active issues from git_dir/hub/active-issues file.
fn load_active_issues(git_dir : String) -> Array[String] {
let fs = OsFs::new()
let path = hub_active_issues_path(git_dir)
if !fs.is_file(path) {
return []
}
let bytes = fs.read_file(path) catch { _ => return [] }
let content = @utf8.decode_lossy(bytes[:]).to_string()
parse_active_issues(content)
}
///|
/// Save active issues to git_dir/hub/active-issues file.
fn save_active_issues(
git_dir : String,
entries : Array[String],
) -> Unit raise Error {
let fs = OsFs::new()
let path = hub_active_issues_path(git_dir)
let dir = match path.rev_find("/") {
Some(idx) => String::unsafe_substring(path, start=0, end=idx)
None => "."
}
fs.mkdir_p(dir)
let content = serialize_active_issues(entries)
fs.write_string(path, content)
}
///|
async fn handle_hub_issue_start(args : Array[String]) -> Unit raise Error {
if args.length() == 0 {
eprint_line("Usage: git-bit issue start [")
@sys.exit(1)
}
let issue_ref = args[0]
let root = get_work_root()
let git_dir = resolve_hub_git_dir(root)
let entries = load_active_issues(git_dir)
let updated = add_active_issue(entries, issue_ref)
save_active_issues(git_dir, updated)
print_line("Added \{issue_ref} to active issues")
}
///|
async fn handle_hub_issue_stop(args : Array[String]) -> Unit raise Error {
if args.length() == 0 {
eprint_line("Usage: git-bit issue stop ][")
@sys.exit(1)
}
let issue_ref = args[0]
let root = get_work_root()
let git_dir = resolve_hub_git_dir(root)
let entries = load_active_issues(git_dir)
let updated = remove_active_issue(entries, issue_ref)
save_active_issues(git_dir, updated)
print_line("Removed \{issue_ref} from active issues")
}
///|
async fn handle_hub_issue_active(_args : Array[String]) -> Unit raise Error {
let root = get_work_root()
let git_dir = resolve_hub_git_dir(root)
let entries = load_active_issues(git_dir)
if entries.length() == 0 {
print_line("No active issues")
return
}
let home = @env.get_env_var("HOME").unwrap_or("/")
let aliases = load_aliases(git_dir)
for entry in entries {
let (repo_ref, issue_id) = parse_cross_repo_ref(entry)
let target_git_dir = if repo_ref.length() > 0 {
try {
let remote_path = resolve_repo_ref_to_path(repo_ref, home, aliases~)
resolve_hub_git_dir(remote_path)
} catch {
_ => {
print_line("\{entry} (repo not found)")
continue
}
}
} else {
git_dir
}
let (objects, refs, _clock) = make_hub_stores(target_git_dir)
let hub = load_hub_store(objects, refs) catch {
_ => {
print_line("\{entry} (hub not initialized)")
continue
}
}
match hub.get_issue(objects, issue_id) {
Some(issue) => {
let prefix = if repo_ref.length() > 0 { repo_ref + "#" } else { "#" }
print_line("\{prefix}\{issue.id} [\{issue.state}] \{issue.title}")
}
None => print_line("\{entry} (issue not found)")
}
}
}
]