diff options
Diffstat (limited to 'xtask')
-rw-r--r-- | xtask/src/ast_src.rs | 21 | ||||
-rw-r--r-- | xtask/src/codegen/gen_syntax.rs | 1 | ||||
-rw-r--r-- | xtask/src/dist.rs | 8 | ||||
-rw-r--r-- | xtask/src/lib.rs | 89 | ||||
-rw-r--r-- | xtask/src/not_bash.rs | 60 |
5 files changed, 97 insertions, 82 deletions
diff --git a/xtask/src/ast_src.rs b/xtask/src/ast_src.rs index 9c02f7c6f..028f7cbe1 100644 --- a/xtask/src/ast_src.rs +++ b/xtask/src/ast_src.rs | |||
@@ -162,7 +162,7 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
162 | "RECORD_LIT", | 162 | "RECORD_LIT", |
163 | "RECORD_FIELD_LIST", | 163 | "RECORD_FIELD_LIST", |
164 | "RECORD_FIELD", | 164 | "RECORD_FIELD", |
165 | "TRY_BLOCK_EXPR", | 165 | "EFFECT_EXPR", |
166 | "BOX_EXPR", | 166 | "BOX_EXPR", |
167 | // postfix | 167 | // postfix |
168 | "CALL_EXPR", | 168 | "CALL_EXPR", |
@@ -177,7 +177,6 @@ pub(crate) const KINDS_SRC: KindsSrc = KindsSrc { | |||
177 | "PREFIX_EXPR", | 177 | "PREFIX_EXPR", |
178 | "RANGE_EXPR", // just weird | 178 | "RANGE_EXPR", // just weird |
179 | "BIN_EXPR", | 179 | "BIN_EXPR", |
180 | "BLOCK", | ||
181 | "EXTERN_BLOCK", | 180 | "EXTERN_BLOCK", |
182 | "EXTERN_ITEM_LIST", | 181 | "EXTERN_ITEM_LIST", |
183 | "ENUM_VARIANT", | 182 | "ENUM_VARIANT", |
@@ -440,7 +439,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { | |||
440 | } | 439 | } |
441 | struct IfExpr: AttrsOwner { T![if], Condition } | 440 | struct IfExpr: AttrsOwner { T![if], Condition } |
442 | struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] } | 441 | struct LoopExpr: AttrsOwner, LoopBodyOwner { T![loop] } |
443 | struct TryBlockExpr: AttrsOwner { T![try], body: BlockExpr } | 442 | struct EffectExpr: AttrsOwner { Label, T![try], T![unsafe], T![async], BlockExpr } |
444 | struct ForExpr: AttrsOwner, LoopBodyOwner { | 443 | struct ForExpr: AttrsOwner, LoopBodyOwner { |
445 | T![for], | 444 | T![for], |
446 | Pat, | 445 | Pat, |
@@ -451,7 +450,9 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { | |||
451 | struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] } | 450 | struct ContinueExpr: AttrsOwner { T![continue], T![lifetime] } |
452 | struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr } | 451 | struct BreakExpr: AttrsOwner { T![break], T![lifetime], Expr } |
453 | struct Label { T![lifetime] } | 452 | struct Label { T![lifetime] } |
454 | struct BlockExpr: AttrsOwner { Label, T![unsafe], Block } | 453 | struct BlockExpr: AttrsOwner, ModuleItemOwner { |
454 | T!['{'], statements: [Stmt], Expr, T!['}'], | ||
455 | } | ||
455 | struct ReturnExpr: AttrsOwner { Expr } | 456 | struct ReturnExpr: AttrsOwner { Expr } |
456 | struct CallExpr: ArgListOwner { Expr } | 457 | struct CallExpr: ArgListOwner { Expr } |
457 | struct MethodCallExpr: AttrsOwner, ArgListOwner { | 458 | struct MethodCallExpr: AttrsOwner, ArgListOwner { |
@@ -460,7 +461,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { | |||
460 | struct IndexExpr: AttrsOwner { T!['['], T![']'] } | 461 | struct IndexExpr: AttrsOwner { T!['['], T![']'] } |
461 | struct FieldExpr: AttrsOwner { Expr, T![.], NameRef } | 462 | struct FieldExpr: AttrsOwner { Expr, T![.], NameRef } |
462 | struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] } | 463 | struct AwaitExpr: AttrsOwner { Expr, T![.], T![await] } |
463 | struct TryExpr: AttrsOwner { T![try], Expr } | 464 | struct TryExpr: AttrsOwner { Expr, T![?] } |
464 | struct CastExpr: AttrsOwner { Expr, T![as], TypeRef } | 465 | struct CastExpr: AttrsOwner { Expr, T![as], TypeRef } |
465 | struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], Expr } | 466 | struct RefExpr: AttrsOwner { T![&], T![raw], T![mut], Expr } |
466 | struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr } | 467 | struct PrefixExpr: AttrsOwner { /*PrefixOp,*/ Expr } |
@@ -556,12 +557,6 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { | |||
556 | T![;], | 557 | T![;], |
557 | } | 558 | } |
558 | struct Condition { T![let], Pat, T![=], Expr } | 559 | struct Condition { T![let], Pat, T![=], Expr } |
559 | struct Block: AttrsOwner, ModuleItemOwner { | ||
560 | T!['{'], | ||
561 | statements: [Stmt], | ||
562 | Expr, | ||
563 | T!['}'], | ||
564 | } | ||
565 | struct ParamList { | 560 | struct ParamList { |
566 | T!['('], | 561 | T!['('], |
567 | SelfParam, | 562 | SelfParam, |
@@ -595,7 +590,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { | |||
595 | qualifier: Path, | 590 | qualifier: Path, |
596 | } | 591 | } |
597 | struct PathSegment { | 592 | struct PathSegment { |
598 | T![::], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>] | 593 | T![::], T![crate], T![self], T![super], T![<], NameRef, TypeArgList, ParamList, RetType, PathType, T![>] |
599 | } | 594 | } |
600 | struct TypeArgList { | 595 | struct TypeArgList { |
601 | T![::], | 596 | T![::], |
@@ -722,7 +717,7 @@ pub(crate) const AST_SRC: AstSrc = AstSrc { | |||
722 | FieldExpr, | 717 | FieldExpr, |
723 | AwaitExpr, | 718 | AwaitExpr, |
724 | TryExpr, | 719 | TryExpr, |
725 | TryBlockExpr, | 720 | EffectExpr, |
726 | CastExpr, | 721 | CastExpr, |
727 | RefExpr, | 722 | RefExpr, |
728 | PrefixExpr, | 723 | PrefixExpr, |
diff --git a/xtask/src/codegen/gen_syntax.rs b/xtask/src/codegen/gen_syntax.rs index e9dc09552..8028575c5 100644 --- a/xtask/src/codegen/gen_syntax.rs +++ b/xtask/src/codegen/gen_syntax.rs | |||
@@ -432,6 +432,7 @@ impl Field<'_> { | |||
432 | ":" => "colon", | 432 | ":" => "colon", |
433 | "::" => "coloncolon", | 433 | "::" => "coloncolon", |
434 | "#" => "pound", | 434 | "#" => "pound", |
435 | "?" => "question_mark", | ||
435 | _ => name, | 436 | _ => name, |
436 | }; | 437 | }; |
437 | format_ident!("{}_token", name) | 438 | format_ident!("{}_token", name) |
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs index a56eeef8d..aef68089e 100644 --- a/xtask/src/dist.rs +++ b/xtask/src/dist.rs | |||
@@ -50,21 +50,19 @@ fn dist_server(nightly: bool) -> Result<()> { | |||
50 | if cfg!(target_os = "linux") { | 50 | if cfg!(target_os = "linux") { |
51 | std::env::set_var("CC", "clang"); | 51 | std::env::set_var("CC", "clang"); |
52 | run!( | 52 | run!( |
53 | "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release | 53 | "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release" |
54 | --target x86_64-unknown-linux-musl | ||
55 | " | ||
56 | // We'd want to add, but that requires setting the right linker somehow | 54 | // We'd want to add, but that requires setting the right linker somehow |
57 | // --features=jemalloc | 55 | // --features=jemalloc |
58 | )?; | 56 | )?; |
59 | if !nightly { | 57 | if !nightly { |
60 | run!("strip ./target/x86_64-unknown-linux-musl/release/rust-analyzer")?; | 58 | run!("strip ./target/release/rust-analyzer")?; |
61 | } | 59 | } |
62 | } else { | 60 | } else { |
63 | run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; | 61 | run!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --release")?; |
64 | } | 62 | } |
65 | 63 | ||
66 | let (src, dst) = if cfg!(target_os = "linux") { | 64 | let (src, dst) = if cfg!(target_os = "linux") { |
67 | ("./target/x86_64-unknown-linux-musl/release/rust-analyzer", "./dist/rust-analyzer-linux") | 65 | ("./target/release/rust-analyzer", "./dist/rust-analyzer-linux") |
68 | } else if cfg!(target_os = "windows") { | 66 | } else if cfg!(target_os = "windows") { |
69 | ("./target/release/rust-analyzer.exe", "./dist/rust-analyzer-windows.exe") | 67 | ("./target/release/rust-analyzer.exe", "./dist/rust-analyzer-windows.exe") |
70 | } else if cfg!(target_os = "macos") { | 68 | } else if cfg!(target_os = "macos") { |
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs index ec824a518..2b7a461e5 100644 --- a/xtask/src/lib.rs +++ b/xtask/src/lib.rs | |||
@@ -10,23 +10,19 @@ pub mod pre_commit; | |||
10 | pub mod codegen; | 10 | pub mod codegen; |
11 | mod ast_src; | 11 | mod ast_src; |
12 | 12 | ||
13 | use anyhow::Context; | ||
14 | use std::{ | 13 | use std::{ |
15 | env, | 14 | env, |
16 | io::Write, | ||
17 | path::{Path, PathBuf}, | 15 | path::{Path, PathBuf}, |
18 | process::{Command, Stdio}, | ||
19 | }; | 16 | }; |
17 | |||
20 | use walkdir::{DirEntry, WalkDir}; | 18 | use walkdir::{DirEntry, WalkDir}; |
21 | 19 | ||
22 | use crate::{ | 20 | use crate::{ |
23 | codegen::Mode, | 21 | codegen::Mode, |
24 | not_bash::{date_iso, fs2, pushd, rm_rf, run}, | 22 | not_bash::{date_iso, fs2, pushd, pushenv, rm_rf, run}, |
25 | }; | 23 | }; |
26 | 24 | ||
27 | pub use anyhow::Result; | 25 | pub use anyhow::{bail, Context as _, Result}; |
28 | |||
29 | const TOOLCHAIN: &str = "stable"; | ||
30 | 26 | ||
31 | pub fn project_root() -> PathBuf { | 27 | pub fn project_root() -> PathBuf { |
32 | Path::new( | 28 | Path::new( |
@@ -55,54 +51,44 @@ pub fn rust_files(path: &Path) -> impl Iterator<Item = PathBuf> { | |||
55 | 51 | ||
56 | pub fn run_rustfmt(mode: Mode) -> Result<()> { | 52 | pub fn run_rustfmt(mode: Mode) -> Result<()> { |
57 | let _dir = pushd(project_root()); | 53 | let _dir = pushd(project_root()); |
54 | let _e = pushenv("RUSTUP_TOOLCHAIN", "stable"); | ||
58 | ensure_rustfmt()?; | 55 | ensure_rustfmt()?; |
59 | 56 | match mode { | |
60 | let check = if mode == Mode::Verify { "--check" } else { "" }; | 57 | Mode::Overwrite => run!("cargo fmt"), |
61 | run!("rustup run {} -- cargo fmt -- {}", TOOLCHAIN, check)?; | 58 | Mode::Verify => run!("cargo fmt -- --check"), |
59 | }?; | ||
62 | Ok(()) | 60 | Ok(()) |
63 | } | 61 | } |
64 | 62 | ||
65 | fn reformat(text: impl std::fmt::Display) -> Result<String> { | 63 | fn reformat(text: impl std::fmt::Display) -> Result<String> { |
64 | let _e = pushenv("RUSTUP_TOOLCHAIN", "stable"); | ||
66 | ensure_rustfmt()?; | 65 | ensure_rustfmt()?; |
67 | let mut rustfmt = Command::new("rustup") | 66 | let stdout = run!( |
68 | .args(&["run", TOOLCHAIN, "--", "rustfmt", "--config-path"]) | 67 | "rustfmt --config-path {} --config fn_single_line=true", project_root().join("rustfmt.toml").display(); |
69 | .arg(project_root().join("rustfmt.toml")) | 68 | <text.to_string().as_bytes() |
70 | .args(&["--config", "fn_single_line=true"]) | 69 | )?; |
71 | .stdin(Stdio::piped()) | ||
72 | .stdout(Stdio::piped()) | ||
73 | .spawn()?; | ||
74 | write!(rustfmt.stdin.take().unwrap(), "{}", text)?; | ||
75 | let output = rustfmt.wait_with_output()?; | ||
76 | let stdout = String::from_utf8(output.stdout)?; | ||
77 | let preamble = "Generated file, do not edit by hand, see `xtask/src/codegen`"; | 70 | let preamble = "Generated file, do not edit by hand, see `xtask/src/codegen`"; |
78 | Ok(format!("//! {}\n\n{}", preamble, stdout)) | 71 | Ok(format!("//! {}\n\n{}\n", preamble, stdout)) |
79 | } | 72 | } |
80 | 73 | ||
81 | fn ensure_rustfmt() -> Result<()> { | 74 | fn ensure_rustfmt() -> Result<()> { |
82 | match Command::new("rustup") | 75 | let out = run!("rustfmt --version")?; |
83 | .args(&["run", TOOLCHAIN, "--", "cargo", "fmt", "--version"]) | 76 | if !out.contains("stable") { |
84 | .stderr(Stdio::null()) | 77 | bail!( |
85 | .stdout(Stdio::null()) | 78 | "Failed to run rustfmt from toolchain 'stable'. \ |
86 | .status() | 79 | Please run `rustup component add rustfmt --toolchain stable` to install it.", |
87 | { | 80 | ) |
88 | Ok(status) if status.success() => return Ok(()), | 81 | } |
89 | _ => (), | ||
90 | }; | ||
91 | run!("rustup toolchain install {}", TOOLCHAIN)?; | ||
92 | run!("rustup component add rustfmt --toolchain {}", TOOLCHAIN)?; | ||
93 | Ok(()) | 82 | Ok(()) |
94 | } | 83 | } |
95 | 84 | ||
96 | pub fn run_clippy() -> Result<()> { | 85 | pub fn run_clippy() -> Result<()> { |
97 | match Command::new("rustup") | 86 | if run!("cargo clippy --version").is_err() { |
98 | .args(&["run", TOOLCHAIN, "--", "cargo", "clippy", "--version"]) | 87 | bail!( |
99 | .stderr(Stdio::null()) | 88 | "Failed run cargo clippy. \ |
100 | .stdout(Stdio::null()) | 89 | Please run `rustup component add clippy` to install it.", |
101 | .status() | 90 | ) |
102 | { | 91 | } |
103 | Ok(status) if status.success() => (), | ||
104 | _ => install_clippy().context("install clippy")?, | ||
105 | }; | ||
106 | 92 | ||
107 | let allowed_lints = [ | 93 | let allowed_lints = [ |
108 | "clippy::collapsible_if", | 94 | "clippy::collapsible_if", |
@@ -110,27 +96,24 @@ pub fn run_clippy() -> Result<()> { | |||
110 | "clippy::nonminimal_bool", | 96 | "clippy::nonminimal_bool", |
111 | "clippy::redundant_pattern_matching", | 97 | "clippy::redundant_pattern_matching", |
112 | ]; | 98 | ]; |
113 | run!( | 99 | run!("cargo clippy --all-features --all-targets -- -A {}", allowed_lints.join(" -A "))?; |
114 | "rustup run {} -- cargo clippy --all-features --all-targets -- -A {}", | ||
115 | TOOLCHAIN, | ||
116 | allowed_lints.join(" -A ") | ||
117 | )?; | ||
118 | Ok(()) | ||
119 | } | ||
120 | |||
121 | fn install_clippy() -> Result<()> { | ||
122 | run!("rustup toolchain install {}", TOOLCHAIN)?; | ||
123 | run!("rustup component add clippy --toolchain {}", TOOLCHAIN)?; | ||
124 | Ok(()) | 100 | Ok(()) |
125 | } | 101 | } |
126 | 102 | ||
127 | pub fn run_fuzzer() -> Result<()> { | 103 | pub fn run_fuzzer() -> Result<()> { |
128 | let _d = pushd("./crates/ra_syntax"); | 104 | let _d = pushd("./crates/ra_syntax"); |
105 | let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly"); | ||
129 | if run!("cargo fuzz --help").is_err() { | 106 | if run!("cargo fuzz --help").is_err() { |
130 | run!("cargo install cargo-fuzz")?; | 107 | run!("cargo install cargo-fuzz")?; |
131 | }; | 108 | }; |
132 | 109 | ||
133 | run!("rustup run nightly -- cargo fuzz run parser")?; | 110 | // Expecting nightly rustc |
111 | let out = run!("rustc --version")?; | ||
112 | if !out.contains("nightly") { | ||
113 | bail!("fuzz tests require nightly rustc") | ||
114 | } | ||
115 | |||
116 | run!("cargo fuzz run parser")?; | ||
134 | Ok(()) | 117 | Ok(()) |
135 | } | 118 | } |
136 | 119 | ||
diff --git a/xtask/src/not_bash.rs b/xtask/src/not_bash.rs index ef1699934..a6431e586 100644 --- a/xtask/src/not_bash.rs +++ b/xtask/src/not_bash.rs | |||
@@ -3,6 +3,8 @@ | |||
3 | use std::{ | 3 | use std::{ |
4 | cell::RefCell, | 4 | cell::RefCell, |
5 | env, | 5 | env, |
6 | ffi::OsString, | ||
7 | io::Write, | ||
6 | path::{Path, PathBuf}, | 8 | path::{Path, PathBuf}, |
7 | process::{Command, Stdio}, | 9 | process::{Command, Stdio}, |
8 | }; | 10 | }; |
@@ -57,7 +59,10 @@ macro_rules! _run { | |||
57 | run!($($expr),*; echo = true) | 59 | run!($($expr),*; echo = true) |
58 | }; | 60 | }; |
59 | ($($expr:expr),* ; echo = $echo:expr) => { | 61 | ($($expr:expr),* ; echo = $echo:expr) => { |
60 | $crate::not_bash::run_process(format!($($expr),*), $echo) | 62 | $crate::not_bash::run_process(format!($($expr),*), $echo, None) |
63 | }; | ||
64 | ($($expr:expr),* ; <$stdin:expr) => { | ||
65 | $crate::not_bash::run_process(format!($($expr),*), false, Some($stdin)) | ||
61 | }; | 66 | }; |
62 | } | 67 | } |
63 | pub(crate) use _run as run; | 68 | pub(crate) use _run as run; |
@@ -77,6 +82,21 @@ impl Drop for Pushd { | |||
77 | } | 82 | } |
78 | } | 83 | } |
79 | 84 | ||
85 | pub struct Pushenv { | ||
86 | _p: (), | ||
87 | } | ||
88 | |||
89 | pub fn pushenv(var: &str, value: &str) -> Pushenv { | ||
90 | Env::with(|env| env.pushenv(var.into(), value.into())); | ||
91 | Pushenv { _p: () } | ||
92 | } | ||
93 | |||
94 | impl Drop for Pushenv { | ||
95 | fn drop(&mut self) { | ||
96 | Env::with(|env| env.popenv()) | ||
97 | } | ||
98 | } | ||
99 | |||
80 | pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> { | 100 | pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> { |
81 | let path = path.as_ref(); | 101 | let path = path.as_ref(); |
82 | if !path.exists() { | 102 | if !path.exists() { |
@@ -90,15 +110,15 @@ pub fn rm_rf(path: impl AsRef<Path>) -> Result<()> { | |||
90 | } | 110 | } |
91 | 111 | ||
92 | #[doc(hidden)] | 112 | #[doc(hidden)] |
93 | pub fn run_process(cmd: String, echo: bool) -> Result<String> { | 113 | pub fn run_process(cmd: String, echo: bool, stdin: Option<&[u8]>) -> Result<String> { |
94 | run_process_inner(&cmd, echo).with_context(|| format!("process `{}` failed", cmd)) | 114 | run_process_inner(&cmd, echo, stdin).with_context(|| format!("process `{}` failed", cmd)) |
95 | } | 115 | } |
96 | 116 | ||
97 | pub fn date_iso() -> Result<String> { | 117 | pub fn date_iso() -> Result<String> { |
98 | run!("date --iso --utc") | 118 | run!("date --iso --utc") |
99 | } | 119 | } |
100 | 120 | ||
101 | fn run_process_inner(cmd: &str, echo: bool) -> Result<String> { | 121 | fn run_process_inner(cmd: &str, echo: bool, stdin: Option<&[u8]>) -> Result<String> { |
102 | let mut args = shelx(cmd); | 122 | let mut args = shelx(cmd); |
103 | let binary = args.remove(0); | 123 | let binary = args.remove(0); |
104 | let current_dir = Env::with(|it| it.cwd().to_path_buf()); | 124 | let current_dir = Env::with(|it| it.cwd().to_path_buf()); |
@@ -107,12 +127,17 @@ fn run_process_inner(cmd: &str, echo: bool) -> Result<String> { | |||
107 | println!("> {}", cmd) | 127 | println!("> {}", cmd) |
108 | } | 128 | } |
109 | 129 | ||
110 | let output = Command::new(binary) | 130 | let mut command = Command::new(binary); |
111 | .args(args) | 131 | command.args(args).current_dir(current_dir).stderr(Stdio::inherit()); |
112 | .current_dir(current_dir) | 132 | let output = match stdin { |
113 | .stdin(Stdio::null()) | 133 | None => command.stdin(Stdio::null()).output(), |
114 | .stderr(Stdio::inherit()) | 134 | Some(stdin) => { |
115 | .output()?; | 135 | command.stdin(Stdio::piped()).stdout(Stdio::piped()); |
136 | let mut process = command.spawn()?; | ||
137 | process.stdin.take().unwrap().write_all(stdin)?; | ||
138 | process.wait_with_output() | ||
139 | } | ||
140 | }?; | ||
116 | let stdout = String::from_utf8(output.stdout)?; | 141 | let stdout = String::from_utf8(output.stdout)?; |
117 | 142 | ||
118 | if echo { | 143 | if echo { |
@@ -133,13 +158,15 @@ fn shelx(cmd: &str) -> Vec<String> { | |||
133 | 158 | ||
134 | struct Env { | 159 | struct Env { |
135 | pushd_stack: Vec<PathBuf>, | 160 | pushd_stack: Vec<PathBuf>, |
161 | pushenv_stack: Vec<(OsString, Option<OsString>)>, | ||
136 | } | 162 | } |
137 | 163 | ||
138 | impl Env { | 164 | impl Env { |
139 | fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T { | 165 | fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T { |
140 | thread_local! { | 166 | thread_local! { |
141 | static ENV: RefCell<Env> = RefCell::new(Env { | 167 | static ENV: RefCell<Env> = RefCell::new(Env { |
142 | pushd_stack: vec![env::current_dir().unwrap()] | 168 | pushd_stack: vec![env::current_dir().unwrap()], |
169 | pushenv_stack: vec![], | ||
143 | }); | 170 | }); |
144 | } | 171 | } |
145 | ENV.with(|it| f(&mut *it.borrow_mut())) | 172 | ENV.with(|it| f(&mut *it.borrow_mut())) |
@@ -154,6 +181,17 @@ impl Env { | |||
154 | self.pushd_stack.pop().unwrap(); | 181 | self.pushd_stack.pop().unwrap(); |
155 | env::set_current_dir(self.cwd()).unwrap(); | 182 | env::set_current_dir(self.cwd()).unwrap(); |
156 | } | 183 | } |
184 | fn pushenv(&mut self, var: OsString, value: OsString) { | ||
185 | self.pushenv_stack.push((var.clone(), env::var_os(&var))); | ||
186 | env::set_var(var, value) | ||
187 | } | ||
188 | fn popenv(&mut self) { | ||
189 | let (var, value) = self.pushenv_stack.pop().unwrap(); | ||
190 | match value { | ||
191 | None => env::remove_var(var), | ||
192 | Some(value) => env::set_var(var, value), | ||
193 | } | ||
194 | } | ||
157 | fn cwd(&self) -> &Path { | 195 | fn cwd(&self) -> &Path { |
158 | self.pushd_stack.last().unwrap() | 196 | self.pushd_stack.last().unwrap() |
159 | } | 197 | } |