Skip to content

Commit 543e79e

Browse files
ref(proguard): Replace MappingRef with ProguardMapping
The new `ProguardMapping` type directly references the `ByteView` of the Proguard file, rather than simply storing the path to the file. This change will enable us to replace `ChunkedMapping` with `Chunked<ProguardMapping>`. ref #2196
1 parent 2790aa1 commit 543e79e

File tree

6 files changed

+95
-49
lines changed

6 files changed

+95
-49
lines changed

src/commands/upload_proguard.rs

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
use std::env;
2-
use std::fs;
32
use std::io;
4-
use std::path::Path;
5-
use std::path::PathBuf;
63

7-
use ::proguard::ProguardMapping;
84
use anyhow::{bail, Error, Result};
95
use clap::ArgAction;
106
use clap::{Arg, ArgMatches, Command};
@@ -20,24 +16,12 @@ use crate::utils::android::dump_proguard_uuids_as_properties;
2016
use crate::utils::args::ArgExt;
2117
use crate::utils::fs::TempFile;
2218
use crate::utils::proguard;
19+
use crate::utils::proguard::ProguardMapping;
2320
use crate::utils::system::QuietExit;
2421
use crate::utils::ui::{copy_with_progress, make_byte_progress_bar};
2522

2623
const CHUNK_UPLOAD_ENV_VAR: &str = "SENTRY_EXPERIMENTAL_PROGUARD_CHUNK_UPLOAD";
2724

28-
#[derive(Debug)]
29-
pub struct MappingRef {
30-
pub path: PathBuf,
31-
pub size: u64,
32-
pub uuid: Uuid,
33-
}
34-
35-
impl AsRef<Path> for MappingRef {
36-
fn as_ref(&self) -> &Path {
37-
&self.path
38-
}
39-
}
40-
4125
pub fn make_command(command: Command) -> Command {
4226
command
4327
.about("Upload ProGuard mapping files to a project.")
@@ -168,21 +152,10 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
168152
// them all up.
169153
for path in &paths {
170154
match ByteView::open(path) {
171-
Ok(byteview) => {
172-
let mapping = ProguardMapping::new(&byteview);
173-
if !mapping.has_line_info() {
174-
eprintln!(
175-
"warning: proguard mapping '{path}' was ignored because it \
176-
does not contain any line information."
177-
);
178-
} else {
179-
mappings.push(MappingRef {
180-
path: PathBuf::from(path),
181-
size: byteview.len() as u64,
182-
uuid: forced_uuid.copied().unwrap_or_else(|| mapping.uuid()),
183-
});
184-
}
185-
}
155+
Ok(byteview) => match ProguardMapping::try_from(byteview) {
156+
Ok(mapping) => mappings.push(mapping),
157+
Err(e) => eprintln!("warning: ignoring proguard mapping '{path}': {e}"),
158+
},
186159
Err(ref err) if err.kind() == io::ErrorKind::NotFound => {
187160
eprintln!(
188161
"warning: proguard mapping '{path}' does not exist. This \
@@ -198,6 +171,14 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
198171
}
199172
}
200173

174+
if let Some(&uuid) = forced_uuid {
175+
// There should only be one mapping if we are forcing a UUID.
176+
// This is checked earlier.
177+
for mapping in &mut mappings {
178+
mapping.force_uuid(uuid);
179+
}
180+
}
181+
201182
let api = Api::current();
202183
let config = Config::current();
203184

@@ -243,19 +224,19 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
243224
{
244225
let mut zip = zip::ZipWriter::new(tf.open()?);
245226
for mapping in &mappings {
246-
let pb = make_byte_progress_bar(mapping.size);
227+
let pb = make_byte_progress_bar(mapping.len() as u64);
247228
zip.start_file(
248-
format!("proguard/{}.txt", mapping.uuid),
229+
format!("proguard/{}.txt", mapping.uuid()),
249230
zip::write::FileOptions::default(),
250231
)?;
251-
copy_with_progress(&pb, &mut fs::File::open(&mapping.path)?, &mut zip)?;
232+
copy_with_progress(&pb, &mut mapping.as_ref(), &mut zip)?;
252233
pb.finish_and_clear();
253234
}
254235
}
255236

256237
// write UUIDs into the mapping file.
257238
if let Some(p) = matches.get_one::<String>("write_properties") {
258-
let uuids: Vec<_> = mappings.iter().map(|x| x.uuid).collect();
239+
let uuids: Vec<_> = mappings.iter().map(|x| x.uuid()).collect();
259240
dump_proguard_uuids_as_properties(p, &uuids)?;
260241
}
261242

@@ -305,7 +286,7 @@ pub fn execute(matches: &ArgMatches) -> Result<()> {
305286
}
306287

307288
for mapping in &mappings {
308-
let uuid = forced_uuid.unwrap_or(&mapping.uuid);
289+
let uuid = forced_uuid.copied().unwrap_or(mapping.uuid());
309290
authenticated_api.associate_proguard_mappings(
310291
&org,
311292
&project,

src/utils/proguard/mapping.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
use symbolic::common::ByteView;
2+
use thiserror::Error;
3+
use uuid::Uuid;
4+
5+
#[derive(Debug, Error)]
6+
pub enum ProguardMappingError {
7+
#[error("Proguard mapping does not contain line information")]
8+
MissingLineInfo,
9+
}
10+
11+
pub struct ProguardMapping<'a> {
12+
bytes: ByteView<'a>,
13+
uuid: Uuid,
14+
}
15+
16+
impl<'a> ProguardMapping<'a> {
17+
/// Get the length of the mapping in bytes.
18+
pub fn len(&self) -> usize {
19+
self.bytes.len()
20+
}
21+
22+
/// Get the UUID of the mapping.
23+
pub fn uuid(&self) -> Uuid {
24+
self.uuid
25+
}
26+
27+
/// Force the UUID of the mapping to a specific value, rather
28+
/// than the UUID which is derived from the proguard crate.
29+
pub fn force_uuid(&mut self, uuid: Uuid) {
30+
self.uuid = uuid;
31+
}
32+
33+
/// Create a new `ProguardMapping` from a `ByteView`.
34+
/// Not public because we want to ensure that the `ByteView` contains line
35+
/// information, and this method does not check for that. To create a
36+
/// `ProguardMapping` externally, use the `TryFrom<ByteView>` implementation.
37+
fn new(bytes: ByteView<'a>, uuid: Uuid) -> Self {
38+
Self { bytes, uuid }
39+
}
40+
}
41+
42+
impl<'a> TryFrom<ByteView<'a>> for ProguardMapping<'a> {
43+
type Error = ProguardMappingError;
44+
45+
/// Try to create a `ProguardMapping` from a `ByteView`.
46+
/// The method returns an error if the mapping does not contain
47+
/// line information.
48+
fn try_from(value: ByteView<'a>) -> Result<Self, Self::Error> {
49+
let mapping = ::proguard::ProguardMapping::new(&value);
50+
51+
if !mapping.has_line_info() {
52+
return Err(ProguardMappingError::MissingLineInfo);
53+
}
54+
55+
let uuid = mapping.uuid();
56+
Ok(ProguardMapping::new(value, uuid))
57+
}
58+
}
59+
60+
impl AsRef<[u8]> for ProguardMapping<'_> {
61+
fn as_ref(&self) -> &[u8] {
62+
self.bytes.as_ref()
63+
}
64+
}

src/utils/proguard/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
mod mapping;
12
mod upload;
23

4+
pub use self::mapping::ProguardMapping;
35
pub use self::upload::chunk_upload;

src/utils/proguard/upload.rs

Lines changed: 9 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,17 @@
44
//! Proguard mappings, while we work on a more permanent solution, which will
55
//! work for all different types of debug files.
66
7+
use std::thread;
78
use std::time::{Duration, Instant};
8-
use std::{fs, thread};
99

1010
use anyhow::Result;
1111
use indicatif::ProgressStyle;
1212
use sha1_smol::Digest;
1313

1414
use crate::api::{Api, ChunkUploadOptions, ChunkedDifRequest, ChunkedFileState};
15-
use crate::commands::upload_proguard::MappingRef;
16-
use crate::utils::chunks;
17-
use crate::utils::chunks::Chunk;
15+
use crate::utils::chunks::{self, Chunk};
1816
use crate::utils::fs::get_sha1_checksums;
17+
use crate::utils::proguard::ProguardMapping;
1918

2019
/// How often to poll the server for the status of the assembled mappings.
2120
const ASSEMBLE_POLL_INTERVAL: Duration = Duration::from_secs(1);
@@ -34,9 +33,9 @@ struct ChunkedMapping {
3433
}
3534

3635
impl ChunkedMapping {
37-
fn try_from_mapping(mapping: &MappingRef, chunk_size: u64) -> Result<Self> {
38-
let raw_data = fs::read(mapping)?;
39-
let file_name = format!("/proguard/{}.txt", mapping.uuid);
36+
fn try_from_mapping(mapping: &ProguardMapping, chunk_size: u64) -> Result<Self> {
37+
let raw_data = mapping.as_ref().to_vec();
38+
let file_name = format!("/proguard/{}.txt", mapping.uuid());
4039

4140
let (hash, chunk_hashes) = get_sha1_checksums(&raw_data, chunk_size as usize)?;
4241
Ok(Self {
@@ -66,14 +65,14 @@ impl<'a> From<&'a ChunkedMapping> for ChunkedDifRequest<'a> {
6665
/// Blocks until the mappings have been assembled (up to ASSEMBLE_POLL_TIMEOUT).
6766
/// Returns an error if the mappings fail to assemble, or if the timeout is reached.
6867
pub fn chunk_upload(
69-
paths: &[MappingRef],
68+
mappings: &[ProguardMapping<'_>],
7069
chunk_upload_options: &ChunkUploadOptions,
7170
org: &str,
7271
project: &str,
7372
) -> Result<()> {
74-
let chunked_mappings: Vec<ChunkedMapping> = paths
73+
let chunked_mappings: Vec<ChunkedMapping> = mappings
7574
.iter()
76-
.map(|path| ChunkedMapping::try_from_mapping(path, chunk_upload_options.chunk_size))
75+
.map(|mapping| ChunkedMapping::try_from_mapping(mapping, chunk_upload_options.chunk_size))
7776
.collect::<Result<_>>()?;
7877

7978
let progress_style = ProgressStyle::default_bar().template(

tests/integration/_cases/upload_proguard/upload_proguard-no-upload.trycmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
```
22
$ sentry-cli upload-proguard tests/integration/_fixtures/proguard.txt --no-upload
33
? success
4-
warning: proguard mapping 'tests/integration/_fixtures/proguard.txt' was ignored because it does not contain any line information.
4+
warning: ignoring proguard mapping 'tests/integration/_fixtures/proguard.txt': Proguard mapping does not contain line information
55
> compressing mappings
66
> skipping upload.
77

tests/integration/_cases/upload_proguard/upload_proguard.trycmd

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
```
22
$ sentry-cli upload-proguard tests/integration/_fixtures/proguard.txt
33
? success
4-
warning: proguard mapping 'tests/integration/_fixtures/proguard.txt' was ignored because it does not contain any line information.
4+
warning: ignoring proguard mapping 'tests/integration/_fixtures/proguard.txt': Proguard mapping does not contain line information
55
> compressing mappings
66
> uploading mappings
77
> Uploaded a total of 0 new mapping files

0 commit comments

Comments
 (0)