Add first pass of documentation around the library.
parent
4c27331ac0
commit
c1476f3412
|
@ -133,6 +133,12 @@ Refer to `:h backupcopy` for details on how this works.
|
||||||
|
|
||||||
## Contribution
|
## Contribution
|
||||||
|
|
||||||
|
To get started, we recommend reviewing the documentation:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cargo doc --open
|
||||||
|
```
|
||||||
|
|
||||||
Install git hooks as follows:
|
Install git hooks as follows:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
@ -1,3 +1,29 @@
|
||||||
|
//! The in-memory representation of the homesync config. Refer to
|
||||||
|
//! [homesync/template.yml](https://github.com/jrpotter/homesync/blob/main/rsrc/template.yml)
|
||||||
|
//! (copied below) for an example of what this config might look like.
|
||||||
|
//!
|
||||||
|
//! ```yaml
|
||||||
|
//! ---
|
||||||
|
//! user:
|
||||||
|
//! name: name
|
||||||
|
//! email: email@email.com
|
||||||
|
//! ssh:
|
||||||
|
//! public: $HOME/.ssh/id_ed25519.pub
|
||||||
|
//! private: $HOME/.ssh/id_ed25519
|
||||||
|
//! repos:
|
||||||
|
//! local: $HOME/.homesync
|
||||||
|
//! remote:
|
||||||
|
//! name: origin
|
||||||
|
//! branch: master
|
||||||
|
//! url: "https://github.com/owner/repo.git"
|
||||||
|
//! packages:
|
||||||
|
//! homesync:
|
||||||
|
//! - $HOME/.homesync.yml
|
||||||
|
//! - $HOME/.config/homesync/homesync.yml
|
||||||
|
//! - $XDG_CONFIG_HOME/homesync.yml
|
||||||
|
//! - $XDG_CONFIG_HOME/homesync/homesync.yml
|
||||||
|
//! ```
|
||||||
|
|
||||||
use super::{path, path::ResPathBuf};
|
use super::{path, path::ResPathBuf};
|
||||||
use paris::formatter::colorize_string;
|
use paris::formatter::colorize_string;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
|
@ -134,6 +160,7 @@ impl PathConfig {
|
||||||
// Loading
|
// Loading
|
||||||
// ========================================
|
// ========================================
|
||||||
|
|
||||||
|
/// The paths our homesync configuration may live in, ordered by priority.
|
||||||
pub const DEFAULT_PATHS: &[&str] = &[
|
pub const DEFAULT_PATHS: &[&str] = &[
|
||||||
"$HOME/.homesync.yml",
|
"$HOME/.homesync.yml",
|
||||||
"$HOME/.config/homesync/homesync.yml",
|
"$HOME/.config/homesync/homesync.yml",
|
||||||
|
@ -141,10 +168,13 @@ pub const DEFAULT_PATHS: &[&str] = &[
|
||||||
"$XDG_CONFIG_HOME/homesync/homesync.yml",
|
"$XDG_CONFIG_HOME/homesync/homesync.yml",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
/// The paths our homesync configuration may live in, ordered by priority.
|
||||||
pub fn default_paths() -> Vec<PathBuf> {
|
pub fn default_paths() -> Vec<PathBuf> {
|
||||||
DEFAULT_PATHS.iter().map(|s| PathBuf::from(s)).collect()
|
DEFAULT_PATHS.iter().map(|s| PathBuf::from(s)).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads in the homesync configuration file into a [PathConfig](struct.PathConfig.html)
|
||||||
|
/// instance.
|
||||||
pub fn load(candidates: &Vec<ResPathBuf>) -> Result<PathConfig> {
|
pub fn load(candidates: &Vec<ResPathBuf>) -> Result<PathConfig> {
|
||||||
// When trying our paths, the only acceptable error is a `NotFound` file.
|
// When trying our paths, the only acceptable error is a `NotFound` file.
|
||||||
// Anything else should be surfaced to the end user.
|
// Anything else should be surfaced to the end user.
|
||||||
|
@ -161,6 +191,11 @@ pub fn load(candidates: &Vec<ResPathBuf>) -> Result<PathConfig> {
|
||||||
Err(Error::MissingConfig)
|
Err(Error::MissingConfig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Reads in the homesync configuration file into a [PathConfig](struct.PathConfig.html)
|
||||||
|
/// instance.
|
||||||
|
///
|
||||||
|
/// Useful in cases where we notice the homesync config itself has changed while
|
||||||
|
/// homesync is running.
|
||||||
pub fn reload(pc: &PathConfig) -> Result<PathConfig> {
|
pub fn reload(pc: &PathConfig) -> Result<PathConfig> {
|
||||||
info!(
|
info!(
|
||||||
"<bold>Reloaded:</> Configuration <cyan>{}</>.",
|
"<bold>Reloaded:</> Configuration <cyan>{}</>.",
|
||||||
|
@ -173,6 +208,7 @@ pub fn reload(pc: &PathConfig) -> Result<PathConfig> {
|
||||||
// Listing
|
// Listing
|
||||||
// ========================================
|
// ========================================
|
||||||
|
|
||||||
|
/// Prints the list of packages found in a [PathConfig](struct.PathConfig.html).
|
||||||
pub fn list_packages(pc: PathConfig) {
|
pub fn list_packages(pc: PathConfig) {
|
||||||
println!(
|
println!(
|
||||||
"Listing packages in {}...\n",
|
"Listing packages in {}...\n",
|
||||||
|
|
11
src/copy.rs
11
src/copy.rs
|
@ -1,3 +1,5 @@
|
||||||
|
//! Utilities for traversing directories and copying files around.
|
||||||
|
|
||||||
use super::{config::PathConfig, path, path::ResPathBuf};
|
use super::{config::PathConfig, path, path::ResPathBuf};
|
||||||
use git2::Repository;
|
use git2::Repository;
|
||||||
use simplelog::{info, paris, warn};
|
use simplelog::{info, paris, warn};
|
||||||
|
@ -122,6 +124,13 @@ fn apply_one(pc: &PathConfig, package: &str) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Copy files from the local repository to the corresponding file location on
|
||||||
|
/// the current machine.
|
||||||
|
///
|
||||||
|
/// By default we are required to specify which package we want to apply. If
|
||||||
|
/// we'd like, we can choose to apply all files found in the local repository.
|
||||||
|
/// Warning! You should probably `pull` first to ensure your local repository is
|
||||||
|
/// synced with the remote one, especially if running with `--all`.
|
||||||
pub fn apply(pc: &PathConfig, package: Option<&str>) -> Result<()> {
|
pub fn apply(pc: &PathConfig, package: Option<&str>) -> Result<()> {
|
||||||
if let Some(package) = package {
|
if let Some(package) = package {
|
||||||
apply_one(pc, package)
|
apply_one(pc, package)
|
||||||
|
@ -134,6 +143,8 @@ pub fn apply(pc: &PathConfig, package: Option<&str>) -> Result<()> {
|
||||||
// Staging
|
// Staging
|
||||||
// ========================================
|
// ========================================
|
||||||
|
|
||||||
|
/// Finds all files specified in the homesync config and copies them (if they
|
||||||
|
/// exist) into the local repo.
|
||||||
pub fn stage(pc: &PathConfig) -> Result<()> {
|
pub fn stage(pc: &PathConfig) -> Result<()> {
|
||||||
let workdir = get_workdir(pc)?;
|
let workdir = get_workdir(pc)?;
|
||||||
let repo_files = walk_repo(workdir.as_ref())?;
|
let repo_files = walk_repo(workdir.as_ref())?;
|
||||||
|
|
|
@ -1,3 +1,10 @@
|
||||||
|
//! Utilites around launching a filewatcher daemon service.
|
||||||
|
//!
|
||||||
|
//! This is intended to be the primary use case of Homesync once stable. The
|
||||||
|
//! daemon is responsible for loading in the homesync config (reloading as it
|
||||||
|
//! changes) and monitoring any files/file paths specified within. On changes,
|
||||||
|
//! it will automatically stage the files to the local repository.
|
||||||
|
|
||||||
use super::{config, config::PathConfig, copy, path, path::ResPathBuf};
|
use super::{config, config::PathConfig, copy, path, path::ResPathBuf};
|
||||||
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
|
use notify::{DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher};
|
||||||
use simplelog::{error, paris, trace, warn};
|
use simplelog::{error, paris, trace, warn};
|
||||||
|
@ -137,6 +144,10 @@ impl<'a> WatchState<'a> {
|
||||||
// Daemon
|
// Daemon
|
||||||
// ========================================
|
// ========================================
|
||||||
|
|
||||||
|
/// Launches a daemon service that monitors changes to files specified in the
|
||||||
|
/// config and stages them for changes in the local repository.
|
||||||
|
///
|
||||||
|
/// Warning! This service is still under development.
|
||||||
pub fn launch(mut pc: PathConfig, freq_secs: u64) -> Result<(), Box<dyn Error>> {
|
pub fn launch(mut pc: PathConfig, freq_secs: u64) -> Result<(), Box<dyn Error>> {
|
||||||
let (poll_tx, poll_rx) = channel();
|
let (poll_tx, poll_rx) = channel();
|
||||||
let (watch_tx, watch_rx) = channel();
|
let (watch_tx, watch_rx) = channel();
|
||||||
|
|
17
src/git.rs
17
src/git.rs
|
@ -1,3 +1,7 @@
|
||||||
|
//! Utilities around git
|
||||||
|
//! [plumbing](https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain)
|
||||||
|
//! commands.
|
||||||
|
|
||||||
use super::{config::PathConfig, path};
|
use super::{config::PathConfig, path};
|
||||||
use git2::{
|
use git2::{
|
||||||
BranchType, Commit, Cred, DiffOptions, Direction, FetchOptions, Index, IndexAddOption,
|
BranchType, Commit, Cred, DiffOptions, Direction, FetchOptions, Index, IndexAddOption,
|
||||||
|
@ -83,7 +87,8 @@ fn clone(pc: &PathConfig, expanded: &Path) -> Result<Repository> {
|
||||||
// for both ensuring any remote repositories are already managed by homesync and
|
// for both ensuring any remote repositories are already managed by homesync and
|
||||||
// for storing any persisted configurations.
|
// for storing any persisted configurations.
|
||||||
|
|
||||||
/// Sets up a local github repository all configuration files will be synced to.
|
/// Sets up a local git repository all configuration files will be synced to.
|
||||||
|
///
|
||||||
/// If there does not exist a local repository at the requested location, we
|
/// If there does not exist a local repository at the requested location, we
|
||||||
/// attempt to make it via cloning or initializing.
|
/// attempt to make it via cloning or initializing.
|
||||||
pub fn init(pc: &PathConfig) -> Result<Repository> {
|
pub fn init(pc: &PathConfig) -> Result<Repository> {
|
||||||
|
@ -153,6 +158,11 @@ fn create_readme(repo: &Repository) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Take the current state of the local repository and push changes to the
|
||||||
|
/// remote.
|
||||||
|
///
|
||||||
|
/// This method will always pull before pushing to make sure there are no
|
||||||
|
/// conflicts that should be resolved.
|
||||||
pub fn push(pc: &PathConfig, repo: &mut Repository) -> Result<()> {
|
pub fn push(pc: &PathConfig, repo: &mut Repository) -> Result<()> {
|
||||||
// First pull to make sure there are no conflicts when we push our changes.
|
// First pull to make sure there are no conflicts when we push our changes.
|
||||||
// This will also perform validation and construct our local and remote
|
// This will also perform validation and construct our local and remote
|
||||||
|
@ -260,6 +270,11 @@ fn local_rebase_remote(pc: &PathConfig, repo: &Repository) -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Take the current state of the remote repository and pull changes to the
|
||||||
|
/// local.
|
||||||
|
///
|
||||||
|
/// Using git parlance, this method will stash any changes that currently exist
|
||||||
|
/// and reapply the changes after in case of merge conflicts.
|
||||||
pub fn pull(pc: &PathConfig, repo: &mut Repository) -> Result<()> {
|
pub fn pull(pc: &PathConfig, repo: &mut Repository) -> Result<()> {
|
||||||
repo.workdir().ok_or(Error::InvalidBareRepo)?;
|
repo.workdir().ok_or(Error::InvalidBareRepo)?;
|
||||||
|
|
||||||
|
|
20
src/lib.rs
20
src/lib.rs
|
@ -1,3 +1,17 @@
|
||||||
|
//! [homesync](https://github.com/jrpotter/homesync) is a project for collecting
|
||||||
|
//! various files strewn across your computer and consolidating them
|
||||||
|
//! automatically into a local git repository. It has the means of pushing those
|
||||||
|
//! changes to a remote git repository for syncing to other machines. Homesync
|
||||||
|
//! can pull in these changes on a different machine and *apply* the files,
|
||||||
|
//! putting them all in the correct spot.
|
||||||
|
//!
|
||||||
|
//! Throughout this documentation the "local repository" always refers to the
|
||||||
|
//! git repository homesync is managing (and potentially created on start). The
|
||||||
|
//! remote repository refers to the git repo hosted at the URL specified in the
|
||||||
|
//! homesync config.
|
||||||
|
//!
|
||||||
|
//! Thank you for your interest in contributing!
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
pub mod copy;
|
pub mod copy;
|
||||||
pub mod daemon;
|
pub mod daemon;
|
||||||
|
@ -9,33 +23,39 @@ use std::error::Error;
|
||||||
|
|
||||||
type Result = std::result::Result<(), Box<dyn Error>>;
|
type Result = std::result::Result<(), Box<dyn Error>>;
|
||||||
|
|
||||||
|
/// Refer to [copy::apply](copy/fn.apply.html).
|
||||||
pub fn run_apply(config: PathConfig, package: Option<&str>) -> Result {
|
pub fn run_apply(config: PathConfig, package: Option<&str>) -> Result {
|
||||||
copy::apply(&config, package)?;
|
copy::apply(&config, package)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refer to [daemon::launch](daemon/fn.launch.html).
|
||||||
pub fn run_daemon(config: PathConfig, freq_secs: u64) -> Result {
|
pub fn run_daemon(config: PathConfig, freq_secs: u64) -> Result {
|
||||||
daemon::launch(config, freq_secs)?;
|
daemon::launch(config, freq_secs)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refer to [config::list_packages](config/fn.list_packages.html).
|
||||||
pub fn run_list(config: PathConfig) -> Result {
|
pub fn run_list(config: PathConfig) -> Result {
|
||||||
config::list_packages(config);
|
config::list_packages(config);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refer to [git::push](git/fn.run_push.html).
|
||||||
pub fn run_push(config: PathConfig) -> Result {
|
pub fn run_push(config: PathConfig) -> Result {
|
||||||
let mut repo = git::init(&config)?;
|
let mut repo = git::init(&config)?;
|
||||||
git::push(&config, &mut repo)?;
|
git::push(&config, &mut repo)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refer to [git::pull](git/fn.run_pull.html).
|
||||||
pub fn run_pull(config: PathConfig) -> Result {
|
pub fn run_pull(config: PathConfig) -> Result {
|
||||||
let mut repo = git::init(&config)?;
|
let mut repo = git::init(&config)?;
|
||||||
git::pull(&config, &mut repo)?;
|
git::pull(&config, &mut repo)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Refer to [copy::stage](copy/fn.stage.html).
|
||||||
pub fn run_stage(config: PathConfig) -> Result {
|
pub fn run_stage(config: PathConfig) -> Result {
|
||||||
copy::stage(&config)?;
|
copy::stage(&config)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
@ -42,7 +42,7 @@ fn main() {
|
||||||
)
|
)
|
||||||
.subcommand(
|
.subcommand(
|
||||||
App::new("apply")
|
App::new("apply")
|
||||||
.about("Copy files from local repository to rest of desktop")
|
.about("Copy files from local repository to corresponding location")
|
||||||
.arg(
|
.arg(
|
||||||
Arg::new("package")
|
Arg::new("package")
|
||||||
.value_name("PACKAGE")
|
.value_name("PACKAGE")
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! Utilities for resolving paths.
|
||||||
|
|
||||||
use serde::{
|
use serde::{
|
||||||
de,
|
de,
|
||||||
de::{Unexpected, Visitor},
|
de::{Unexpected, Visitor},
|
||||||
|
@ -54,6 +56,10 @@ impl error::Error for Error {}
|
||||||
// Path
|
// Path
|
||||||
// ========================================
|
// ========================================
|
||||||
|
|
||||||
|
/// A "resolved" `PathBuf` that takes in the originally supplied (potentially
|
||||||
|
/// relative) path and annotates it with the absolute path. A `ResPathBuf`
|
||||||
|
/// instance cannot be made if the relative path supplied to it does not refer
|
||||||
|
/// to an actual file.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ResPathBuf {
|
pub struct ResPathBuf {
|
||||||
inner: PathBuf,
|
inner: PathBuf,
|
||||||
|
|
Loading…
Reference in New Issue