mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-16 05:33:07 +02:00
[yabridgectl] Locate libyabridge-vst3.so
And unify how finding files in yabridgectl works.
This commit is contained in:
@@ -21,7 +21,7 @@ use colored::Colorize;
|
|||||||
use std::fs;
|
use std::fs;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
use crate::config::{Config, InstallationMethod};
|
use crate::config::{Config, InstallationMethod, YabridgeFiles};
|
||||||
use crate::files;
|
use crate::files;
|
||||||
use crate::files::FoundFile;
|
use crate::files::FoundFile;
|
||||||
use crate::utils;
|
use crate::utils;
|
||||||
@@ -95,15 +95,27 @@ pub fn show_status(config: &Config) -> Result<()> {
|
|||||||
.map(|path| format!("'{}'", path.display()))
|
.map(|path| format!("'{}'", path.display()))
|
||||||
.unwrap_or_else(|| String::from("<auto>"))
|
.unwrap_or_else(|| String::from("<auto>"))
|
||||||
);
|
);
|
||||||
println!(
|
|
||||||
"libyabridge-vst2.so: {}",
|
|
||||||
config
|
|
||||||
.libyabridge_vst2()
|
|
||||||
.map(|path| format!("'{}'", path.display()))
|
|
||||||
.unwrap_or_else(|_| format!("{}", "<not found>".red()))
|
|
||||||
);
|
|
||||||
println!("installation method: {}", config.method);
|
|
||||||
|
|
||||||
|
match config.files() {
|
||||||
|
Ok(files) => {
|
||||||
|
println!(
|
||||||
|
"libyabridge-vst2.so: '{}'",
|
||||||
|
files.libyabridge_vst2.display()
|
||||||
|
);
|
||||||
|
println!(
|
||||||
|
"libyabridge-vst3.so: {}\n",
|
||||||
|
files
|
||||||
|
.libyabridge_vst3
|
||||||
|
.map(|path| format!("'{}'", path.display()))
|
||||||
|
.unwrap_or_else(|| "<not found>".red().to_string())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
println!("Could not find yabridge's files files: {}\n", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("installation method: {}", config.method);
|
||||||
for (path, search_results) in results {
|
for (path, search_results) in results {
|
||||||
println!("\n{}:", path.display());
|
println!("\n{}:", path.display());
|
||||||
|
|
||||||
@@ -154,9 +166,9 @@ pub struct SyncOptions {
|
|||||||
/// Set up yabridge for all Windows VST2 plugins in the plugin directories. Will also remove orphan
|
/// Set up yabridge for all Windows VST2 plugins in the plugin directories. Will also remove orphan
|
||||||
/// `.so` files if the prune option is set.
|
/// `.so` files if the prune option is set.
|
||||||
pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
||||||
let libyabridge_vst2_path = config.libyabridge_vst2()?;
|
let files: YabridgeFiles = config.files()?;
|
||||||
let libyabridge_vst2_hash = utils::hash_file(&libyabridge_vst2_path)?;
|
let libyabridge_vst2_hash = utils::hash_file(&files.libyabridge_vst2)?;
|
||||||
println!("Using '{}'\n", libyabridge_vst2_path.display());
|
println!("Using '{}'\n", files.libyabridge_vst2.display());
|
||||||
|
|
||||||
let results = config
|
let results = config
|
||||||
.index_directories()
|
.index_directories()
|
||||||
@@ -200,7 +212,7 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
|||||||
// If the target file is already a symlink to `libyabridge-vst2.so`, then we
|
// If the target file is already a symlink to `libyabridge-vst2.so`, then we
|
||||||
// can skip this file
|
// can skip this file
|
||||||
if metadata.file_type().is_symlink()
|
if metadata.file_type().is_symlink()
|
||||||
&& target_path.read_link()? == libyabridge_vst2_path
|
&& target_path.read_link()? == files.libyabridge_vst2
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -217,10 +229,10 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
|||||||
num_new += 1;
|
num_new += 1;
|
||||||
match config.method {
|
match config.method {
|
||||||
InstallationMethod::Copy => {
|
InstallationMethod::Copy => {
|
||||||
utils::copy(&libyabridge_vst2_path, &target_path)?;
|
utils::copy(&files.libyabridge_vst2, &target_path)?;
|
||||||
}
|
}
|
||||||
InstallationMethod::Symlink => {
|
InstallationMethod::Symlink => {
|
||||||
utils::symlink(&libyabridge_vst2_path, &target_path)?;
|
utils::symlink(&files.libyabridge_vst2, &target_path)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,16 @@ use xdg::BaseDirectories;
|
|||||||
|
|
||||||
use crate::files::{self, SearchResults};
|
use crate::files::{self, SearchResults};
|
||||||
|
|
||||||
/// The name of the config file, relative to `$XDG_CONFIG_HOME/CONFIG_PREFIX`.
|
/// The name of the config file, relative to `$XDG_CONFIG_HOME/YABRIDGECTL_PREFIX`.
|
||||||
pub const CONFIG_FILE_NAME: &str = "config.toml";
|
pub const CONFIG_FILE_NAME: &str = "config.toml";
|
||||||
/// The name of the XDG base directory prefix for yabridgectl, relative to `$XDG_CONFIG_HOME` and
|
/// The name of the XDG base directory prefix for yabridgectl, relative to `$XDG_CONFIG_HOME` and
|
||||||
/// `$XDG_DATA_HOME`.
|
/// `$XDG_DATA_HOME`.
|
||||||
const YABRIDGECTL_PREFIX: &str = "yabridgectl";
|
const YABRIDGECTL_PREFIX: &str = "yabridgectl";
|
||||||
|
|
||||||
/// The name of the library file we're searching for.
|
/// The name of yabridge's VST2 library.
|
||||||
pub const LIBYABRIDGE_VST2_NAME: &str = "libyabridge-vst2.so";
|
pub const LIBYABRIDGE_VST2_NAME: &str = "libyabridge-vst2.so";
|
||||||
|
/// The name of yabridge's VST3 library.
|
||||||
|
pub const LIBYABRIDGE_VST3_NAME: &str = "libyabridge-vst3.so";
|
||||||
/// The name of the script we're going to run to verify that everything's working correctly.
|
/// The name of the script we're going to run to verify that everything's working correctly.
|
||||||
pub const YABRIDGE_HOST_EXE_NAME: &str = "yabridge-host.exe";
|
pub const YABRIDGE_HOST_EXE_NAME: &str = "yabridge-host.exe";
|
||||||
/// The name of the XDG base directory prefix for yabridge's own files, relative to
|
/// The name of the XDG base directory prefix for yabridge's own files, relative to
|
||||||
@@ -66,13 +68,13 @@ pub struct Config {
|
|||||||
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
|
#[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-vst2.so` for every Windows VST2 plugin .dll file found. After
|
/// Create a copy of `libyabridge-{vst2,vst3}.so` for every Windows VST2 plugin .dll file or
|
||||||
/// updating yabridge, the user will have to rerun `yabridgectl sync` to copy over the new
|
/// VST3 module found. After updating yabridge, the user will have to rerun `yabridgectl sync`
|
||||||
/// version.
|
/// to copy over the new version.
|
||||||
Copy,
|
Copy,
|
||||||
/// This will create a symlink to `libyabridge-vst2.so` for every VST2 .dll file in the plugin
|
/// This will create a symlink to `libyabridge-{vst2,vst3}.so` for every VST2 plugin .dll file
|
||||||
/// directories. As explained in the readme, this makes updating easier and remvoes the need to
|
/// or VST3 module in the plugin directories. Now that yabridge also searches in
|
||||||
/// modify the `PATH` environment variable.
|
/// `~/.local/share/yabridge` since yabridge 2.1 this option is not really needed anymore.
|
||||||
Symlink,
|
Symlink,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,6 +119,23 @@ pub struct KnownConfig {
|
|||||||
pub yabridge_host_hash: i64,
|
pub yabridge_host_hash: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Paths to all of yabridge's files based on the `yabridge_home` setting. Created by
|
||||||
|
/// `Config::files`.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct YabridgeFiles {
|
||||||
|
/// The path to `libyabridge-vst2.so` we should use.
|
||||||
|
pub libyabridge_vst2: PathBuf,
|
||||||
|
/// The path to `libyabridge-vst3.so` we should use, if yabridge has been compiled with VST3
|
||||||
|
/// support.
|
||||||
|
pub libyabridge_vst3: Option<PathBuf>,
|
||||||
|
/// The path to `yabridge-host.exe`. This is the path yabridge will actually use, and it does
|
||||||
|
/// not have to be relative to `yabridge_home`.
|
||||||
|
pub yabridge_host_exe: PathBuf,
|
||||||
|
/// The actual Winelib binary for `yabridge-host.exe`. Will be hashed to check whether the user
|
||||||
|
/// has updated yabridge.
|
||||||
|
pub yabridge_host_exe_so: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
/// Try to read the config file, creating a new default file if necessary. This will fail if the
|
/// Try to read the config file, creating a new default file if necessary. This will fail if the
|
||||||
/// file could not be created or if it could not be parsed.
|
/// file could not be created or if it could not be parsed.
|
||||||
@@ -158,21 +177,23 @@ impl Config {
|
|||||||
.with_context(|| format!("Failed to write config file to '{}'", config_path.display()))
|
.with_context(|| format!("Failed to write config file to '{}'", config_path.display()))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the path to `libyabridge-vst2.so`, or a descriptive error if it can't be found. If
|
/// Find all of yabridge's files based on `yabridge_home`. For the binaries we'll search for
|
||||||
/// `yabridge_home` is `None`, then we'll search in both `/usr/lib` and
|
/// them the exact same way as yabridge itself will.
|
||||||
/// `$XDG_DATA_HOME/yabridge`.
|
pub fn files(&self) -> Result<YabridgeFiles> {
|
||||||
pub fn libyabridge_vst2(&self) -> Result<PathBuf> {
|
let xdg_dirs = yabridge_directories()?;
|
||||||
match &self.yabridge_home {
|
|
||||||
|
// First find `libyabridge-vst2.so`
|
||||||
|
let libyabridge_vst2: PathBuf = match &self.yabridge_home {
|
||||||
Some(directory) => {
|
Some(directory) => {
|
||||||
let candidate = directory.join(LIBYABRIDGE_VST2_NAME);
|
let candidate = directory.join(LIBYABRIDGE_VST2_NAME);
|
||||||
if candidate.exists() {
|
if candidate.exists() {
|
||||||
Ok(candidate)
|
candidate
|
||||||
} else {
|
} else {
|
||||||
Err(anyhow!(
|
return Err(anyhow!(
|
||||||
"Could not find '{}' in '{}'",
|
"Could not find '{}' in '{}'",
|
||||||
LIBYABRIDGE_VST2_NAME,
|
LIBYABRIDGE_VST2_NAME,
|
||||||
directory.display()
|
directory.display()
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
@@ -182,42 +203,58 @@ impl Config {
|
|||||||
// when `libyabridge-vst2.so` can't be found.
|
// when `libyabridge-vst2.so` can't be found.
|
||||||
let system_path = Path::new("/usr/lib");
|
let system_path = Path::new("/usr/lib");
|
||||||
let system_path_alt = Path::new("/usr/local/lib");
|
let system_path_alt = Path::new("/usr/local/lib");
|
||||||
let user_path = yabridge_directories()?.get_data_home();
|
let user_path = xdg_dirs.get_data_home();
|
||||||
for directory in &[system_path, system_path_alt, &user_path] {
|
let directories = [system_path, system_path_alt, &user_path];
|
||||||
let candidate = directory.join(LIBYABRIDGE_VST2_NAME);
|
let mut candidates = directories
|
||||||
if candidate.exists() {
|
.iter()
|
||||||
return Ok(candidate);
|
.map(|directory| directory.join(LIBYABRIDGE_VST2_NAME));
|
||||||
|
match candidates.find(|directory| directory.exists()) {
|
||||||
|
Some(candidate) => candidate,
|
||||||
|
_ => {
|
||||||
|
return Err(anyhow!(
|
||||||
|
"Could not find '{}' in either '{}' or '{}'. You can override the \
|
||||||
|
default search path using 'yabridgectl set --path=<path>'.",
|
||||||
|
LIBYABRIDGE_VST2_NAME,
|
||||||
|
system_path.display(),
|
||||||
|
user_path.display()
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(anyhow!(
|
|
||||||
"Could not find '{}' in either '{}' or '{}'. You can override the default \
|
|
||||||
search path using 'yabridgectl set --path=<path>'.",
|
|
||||||
LIBYABRIDGE_VST2_NAME,
|
|
||||||
system_path.display(),
|
|
||||||
user_path.display()
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the path to `yabridge-host.exe`, or a descriptive error if it can't be found. This
|
// Based on that we can check if `libyabridge-vst3.so` exists, since yabridge can be
|
||||||
/// will first search alongside `libyabridge-vst2.so` and then search through the search path.
|
// compiled without VST3 support
|
||||||
pub fn yabridge_host_exe(&self) -> Result<PathBuf> {
|
let libyabridge_vst3 = match libyabridge_vst2.with_file_name(LIBYABRIDGE_VST3_NAME) {
|
||||||
let yabridge_path = self.libyabridge_vst2()?;
|
path if path.exists() => Some(path),
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let yabridge_host_exe_candidate = yabridge_path.with_file_name(YABRIDGE_HOST_EXE_NAME);
|
// `yabridge-host.exe` should either be in the search path, or it should be in
|
||||||
if yabridge_host_exe_candidate.exists() {
|
// `~/.local/share/yabridge`
|
||||||
return Ok(yabridge_host_exe_candidate);
|
let yabridge_host_exe = match which(YABRIDGE_HOST_EXE_NAME)
|
||||||
}
|
.ok()
|
||||||
|
.or_else(|| xdg_dirs.find_data_file(YABRIDGE_HOST_EXE_NAME))
|
||||||
|
{
|
||||||
|
Some(path) => path,
|
||||||
|
_ => {
|
||||||
|
return Err(anyhow!("Could not locate '{}'.", YABRIDGE_HOST_EXE_NAME));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let yabridge_host_exe_so = yabridge_host_exe.with_extension("exe.so");
|
||||||
|
|
||||||
// Normally we wouldn't need the full absolute path to `yabridge-host.exe`, but it's useful
|
Ok(YabridgeFiles {
|
||||||
// for the error messages
|
libyabridge_vst2,
|
||||||
Ok(which(YABRIDGE_HOST_EXE_NAME)?)
|
libyabridge_vst3,
|
||||||
|
yabridge_host_exe,
|
||||||
|
yabridge_host_exe_so,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search for VST2 plugins in all of the registered plugins directories. This will return an
|
/// Search for VST2 plugins in all of the registered plugins directories. This will return an
|
||||||
/// error if `winedump` could not be called.
|
/// error if `winedump` could not be called.
|
||||||
|
///
|
||||||
|
/// TODO: Next step is including VST3 modules in the search
|
||||||
pub fn index_directories(&self) -> Result<BTreeMap<&Path, SearchResults>> {
|
pub fn index_directories(&self) -> Result<BTreeMap<&Path, SearchResults>> {
|
||||||
self.plugin_dirs
|
self.plugin_dirs
|
||||||
.par_iter()
|
.par_iter()
|
||||||
|
|||||||
@@ -90,17 +90,21 @@ pub fn hash_file(file: &Path) -> Result<i64> {
|
|||||||
/// In the last case we'll just print a warning since we don't know how to invoke the shell as a
|
/// 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
|
/// 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 the VST host is launched from the desktop enviornment.
|
||||||
|
///
|
||||||
|
/// This is a bit messy, and with yabridge 2.1 automatically searching in `~/.local/share/yabridge`
|
||||||
|
/// it's probably not really needed anymore, but it could still be useful in some edge case
|
||||||
|
/// scenarios.
|
||||||
pub fn verify_path_setup(config: &Config) -> Result<bool> {
|
pub fn verify_path_setup(config: &Config) -> Result<bool> {
|
||||||
// First we'll check `~/.local/share/yabridge`, since that's a special location where yabridge
|
// First we'll check `~/.local/share/yabridge`, since that's a special location where yabridge
|
||||||
// will always search
|
// will always search
|
||||||
if config::yabridge_directories()
|
let xdg_data_yabridge_exists = config::yabridge_directories()
|
||||||
.map(|dirs| {
|
.map(|dirs| {
|
||||||
dirs.get_data_home()
|
dirs.get_data_home()
|
||||||
.join(YABRIDGE_HOST_EXE_NAME)
|
.join(YABRIDGE_HOST_EXE_NAME)
|
||||||
.is_executable()
|
.is_executable()
|
||||||
})
|
})
|
||||||
.unwrap_or(false)
|
.unwrap_or(false);
|
||||||
{
|
if xdg_data_yabridge_exists {
|
||||||
return Ok(true);
|
return Ok(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +183,7 @@ pub fn verify_path_setup(config: &Config) -> Result<bool> {
|
|||||||
reboot your system to complete the setup.\n\
|
reboot your system to complete the setup.\n\
|
||||||
\n\
|
\n\
|
||||||
https://github.com/robbert-vdh/yabridge#troubleshooting-common-issues",
|
https://github.com/robbert-vdh/yabridge#troubleshooting-common-issues",
|
||||||
config.libyabridge_vst2()?.parent().unwrap().display(),
|
config.files()?.libyabridge_vst2.parent().unwrap().display(),
|
||||||
shell.bright_white(),
|
shell.bright_white(),
|
||||||
"PATH".bright_white()
|
"PATH".bright_white()
|
||||||
))
|
))
|
||||||
@@ -230,13 +234,13 @@ pub fn verify_wine_setup(config: &mut Config) -> Result<()> {
|
|||||||
let mut wine_version = String::from_utf8(wine_version_output)?;
|
let mut wine_version = String::from_utf8(wine_version_output)?;
|
||||||
wine_version.pop().unwrap();
|
wine_version.pop().unwrap();
|
||||||
|
|
||||||
let yabridge_host_exe_path = config
|
let files = config
|
||||||
.yabridge_host_exe()
|
.files()
|
||||||
.context(format!("Could not find '{}'", YABRIDGE_HOST_EXE_NAME))?;
|
.context(format!("Could not find '{}'", YABRIDGE_HOST_EXE_NAME))?;
|
||||||
|
|
||||||
// Hash the contents of `yabridge-host.exe.so` since `yabridge-host.exe` is only a Wine
|
// Hash the contents of `yabridge-host.exe.so` since `yabridge-host.exe` is only a Wine
|
||||||
// generated shell script
|
// generated shell script
|
||||||
let yabridge_host_hash = hash_file(&yabridge_host_exe_path.with_extension("exe.so"))?;
|
let yabridge_host_hash = hash_file(&files.yabridge_host_exe_so)?;
|
||||||
|
|
||||||
// Since these checks can take over a second if wineserver isn't already running we'll only
|
// Since these checks can take over a second if wineserver isn't already running we'll only
|
||||||
// perform them when something has changed
|
// perform them when something has changed
|
||||||
@@ -248,9 +252,9 @@ pub fn verify_wine_setup(config: &mut Config) -> Result<()> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = Command::new(&yabridge_host_exe_path)
|
let output = Command::new(&files.yabridge_host_exe)
|
||||||
.output()
|
.output()
|
||||||
.with_context(|| format!("Could not run '{}'", yabridge_host_exe_path.display()))?;
|
.with_context(|| format!("Could not run '{}'", files.yabridge_host_exe.display()))?;
|
||||||
let stderr = String::from_utf8(output.stderr)?;
|
let stderr = String::from_utf8(output.stderr)?;
|
||||||
|
|
||||||
// There are three scenarios here:
|
// There are three scenarios here:
|
||||||
|
|||||||
Reference in New Issue
Block a user