new.rs 3.33 KB
Newer Older
1
// Copyright 2018-2019 Parity Technologies (UK) Ltd.
2
// This file is part of ink!.
3
//
4
// ink! is free software: you can redistribute it and/or modify
5
6
7
8
// 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.
//
9
// ink! is distributed in the hope that it will be useful,
10
11
12
13
14
// 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
15
// along with ink!.  If not, see <http://www.gnu.org/licenses/>.
16

17
18
19
20
21
22
23
24
use crate::{
    cmd::{
        CommandError,
        CommandErrorKind,
        Result,
    },
    AbstractionLayer,
};
25
26
27
28
29
use heck::CamelCase as _;
use std::{
    fs,
    io::{
        Cursor,
Hero Bird's avatar
Hero Bird committed
30
        Read,
31
32
33
34
35
36
        Seek,
        SeekFrom,
        Write,
    },
    path,
};
37

38
39
/// Initializes a project structure for the `lang` abstraction layer.
fn initialize_for_lang(name: &str) -> Result<()> {
40
41
42
    if name.contains("-") {
        return Err("Contract names cannot contain hyphens".into())
    }
43
    fs::create_dir(name)?;
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
    let out_dir = path::Path::new(name);

    let template = include_bytes!(concat!(env!("OUT_DIR"), "/template.zip"));
    let mut cursor = Cursor::new(Vec::new());
    cursor.write_all(template)?;
    cursor.seek(SeekFrom::Start(0))?;

    let mut archive = zip::ZipArchive::new(cursor)?;

    for i in 0..archive.len() {
        let mut file = archive.by_index(i)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;

        // replace template placeholders
        let contents = contents.replace("{{name}}", name);
        let contents = contents.replace("{{camel_name}}", &name.to_camel_case());

        let outpath = out_dir.join(file.sanitized_name());

        if (&*file.name()).ends_with('/') {
            fs::create_dir_all(&outpath)?;
        } else {
            if let Some(p) = outpath.parent() {
                if !p.exists() {
                    fs::create_dir_all(&p)?;
                }
            }
            let mut outfile = fs::File::create(&outpath)?;
Hero Bird's avatar
Hero Bird committed
73
            outfile.write_all(contents.as_bytes())?;
74
75
76
77
78
79
80
81
82
83
84
85
86
        }

        // Get and set permissions
        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;

            if let Some(mode) = file.unix_mode() {
                fs::set_permissions(&outpath, fs::Permissions::from_mode(mode))?;
            }
        }
    }

87
88
89
    Ok(())
}

Hero Bird's avatar
Hero Bird committed
90
pub(crate) fn execute_new(layer: AbstractionLayer, name: &str) -> Result<()> {
91
92
93
94
95
96
97
98
99
100
101
102
103
104
    match layer {
        AbstractionLayer::Core => {
            Err(CommandError::new(
                CommandErrorKind::UnimplementedAbstractionLayer,
            ))
        }
        AbstractionLayer::Model => {
            Err(CommandError::new(
                CommandErrorKind::UnimplementedAbstractionLayer,
            ))
        }
        AbstractionLayer::Lang => initialize_for_lang(name),
    }
}
105
106
107
108
109
110
111
112
113
114
115
116

#[cfg(test)]
mod tests {
    #[test]
    fn rejects_hyphenated_name() {
        let result = super::initialize_for_lang("should-fail");
        assert_eq!(
            format!("{:?}", result),
            r#"Err(CommandError { kind: Other("Contract names cannot contain hyphens") })"#
        )
    }
}