From 1e95aa7293ded72ff1c2777e6aed8c4b14f69d77 Mon Sep 17 00:00:00 2001 From: Kostia Balytskyi Date: Tue, 21 Apr 2020 02:27:29 -0700 Subject: [PATCH] admin: move subcommand definitions into subcommand files Summary: This feels like a more natural place to store them. Also, it will make `main.rs` more readable. Reviewed By: StanislavGlebik Differential Revision: D21143850 fbshipit-source-id: 6ab3ec268beea92d7f897860f7688a775d60c4bf --- eden/mononoke/cmds/admin/blobstore_fetch.rs | 49 ++- eden/mononoke/cmds/admin/bonsai_fetch.rs | 12 +- eden/mononoke/cmds/admin/bookmarks_manager.rs | 7 +- eden/mononoke/cmds/admin/cmdargs.rs | 1 + eden/mononoke/cmds/admin/content_fetch.rs | 12 +- eden/mononoke/cmds/admin/crossrepo.rs | 5 +- eden/mononoke/cmds/admin/derived_data.rs | 5 +- eden/mononoke/cmds/admin/filenodes.rs | 5 +- eden/mononoke/cmds/admin/filestore.rs | 5 +- eden/mononoke/cmds/admin/hash_convert.rs | 27 +- eden/mononoke/cmds/admin/hg_changeset.rs | 25 +- eden/mononoke/cmds/admin/hg_sync.rs | 83 +++- eden/mononoke/cmds/admin/main.rs | 383 +----------------- eden/mononoke/cmds/admin/mutable_counters.rs | 44 +- eden/mononoke/cmds/admin/phases.rs | 60 ++- eden/mononoke/cmds/admin/redaction.rs | 55 ++- .../cmds/admin/skiplist_subcommand.rs | 23 +- eden/mononoke/cmds/admin/subcommand_blame.rs | 6 +- .../cmds/admin/subcommand_deleted_manifest.rs | 6 +- eden/mononoke/cmds/admin/subcommand_unodes.rs | 6 +- 20 files changed, 424 insertions(+), 395 deletions(-) diff --git a/eden/mononoke/cmds/admin/blobstore_fetch.rs b/eden/mononoke/cmds/admin/blobstore_fetch.rs index 55e0fccff6..1f0fcf21ff 100644 --- a/eden/mononoke/cmds/admin/blobstore_fetch.rs +++ b/eden/mononoke/cmds/admin/blobstore_fetch.rs @@ -10,7 +10,7 @@ use std::fmt; use std::sync::Arc; use anyhow::{format_err, Error, Result}; -use clap::ArgMatches; +use clap::{App, Arg, ArgMatches, SubCommand}; use fbinit::FacebookInit; use futures::compat::Future01CompatExt; use futures_ext::{try_boxfuture, BoxFuture, FutureExt}; @@ -36,9 +36,54 @@ use std::collections::HashMap; use std::iter::FromIterator; use std::str::FromStr; +use crate::cmdargs::{BLOBSTORE_FETCH, SCRUB_BLOBSTORE_ACTION_ARG}; use crate::error::SubcommandError; -pub const SCRUB_BLOBSTORE_ACTION_ARG: &'static str = "scrub-blobstore-action"; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(BLOBSTORE_FETCH) + .about("fetches blobs from manifold") + .args_from_usage("[KEY] 'key of the blob to be fetched'") + .arg( + Arg::with_name("decode-as") + .long("decode-as") + .short("d") + .takes_value(true) + .possible_values(&["auto", "changeset", "manifest", "file", "contents", "git-tree"]) + .required(false) + .help("if provided decode the value"), + ) + .arg( + Arg::with_name("use-memcache") + .long("use-memcache") + .short("m") + .takes_value(true) + .possible_values(&["cache-only", "no-fill", "fill-mc"]) + .required(false) + .help("Use memcache to cache access to the blob store"), + ) + .arg( + Arg::with_name("no-prefix") + .long("no-prefix") + .short("P") + .takes_value(false) + .required(false) + .help("Don't prepend a prefix based on the repo id to the key"), + ) + .arg( + Arg::with_name("inner-blobstore-id") + .long("inner-blobstore-id") + .takes_value(true) + .required(false) + .help("If main blobstore in the storage config is a multiplexed one, use inner blobstore with this id") + ) + .arg( + Arg::with_name(SCRUB_BLOBSTORE_ACTION_ARG) + .long(SCRUB_BLOBSTORE_ACTION_ARG) + .takes_value(true) + .required(false) + .help("Enable ScrubBlobstore with the given action. Checks for keys missing from stores. In ReportOnly mode this logs only, otherwise it performs a copy to the missing stores."), + ) +} fn get_blobconfig( blob_config: BlobConfig, diff --git a/eden/mononoke/cmds/admin/bonsai_fetch.rs b/eden/mononoke/cmds/admin/bonsai_fetch.rs index 64797b1bb3..7296d430eb 100644 --- a/eden/mononoke/cmds/admin/bonsai_fetch.rs +++ b/eden/mononoke/cmds/admin/bonsai_fetch.rs @@ -5,7 +5,7 @@ * GNU General Public License version 2. */ -use clap::ArgMatches; +use clap::{App, ArgMatches, SubCommand}; use cmdlib::args; use context::CoreContext; use fbinit::FacebookInit; @@ -16,9 +16,19 @@ use serde_derive::Serialize; use slog::Logger; use std::collections::BTreeMap; +use crate::cmdargs::BONSAI_FETCH; use crate::common::fetch_bonsai_changeset; use crate::error::SubcommandError; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(BONSAI_FETCH) + .about("fetches content of the file or manifest from blobrepo") + .args_from_usage( + r#" 'hg/bonsai id or bookmark to fetch file from' + --json 'if provided json will be returned'"#, + ) +} + pub async fn subcommand_bonsai_fetch<'a>( fb: FacebookInit, logger: Logger, diff --git a/eden/mononoke/cmds/admin/bookmarks_manager.rs b/eden/mononoke/cmds/admin/bookmarks_manager.rs index ac550eeafd..8f5653a141 100644 --- a/eden/mononoke/cmds/admin/bookmarks_manager.rs +++ b/eden/mononoke/cmds/admin/bookmarks_manager.rs @@ -21,6 +21,7 @@ use slog::{info, Logger}; use blobrepo::BlobRepo; use bookmarks::{BookmarkName, BookmarkUpdateReason}; +use crate::cmdargs::BOOKMARKS; use crate::common::{fetch_bonsai_changeset, format_bookmark_log_entry}; use crate::error::SubcommandError; @@ -30,7 +31,8 @@ const LOG_CMD: &'static str = "log"; const LIST_CMD: &'static str = "list"; const DEL_CMD: &'static str = "delete"; -pub fn prepare_command<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + let parent_subcommand = SubCommand::with_name(BOOKMARKS); let set = SubCommand::with_name(SET_CMD) .about( "sets a bookmark to a specific hg changeset, if the bookmark does not exist it will @@ -102,7 +104,8 @@ pub fn prepare_command<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { "#, ); - app.about("set of commands to manipulate bookmarks") + parent_subcommand + .about("set of commands to manipulate bookmarks") .subcommand(set) .subcommand(get) .subcommand(log) diff --git a/eden/mononoke/cmds/admin/cmdargs.rs b/eden/mononoke/cmds/admin/cmdargs.rs index d91c56ca8a..ae24f6375c 100644 --- a/eden/mononoke/cmds/admin/cmdargs.rs +++ b/eden/mononoke/cmds/admin/cmdargs.rs @@ -43,3 +43,4 @@ pub const SKIPLIST: &'static str = "skiplist"; pub const UNODES: &'static str = "unodes"; pub const BLAME: &'static str = "blame"; pub const DELETED_MANIFEST: &'static str = "deleted-manifest"; +pub const SCRUB_BLOBSTORE_ACTION_ARG: &'static str = "scrub-blobstore-action"; diff --git a/eden/mononoke/cmds/admin/content_fetch.rs b/eden/mononoke/cmds/admin/content_fetch.rs index 790b65fd3b..79750f35d6 100644 --- a/eden/mononoke/cmds/admin/content_fetch.rs +++ b/eden/mononoke/cmds/admin/content_fetch.rs @@ -9,7 +9,7 @@ use anyhow::{format_err, Error}; use blobrepo::BlobRepo; use blobstore::Loadable; use bytes::BytesMut; -use clap::ArgMatches; +use clap::{App, ArgMatches, SubCommand}; use cloned::cloned; use cmdlib::{args, helpers}; use context::CoreContext; @@ -23,8 +23,18 @@ use mercurial_types::manifest::Content; use mercurial_types::{HgManifest, MPath, MPathElement}; use slog::{debug, Logger}; +use crate::cmdargs::CONTENT_FETCH; use crate::error::SubcommandError; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(CONTENT_FETCH) + .about("fetches content of the file or manifest from blobrepo") + .args_from_usage( + " 'hg/bonsai id or bookmark to fetch file from' + 'path to fetch'", + ) +} + pub async fn subcommand_content_fetch<'a>( fb: FacebookInit, logger: Logger, diff --git a/eden/mononoke/cmds/admin/crossrepo.rs b/eden/mononoke/cmds/admin/crossrepo.rs index 36764d8212..f4a0753890 100644 --- a/eden/mononoke/cmds/admin/crossrepo.rs +++ b/eden/mononoke/cmds/admin/crossrepo.rs @@ -30,6 +30,7 @@ use movers::{get_large_to_small_mover, get_small_to_large_mover}; use slog::{info, warn, Logger}; use synced_commit_mapping::{SqlSyncedCommitMapping, SyncedCommitMapping}; +use crate::cmdargs::CROSSREPO; use crate::error::SubcommandError; const MAP_SUBCOMMAND: &str = "map"; @@ -339,7 +340,7 @@ async fn update_large_repo_bookmarks( Ok(()) } -pub fn build_subcommand(name: &str) -> App { +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { let map_subcommand = SubCommand::with_name(MAP_SUBCOMMAND) .about("Check cross-repo commit mapping") .arg( @@ -366,7 +367,7 @@ pub fn build_subcommand(name: &str) -> App { .help("update any inconsistencies between bookmarks (except for the common bookmarks between large and small repo e.g. 'master')"), ); - SubCommand::with_name(name) + SubCommand::with_name(CROSSREPO) .subcommand(map_subcommand) .subcommand(verify_wc_subcommand) .subcommand(verify_bookmarks_subcommand) diff --git a/eden/mononoke/cmds/admin/derived_data.rs b/eden/mononoke/cmds/admin/derived_data.rs index 7e489a3242..30b93d00c3 100644 --- a/eden/mononoke/cmds/admin/derived_data.rs +++ b/eden/mononoke/cmds/admin/derived_data.rs @@ -17,6 +17,7 @@ use futures::{compat::Future01CompatExt, future::FutureExt as PreviewFutureExt, use futures_util::future::try_join_all; use slog::Logger; +use crate::cmdargs::DERIVED_DATA; use crate::error::SubcommandError; const SUBCOMMAND_EXISTS: &'static str = "exists"; @@ -24,8 +25,8 @@ const SUBCOMMAND_EXISTS: &'static str = "exists"; const ARG_HASH_OR_BOOKMARK: &'static str = "hash-or-bookmark"; const ARG_TYPE: &'static str = "type"; -pub fn build_subcommand(name: &str) -> App { - SubCommand::with_name(name) +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(DERIVED_DATA) .about("request information about derived data") .subcommand( SubCommand::with_name(SUBCOMMAND_EXISTS) diff --git a/eden/mononoke/cmds/admin/filenodes.rs b/eden/mononoke/cmds/admin/filenodes.rs index 4869540525..d8b4e34200 100644 --- a/eden/mononoke/cmds/admin/filenodes.rs +++ b/eden/mononoke/cmds/admin/filenodes.rs @@ -25,6 +25,7 @@ use mercurial_types::{HgFileEnvelope, HgFileNodeId, MPath}; use mononoke_types::RepoPath; use slog::{debug, info, Logger}; +use crate::cmdargs::FILENODES; use crate::common::get_file_nodes; use crate::error::SubcommandError; @@ -40,8 +41,8 @@ const ARG_PATHS: &str = "paths"; const ARG_ID: &str = "id"; const ARG_PATH: &str = "path"; -pub fn build_subcommand(name: &str) -> App { - SubCommand::with_name(name) +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(FILENODES) .about("fetches hg filenodes information for a commit and one or more paths") .arg( Arg::with_name(ARG_ENVELOPE) diff --git a/eden/mononoke/cmds/admin/filestore.rs b/eden/mononoke/cmds/admin/filestore.rs index 1cd64b8cec..604f2e9e2e 100644 --- a/eden/mononoke/cmds/admin/filestore.rs +++ b/eden/mononoke/cmds/admin/filestore.rs @@ -26,6 +26,7 @@ use std::io::BufReader; use std::str::FromStr; use tokio_old::{codec, fs::File}; +use crate::cmdargs::FILESTORE; use crate::error::SubcommandError; const COMMAND_METADATA: &str = "metadata"; @@ -40,7 +41,7 @@ const ARG_FILE: &str = "file"; // NOTE: Fetching by GitSha1 is not concurrently supported since that needs a size to instantiate. const VALID_KINDS: [&str; 3] = ["id", "sha1", "sha256"]; -pub fn build_subcommand(name: &str) -> App { +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { let kind_arg = Arg::with_name(ARG_KIND) .possible_values(&VALID_KINDS) .help("Identifier kind") @@ -52,7 +53,7 @@ pub fn build_subcommand(name: &str) -> App { .takes_value(true) .required(true); - SubCommand::with_name(name) + SubCommand::with_name(FILESTORE) .about("inspect and interact with filestore data") .subcommand( SubCommand::with_name(COMMAND_METADATA) diff --git a/eden/mononoke/cmds/admin/hash_convert.rs b/eden/mononoke/cmds/admin/hash_convert.rs index 80e11dca19..4fdb41750a 100644 --- a/eden/mononoke/cmds/admin/hash_convert.rs +++ b/eden/mononoke/cmds/admin/hash_convert.rs @@ -5,7 +5,7 @@ * GNU General Public License version 2. */ -use clap::ArgMatches; +use clap::{App, Arg, ArgMatches, SubCommand}; use fbinit::FacebookInit; use futures::compat::Future01CompatExt; use futures_ext::FutureExt; @@ -18,8 +18,33 @@ use mercurial_types::HgChangesetId; use mononoke_types::ChangesetId; use slog::Logger; +use crate::cmdargs::HASH_CONVERT; use crate::error::SubcommandError; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(HASH_CONVERT) + .about("convert between bonsai and hg changeset hashes") + .arg( + Arg::with_name("from") + .long("from") + .short("f") + .required(true) + .takes_value(true) + .possible_values(&["hg", "bonsai"]) + .help("Source hash type"), + ) + .arg( + Arg::with_name("to") + .long("to") + .short("t") + .required(true) + .takes_value(true) + .possible_values(&["hg", "bonsai"]) + .help("Target hash type"), + ) + .args_from_usage(" 'source hash'") +} + pub async fn subcommand_hash_convert<'a>( fb: FacebookInit, logger: Logger, diff --git a/eden/mononoke/cmds/admin/hg_changeset.rs b/eden/mononoke/cmds/admin/hg_changeset.rs index 23a7e602dc..2619a70871 100644 --- a/eden/mononoke/cmds/admin/hg_changeset.rs +++ b/eden/mononoke/cmds/admin/hg_changeset.rs @@ -8,7 +8,7 @@ use anyhow::{format_err, Error}; use blobrepo::BlobRepo; use blobstore::Loadable; -use clap::ArgMatches; +use clap::{App, ArgMatches, SubCommand}; use cloned::cloned; use cmdlib::args; use context::CoreContext; @@ -26,9 +26,30 @@ use std::collections::BTreeMap; use std::io; use std::str::FromStr; -use crate::cmdargs::{HG_CHANGESET_DIFF, HG_CHANGESET_RANGE}; +use crate::cmdargs::{HG_CHANGESET, HG_CHANGESET_DIFF, HG_CHANGESET_RANGE}; use crate::error::SubcommandError; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(HG_CHANGESET) + .about("mercural changeset level queries") + .subcommand( + SubCommand::with_name(HG_CHANGESET_DIFF) + .about("compare two changeset (used by pushrebase replayer)") + .args_from_usage( + " 'left changeset id' + 'right changeset id'", + ), + ) + .subcommand( + SubCommand::with_name(HG_CHANGESET_RANGE) + .about("returns `x::y` revset") + .args_from_usage( + " 'start changeset id' + 'stop changeset id'", + ), + ) +} + pub async fn subcommand_hg_changeset<'a>( fb: FacebookInit, logger: Logger, diff --git a/eden/mononoke/cmds/admin/hg_sync.rs b/eden/mononoke/cmds/admin/hg_sync.rs index 2ade267501..3e58192c78 100644 --- a/eden/mononoke/cmds/admin/hg_sync.rs +++ b/eden/mononoke/cmds/admin/hg_sync.rs @@ -7,7 +7,7 @@ use anyhow::Error; use bookmarks::{BookmarkUpdateReason, Bookmarks, Freshness}; -use clap::ArgMatches; +use clap::{App, Arg, ArgMatches, SubCommand}; use cloned::cloned; use cmdlib::args; use context::CoreContext; @@ -25,11 +25,90 @@ use mutable_counters::{MutableCounters, SqlMutableCounters}; use slog::{info, Logger}; use crate::cmdargs::{ - HG_SYNC_FETCH_BUNDLE, HG_SYNC_LAST_PROCESSED, HG_SYNC_REMAINS, HG_SYNC_SHOW, HG_SYNC_VERIFY, + HG_SYNC_BUNDLE, HG_SYNC_FETCH_BUNDLE, HG_SYNC_LAST_PROCESSED, HG_SYNC_REMAINS, HG_SYNC_SHOW, + HG_SYNC_VERIFY, }; use crate::common::{format_bookmark_log_entry, LATEST_REPLAYED_REQUEST_KEY}; use crate::error::SubcommandError; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(HG_SYNC_BUNDLE) + .about("things related to mononoke-hg-sync counters") + .subcommand( + SubCommand::with_name(HG_SYNC_LAST_PROCESSED) + .about("inspect/change mononoke-hg sync last processed counter") + .arg( + Arg::with_name("set") + .long("set") + .required(false) + .takes_value(true) + .help("set the value of the latest processed mononoke-hg-sync counter"), + ) + .arg( + Arg::with_name("skip-blobimport") + .long("skip-blobimport") + .required(false) + .help("skip to the next non-blobimport entry in mononoke-hg-sync counter"), + ) + .arg( + Arg::with_name("dry-run") + .long("dry-run") + .required(false) + .help("don't make changes, only show what would have been done (--skip-blobimport only)"), + ), + ) + .subcommand( + SubCommand::with_name(HG_SYNC_REMAINS) + .about("get the value of the last mononoke-hg-sync counter to be processed") + .arg( + Arg::with_name("quiet") + .long("quiet") + .required(false) + .takes_value(false) + .help("only print the number if present"), + ) + .arg( + Arg::with_name("without-blobimport") + .long("without-blobimport") + .required(false) + .takes_value(false) + .help("exclude blobimport entries from the count"), + ), + ) + .subcommand( + SubCommand::with_name(HG_SYNC_SHOW).about("show hg hashes of yet to be replayed bundles") + .arg( + Arg::with_name("limit") + .long("limit") + .required(false) + .takes_value(true) + .help("how many bundles to show"), + ) + ) + .subcommand( + SubCommand::with_name(HG_SYNC_FETCH_BUNDLE) + .about("fetches a bundle by id") + .arg( + Arg::with_name("id") + .long("id") + .required(true) + .takes_value(true) + .help("bookmark log id. If it has associated bundle it will be fetched."), + ) + .arg( + Arg::with_name("output-file") + .long("output-file") + .required(true) + .takes_value(true) + .help("where a bundle will be saved"), + ), + ) + .subcommand( + SubCommand::with_name(HG_SYNC_VERIFY) + .about("verify the consistency of yet-to-be-processed bookmark log entries"), + ) +} + pub async fn subcommand_process_hg_sync<'a>( fb: FacebookInit, sub_m: &'a ArgMatches<'_>, diff --git a/eden/mononoke/cmds/admin/main.rs b/eden/mononoke/cmds/admin/main.rs index 4f6b721a75..3010c5a515 100644 --- a/eden/mononoke/cmds/admin/main.rs +++ b/eden/mononoke/cmds/admin/main.rs @@ -8,7 +8,7 @@ #![deny(warnings)] #![feature(process_exitcode_placeholder)] -use clap::{App, Arg, SubCommand}; +use clap::App; use fbinit::FacebookInit; use futures_ext::FutureExt as Future01Ext; use std::process::ExitCode; @@ -20,13 +20,9 @@ use slog::error; use crate::blobstore_fetch::subcommand_blobstore_fetch; use crate::bonsai_fetch::subcommand_bonsai_fetch; use crate::cmdargs::{ - ADD_PUBLIC_PHASES, BLAME, BLOBSTORE_FETCH, BONSAI_FETCH, BOOKMARKS, CONTENT_FETCH, CROSSREPO, - DELETED_MANIFEST, DERIVED_DATA, FETCH_PHASE, FILENODES, FILESTORE, HASH_CONVERT, HG_CHANGESET, - HG_CHANGESET_DIFF, HG_CHANGESET_RANGE, HG_SYNC_BUNDLE, HG_SYNC_FETCH_BUNDLE, - HG_SYNC_LAST_PROCESSED, HG_SYNC_REMAINS, HG_SYNC_SHOW, HG_SYNC_VERIFY, LIST_PUBLIC, - MUTABLE_COUNTERS, MUTABLE_COUNTERS_GET, MUTABLE_COUNTERS_LIST, MUTABLE_COUNTERS_NAME, - MUTABLE_COUNTERS_SET, MUTABLE_COUNTERS_VALUE, PHASES, REDACTION, REDACTION_ADD, REDACTION_LIST, - REDACTION_REMOVE, SKIPLIST, SKIPLIST_BUILD, SKIPLIST_READ, UNODES, + BLAME, BLOBSTORE_FETCH, BONSAI_FETCH, BOOKMARKS, CONTENT_FETCH, CROSSREPO, DELETED_MANIFEST, + DERIVED_DATA, FILENODES, FILESTORE, HASH_CONVERT, HG_CHANGESET, HG_SYNC_BUNDLE, + MUTABLE_COUNTERS, PHASES, REDACTION, SKIPLIST, UNODES, }; use crate::content_fetch::subcommand_content_fetch; use crate::crossrepo::subcommand_crossrepo; @@ -62,365 +58,30 @@ mod subcommand_deleted_manifest; mod subcommand_unodes; fn setup_app<'a, 'b>() -> App<'a, 'b> { - let blobstore_fetch = SubCommand::with_name(BLOBSTORE_FETCH) - .about("fetches blobs from manifold") - .args_from_usage("[KEY] 'key of the blob to be fetched'") - .arg( - Arg::with_name("decode-as") - .long("decode-as") - .short("d") - .takes_value(true) - .possible_values(&["auto", "changeset", "manifest", "file", "contents", "git-tree"]) - .required(false) - .help("if provided decode the value"), - ) - .arg( - Arg::with_name("use-memcache") - .long("use-memcache") - .short("m") - .takes_value(true) - .possible_values(&["cache-only", "no-fill", "fill-mc"]) - .required(false) - .help("Use memcache to cache access to the blob store"), - ) - .arg( - Arg::with_name("no-prefix") - .long("no-prefix") - .short("P") - .takes_value(false) - .required(false) - .help("Don't prepend a prefix based on the repo id to the key"), - ) - .arg( - Arg::with_name("inner-blobstore-id") - .long("inner-blobstore-id") - .takes_value(true) - .required(false) - .help("If main blobstore in the storage config is a multiplexed one, use inner blobstore with this id") - ) - .arg( - Arg::with_name(blobstore_fetch::SCRUB_BLOBSTORE_ACTION_ARG) - .long(blobstore_fetch::SCRUB_BLOBSTORE_ACTION_ARG) - .takes_value(true) - .required(false) - .help("Enable ScrubBlobstore with the given action. Checks for keys missing from stores. In ReportOnly mode this logs only, otherwise it performs a copy to the missing stores."), - ); - - let content_fetch = SubCommand::with_name(CONTENT_FETCH) - .about("fetches content of the file or manifest from blobrepo") - .args_from_usage( - " 'hg/bonsai id or bookmark to fetch file from' - 'path to fetch'", - ); - - let bonsai_fetch = SubCommand::with_name(BONSAI_FETCH) - .about("fetches content of the file or manifest from blobrepo") - .args_from_usage( - r#" 'hg/bonsai id or bookmark to fetch file from' - --json 'if provided json will be returned'"#, - ); - - let hg_changeset = SubCommand::with_name(HG_CHANGESET) - .about("mercural changeset level queries") - .subcommand( - SubCommand::with_name(HG_CHANGESET_DIFF) - .about("compare two changeset (used by pushrebase replayer)") - .args_from_usage( - " 'left changeset id' - 'right changeset id'", - ), - ) - .subcommand( - SubCommand::with_name(HG_CHANGESET_RANGE) - .about("returns `x::y` revset") - .args_from_usage( - " 'start changeset id' - 'stop changeset id'", - ), - ); - - let skiplist = SubCommand::with_name(SKIPLIST) - .about("commands to build or read skiplist indexes") - .subcommand( - SubCommand::with_name(SKIPLIST_BUILD) - .about("build skiplist index") - .args_from_usage( - " 'Blobstore key where to store the built skiplist'", - ), - ) - .subcommand( - SubCommand::with_name(SKIPLIST_READ) - .about("read skiplist index") - .args_from_usage( - " 'Blobstore key from where to read the skiplist'", - ), - ); - - let convert = SubCommand::with_name(HASH_CONVERT) - .about("convert between bonsai and hg changeset hashes") - .arg( - Arg::with_name("from") - .long("from") - .short("f") - .required(true) - .takes_value(true) - .possible_values(&["hg", "bonsai"]) - .help("Source hash type"), - ) - .arg( - Arg::with_name("to") - .long("to") - .short("t") - .required(true) - .takes_value(true) - .possible_values(&["hg", "bonsai"]) - .help("Target hash type"), - ) - .args_from_usage(" 'source hash'"); - - let hg_sync = SubCommand::with_name(HG_SYNC_BUNDLE) - .about("things related to mononoke-hg-sync counters") - .subcommand( - SubCommand::with_name(HG_SYNC_LAST_PROCESSED) - .about("inspect/change mononoke-hg sync last processed counter") - .arg( - Arg::with_name("set") - .long("set") - .required(false) - .takes_value(true) - .help("set the value of the latest processed mononoke-hg-sync counter"), - ) - .arg( - Arg::with_name("skip-blobimport") - .long("skip-blobimport") - .required(false) - .help("skip to the next non-blobimport entry in mononoke-hg-sync counter"), - ) - .arg( - Arg::with_name("dry-run") - .long("dry-run") - .required(false) - .help("don't make changes, only show what would have been done (--skip-blobimport only)"), - ), - ) - .subcommand( - SubCommand::with_name(HG_SYNC_REMAINS) - .about("get the value of the last mononoke-hg-sync counter to be processed") - .arg( - Arg::with_name("quiet") - .long("quiet") - .required(false) - .takes_value(false) - .help("only print the number if present"), - ) - .arg( - Arg::with_name("without-blobimport") - .long("without-blobimport") - .required(false) - .takes_value(false) - .help("exclude blobimport entries from the count"), - ), - ) - .subcommand( - SubCommand::with_name(HG_SYNC_SHOW).about("show hg hashes of yet to be replayed bundles") - .arg( - Arg::with_name("limit") - .long("limit") - .required(false) - .takes_value(true) - .help("how many bundles to show"), - ) - ) - .subcommand( - SubCommand::with_name(HG_SYNC_FETCH_BUNDLE) - .about("fetches a bundle by id") - .arg( - Arg::with_name("id") - .long("id") - .required(true) - .takes_value(true) - .help("bookmark log id. If it has associated bundle it will be fetched."), - ) - .arg( - Arg::with_name("output-file") - .long("output-file") - .required(true) - .takes_value(true) - .help("where a bundle will be saved"), - ), - ) - .subcommand( - SubCommand::with_name(HG_SYNC_VERIFY) - .about("verify the consistency of yet-to-be-processed bookmark log entries"), - ); - - let phases = SubCommand::with_name(PHASES) - .about("commands to work with phases") - .subcommand( - SubCommand::with_name(ADD_PUBLIC_PHASES) - .about("mark mercurial commits as public from provided new-line separated list") - .arg( - Arg::with_name("input-file") - .help("new-line separated mercurial public commits") - .required(true) - .index(1), - ) - .arg( - Arg::with_name("chunk-size") - .help("partition input file to chunks of specified size") - .long("chunk-size") - .takes_value(true), - ), - ) - .subcommand( - SubCommand::with_name(FETCH_PHASE) - .about("fetch phase of a commit") - .arg( - Arg::with_name("changeset-type") - .long("changeset-type") - .short("c") - .takes_value(true) - .possible_values(&["bonsai", "hg"]) - .required(false) - .help( - "What changeset type to return, either bonsai or hg. Defaults to hg.", - ), - ) - .arg( - Arg::with_name("hash") - .help("changeset hash") - .takes_value(true), - ), - ) - .subcommand( - SubCommand::with_name(LIST_PUBLIC) - .arg( - Arg::with_name("changeset-type") - .long("changeset-type") - .short("c") - .takes_value(true) - .possible_values(&["bonsai", "hg"]) - .required(false) - .help( - "What changeset type to return, either bonsai or hg. Defaults to hg.", - ), - ) - .about("List all public commits"), - ); - - let redaction = SubCommand::with_name(REDACTION) - .about("handle file redaction") - .subcommand( - SubCommand::with_name(REDACTION_ADD) - .about("add a new redacted file at a given commit") - .arg( - Arg::with_name("task") - .help("Task tracking the redaction request") - .takes_value(true) - .required(true), - ) - .arg( - Arg::with_name("hash") - .help("hg commit hash") - .takes_value(true) - .required(true), - ) - .args_from_usage( - r#" - ... 'list of files to be be redacted' - "#, - ) - ) - .subcommand( - SubCommand::with_name(REDACTION_REMOVE) - .about("remove a file from the redaction") - .arg( - Arg::with_name("hash") - .help("hg commit hash") - .takes_value(true) - .required(true), - ) - .args_from_usage( - r#" - ... 'list of files to be be unredacted' - "#, - ) - ) - .subcommand( - SubCommand::with_name(REDACTION_LIST) - .about("list all redacted file for a given commit") - .arg( - Arg::with_name("hash") - .help("hg commit hash or a bookmark") - .takes_value(true) - .required(true), - ) - ); - - let mutable_counters = SubCommand::with_name(MUTABLE_COUNTERS) - .about("handle mutable counters") - .subcommand( - SubCommand::with_name(MUTABLE_COUNTERS_LIST) - .about("get all the mutable counters for a repo"), - ) - .subcommand( - SubCommand::with_name(MUTABLE_COUNTERS_GET) - .about("get the value of the mutable counter") - .arg( - Arg::with_name(MUTABLE_COUNTERS_NAME) - .help("name of the mutable counter to get") - .takes_value(true) - .required(true) - .index(1), - ), - ) - .subcommand( - SubCommand::with_name(MUTABLE_COUNTERS_SET) - .about("set the value of the mutable counter") - .arg( - Arg::with_name(MUTABLE_COUNTERS_NAME) - .help("name of the mutable counter to set") - .takes_value(true) - .required(true) - .index(1), - ) - .arg( - Arg::with_name(MUTABLE_COUNTERS_VALUE) - .help("value of the mutable counter to set") - .takes_value(true) - .required(true) - .index(2), - ), - ); - args::MononokeApp::new("Mononoke admin command line tool") .with_advanced_args_hidden() .with_source_and_target_repos() .build() .version("0.0.0") .about("Poke at mononoke internals for debugging and investigating data structures.") - .subcommand(blobstore_fetch) - .subcommand(bonsai_fetch) - .subcommand(content_fetch) - .subcommand(bookmarks_manager::prepare_command(SubCommand::with_name( - BOOKMARKS, - ))) - .subcommand(hg_changeset) - .subcommand(skiplist) - .subcommand(convert) - .subcommand(hg_sync) - .subcommand(mutable_counters) - .subcommand(redaction) - .subcommand(filenodes::build_subcommand(FILENODES)) - .subcommand(phases) - .subcommand(filestore::build_subcommand(FILESTORE)) - .subcommand(subcommand_unodes::subcommand_unodes_build(UNODES)) - .subcommand(crossrepo::build_subcommand(CROSSREPO)) - .subcommand(subcommand_blame::subcommand_blame_build(BLAME)) - .subcommand( - subcommand_deleted_manifest::subcommand_deleted_manifest_build(DELETED_MANIFEST), - ) - .subcommand(derived_data::build_subcommand(DERIVED_DATA)) + .subcommand(blobstore_fetch::build_subcommand()) + .subcommand(bonsai_fetch::build_subcommand()) + .subcommand(content_fetch::build_subcommand()) + .subcommand(bookmarks_manager::build_subcommand()) + .subcommand(hg_changeset::build_subcommand()) + .subcommand(skiplist_subcommand::build_subcommand()) + .subcommand(hash_convert::build_subcommand()) + .subcommand(hg_sync::build_subcommand()) + .subcommand(mutable_counters::build_subcommand()) + .subcommand(redaction::build_subcommand()) + .subcommand(filenodes::build_subcommand()) + .subcommand(phases::build_subcommand()) + .subcommand(filestore::build_subcommand()) + .subcommand(subcommand_unodes::build_subcommand()) + .subcommand(crossrepo::build_subcommand()) + .subcommand(subcommand_blame::build_subcommand()) + .subcommand(subcommand_deleted_manifest::build_subcommand()) + .subcommand(derived_data::build_subcommand()) } #[fbinit::main] diff --git a/eden/mononoke/cmds/admin/mutable_counters.rs b/eden/mononoke/cmds/admin/mutable_counters.rs index 4804d33e23..da8c4e9d88 100644 --- a/eden/mononoke/cmds/admin/mutable_counters.rs +++ b/eden/mononoke/cmds/admin/mutable_counters.rs @@ -6,13 +6,13 @@ */ use crate::cmdargs::{ - MUTABLE_COUNTERS_GET, MUTABLE_COUNTERS_LIST, MUTABLE_COUNTERS_NAME, MUTABLE_COUNTERS_SET, - MUTABLE_COUNTERS_VALUE, + MUTABLE_COUNTERS, MUTABLE_COUNTERS_GET, MUTABLE_COUNTERS_LIST, MUTABLE_COUNTERS_NAME, + MUTABLE_COUNTERS_SET, MUTABLE_COUNTERS_VALUE, }; use crate::error::SubcommandError; use anyhow::{format_err, Error}; -use clap::ArgMatches; +use clap::{App, Arg, ArgMatches, SubCommand}; use cmdlib::args; use context::CoreContext; use failure_ext::FutureFailureErrorExt; @@ -22,6 +22,44 @@ use mononoke_types::RepositoryId; use mutable_counters::{MutableCounters, SqlMutableCounters}; use slog::{info, Logger}; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(MUTABLE_COUNTERS) + .about("handle mutable counters") + .subcommand( + SubCommand::with_name(MUTABLE_COUNTERS_LIST) + .about("get all the mutable counters for a repo"), + ) + .subcommand( + SubCommand::with_name(MUTABLE_COUNTERS_GET) + .about("get the value of the mutable counter") + .arg( + Arg::with_name(MUTABLE_COUNTERS_NAME) + .help("name of the mutable counter to get") + .takes_value(true) + .required(true) + .index(1), + ), + ) + .subcommand( + SubCommand::with_name(MUTABLE_COUNTERS_SET) + .about("set the value of the mutable counter") + .arg( + Arg::with_name(MUTABLE_COUNTERS_NAME) + .help("name of the mutable counter to set") + .takes_value(true) + .required(true) + .index(1), + ) + .arg( + Arg::with_name(MUTABLE_COUNTERS_VALUE) + .help("value of the mutable counter to set") + .takes_value(true) + .required(true) + .index(2), + ), + ) +} + pub async fn subcommand_mutable_counters<'a>( fb: FacebookInit, sub_m: &'a ArgMatches<'_>, diff --git a/eden/mononoke/cmds/admin/phases.rs b/eden/mononoke/cmds/admin/phases.rs index 244db23208..e574983582 100644 --- a/eden/mononoke/cmds/admin/phases.rs +++ b/eden/mononoke/cmds/admin/phases.rs @@ -5,9 +5,9 @@ * GNU General Public License version 2. */ -use crate::cmdargs::{ADD_PUBLIC_PHASES, FETCH_PHASE, LIST_PUBLIC}; +use crate::cmdargs::{ADD_PUBLIC_PHASES, FETCH_PHASE, LIST_PUBLIC, PHASES}; use anyhow::{bail, format_err, Error}; -use clap::ArgMatches; +use clap::{App, Arg, ArgMatches, SubCommand}; use cloned::cloned; use fbinit::FacebookInit; use futures::{ @@ -36,6 +36,62 @@ use slog::{info, Logger}; use crate::error::SubcommandError; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(PHASES) + .about("commands to work with phases") + .subcommand( + SubCommand::with_name(ADD_PUBLIC_PHASES) + .about("mark mercurial commits as public from provided new-line separated list") + .arg( + Arg::with_name("input-file") + .help("new-line separated mercurial public commits") + .required(true) + .index(1), + ) + .arg( + Arg::with_name("chunk-size") + .help("partition input file to chunks of specified size") + .long("chunk-size") + .takes_value(true), + ), + ) + .subcommand( + SubCommand::with_name(FETCH_PHASE) + .about("fetch phase of a commit") + .arg( + Arg::with_name("changeset-type") + .long("changeset-type") + .short("c") + .takes_value(true) + .possible_values(&["bonsai", "hg"]) + .required(false) + .help( + "What changeset type to return, either bonsai or hg. Defaults to hg.", + ), + ) + .arg( + Arg::with_name("hash") + .help("changeset hash") + .takes_value(true), + ), + ) + .subcommand( + SubCommand::with_name(LIST_PUBLIC) + .arg( + Arg::with_name("changeset-type") + .long("changeset-type") + .short("c") + .takes_value(true) + .possible_values(&["bonsai", "hg"]) + .required(false) + .help( + "What changeset type to return, either bonsai or hg. Defaults to hg.", + ), + ) + .about("List all public commits"), + ) +} + pub async fn subcommand_phases<'a>( fb: FacebookInit, logger: Logger, diff --git a/eden/mononoke/cmds/admin/redaction.rs b/eden/mononoke/cmds/admin/redaction.rs index 244d1b2f7a..bbda92a738 100644 --- a/eden/mononoke/cmds/admin/redaction.rs +++ b/eden/mononoke/cmds/admin/redaction.rs @@ -5,12 +5,12 @@ * GNU General Public License version 2. */ -use crate::cmdargs::{REDACTION_ADD, REDACTION_LIST, REDACTION_REMOVE}; +use crate::cmdargs::{REDACTION, REDACTION_ADD, REDACTION_LIST, REDACTION_REMOVE}; use crate::common::get_file_nodes; use anyhow::{format_err, Error}; use blobrepo::BlobRepo; use blobstore::Loadable; -use clap::ArgMatches; +use clap::{App, Arg, ArgMatches, SubCommand}; use cloned::cloned; use cmdlib::{args, helpers}; use context::CoreContext; @@ -32,6 +32,57 @@ use std::sync::Arc; use crate::error::SubcommandError; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(REDACTION) + .about("handle file redaction") + .subcommand( + SubCommand::with_name(REDACTION_ADD) + .about("add a new redacted file at a given commit") + .arg( + Arg::with_name("task") + .help("Task tracking the redaction request") + .takes_value(true) + .required(true), + ) + .arg( + Arg::with_name("hash") + .help("hg commit hash") + .takes_value(true) + .required(true), + ) + .args_from_usage( + r#" + ... 'list of files to be be redacted' + "#, + ) + ) + .subcommand( + SubCommand::with_name(REDACTION_REMOVE) + .about("remove a file from the redaction") + .arg( + Arg::with_name("hash") + .help("hg commit hash") + .takes_value(true) + .required(true), + ) + .args_from_usage( + r#" + ... 'list of files to be be unredacted' + "#, + ) + ) + .subcommand( + SubCommand::with_name(REDACTION_LIST) + .about("list all redacted file for a given commit") + .arg( + Arg::with_name("hash") + .help("hg commit hash or a bookmark") + .takes_value(true) + .required(true), + ) + ) +} + fn find_files_with_given_content_id_blobstore_keys( logger: Logger, ctx: CoreContext, diff --git a/eden/mononoke/cmds/admin/skiplist_subcommand.rs b/eden/mononoke/cmds/admin/skiplist_subcommand.rs index 95099c7b3c..835224a4f7 100644 --- a/eden/mononoke/cmds/admin/skiplist_subcommand.rs +++ b/eden/mononoke/cmds/admin/skiplist_subcommand.rs @@ -6,7 +6,7 @@ */ use anyhow::Error; -use clap::ArgMatches; +use clap::{App, ArgMatches, SubCommand}; use cloned::cloned; use fbinit::FacebookInit; use fbthrift::compact_protocol; @@ -28,9 +28,28 @@ use mononoke_types::{BlobstoreBytes, ChangesetId, Generation, RepositoryId}; use skiplist::{deserialize_skiplist_index, SkiplistIndex, SkiplistNodeType}; use slog::{debug, info, Logger}; -use crate::cmdargs::{SKIPLIST_BUILD, SKIPLIST_READ}; +use crate::cmdargs::{SKIPLIST, SKIPLIST_BUILD, SKIPLIST_READ}; use crate::error::SubcommandError; +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { + SubCommand::with_name(SKIPLIST) + .about("commands to build or read skiplist indexes") + .subcommand( + SubCommand::with_name(SKIPLIST_BUILD) + .about("build skiplist index") + .args_from_usage( + " 'Blobstore key where to store the built skiplist'", + ), + ) + .subcommand( + SubCommand::with_name(SKIPLIST_READ) + .about("read skiplist index") + .args_from_usage( + " 'Blobstore key from where to read the skiplist'", + ), + ) +} + pub async fn subcommand_skiplist<'a>( fb: FacebookInit, logger: Logger, diff --git a/eden/mononoke/cmds/admin/subcommand_blame.rs b/eden/mononoke/cmds/admin/subcommand_blame.rs index 0377444e3f..6192c96ca7 100644 --- a/eden/mononoke/cmds/admin/subcommand_blame.rs +++ b/eden/mononoke/cmds/admin/subcommand_blame.rs @@ -5,7 +5,9 @@ * GNU General Public License version 2. */ +use crate::cmdargs::BLAME; use crate::error::SubcommandError; + use anyhow::{format_err, Error}; use blame::{fetch_blame, fetch_file_full_content}; use blobrepo::BlobRepo; @@ -41,7 +43,7 @@ const ARG_CSID: &'static str = "csid"; const ARG_PATH: &'static str = "path"; const ARG_LINE: &'static str = "line"; -pub fn subcommand_blame_build(name: &str) -> App { +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { let csid_arg = Arg::with_name(ARG_CSID) .help("{hg|bonsai} changeset id or bookmark name") .index(1) @@ -57,7 +59,7 @@ pub fn subcommand_blame_build(name: &str) -> App { .takes_value(false) .required(false); - SubCommand::with_name(name) + SubCommand::with_name(BLAME) .about("fetch/derive blame for specified changeset and path") .subcommand( SubCommand::with_name(COMMAND_DERIVE) diff --git a/eden/mononoke/cmds/admin/subcommand_deleted_manifest.rs b/eden/mononoke/cmds/admin/subcommand_deleted_manifest.rs index 33d7682c2b..b77f88250c 100644 --- a/eden/mononoke/cmds/admin/subcommand_deleted_manifest.rs +++ b/eden/mononoke/cmds/admin/subcommand_deleted_manifest.rs @@ -5,7 +5,9 @@ * GNU General Public License version 2. */ +use crate::cmdargs::DELETED_MANIFEST; use crate::error::SubcommandError; + use anyhow::{format_err, Error}; use blobrepo::BlobRepo; use blobstore::Loadable; @@ -32,7 +34,7 @@ const ARG_CSID: &'static str = "csid"; const ARG_LIMIT: &'static str = "limit"; const ARG_PATH: &'static str = "path"; -pub fn subcommand_deleted_manifest_build(name: &str) -> App { +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { let csid_arg = Arg::with_name(ARG_CSID) .help("{hg|boinsai} changset id or bookmark name") .index(1) @@ -43,7 +45,7 @@ pub fn subcommand_deleted_manifest_build(name: &str) -> App { .index(2) .default_value(""); - SubCommand::with_name(name) + SubCommand::with_name(DELETED_MANIFEST) .about("derive, inspect and verify deleted files manifest") .subcommand( SubCommand::with_name(COMMAND_MANIFEST) diff --git a/eden/mononoke/cmds/admin/subcommand_unodes.rs b/eden/mononoke/cmds/admin/subcommand_unodes.rs index 449c88626b..4b24a7f839 100644 --- a/eden/mononoke/cmds/admin/subcommand_unodes.rs +++ b/eden/mononoke/cmds/admin/subcommand_unodes.rs @@ -5,7 +5,9 @@ * GNU General Public License version 2. */ +use crate::cmdargs::UNODES; use crate::error::SubcommandError; + use anyhow::{bail, Error}; use blobrepo::BlobRepo; use blobstore::Loadable; @@ -40,7 +42,7 @@ fn path_resolve(path: &str) -> Result, Error> { } } -pub fn subcommand_unodes_build(name: &str) -> App { +pub fn build_subcommand<'a, 'b>() -> App<'a, 'b> { let csid_arg = Arg::with_name(ARG_CSID) .help("{hg|boinsai} changset id or bookmark name") .index(1) @@ -51,7 +53,7 @@ pub fn subcommand_unodes_build(name: &str) -> App { .index(2) .default_value("/"); - SubCommand::with_name(name) + SubCommand::with_name(UNODES) .about("inspect and interact with unodes") .arg( Arg::with_name(ARG_TRACE)