mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-27 05:23:24 +00:00
Merge #3136
3136: Not bash r=matklad a=matklad More declarative installation Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
commit
94323c8996
7 changed files with 203 additions and 163 deletions
2
editors/code/package-lock.json
generated
2
editors/code/package-lock.json
generated
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "rust-analyzer",
|
||||
"version": "0.1.0",
|
||||
"version": "0.2.0-dev",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
|
|
|
@ -5,7 +5,8 @@
|
|||
"preview": true,
|
||||
"private": true,
|
||||
"icon": "icon.png",
|
||||
"version": "0.1.0",
|
||||
"//": "The real version is in release.yaml, this one just needs to be bigger",
|
||||
"version": "0.2.0-dev",
|
||||
"publisher": "matklad",
|
||||
"repository": {
|
||||
"url": "https://github.com/rust-analyzer/rust-analyzer.git",
|
||||
|
|
|
@ -1,56 +0,0 @@
|
|||
use std::process::{Command, Output, Stdio};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
|
||||
use crate::project_root;
|
||||
|
||||
pub struct Cmd<'a> {
|
||||
pub unix: &'a str,
|
||||
pub windows: &'a str,
|
||||
pub work_dir: &'a str,
|
||||
}
|
||||
|
||||
impl Cmd<'_> {
|
||||
pub fn run(self) -> Result<()> {
|
||||
if cfg!(windows) {
|
||||
run(self.windows, self.work_dir)
|
||||
} else {
|
||||
run(self.unix, self.work_dir)
|
||||
}
|
||||
}
|
||||
pub fn run_with_output(self) -> Result<String> {
|
||||
if cfg!(windows) {
|
||||
run_with_output(self.windows, self.work_dir)
|
||||
} else {
|
||||
run_with_output(self.unix, self.work_dir)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(cmdline: &str, dir: &str) -> Result<()> {
|
||||
do_run(cmdline, dir, &mut |c| {
|
||||
c.stdout(Stdio::inherit());
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
pub fn run_with_output(cmdline: &str, dir: &str) -> Result<String> {
|
||||
let output = do_run(cmdline, dir, &mut |_| {})?;
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
let stdout = stdout.trim().to_string();
|
||||
Ok(stdout)
|
||||
}
|
||||
|
||||
fn do_run(cmdline: &str, dir: &str, f: &mut dyn FnMut(&mut Command)) -> Result<Output> {
|
||||
eprintln!("\nwill run: {}", cmdline);
|
||||
let proj_dir = project_root().join(dir);
|
||||
let mut args = cmdline.split_whitespace();
|
||||
let exec = args.next().unwrap();
|
||||
let mut cmd = Command::new(exec);
|
||||
f(cmd.args(args).current_dir(proj_dir).stderr(Stdio::inherit()));
|
||||
let output = cmd.output().with_context(|| format!("running `{}`", cmdline))?;
|
||||
if !output.status.success() {
|
||||
anyhow::bail!("`{}` exited with {}", cmdline, output.status);
|
||||
}
|
||||
Ok(output)
|
||||
}
|
|
@ -2,9 +2,9 @@
|
|||
|
||||
use std::{env, path::PathBuf, str};
|
||||
|
||||
use anyhow::{Context, Result};
|
||||
use anyhow::{bail, format_err, Context, Result};
|
||||
|
||||
use crate::cmd::{run, run_with_output, Cmd};
|
||||
use crate::not_bash::{ls, pushd, rm, run};
|
||||
|
||||
// Latest stable, feel free to send a PR if this lags behind.
|
||||
const REQUIRED_RUST_VERSION: u32 = 41;
|
||||
|
@ -55,7 +55,7 @@ fn fix_path_for_mac() -> Result<()> {
|
|||
const ROOT_DIR: &str = "";
|
||||
let home_dir = match env::var("HOME") {
|
||||
Ok(home) => home,
|
||||
Err(e) => anyhow::bail!("Failed getting HOME from environment with error: {}.", e),
|
||||
Err(e) => bail!("Failed getting HOME from environment with error: {}.", e),
|
||||
};
|
||||
|
||||
[ROOT_DIR, &home_dir]
|
||||
|
@ -69,7 +69,7 @@ fn fix_path_for_mac() -> Result<()> {
|
|||
if !vscode_path.is_empty() {
|
||||
let vars = match env::var_os("PATH") {
|
||||
Some(path) => path,
|
||||
None => anyhow::bail!("Could not get PATH variable from env."),
|
||||
None => bail!("Could not get PATH variable from env."),
|
||||
};
|
||||
|
||||
let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
|
||||
|
@ -82,84 +82,61 @@ fn fix_path_for_mac() -> Result<()> {
|
|||
}
|
||||
|
||||
fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
|
||||
let npm_version = Cmd {
|
||||
unix: r"npm --version",
|
||||
windows: r"cmd.exe /c npm --version",
|
||||
work_dir: "./editors/code",
|
||||
}
|
||||
.run();
|
||||
let _dir = pushd("./editors/code");
|
||||
|
||||
if npm_version.is_err() {
|
||||
eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin")
|
||||
}
|
||||
|
||||
Cmd { unix: r"npm install", windows: r"cmd.exe /c npm install", work_dir: "./editors/code" }
|
||||
.run()?;
|
||||
Cmd {
|
||||
unix: r"npm run package --scripts-prepend-node-path",
|
||||
windows: r"cmd.exe /c npm run package",
|
||||
work_dir: "./editors/code",
|
||||
}
|
||||
.run()?;
|
||||
|
||||
let code_binary = ["code", "code-insiders", "codium", "code-oss"].iter().find(|bin| {
|
||||
Cmd {
|
||||
unix: &format!("{} --version", bin),
|
||||
windows: &format!("cmd.exe /c {}.cmd --version", bin),
|
||||
work_dir: "./editors/code",
|
||||
}
|
||||
.run()
|
||||
.is_ok()
|
||||
});
|
||||
|
||||
let code_binary = match code_binary {
|
||||
Some(it) => it,
|
||||
None => anyhow::bail!("Can't execute `code --version`. Perhaps it is not in $PATH?"),
|
||||
let find_code = |f: fn(&str) -> bool| -> Result<&'static str> {
|
||||
["code", "code-insiders", "codium", "code-oss"]
|
||||
.iter()
|
||||
.copied()
|
||||
.find(|bin| f(bin))
|
||||
.ok_or_else(|| {
|
||||
format_err!("Can't execute `code --version`. Perhaps it is not in $PATH?")
|
||||
})
|
||||
};
|
||||
|
||||
Cmd {
|
||||
unix: &format!(r"{} --install-extension ./rust-analyzer-0.1.0.vsix --force", code_binary),
|
||||
windows: &format!(
|
||||
r"cmd.exe /c {}.cmd --install-extension ./rust-analyzer-0.1.0.vsix --force",
|
||||
code_binary
|
||||
),
|
||||
work_dir: "./editors/code",
|
||||
}
|
||||
.run()?;
|
||||
let installed_extensions;
|
||||
if cfg!(unix) {
|
||||
run!("npm --version").context("`npm` is required to build the VS Code plugin")?;
|
||||
run!("npm install")?;
|
||||
|
||||
let installed_extensions = Cmd {
|
||||
unix: &format!(r"{} --list-extensions", code_binary),
|
||||
windows: &format!(r"cmd.exe /c {}.cmd --list-extensions", code_binary),
|
||||
work_dir: ".",
|
||||
let vsix_pkg = {
|
||||
rm("*.vsix")?;
|
||||
run!("npm run package --scripts-prepend-node-path")?;
|
||||
ls("*.vsix")?.pop().unwrap()
|
||||
};
|
||||
|
||||
let code = find_code(|bin| run!("{} --version", bin).is_ok())?;
|
||||
run!("{} --install-extension {} --force", code, vsix_pkg.display())?;
|
||||
installed_extensions = run!("{} --list-extensions", code; echo = false)?;
|
||||
} else {
|
||||
run!("cmd.exe /c npm --version")
|
||||
.context("`npm` is required to build the VS Code plugin")?;
|
||||
run!("cmd.exe /c npm install")?;
|
||||
|
||||
let vsix_pkg = {
|
||||
rm("*.vsix")?;
|
||||
run!("cmd.exe /c npm run package")?;
|
||||
ls("*.vsix")?.pop().unwrap()
|
||||
};
|
||||
|
||||
let code = find_code(|bin| run!("cmd.exe /c {}.cmd --version", bin).is_ok())?;
|
||||
run!(r"cmd.exe /c {}.cmd --install-extension {} --force", code, vsix_pkg.display())?;
|
||||
installed_extensions = run!("cmd.exe /c {}.cmd --list-extensions", code; echo = false)?;
|
||||
}
|
||||
.run_with_output()?;
|
||||
|
||||
if !installed_extensions.contains("rust-analyzer") {
|
||||
anyhow::bail!(
|
||||
bail!(
|
||||
"Could not install the Visual Studio Code extension. \
|
||||
Please make sure you have at least NodeJS 10.x together with the latest version of VS Code installed and try again."
|
||||
);
|
||||
}
|
||||
|
||||
if installed_extensions.contains("ra-lsp") {
|
||||
Cmd {
|
||||
unix: &format!(r"{} --uninstall-extension matklad.ra-lsp", code_binary),
|
||||
windows: &format!(
|
||||
r"cmd.exe /c {}.cmd --uninstall-extension matklad.ra-lsp",
|
||||
code_binary
|
||||
),
|
||||
work_dir: "./editors/code",
|
||||
}
|
||||
.run()?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn install_server(opts: ServerOpt) -> Result<()> {
|
||||
let mut old_rust = false;
|
||||
if let Ok(stdout) = run_with_output("cargo --version", ".") {
|
||||
println!("{}", stdout);
|
||||
if let Ok(stdout) = run!("cargo --version") {
|
||||
if !check_version(&stdout, REQUIRED_RUST_VERSION) {
|
||||
old_rust = true;
|
||||
}
|
||||
|
@ -172,20 +149,17 @@ fn install_server(opts: ServerOpt) -> Result<()> {
|
|||
)
|
||||
}
|
||||
|
||||
let res = if opts.jemalloc {
|
||||
run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".")
|
||||
} else {
|
||||
run("cargo install --path crates/ra_lsp_server --locked --force", ".")
|
||||
};
|
||||
let jemalloc = if opts.jemalloc { "--features jemalloc" } else { "" };
|
||||
let res = run!("cargo install --path crates/ra_lsp_server --locked --force {}", jemalloc);
|
||||
|
||||
if res.is_err() && old_rust {
|
||||
eprintln!(
|
||||
"\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
|
||||
REQUIRED_RUST_VERSION,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
res
|
||||
res.map(drop)
|
||||
}
|
||||
|
||||
fn check_version(version_output: &str, min_minor_version: u32) -> bool {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! FIXME: write short doc here
|
||||
|
||||
mod cmd;
|
||||
pub mod not_bash;
|
||||
pub mod install;
|
||||
pub mod pre_commit;
|
||||
|
||||
|
@ -16,8 +16,8 @@ use std::{
|
|||
};
|
||||
|
||||
use crate::{
|
||||
cmd::{run, run_with_output},
|
||||
codegen::Mode,
|
||||
not_bash::{pushd, run},
|
||||
};
|
||||
|
||||
pub use anyhow::Result;
|
||||
|
@ -38,9 +38,9 @@ pub fn run_rustfmt(mode: Mode) -> Result<()> {
|
|||
ensure_rustfmt()?;
|
||||
|
||||
if mode == Mode::Verify {
|
||||
run(&format!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN), ".")?;
|
||||
run!("rustup run {} -- cargo fmt -- --check", TOOLCHAIN)?;
|
||||
} else {
|
||||
run(&format!("rustup run {} -- cargo fmt", TOOLCHAIN), ".")?;
|
||||
run!("rustup run {} -- cargo fmt", TOOLCHAIN)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
@ -70,8 +70,9 @@ fn ensure_rustfmt() -> Result<()> {
|
|||
Ok(status) if status.success() => return Ok(()),
|
||||
_ => (),
|
||||
};
|
||||
run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
|
||||
run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".")
|
||||
run!("rustup toolchain install {}", TOOLCHAIN)?;
|
||||
run!("rustup component add rustfmt --toolchain {}", TOOLCHAIN)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_clippy() -> Result<()> {
|
||||
|
@ -92,34 +93,31 @@ pub fn run_clippy() -> Result<()> {
|
|||
"clippy::nonminimal_bool",
|
||||
"clippy::redundant_pattern_matching",
|
||||
];
|
||||
run(
|
||||
&format!(
|
||||
"rustup run {} -- cargo clippy --all-features --all-targets -- -A {}",
|
||||
TOOLCHAIN,
|
||||
allowed_lints.join(" -A ")
|
||||
),
|
||||
".",
|
||||
run!(
|
||||
"rustup run {} -- cargo clippy --all-features --all-targets -- -A {}",
|
||||
TOOLCHAIN,
|
||||
allowed_lints.join(" -A ")
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn install_clippy() -> Result<()> {
|
||||
run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
|
||||
run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".")
|
||||
run!("rustup toolchain install {}", TOOLCHAIN)?;
|
||||
run!("rustup component add clippy --toolchain {}", TOOLCHAIN)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn run_fuzzer() -> Result<()> {
|
||||
match Command::new("cargo")
|
||||
.args(&["fuzz", "--help"])
|
||||
.stderr(Stdio::null())
|
||||
.stdout(Stdio::null())
|
||||
.status()
|
||||
{
|
||||
Ok(status) if status.success() => (),
|
||||
_ => run("cargo install cargo-fuzz", ".")?,
|
||||
let _d = pushd("./crates/ra_syntax");
|
||||
match run!("cargo fuzz --help") {
|
||||
Ok(_) => (),
|
||||
_ => {
|
||||
run!("cargo install cargo-fuzz")?;
|
||||
}
|
||||
};
|
||||
|
||||
run("rustup run nightly -- cargo fuzz run parser", "./crates/ra_syntax")
|
||||
run!("rustup run nightly -- cargo fuzz run parser")?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Cleans the `./target` dir after the build such that only
|
||||
|
@ -161,15 +159,15 @@ fn rm_rf(path: &Path) -> Result<()> {
|
|||
}
|
||||
|
||||
pub fn run_release() -> Result<()> {
|
||||
run("git switch release", ".")?;
|
||||
run("git fetch upstream", ".")?;
|
||||
run("git reset --hard upstream/master", ".")?;
|
||||
run("git push", ".")?;
|
||||
run!("git switch release")?;
|
||||
run!("git fetch upstream")?;
|
||||
run!("git reset --hard upstream/master")?;
|
||||
run!("git push")?;
|
||||
|
||||
let changelog_dir = project_root().join("../rust-analyzer.github.io/thisweek/_posts");
|
||||
|
||||
let today = run_with_output("date --iso", ".")?;
|
||||
let commit = run_with_output("git rev-parse HEAD", ".")?;
|
||||
let today = run!("date --iso")?;
|
||||
let commit = run!("git rev-parse HEAD")?;
|
||||
let changelog_n = fs::read_dir(changelog_dir.as_path())?.count();
|
||||
|
||||
let contents = format!(
|
||||
|
|
123
xtask/src/not_bash.rs
Normal file
123
xtask/src/not_bash.rs
Normal file
|
@ -0,0 +1,123 @@
|
|||
//! A bad shell -- small cross platform module for writing glue code
|
||||
use std::{
|
||||
cell::RefCell,
|
||||
env,
|
||||
ffi::OsStr,
|
||||
fs,
|
||||
path::PathBuf,
|
||||
process::{Command, Stdio},
|
||||
};
|
||||
|
||||
use anyhow::{bail, Context, Result};
|
||||
|
||||
macro_rules! _run {
|
||||
($($expr:expr),*) => {
|
||||
run!($($expr),*; echo = true)
|
||||
};
|
||||
($($expr:expr),* ; echo = $echo:expr) => {
|
||||
$crate::not_bash::run_process(format!($($expr),*), $echo)
|
||||
};
|
||||
}
|
||||
pub(crate) use _run as run;
|
||||
|
||||
pub struct Pushd {
|
||||
_p: (),
|
||||
}
|
||||
|
||||
pub fn pushd(path: impl Into<PathBuf>) -> Pushd {
|
||||
Env::with(|env| env.pushd(path.into()));
|
||||
Pushd { _p: () }
|
||||
}
|
||||
|
||||
impl Drop for Pushd {
|
||||
fn drop(&mut self) {
|
||||
Env::with(|env| env.popd())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rm(glob: &str) -> Result<()> {
|
||||
let cwd = Env::with(|env| env.cwd());
|
||||
ls(glob)?.into_iter().try_for_each(|it| fs::remove_file(cwd.join(it)))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn ls(glob: &str) -> Result<Vec<PathBuf>> {
|
||||
let cwd = Env::with(|env| env.cwd());
|
||||
let mut res = Vec::new();
|
||||
for entry in fs::read_dir(&cwd)? {
|
||||
let entry = entry?;
|
||||
if matches(&entry.file_name(), glob) {
|
||||
let path = entry.path();
|
||||
let path = path.strip_prefix(&cwd).unwrap();
|
||||
res.push(path.to_path_buf())
|
||||
}
|
||||
}
|
||||
return Ok(res);
|
||||
|
||||
fn matches(file_name: &OsStr, glob: &str) -> bool {
|
||||
assert!(glob.starts_with('*'));
|
||||
file_name.to_string_lossy().ends_with(&glob[1..])
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn run_process(cmd: String, echo: bool) -> Result<String> {
|
||||
run_process_inner(&cmd, echo).with_context(|| format!("process `{}` failed", cmd))
|
||||
}
|
||||
|
||||
fn run_process_inner(cmd: &str, echo: bool) -> Result<String> {
|
||||
let cwd = Env::with(|env| env.cwd());
|
||||
let mut args = shelx(cmd);
|
||||
let binary = args.remove(0);
|
||||
|
||||
if echo {
|
||||
println!("> {}", cmd)
|
||||
}
|
||||
|
||||
let output = Command::new(binary)
|
||||
.args(args)
|
||||
.current_dir(cwd)
|
||||
.stdin(Stdio::null())
|
||||
.stderr(Stdio::inherit())
|
||||
.output()?;
|
||||
let stdout = String::from_utf8(output.stdout)?;
|
||||
|
||||
if echo {
|
||||
print!("{}", stdout)
|
||||
}
|
||||
|
||||
if !output.status.success() {
|
||||
bail!("{}", output.status)
|
||||
}
|
||||
|
||||
Ok(stdout)
|
||||
}
|
||||
|
||||
// FIXME: some real shell lexing here
|
||||
fn shelx(cmd: &str) -> Vec<String> {
|
||||
cmd.split_whitespace().map(|it| it.to_string()).collect()
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Env {
|
||||
pushd_stack: Vec<PathBuf>,
|
||||
}
|
||||
|
||||
impl Env {
|
||||
fn with<F: FnOnce(&mut Env) -> T, T>(f: F) -> T {
|
||||
thread_local! {
|
||||
static ENV: RefCell<Env> = Default::default();
|
||||
}
|
||||
ENV.with(|it| f(&mut *it.borrow_mut()))
|
||||
}
|
||||
|
||||
fn pushd(&mut self, dir: PathBuf) {
|
||||
self.pushd_stack.push(dir)
|
||||
}
|
||||
fn popd(&mut self) {
|
||||
self.pushd_stack.pop().unwrap();
|
||||
}
|
||||
fn cwd(&self) -> PathBuf {
|
||||
self.pushd_stack.last().cloned().unwrap_or_else(|| env::current_dir().unwrap())
|
||||
}
|
||||
}
|
|
@ -4,18 +4,18 @@ use std::{fs, path::PathBuf};
|
|||
|
||||
use anyhow::{bail, Result};
|
||||
|
||||
use crate::{cmd::run_with_output, project_root, run, run_rustfmt, Mode};
|
||||
use crate::{not_bash::run, project_root, run_rustfmt, Mode};
|
||||
|
||||
// FIXME: if there are changed `.ts` files, also reformat TypeScript (by
|
||||
// shelling out to `npm fmt`).
|
||||
pub fn run_hook() -> Result<()> {
|
||||
run_rustfmt(Mode::Overwrite)?;
|
||||
|
||||
let diff = run_with_output("git diff --diff-filter=MAR --name-only --cached", ".")?;
|
||||
let diff = run!("git diff --diff-filter=MAR --name-only --cached")?;
|
||||
|
||||
let root = project_root();
|
||||
for line in diff.lines() {
|
||||
run(&format!("git update-index --add {}", root.join(line).to_string_lossy()), ".")?;
|
||||
run!("git update-index --add {}", root.join(line).display())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
Loading…
Reference in a new issue