|
2 | 2 | // Licensed under the Apache License, Version 2.0 (see LICENSE).
|
3 | 3 |
|
4 | 4 | use std::env;
|
| 5 | +use std::ffi::OsString; |
5 | 6 | use std::io::Write;
|
6 | 7 | use std::path::{Path, PathBuf};
|
7 | 8 | use std::process::{Command, Output, Stdio};
|
8 | 9 |
|
9 | 10 | use anyhow::{Context, Result};
|
| 11 | +use regex::Regex; |
10 | 12 | use tempfile::TempDir;
|
11 | 13 | use termcolor::{Color, WriteColor};
|
12 | 14 |
|
@@ -130,6 +132,9 @@ pub(crate) fn run_integration_tests(
|
130 | 132 | test_caching_issue_129(scie_pants_scie);
|
131 | 133 | test_custom_pants_toml_issue_153(scie_pants_scie);
|
132 | 134 | test_pants_native_client_perms_issue_182(scie_pants_scie);
|
| 135 | + |
| 136 | + #[cfg(unix)] |
| 137 | + test_non_utf8_env_vars_issue_198(scie_pants_scie); |
133 | 138 | }
|
134 | 139 |
|
135 | 140 | // Max Python supported is 3.8 and only Linux and macOS x86_64 wheels were released.
|
@@ -888,3 +893,81 @@ fn test_pants_native_client_perms_issue_182(scie_pants_scie: &Path) {
|
888 | 893 | decode_output(output.unwrap().stdout).unwrap().trim()
|
889 | 894 | );
|
890 | 895 | }
|
| 896 | + |
| 897 | +#[cfg(unix)] |
| 898 | +fn test_non_utf8_env_vars_issue_198(scie_pants_scie: &Path) { |
| 899 | + integration_test!( |
| 900 | + "Verifying scie-pants is robust to environments with non-utf8 env vars present ({issue})", |
| 901 | + issue = issue_link(198) |
| 902 | + ); |
| 903 | + |
| 904 | + let tmpdir = create_tempdir().unwrap(); |
| 905 | + |
| 906 | + let pants_release = "2.17.0a1"; |
| 907 | + let pants_toml_content = format!( |
| 908 | + r#" |
| 909 | + [GLOBAL] |
| 910 | + pants_version = "{pants_release}" |
| 911 | + "# |
| 912 | + ); |
| 913 | + let pants_toml = tmpdir.path().join("pants.toml"); |
| 914 | + write_file(&pants_toml, false, pants_toml_content).unwrap(); |
| 915 | + |
| 916 | + use std::os::unix::ffi::OsStringExt; |
| 917 | + env::set_var("FOO", OsString::from_vec(vec![b'B', 0xa5, b'R'])); |
| 918 | + |
| 919 | + let err = execute( |
| 920 | + Command::new(scie_pants_scie) |
| 921 | + .arg("-V") |
| 922 | + .env("RUST_LOG", "trace") |
| 923 | + .stderr(Stdio::piped()) |
| 924 | + .current_dir(&tmpdir), |
| 925 | + ) |
| 926 | + .unwrap_err(); |
| 927 | + let error_text = err.to_string(); |
| 928 | + // N.B.: This is a very hacky way to confirm the `scie-jump` is done processing env vars and has |
| 929 | + // exec'd the `scie-pants` native client; which then proceeds to choke on env vars in the same |
| 930 | + // way scie-jump <= 0.11.0 did using `env::vars()`. |
| 931 | + assert!(Regex::new(concat!( |
| 932 | + r#"exe: ".*/bindings/venvs/2\.17\.0a1/lib/python3\.9/"#, |
| 933 | + r#"site-packages/pants/bin/native_client""# |
| 934 | + )) |
| 935 | + .unwrap() |
| 936 | + .find(&error_text) |
| 937 | + .is_some()); |
| 938 | + assert!(error_text.contains("[DEBUG TimerFinished] jump::prepare_boot(), Elapsed=")); |
| 939 | + assert!(error_text |
| 940 | + .contains(r#"panicked at 'called `Result::unwrap()` on an `Err` value: "B\xA5R"'"#)); |
| 941 | + |
| 942 | + // The error path we test below requires flowing through the pantsd path via PyNailgunClient. |
| 943 | + let err = execute( |
| 944 | + Command::new(scie_pants_scie) |
| 945 | + .arg("--pantsd") |
| 946 | + .arg("-V") |
| 947 | + .env("PANTS_NO_NATIVE_CLIENT", "1") |
| 948 | + .stderr(Stdio::piped()) |
| 949 | + .current_dir(&tmpdir), |
| 950 | + ) |
| 951 | + .unwrap_err(); |
| 952 | + // Here we're asking the native client to exit very early before it processed `env::vars()`; so |
| 953 | + // the execution makes it into Python code that calls |
| 954 | + // `PyNailgunClient(...).execute(command, args, modified_env)`. That's Rust code implementing a |
| 955 | + // Python extension object that also wrongly assumes utf8 when converting env vars. |
| 956 | + assert!(err.to_string().contains(concat!( |
| 957 | + r#"UnicodeEncodeError: 'utf-8' codec can't encode character '\udca5' in "#, |
| 958 | + "position 1: surrogates not allowed" |
| 959 | + ))); |
| 960 | + |
| 961 | + let output = execute( |
| 962 | + Command::new(scie_pants_scie) |
| 963 | + .arg("--no-pantsd") |
| 964 | + .arg("-V") |
| 965 | + .env("PANTS_NO_NATIVE_CLIENT", "1") |
| 966 | + .stdout(Stdio::piped()) |
| 967 | + .current_dir(&tmpdir), |
| 968 | + ) |
| 969 | + .unwrap(); |
| 970 | + assert_eq!(pants_release, decode_output(output.stdout).unwrap().trim()); |
| 971 | + |
| 972 | + env::remove_var("FOO"); |
| 973 | +} |
0 commit comments