nereond/
lib.rs

1// Copyright (c) 2018, [Ribose Inc](https://www.ribose.com).
2//
3// Redistribution and use in source and binary forms, with or without
4// modification, are permitted provided that the following conditions
5// are met:
6// 1. Redistributions of source code must retain the above copyright
7//    notice, this list of conditions and the following disclaimer.
8// 2. Redistributions in binary form must reproduce the above copyright
9//    notice, this list of conditions and the following disclaimer in the
10//    documentation and/or other materials provided with the distribution.
11//
12// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
13// ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
14// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
15// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
16// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
17// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
18// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
22// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23
24extern crate base64;
25extern crate libc;
26extern crate nereon;
27
28#[macro_use]
29extern crate nereon_derive;
30
31#[macro_use]
32extern crate log;
33
34mod file;
35mod distro;
36
37use nereon::{FromValue, Value};
38use std::env;
39use std::fs;
40
41const VERSION: &str = env!("CARGO_PKG_VERSION");
42const AUTHORS: &str = env!("CARGO_PKG_AUTHORS");
43const LICENSE: &str = "BSD-2-Clause";
44const APPNAME: &str = env!("CARGO_PKG_NAME");
45
46#[derive(Debug, FromValue)]
47struct Config {
48    packages: Vec<String>,
49    fileset_file: Option<String>,
50    fileset_env: Option<String>,
51}
52
53pub fn nereond() -> Result<(), String> {
54    let nos = format!(
55        r#"
56        authors ["{}"]
57        license "{}"
58        name "{}"
59        version {}
60        option fileset_file {{
61            flags [takesvalue]
62            short f
63            long fileset
64            env NEREON_FILESET_FILE
65            hint FILE
66            usage "File containing a nereon fileset"
67            key [fileset_file]
68        }},
69        option fileset {{
70            flags [takesvalue]
71            long fileset-env
72            env NEREON_FILESET
73            hint FILESET
74            usage "Fileset as environment variable"
75            key [fileset_env]
76        }},
77        option packages {{
78            flags [takesvalue, multiple]
79            long package
80            short p
81            hint PACKAGE
82            usage "Install package using apt, yum etc."
83            key [packages]
84        }}"#,
85        AUTHORS, LICENSE, APPNAME, VERSION
86    );
87
88    let config = nereon::configure::<Config, _, _>(&nos, env::args()).unwrap();
89
90    // install packages
91    distro::install_packages(&config.packages)?;
92
93    // get the fileset from file/env
94    config
95        .fileset_file
96        .as_ref()
97        .map_or_else(
98            || {
99                config.fileset_env.as_ref().map_or_else(
100                    || Err("No fileset from args or environment.".to_owned()),
101                    |s| {
102                        base64::decode(&s)
103                            .map_err(|_| "Invalid base64 data in env[NEREON_FILESET]".to_owned())
104                            .and_then(|bs| {
105                                String::from_utf8(bs).map_err(|_| {
106                                    "Invalid utf8 data in env[NEREON_FILESET]".to_owned()
107                                })
108                            })
109                    },
110                )
111            },
112            |file| {
113                fs::read_to_string(&file)
114                    .map_err(|e| format!("Failed to read fileset file {}: {:?}.", file, e))
115            },
116        ).and_then(|fileset| file::parse_fileset(&mut fileset.as_bytes()))
117        .map(|fileset| {
118            fileset.iter().for_each(|(id, (f, decoded_content))| {
119                f.update(decoded_content)
120                    .map_err(|e| warn!("Failed to update {}: {}", id, e))
121                    .ok();
122            })
123        })
124
125    // At this point we're initialized: ie written an initial set of configs.
126    // To signal this we either fork and continue to listen for configuration updates
127    // or simply exit.
128
129    // Either way, control should return to the process spawner which now can start
130    // any processes dependent on nereond for configuration.
131}