// Copyright (C) 2018 Jakob L. Kreuze, All Rights Reserved.
//
// This file is part of rebuild.
//
// rebuild 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.
//
// rebuild 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
// rebuild. If not, see .
use std::env;
use std::error::Error;
use std::path::Path;
/// Manager for a list of "search paths" on the filesystem, for the purpose of
/// resolving the absolute path of data files that have several possible
/// locations. See the documentation of 'find' for more information on the
/// default search paths.
#[derive(Debug)]
pub struct PathManager {
search: Vec,
}
impl PathManager {
// TODO: Implement the following additional search paths:
// - The steam paths on GNU/Linux.
// - The "standard" paths for OSX (See G_AddSearchPaths)
// - The "standard" paths for Windows (See G_AddSearchPaths)
// - Those specified on the command-line.
// - See the CommandPaths and CommandGrps globals in common.cpp
// - The "app dir" on OSX.
// - PROPERLY add the CWD.
// - $HOME/apps/rebuild/ (?)
// - $HOME/.config/rebuild/
// - Those specified via DUKE3DGRP environment variable.
// - See JBF 20031220
/// Create a new PathManager and initialize the search path list with
/// acceptable defaults. See the documentation of 'find' for more
/// information on the default search paths.
pub fn new() -> PathManager {
let mut result = PathManager { search: Vec::new() };
let directories = vec![
".",
"/usr/share/games/jfduke3d",
"/usr/local/share/games/jfduke3d",
"/usr/share/games/eduke32",
"/usr/local/share/games/eduke32",
"/usr/share/games/rebuild",
"/usr/local/share/games/rebuild",
];
for directory in directories.iter() {
result.add_path(directory).ok();
}
let directories = vec![
"$HOME/.rebuild",
];
if let Some(home) = env::home_dir() {
if let Some(home) = home.to_str() {
for path in directories.iter() {
let path = String::from(*path).replace("$HOME", home);
result.add_path(&path).ok();
}
}
}
result
}
/// Add an additional path for searching.
///
/// # Errors
///
/// A return value of 'Err' indicates that the given path did not exist.
pub fn add_path(&mut self, path: &str) -> Result<(), Box> {
if Path::new(&path).exists() {
self.search.push(String::from(path));
} else {
bail!("Path does not exist");
}
Ok(())
}
/// Go through the search path list in order and return the first existing
/// path with the the given name, or None if no such file was found. The
/// default search path order is:
///
/// - ".",
/// - "/usr/local/share/games/rebuild",
/// - "/usr/share/games/rebuild",
/// - "/usr/local/share/games/eduke32",
/// - "/usr/share/games/eduke32",
/// - "/usr/local/share/games/jfduke3d",
/// - "/usr/share/games/jfduke3d",
/// - "$HOME/.rebuild",
///
/// This is followed by any additional paths in the search path list tha`t
/// were added by 'add_path'.
pub fn find(&self, name: &str) -> Option {
for directory in self.search.iter() {
let path = format!("{}/{}", directory, name);
if Path::new(&path).exists() {
return Some(path);
}
}
None
}
}