@@ -6,9 +6,9 @@ use anyhow::{Context, Result};
6
6
7
7
use fn_error_context:: context;
8
8
use ostree:: { gio, glib} ;
9
- use ostree_container:: store:: LayeredImageState ;
10
9
use ostree_container:: OstreeImageReference ;
11
10
use ostree_ext:: container as ostree_container;
11
+ use ostree_ext:: container:: store:: PrepareResult ;
12
12
use ostree_ext:: ostree;
13
13
use ostree_ext:: ostree:: Deployment ;
14
14
use ostree_ext:: sysroot:: SysrootLock ;
@@ -27,6 +27,13 @@ pub(crate) struct RequiredHostSpec<'a> {
27
27
pub ( crate ) image : & ' a ImageReference ,
28
28
}
29
29
30
+ /// State of a locally fetched image
31
+ pub ( crate ) struct ImageState {
32
+ pub ( crate ) manifest_digest : String ,
33
+ pub ( crate ) version : Option < String > ,
34
+ pub ( crate ) ostree_commit : String ,
35
+ }
36
+
30
37
impl < ' a > RequiredHostSpec < ' a > {
31
38
/// Given a (borrowed) host specification, "unwrap" its internal
32
39
/// options, giving a spec that is required to have a base container image.
@@ -39,6 +46,81 @@ impl<'a> RequiredHostSpec<'a> {
39
46
}
40
47
}
41
48
49
+ impl From < ostree_container:: store:: LayeredImageState > for ImageState {
50
+ fn from ( value : ostree_container:: store:: LayeredImageState ) -> Self {
51
+ let version = value. version ( ) . map ( |v| v. to_owned ( ) ) ;
52
+ let ostree_commit = value. get_commit ( ) . to_owned ( ) ;
53
+ Self {
54
+ manifest_digest : value. manifest_digest ,
55
+ version,
56
+ ostree_commit,
57
+ }
58
+ }
59
+ }
60
+
61
+ impl ImageState {
62
+ /// Fetch the manifest corresponding to this image. May not be available in all backends.
63
+ pub ( crate ) fn get_manifest (
64
+ & self ,
65
+ repo : & ostree:: Repo ,
66
+ ) -> Result < Option < ostree_ext:: oci_spec:: image:: ImageManifest > > {
67
+ ostree_container:: store:: query_image_commit ( repo, & self . ostree_commit )
68
+ . map ( |v| Some ( v. manifest ) )
69
+ }
70
+ }
71
+
72
+ /// Wrapper for pulling a container image, wiring up status output.
73
+ pub ( crate ) async fn new_importer (
74
+ repo : & ostree:: Repo ,
75
+ imgref : & ostree_container:: OstreeImageReference ,
76
+ ) -> Result < ostree_container:: store:: ImageImporter > {
77
+ let config = Default :: default ( ) ;
78
+ let mut imp = ostree_container:: store:: ImageImporter :: new ( repo, imgref, config) . await ?;
79
+ imp. require_bootable ( ) ;
80
+ Ok ( imp)
81
+ }
82
+
83
+ /// Wrapper for pulling a container image, wiring up status output.
84
+ #[ context( "Pulling" ) ]
85
+ pub ( crate ) async fn pull (
86
+ sysroot : & SysrootLock ,
87
+ imgref : & ImageReference ,
88
+ quiet : bool ,
89
+ ) -> Result < Box < ImageState > > {
90
+ let repo = & sysroot. repo ( ) ;
91
+ let imgref = & OstreeImageReference :: from ( imgref. clone ( ) ) ;
92
+ let mut imp = new_importer ( repo, imgref) . await ?;
93
+ let prep = match imp. prepare ( ) . await ? {
94
+ PrepareResult :: AlreadyPresent ( c) => {
95
+ println ! ( "No changes in {} => {}" , imgref, c. manifest_digest) ;
96
+ return Ok ( Box :: new ( ( * c) . into ( ) ) ) ;
97
+ }
98
+ PrepareResult :: Ready ( p) => p,
99
+ } ;
100
+ if let Some ( warning) = prep. deprecated_warning ( ) {
101
+ ostree_ext:: cli:: print_deprecated_warning ( warning) . await ;
102
+ }
103
+ ostree_ext:: cli:: print_layer_status ( & prep) ;
104
+ let printer = ( !quiet) . then ( || {
105
+ let layer_progress = imp. request_progress ( ) ;
106
+ let layer_byte_progress = imp. request_layer_progress ( ) ;
107
+ tokio:: task:: spawn ( async move {
108
+ ostree_ext:: cli:: handle_layer_progress_print ( layer_progress, layer_byte_progress) . await
109
+ } )
110
+ } ) ;
111
+ let import = imp. import ( prep) . await ;
112
+ if let Some ( printer) = printer {
113
+ let _ = printer. await ;
114
+ }
115
+ let import = import?;
116
+ if let Some ( msg) =
117
+ ostree_container:: store:: image_filtered_content_warning ( repo, & imgref. imgref ) ?
118
+ {
119
+ eprintln ! ( "{msg}" )
120
+ }
121
+ Ok ( Box :: new ( ( * import) . into ( ) ) )
122
+ }
123
+
42
124
pub ( crate ) async fn cleanup ( sysroot : & SysrootLock ) -> Result < ( ) > {
43
125
let repo = sysroot. repo ( ) ;
44
126
let sysroot = sysroot. sysroot . clone ( ) ;
@@ -90,16 +172,15 @@ async fn deploy(
90
172
sysroot : & SysrootLock ,
91
173
merge_deployment : Option < & Deployment > ,
92
174
stateroot : & str ,
93
- image : & LayeredImageState ,
175
+ image : & ImageState ,
94
176
origin : & glib:: KeyFile ,
95
177
) -> Result < ( ) > {
96
178
let stateroot = Some ( stateroot) ;
97
179
// Copy to move into thread
98
- let base_commit = image. get_commit ( ) . to_owned ( ) ;
99
180
let cancellable = gio:: Cancellable :: NONE ;
100
181
let _new_deployment = sysroot. stage_tree_with_options (
101
182
stateroot,
102
- & base_commit ,
183
+ image . ostree_commit . as_str ( ) ,
103
184
Some ( origin) ,
104
185
merge_deployment,
105
186
& Default :: default ( ) ,
@@ -113,7 +194,7 @@ async fn deploy(
113
194
pub ( crate ) async fn stage (
114
195
sysroot : & SysrootLock ,
115
196
stateroot : & str ,
116
- image : & LayeredImageState ,
197
+ image : & ImageState ,
117
198
spec : & RequiredHostSpec < ' _ > ,
118
199
) -> Result < ( ) > {
119
200
let merge_deployment = sysroot. merge_deployment ( Some ( stateroot) ) ;
@@ -134,11 +215,7 @@ pub(crate) async fn stage(
134
215
. await ?;
135
216
crate :: deploy:: cleanup ( sysroot) . await ?;
136
217
println ! ( "Queued for next boot: {imgref}" ) ;
137
- if let Some ( version) = image
138
- . configuration
139
- . as_ref ( )
140
- . and_then ( ostree_container:: version_for_config)
141
- {
218
+ if let Some ( version) = image. version . as_deref ( ) {
142
219
println ! ( " Version: {version}" ) ;
143
220
}
144
221
println ! ( " Digest: {}" , image. manifest_digest) ;
0 commit comments