repo_backup/
lib.rs

1//! A small utility for making a local copy of all your projects from a variety
2//! of various sources.
3//!
4//! Sources currently supported:
5//!
6//! - [GitHub](https://github.com/) ([Provider](./struct.GitHub.html))
7//! - [GitLab](https://about.gitlab.com/) ([Provider](./struct.GitLab.html))
8//!
9//!
10//! # Configuration
11//!
12//! Configuration is done via a `repo-backup.toml` file. By default the
13//! `repo-backup` program will look for this in your home directory (as
14//! `~/.repo-backup.toml`), but this can be overridden via the command line.
15//!
16//! The configuration file looks something like this:
17//!
18//! ```rust
19//! # use repo_backup::Config;
20//! # let src = r#"
21//! [general]
22//! dest-dir = "/srv"
23//!
24//! [github]
25//! api-key = "your API key"
26//! owned = true
27//! starred = false
28//!
29//! [gitlab]
30//! api-key = "your API key"
31//! host = "gitlab.com"
32//! organisations = true
33//! owned = true
34//! # "#;
35//! # let example = Config::from_str(src).unwrap();
36//! # assert_eq!(example, Config::example());
37//! ```
38//!
39//! The only required table is `general`, with the others used to enable and
40//! configure the corresponding [`Provider`].
41//!
42//! # Examples
43//!
44//! This crate is designed to be really easy to use as both an executable, *and*
45//! a library.
46//!
47//! The [`Driver`] will:
48//!
49//! - Query each [`Provider`] in the [`Config`] for the available repositories, and
50//! - Download each repository to [`dest_dir`].
51//!
52//! ```rust,no_run
53//! # extern crate repo_backup;
54//! # extern crate failure;
55//! # use failure::Error;
56//! use repo_backup::{Config, Driver};
57//!
58//! # fn run() -> Result<(), Error> {
59//! let cfg = Config::from_file("/path/to/repo-backup.toml")?;
60//! let driver = Driver::with_config(cfg);
61//!
62//! driver.run()?;
63//! # Ok(())
64//! # }
65//! # fn main() { run().unwrap() }
66//! ```
67//!
68//! Or if you want control over the list fetching and download process (e.g.
69//! to add a couple extra git repos to the list or use your own [`Provider`]):
70//!
71//! ```rust,no_run
72//! # extern crate repo_backup;
73//! # extern crate failure;
74//! # use failure::Error;
75//! use repo_backup::{Config, Driver, Repo, Provider};
76//!
77//! struct MyCustomProvider;
78//!
79//! impl Provider for MyCustomProvider {
80//!     fn name(&self) -> &str {
81//!         "custom-provider"
82//!     }
83//!
84//!     fn repositories(&self) -> Result<Vec<Repo>,  Error> {
85//!         unimplemented!()
86//!     }
87//! }
88//!
89//! # fn run() -> Result<(), Error> {
90//! let cfg = Config::from_file("/path/to/repo-backup.toml")?;
91//! let driver = Driver::with_config(cfg);
92//!
93//! let providers: Vec<Box<Provider>> = vec![Box::new(MyCustomProvider)];
94//! let mut repos = driver.get_repos_from_providers(&providers)?;
95//!
96//! let my_repo = Repo {
97//!     name: String::from("My Repo"),
98//!     owner: String::from("Michael-F-Bryan"),
99//!     provider: String::from("custom"),
100//!     url: String::from("http://my.git.server/Michael-F-Bryan/my_repo"),
101//! };
102//! repos.push(my_repo);
103//!
104//! driver.update_repos(&repos)?;
105//! # Ok(())
106//! # }
107//! # fn main() { run().unwrap() }
108//! ```
109//!
110//! [`Driver`]: struct.Driver.html
111//! [`Provider`]: trait.Provider.html
112//! [`Config`]: config/struct.Config.html
113//! [`dest_dir`]: config/struct.General.html#structfield.dest_dir
114
115#![deny(
116    missing_docs,
117    missing_debug_implementations,
118    missing_copy_implementations,
119    trivial_casts,
120    trivial_numeric_casts,
121    unsafe_code,
122    unstable_features,
123    unused_import_braces,
124    unused_imports,
125    unused_qualifications
126)]
127
128extern crate failure;
129extern crate hyperx;
130#[macro_use]
131extern crate failure_derive;
132extern crate gitlab;
133#[macro_use]
134extern crate log;
135extern crate reqwest;
136extern crate sec;
137extern crate serde;
138#[macro_use]
139extern crate serde_derive;
140extern crate serde_json;
141extern crate toml;
142
143#[macro_use]
144mod utils;
145pub mod config;
146mod driver;
147mod github;
148mod gitlab_provider;
149
150pub use config::Config;
151pub use driver::{Driver, UpdateFailure};
152pub use github::GitHub;
153pub use gitlab_provider::GitLab;
154
155use failure::{Error, SyncFailure};
156
157/// A repository.
158#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
159pub struct Repo {
160    /// The repository's owner.
161    pub owner: String,
162    /// The name of the repository.
163    pub name: String,
164    /// Which provider this repository was retrieved from.
165    pub provider: String,
166    /// A URL which can be used when downloading the repo.
167    pub url: String,
168}
169
170impl Repo {
171    /// Get the repository's canonical name in `$provider/$owner/$name` form
172    /// (e.g. `github/Michael-F-Bryan/repo-backup`).
173    pub fn full_name(&self) -> String {
174        format!("{}/{}/{}", self.provider, self.owner, self.name)
175    }
176}
177
178/// A source of repositories.
179pub trait Provider {
180    /// The `Provider`'s name.
181    fn name(&self) -> &str;
182
183    /// Get a list of all the available repositories from this source.
184    fn repositories(&self) -> Result<Vec<Repo>, Error>;
185}
186
187trait SyncResult<T, E> {
188    fn sync(self) -> Result<T, SyncFailure<E>>
189    where
190        Self: Sized,
191        E: ::std::error::Error + Send + 'static;
192}
193
194impl<T, E> SyncResult<T, E> for Result<T, E> {
195    fn sync(self) -> Result<T, SyncFailure<E>>
196    where
197        Self: Sized,
198        E: ::std::error::Error + Send + 'static,
199    {
200        self.map_err(SyncFailure::new)
201    }
202}