Struct CommitSaver

Source
pub struct CommitSaver {
    pub repository_url: String,
    pub commit_branch_name: String,
    pub commit_hash: String,
    pub commit_msg: String,
    pub commit_datetime: DateTime<Utc>,
}
Expand description

Stores Git commit metadata for logging to Obsidian diary entries.

This struct captures all essential information about a single Git commit that will be written as a row in the daily diary table. It’s automatically populated from the current Git repository’s HEAD commit.

§Examples

use rusty_commit_saver::CommitSaver;

// Automatically populated from current Git repository
let saver = CommitSaver::new();

println!("Repository: {}", saver.repository_url);
println!("Branch: {}", saver.commit_branch_name);
println!("Hash: {}", saver.commit_hash);
println!("Message: {}", saver.commit_msg);

§See Also

Fields§

§repository_url: String

The Git remote origin URL.

Retrieved from the repository’s origin remote. Double quotes are stripped.

§Examples

  • https://github.com/user/repo.git
  • git@github.com:user/repo.git
  • https://git.sr.ht/~user/repo
§commit_branch_name: String

The current Git branch name.

Retrieved from the repository’s HEAD reference. Double quotes are stripped.

§Examples

  • main
  • develop
  • feature/add-documentation
§commit_hash: String

The full SHA-1 commit hash (40 characters).

Uniquely identifies the commit in the Git repository.

§Format

Always 40 hexadecimal characters (e.g., abc123def456...)

§commit_msg: String

The formatted commit message for Obsidian display.

The message is processed for safe rendering in Markdown tables:

  • Pipe characters (|) are escaped to \|
  • Multiple lines are joined with <br/>
  • Empty lines are filtered out
  • Leading/trailing whitespace is trimmed

§Examples

Original: "feat: add feature\n\nWith details"
Formatted: "feat: add feature<br/>With details"

Original: "fix: issue | problem"
Formatted: "fix: issue \| problem"
§commit_datetime: DateTime<Utc>

The UTC timestamp when the commit was created.

Used for:

  • Generating date-based directory paths
  • Displaying commit time in diary entries
  • Creating frontmatter tags (week number, day of week)

§Format

Stored as DateTime<Utc> from the chrono crate.

Implementations§

Source§

impl CommitSaver

Source

pub fn new() -> Self

Creates a new CommitSaver instance by discovering the current Git repository.

This function automatically:

  • Discovers the Git repository in the current directory (.)
  • Extracts commit metadata from the HEAD commit
  • Formats the commit message for Obsidian (escapes pipes, adds <br/>)
§Panics

Panics if:

  • No Git repository is found in the current directory
  • The repository has no HEAD (uninitialized repo)
  • The HEAD cannot be resolved to a commit
§Examples
use rusty_commit_saver::CommitSaver;

let saver = CommitSaver::new();
println!("Commit hash: {}", saver.commit_hash);
Source

fn prepare_commit_entry_as_string(&mut self, path: &Path) -> String

Formats commit metadata as a Markdown table row for diary entry.

Generates a single table row containing all commit information in the format expected by the Obsidian diary template. The row includes pipe delimiters and ends with a newline.

§Arguments
  • path - The current working directory where the commit was made
§Returns

A formatted string representing one table row with these columns:

  1. FOLDER - Current working directory path
  2. TIME - Commit timestamp (HH:MM:SS format)
  3. COMMIT MESSAGE - Escaped and formatted commit message
  4. REPOSITORY URL - Git remote origin URL
  5. BRANCH - Current branch name
  6. COMMIT HASH - Full SHA-1 commit hash
§Format
| /path/to/repo | 14:30:45 | feat: add feature | https://github.com/user/repo.git | main | abc123... |
§Note

This is a private helper method called by append_entry_to_diary(). The commit message has already been formatted with escaped pipes and <br/> separators during struct initialization.

Source

pub fn prepare_frontmatter_tags(&mut self) -> Vec<String>

Generates Obsidian-style frontmatter tags based on the commit timestamp.

Creates three metadata tags for organizing diary entries:

  1. Week tag: #datetime/week/WW (e.g., #datetime/week/02 for week 2)
  2. Day tag: #datetime/days/DDDD (e.g., #datetime/days/Monday)
  3. Category tag: #diary/commits (constant)

These tags are used in the Obsidian diary file’s YAML frontmatter to enable:

  • Filtering commits by week number
  • Organizing by day of week
  • Cross-referencing with other diary entries
§Returns

A vector of three strings containing formatted Obsidian tags

§Examples
use rusty_commit_saver::CommitSaver;
use chrono::{TimeZone, Utc};

let mut saver = CommitSaver {
    repository_url: "https://github.com/example/repo.git".to_string(),
    commit_branch_name: "main".to_string(),
    commit_hash: "abc123".to_string(),
    commit_msg: "feat: add feature".to_string(),
    commit_datetime: Utc.with_ymd_and_hms(2025, 1, 13, 10, 30, 0).unwrap(), // Monday
};

let tags = saver.prepare_frontmatter_tags();
assert_eq!(tags.len(), 3);
assert!(tags.contains("week"));
assert!(tags.contains("Monday"));[1]
assert_eq!(tags, "#diary/commits");
Source

pub fn prepare_path_for_commit( &mut self, obsidian_commit_path: &Path, template_commit_date_path: &str, ) -> String

Constructs the full file path for a diary entry based on the commit timestamp.

Combines the Obsidian commit directory path with a date-formatted subdirectory structure to create the final path where the commit entry should be saved.

§Arguments
  • obsidian_commit_path - Base directory path for commits (e.g., Diaries/Commits)
  • template_commit_date_path - Chrono format string for the date hierarchy (e.g., %Y/%m-%B/%F.md)
§Returns

A formatted path string combining the base directory and formatted date

§Format Specifiers (Chrono)
  • %Y - Year (e.g., 2025)
  • %m - Month as number (e.g., 01)
  • %B - Full month name (e.g., January)
  • %F - ISO 8601 date (e.g., 2025-01-14.md)
  • %d - Day of month (e.g., 14)
§Panics

Panics if:

  • The obsidian_commit_path cannot be converted to a valid UTF-8 string
  • The path contains invalid characters that cannot be represented as a string
§Examples
use rusty_commit_saver::CommitSaver;
use std::path::PathBuf;
use chrono::{TimeZone, Utc};

let mut saver = CommitSaver {
    repository_url: "https://github.com/example/repo.git".to_string(),
    commit_branch_name: "main".to_string(),
    commit_hash: "abc123".to_string(),
    commit_msg: "feat: add feature".to_string(),
    commit_datetime: Utc.with_ymd_and_hms(2025, 1, 14, 10, 30, 0).unwrap(),
};

let path = saver.prepare_path_for_commit(
    &PathBuf::from("Diaries/Commits"),
    "%Y/%m-%B/%F.md"
);
// Returns: "/Diaries/Commits/2025/01-January/2025-01-14.md"
assert!(path.contains("2025"));
assert!(path.contains("January"));
assert!(path.contains("2025-01-14.md"));
Source

fn prepare_date_for_commit_file(&mut self, path_format: &str) -> String

Formats the commit timestamp using a Chrono date format string.

Applies the given format template to the commit’s datetime to generate a date-based directory path or filename. This enables flexible organization of diary entries by year, month, week, or custom hierarchies.

§Arguments
  • path_format - Chrono format string (e.g., %Y/%m-%B/%F.md)
§Returns

A formatted date string suitable for file paths

§Common Format Specifiers
  • %Y - Year (4 digits, e.g., 2025)
  • %m - Month (2 digits, e.g., 01)
  • %B - Full month name (e.g., January)
  • %b - Abbreviated month (e.g., Jan)
  • %d - Day of month (2 digits, e.g., 14)
  • %F - ISO 8601 date format (%Y-%m-%d, e.g., 2025-01-14)
  • %A - Full weekday name (e.g., Monday)
  • %W - Week number (e.g., 02)
§Examples
// With format "%Y/%m-%B/%F.md" and datetime 2025-01-14:
// Returns: "2025/01-January/2025-01-14.md"

// With format "%Y/week-%W/%F.md" and datetime in week 2:
// Returns: "2025/week-02/2025-01-14.md"
§Note

This is a private helper method called by prepare_path_for_commit().

Source

pub fn append_entry_to_diary( &mut self, wiki: &PathBuf, ) -> Result<(), Box<dyn Error>>

Appends the current commit as a table row to an Obsidian diary file.

This method writes a formatted commit entry to the specified diary file in append mode. The entry includes: current directory, timestamp, commit message, repository URL, branch, and commit hash.

§Arguments
  • wiki - Path to the diary file where the commit entry should be appended
§Returns
  • Ok(()) - Successfully appended the commit entry to the file
  • Err(Box<dyn Error>) - If file operations fail (file doesn’t exist, permission denied, etc.)
§Errors

Returns an error if:

  • The diary file cannot be opened for appending
  • The current working directory cannot be determined
  • File write operations fail (I/O error, permission denied)
§Examples
use rusty_commit_saver::CommitSaver;
use std::path::PathBuf;

let mut saver = CommitSaver::new();
let diary_path = PathBuf::from("/home/user/diary/2025-01-14.md");

match saver.append_entry_to_diary(&diary_path) {
    Ok(()) => println!("Commit logged successfully!"),
    Err(e) => eprintln!("Failed to log commit: {}", e),
}

Trait Implementations§

Source§

impl Clone for CommitSaver

Source§

fn clone(&self) -> CommitSaver

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for CommitSaver

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for CommitSaver

Creates a CommitSaver instance with default values from the current Git repository.

This implementation automatically discovers the Git repository in the current directory and extracts all commit metadata from the HEAD commit. It’s the core logic used by CommitSaver::new().

§Panics

Panics if:

  • No Git repository is found in the current directory or any parent directory
  • The repository has no HEAD (uninitialized or corrupted repository)
  • The HEAD reference cannot be resolved to a commit
  • The remote “origin” doesn’t exist

§Commit Message Processing

The commit message undergoes several transformations:

  1. Split into individual lines
  2. Trim whitespace from each line
  3. Escape pipe characters: |\| (for Markdown table compatibility)
  4. Filter out empty lines
  5. Join with <br/> separator (for Obsidian rendering)

§Examples

use rusty_commit_saver::CommitSaver;

// Using Default trait directly
let saver = CommitSaver::default();

// Equivalent to:
let saver2 = CommitSaver::new();
Source§

fn default() -> CommitSaver

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.