11//! Searches, processes and uploads release files.
22use std:: collections:: { BTreeMap , HashMap } ;
3- use std:: fmt;
3+ use std:: fmt:: { self , Display } ;
44use std:: io:: BufWriter ;
55use std:: path:: PathBuf ;
66use std:: str;
@@ -19,6 +19,7 @@ use symbolic::common::ByteView;
1919use symbolic:: debuginfo:: sourcebundle:: {
2020 SourceBundleErrorKind , SourceBundleWriter , SourceFileInfo , SourceFileType ,
2121} ;
22+ use thiserror:: Error ;
2223use url:: Url ;
2324
2425use crate :: api:: NewRelease ;
@@ -100,6 +101,108 @@ impl UploadContext<'_> {
100101 }
101102}
102103
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+ note : _,
189+ wait : _,
190+ max_wait : _,
191+ dedupe : _,
192+ chunk_upload_options : _,
193+ } = value;
194+
195+ let release = release. ok_or ( LegacyUploadContextError :: ReleaseMissing ) ?;
196+
197+ Ok ( Self {
198+ org,
199+ project,
200+ release,
201+ dist,
202+ } )
203+ }
204+ }
205+
103206#[ derive( Eq , PartialEq , Debug , Copy , Clone ) ]
104207pub enum LogLevel {
105208 Warning ,
@@ -215,7 +318,19 @@ impl<'a> FileUpload<'a> {
215318 . context
216319 . chunk_upload_options
217320 . map_or ( DEFAULT_CONCURRENCY , |o| usize:: from ( o. concurrency ) ) ;
218- upload_files_parallel ( self . context , & self . files , concurrency)
321+
322+ let legacy_context = & self . context . try_into ( ) . map_err ( |e| {
323+ anyhow:: anyhow!(
324+ "Error while performing legacy upload: {e}. \
325+ If you would like to upload files {}, you need to upgrade your Sentry server \
326+ or switch to our SaaS offering.",
327+ match e {
328+ LegacyUploadContextError :: ReleaseMissing => "without specifying a release" ,
329+ }
330+ )
331+ } ) ?;
332+
333+ upload_files_parallel ( legacy_context, & self . files , concurrency)
219334 }
220335
221336 pub fn build_jvm_bundle ( & self , debug_id : Option < DebugId > ) -> Result < TempFile > {
@@ -224,18 +339,18 @@ impl<'a> FileUpload<'a> {
224339}
225340
226341fn upload_files_parallel (
227- context : & UploadContext ,
342+ context : & LegacyUploadContext ,
228343 files : & SourceFiles ,
229344 num_threads : usize ,
230345) -> Result < ( ) > {
231346 let api = Api :: current ( ) ;
232- let release = context. release ( ) ? ;
347+ let release = context. release ( ) ;
233348
234349 // get a list of release files first so we know the file IDs of
235350 // files that already exist.
236351 let release_files: HashMap < _ , _ > = api
237352 . authenticated ( ) ?
238- . list_release_files ( context. org , context. project , release) ?
353+ . list_release_files ( context. org , context. project ( ) , release) ?
239354 . into_iter ( )
240355 . map ( |artifact| ( ( artifact. dist , artifact. name ) , artifact. id ) )
241356 . collect ( ) ;
@@ -308,7 +423,7 @@ fn upload_files_parallel(
308423
309424 pb. finish_and_clear ( ) ;
310425
311- print_upload_context_details ( context) ;
426+ println ! ( "{}" , context) ;
312427
313428 Ok ( ( ) )
314429}
0 commit comments