From 60feeb7ad6a63362c8e23958b72a390d89f10bbb Mon Sep 17 00:00:00 2001
From: Cecile Tonglet <cecile.tonglet@cecton.com>
Date: Thu, 16 Jan 2020 13:57:19 +0100
Subject: [PATCH] Getting configuration from commands (#4643)

* Expose a method that allows converting RunCmd to Configuration

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP
---
 substrate/bin/node/cli/src/cli.rs |   1 +
 substrate/client/cli/src/lib.rs   | 209 +++++++++++++++++++++++++++---
 2 files changed, 194 insertions(+), 16 deletions(-)

diff --git a/substrate/bin/node/cli/src/cli.rs b/substrate/bin/node/cli/src/cli.rs
index 4442bb1b037..dcc5d39dbb7 100644
--- a/substrate/bin/node/cli/src/cli.rs
+++ b/substrate/bin/node/cli/src/cli.rs
@@ -138,6 +138,7 @@ pub fn run<I, T, E>(args: I, exit: E, version: sc_cli::VersionInfo) -> error::Re
 				load_spec,
 				&cli_args.shared_params,
 				&version,
+				None,
 			)?;
 			sc_cli::fill_import_params(&mut config, &cli_args.import_params, ServiceRoles::FULL)?;
 
diff --git a/substrate/client/cli/src/lib.rs b/substrate/client/cli/src/lib.rs
index 1e8d40cb0f8..52a3fc46ec7 100644
--- a/substrate/client/cli/src/lib.rs
+++ b/substrate/client/cli/src/lib.rs
@@ -142,8 +142,13 @@ pub fn load_spec<F, G, E>(cli: &SharedParams, factory: F) -> error::Result<Chain
 	Ok(spec)
 }
 
-fn base_path(cli: &SharedParams, version: &VersionInfo) -> PathBuf {
+fn base_path(
+	cli: &SharedParams,
+	version: &VersionInfo,
+	default_base_path: Option<PathBuf>,
+) -> PathBuf {
 	cli.base_path.clone()
+		.or(default_base_path)
 		.unwrap_or_else(||
 			app_dirs::get_app_root(
 				AppDataType::UserData,
@@ -295,6 +300,78 @@ impl<'a, CC, RP> ParseAndPrepare<'a, CC, RP> where CC: GetSharedParams {
 	}
 }
 
+impl<'a, CC, RP> ParseAndPrepare<'a, CC, RP> {
+	/// Convert ParseAndPrepare to Configuration
+	pub fn into_configuration<C, G, E, S>(
+		self,
+		spec_factory: S,
+		default_base_path: Option<PathBuf>,
+	) -> error::Result<Option<Configuration<C, G, E>>>
+	where
+		C: Default,
+		G: RuntimeGenesis,
+		E: ChainSpecExtension,
+		S: FnOnce(&str) -> Result<Option<ChainSpec<G, E>>, String>,
+	{
+		match self {
+			ParseAndPrepare::Run(c) =>
+				Some(create_run_node_config(
+					c.params.left,
+					spec_factory,
+					c.impl_name,
+					c.version,
+					default_base_path,
+				)).transpose(),
+			ParseAndPrepare::BuildSpec(c) => {
+				let spec = load_spec(&c.params.shared_params, spec_factory)?;
+
+				Some(create_build_spec_config(
+					&spec,
+					&c.params.shared_params,
+					c.version,
+					default_base_path,
+				)).transpose()
+			},
+			ParseAndPrepare::ExportBlocks(c) =>
+				Some(create_config_with_db_path(
+					spec_factory,
+					&c.params.shared_params,
+					c.version,
+					default_base_path,
+				)).transpose(),
+			ParseAndPrepare::ImportBlocks(c) =>
+				Some(create_config_with_db_path(
+					spec_factory,
+					&c.params.shared_params,
+					c.version,
+					default_base_path,
+				)).transpose(),
+			ParseAndPrepare::CheckBlock(c) =>
+				Some(create_config_with_db_path(
+					spec_factory,
+					&c.params.shared_params,
+					c.version,
+					default_base_path,
+				)).transpose(),
+			ParseAndPrepare::PurgeChain(c) =>
+				Some(create_config_with_db_path(
+					spec_factory,
+					&c.params.shared_params,
+					c.version,
+					default_base_path,
+				)).transpose(),
+			ParseAndPrepare::RevertChain(c) =>
+				Some(create_config_with_db_path(
+					spec_factory,
+					&c.params.shared_params,
+					c.version,
+					default_base_path,
+				)).transpose(),
+			ParseAndPrepare::CustomCommand(_) => Ok(None),
+		}
+	}
+}
+
 /// Command ready to run the main client.
 pub struct ParseAndPrepareRun<'a, RP> {
 	params: MergeParameters<RunCmd, RP>,
@@ -321,7 +398,11 @@ impl<'a, RP> ParseAndPrepareRun<'a, RP> {
 		RS: FnOnce(Exit, RunCmd, RP, Configuration<C, G, CE>) -> Result<(), E>
 	{
 		let config = create_run_node_config(
-			self.params.left.clone(), spec_factory, self.impl_name, self.version,
+			self.params.left.clone(),
+			spec_factory,
+			self.impl_name,
+			self.version,
+			None,
 		)?;
 
 		run_service(exit, self.params.left, self.params.right, config).map_err(Into::into)
@@ -350,11 +431,12 @@ impl<'a> ParseAndPrepareBuildSpec<'a> {
 		let mut spec = load_spec(&self.params.shared_params, spec_factory)?;
 
 		if spec.boot_nodes().is_empty() && !self.params.disable_default_bootnode {
-			let base_path = base_path(&self.params.shared_params, self.version);
-			let cfg = sc_service::Configuration::<C,_,_>::default_with_spec_and_base_path(
-				spec.clone(),
-				Some(base_path),
-			);
+			let cfg = create_build_spec_config::<C, _, _>(
+				&spec,
+				&self.params.shared_params,
+				self.version,
+				None,
+			)?;
 			let node_key = node_key_config(
 				self.params.node_key_params,
 				&Some(cfg.in_chain_config_dir(DEFAULT_NETWORK_CONFIG_PATH).expect("We provided a base_path"))
@@ -401,7 +483,12 @@ impl<'a> ParseAndPrepareExport<'a> {
 		E: ChainSpecExtension,
 		Exit: IntoExit
 	{
-		let mut config = create_config_with_db_path(spec_factory, &self.params.shared_params, self.version)?;
+		let mut config = create_config_with_db_path(
+			spec_factory,
+			&self.params.shared_params,
+			self.version,
+			None,
+		)?;
 		fill_config_keystore_in_memory(&mut config)?;
 
 		if let DatabaseConfig::Path { ref path, .. } = &config.database {
@@ -463,7 +550,12 @@ impl<'a> ParseAndPrepareImport<'a> {
 		E: ChainSpecExtension,
 		Exit: IntoExit
 	{
-		let mut config = create_config_with_db_path(spec_factory, &self.params.shared_params, self.version)?;
+		let mut config = create_config_with_db_path(
+			spec_factory,
+			&self.params.shared_params,
+			self.version,
+			None,
+		)?;
 		fill_import_params(&mut config, &self.params.import_params, sc_service::Roles::FULL)?;
 
 		let file: Box<dyn ReadPlusSeek + Send> = match self.params.input {
@@ -522,7 +614,12 @@ impl<'a> CheckBlock<'a> {
 			E: ChainSpecExtension,
 			Exit: IntoExit
 	{
-		let mut config = create_config_with_db_path(spec_factory, &self.params.shared_params, self.version)?;
+		let mut config = create_config_with_db_path(
+			spec_factory,
+			&self.params.shared_params,
+			self.version,
+			None,
+		)?;
 		fill_import_params(&mut config, &self.params.import_params, sc_service::Roles::FULL)?;
 		fill_config_keystore_in_memory(&mut config)?;
 
@@ -562,7 +659,10 @@ impl<'a> ParseAndPreparePurge<'a> {
 		E: ChainSpecExtension,
 	{
 		let mut config = create_config_with_db_path::<(), _, _, _>(
-			spec_factory, &self.params.shared_params, self.version
+			spec_factory,
+			&self.params.shared_params,
+			self.version,
+			None,
 		)?;
 		fill_config_keystore_in_memory(&mut config)?;
 		let db_path = match config.database {
@@ -627,7 +727,10 @@ impl<'a> ParseAndPrepareRevert<'a> {
 		E: ChainSpecExtension,
 	{
 		let mut config = create_config_with_db_path(
-			spec_factory, &self.params.shared_params, self.version
+			spec_factory,
+			&self.params.shared_params,
+			self.version,
+			None,
 		)?;
 		fill_config_keystore_in_memory(&mut config)?;
 
@@ -852,7 +955,11 @@ pub fn fill_import_params<C, G, E>(
 }
 
 fn create_run_node_config<C, G, E, S>(
-	cli: RunCmd, spec_factory: S, impl_name: &'static str, version: &VersionInfo,
+	cli: RunCmd,
+	spec_factory: S,
+	impl_name: &'static str,
+	version: &VersionInfo,
+	default_base_path: Option<PathBuf>,
 ) -> error::Result<Configuration<C, G, E>>
 where
 	C: Default,
@@ -860,7 +967,12 @@ where
 	E: ChainSpecExtension,
 	S: FnOnce(&str) -> Result<Option<ChainSpec<G, E>>, String>,
 {
-	let mut config = create_config_with_db_path(spec_factory, &cli.shared_params, &version)?;
+	let mut config = create_config_with_db_path(
+		spec_factory,
+		&cli.shared_params,
+		&version,
+		default_base_path,
+	)?;
 
 	fill_config_keystore_password_and_path(&mut config, &cli)?;
 
@@ -994,7 +1106,10 @@ fn interface_str(
 
 /// Creates a configuration including the database path.
 pub fn create_config_with_db_path<C, G, E, S>(
-	spec_factory: S, cli: &SharedParams, version: &VersionInfo,
+	spec_factory: S,
+	cli: &SharedParams,
+	version: &VersionInfo,
+	default_base_path: Option<PathBuf>,
 ) -> error::Result<Configuration<C, G, E>>
 where
 	C: Default,
@@ -1003,7 +1118,7 @@ where
 	S: FnOnce(&str) -> Result<Option<ChainSpec<G, E>>, String>,
 {
 	let spec = load_spec(cli, spec_factory)?;
-	let base_path = base_path(cli, version);
+	let base_path = base_path(cli, version, default_base_path);
 
 	let mut config = sc_service::Configuration::default_with_spec_and_base_path(
 		spec.clone(),
@@ -1018,6 +1133,27 @@ where
 	Ok(config)
 }
 
+/// Creates a configuration including the base path and the shared params
+fn create_build_spec_config<C, G, E>(
+	spec: &ChainSpec<G, E>,
+	cli: &SharedParams,
+	version: &VersionInfo,
+	default_base_path: Option<PathBuf>,
+) -> error::Result<Configuration<C, G, E>>
+where
+	C: Default,
+	G: RuntimeGenesis,
+	E: ChainSpecExtension,
+{
+	let base_path = base_path(&cli, version, default_base_path);
+	let cfg = sc_service::Configuration::<C,_,_>::default_with_spec_and_base_path(
+		spec.clone(),
+		Some(base_path),
+	);
+
+	Ok(cfg)
+}
+
 /// Internal trait used to cast to a dynamic type that implements Read and Seek.
 trait ReadPlusSeek: Read + Seek {}
 
@@ -1255,6 +1391,7 @@ mod tests {
 				|_| Ok(Some(chain_spec.clone())),
 				"test",
 				&version_info,
+				None,
 			).unwrap();
 
 			let expected_path = match keystore_path {
@@ -1265,4 +1402,44 @@ mod tests {
 			assert_eq!(expected_path, node_config.keystore.path().unwrap().to_owned());
 		}
 	}
+
+	#[test]
+	fn parse_and_prepare_into_configuration() {
+		let chain_spec = ChainSpec::from_genesis(
+			"test",
+			"test-id",
+			|| (),
+			Vec::new(),
+			None,
+			None,
+			None,
+			None,
+		);
+		let version = VersionInfo {
+			name: "test",
+			version: "42",
+			commit: "234234",
+			executable_name: "test",
+			description: "cool test",
+			author: "universe",
+			support_url: "com",
+		};
+		let spec_factory = |_: &str| Ok(Some(chain_spec.clone()));
+
+		let args = vec!["substrate", "--dev", "--state-cache-size=42"];
+		let pnp = parse_and_prepare::<NoCustom, NoCustom, _>(&version, "test", args);
+		let config = pnp.into_configuration::<(), _, _, _>(spec_factory, None).unwrap().unwrap();
+		assert_eq!(config.roles, sc_service::Roles::AUTHORITY);
+		assert_eq!(config.state_cache_size, 42);
+
+		let args = vec!["substrate", "import-blocks", "--dev"];
+		let pnp = parse_and_prepare::<NoCustom, NoCustom, _>(&version, "test", args);
+		let config = pnp.into_configuration::<(), _, _, _>(spec_factory, None).unwrap().unwrap();
+		assert_eq!(config.roles, sc_service::Roles::FULL);
+
+		let args = vec!["substrate", "--base-path=/foo"];
+		let pnp = parse_and_prepare::<NoCustom, NoCustom, _>(&version, "test", args);
+		let config = pnp.into_configuration::<(), _, _, _>(spec_factory, Some("/bar".into())).unwrap().unwrap();
+		assert_eq!(config.config_dir, Some("/foo".into()));
+	}
 }
-- 
GitLab