Skip to main content

standard_version/
version_file.rs

1//! Version file detection and updating.
2//!
3//! Provides the [`VersionFile`] trait for ecosystem-specific version file
4//! engines, and the [`update_version_files`] / [`detect_version_files`]
5//! functions (in the [`scan`](crate::scan) module) that discover and
6//! update version files at a repository root.
7
8use std::path::PathBuf;
9
10// ---------------------------------------------------------------------------
11// Error
12// ---------------------------------------------------------------------------
13
14/// Errors that can occur when reading or writing version files.
15#[derive(Debug, thiserror::Error)]
16#[non_exhaustive]
17pub enum VersionFileError {
18    /// The expected file was not found on disk.
19    #[error("file not found: {}", .0.display())]
20    FileNotFound(PathBuf),
21    /// The file does not contain a version field this engine can handle.
22    #[error("no version field found")]
23    NoVersionField,
24    /// Writing the updated content back to disk failed.
25    #[error("write failed: {0}")]
26    WriteFailed(#[source] std::io::Error),
27    /// Reading the file from disk failed.
28    #[error("read failed: {0}")]
29    ReadFailed(#[source] std::io::Error),
30    /// A user-supplied regex pattern is invalid or has no capture groups.
31    #[error("invalid regex: {0}")]
32    InvalidRegex(String),
33}
34
35// ---------------------------------------------------------------------------
36// Trait
37// ---------------------------------------------------------------------------
38
39/// A version file engine that can detect, read, and write a version field
40/// inside a specific file format (e.g. `Cargo.toml`, `package.json`).
41pub trait VersionFile {
42    /// Human-readable name (e.g. `"Cargo.toml"`).
43    fn name(&self) -> &str;
44
45    /// Filenames to look for at the repository root.
46    fn filenames(&self) -> &[&str];
47
48    /// Check if `content` contains a version field this engine handles.
49    fn detect(&self, content: &str) -> bool;
50
51    /// Extract the current version string from file content.
52    fn read_version(&self, content: &str) -> Option<String>;
53
54    /// Return updated file content with `new_version` replacing the old value.
55    fn write_version(&self, content: &str, new_version: &str) -> Result<String, VersionFileError>;
56
57    /// Compare old and new file content and return optional extra information
58    /// about side-effects (e.g. `VERSION_CODE` increment in gradle).
59    ///
60    /// The default implementation returns `None`.
61    fn extra_info(&self, _old_content: &str, _new_content: &str) -> Option<String> {
62        None
63    }
64}
65
66// ---------------------------------------------------------------------------
67// UpdateResult
68// ---------------------------------------------------------------------------
69
70/// The outcome of updating a single version file.
71#[derive(Debug, Clone, PartialEq, Eq)]
72pub struct UpdateResult {
73    /// Absolute path to the file that was updated.
74    pub path: PathBuf,
75    /// Human-readable engine name (e.g. `"Cargo.toml"`).
76    pub name: String,
77    /// Version string before the update.
78    pub old_version: String,
79    /// Version string after the update.
80    pub new_version: String,
81    /// Optional extra info (e.g. `"VERSION_CODE: 42 → 43"`).
82    pub extra: Option<String>,
83}
84
85// ---------------------------------------------------------------------------
86// DetectedFile
87// ---------------------------------------------------------------------------
88
89/// Information about a detected version file (no writes performed).
90#[derive(Debug, Clone, PartialEq, Eq)]
91pub struct DetectedFile {
92    /// Absolute path to the file.
93    pub path: PathBuf,
94    /// Human-readable engine name (e.g. `"Cargo.toml"`).
95    pub name: String,
96    /// Current version string in the file.
97    pub old_version: String,
98}
99
100// ---------------------------------------------------------------------------
101// CustomVersionFile
102// ---------------------------------------------------------------------------
103
104/// A user-defined version file matched by path and regex.
105///
106/// Processed by [`RegexVersionFile`](crate::regex_engine::RegexVersionFile)
107/// during [`update_version_files`](crate::scan::update_version_files).
108#[derive(Debug, Clone)]
109pub struct CustomVersionFile {
110    /// Path to the file, relative to the repository root.
111    pub path: PathBuf,
112    /// Regex pattern whose first capture group contains the version string.
113    pub pattern: String,
114}
115
116// Re-export scan functions so existing `use version_file::update_version_files`
117// paths continue to work.
118pub use crate::scan::{detect_version_files, update_version_files};