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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
//! # ReBackup program
//!
//! ReBackup is a simple backup program that doesn't actually create backups
//! but instead creates a list of files to backup from a source directory.
//!
//! It uses a walker to traverse filesystem items, which can be customized through rules (see [`WalkerRule`]).
//!
//! Its main features are:
//!
//! * Fast recursive directory traversing
//! * Powerful rules system to include, exclude or remap items
//! * Handling of symbolic links (requires to enable an option for the walker)
//! * Detection of already visited paths
//! * Command-line interface
//!
//! ReBackup can be used either:
//!
//! * As a library (see [`walk`](walker::walk))
//! * As a standalone binary with the `cli` feature
//!
//! ## Library usage
//!
//! ReBackup only exports one single function which is the Walker: [`walk`](walker::walk).
//!
//! It can be used like this:
//!
//! ```no_run
//! use std::path::PathBuf;
//! use rebackup::{fail, walk, WalkerConfig};
//!
//! let source = std::env::args().nth(1)
//!     .unwrap_or_else(|| fail!(exit 1, "Please provide a source directory"));
//!
//! // NOTE: This can be shortened to `WalkerConfig::new(vec![])`
//! //       (expanded here for explanations purpose)
//! let config = WalkerConfig {
//!     rules: vec![],
//!     follow_symlinks: false,
//!     drop_empty_dirs: false,
//! };
//!
//! let files_list = walk(&PathBuf::from(source), &config)
//!     .unwrap_or_else(|err| fail!(exit 2, "Failed to build the files list: {}", err));
//!
//! let files_list_str: Vec<_> = files_list
//!     .iter()
//!     .map(|item| item.to_string_lossy())
//!     .collect();
//!
//! println!("{}", files_list_str.join("\n"));
//! ```
//!
//! ### Rules
//!
//! You can use powerful rules to configure how the walker behaves.
//!
//! A rule is defined using [`WalkerRule`](config::WalkerRule), and uses two callbacks:
//!
//! * One to determine if the rule applies on a specific item
//! * One to run the rule itself
//!
//! Here is a basic rule excluding all directories containing `.nomedia` files:
//!
//! ```
//! use rebackup::config::*;
//!
//! let rule = WalkerRule {
//!     // Name of the rule
//!     name: "nomedia",
//!
//!     // Optional description of the rule
//!     description: None,
//!
//!     // The type of items the rule applies to (`None` for all)
//!     only_for: Some(WalkerItemType::Directory),
//!
//!     // Check if the rule would match a specific item
//!     matches: Box::new(|path, _, _| path.join(".nomedia").is_file()),
//!
//!     // Apply the rule to determine what to do
//!     action: Box::new(|_, _, _| Ok(WalkerRuleResult::ExcludeItem)),
//! };
//! ```
//!
//! You can also build more powerful rules, like excluding files ignored by Git:
//!
//! ```
//! use std::env;
//! use std::process::Command;
//! use rebackup::config::*;
//!
//! let rule = WalkerRule {
//!     name: "gitignore",
//!     description: None,
//!     only_for: None,
//!     matches: Box::new(|path, _, _| path.ancestors().any(|path| path.join(".git").is_dir())),
//!     action: Box::new(|dir, _, _| {
//!         let cwd = env::current_dir()?;
//!
//!         if dir.is_dir() {
//!             env::set_current_dir(dir)?;
//!         } else if let Some(parent) = dir.parent() {
//!             env::set_current_dir(parent)?;
//!         }
//!
//!         let is_excluded = Command::new("git")
//!             .arg("check-ignore")
//!             .arg(dir.to_string_lossy().to_string())
//!             .output();
//!
//!         // Restore the current directory before returning eventual error from the command
//!         env::set_current_dir(cwd)?;
//!
//!         if is_excluded?.status.success() {
//!             Ok(WalkerRuleResult::ExcludeItem)
//!         } else {
//!             Ok(WalkerRuleResult::IncludeItem)
//!         }
//!     }),
//! };
//! ```
//!
//! You can check more examples of rules in `examples/rules.rs`.
//!
//! ## Command-line usage
//!
//! ```shell
//! # Build the list of files to backup, and pipe it to 'tar'
//! # to create a compressed archive
//! # Be aware of not creating the archive inside the directory to backup, or the archive
//! # will be listed as well (you can still exclude it from the results afterwards)
//! rebackup path_to_backup/ | tar -czf output.tgz -T -
//!
//! # If you are in another directory, ask for absolute paths instead
//! # Please note that the archive's content will have absolute paths as well
//! rebackup path_to_backup/ -a | tar -czf output.tgz -T -
//!
//! # Using filters to exclude items based on patterns
//! # Here we're excluding all items ignored by the '.gitignore' file in Git repositories
//! rebackup path_to_backup/ -f '! git check-ignore "$REBACKUP_ITEM"'
//!
//! # To also exclude the ".git" folder (using glob pattern):
//! rebackup path_to_backup/ -f '! git check-ignore "$REBACKUP_ITEM"' -e '**/.git'
//!
//! # Use an alternate shell:
//! rebackup path_to_backup/ -f '! git check-ignore "$REBACKUP_ITEM"' --shell zsh --shell-head-args=-c
//!
//! # To list all available arguments:
//! rebackup --help
//! ```

#![forbid(unsafe_code)]
#![forbid(unused_must_use)]

#[macro_use]
pub mod logger;
pub mod config;
pub mod walker;

pub use config::*;
pub use logger::*;
pub use walker::*;

// Re-export used crates
pub use atomic;
pub use lazy_static;
pub use thiserror;

// Re-export crates used by the CLI
#[cfg(feature = "cli")]
pub use clap;
#[cfg(feature = "cli")]
pub use glob;