@opencode-cloud/core 1.0.10 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,120 @@
1
+ //! Image state tracking for provenance information
2
+ //!
3
+ //! Tracks where the current Docker image came from (prebuilt or built)
4
+ //! and which registry it was pulled from.
5
+
6
+ use chrono::Utc;
7
+ use serde::{Deserialize, Serialize};
8
+ use std::path::PathBuf;
9
+
10
+ /// Image provenance state
11
+ #[derive(Debug, Clone, Serialize, Deserialize)]
12
+ pub struct ImageState {
13
+ /// Image version (e.g., "1.0.12")
14
+ pub version: String,
15
+ /// Source: "prebuilt" or "build"
16
+ pub source: String,
17
+ /// Registry if prebuilt: "ghcr.io" or "docker.io", None for build
18
+ #[serde(skip_serializing_if = "Option::is_none")]
19
+ pub registry: Option<String>,
20
+ /// When the image was acquired (ISO8601)
21
+ pub acquired_at: String,
22
+ }
23
+
24
+ impl ImageState {
25
+ /// Create a new ImageState for a prebuilt image
26
+ pub fn prebuilt(version: &str, registry: &str) -> Self {
27
+ Self {
28
+ version: version.to_string(),
29
+ source: "prebuilt".to_string(),
30
+ registry: Some(registry.to_string()),
31
+ acquired_at: Utc::now().to_rfc3339(),
32
+ }
33
+ }
34
+
35
+ /// Create a new ImageState for a locally built image
36
+ pub fn built(version: &str) -> Self {
37
+ Self {
38
+ version: version.to_string(),
39
+ source: "build".to_string(),
40
+ registry: None,
41
+ acquired_at: Utc::now().to_rfc3339(),
42
+ }
43
+ }
44
+ }
45
+
46
+ /// Get the path to the image state file
47
+ pub fn get_state_path() -> Option<PathBuf> {
48
+ crate::config::paths::get_data_dir().map(|p| p.join("image-state.json"))
49
+ }
50
+
51
+ /// Save image state to disk
52
+ pub fn save_state(state: &ImageState) -> anyhow::Result<()> {
53
+ let path = get_state_path().ok_or_else(|| anyhow::anyhow!("Could not determine state path"))?;
54
+
55
+ // Ensure parent directory exists
56
+ if let Some(parent) = path.parent() {
57
+ std::fs::create_dir_all(parent)?;
58
+ }
59
+
60
+ let json = serde_json::to_string_pretty(state)?;
61
+ std::fs::write(&path, json)?;
62
+ Ok(())
63
+ }
64
+
65
+ /// Load image state from disk
66
+ pub fn load_state() -> Option<ImageState> {
67
+ let path = get_state_path()?;
68
+ let content = std::fs::read_to_string(&path).ok()?;
69
+ serde_json::from_str(&content).ok()
70
+ }
71
+
72
+ /// Clear image state (e.g., after image removal)
73
+ pub fn clear_state() -> anyhow::Result<()> {
74
+ if let Some(path) = get_state_path() {
75
+ if path.exists() {
76
+ std::fs::remove_file(&path)?;
77
+ }
78
+ }
79
+ Ok(())
80
+ }
81
+
82
+ #[cfg(test)]
83
+ mod tests {
84
+ use super::*;
85
+
86
+ #[test]
87
+ fn test_image_state_prebuilt() {
88
+ let state = ImageState::prebuilt("1.0.12", "ghcr.io");
89
+ assert_eq!(state.version, "1.0.12");
90
+ assert_eq!(state.source, "prebuilt");
91
+ assert_eq!(state.registry, Some("ghcr.io".to_string()));
92
+ assert!(!state.acquired_at.is_empty());
93
+ }
94
+
95
+ #[test]
96
+ fn test_image_state_built() {
97
+ let state = ImageState::built("1.0.12");
98
+ assert_eq!(state.version, "1.0.12");
99
+ assert_eq!(state.source, "build");
100
+ assert!(state.registry.is_none());
101
+ }
102
+
103
+ #[test]
104
+ fn test_image_state_serialize_deserialize() {
105
+ let state = ImageState::prebuilt("1.0.12", "docker.io");
106
+ let json = serde_json::to_string(&state).unwrap();
107
+ let parsed: ImageState = serde_json::from_str(&json).unwrap();
108
+ assert_eq!(state.version, parsed.version);
109
+ assert_eq!(state.source, parsed.source);
110
+ assert_eq!(state.registry, parsed.registry);
111
+ }
112
+
113
+ #[test]
114
+ fn test_get_state_path() {
115
+ let path = get_state_path();
116
+ assert!(path.is_some());
117
+ let p = path.unwrap();
118
+ assert!(p.to_string_lossy().contains("image-state.json"));
119
+ }
120
+ }
@@ -6,7 +6,7 @@ use std::fs::{self, File, OpenOptions};
6
6
  use std::io::{BufReader, Write};
7
7
  use std::path::PathBuf;
8
8
 
9
- use ssh2_config::{ParseRule, SshConfig};
9
+ use ssh2_config_rs::{ParseRule, SshConfig};
10
10
 
11
11
  use super::error::HostError;
12
12