[yabridgectl] Index .vst3 files

It doesn't actually identify VST3 modules yet though.
This commit is contained in:
Robbert van der Helm
2020-12-23 18:39:22 +01:00
parent 3dc1b1585b
commit 3d27426b9d
3 changed files with 92 additions and 70 deletions
+3 -3
View File
@@ -43,7 +43,7 @@ pub fn remove_directory(config: &mut Config, path: &Path) -> Result<()> {
// Ask the user to remove any leftover files to prevent possible future problems and out of date
// copies
let orphan_files = files::index_so_files(path);
let orphan_files = files::index(path).so_files;
if !orphan_files.is_empty() {
println!(
"Warning: Found {} leftover .so files still in this directory:",
@@ -84,7 +84,7 @@ pub fn list_directories(config: &Config) -> Result<()> {
/// Print the current configuration and the installation status for all found plugins.
pub fn show_status(config: &Config) -> Result<()> {
let results = config
.index_directories()
.search_directories()
.context("Failure while searching for plugins")?;
println!(
@@ -171,7 +171,7 @@ pub fn do_sync(config: &mut Config, options: &SyncOptions) -> Result<()> {
println!("Using '{}'\n", files.libyabridge_vst2.display());
let results = config
.index_directories()
.search_directories()
.context("Failure while searching for plugins")?;
// Keep track of some global statistics
+6 -2
View File
@@ -255,10 +255,14 @@ impl Config {
/// Search for VST2 and VST3 plugins in all of the registered plugins directories. This will
/// return an error if `winedump` could not be called.
pub fn index_directories(&self) -> Result<BTreeMap<&Path, SearchResults>> {
pub fn search_directories(&self) -> Result<BTreeMap<&Path, SearchResults>> {
self.plugin_dirs
.par_iter()
.map(|path| files::index(path).map(|search_results| (path.as_path(), search_results)))
.map(|path| {
files::index(path)
.search()
.map(|search_results| (path.as_path(), search_results))
})
.collect()
}
}
+83 -65
View File
@@ -36,9 +36,24 @@ pub struct SearchResults {
pub vst2_files: Vec<PathBuf>,
/// Absolute paths to found VST3 modules. Either legacy `.vst3` DLL files or VST 3.6.10 bundles.
pub vst3_modules: Vec<Vst3Module>,
/// `.dll` files skipped over during the serach. Used for printing statistics and shown when
/// `.dll` files skipped over during the search. Used for printing statistics and shown when
/// running `yabridgectl sync --verbose`.
pub skipped_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>,
}
/// The results of the first step of the search process. We'll first index all possibly relevant
/// files in a directory before filtering them down to a `SearchResults` object.
#[derive(Debug)]
pub struct SearchIndex {
/// Any `.dll` file.
pub dll_files: Vec<PathBuf>,
/// Any `.vst3` file or directory. This can be either a legacy `.vst3` DLL module or a VST
/// 3.6.10 module (or some kind of random other file, of course).
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>,
@@ -68,6 +83,8 @@ impl SearchResults {
///
/// These two functions could be combined into a single function, but speed isn't really an
/// issue here and it's a bit more organized this way.
///
/// TODO: Do this for VST3 plugins
pub fn installation_status(&self) -> BTreeMap<&Path, Option<&NativeSoFile>> {
let so_files: HashMap<&Path, &NativeSoFile> = self
.so_files
@@ -87,6 +104,8 @@ impl SearchResults {
}
/// 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 need to store these in a map so we can easily entries with corresponding `.dll` files
let mut orphans: HashMap<&Path, &NativeSoFile> = self
@@ -98,7 +117,7 @@ impl SearchResults {
orphans.remove(vst2_path.with_extension("so").as_path());
}
orphans.into_iter().map(|(_, file)| file).collect()
orphans.values().cloned().collect()
}
}
@@ -112,69 +131,11 @@ impl NativeSoFile {
}
}
/// Search for Windows VST2 plugins and .so files under a directory. This will return an error if
/// the directory does not exist, or if `winedump` could not be found.
pub fn index(directory: &Path) -> Result<SearchResults> {
// First we'll find all .dll and .so files in the directory
let (dll_files, so_files) = find_files(directory);
lazy_static! {
static ref VST2_AUTOMATON: AhoCorasick =
AhoCorasick::new_auto_configured(&["VSTPluginMain", "main", "main_plugin"]);
}
// THne we'll figure out which `.dll` files are VST2 plugins and which should be skipped by
// checking whether the file contains one of the VST2 entry point functions. The boolean flag in
// this vector indicates whether it is a VST2 plugin.
let dll_files: Vec<(PathBuf, bool)> = dll_files
.into_par_iter()
.map(|path| {
let exported_functions = Command::new("winedump")
.arg("-j")
.arg("export")
.arg(&path)
.output()
.context(
"Could not find 'winedump'. In some distributions this is part of a seperate \
Wine tools package.",
)?
.stdout;
Ok((path, VST2_AUTOMATON.is_match(exported_functions)))
})
.collect::<Result<_>>()?;
let mut vst2_files = Vec::new();
let mut skipped_files = Vec::new();
for (path, is_vst2_plugin) in dll_files {
if is_vst2_plugin {
vst2_files.push(path);
} else {
skipped_files.push(path);
}
}
Ok(SearchResults {
vst2_files,
skipped_files,
so_files,
// TODO: Search for VST3 modules
vst3_modules: Vec::new(),
})
}
/// THe same as [index()](index), but only report found `.so` files. This avoids unnecesarily
/// filtering the found `.dll` files.
pub fn index_so_files(directory: &Path) -> Vec<NativeSoFile> {
let (_, so_files) = find_files(directory);
so_files
}
/// Find all `.dll` and `.so` files under a directory. The results are a pair of `(dll_files,
/// so_files)`.
fn find_files(directory: &Path) -> (Vec<PathBuf>, Vec<NativeSoFile>) {
/// Find all `.dll`, `.vst3` and `.so` files under a directory. These results can be filtered down
/// to actual VST2 plugins and VST3 modules using `search()`.
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();
// 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.
@@ -198,6 +159,7 @@ fn find_files(directory: &Path) -> (Vec<PathBuf>, Vec<NativeSoFile>) {
match entry.path().extension().and_then(|os| os.to_str()) {
Some("dll") => dll_files.push(entry.into_path()),
Some("vst3") => vst3_files.push(entry.into_path()),
Some("so") => {
if entry.path_is_symlink() {
so_files.push(NativeSoFile::Symlink(entry.into_path()));
@@ -209,5 +171,61 @@ fn find_files(directory: &Path) -> (Vec<PathBuf>, Vec<NativeSoFile>) {
}
}
(dll_files, so_files)
SearchIndex {
dll_files,
vst3_files,
so_files,
}
}
impl SearchIndex {
/// Filter these indexing results down to actual VST2 plugins and VST3 modules. This will skip
/// all invalid files, such as regular `.dll` libraries. Will return an error if `winedump`
/// could not be found.
pub fn search(self) -> Result<SearchResults> {
lazy_static! {
static ref VST2_AUTOMATON: AhoCorasick =
AhoCorasick::new_auto_configured(&["VSTPluginMain", "main", "main_plugin"]);
}
// THne we'll figure out which `.dll` files are VST2 plugins and which should be skipped by
// checking whether the file contains one of the VST2 entry point functions. The boolean flag in
// this vector indicates whether it is a VST2 plugin.
let dll_files: Vec<(PathBuf, bool)> = self
.dll_files
.into_par_iter()
.map(|path| {
let exported_functions = Command::new("winedump")
.arg("-j")
.arg("export")
.arg(&path)
.output()
.context(
"Could not find 'winedump'. In some distributions this is part of a seperate \
Wine tools package.",
)?
.stdout;
Ok((path, VST2_AUTOMATON.is_match(exported_functions)))
})
.collect::<Result<_>>()?;
let mut vst2_files: Vec<PathBuf> = Vec::new();
let mut skipped_files: Vec<PathBuf> = Vec::new();
for (path, is_vst2_plugin) in dll_files {
if is_vst2_plugin {
vst2_files.push(path);
} else {
skipped_files.push(path);
}
}
Ok(SearchResults {
vst2_files,
// TODO: Search for VST3 modules
vst3_modules: Vec::new(),
skipped_files,
so_files: self.so_files,
})
}
}