mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 20:10:13 +02:00
[yabridgectl] Allow setting up VST3 plugins
This is still missing checks for removing leftover files, symlinks for resources and presets, and a way to differentiate between plugins with the same name from different prefixes.
This commit is contained in:
@@ -23,7 +23,7 @@ use std::path::{Path, PathBuf};
|
||||
|
||||
use crate::config::{Config, InstallationMethod, YabridgeFiles};
|
||||
use crate::files;
|
||||
use crate::files::NativeSoFile;
|
||||
use crate::files::NativeFile;
|
||||
use crate::utils;
|
||||
use crate::utils::{verify_path_setup, verify_wine_setup};
|
||||
|
||||
@@ -34,10 +34,9 @@ pub fn add_directory(config: &mut Config, path: PathBuf) -> Result<()> {
|
||||
}
|
||||
|
||||
/// Remove a direcotry to the plugin locations. The path is assumed to be part of
|
||||
/// `config.plugin_dirs`, otherwise this si silently ignored.
|
||||
/// `config.plugin_dirs`, otherwise this is silently ignored.
|
||||
pub fn remove_directory(config: &mut Config, path: &Path) -> Result<()> {
|
||||
// We've already verified that this path is in `config.plugin_dirs`
|
||||
// XXS: Would it be a good idea to warn about leftover .so files?
|
||||
config.plugin_dirs.remove(path);
|
||||
config.write()?;
|
||||
|
||||
@@ -121,8 +120,9 @@ pub fn show_status(config: &Config) -> Result<()> {
|
||||
|
||||
for (plugin, status) in search_results.installation_status() {
|
||||
let status_str = match status {
|
||||
Some(NativeSoFile::Regular(_)) => "copy".green(),
|
||||
Some(NativeSoFile::Symlink(_)) => "symlink".green(),
|
||||
Some(NativeFile::Regular(_)) => "copy".green(),
|
||||
Some(NativeFile::Symlink(_)) => "symlink".green(),
|
||||
Some(NativeFile::Directory(_)) => "invalid".red(),
|
||||
None => "not installed".red(),
|
||||
};
|
||||
|
||||
@@ -168,20 +168,47 @@ pub struct SyncOptions {
|
||||
pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
||||
let files: YabridgeFiles = config.files()?;
|
||||
let libyabridge_vst2_hash = utils::hash_file(&files.libyabridge_vst2)?;
|
||||
println!("Using '{}'\n", files.libyabridge_vst2.display());
|
||||
let libyabridge_vst3_hash = match &files.libyabridge_vst3 {
|
||||
Some(path) => Some(utils::hash_file(path)?),
|
||||
None => None,
|
||||
};
|
||||
|
||||
if let Some(libyabridge_vst3_path) = &files.libyabridge_vst3 {
|
||||
println!("Setting up VST2 and VST3 plugins using:");
|
||||
println!("- {}", files.libyabridge_vst2.display());
|
||||
println!("- {}\n", libyabridge_vst3_path.display());
|
||||
} else {
|
||||
println!("Setting up VST2 plugins using:");
|
||||
println!("- {}\n", files.libyabridge_vst2.display());
|
||||
}
|
||||
|
||||
let results = config
|
||||
.search_directories()
|
||||
.context("Failure while searching for plugins")?;
|
||||
|
||||
// Keep track of some global statistics
|
||||
// The number of plugins we set up yabridge for
|
||||
let mut num_installed = 0;
|
||||
// The number of plugins we create a (new) copy of `libyabridge-{vst2,vst3}.so` for
|
||||
let mut num_new = 0;
|
||||
// The files we skipped during the scan because they turned out to not be plugins
|
||||
let mut skipped_dll_files: Vec<PathBuf> = Vec::new();
|
||||
let mut orphan_so_files: Vec<NativeSoFile> = Vec::new();
|
||||
// `.so` files we found during scanning that didn't have a corresponding copy or symlink of
|
||||
// `libyabridge-vst2.so`
|
||||
let mut orphan_vst2_so_files: Vec<NativeFile> = Vec::new();
|
||||
// All the VST3 modules we have set up yabridge for. We need this to detect leftover VST3
|
||||
// modules in `~/.vst3/yabridge`.
|
||||
let mut yabridge_vst3_bundles: Vec<PathBuf> = Vec::new();
|
||||
for (path, search_results) in results {
|
||||
num_installed += search_results.vst2_files.len();
|
||||
orphan_so_files.extend(search_results.orphans().into_iter().cloned());
|
||||
num_installed += search_results.vst3_modules.len();
|
||||
orphan_vst2_so_files.extend(search_results.vst2_orphans().into_iter().cloned());
|
||||
yabridge_vst3_bundles.extend(
|
||||
search_results
|
||||
.vst3_modules
|
||||
.iter()
|
||||
.map(|module| module.yabridge_bundle_home()),
|
||||
);
|
||||
skipped_dll_files.extend(search_results.skipped_files);
|
||||
|
||||
if options.verbose {
|
||||
@@ -190,56 +217,58 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
||||
for plugin in search_results.vst2_files {
|
||||
let target_path = plugin.with_extension("so");
|
||||
|
||||
// We'll only recreate existing files when updating yabridge, when switching between the
|
||||
// symlink and copy installation methods, or when the `force` option is set. If the
|
||||
// target file already exists and does not require updating, we'll just skip the file
|
||||
// since some DAWs will otherwise unnecessarily reindex the file.
|
||||
// We check `std::fs::symlink_metadata` instead of `Path::exists()` because the latter
|
||||
// reports false for broken symlinks.
|
||||
if let Ok(metadata) = fs::symlink_metadata(&target_path) {
|
||||
match (options.force, &config.method) {
|
||||
(false, InstallationMethod::Copy) => {
|
||||
// If the target file is already a real file (not a symlink) and its hash is
|
||||
// the same as the `libyabridge-vst2.so` file we're trying to copy there,
|
||||
// then we don't have to do anything
|
||||
if metadata.file_type().is_file()
|
||||
&& utils::hash_file(&target_path)? == libyabridge_vst2_hash
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
(false, InstallationMethod::Symlink) => {
|
||||
// If the target file is already a symlink to `libyabridge-vst2.so`, then we
|
||||
// can skip this file
|
||||
if metadata.file_type().is_symlink()
|
||||
&& target_path.read_link()? == files.libyabridge_vst2
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// With the force option we always want to recreate existing .so files
|
||||
(true, _) => (),
|
||||
}
|
||||
|
||||
utils::remove_file(&target_path)?;
|
||||
};
|
||||
|
||||
// Since we skip some files, we'll also keep track of how many new file we've actually
|
||||
// set up
|
||||
num_new += 1;
|
||||
match config.method {
|
||||
InstallationMethod::Copy => {
|
||||
utils::copy(&files.libyabridge_vst2, &target_path)?;
|
||||
}
|
||||
InstallationMethod::Symlink => {
|
||||
utils::symlink(&files.libyabridge_vst2, &target_path)?;
|
||||
}
|
||||
if install_file(
|
||||
options.force,
|
||||
config.method,
|
||||
&files.libyabridge_vst2,
|
||||
libyabridge_vst2_hash,
|
||||
&target_path,
|
||||
)? {
|
||||
num_new += 1;
|
||||
}
|
||||
|
||||
if options.verbose {
|
||||
println!(" {}", plugin.display());
|
||||
}
|
||||
}
|
||||
if let Some(libyabridge_vst3_hash) = libyabridge_vst3_hash {
|
||||
for module in search_results.vst3_modules {
|
||||
let native_module_path = module.yabridge_native_module_path();
|
||||
|
||||
// For VST3 plugins we'll first have to create the bundle structure
|
||||
utils::create_dir_all(native_module_path.parent().unwrap())?;
|
||||
|
||||
// We'll then symlink the Windows VST3 module to that bundle to create a merged
|
||||
// bundle: https://steinbergmedia.github.io/vst3_doc/vstinterfaces/vst3loc.html#mergedbundles
|
||||
let windows_module_path = module.yabridge_windows_module_path();
|
||||
utils::create_dir_all(windows_module_path.parent().unwrap())?;
|
||||
install_file(
|
||||
true,
|
||||
InstallationMethod::Symlink,
|
||||
&module.original_module_path(),
|
||||
0,
|
||||
&windows_module_path,
|
||||
)?;
|
||||
|
||||
// TODO: Symlink resources and presets
|
||||
|
||||
if install_file(
|
||||
options.force,
|
||||
config.method,
|
||||
files.libyabridge_vst3.as_ref().unwrap(),
|
||||
libyabridge_vst3_hash,
|
||||
&native_module_path,
|
||||
)? {
|
||||
num_new += 1;
|
||||
}
|
||||
|
||||
if options.verbose {
|
||||
println!(" {}", module.original_path().display());
|
||||
}
|
||||
}
|
||||
}
|
||||
if options.verbose {
|
||||
println!();
|
||||
}
|
||||
@@ -255,19 +284,24 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
||||
println!();
|
||||
}
|
||||
|
||||
// Always warn about leftover files sicne those might cause warnings or errors when a VST host
|
||||
// TODO: Remove leftover files for VST3 plugins
|
||||
|
||||
// Always warn about leftover files since those might cause warnings or errors when a VST host
|
||||
// tries to load them
|
||||
if !orphan_so_files.is_empty() {
|
||||
if !orphan_vst2_so_files.is_empty() {
|
||||
if options.prune {
|
||||
println!("Removing {} leftover .so files:", orphan_so_files.len());
|
||||
println!(
|
||||
"Removing {} leftover .so files:",
|
||||
orphan_vst2_so_files.len()
|
||||
);
|
||||
} else {
|
||||
println!(
|
||||
"Found {} leftover .so files, rerun with the '--prune' option to remove them:",
|
||||
orphan_so_files.len()
|
||||
orphan_vst2_so_files.len()
|
||||
);
|
||||
}
|
||||
|
||||
for file in orphan_so_files {
|
||||
for file in orphan_vst2_so_files {
|
||||
let path = file.path();
|
||||
|
||||
println!("- {}", path.display());
|
||||
@@ -291,6 +325,8 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// The path setup is to make sure that the `libyabridge-{vst2,vst3}.so` copies can find
|
||||
// `yabridge-host.exe`
|
||||
if config.method == InstallationMethod::Copy {
|
||||
verify_path_setup(config)?;
|
||||
}
|
||||
@@ -300,3 +336,53 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Create a copy or symlink of `from` to `to`. Depending on `force`, we might not actually create a
|
||||
/// new copy or symlink if `to` matches `from_hash`.
|
||||
fn install_file(
|
||||
force: bool,
|
||||
method: InstallationMethod,
|
||||
from: &Path,
|
||||
from_hash: i64,
|
||||
to: &Path,
|
||||
) -> Result<bool> {
|
||||
// We'll only recreate existing files when updating yabridge, when switching between the symlink
|
||||
// and copy installation methods, or when the `force` option is set. If the target file already
|
||||
// exists and does not require updating, we'll just skip the file since some DAWs will otherwise
|
||||
// unnecessarily reindex the file. We check `std::fs::symlink_metadata` instead of
|
||||
// `Path::exists()` because the latter reports false for broken symlinks.
|
||||
if let Ok(metadata) = fs::symlink_metadata(&to) {
|
||||
match (force, &method) {
|
||||
(false, InstallationMethod::Copy) => {
|
||||
// If the target file is already a real file (not a symlink) and its hash is
|
||||
// the same as the `libyabridge-vst2.so` file we're trying to copy there,
|
||||
// then we don't have to do anything
|
||||
if metadata.file_type().is_file() && utils::hash_file(to)? == from_hash {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
(false, InstallationMethod::Symlink) => {
|
||||
// If the target file is already a symlink to `libyabridge-vst2.so`, then we
|
||||
// can skip this file
|
||||
if metadata.file_type().is_symlink() && to.read_link()? == from {
|
||||
return Ok(false);
|
||||
}
|
||||
}
|
||||
// With the force option we always want to recreate existing .so files
|
||||
(true, _) => (),
|
||||
}
|
||||
|
||||
utils::remove_file(&to)?;
|
||||
};
|
||||
|
||||
match method {
|
||||
InstallationMethod::Copy => {
|
||||
utils::copy(from, to)?;
|
||||
}
|
||||
InstallationMethod::Symlink => {
|
||||
utils::symlink(from, to)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ pub struct Config {
|
||||
}
|
||||
|
||||
/// Specifies how yabridge will be set up for the found plugins.
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq)]
|
||||
#[derive(Deserialize, Serialize, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
#[serde(rename_all = "snake_case")]
|
||||
pub enum InstallationMethod {
|
||||
/// Create a copy of `libyabridge-{vst2,vst3}.so` for every Windows VST2 plugin `.dll` file or
|
||||
|
||||
@@ -26,6 +26,7 @@ use std::process::Command;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
use crate::config::yabridge_vst3_home;
|
||||
use crate::utils::get_file_type;
|
||||
|
||||
/// Stores the results from searching through a directory. We'll search for Windows VST2 plugin
|
||||
/// `.dll` files, Windows VST3 plugin modules, and native Linux `.so` files inside of a directory.
|
||||
@@ -44,7 +45,7 @@ pub struct SearchResults {
|
||||
|
||||
/// Absolute paths to any `.so` files inside of the directory, and whether they're a symlink or
|
||||
/// a regular file.
|
||||
pub so_files: Vec<NativeSoFile>,
|
||||
pub so_files: Vec<NativeFile>,
|
||||
}
|
||||
|
||||
/// The results of the first step of the search process. We'll first index all possibly relevant
|
||||
@@ -58,22 +59,24 @@ pub struct SearchIndex {
|
||||
pub vst3_files: Vec<PathBuf>,
|
||||
/// Absolute paths to any `.so` files inside of the directory, and whether they're a symlink or
|
||||
/// a regular file.
|
||||
pub so_files: Vec<NativeSoFile>,
|
||||
pub so_files: Vec<NativeFile>,
|
||||
}
|
||||
|
||||
/// Native `.so` files we found during a search.
|
||||
/// Native `.so` files and VST3 bundle directories we found during a search.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum NativeSoFile {
|
||||
pub enum NativeFile {
|
||||
Symlink(PathBuf),
|
||||
Regular(PathBuf),
|
||||
Directory(PathBuf),
|
||||
}
|
||||
|
||||
impl NativeSoFile {
|
||||
impl NativeFile {
|
||||
/// Return the path of a found `.so` file.
|
||||
pub fn path(&self) -> &Path {
|
||||
match &self {
|
||||
NativeSoFile::Symlink(path) => path,
|
||||
NativeSoFile::Regular(path) => path,
|
||||
NativeFile::Symlink(path) | NativeFile::Regular(path) | NativeFile::Directory(path) => {
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,19 +104,16 @@ impl Vst3Module {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the path to the `libyabridge.so` file in `~/.vst3` corresponding to the bridged version
|
||||
/// of this module.
|
||||
pub fn libyabridge_location(&self) -> PathBuf {
|
||||
let mut path = yabridge_vst3_home();
|
||||
path.push(self.module_name());
|
||||
path.push("Contents");
|
||||
path.push("x86_64-linux");
|
||||
path.push(self.native_module_name());
|
||||
path
|
||||
/// Get the path to the Windows VST3 plugin. This can be either a file or a directory depending
|
||||
/// on the type of moudle.
|
||||
pub fn original_path(&self) -> &Path {
|
||||
match &self {
|
||||
Vst3Module::Legacy(path, _) | Vst3Module::Bundle(path, _) => path,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the name of the module as a string. Should be in the format `Plugin Name.vst3`.
|
||||
pub fn module_name(&self) -> &str {
|
||||
pub fn original_module_name(&self) -> &str {
|
||||
match &self {
|
||||
Vst3Module::Legacy(path, _) | Vst3Module::Bundle(path, _) => path
|
||||
.file_name()
|
||||
@@ -123,9 +123,32 @@ impl Vst3Module {
|
||||
}
|
||||
}
|
||||
|
||||
/// `module_name()` but with a `.so` file extension isntead of `.vst3`.
|
||||
pub fn native_module_name(&self) -> String {
|
||||
/// Get the path to the actual `.vst3` module file.
|
||||
pub fn original_module_path(&self) -> PathBuf {
|
||||
match &self {
|
||||
Vst3Module::Legacy(path, _) => path.to_owned(),
|
||||
Vst3Module::Bundle(bundle_home, architecture) => {
|
||||
let mut path = bundle_home.join("Contents");
|
||||
path.push(architecture.vst_arch());
|
||||
path.push(self.original_module_name());
|
||||
|
||||
path
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the path to the bundle in `~/.vst3` corresponding to the bridged version of this module.
|
||||
///
|
||||
/// FIXME: How do we solve naming clashes from the same VST3 plugin being installed to multiple
|
||||
/// Wine prefixes?
|
||||
pub fn yabridge_bundle_home(&self) -> PathBuf {
|
||||
yabridge_vst3_home().join(self.original_module_name())
|
||||
}
|
||||
|
||||
/// Get the path to the `libyabridge.so` file in `~/.vst3` corresponding to the bridged version
|
||||
/// of this module.
|
||||
pub fn yabridge_native_module_path(&self) -> PathBuf {
|
||||
let native_module_name = match &self {
|
||||
Vst3Module::Legacy(path, _) | Vst3Module::Bundle(path, _) => path
|
||||
.with_extension("so")
|
||||
.file_name()
|
||||
@@ -133,15 +156,23 @@ impl Vst3Module {
|
||||
.to_str()
|
||||
.expect("VST3 module name contains invalid UTF-8")
|
||||
.to_owned(),
|
||||
}
|
||||
};
|
||||
|
||||
let mut path = self.yabridge_bundle_home();
|
||||
path.push("Contents");
|
||||
path.push("x86_64-linux");
|
||||
path.push(native_module_name);
|
||||
path
|
||||
}
|
||||
|
||||
/// Get the path to the module. This can be either a file or a directory depending on the type
|
||||
/// of moudle.
|
||||
pub fn path(&self) -> &Path {
|
||||
match &self {
|
||||
Vst3Module::Legacy(path, _) | Vst3Module::Bundle(path, _) => path,
|
||||
}
|
||||
/// Get the path to where we'll symlink `original_module_path`. This is part of the merged VST3
|
||||
/// bundle in `~/.vst3/yabridge`.
|
||||
pub fn yabridge_windows_module_path(&self) -> PathBuf {
|
||||
let mut path = self.yabridge_bundle_home();
|
||||
path.push("Contents");
|
||||
path.push(self.architecture().vst_arch());
|
||||
path.push(self.original_module_name());
|
||||
path
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,21 +198,21 @@ impl SearchResults {
|
||||
/// For every found VST2 plugin and VST3 module, find the associated copy or symlink of
|
||||
/// `libyabridge-{vst2,vst3}.so`. The returned hashmap will contain a `None` value for plugins
|
||||
/// that have not yet been set up.
|
||||
pub fn installation_status(&self) -> BTreeMap<&Path, Option<NativeSoFile>> {
|
||||
let so_files: HashMap<&Path, &NativeSoFile> = self
|
||||
pub fn installation_status(&self) -> BTreeMap<PathBuf, Option<NativeFile>> {
|
||||
let so_files: HashMap<&Path, &NativeFile> = self
|
||||
.so_files
|
||||
.iter()
|
||||
.map(|file| (file.path(), file))
|
||||
.collect();
|
||||
|
||||
// Do this for the VST2 plugins
|
||||
let mut installation_status: BTreeMap<&Path, Option<NativeSoFile>> = self
|
||||
let mut installation_status: BTreeMap<PathBuf, Option<NativeFile>> = self
|
||||
.vst2_files
|
||||
.iter()
|
||||
.map(
|
||||
|path| match so_files.get(path.with_extension("so").as_path()) {
|
||||
Some(&file_type) => (path.as_path(), Some(file_type.clone())),
|
||||
None => (path.as_path(), None),
|
||||
Some(&file_type) => (path.clone(), Some(file_type.clone())),
|
||||
None => (path.clone(), None),
|
||||
},
|
||||
)
|
||||
.collect();
|
||||
@@ -189,29 +220,25 @@ impl SearchResults {
|
||||
// And for VST3 modules. We have not stored the paths to the corresponding `.so` files yet
|
||||
// because they are not in any of the directories we're indexing.
|
||||
installation_status.extend(self.vst3_modules.iter().map(|module| {
|
||||
let install_path = module.libyabridge_location();
|
||||
match install_path.metadata() {
|
||||
Ok(metadata) if metadata.file_type().is_symlink() => {
|
||||
(module.path(), Some(NativeSoFile::Symlink(install_path)))
|
||||
}
|
||||
Ok(_) => (module.path(), Some(NativeSoFile::Regular(install_path))),
|
||||
Err(_) => (module.path(), None),
|
||||
}
|
||||
let module_path = module.yabridge_native_module_path();
|
||||
let install_type = get_file_type(&module_path);
|
||||
(module_path, install_type)
|
||||
}));
|
||||
|
||||
installation_status
|
||||
}
|
||||
|
||||
/// Find all `.so` files in the search results that do not belong to a VST2 plugin `.dll` file.
|
||||
///
|
||||
/// TODO: Also do something similar for VST3 plugins
|
||||
pub fn orphans(&self) -> Vec<&NativeSoFile> {
|
||||
/// We cannot yet do the same thing for VST3 plguins because they will all be installed in
|
||||
/// `~/.vst3`.
|
||||
pub fn vst2_orphans(&self) -> Vec<&NativeFile> {
|
||||
// We need to store these in a map so we can easily entries with corresponding `.dll` files
|
||||
let mut orphans: HashMap<&Path, &NativeSoFile> = self
|
||||
let mut orphans: HashMap<&Path, &NativeFile> = self
|
||||
.so_files
|
||||
.iter()
|
||||
.map(|file| (file.path(), file))
|
||||
.map(|file_type| (file_type.path(), file_type))
|
||||
.collect();
|
||||
|
||||
for vst2_path in &self.vst2_files {
|
||||
orphans.remove(vst2_path.with_extension("so").as_path());
|
||||
}
|
||||
@@ -225,7 +252,7 @@ impl SearchResults {
|
||||
pub fn index(directory: &Path) -> SearchIndex {
|
||||
let mut dll_files: Vec<PathBuf> = Vec::new();
|
||||
let mut vst3_files: Vec<PathBuf> = Vec::new();
|
||||
let mut so_files: Vec<NativeSoFile> = Vec::new();
|
||||
let mut so_files: Vec<NativeFile> = Vec::new();
|
||||
// XXX: We're silently skipping directories and files we don't have permission to read. This
|
||||
// sounds like the expected behavior, but I"m not entirely sure.
|
||||
for (file_idx, entry) in WalkDir::new(directory)
|
||||
@@ -251,9 +278,9 @@ pub fn index(directory: &Path) -> SearchIndex {
|
||||
Some("vst3") => vst3_files.push(entry.into_path()),
|
||||
Some("so") => {
|
||||
if entry.path_is_symlink() {
|
||||
so_files.push(NativeSoFile::Symlink(entry.into_path()));
|
||||
so_files.push(NativeFile::Symlink(entry.into_path()));
|
||||
} else {
|
||||
so_files.push(NativeSoFile::Regular(entry.into_path()));
|
||||
so_files.push(NativeFile::Regular(entry.into_path()));
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
|
||||
@@ -30,6 +30,7 @@ use std::process::{Command, Stdio};
|
||||
use textwrap::Wrapper;
|
||||
|
||||
use crate::config::{self, Config, KnownConfig, YABRIDGE_HOST_EXE_NAME};
|
||||
use crate::files::NativeFile;
|
||||
|
||||
/// (Part of) the expected output when running `yabridge-host.exe`. Used to verify that everything's
|
||||
/// working correctly. We'll only match this prefix so we can modify the exact output at a later
|
||||
@@ -47,6 +48,17 @@ pub fn copy<P: AsRef<Path>, Q: AsRef<Path>>(from: P, to: Q) -> Result<u64> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Wrapper around [`std::fs::create_dir_all()`](std::fs::create_dir_all) with a human readable
|
||||
/// error message.
|
||||
pub fn create_dir_all<P: AsRef<Path>>(path: P) -> Result<()> {
|
||||
fs::create_dir_all(&path).with_context(|| {
|
||||
format!(
|
||||
"Error creating directories for '{}'",
|
||||
path.as_ref().display(),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Wrapper around [`std::fs::remove_file()`](std::fs::remove_file) with a human readable error
|
||||
/// message.
|
||||
pub fn remove_file<P: AsRef<Path>>(path: P) -> Result<()> {
|
||||
@@ -66,6 +78,20 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> Result<()> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the type of a file, if it exists.
|
||||
pub fn get_file_type(path: &Path) -> Option<NativeFile> {
|
||||
match path.metadata() {
|
||||
Ok(metadata) if metadata.file_type().is_symlink() => {
|
||||
Some(NativeFile::Symlink(path.to_owned()))
|
||||
}
|
||||
Ok(metadata) if metadata.file_type().is_dir() => {
|
||||
Some(NativeFile::Directory(path.to_owned()))
|
||||
}
|
||||
Ok(_) => Some(NativeFile::Regular(path.to_owned())),
|
||||
Err(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Hash the conetnts of a file as an `i64` using Rust's built in hasher. Collisions are not a big
|
||||
/// issue in our situation so we can get away with this.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user