1
1
use anyhow:: { anyhow, Context , Error , Result } ;
2
- use futures:: future:: try_join_all;
3
2
use futures:: FutureExt ;
4
3
use itertools:: Itertools ;
5
4
use simplelog:: { debug, trace} ;
6
5
use std:: fs:: File ;
7
6
use std:: io:: { BufReader , Read , Write } ;
7
+ use std:: iter:: repeat_with;
8
8
use std:: path:: { Path , PathBuf } ;
9
9
use tempfile:: tempdir_in;
10
10
use zip;
11
11
12
12
use crate :: builder:: docker;
13
13
use crate :: clients:: docker;
14
14
use crate :: configparser:: challenge:: { ChallengeConfig , ProvideConfig } ;
15
+ use crate :: utils:: TryJoinAll ;
15
16
16
17
/// extract assets from provide config and possible container to challenge directory, return file path(s) extracted
17
- #[ tokio:: main( flavor = "current_thread" ) ] // make this a sync function
18
18
pub async fn extract_asset (
19
19
chal : & ChallengeConfig ,
20
20
provide : & ProvideConfig ,
@@ -62,73 +62,76 @@ pub async fn extract_asset(
62
62
Ok ( vec ! [ archive_name. clone( ) ] )
63
63
}
64
64
65
+ // handle all container events together to manage container, then match again
65
66
ProvideConfig :: FromContainer {
66
67
container : container_name,
67
- files,
68
- } => {
69
- let tag = chal. container_tag_for_pod ( profile_name, container_name) ?;
70
-
71
- let name = format ! (
72
- "asset-container-{}-{}" ,
73
- chal. directory. to_string_lossy( ) . replace( "/" , "-" ) ,
74
- container_name
75
- ) ;
76
- let container = docker:: create_container ( & tag, & name) . await ?;
77
-
78
- let files = extract_files ( chal, & container, files) . await ;
79
-
80
- docker:: remove_container ( container) . await ?;
81
-
82
- files
68
+ ..
83
69
}
84
- . with_context ( || format ! ( "could not copy files {files:?} from container {container_name}" ) ) ,
85
-
86
- ProvideConfig :: FromContainerRename {
70
+ | ProvideConfig :: FromContainerRename {
87
71
container : container_name,
88
- from,
89
- to,
90
- } => {
91
- let tag = chal. container_tag_for_pod ( profile_name, container_name) ?;
92
-
93
- let name = format ! (
94
- "asset-container-{}-{}" ,
95
- chal. directory. to_string_lossy( ) . replace( "/" , "-" ) ,
96
- container_name
97
- ) ;
98
- let container = docker:: create_container ( & tag, & name) . await ?;
99
-
100
- let files = extract_rename ( chal, & container, from, & chal. directory . join ( to) ) . await ;
101
-
102
- docker:: remove_container ( container) . await ?;
103
-
104
- files
72
+ ..
105
73
}
106
- . with_context ( || format ! ( "could not copy file {from:?} from container {container_name}" ) ) ,
107
-
108
- ProvideConfig :: FromContainerArchive {
74
+ | ProvideConfig :: FromContainerArchive {
109
75
container : container_name,
110
- files,
111
- archive_name,
76
+ ..
112
77
} => {
113
78
let tag = chal. container_tag_for_pod ( profile_name, container_name) ?;
114
79
115
80
let name = format ! (
116
- "asset-container-{}-{}" ,
81
+ "asset-container-{}-{}-{} " ,
117
82
chal. directory. to_string_lossy( ) . replace( "/" , "-" ) ,
118
- container_name
83
+ container_name,
84
+ // include random discriminator to avoid name collisions
85
+ repeat_with( fastrand:: alphanumeric)
86
+ . take( 6 )
87
+ . collect:: <String >( )
119
88
) ;
89
+
120
90
let container = docker:: create_container ( & tag, & name) . await ?;
121
91
122
- let files =
123
- extract_archive ( chal, & container, files, & chal. directory . join ( archive_name) ) . await ;
92
+ // match on `provide` enum again to handle each container type
93
+ let files = match provide {
94
+ ProvideConfig :: FromContainer {
95
+ container : container_name,
96
+ files,
97
+ } => extract_files ( chal, & container, files)
98
+ . await
99
+ . with_context ( || {
100
+ format ! ( "could not copy files {files:?} from container {container_name}" )
101
+ } ) ,
102
+
103
+ ProvideConfig :: FromContainerRename {
104
+ container : container_name,
105
+ from,
106
+ to,
107
+ } => extract_rename ( chal, & container, from, & chal. directory . join ( to) )
108
+ . await
109
+ . with_context ( || {
110
+ format ! ( "could not copy file {from:?} from container {container_name}" )
111
+ } ) ,
112
+
113
+ ProvideConfig :: FromContainerArchive {
114
+ container : container_name,
115
+ files,
116
+ archive_name,
117
+ } => extract_archive ( chal, & container, files, & chal. directory . join ( archive_name) )
118
+ . await
119
+ . with_context ( || {
120
+ // rustfmt chokes silently if these format args are inlined... ???
121
+ format ! (
122
+ "could not create archive {:?} with files {:?} from container {}" ,
123
+ archive_name, files, container_name
124
+ )
125
+ } ) ,
126
+
127
+ // non-container variants handled by outer match
128
+ _ => unreachable ! ( ) ,
129
+ } ;
124
130
125
131
docker:: remove_container ( container) . await ?;
126
132
127
133
files
128
134
}
129
- . with_context ( || {
130
- format ! ( "could not create archive {archive_name:?} from container {container_name}" )
131
- } ) ,
132
135
}
133
136
}
134
137
@@ -144,12 +147,15 @@ async fn extract_files(
144
147
files
145
148
) ;
146
149
147
- try_join_all ( files. iter ( ) . map ( |from| async {
148
- // use basename of source file as target name
149
- let to = chal. directory . join ( from. file_name ( ) . unwrap ( ) ) ;
150
- docker:: copy_file ( container, from, & to) . await
151
- } ) )
152
- . await
150
+ files
151
+ . iter ( )
152
+ . map ( |from| async {
153
+ // use basename of source file as target name
154
+ let to = chal. directory . join ( from. file_name ( ) . unwrap ( ) ) ;
155
+ docker:: copy_file ( container, from, & to) . await
156
+ } )
157
+ . try_join_all ( )
158
+ . await
153
159
}
154
160
155
161
/// Extract one file from container and rename
@@ -170,7 +176,6 @@ async fn extract_rename(
170
176
async fn extract_archive (
171
177
chal : & ChallengeConfig ,
172
178
container : & docker:: ContainerInfo ,
173
- // files: &Vec<PathBuf>,
174
179
files : & [ PathBuf ] ,
175
180
archive_name : & Path ,
176
181
) -> Result < Vec < PathBuf > > {
@@ -185,16 +190,19 @@ async fn extract_archive(
185
190
let tempdir = tempfile:: Builder :: new ( )
186
191
. prefix ( ".beavercds-archive-" )
187
192
. tempdir_in ( "." ) ?;
188
- let copied_files = try_join_all ( files. iter ( ) . map ( |from| async {
189
- let to = tempdir. path ( ) . join ( from. file_name ( ) . unwrap ( ) ) ;
190
- docker:: copy_file ( container, from, & to) . await
191
- } ) )
192
- . await ?;
193
+ let copied_files = files
194
+ . iter ( )
195
+ . map ( |from| async {
196
+ let to = tempdir. path ( ) . join ( from. file_name ( ) . unwrap ( ) ) ;
197
+ docker:: copy_file ( container, from, & to) . await
198
+ } )
199
+ . try_join_all ( )
200
+ . await ?;
193
201
194
202
// archive_name already has the chal dir prepended
195
203
zip_files ( archive_name, & copied_files) ?;
196
204
197
- Ok ( vec ! [ chal . directory . join ( archive_name ) ] )
205
+ Ok ( vec ! [ archive_name . to_path_buf ( ) ] )
198
206
}
199
207
200
208
/// Add multiple local `files` to a zipfile at `zip_name`
0 commit comments