1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
use std::path::{Path, PathBuf};

use provider::{
    constants::NODE_CONFIG_DIR,
    types::{GenerateFileCommand, GenerateFilesOptions, TransferedFile},
    DynNamespace,
};
use serde::Serialize;
use support::fs::FileSystem;
use uuid::Uuid;

use super::errors::GeneratorError;
use crate::ScopedFilesystem;

#[derive(Debug, Clone, Serialize)]
pub(crate) enum ParaArtifactType {
    Wasm,
    State,
}

#[derive(Debug, Clone, Serialize)]
pub(crate) enum ParaArtifactBuildOption {
    Path(String),
    Command(String),
}

/// Parachain artifact (could be either the genesis state or genesis wasm)
#[derive(Debug, Clone, Serialize)]
pub struct ParaArtifact {
    artifact_type: ParaArtifactType,
    build_option: ParaArtifactBuildOption,
    artifact_path: Option<PathBuf>,
    // image to use for building the para artifact
    image: Option<String>,
}

impl ParaArtifact {
    pub(crate) fn new(
        artifact_type: ParaArtifactType,
        build_option: ParaArtifactBuildOption,
    ) -> Self {
        Self {
            artifact_type,
            build_option,
            artifact_path: None,
            image: None,
        }
    }

    pub(crate) fn image(mut self, image: Option<String>) -> Self {
        self.image = image;
        self
    }

    pub(crate) fn artifact_path(&self) -> Option<&PathBuf> {
        self.artifact_path.as_ref()
    }

    pub(crate) async fn build<'a, T>(
        &mut self,
        chain_spec_path: Option<impl AsRef<Path>>,
        artifact_path: impl AsRef<Path>,
        ns: &DynNamespace,
        scoped_fs: &ScopedFilesystem<'a, T>,
    ) -> Result<(), GeneratorError>
    where
        T: FileSystem,
    {
        match &self.build_option {
            ParaArtifactBuildOption::Path(path) => {
                let t = TransferedFile::new(PathBuf::from(path), artifact_path.as_ref().into());
                scoped_fs.copy_files(vec![&t]).await?;
                self.artifact_path = Some(artifact_path.as_ref().into());
            },
            ParaArtifactBuildOption::Command(cmd) => {
                let generate_subcmd = match self.artifact_type {
                    ParaArtifactType::Wasm => "export-genesis-wasm",
                    ParaArtifactType::State => "export-genesis-state",
                };

                // TODO: replace uuid with para_id-random
                let temp_name = format!("temp-{}-{}", generate_subcmd, Uuid::new_v4());
                let mut args: Vec<String> = vec![generate_subcmd.into()];

                let files_to_inject = if let Some(chain_spec_path) = chain_spec_path {
                    // TODO: we should get the full path from the scoped filesystem
                    let chain_spec_path_local = format!(
                        "{}/{}",
                        ns.base_dir().to_string_lossy(),
                        chain_spec_path.as_ref().to_string_lossy()
                    );
                    // Remote path to be injected
                    let chain_spec_path_in_pod = format!(
                        "{}/{}",
                        NODE_CONFIG_DIR,
                        chain_spec_path.as_ref().to_string_lossy()
                    );
                    // Path in the context of the node, this can be different in the context of the providers (e.g native)
                    let chain_spec_path_in_args = if ns.capabilities().prefix_with_full_path {
                        // In native
                        format!(
                            "{}/{}{}",
                            ns.base_dir().to_string_lossy(),
                            &temp_name,
                            &chain_spec_path_in_pod
                        )
                    } else {
                        chain_spec_path_in_pod.clone()
                    };

                    args.push("--chain".into());
                    args.push(chain_spec_path_in_args);

                    vec![TransferedFile::new(
                        chain_spec_path_local,
                        chain_spec_path_in_pod,
                    )]
                } else {
                    vec![]
                };

                let artifact_path_ref = artifact_path.as_ref();
                let generate_command =
                    GenerateFileCommand::new(cmd.as_str(), artifact_path_ref).args(args);
                let options = GenerateFilesOptions::with_files(
                    vec![generate_command],
                    self.image.clone(),
                    &files_to_inject,
                )
                .temp_name(temp_name);
                ns.generate_files(options).await?;
                self.artifact_path = Some(artifact_path_ref.into());
            },
        }

        Ok(())
    }
}