@@ -207,6 +207,9 @@ pub struct BuildSpecCommand {
207207 /// based on `runtime`.
208208 #[ clap( long, requires = "deterministic" ) ]
209209 pub package : Option < String > ,
210+ /// Generate a raw chain specification.
211+ #[ arg( long) ]
212+ pub ( crate ) raw : bool ,
210213}
211214
212215impl BuildSpecCommand {
@@ -258,6 +261,7 @@ impl BuildSpecCommand {
258261 package,
259262 runtime_dir,
260263 is_relay,
264+ raw,
261265 ..
262266 } = self ;
263267
@@ -508,6 +512,7 @@ impl BuildSpecCommand {
508512 package,
509513 runtime_dir,
510514 use_existing_plain_spec : !prompt,
515+ raw,
511516 } )
512517 }
513518}
@@ -518,7 +523,7 @@ pub struct GenesisArtifacts {
518523 /// Path to the plain text chain specification file.
519524 pub chain_spec : PathBuf ,
520525 /// Path to the raw chain specification file.
521- pub raw_chain_spec : PathBuf ,
526+ pub raw_chain_spec : Option < PathBuf > ,
522527 /// Optional path to the genesis state file.
523528 pub genesis_state_file : Option < CodePathBuf > ,
524529 /// Optional path to the genesis code file.
@@ -570,6 +575,7 @@ pub(crate) struct BuildSpec {
570575 package : String ,
571576 runtime_dir : Option < PathBuf > ,
572577 use_existing_plain_spec : bool ,
578+ raw : bool ,
573579}
574580
575581impl BuildSpec {
@@ -655,54 +661,66 @@ impl BuildSpec {
655661 ) ) ;
656662 }
657663
658- // Generate raw spec.
659- spinner. set_message ( "Generating raw chain specification..." ) ;
660- let spec_name = self
661- . output_file
662- . file_name ( )
663- . and_then ( |s| s. to_str ( ) )
664- . unwrap_or ( DEFAULT_SPEC_NAME )
665- . trim_end_matches ( ".json" ) ;
666- let raw_spec_name = format ! ( "{spec_name}-raw.json" ) ;
667- let raw_chain_spec = builder. generate_raw_chain_spec ( & self . output_file , & raw_spec_name) ?;
668- generated_files. push ( format ! (
669- "Raw chain specification file generated at: {}" ,
670- raw_chain_spec. display( )
671- ) ) ;
664+ let ( raw_chain_spec, genesis_code_file, genesis_state_file) = if self . raw ||
665+ self . genesis_code ||
666+ self . genesis_state
667+ {
668+ // Generate raw spec.
669+ spinner. set_message ( "Generating raw chain specification..." ) ;
670+ let spec_name = self
671+ . output_file
672+ . file_name ( )
673+ . and_then ( |s| s. to_str ( ) )
674+ . unwrap_or ( DEFAULT_SPEC_NAME )
675+ . trim_end_matches ( ".json" ) ;
676+ let raw_spec_name = format ! ( "{spec_name}-raw.json" ) ;
677+ let raw_chain_spec =
678+ builder. generate_raw_chain_spec ( & self . output_file , & raw_spec_name) ?;
679+ generated_files. push ( format ! (
680+ "Raw chain specification file generated at: {}" ,
681+ raw_chain_spec. display( )
682+ ) ) ;
672683
673- if is_runtime_build {
674- // The runtime version of the raw chain spec does not include certain parameters, like
675- // the relay chain, so we have to overwrite them again.
676- self . customize ( & raw_chain_spec) ?;
677- }
684+ if is_runtime_build {
685+ // The runtime version of the raw chain spec does not include certain parameters,
686+ // like the relay chain, so we have to overwrite them again.
687+ self . customize ( & raw_chain_spec) ?;
688+ }
678689
679- // Generate genesis artifacts.
680- let genesis_code_file = if self . genesis_code {
681- spinner. set_message ( "Generating genesis code..." ) ;
682- let wasm_file = builder. export_wasm_file ( & raw_chain_spec, "genesis-code.wasm" ) ?;
683- generated_files
684- . push ( format ! ( "WebAssembly runtime file exported at: {}" , wasm_file. display( ) ) ) ;
685- Some ( wasm_file)
686- } else {
687- None
688- } ;
689- let genesis_state_file = if self . genesis_state {
690- spinner. set_message ( "Generating genesis state..." ) ;
691- let binary_path = match builder {
692- ChainSpecBuilder :: Runtime { .. } =>
693- source_polkadot_omni_node_binary ( cli, & spinner, & crate :: cache ( ) ?, true ) . await ?,
694- ChainSpecBuilder :: Node { .. } => builder. artifact_path ( ) ?,
690+ // Generate genesis artifacts.
691+ let genesis_code_file = if self . genesis_code {
692+ spinner. set_message ( "Generating genesis code..." ) ;
693+ let wasm_file = builder. export_wasm_file ( & raw_chain_spec, "genesis-code.wasm" ) ?;
694+ generated_files
695+ . push ( format ! ( "WebAssembly runtime file exported at: {}" , wasm_file. display( ) ) ) ;
696+ Some ( wasm_file)
697+ } else {
698+ None
695699 } ;
696- let genesis_state_file = generate_genesis_state_file_with_node (
697- & binary_path,
698- & raw_chain_spec,
699- "genesis-state" ,
700- ) ?;
701- generated_files
702- . push ( format ! ( "Genesis State file exported at: {}" , genesis_state_file. display( ) ) ) ;
703- Some ( genesis_state_file)
700+ let genesis_state_file = if self . genesis_state {
701+ spinner. set_message ( "Generating genesis state..." ) ;
702+ let binary_path = match builder {
703+ ChainSpecBuilder :: Runtime { .. } =>
704+ source_polkadot_omni_node_binary ( cli, & spinner, & crate :: cache ( ) ?, true )
705+ . await ?,
706+ ChainSpecBuilder :: Node { .. } => builder. artifact_path ( ) ?,
707+ } ;
708+ let genesis_state_file = generate_genesis_state_file_with_node (
709+ & binary_path,
710+ & raw_chain_spec,
711+ "genesis-state" ,
712+ ) ?;
713+ generated_files. push ( format ! (
714+ "Genesis State file exported at: {}" ,
715+ genesis_state_file. display( )
716+ ) ) ;
717+ Some ( genesis_state_file)
718+ } else {
719+ None
720+ } ;
721+ ( Some ( raw_chain_spec) , genesis_code_file, genesis_state_file)
704722 } else {
705- None
723+ ( None , None , None )
706724 } ;
707725
708726 spinner. stop ( "Chain specification built successfully." ) ;
@@ -789,15 +807,16 @@ fn prepare_output_path(output_path: impl AsRef<Path>) -> anyhow::Result<PathBuf>
789807 . and_then ( |ext| ext. to_str ( ) )
790808 . map ( |ext| ext. eq_ignore_ascii_case ( "json" ) )
791809 . unwrap_or ( false ) ;
810+ let is_dir = output_path. is_dir ( ) ;
792811
793- if ! is_json_file {
794- // Treat as directory.
812+ if is_dir || ( !output_path . exists ( ) && ! is_json_file) {
813+ // Treat as directory (existing or to-be-created)
795814 if !output_path. exists ( ) {
796815 create_dir_all ( & output_path) ?;
797816 }
798817 output_path. push ( DEFAULT_SPEC_NAME ) ;
799818 } else {
800- // Treat as file.
819+ // Treat as file; ensure parent dir exists
801820 if let Some ( parent_dir) = output_path. parent ( ) &&
802821 !parent_dir. exists ( )
803822 {
@@ -837,6 +856,7 @@ mod tests {
837856 let runtime_dir = PathBuf :: from ( "./new-runtime-dir" ) ;
838857 let path = PathBuf :: from ( "./" ) ;
839858 let properties = "tokenSymbol=UNIT,decimals=12,isEthereum=false" ;
859+ let raw = true ;
840860
841861 let mut flags_used = false ;
842862 for ( build_spec_cmd, chain) in [
@@ -865,6 +885,7 @@ mod tests {
865885 deterministic : Some ( deterministic) ,
866886 package : Some ( package. to_string ( ) ) ,
867887 runtime_dir : Some ( runtime_dir. clone ( ) ) ,
888+ raw,
868889 } ,
869890 Some ( "local" . to_string ( ) ) ,
870891 ) ,
@@ -891,6 +912,7 @@ mod tests {
891912 deterministic : Some ( deterministic) ,
892913 package : Some ( package. to_string ( ) ) ,
893914 runtime_dir : Some ( runtime_dir. clone ( ) ) ,
915+ raw,
894916 } ,
895917 Some ( "local" . to_string ( ) ) ,
896918 ) ,
@@ -1034,6 +1056,7 @@ mod tests {
10341056 deterministic : None ,
10351057 package : Some ( package. to_string ( ) ) ,
10361058 runtime_dir : Some ( runtime_dir. clone ( ) ) ,
1059+ raw : true ,
10371060 } ,
10381061 // All flags used. Relay
10391062 BuildSpecCommand {
@@ -1057,6 +1080,7 @@ mod tests {
10571080 deterministic : None ,
10581081 package : Some ( package. to_string ( ) ) ,
10591082 runtime_dir : Some ( runtime_dir. clone ( ) ) ,
1083+ raw : true ,
10601084 } ,
10611085 ] {
10621086 let mut cli = MockCli :: new ( ) . expect_confirm (
0 commit comments