use std::{collections::HashSet, path::PathBuf}; use clap::Parser; use git_branchless_opts::{ResolveRevsetOptions, Revset}; use git_branchless_revset::resolve_commits; use git_branchless_submit::phabricator; use lib::core::dag::{sorted_commit_set, Dag}; use lib::core::effects::Effects; use lib::core::eventlog::{EventLogDb, EventReplayer}; use lib::core::formatting::Glyphs; use lib::core::repo_ext::RepoExt; use lib::git::{GitRunInfo, NonZeroOid, Repo}; #[derive(Debug, Parser)] struct Opts { #[clap(short = 'C', long = "working-directory")] working_directory: Option, #[clap(default_value = ".")] revset: Revset, } fn main() -> eyre::Result<()> { let Opts { working_directory, revset, } = Opts::try_parse()?; match working_directory { Some(working_directory) => { std::env::set_current_dir(working_directory)?; } None => { eprintln!("Warning: --working-directory was not passed, so running in current directory. But git-branchless is not hosted on Phabricator, so this seems unlikely to be useful, since there will be no assocated Phabricator information. Try running in your repository."); } } let effects = Effects::new(Glyphs::detect()); let git_run_info = GitRunInfo { path_to_git: "git".into(), working_directory: std::env::current_dir()?, env: Default::default(), }; let repo = Repo::from_current_dir()?; let conn = repo.get_db_conn()?; let event_log_db = EventLogDb::new(&conn)?; let event_replayer = EventReplayer::from_event_log_db(&effects, &repo, &event_log_db)?; let event_cursor = event_replayer.make_default_cursor(); let references_snapshot = repo.get_references_snapshot()?; let mut dag = Dag::open_and_sync( &effects, &repo, &event_replayer, event_cursor, &references_snapshot, )?; let resolved_commits = resolve_commits( &effects, &repo, &mut dag, &[revset.clone()], &ResolveRevsetOptions { show_hidden_commits: false, }, )?; let commits = match resolved_commits.as_slice() { [commits] => commits, other => eyre::bail!("Unexpected number of returned commit sets for {revset}: {other:?}"), }; let commit_oids: HashSet = dag.commit_set_to_vec(commits)?.into_iter().collect(); let commits = sorted_commit_set(&repo, &dag, commits)?; let phabricator = phabricator::PhabricatorForge { effects: &effects, git_run_info: &git_run_info, repo: &repo, dag: &mut dag, event_log_db: &event_log_db, revset: &revset, }; let dependency_oids = phabricator.query_remote_dependencies(commit_oids)?; for commit in commits { println!( "Dependencies for {} {}:", revision_id_str(&phabricator, commit.get_oid())?, effects .get_glyphs() .render(commit.friendly_describe(effects.get_glyphs())?)? ); let dependency_oids = &dependency_oids[&commit.get_oid()]; if dependency_oids.is_empty() { println!("- "); } else { for dependency_oid in dependency_oids { let dependency_commit = repo.find_commit_or_fail(*dependency_oid)?; println!( "- {} {}", revision_id_str(&phabricator, *dependency_oid)?, effects .get_glyphs() .render(dependency_commit.friendly_describe(effects.get_glyphs())?)? ); } } } Ok(()) } fn revision_id_str( phabricator: &phabricator::PhabricatorForge, commit_oid: NonZeroOid, ) -> eyre::Result { let id = phabricator.get_revision_id(commit_oid)?; let revision_id = match id.as_ref() { Some(phabricator::Id(id)) => id, None => "???", }; Ok(format!("D{revision_id}")) }