repo_backup/
config.rs

1//! Configuration for `repo-backup`.
2
3use sec::Secret;
4use std::fs::File;
5use std::io::Read;
6use std::path::{Path, PathBuf};
7
8use failure::{Error, ResultExt};
9use toml;
10
11/// The overall configuration struct.
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub struct Config {
14    /// General configuration options.
15    pub general: General,
16    /// Settings specific to the `Github` provider.
17    pub github: Option<GithubConfig>,
18    /// Settings for the `GitLab` provider.
19    pub gitlab: Option<GitLabConfig>,
20}
21
22/// General settings used by `repo-backup`.
23#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
24#[serde(rename_all = "kebab-case")]
25pub struct General {
26    /// The root directory to place all downloaded repositories.
27    pub dest_dir: PathBuf,
28}
29
30/// Github-specific settings.
31#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
32#[serde(rename_all = "kebab-case")]
33pub struct GithubConfig {
34    /// The API key to use. You will need to [create a new personal access
35    /// token][new] and give it the `public_repo` permissions before you can
36    /// fetch repos from GitHub.
37    ///
38    /// [new]: https://github.com/settings/tokens/new
39    pub api_key: Secret<String>,
40    /// Should we download all starred repos? (default: true)
41    #[serde(default = "always_true")]
42    pub starred: bool,
43    /// Should we download all owned repos? (default: true)
44    #[serde(default = "always_true")]
45    pub owned: bool,
46}
47
48/// Github-specific settings.
49#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
50#[serde(rename_all = "kebab-case")]
51#[allow(deprecated)]
52pub struct GitLabConfig {
53    /// The API key to use. Make sure you create a new [personal access token][new]
54    /// and give it the "api" scope, if you haven't already.
55    ///
56    /// [new]: https://gitlab.com/profile/personal_access_tokens
57    pub api_key: Secret<String>,
58    /// Hostname of the GitLab instance to fetch repositories from.
59    #[serde(default = "default_gitlab_url")]
60    pub host: String,
61    /// Should we download all repos owned by organisations you are a part of?
62    /// (default: false)
63    #[serde(default = "always_false")]
64    pub organisations: bool,
65    /// Should we download all owned repos? (default: true)
66    #[serde(default = "always_true")]
67    pub owned: bool,
68}
69
70fn always_true() -> bool {
71    true
72}
73
74fn always_false() -> bool {
75    false
76}
77
78fn default_gitlab_url() -> String {
79    String::from("https://gitlab.com/")
80}
81
82impl Config {
83    /// Load a `Config` from some file on disk.
84    pub fn from_file<P: AsRef<Path>>(file: P) -> Result<Config, Error> {
85        let file = file.as_ref();
86        debug!("Reading config from {}", file.display());
87
88        let mut buffer = String::new();
89        File::open(file)
90            .with_context(|_| format!("Unable to open {}", file.display()))?
91            .read_to_string(&mut buffer)
92            .context("Reading config file failed")?;
93
94        Config::from_str(&buffer)
95    }
96
97    /// Load the config directly from a source string.
98    pub fn from_str(src: &str) -> Result<Config, Error> {
99        toml::from_str(src)
100            .context("Parsing config file failed")
101            .map_err(Error::from)
102    }
103
104    /// Generate an example config.
105    pub fn example() -> Config {
106        Config {
107            general: General {
108                dest_dir: PathBuf::from("/srv"),
109            },
110            github: Some(GithubConfig {
111                api_key: String::from("your API key").into(),
112                owned: true,
113                starred: false,
114            }),
115            gitlab: Some(GitLabConfig {
116                api_key: String::from("your API key").into(),
117                host: String::from("gitlab.com"),
118                organisations: true,
119                owned: true,
120            }),
121        }
122    }
123
124    /// Serialize the `Config` as TOML.
125    pub fn as_toml(&self) -> String {
126        match toml::to_string_pretty(self) {
127            Ok(s) => s,
128            Err(e) => {
129                panic!("Serializing a Config should never fail. {}", e);
130            }
131        }
132    }
133}