| use clap::{ |
| builder::{EnumValueParser, PossibleValuesParser}, |
| Arg, ArgAction, Command, |
| }; |
| use clap_complete::Shell; |
| |
| use crate::print_schema; |
| |
| pub fn build_cli() -> Command { |
| let database_arg = Arg::new("DATABASE_URL") |
| .long("database-url") |
| .help( |
| "Specifies the database URL to connect to. Falls back to \ |
| the DATABASE_URL environment variable if unspecified.", |
| ) |
| .global(true) |
| .num_args(1); |
| |
| let migration_subcommand = Command::new("migration") |
| .about( |
| "A group of commands for generating, running, and reverting \ |
| migrations.", |
| ) |
| .arg(migration_dir_arg()) |
| .subcommand(Command::new("run").about("Runs all pending migrations.")) |
| .subcommand( |
| Command::new("revert") |
| .about("Reverts the specified migrations.") |
| .arg( |
| Arg::new("REVERT_ALL") |
| .long("all") |
| .short('a') |
| .help("Reverts previously run migration files.") |
| .action(ArgAction::SetTrue) |
| .conflicts_with("REVERT_NUMBER"), |
| ) |
| .arg( |
| Arg::new("REVERT_NUMBER") |
| .long("number") |
| .short('n') |
| .help("Reverts the last `n` migration files.") |
| .long_help( |
| "When this option is specified the last `n` migration files \ |
| will be reverted. By default revert the last one.", |
| ) |
| .default_value("1") |
| .num_args(1) |
| .value_parser(clap::value_parser!(u64)) |
| .conflicts_with("REVERT_ALL"), |
| ), |
| ) |
| .subcommand( |
| Command::new("redo") |
| .about( |
| "Reverts and re-runs the latest migration. Useful \ |
| for testing that a migration can in fact be reverted.", |
| ) |
| .arg( |
| Arg::new("REDO_ALL") |
| .long("all") |
| .short('a') |
| .help("Reverts and re-runs all migrations.") |
| .long_help( |
| "When this option is specified all migrations \ |
| will be reverted and re-runs. Useful for testing \ |
| that your migrations can be reverted and applied.", |
| ) |
| .action(ArgAction::SetTrue) |
| .conflicts_with("REDO_NUMBER"), |
| ) |
| .arg( |
| Arg::new("REDO_NUMBER") |
| .long("number") |
| .short('n') |
| .help("Redo the last `n` migration files.") |
| .long_help( |
| "When this option is specified the last `n` migration files \ |
| will be reverted and re-runs. By default redo the last migration.", |
| ) |
| .default_value("1") |
| .num_args(1) |
| .value_parser(clap::value_parser!(u64)) |
| .conflicts_with("REDO_ALL"), |
| ), |
| ) |
| .subcommand( |
| Command::new("list") |
| .about("Lists all available migrations, marking those that have been applied."), |
| ) |
| .subcommand( |
| Command::new("pending").about("Returns true if there are any pending migrations."), |
| ) |
| .subcommand( |
| Command::new("generate") |
| .about( |
| "Generate a new migration with the given name, and \ |
| the current timestamp as the version.", |
| ) |
| .arg( |
| Arg::new("MIGRATION_NAME") |
| .index(1) |
| .num_args(1) |
| .help("The name of the migration to create.") |
| .required(true), |
| ) |
| .arg( |
| Arg::new("MIGRATION_VERSION") |
| .long("version") |
| .help( |
| "The version number to use when generating the migration. \ |
| Defaults to the current timestamp, which should suffice \ |
| for most use cases.", |
| ) |
| .num_args(1), |
| ) |
| .arg( |
| Arg::new("MIGRATION_NO_DOWN_FILE") |
| .short('u') // only Up |
| .long("no-down") |
| .help( |
| "Don't generate a down.sql file. \ |
| You won't be able to run migration `revert` or `redo`.", |
| ) |
| .action(ArgAction::SetTrue), |
| ) |
| .arg( |
| Arg::new("MIGRATION_FORMAT") |
| .long("format") |
| .value_parser(PossibleValuesParser::new(["sql"])) |
| .num_args(1) |
| .default_value("sql") |
| .help("The format of the migration to be generated."), |
| ) |
| .arg( |
| Arg::new("SCHEMA_RS") |
| .long("diff-schema") |
| .help( |
| "Populate the generated migrations \ |
| based on the current difference between \ |
| your `schema.rs` file and the specified \ |
| database. \n\n\ |
| The generated migrations are not expected to \ |
| be perfect. Be sure to check whether they meet \ |
| your expectations. Adjust the generated output \ |
| if that's not the case.", |
| ) |
| .default_missing_value("NOT_SET") |
| .num_args(0..=1) |
| .require_equals(true), |
| ) |
| .arg( |
| Arg::new("table-name") |
| .index(2) |
| .num_args(1..) |
| .action(clap::ArgAction::Append) |
| .help("Table names to filter."), |
| ) |
| .arg( |
| Arg::new("only-tables") |
| .short('o') |
| .long("only-tables") |
| .action(ArgAction::SetTrue) |
| .help("Only include tables from table-name that matches regexp.") |
| .conflicts_with("except-tables"), |
| ) |
| .arg( |
| Arg::new("except-tables") |
| .short('e') |
| .long("except-tables") |
| .action(ArgAction::SetTrue) |
| .help("Exclude tables from table-name that matches regex.") |
| .conflicts_with("only-tables"), |
| ), |
| ) |
| .subcommand_required(true) |
| .arg_required_else_help(true); |
| |
| let setup_subcommand = Command::new("setup").arg(migration_dir_arg()).about( |
| "Creates the migrations directory, creates the database \ |
| specified in your DATABASE_URL, and runs existing migrations.", |
| ); |
| |
| let database_subcommand = Command::new("database") |
| .alias("db") |
| .arg(migration_dir_arg()) |
| .about("A group of commands for setting up and resetting your database.") |
| .subcommand(Command::new("setup").about( |
| "Creates the database specified in your DATABASE_URL, \ |
| and then runs any existing migrations.", |
| )) |
| .subcommand(Command::new("reset").about( |
| "Resets your database by dropping the database specified \ |
| in your DATABASE_URL and then running `diesel database setup`.", |
| )) |
| .subcommand( |
| Command::new("drop") |
| .about("Drops the database specified in your DATABASE_URL.") |
| .hide(true), |
| ) |
| .subcommand_required(true) |
| .arg_required_else_help(true); |
| |
| let generate_completions_subcommand = Command::new("completions") |
| .about("Generate shell completion scripts for the diesel command.") |
| .arg( |
| Arg::new("SHELL") |
| .index(1) |
| .required(true) |
| .value_parser(EnumValueParser::<Shell>::new()), |
| ); |
| |
| let infer_schema_subcommand = Command::new("print-schema") |
| .about("Print table definitions for database schema.") |
| .arg( |
| Arg::new("schema") |
| .long("schema") |
| .short('s') |
| .num_args(1) |
| .help("The name of the schema."), |
| ) |
| .arg( |
| Arg::new("table-name") |
| .index(1) |
| .num_args(1..) |
| .action(clap::ArgAction::Append) |
| .help("Table names to filter."), |
| ) |
| .arg( |
| Arg::new("only-tables") |
| .short('o') |
| .long("only-tables") |
| .action(ArgAction::SetTrue) |
| .help("Only include tables from table-name that matches regexp.") |
| .conflicts_with("except-tables"), |
| ) |
| .arg( |
| Arg::new("except-tables") |
| .short('e') |
| .long("except-tables") |
| .action(ArgAction::SetTrue) |
| .help("Exclude tables from table-name that matches regex.") |
| .conflicts_with("only-tables"), |
| ) |
| .arg( |
| Arg::new("with-docs") |
| .long("with-docs") |
| .action(ArgAction::SetTrue) |
| .help("Render documentation comments for tables and columns."), |
| ) |
| .arg( |
| Arg::new("with-docs-config") |
| .long("with-docs-config") |
| .help("Render documentation comments for tables and columns.") |
| .num_args(1) |
| .value_parser(PossibleValuesParser::new(print_schema::DocConfig::VARIANTS_STR)), |
| ) |
| .arg( |
| Arg::new("column-sorting") |
| .long("column-sorting") |
| .help("Sort order for table columns.") |
| .num_args(1) |
| .value_parser(PossibleValuesParser::new(["ordinal_position", "name"])), |
| ) |
| .arg( |
| Arg::new("patch-file") |
| .long("patch-file") |
| .num_args(1) |
| .value_parser(clap::value_parser!(std::path::PathBuf)) |
| .help("A unified diff file to be applied to the final schema."), |
| ) |
| .arg( |
| Arg::new("import-types") |
| .long("import-types") |
| .num_args(1..) |
| .action(clap::ArgAction::Append) |
| .number_of_values(1) |
| .help("A list of types to import for every table, separated by commas."), |
| ) |
| .arg( |
| Arg::new("generate-custom-type-definitions") |
| .long("no-generate-missing-sql-type-definitions") |
| .action(ArgAction::SetTrue) |
| .help("Generate SQL type definitions for types not provided by diesel"), |
| ) |
| .arg( |
| Arg::new("custom-type-derives") |
| .long("custom-type-derives") |
| .num_args(1..) |
| .action(clap::ArgAction::Append) |
| .number_of_values(1) |
| .help("A list of derives to implement for every automatically generated SqlType in the schema, separated by commas."), |
| ); |
| |
| let config_arg = Arg::new("CONFIG_FILE") |
| .value_parser(clap::value_parser!(std::path::PathBuf)) |
| .long("config-file") |
| .help( |
| "The location of the configuration file to use. Falls back to the \ |
| `DIESEL_CONFIG_FILE` environment variable if unspecified. Defaults \ |
| to `diesel.toml` in your project root. See \ |
| diesel.rs/guides/configuring-diesel-cli for documentation on this file.", |
| ) |
| .global(true) |
| .num_args(1); |
| |
| let locked_schema_arg = Arg::new("LOCKED_SCHEMA") |
| .long("locked-schema") |
| .help("Require that the schema file is up to date.") |
| .long_help( |
| "When `print_schema.file` is specified in your config file, this \ |
| flag will cause Diesel CLI to error if any command would result in \ |
| changes to that file. It is recommended that you use this flag when \ |
| running migrations in CI or production.", |
| ) |
| .action(ArgAction::SetTrue) |
| .global(true); |
| |
| Command::new("diesel") |
| .version(clap::crate_version!()) |
| .long_version( |
| clap::builder::Str::from( |
| format!( |
| "\n Version: {}\n Supported Backends: {}", |
| clap::crate_version!(), |
| super::supported_backends() |
| ) |
| ) |
| ) |
| .after_help( |
| "You can also run `diesel SUBCOMMAND -h` to get more information about that subcommand.", |
| ) |
| .arg(database_arg) |
| .arg(config_arg) |
| .arg(locked_schema_arg) |
| .subcommand(migration_subcommand) |
| .subcommand(setup_subcommand) |
| .subcommand(database_subcommand) |
| .subcommand(generate_completions_subcommand) |
| .subcommand(infer_schema_subcommand) |
| .subcommand_required(true) |
| .arg_required_else_help(true) |
| } |
| |
| fn migration_dir_arg() -> Arg { |
| Arg::new("MIGRATION_DIRECTORY") |
| .long("migration-dir") |
| .help( |
| "The location of your migration directory. By default this \ |
| will look for a directory called `migrations` in the \ |
| current directory and its parents.", |
| ) |
| .num_args(1) |
| .value_parser(clap::value_parser!(std::path::PathBuf)) |
| .global(true) |
| } |