Skip to content

Commit 5fa6fa7

Browse files
if0nedaamien
authored andcommitted
Decoding command output in Windows (pgcentralfoundation#2084)
Closes pgcentralfoundation#2069
1 parent 99d58ed commit 5fa6fa7

5 files changed

Lines changed: 76 additions & 18 deletions

File tree

Cargo.lock

Lines changed: 22 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

README.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -99,17 +99,17 @@ without considerable ongoing technical and financial contributions.
9999

100100
Running PGRX on a Mac requires some additional setup.
101101

102-
The Mac C compiler (clang) and related tools are bundled with [XCode](https://developer.apple.com/xcode/).
102+
The Mac C compiler (clang) and related tools are bundled with [XCode](https://developer.apple.com/xcode/).
103103
XCode can be installed from the Mac App Store.
104104

105-
For additional C libraries, it's easiest to use [Homebrew](https://brew.sh/). In particular,
105+
For additional C libraries, it's easiest to use [Homebrew](https://brew.sh/). In particular,
106106
you will probably need these if you don't have them already:
107107

108108
```zsh
109109
brew install git icu4c pkg-config
110110
```
111-
The config script that Postgres 17 uses in its build process does not automatically detect
112-
the Homebrew install directory. (Earlier versions of Postgres do not have this problem.)
111+
The config script that Postgres 17 uses in its build process does not automatically detect
112+
the Homebrew install directory. (Earlier versions of Postgres do not have this problem.)
113113
You may see this error:
114114

115115
```configure: error: ICU library not found```
@@ -163,7 +163,7 @@ cd my_extension
163163
This will create a new directory for the extension crate.
164164

165165
```
166-
$ tree
166+
$ tree
167167
.
168168
├── Cargo.toml
169169
├── my_extension.control
@@ -324,9 +324,9 @@ but rather extend additional support for other kinds of Rust code. These are not
324324
### "unsafe-postgres": Allow compilation for Postgres forks that have a different ABI
325325

326326
As of Postgres 15, forks are allowed to specify they use a different ABI than canonical Postgres.
327-
Since pgrx makes countless assumptions about Postgres' internal ABI it is not possible for it to
327+
Since pgrx makes countless assumptions about Postgres' internal ABI it is not possible for it to
328328
guarantee that a compiled pgrx extension will probably execute within such a Postgres fork. You,
329-
dear compiler runner, can make this guarantee for yourself by specifying the `unsafe-postgres`
329+
dear compiler runner, can make this guarantee for yourself by specifying the `unsafe-postgres`
330330
feature flag. Otherwise, a pgrx extension will fail to compile with an error similar to:
331331

332332
```
@@ -372,7 +372,7 @@ This approach can also be used in extensions to ensure a matching version of `ca
372372
## License
373373

374374
```
375-
Portions Copyright 2019-2021 ZomboDB, LLC.
375+
Portions Copyright 2019-2021 ZomboDB, LLC.
376376
Portions Copyright 2021-2023 Technology Concepts & Design, Inc.
377377
Portions Copyright 2023 PgCentral Foundation, Inc.
378378

pgrx-pg-config/Cargo.toml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#LICENSE All rights reserved.
88
#LICENSE
99
#LICENSE Use of this source code is governed by the MIT license that can be found in the LICENSE file.
10-
10+
1111
[package]
1212
name = "pgrx-pg-config"
1313
version = "0.14.3"
@@ -34,3 +34,8 @@ url.workspace = true
3434

3535
home = "0.5.11"
3636
pathsearch = "0.2.0"
37+
38+
[target.'cfg(target_os = "windows")'.dependencies]
39+
codepage = "0.1.2"
40+
encoding_rs = "0.8.35"
41+
winapi = { version = "0.3.9", features = ["winnls"] }

pgrx-pg-config/src/decoding.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use std::borrow::Cow;
2+
3+
#[cfg(target_os = "windows")]
4+
pub fn decode_from_bytes(output: &[u8]) -> Cow<'_, str> {
5+
use encoding_rs::Encoding;
6+
use std::sync::LazyLock;
7+
8+
fn get_encoding() -> &'static Encoding {
9+
let acp = unsafe { winapi::um::winnls::GetACP() };
10+
11+
codepage::to_encoding(acp as u16).unwrap_or(encoding_rs::UTF_8)
12+
}
13+
14+
static ENCODING: LazyLock<&'static Encoding> = LazyLock::new(get_encoding);
15+
16+
let (decoded, _, had_errors) = ENCODING.decode(output);
17+
18+
if had_errors {
19+
String::from_utf8_lossy(output)
20+
} else {
21+
decoded
22+
}
23+
}
24+
25+
#[cfg(not(target_os = "windows"))]
26+
pub fn decode_from_bytes(output: &[u8]) -> Cow<'_, str> {
27+
String::from_utf8_lossy(&output)
28+
}

pgrx-pg-config/src/lib.rs

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ use std::str::FromStr;
2222
use thiserror::Error;
2323
use url::Url;
2424

25+
mod decoding;
26+
2527
pub mod cargo;
2628

2729
pub static BASE_POSTGRES_PORT_NO: u16 = 28800;
@@ -61,6 +63,8 @@ pub fn get_c_locale_flags() -> &'static [&'static str] {
6163
mod path_methods;
6264
pub use path_methods::{get_target_dir, prefix_path};
6365

66+
use crate::decoding::decode_from_bytes;
67+
6468
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
6569
pub enum PgMinorVersion {
6670
Latest,
@@ -470,7 +474,7 @@ impl PgConfig {
470474
});
471475

472476
match Command::new(&pg_config).arg(arg).output() {
473-
Ok(output) => Ok(String::from_utf8(output.stdout).unwrap().trim().to_string()),
477+
Ok(output) => Ok(decode_from_bytes(&output.stdout).trim().to_string()),
474478
Err(e) => match e.kind() {
475479
ErrorKind::NotFound => Err(e).wrap_err_with(|| {
476480
let pg_config_str = pg_config.display().to_string();
@@ -777,8 +781,8 @@ pub fn createdb(
777781
return Err(eyre!(
778782
"problem running createdb: {}\n\n{}{}",
779783
command_str,
780-
String::from_utf8(output.stdout).unwrap(),
781-
String::from_utf8(output.stderr).unwrap()
784+
decode_from_bytes(&output.stdout),
785+
decode_from_bytes(&output.stderr)
782786
));
783787
}
784788

@@ -837,8 +841,8 @@ pub fn dropdb(
837841
return Err(eyre!(
838842
"problem running dropdb: {}\n\n{}{}",
839843
command_str,
840-
String::from_utf8(output.stdout).unwrap(),
841-
String::from_utf8(output.stderr).unwrap()
844+
decode_from_bytes(&output.stdout),
845+
decode_from_bytes(&output.stderr)
842846
));
843847
}
844848

@@ -871,11 +875,11 @@ fn does_db_exist(pg_config: &PgConfig, dbname: &str) -> eyre::Result<bool> {
871875
"problem checking if database '{}' exists: {}\n\n{}{}",
872876
dbname,
873877
command_str,
874-
String::from_utf8(output.stdout).unwrap(),
875-
String::from_utf8(output.stderr).unwrap()
878+
decode_from_bytes(&output.stdout),
879+
decode_from_bytes(&output.stderr)
876880
))
877881
} else {
878-
let count = i32::from_str(String::from_utf8(output.stdout).unwrap().trim())
882+
let count = i32::from_str(decode_from_bytes(&output.stdout).trim())
879883
.wrap_err("result is not a number")?;
880884
Ok(count > 0)
881885
}

0 commit comments

Comments
 (0)