Verify that the PATH has been set up correctly

When creating copies with yabridgectl. This should at least give an
advance warning that some additional steps are required when first
setting up yabridge.
This commit is contained in:
Robbert van der Helm
2020-07-16 16:56:27 +02:00
parent 2ec53c78d9
commit 836aefcfbb
7 changed files with 134 additions and 4 deletions
+1 -1
View File
@@ -422,7 +422,7 @@ intptr_t PluginBridge::dispatch(AEffect* /*plugin*/,
logger.log_event(true, opcode, index, value, nullptr, option, logger.log_event(true, opcode, index, value, nullptr, option,
std::nullopt); std::nullopt);
logger.log( logger.log(
" WARNING: The host has dispatched an event before the plugin " " Warning: The host has dispatched an event before the plugin "
"has finished initializing, ignoring the event. (are we running " "has finished initializing, ignoring the event. (are we running "
"Ardour 5.X?)"); "Ardour 5.X?)");
logger.log_event_response(true, opcode, 0, nullptr, std::nullopt); logger.log_event_response(true, opcode, 0, nullptr, std::nullopt);
+1
View File
@@ -679,6 +679,7 @@ dependencies = [
"rayon", "rayon",
"serde", "serde",
"serde_derive", "serde_derive",
"textwrap",
"toml", "toml",
"walkdir", "walkdir",
"xdg", "xdg",
+1
View File
@@ -19,6 +19,7 @@ promptly = "0.3.0"
rayon = "1.3.1" rayon = "1.3.1"
serde = "1.0.114" serde = "1.0.114"
serde_derive = "1.0.114" serde_derive = "1.0.114"
textwrap = "*"
toml = "0.5.6" toml = "0.5.6"
walkdir = "2.3.1" walkdir = "2.3.1"
xdg = "2.2.0" xdg = "2.2.0"
+23 -1
View File
@@ -26,6 +26,7 @@ use std::path::{Path, PathBuf};
use crate::config::{Config, InstallationMethod}; use crate::config::{Config, InstallationMethod};
use crate::files; use crate::files;
use crate::files::FoundFile; use crate::files::FoundFile;
use crate::utils::{verify_path_setup, wrap};
/// Add a direcotry to the plugin locations. Duplicates get ignord because we're using ordered sets. /// Add a direcotry to the plugin locations. Duplicates get ignord because we're using ordered sets.
pub fn add_directory(config: &mut Config, path: PathBuf) -> Result<()> { pub fn add_directory(config: &mut Config, path: PathBuf) -> Result<()> {
@@ -46,7 +47,7 @@ pub fn remove_directory(config: &mut Config, path: &Path) -> Result<()> {
let orphan_files = files::index_so_files(path); let orphan_files = files::index_so_files(path);
if !orphan_files.is_empty() { if !orphan_files.is_empty() {
println!( println!(
"WARNING: Found {} leftover '.so' files still in this directory:", "Warning: Found {} leftover '.so' files still in this directory:",
orphan_files.len() orphan_files.len()
); );
@@ -248,5 +249,26 @@ pub fn do_sync(config: &Config, prune: bool, verbose: bool) -> Result<()> {
num_skipped_files num_skipped_files
); );
if config.method == InstallationMethod::Copy {
if let Err(shell_name) = verify_path_setup() {
println!(
"\n{}",
wrap(&format!(
"Warning: 'yabridge-host.exe' is not present in your login shell's search \
path. Yabridge won't be able to run using the copy-based installatin method \
until this is fixed.\n\
Add '{}' to {}'s login shell {} environment variable. See the \
troubleshooting section of the readme for more details. Rerun this command to \
verify that this has been set up correctly, and then reboot your system.\n\
\n\
https://github.com/robbert-vdh/yabridge#troubleshooting-common-issues",
libyabridge_path.parent().unwrap().display(),
shell_name.bright_white(),
"PATH".bright_white()
))
)
}
}
Ok(()) Ok(())
} }
+1 -1
View File
@@ -56,7 +56,7 @@ pub struct Config {
} }
/// Specifies how yabridge will be set up for the found plugins. /// Specifies how yabridge will be set up for the found plugins.
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
#[serde(rename_all = "snake_case")] #[serde(rename_all = "snake_case")]
pub enum InstallationMethod { pub enum InstallationMethod {
/// Create a copy of `libyabridge.so` for every Windows VST2 plugin .dll file found. After /// Create a copy of `libyabridge.so` for every Windows VST2 plugin .dll file found. After
+1 -1
View File
@@ -24,9 +24,9 @@ use crate::config::Config;
mod actions; mod actions;
mod config; mod config;
mod files; mod files;
mod utils;
// TODO: Naming and descriptions could be made clearer // TODO: Naming and descriptions could be made clearer
// TODO: When creating copies, check whether `yabridge-host.exe` is in the PATH for the login shell
// TODO: Reward parts of the readme // TODO: Reward parts of the readme
fn main() -> Result<()> { fn main() -> Result<()> {
+106
View File
@@ -0,0 +1,106 @@
// yabridge: a Wine VST bridge
// Copyright (C) 2020 Robbert van der Helm
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! Small helper utilities.
use colored::Colorize;
use std::env;
use std::path::Path;
use std::process::{Command, Stdio};
use textwrap::Wrapper;
/// Verify that `yabridge-host.exe` is accessible in a login shell. Returns unit if it is, or if we
/// the login shell is set to an unknown shell. In the last case we'll just print a warning since we
/// don't know how to invoke the shell as a login shell. This is needed when using copies to ensure
/// that yabridge can find the host binaries when the VST host is launched from the desktop
/// enviornment.
///
/// When we could not find `yabridge-host.exe`, we'll return `Err(shell_name)` so we can print a
/// descriptive warning message.
///
/// # TODO
///
/// Starting from Rust 1.45 we can just modify `argv[0]` to start with a dash instead, see
/// https://doc.rust-lang.org/std/os/unix/process/trait.CommandExt.html#tymethod.arg0
/// https://github.com/rust-lang/rust/issues/66510
pub fn verify_path_setup() -> Result<(), String> {
match env::var("SHELL") {
Ok(shell_path) => {
// `$SHELL` will often contain a full path, but it doesn't have to
let shell = Path::new(&shell_path)
.file_name()
.and_then(|os_str| os_str.to_str())
.unwrap_or_else(|| shell_path.as_str());
let mut command = Command::new(&shell_path);
let command = match shell {
// All of these shells support the `-l` flag to start a login shell and
// "-c<command>" to directly run a command under that login shell
"ash" | "bash" | "csh" | "ksh" | "dash" | "fish" | "sh" | "tcsh" | "zsh" => command
.arg("-l")
.arg("-c")
.arg("command -v yabridge-host.exe"),
// I don't know if anyone uses PowerShell as their login shell under Linux, but it
// doesn't implement the POSIX `command` function so we'll just use which instead
"pwsh" => command.arg("-l").arg("-c").arg("which yabridge-host.exe"),
shell => {
eprintln!(
"{}",
wrap(&format!(
"WARNING: Yabridgectl does not know how to handle your login shell, \
'{}', skipping PATH setup check. Feel free to open a bug report to \
get yabridgectl to support your shell.\n\
\n\
https://github.com/robbert-vdh/yabridge/issues",
shell.bright_white(),
))
);
return Ok(());
}
};
// For the login shell we want to a clean environment, but we still have to set `$HOME`
// or else most shells won't know which profile to load
command
.env_clear()
.env("HOME", env::var("HOME").unwrap_or_default());
match command.stdout(Stdio::null()).stderr(Stdio::null()).status() {
Ok(status) if status.success() => Ok(()),
Ok(_) => Err(shell.to_string()),
Err(err) => {
eprintln!(
"Warning: could not run login shell, skipping PATH setup check: {}",
err
);
Ok(())
}
}
}
Err(_) => {
eprintln!("\nWarning: Could not determine login shell, skipping PATH setup check");
Ok(())
}
}
}
/// Wrap a long paragraph of text to terminal width, or 80 characters if the width of the terminal
/// can't be determined. Everything after the first line gets indented with four spaces.
pub fn wrap(text: &str) -> String {
let wrapper = Wrapper::with_termwidth().subsequent_indent(" ");
wrapper.fill(text)
}