1
+ extern crate dirs;
1
2
extern crate dkregistry;
2
3
extern crate futures;
3
4
extern crate serde_json;
4
5
extern crate tokio_core;
5
6
6
7
use dkregistry:: { reference, render} ;
8
+ use futures:: prelude:: * ;
9
+ use std:: result:: Result ;
10
+ use std:: str:: FromStr ;
7
11
use std:: { boxed, env, error, fs, io} ;
8
12
use tokio_core:: reactor:: Core ;
9
13
10
- use std:: str:: FromStr ;
11
-
12
- type Result < T > = std:: result:: Result < T , boxed:: Box < error:: Error > > ;
14
+ mod common;
13
15
14
16
fn main ( ) {
15
17
let dkr_ref = match std:: env:: args ( ) . nth ( 1 ) {
@@ -22,7 +24,7 @@ fn main() {
22
24
23
25
let mut user = None ;
24
26
let mut password = None ;
25
- let home = env :: home_dir ( ) . unwrap_or ( "/root" . into ( ) ) ;
27
+ let home = dirs :: home_dir ( ) . unwrap ( ) ;
26
28
let cfg = fs:: File :: open ( home. join ( ".docker/config.json" ) ) ;
27
29
if let Ok ( fp) = cfg {
28
30
let creds = dkregistry:: get_credentials ( io:: BufReader :: new ( fp) , & registry) ;
@@ -51,87 +53,90 @@ fn main() {
51
53
} ;
52
54
}
53
55
54
- fn run ( dkr_ref : & reference:: Reference , user : Option < String > , passwd : Option < String > ) -> Result < ( ) > {
55
- let image = dkr_ref. repository ( ) ;
56
- let version = dkr_ref. version ( ) ;
57
-
56
+ fn run (
57
+ dkr_ref : & reference:: Reference ,
58
+ user : Option < String > ,
59
+ passwd : Option < String > ,
60
+ ) -> Result < ( ) , boxed:: Box < error:: Error > > {
58
61
let mut tcore = try!( Core :: new ( ) ) ;
59
- let mut dclient = try!(
60
- dkregistry:: v2:: Client :: configure ( & tcore. handle ( ) )
61
- . registry ( & dkr_ref. registry ( ) )
62
- . insecure_registry ( false )
63
- . username ( user)
64
- . password ( passwd)
65
- . build ( )
66
- ) ;
67
-
68
- let futcheck = try!( dclient. is_v2_supported ( ) ) ;
69
- let supported = try!( tcore. run ( futcheck) ) ;
70
- if !supported {
71
- return Err ( "API v2 not supported" . into ( ) ) ;
72
- }
73
62
74
- let fut_token = try!( dclient. login ( & [ & format ! ( "repository:{}:pull" , image) ] ) ) ;
75
- let token_auth = try!( tcore. run ( fut_token) ) ;
76
-
77
- let futauth = try!( dclient. is_auth ( Some ( token_auth. token ( ) ) ) ) ;
78
- if !try!( tcore. run ( futauth) ) {
79
- return Err ( "login failed" . into ( ) ) ;
80
- }
63
+ let mut client = dkregistry:: v2:: Client :: configure ( & tcore. handle ( ) )
64
+ . registry ( & dkr_ref. registry ( ) )
65
+ . insecure_registry ( false )
66
+ . username ( user)
67
+ . password ( passwd)
68
+ . build ( ) ?;
81
69
82
- dclient. set_token ( Some ( token_auth. token ( ) ) ) ;
83
-
84
- let fut_hasmanif = dclient. has_manifest ( & image, & version, None ) ?;
85
- let manifest_kind = try!( tcore. run ( fut_hasmanif) ?. ok_or ( "no manifest found" ) ) ;
86
-
87
- let fut_manif = dclient. get_manifest ( & image, & version) ?;
88
- let body = tcore. run ( fut_manif) ?;
70
+ let image = dkr_ref. repository ( ) ;
71
+ let login_scope = format ! ( "repository:{}:pull" , image) ;
72
+ let version = dkr_ref. version ( ) ;
89
73
90
- let layers = match manifest_kind {
91
- dkregistry:: mediatypes:: MediaTypes :: ManifestV2S1Signed => {
92
- let m: dkregistry:: v2:: manifest:: ManifestSchema1Signed =
93
- try!( serde_json:: from_slice ( body. as_slice ( ) ) ) ;
94
- m. get_layers ( )
95
- }
96
- dkregistry:: mediatypes:: MediaTypes :: ManifestV2S2 => {
97
- let m: dkregistry:: v2:: manifest:: ManifestSchema2 =
98
- try!( serde_json:: from_slice ( body. as_slice ( ) ) ) ;
99
- m. get_layers ( )
100
- }
101
- _ => return Err ( "unknown format" . into ( ) ) ,
74
+ let futures = common:: authenticate_client ( & mut client, & login_scope)
75
+ . and_then ( |dclient| {
76
+ dclient
77
+ . has_manifest ( & image, & version, None )
78
+ . and_then ( move |manifest_option| Ok ( ( dclient, manifest_option) ) )
79
+ . and_then ( |( dclient, manifest_option) | match manifest_option {
80
+ None => Err ( format ! ( "{}:{} doesn't have a manifest" , & image, & version) . into ( ) ) ,
81
+
82
+ Some ( manifest_kind) => Ok ( ( dclient, manifest_kind) ) ,
83
+ } )
84
+ } ) . and_then ( |( dclient, manifest_kind) | {
85
+ let image = image. clone ( ) ;
86
+ dclient. get_manifest ( & image, & version) . and_then (
87
+ move |manifest_body| match manifest_kind {
88
+ dkregistry:: mediatypes:: MediaTypes :: ManifestV2S1Signed => {
89
+ let m: dkregistry:: v2:: manifest:: ManifestSchema1Signed = match
90
+ serde_json:: from_slice ( manifest_body. as_slice ( ) ) {
91
+ Ok ( json) => json,
92
+ Err ( e) => return Err ( e. into ( ) ) ,
93
+
94
+ } ;
95
+ Ok ( ( dclient, m. get_layers ( ) ) )
96
+ }
97
+ dkregistry:: mediatypes:: MediaTypes :: ManifestV2S2 => {
98
+ let m: dkregistry:: v2:: manifest:: ManifestSchema2 =
99
+ match serde_json:: from_slice ( manifest_body. as_slice ( ) ) {
100
+ Ok ( json) => json,
101
+ Err ( e) => return Err ( e. into ( ) ) ,
102
+ } ;
103
+ Ok ( ( dclient, m. get_layers ( ) ) )
104
+ }
105
+ _ => Err ( "unknown format" . into ( ) ) ,
106
+ } ,
107
+ )
108
+ } ) . and_then ( |( dclient, layers) | {
109
+ let image = image. clone ( ) ;
110
+
111
+ println ! ( "{} -> got {} layer(s)" , & image, layers. len( ) , ) ;
112
+
113
+ futures:: stream:: iter_ok :: < _ , dkregistry:: errors:: Error > ( layers)
114
+ . and_then ( move |layer| {
115
+ let get_blob_future = dclient. get_blob ( & image, & layer) ;
116
+ get_blob_future. inspect ( move |blob| {
117
+ println ! ( "Layer {}, got {} bytes.\n " , layer, blob. len( ) ) ;
118
+ } )
119
+ } ) . collect ( )
120
+ } ) ;
121
+
122
+ let blobs = match tcore. run ( futures) {
123
+ Ok ( blobs) => blobs,
124
+ Err ( e) => return Err ( Box :: new ( e) ) ,
102
125
} ;
103
126
104
- println ! (
105
- "{} -> got {} layer(s), saving to directory {:?}" ,
106
- image,
107
- layers. len( ) ,
108
- version
109
- ) ;
110
- std:: fs:: create_dir ( & version) ?;
111
- let mut blobs: Vec < Vec < u8 > > = vec ! [ ] ;
112
-
113
- for ( i, digest) in layers. iter ( ) . enumerate ( ) {
114
- let fut_presence = dclient. has_blob ( & image, & digest) ?;
115
- let has_blob = tcore. run ( fut_presence) ?;
116
- if !has_blob {
117
- return Err ( format ! ( "missing layer {}" , digest) . into ( ) ) ;
118
- }
127
+ println ! ( "Downloaded {} layers" , blobs. len( ) ) ;
119
128
120
- println ! ( "Downloading layer {}..." , digest) ;
121
- let fut_out = dclient. get_blob ( & image, & digest) ?;
122
- let out = tcore. run ( fut_out) ?;
123
- println ! (
124
- "Layer {}/{}, got {} bytes.\n " ,
125
- i + 1 ,
126
- layers. len( ) ,
127
- out. len( )
128
- ) ;
129
- blobs. push ( out) ;
129
+ let path = & format ! ( "{}:{}" , & image, & version) . replace ( "/" , "_" ) ;
130
+ let path = std:: path:: Path :: new ( & path) ;
131
+ if path. exists ( ) {
132
+ return Err ( format ! ( "path {:?} already exists, exiting" , & path) . into ( ) ) ;
130
133
}
134
+ // TODO: use async io
135
+ std:: fs:: create_dir ( & path) . unwrap ( ) ;
136
+ let can_path = path. canonicalize ( ) . unwrap ( ) ;
137
+
138
+ println ! ( "Unpacking layers to {:?}" , & can_path) ;
139
+ let r = render:: unpack ( & blobs, & can_path) . unwrap ( ) ;
131
140
132
- let can_path = std:: fs:: canonicalize ( & version) ?;
133
- let r = render:: unpack ( & blobs, & can_path) ;
134
- println ! ( "{:?}" , r) ;
135
- r?;
136
- Ok ( ( ) )
141
+ Ok ( r)
137
142
}
0 commit comments