agpm_cli/upgrade/
config.rs

1use serde::{Deserialize, Serialize};
2
3/// Configuration settings for AGPM self-update behavior.
4///
5/// `UpgradeConfig` defines how AGPM handles automatic update checking,
6/// backup creation, and security verification during upgrades. These settings
7/// can be configured globally or per-project to control update behavior.
8///
9/// # Configuration Categories
10///
11/// ## Update Timing
12/// - **Startup Checks**: Whether to check for updates when AGPM starts
13/// - **Check Intervals**: How frequently to perform background update checks
14///
15/// ## Safety Settings
16/// - **Automatic Backups**: Whether to create backups before upgrades
17/// - **Checksum Verification**: Whether to verify download integrity
18///
19/// # Default Behavior
20///
21/// The default configuration prioritizes safety and user control:
22/// - No automatic update checking on startup (avoids startup delays)
23/// - 24-hour intervals for update checks (balances freshness with performance)
24/// - Always create backups (enables rollback on failures)
25/// - Always verify checksums (ensures download integrity)
26///
27/// # Examples
28///
29/// ## Using Default Configuration
30/// ```rust,no_run
31/// use agpm_cli::upgrade::config::UpgradeConfig;
32///
33/// let config = UpgradeConfig::default();
34/// assert_eq!(config.check_on_startup, false);
35/// assert_eq!(config.auto_backup, true);
36/// ```
37///
38/// ## Custom Configuration
39/// ```rust,no_run
40/// use agpm_cli::upgrade::config::UpgradeConfig;
41///
42/// let config = UpgradeConfig {
43///     check_on_startup: true,
44///     check_interval: 3600, // 1 hour
45///     auto_backup: true,
46///     verify_checksum: true,
47/// };
48/// ```
49///
50/// # Serialization
51///
52/// This configuration can be serialized to TOML, JSON, or other formats
53/// supported by serde for storage in configuration files.
54///
55/// ## TOML Example
56/// ```toml
57/// [upgrade]
58/// check_on_startup = false
59/// check_interval = 86400
60/// auto_backup = true
61/// verify_checksum = true
62/// ```
63#[derive(Debug, Clone, Serialize, Deserialize)]
64pub struct UpgradeConfig {
65    /// Whether to check for updates when AGPM starts.
66    ///
67    /// When enabled, AGPM will perform a background check for updates every
68    /// time it starts up. This provides the earliest notification of available
69    /// updates but may slightly delay startup time.
70    ///
71    /// # Default: `false`
72    ///
73    /// Disabled by default to avoid slowing down CLI operations. Users can
74    /// manually check for updates using `agpm upgrade --check`.
75    ///
76    /// # Considerations
77    ///
78    /// - **Startup Performance**: Adds network delay to every AGPM invocation
79    /// - **Network Dependency**: May fail or timeout in poor network conditions
80    /// - **Rate Limiting**: Frequent use may hit GitHub API rate limits
81    /// - **User Experience**: Can be intrusive for automated scripts
82    #[serde(default = "default_check_on_startup")]
83    pub check_on_startup: bool,
84
85    /// Interval between automatic update checks in seconds.
86    ///
87    /// Controls how frequently AGPM performs background checks for new versions.
88    /// This setting balances update notification timeliness with network usage
89    /// and API rate limit consumption.
90    ///
91    /// # Default: `86400` (24 hours)
92    ///
93    /// The default 24-hour interval provides daily update notifications while
94    /// being respectful of GitHub's API rate limits.
95    ///
96    /// # Recommended Values
97    ///
98    /// - **3600** (1 hour): For development environments or beta testing
99    /// - **21600** (6 hours): For active development workflows
100    /// - **86400** (1 day): Standard for most users (default)
101    /// - **604800** (1 week): For stable environments with infrequent updates
102    ///
103    /// # Rate Limiting
104    ///
105    /// GitHub allows 60 unauthenticated API requests per hour per IP address.
106    /// Setting intervals below 1 minute may exceed rate limits with heavy usage.
107    #[serde(default = "default_check_interval")]
108    pub check_interval: u64,
109
110    /// Whether to automatically create backups before upgrades.
111    ///
112    /// When enabled, AGPM creates a backup copy of the current binary before
113    /// attempting any upgrade. This enables rollback if the upgrade fails or
114    /// the new version has issues.
115    ///
116    /// # Default: `true`
117    ///
118    /// Enabled by default for maximum safety. Backups use minimal disk space
119    /// and provide crucial recovery capability.
120    ///
121    /// # Backup Process
122    ///
123    /// - Creates a copy with `.backup` suffix in the same directory
124    /// - Preserves file permissions and metadata
125    /// - Automatically removed after successful upgrades
126    /// - Can be restored manually or via `agpm upgrade --rollback`
127    ///
128    /// # Disabling Backups
129    ///
130    /// Consider disabling only in environments where:
131    /// - Disk space is severely constrained
132    /// - File system permissions prevent backup creation
133    /// - Alternative backup/recovery mechanisms are in place
134    /// - Upgrade failures can be resolved through reinstallation
135    #[serde(default = "default_auto_backup")]
136    pub auto_backup: bool,
137
138    /// Whether to verify checksums of downloaded binaries.
139    ///
140    /// When enabled, AGPM verifies the integrity of downloaded binaries by
141    /// comparing their checksums against expected values. This provides
142    /// protection against corrupted downloads and potential security issues.
143    ///
144    /// # Default: `true`
145    ///
146    /// Enabled by default for security and reliability. Checksum verification
147    /// adds minimal overhead but provides important integrity guarantees.
148    ///
149    /// # Security Benefits
150    ///
151    /// - **Download Integrity**: Detects corrupted or incomplete downloads
152    /// - **Tamper Detection**: Identifies potentially modified binaries
153    /// - **Supply Chain Security**: Helps ensure binary authenticity
154    /// - **Network Reliability**: Catches network-induced corruption
155    ///
156    /// # Verification Process
157    ///
158    /// - Downloads expected checksums from GitHub releases
159    /// - Computes actual checksum of downloaded binary
160    /// - Compares checksums before proceeding with installation
161    /// - Aborts upgrade if checksums don't match
162    ///
163    /// # Disabling Verification
164    ///
165    /// Consider disabling only in environments where:
166    /// - Network reliability is extremely poor
167    /// - Checksum information is unavailable from releases
168    /// - Alternative integrity verification is in place
169    /// - Testing scenarios require bypassing verification
170    #[serde(default = "default_verify_checksum")]
171    pub verify_checksum: bool,
172}
173
174impl Default for UpgradeConfig {
175    /// Create an `UpgradeConfig` with safe, conservative defaults.
176    ///
177    /// The default configuration prioritizes safety, reliability, and user control
178    /// over aggressive update checking. This approach:
179    ///
180    /// - Avoids surprising users with automatic behavior
181    /// - Minimizes impact on CLI performance
182    /// - Provides maximum safety during upgrades
183    /// - Respects GitHub API rate limits
184    ///
185    /// # Default Values
186    ///
187    /// - `check_on_startup`: `false` - No startup delays
188    /// - `check_interval`: `86400` (24 hours) - Daily update checks
189    /// - `auto_backup`: `true` - Always create backups for safety
190    /// - `verify_checksum`: `true` - Always verify download integrity
191    ///
192    /// # Examples
193    ///
194    /// ```rust,no_run
195    /// use agpm_cli::upgrade::config::UpgradeConfig;
196    ///
197    /// let config = UpgradeConfig::default();
198    /// assert_eq!(config.check_on_startup, false);
199    /// assert_eq!(config.check_interval, 86400);
200    /// assert_eq!(config.auto_backup, true);
201    /// assert_eq!(config.verify_checksum, true);
202    /// ```
203    fn default() -> Self {
204        Self {
205            check_on_startup: default_check_on_startup(),
206            check_interval: default_check_interval(),
207            auto_backup: default_auto_backup(),
208            verify_checksum: default_verify_checksum(),
209        }
210    }
211}
212
213/// Default value for startup update checking.
214///
215/// Returns `false` to avoid adding network latency to every AGPM invocation.
216/// Users can explicitly enable this or use manual update checking.
217const fn default_check_on_startup() -> bool {
218    false // Default to not checking on startup to avoid slowing down the CLI
219}
220
221/// Default value for update check interval.
222///
223/// Returns `86400` (24 hours) to provide daily update notifications while
224/// being respectful of GitHub API rate limits and user attention.
225const fn default_check_interval() -> u64 {
226    86400 // 24 hours in seconds
227}
228
229/// Default value for automatic backup creation.
230///
231/// Returns `true` to maximize safety during upgrades. Backups enable quick
232/// recovery from failed upgrades and add minimal overhead.
233const fn default_auto_backup() -> bool {
234    true // Always create backups for safety
235}
236
237/// Default value for checksum verification.
238///
239/// Returns `true` to ensure download integrity and provide security against
240/// corrupted or tampered binaries. Verification adds minimal overhead.
241const fn default_verify_checksum() -> bool {
242    true // Always verify checksums for security
243}
244
245impl UpgradeConfig {
246    /// Create a new `UpgradeConfig` with default settings.
247    ///
248    /// This is equivalent to [`Default::default()`] but provides a more
249    /// conventional constructor-style interface for creating configurations.
250    ///
251    /// # Examples
252    ///
253    /// ```rust,no_run
254    /// use agpm_cli::upgrade::config::UpgradeConfig;
255    ///
256    /// // These are equivalent
257    /// let config1 = UpgradeConfig::new();
258    /// let config2 = UpgradeConfig::default();
259    ///
260    /// assert_eq!(config1.check_on_startup, config2.check_on_startup);
261    /// assert_eq!(config1.auto_backup, config2.auto_backup);
262    /// ```
263    ///
264    /// # See Also
265    ///
266    /// - [`Default::default()`] - Alternative way to create default configuration
267    pub fn new() -> Self {
268        Self::default()
269    }
270}