Skip to content

Commit

Permalink
fix: construct placeholder string at runtime (conda#371)
Browse files Browse the repository at this point in the history
Removes the hardcoded `/opt/anaconda1anaconda2anaconda3` string from the
binary and instead constructs it at runtime. This is required to ensure
that when using the rattler binary in recipe the string is not replaced.
  • Loading branch information
baszalmstra authored Oct 9, 2023
1 parent 7a649bd commit f99bb5c
Showing 1 changed file with 29 additions and 6 deletions.
35 changes: 29 additions & 6 deletions crates/rattler_conda_types/src/package/has_prefix.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
use crate::package::paths::FileMode;
use crate::package::PackageFile;
use crate::{package::paths::FileMode, package::PackageFile};
use nom::{
branch::alt,
bytes::complete::{tag, tag_no_case, take_till1},
Expand All @@ -10,8 +9,10 @@ use nom::{
};
use std::{
borrow::Cow,
hint::black_box,
path::{Path, PathBuf},
str::FromStr,
sync::OnceLock,
};

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -43,6 +44,24 @@ impl PackageFile for HasPrefix {
}
}

/// Returns the default placeholder path. Although this is just a constant it is constructed at
/// runtime. This ensures that the string itself is not present in the binary when compiled. The
/// reason we want that is that conda-build (and friends) tries to replace this placeholder in the
/// binary to point to the actual path in the installed conda environment. In this case we don't
/// want to that so we deliberately break up the string and reconstruct it at runtime.
fn placeholder_string() -> &'static str {
static PLACEHOLDER: OnceLock<String> = OnceLock::new();
PLACEHOLDER
.get_or_init(|| {
let mut result = black_box(String::from("/opt/"));
for i in 1..=3 {
result.push_str(&format!("anaconda{i}"))
}
result
})
.as_str()
}

impl FromStr for HasPrefixEntry {
type Err = std::io::Error;

Expand Down Expand Up @@ -72,7 +91,7 @@ impl FromStr for HasPrefixEntry {
/// Parses "<path>" and fails if there is more input.
fn only_path(buf: &str) -> IResult<&str, HasPrefixEntry> {
all_consuming(map(possibly_quoted_string, |path| HasPrefixEntry {
prefix: Cow::Borrowed("/opt/anaconda1anaconda2anaconda3"),
prefix: Cow::Borrowed(placeholder_string()),
file_mode: FileMode::Text,
relative_path: PathBuf::from(path.as_ref()),
}))(buf)
Expand Down Expand Up @@ -120,10 +139,14 @@ impl FromStr for HasPrefixEntry {

#[cfg(test)]
mod test {
use super::HasPrefixEntry;
use super::*;
use crate::package::FileMode;
use std::str::FromStr;
use std::{borrow::Cow, path::PathBuf};
use std::{borrow::Cow, path::PathBuf, str::FromStr};

#[test]
fn test_placeholder() {
assert_eq!(placeholder_string(), "/opt/anaconda1anaconda2anaconda3");
}

#[test]
pub fn test_parse_has_prefix() {
Expand Down

0 comments on commit f99bb5c

Please sign in to comment.