Skip to content

Commit 156f7af

Browse files
ref: Separate LegacyUploadContext for legacy uploads
Legacy (i.e. non-chunked) are distinct from chunked uploads, so it makes sense to have a separate struct to enforce these differences via the type system. Specifically, legacy uploads must be associated with a release, whereas this is not required for many chunk uploads. Legacy uploads must also be associated with at most one project, whereas chunked uploads can have multiple projects (support for which we will add in the CLI with #2408)
1 parent 046ab9d commit 156f7af

File tree

3 files changed

+99
-19
lines changed

3 files changed

+99
-19
lines changed

src/api/mod.rs

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use uuid::Uuid;
4747
use crate::api::errors::ProjectRenamedError;
4848
use crate::config::{Auth, Config};
4949
use crate::constants::{ARCH, DEFAULT_URL, EXT, PLATFORM, RELEASE_REGISTRY_LATEST_URL, VERSION};
50-
use crate::utils::file_upload::UploadContext;
50+
use crate::utils::file_upload::LegacyUploadContext;
5151
use crate::utils::http::{self, is_absolute_url};
5252
use crate::utils::progress::{ProgressBar, ProgressBarMode};
5353
use crate::utils::retry::{get_default_backoff, DurationAsMilliseconds};
@@ -1425,28 +1425,24 @@ impl RegionSpecificApi<'_> {
14251425
/// system and uploaded as `name`.
14261426
pub fn upload_release_file(
14271427
&self,
1428-
context: &UploadContext,
1428+
context: &LegacyUploadContext,
14291429
contents: &[u8],
14301430
name: &str,
14311431
headers: Option<&[(String, String)]>,
14321432
progress_bar_mode: ProgressBarMode,
14331433
) -> ApiResult<Option<Artifact>> {
1434-
let release = context
1435-
.release()
1436-
.map_err(|err| ApiError::with_source(ApiErrorKind::ReleaseNotFound, err))?;
1437-
1438-
let path = if let Some(project) = context.project {
1434+
let path = if let Some(project) = context.project() {
14391435
format!(
14401436
"/projects/{}/{}/releases/{}/files/",
1441-
PathArg(context.org),
1437+
PathArg(context.org()),
14421438
PathArg(project),
1443-
PathArg(release)
1439+
PathArg(context.release())
14441440
)
14451441
} else {
14461442
format!(
14471443
"/organizations/{}/releases/{}/files/",
1448-
PathArg(context.org),
1449-
PathArg(release)
1444+
PathArg(context.org()),
1445+
PathArg(context.release())
14501446
)
14511447
};
14521448
let mut form = curl::easy::Form::new();
@@ -1459,7 +1455,7 @@ impl RegionSpecificApi<'_> {
14591455
.buffer(filename, contents.to_vec())
14601456
.add()?;
14611457
form.part("name").contents(name.as_bytes()).add()?;
1462-
if let Some(dist) = context.dist {
1458+
if let Some(dist) = context.dist() {
14631459
form.part("dist").contents(dist.as_bytes()).add()?;
14641460
}
14651461

src/commands/files/upload.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
244244
if let Some(artifact) = authenticated_api
245245
.region_specific(context.org)
246246
.upload_release_file(
247-
context,
247+
&context.try_into()?,
248248
&contents,
249249
name,
250250
Some(

src/utils/file_upload.rs

Lines changed: 90 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Searches, processes and uploads release files.
22
use std::collections::{BTreeMap, HashMap};
3-
use std::fmt;
3+
use std::fmt::{self, Display};
44
use std::io::BufWriter;
55
use std::path::PathBuf;
66
use std::str;
@@ -19,6 +19,7 @@ use symbolic::common::ByteView;
1919
use symbolic::debuginfo::sourcebundle::{
2020
SourceBundleErrorKind, SourceBundleWriter, SourceFileInfo, SourceFileType,
2121
};
22+
use thiserror::Error;
2223
use url::Url;
2324

2425
use crate::api::NewRelease;
@@ -100,6 +101,89 @@ impl UploadContext<'_> {
100101
}
101102
}
102103

104+
#[derive(Debug, Error)]
105+
#[non_exhaustive]
106+
pub enum LegacyUploadContextError {
107+
#[error("A release is required for this upload")]
108+
ReleaseMissing,
109+
}
110+
111+
#[derive(Debug, Default)]
112+
pub struct LegacyUploadContext<'a> {
113+
org: &'a str,
114+
project: Option<&'a str>,
115+
release: &'a str,
116+
dist: Option<&'a str>,
117+
}
118+
119+
impl LegacyUploadContext<'_> {
120+
pub fn org(&self) -> &str {
121+
self.org
122+
}
123+
124+
pub fn project(&self) -> Option<&str> {
125+
self.project
126+
}
127+
128+
pub fn release(&self) -> &str {
129+
self.release
130+
}
131+
132+
pub fn dist(&self) -> Option<&str> {
133+
self.dist
134+
}
135+
}
136+
137+
impl Display for LegacyUploadContext<'_> {
138+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
139+
writeln!(
140+
f,
141+
"{} {}",
142+
style("> Organization:").dim(),
143+
style(self.org).yellow()
144+
)?;
145+
writeln!(
146+
f,
147+
"{} {}",
148+
style("> Project:").dim(),
149+
style(self.project.unwrap_or("None")).yellow()
150+
)?;
151+
writeln!(
152+
f,
153+
"{} {}",
154+
style("> Release:").dim(),
155+
style(self.release).yellow()
156+
)?;
157+
writeln!(
158+
f,
159+
"{} {}",
160+
style("> Dist:").dim(),
161+
style(self.dist.unwrap_or("None")).yellow()
162+
)?;
163+
write!(
164+
f,
165+
"{} {}",
166+
style("> Upload type:").dim(),
167+
style("single file/legacy upload").yellow()
168+
)
169+
}
170+
}
171+
172+
impl<'a> TryFrom<&'a UploadContext<'_>> for LegacyUploadContext<'a> {
173+
type Error = LegacyUploadContextError;
174+
175+
fn try_from(value: &'a UploadContext) -> Result<Self, Self::Error> {
176+
Ok(LegacyUploadContext {
177+
org: value.org,
178+
project: value.project,
179+
release: value
180+
.release
181+
.ok_or(LegacyUploadContextError::ReleaseMissing)?,
182+
dist: value.dist,
183+
})
184+
}
185+
}
186+
103187
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
104188
pub enum LogLevel {
105189
Warning,
@@ -215,7 +299,7 @@ impl<'a> FileUpload<'a> {
215299
.context
216300
.chunk_upload_options
217301
.map_or(DEFAULT_CONCURRENCY, |o| usize::from(o.concurrency));
218-
upload_files_parallel(self.context, &self.files, concurrency)
302+
upload_files_parallel(&self.context.try_into()?, &self.files, concurrency)
219303
}
220304

221305
pub fn build_jvm_bundle(&self, debug_id: Option<DebugId>) -> Result<TempFile> {
@@ -224,18 +308,18 @@ impl<'a> FileUpload<'a> {
224308
}
225309

226310
fn upload_files_parallel(
227-
context: &UploadContext,
311+
context: &LegacyUploadContext,
228312
files: &SourceFiles,
229313
num_threads: usize,
230314
) -> Result<()> {
231315
let api = Api::current();
232-
let release = context.release()?;
316+
let release = context.release();
233317

234318
// get a list of release files first so we know the file IDs of
235319
// files that already exist.
236320
let release_files: HashMap<_, _> = api
237321
.authenticated()?
238-
.list_release_files(context.org, context.project, release)?
322+
.list_release_files(context.org, context.project(), release)?
239323
.into_iter()
240324
.map(|artifact| ((artifact.dist, artifact.name), artifact.id))
241325
.collect();
@@ -308,7 +392,7 @@ fn upload_files_parallel(
308392

309393
pb.finish_and_clear();
310394

311-
print_upload_context_details(context);
395+
println!("{}", context);
312396

313397
Ok(())
314398
}

0 commit comments

Comments
 (0)