1
1
//! Searches, processes and uploads release files.
2
2
use std:: collections:: { BTreeMap , HashMap } ;
3
- use std:: fmt;
3
+ use std:: fmt:: { self , Display } ;
4
4
use std:: io:: BufWriter ;
5
5
use std:: path:: PathBuf ;
6
6
use std:: str;
@@ -19,6 +19,7 @@ use symbolic::common::ByteView;
19
19
use symbolic:: debuginfo:: sourcebundle:: {
20
20
SourceBundleErrorKind , SourceBundleWriter , SourceFileInfo , SourceFileType ,
21
21
} ;
22
+ use thiserror:: Error ;
22
23
use url:: Url ;
23
24
24
25
use crate :: api:: NewRelease ;
@@ -100,6 +101,104 @@ impl UploadContext<'_> {
100
101
}
101
102
}
102
103
104
+ #[ derive( Debug , Error ) ]
105
+ pub enum LegacyUploadContextError {
106
+ #[ error( "a release is required for this upload" ) ]
107
+ ReleaseMissing ,
108
+ }
109
+
110
+ /// Represents the context for legacy release uploads.
111
+ ///
112
+ /// `LegacyUploadContext` contains information needed for legacy (non-chunked)
113
+ /// uploads. Legacy uploads are primarily used when uploading to old self-hosted
114
+ /// Sentry servers, which do not support receiving chunked uploads.
115
+ ///
116
+ /// Unlike chunked uploads, legacy uploads require a release to be set,
117
+ /// and do not need to have chunk-upload-related fields.
118
+ #[ derive( Debug , Default ) ]
119
+ pub struct LegacyUploadContext < ' a > {
120
+ org : & ' a str ,
121
+ project : Option < & ' a str > ,
122
+ release : & ' a str ,
123
+ dist : Option < & ' a str > ,
124
+ }
125
+
126
+ impl LegacyUploadContext < ' _ > {
127
+ pub fn org ( & self ) -> & str {
128
+ self . org
129
+ }
130
+
131
+ pub fn project ( & self ) -> Option < & str > {
132
+ self . project
133
+ }
134
+
135
+ pub fn release ( & self ) -> & str {
136
+ self . release
137
+ }
138
+
139
+ pub fn dist ( & self ) -> Option < & str > {
140
+ self . dist
141
+ }
142
+ }
143
+
144
+ impl Display for LegacyUploadContext < ' _ > {
145
+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
146
+ writeln ! (
147
+ f,
148
+ "{} {}" ,
149
+ style( "> Organization:" ) . dim( ) ,
150
+ style( self . org) . yellow( )
151
+ ) ?;
152
+ writeln ! (
153
+ f,
154
+ "{} {}" ,
155
+ style( "> Project:" ) . dim( ) ,
156
+ style( self . project. unwrap_or( "None" ) ) . yellow( )
157
+ ) ?;
158
+ writeln ! (
159
+ f,
160
+ "{} {}" ,
161
+ style( "> Release:" ) . dim( ) ,
162
+ style( self . release) . yellow( )
163
+ ) ?;
164
+ writeln ! (
165
+ f,
166
+ "{} {}" ,
167
+ style( "> Dist:" ) . dim( ) ,
168
+ style( self . dist. unwrap_or( "None" ) ) . yellow( )
169
+ ) ?;
170
+ write ! (
171
+ f,
172
+ "{} {}" ,
173
+ style( "> Upload type:" ) . dim( ) ,
174
+ style( "single file/legacy upload" ) . yellow( )
175
+ )
176
+ }
177
+ }
178
+
179
+ impl < ' a > TryFrom < & ' a UploadContext < ' _ > > for LegacyUploadContext < ' a > {
180
+ type Error = LegacyUploadContextError ;
181
+
182
+ fn try_from ( value : & ' a UploadContext ) -> Result < Self , Self :: Error > {
183
+ let & UploadContext {
184
+ org,
185
+ project,
186
+ release,
187
+ dist,
188
+ ..
189
+ } = value;
190
+
191
+ let release = release. ok_or ( LegacyUploadContextError :: ReleaseMissing ) ?;
192
+
193
+ Ok ( Self {
194
+ org,
195
+ project,
196
+ release,
197
+ dist,
198
+ } )
199
+ }
200
+ }
201
+
103
202
#[ derive( Eq , PartialEq , Debug , Copy , Clone ) ]
104
203
pub enum LogLevel {
105
204
Warning ,
@@ -215,7 +314,19 @@ impl<'a> FileUpload<'a> {
215
314
. context
216
315
. chunk_upload_options
217
316
. map_or ( DEFAULT_CONCURRENCY , |o| usize:: from ( o. concurrency ) ) ;
218
- upload_files_parallel ( self . context , & self . files , concurrency)
317
+
318
+ let legacy_context = & self . context . try_into ( ) . map_err ( |e| {
319
+ anyhow:: anyhow!(
320
+ "Error while performing legacy upload: {e}. \
321
+ If you would like to upload files {}, you need to upgrade your Sentry server \
322
+ or switch to our SaaS offering.",
323
+ match e {
324
+ LegacyUploadContextError :: ReleaseMissing => "without specifying a release" ,
325
+ }
326
+ )
327
+ } ) ?;
328
+
329
+ upload_files_parallel ( legacy_context, & self . files , concurrency)
219
330
}
220
331
221
332
pub fn build_jvm_bundle ( & self , debug_id : Option < DebugId > ) -> Result < TempFile > {
@@ -224,18 +335,18 @@ impl<'a> FileUpload<'a> {
224
335
}
225
336
226
337
fn upload_files_parallel (
227
- context : & UploadContext ,
338
+ context : & LegacyUploadContext ,
228
339
files : & SourceFiles ,
229
340
num_threads : usize ,
230
341
) -> Result < ( ) > {
231
342
let api = Api :: current ( ) ;
232
- let release = context. release ( ) ? ;
343
+ let release = context. release ( ) ;
233
344
234
345
// get a list of release files first so we know the file IDs of
235
346
// files that already exist.
236
347
let release_files: HashMap < _ , _ > = api
237
348
. authenticated ( ) ?
238
- . list_release_files ( context. org , context. project , release) ?
349
+ . list_release_files ( context. org , context. project ( ) , release) ?
239
350
. into_iter ( )
240
351
. map ( |artifact| ( ( artifact. dist , artifact. name ) , artifact. id ) )
241
352
. collect ( ) ;
@@ -308,7 +419,7 @@ fn upload_files_parallel(
308
419
309
420
pb. finish_and_clear ( ) ;
310
421
311
- print_upload_context_details ( context) ;
422
+ println ! ( "{}" , context) ;
312
423
313
424
Ok ( ( ) )
314
425
}
0 commit comments