This repository has been archived by the owner on Nov 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
CLI API refactoring and improvement (#4692)
It changes the way we extended the CLI functionalities of substrate to allow more flexibility. (If this was not clear, here is another version: it changes the `sc_cli` API to allow more flexibility). This touches a few important things: - the startup of the async task with tokei: This was in node and node-template and I moved it to substrate. The idea is to have 1 time the code that handles unix signals (SIGTERM and SIGINT) properly. It is however possible to make this more generic to wait for a future instead and provide only a helper for the basic handling of SIGTERM and SIGINT. - increased the version of structopt and tokei - no more use of structopt internal's API - less use of generics Related to #4643 and paritytech/cumulus#42: the implementation of "into_configuration" and "get_config" are similar but with better flexibility so it is now possible in cumulus to have the command-line arguments only of the run command for polkadot if we want Related to paritytech/cumulus#24 and paritytech/cumulus#34 : it will now be possible to make a configuration struct for polkadot with some overrides of the default parameters much more easily.
- Loading branch information
Showing
28 changed files
with
2,024 additions
and
2,217 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,121 +1,11 @@ | ||
use crate::service; | ||
use futures::{future::{select, Map, Either}, FutureExt, channel::oneshot}; | ||
use std::cell::RefCell; | ||
use tokio::runtime::Runtime; | ||
pub use sc_cli::{VersionInfo, IntoExit, error}; | ||
use sc_cli::{display_role, informant, parse_and_prepare, ParseAndPrepare, NoCustom}; | ||
use sc_service::{AbstractService, Roles as ServiceRoles, Configuration}; | ||
use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; | ||
use crate::chain_spec; | ||
use log::info; | ||
use sc_cli::{RunCmd, Subcommand}; | ||
use structopt::StructOpt; | ||
|
||
/// Parse command line arguments into service configuration. | ||
pub fn run<I, T, E>(args: I, exit: E, version: VersionInfo) -> error::Result<()> where | ||
I: IntoIterator<Item = T>, | ||
T: Into<std::ffi::OsString> + Clone, | ||
E: IntoExit, | ||
{ | ||
type Config<T> = Configuration<(), T>; | ||
match parse_and_prepare::<NoCustom, NoCustom, _>(&version, "substrate-node", args) { | ||
ParseAndPrepare::Run(cmd) => cmd.run(load_spec, exit, | ||
|exit, _cli_args, _custom_args, mut config: Config<_>| { | ||
info!("{}", version.name); | ||
info!(" version {}", config.full_version()); | ||
info!(" by {}, 2017, 2018", version.author); | ||
info!("Chain specification: {}", config.chain_spec.name()); | ||
info!("Node name: {}", config.name); | ||
info!("Roles: {}", display_role(&config)); | ||
let runtime = Runtime::new().map_err(|e| format!("{:?}", e))?; | ||
config.tasks_executor = { | ||
let runtime_handle = runtime.handle().clone(); | ||
Some(Box::new(move |fut| { runtime_handle.spawn(fut); })) | ||
}; | ||
match config.roles { | ||
ServiceRoles::LIGHT => run_until_exit( | ||
runtime, | ||
service::new_light(config)?, | ||
exit | ||
), | ||
_ => run_until_exit( | ||
runtime, | ||
service::new_full(config)?, | ||
exit | ||
), | ||
} | ||
}), | ||
ParseAndPrepare::BuildSpec(cmd) => cmd.run::<NoCustom, _, _, _>(load_spec), | ||
ParseAndPrepare::ExportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>| | ||
Ok(new_full_start!(config).0), load_spec, exit), | ||
ParseAndPrepare::ImportBlocks(cmd) => cmd.run_with_builder(|config: Config<_>| | ||
Ok(new_full_start!(config).0), load_spec, exit), | ||
ParseAndPrepare::CheckBlock(cmd) => cmd.run_with_builder(|config: Config<_>| | ||
Ok(new_full_start!(config).0), load_spec, exit), | ||
ParseAndPrepare::PurgeChain(cmd) => cmd.run(load_spec), | ||
ParseAndPrepare::RevertChain(cmd) => cmd.run_with_builder(|config: Config<_>| | ||
Ok(new_full_start!(config).0), load_spec), | ||
ParseAndPrepare::CustomCommand(_) => Ok(()) | ||
}?; | ||
#[derive(Debug, StructOpt)] | ||
pub struct Cli { | ||
#[structopt(subcommand)] | ||
pub subcommand: Option<Subcommand>, | ||
|
||
Ok(()) | ||
} | ||
|
||
fn load_spec(id: &str) -> Result<Option<chain_spec::ChainSpec>, String> { | ||
Ok(match chain_spec::Alternative::from(id) { | ||
Some(spec) => Some(spec.load()?), | ||
None => None, | ||
}) | ||
} | ||
|
||
fn run_until_exit<T, E>( | ||
mut runtime: Runtime, | ||
service: T, | ||
e: E, | ||
) -> error::Result<()> | ||
where | ||
T: AbstractService, | ||
E: IntoExit, | ||
{ | ||
let (exit_send, exit) = oneshot::channel(); | ||
|
||
let informant = informant::build(&service); | ||
|
||
let handle = runtime.spawn(select(exit, informant)); | ||
|
||
// we eagerly drop the service so that the internal exit future is fired, | ||
// but we need to keep holding a reference to the global telemetry guard | ||
let _telemetry = service.telemetry(); | ||
|
||
let exit = e.into_exit(); | ||
let service_res = runtime.block_on(select(service, exit)); | ||
|
||
let _ = exit_send.send(()); | ||
|
||
if let Err(e) = runtime.block_on(handle) { | ||
log::error!("Error running node: {:?}", e); | ||
} | ||
|
||
match service_res { | ||
Either::Left((res, _)) => res.map_err(error::Error::Service), | ||
Either::Right((_, _)) => Ok(()) | ||
} | ||
} | ||
|
||
// handles ctrl-c | ||
pub struct Exit; | ||
impl IntoExit for Exit { | ||
type Exit = Map<oneshot::Receiver<()>, fn(Result<(), oneshot::Canceled>) -> ()>; | ||
fn into_exit(self) -> Self::Exit { | ||
// can't use signal directly here because CtrlC takes only `Fn`. | ||
let (exit_send, exit) = oneshot::channel(); | ||
|
||
let exit_send_cell = RefCell::new(Some(exit_send)); | ||
ctrlc::set_handler(move || { | ||
let exit_send = exit_send_cell.try_borrow_mut().expect("signal handler not reentrant; qed").take(); | ||
if let Some(exit_send) = exit_send { | ||
exit_send.send(()).expect("Error sending exit notification"); | ||
} | ||
}).expect("Error setting Ctrl-C handler"); | ||
|
||
exit.map(drop) | ||
} | ||
#[structopt(flatten)] | ||
pub run: RunCmd, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,48 @@ | ||
// Copyright 2017-2020 Parity Technologies (UK) Ltd. | ||
// This file is part of Substrate. | ||
|
||
// Substrate is free software: you can redistribute it and/or modify | ||
// it under the terms of the GNU General Public License as published by | ||
// the Free Software Foundation, either version 3 of the License, or | ||
// (at your option) any later version. | ||
|
||
// Substrate is distributed in the hope that it will be useful, | ||
// but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
// GNU General Public License for more details. | ||
|
||
// You should have received a copy of the GNU General Public License | ||
// along with Substrate. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
use sp_consensus_aura::sr25519::{AuthorityPair as AuraPair}; | ||
use sc_cli::{VersionInfo, error}; | ||
use crate::service; | ||
use crate::chain_spec; | ||
use crate::cli::Cli; | ||
|
||
/// Parse and run command line arguments | ||
pub fn run(version: VersionInfo) -> error::Result<()> | ||
{ | ||
let opt = sc_cli::from_args::<Cli>(&version); | ||
|
||
let mut config = sc_service::Configuration::default(); | ||
config.impl_name = "node-template"; | ||
|
||
match opt.subcommand { | ||
Some(subcommand) => sc_cli::run_subcommand( | ||
config, | ||
subcommand, | ||
chain_spec::load_spec, | ||
|config: _| Ok(new_full_start!(config).0), | ||
&version, | ||
), | ||
None => sc_cli::run( | ||
config, | ||
opt.run, | ||
service::new_light, | ||
service::new_full, | ||
chain_spec::load_spec, | ||
&version, | ||
) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.