Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 3 additions & 159 deletions src/commands/files/upload.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,8 @@
use std::collections::BTreeMap;
use std::ffi::OsStr;
use std::fs;
use std::io::Read;
use std::path::Path;
use std::sync::Arc;
use std::time::Duration;

use anyhow::{bail, format_err, Result};
use anyhow::Result;
use clap::{Arg, ArgAction, ArgMatches, Command};
use log::warn;
use symbolic::debuginfo::sourcebundle::SourceFileType;

use crate::api::Api;
use crate::config::Config;
use crate::constants::DEFAULT_MAX_WAIT;
use crate::utils::args::validate_distribution;
use crate::utils::file_search::ReleaseFileSearch;
use crate::utils::file_upload::{
initialize_legacy_release_upload, FileUpload, SourceFile, UploadContext,
};
use crate::utils::fs::{decompress_gzip_content, is_gzip_compressed, path_as_url};
use crate::utils::progress::ProgressBarMode;

pub fn make_command(command: Command) -> Command {
command
Expand Down Expand Up @@ -123,144 +105,6 @@ pub fn make_command(command: Command) -> Command {
)
}

pub fn execute(matches: &ArgMatches) -> Result<()> {
let config = Config::current();
let release = config.get_release_with_legacy_fallback(matches)?;
let org = config.get_org(matches)?;
let project = config.get_project(matches).ok();
let api = Api::current();
let authenticated_api = api.authenticated()?;
let chunk_upload_options = authenticated_api.get_chunk_upload_options(&org)?;

let dist = matches.get_one::<String>("dist").map(String::as_str);
let mut headers = BTreeMap::new();
if let Some(header_list) = matches.get_many::<String>("file-headers") {
for header in header_list {
if !header.contains(':') {
bail!("Invalid header. Needs to be in key:value format");
}
let (key, value) = header.split_once(':').unwrap();
headers.insert(key.trim().to_string(), value.trim().to_string());
}
};

let wait_for_secs = matches.get_one::<u64>("wait_for").copied();
let wait = matches.get_flag("wait") || wait_for_secs.is_some();
let max_wait = wait_for_secs.map_or(DEFAULT_MAX_WAIT, Duration::from_secs);

let context = &UploadContext {
org: &org,
project: project.as_deref(),
release: Some(&release),
dist,
note: None,
wait,
max_wait,
dedupe: false,
chunk_upload_options: chunk_upload_options.as_ref(),
};

let path = Path::new(matches.get_one::<String>("path").unwrap());
// Batch files upload
if path.is_dir() {
let ignore_file = matches
.get_one::<String>("ignore_file")
.map(String::as_str)
.unwrap_or_default();
let ignores: Vec<_> = matches
.get_many::<String>("ignore")
.map(|ignores| ignores.map(|i| format!("!{i}")).collect())
.unwrap_or_default();
let extensions: Vec<_> = matches
.get_many::<String>("extensions")
.map(|extensions| extensions.map(|ext| ext.trim_start_matches('.')).collect())
.unwrap_or_default();

let sources = ReleaseFileSearch::new(path.to_path_buf())
.ignore_file(ignore_file)
.ignores(ignores)
.extensions(extensions)
.decompress(matches.get_flag("decompress"))
.collect_files()?;

let url_suffix = matches
.get_one::<String>("url_suffix")
.map(String::as_str)
.unwrap_or_default();
let mut url_prefix = matches
.get_one::<String>("url_prefix")
.map(String::as_str)
.unwrap_or("~");
// remove a single slash from the end. so ~/ becomes ~ and app:/// becomes app://
if url_prefix.ends_with('/') {
url_prefix = &url_prefix[..url_prefix.len() - 1];
}
let files = sources
.iter()
.map(|source| {
let local_path = source.path.strip_prefix(&source.base_path).unwrap();
let url = format!("{}/{}{}", url_prefix, path_as_url(local_path), url_suffix);

(
url.to_string(),
SourceFile {
url,
path: source.path.clone(),
contents: Arc::new(source.contents.clone()),
ty: SourceFileType::Source,
headers: headers.clone(),
messages: vec![],
already_uploaded: false,
},
)
})
.collect();

FileUpload::new(context).files(&files).upload()
}
// Single file upload
else {
initialize_legacy_release_upload(context)?;

let name = match matches.get_one::<String>("name") {
Some(name) => name,
None => Path::new(path)
.file_name()
.and_then(OsStr::to_str)
.ok_or_else(|| format_err!("No filename provided."))?,
};

let mut f = fs::File::open(path)?;
let mut contents = Vec::new();
f.read_to_end(&mut contents)?;

if matches.get_flag("decompress") && is_gzip_compressed(&contents) {
contents = decompress_gzip_content(&contents).unwrap_or_else(|_| {
warn!("Could not decompress: {}", name);
contents
});
}

if let Some(artifact) = authenticated_api
.region_specific(context.org)
.upload_release_file(
context,
&contents,
name,
Some(
headers
.iter()
.map(|(k, v)| (k.clone(), v.clone()))
.collect::<Vec<_>>()
.as_slice(),
),
ProgressBarMode::Request,
)?
{
println!("A {} ({} bytes)", artifact.sha1, artifact.size);
} else {
bail!("File already present!");
}
Ok(())
}
pub fn execute(_matches: &ArgMatches) -> Result<()> {
unimplemented!("CI should not pass with this change.");
}