Add first pass of documentation around the library.

pull/3/head
Joshua Potter 2022-02-15 06:52:57 -05:00
parent 4c27331ac0
commit c1476f3412
8 changed files with 107 additions and 2 deletions

View File

@ -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

View File

@ -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",

View File

@ -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())?;

View File

@ -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();

View File

@ -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)?;

View File

@ -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(())

View File

@ -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")

View File

@ -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,