Skip to content

Commit 381fe74

Browse files
committed
Command mapping with get_commands()
The cmd module now takes responsibility for collecting all the StGit commands. The new StGitCommand struct defines a common function call interface for commands. Each command module defines a get_command() function that returns its StGitCommand instance. In main(), the clap::App can now be setup more generically, without main() having to have knowledge of each individual command.
1 parent e92bc3f commit 381fe74

File tree

8 files changed

+68
-29
lines changed

8 files changed

+68
-29
lines changed

src/cmd/id.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@ use git2::Repository;
33

44
use crate::revspec::parse_stgit_revision;
55

6-
pub(crate) fn get_subcommand<'help>() -> App<'help> {
6+
pub(super) fn get_command() -> (&'static str, super::StGitCommand) {
7+
("id", super::StGitCommand { get_app, run })
8+
}
9+
10+
fn get_app() -> App<'static> {
711
App::new("id")
812
.about("Print git hash of StGit revision")
913
.long_about("Long about for 'id'.") // TODO
@@ -19,7 +23,7 @@ pub(crate) fn get_subcommand<'help>() -> App<'help> {
1923
.arg(Arg::new("revision").about("StGit revision"))
2024
}
2125

22-
pub(crate) fn run(matches: &ArgMatches) -> super::Result {
26+
fn run(matches: &ArgMatches) -> super::Result {
2327
let opt_branch = matches.value_of("branch");
2428
let opt_spec = matches.value_of("revision");
2529

src/cmd/init.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
1-
use clap::App;
1+
use clap::{App, ArgMatches};
22
use git2::Repository;
33

44
use crate::stack::Stack;
55

6-
pub(crate) fn get_subcommand() -> App<'static> {
6+
pub(super) fn get_command() -> (&'static str, super::StGitCommand) {
7+
("init", super::StGitCommand { get_app, run })
8+
}
9+
10+
fn get_app() -> App<'static> {
711
App::new("init").about("Initialize StGit stack on current branch")
812
}
913

10-
pub(crate) fn run() -> super::Result {
14+
fn run(_: &ArgMatches) -> super::Result {
1115
let repo = Repository::open_from_env()?;
1216
let branch_name = None;
1317
Stack::initialize(&repo, branch_name)?;

src/cmd/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::collections::BTreeMap;
2+
13
pub(crate) mod branch;
24
pub(crate) mod clean;
35
pub(crate) mod clone;
@@ -42,3 +44,19 @@ pub(crate) mod unhide;
4244
pub(crate) mod version;
4345

4446
pub(crate) type Result = std::result::Result<(), crate::error::Error>;
47+
48+
pub(crate) struct StGitCommand {
49+
pub get_app: fn() -> clap::App<'static>,
50+
pub run: fn(&clap::ArgMatches) -> Result,
51+
}
52+
53+
pub(crate) fn get_commands() -> BTreeMap<&'static str, StGitCommand> {
54+
BTreeMap::from([
55+
id::get_command(),
56+
init::get_command(),
57+
new::get_command(),
58+
refresh::get_command(),
59+
series::get_command(),
60+
version::get_command(),
61+
])
62+
}

src/cmd/new.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ use crate::{
1111
stack::{ConflictMode, Stack, StackTransaction},
1212
};
1313

14-
pub(crate) fn get_subcommand() -> App<'static> {
14+
pub(super) fn get_command() -> (&'static str, super::StGitCommand) {
15+
("new", super::StGitCommand { get_app, run })
16+
}
17+
18+
fn get_app() -> App<'static> {
1519
App::new("new")
1620
.about("Create a new patch at top of the stack")
1721
.long_about(
@@ -49,7 +53,7 @@ pub(crate) fn get_subcommand() -> App<'static> {
4953
)
5054
}
5155

52-
pub(crate) fn run(matches: &ArgMatches) -> super::Result {
56+
fn run(matches: &ArgMatches) -> super::Result {
5357
let repo = Repository::open_from_env()?;
5458
let branch_name: Option<&str> = None;
5559
let stack = Stack::from_branch(&repo, branch_name)?;

src/cmd/refresh.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,11 @@ use clap::{App, Arg, ArgGroup, ArgMatches, ArgSettings, ValueHint};
22

33
use crate::argset;
44

5-
pub(crate) fn get_subcommand() -> App<'static> {
5+
pub(super) fn get_command() -> (&'static str, super::StGitCommand) {
6+
("refresh", super::StGitCommand { get_app, run })
7+
}
8+
9+
fn get_app() -> App<'static> {
610
App::new("refresh")
711
.about("Incorporate worktree changes into current patch")
812
.long_about(
@@ -111,7 +115,7 @@ pub(crate) fn get_subcommand() -> App<'static> {
111115
.arg(&*argset::DIFF_OPTS_ARG)
112116
}
113117

114-
pub(crate) fn run(_matches: &ArgMatches) -> super::Result {
118+
fn run(_matches: &ArgMatches) -> super::Result {
115119
println!("refresh!");
116120
Ok(())
117121
}

src/cmd/series.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ use termcolor::WriteColor;
66

77
use crate::{patchname::PatchName, stack::Stack};
88

9+
use super::StGitCommand;
10+
911
const UNPRINTABLE: &str = "???";
1012

11-
pub(crate) fn get_subcommand() -> App<'static> {
13+
pub(super) fn get_command() -> (&'static str, StGitCommand) {
14+
("series", StGitCommand { get_app, run })
15+
}
16+
17+
fn get_app() -> App<'static> {
1218
App::new("series")
1319
.about("Print the patch series")
1420
.long_about(
@@ -121,7 +127,7 @@ pub(crate) fn get_subcommand() -> App<'static> {
121127
.group(ArgGroup::new("all-short-group").args(&["all", "short"]))
122128
}
123129

124-
pub(crate) fn run(matches: &ArgMatches) -> super::Result {
130+
fn run(matches: &ArgMatches) -> super::Result {
125131
let repo = Repository::open_from_env()?;
126132
let opt_branch = matches.value_of("branch");
127133
let stack = Stack::from_branch(&repo, opt_branch)?;

src/cmd/version.rs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
1-
use clap::App;
1+
use clap::{App, ArgMatches};
22

3-
pub(crate) fn get_subcommand() -> App<'static> {
3+
pub(super) fn get_command() -> (&'static str, super::StGitCommand) {
4+
("version", super::StGitCommand { get_app, run })
5+
}
6+
7+
fn get_app() -> App<'static> {
48
App::new("version").about("Print version information and exit")
59
}
610

7-
pub(crate) fn run() -> super::Result {
11+
fn run(_: &ArgMatches) -> super::Result {
812
println!("Stacked Git {}", env!("CARGO_PKG_VERSION"));
913
std::process::Command::new("git")
1014
.arg("--version")

src/main.rs

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ use pyo3::prelude::*;
2323
use termcolor::WriteColor;
2424

2525
fn main() {
26+
let commands = crate::cmd::get_commands();
2627
let app = App::new("stg")
2728
.about("Maintain a stack of patches on top of a Git branch.")
2829
.global_setting(AppSettings::DeriveDisplayOrder)
@@ -34,27 +35,21 @@ fn main() {
3435
.license(crate_license!())
3536
.max_term_width(88)
3637
.subcommand_placeholder("command", "COMMANDS")
37-
.subcommand(cmd::init::get_subcommand())
38-
.subcommand(cmd::new::get_subcommand())
39-
.subcommand(cmd::series::get_subcommand())
40-
.subcommand(cmd::refresh::get_subcommand())
41-
.subcommand(cmd::id::get_subcommand())
42-
.subcommand(cmd::version::get_subcommand());
38+
.subcommands(commands.values().map(|command| (command.get_app)()));
4339

4440
// TODO: alias subcommands from config (stgit.alias.)
4541
// TODO: add top-level -C option
4642
// TODO: get repository and/or stack handle for subcommand
4743

4844
let matches = app.get_matches();
49-
50-
let result: cmd::Result = match matches.subcommand() {
51-
Some(("id", cmd_matches)) => cmd::id::run(cmd_matches),
52-
Some(("init", _)) => cmd::init::run(),
53-
Some(("new", cmd_matches)) => cmd::new::run(cmd_matches),
54-
// Some(("refresh", cmd_matches)) => cmd::refresh::run(cmd_matches),
55-
Some(("series", cmd_matches)) => cmd::series::run(cmd_matches),
56-
Some(("version", _)) => cmd::version::run(),
57-
_ => punt_to_python(),
45+
let result: cmd::Result = if let Some((command_name, cmd_matches)) = matches.subcommand() {
46+
if let Some(command) = commands.get(command_name) {
47+
(command.run)(cmd_matches)
48+
} else {
49+
punt_to_python()
50+
}
51+
} else {
52+
panic!("no subcommand?")
5853
};
5954

6055
if let Err(e) = result {

0 commit comments

Comments
 (0)