Skip to content

Commit

Permalink
config: Check if a theme repo is installed (#20)
Browse files Browse the repository at this point in the history
Updates Repo::compare() to check if themes are already installed and
update the theme directory accordingly in repo config.

Adds Repo::installed_themes() which returns a list of all the existing
themes by their names. It looks for "themes" directory under a given
config directory path for installed themes. The symlinks are traversed
to check the destination to be a theme directory. The "current" theme
directory is ignored.
  • Loading branch information
darkowlzz authored Sep 6, 2021
1 parent 8119960 commit 6957c63
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 2 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,4 @@ pretty_env_logger = "0.4.0"
colored = "2.0.0"
git2 = "0.13.17"
edit-distance = "2.1.0"
tempfile = "3.2.0"
108 changes: 106 additions & 2 deletions src/models/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use std::io::Write;
use std::path::Path;
use xdg::BaseDirectories;

const THEMES_DIR: &str = "themes";

/// Contains a vector of all global repositories.
#[derive(Serialize, Deserialize, Debug, Clone, Default)]
pub struct Config {
Expand Down Expand Up @@ -134,8 +136,20 @@ impl Repo {
pub fn compare(&mut self, theme_wrap: TempThemes) -> Result<&Repo> {
let themes = theme_wrap.theme;
trace!("Comparing themes");
//iterate over all themes, and update/add if needed
for tema in themes {

// Get a list of existing themes.
let path = BaseDirectories::with_prefix("leftwm")?;
let base_config_path = String::from(path.get_config_home().to_str().unwrap());
let existing_themes = Repo::installed_themes(base_config_path).unwrap();
let themes_dir = path.get_config_home().join(THEMES_DIR);

// Iterate over all the themes, and update/add if needed.
for mut tema in themes {
// Check if the theme is already installed and update the theme
// directory attribute.
if existing_themes.contains(&tema.name.clone()) {
tema.directory = Some(themes_dir.join(tema.name.clone()));
}
Repo::update_or_append(self, &tema);
}
Ok(self)
Expand All @@ -157,11 +171,101 @@ impl Repo {
target_theme.version = theme.version.clone();
target_theme.leftwm_versions = theme.leftwm_versions.clone();
target_theme.dependencies = theme.dependencies.clone();
target_theme.directory = theme.directory.clone();
}
// o/w insert a new leaf at the end
None => {
repo.themes.push(theme.clone());
}
}
}

// Returns a list of all the installed theme names under a given config
// path.
fn installed_themes(config_path: String) -> Result<Vec<String>> {
let mut result: Vec<String> = Vec::new();

let theme_path = Path::new(&config_path).join(THEMES_DIR);

// Return empty result if the themes directory is not present.
if !theme_path.exists() {
return Ok(result);
}

// Read the themes directory, iterate through the entries, determine
// which of them are theme directories and add them into the result.
let paths = fs::read_dir(theme_path).unwrap();
for path in paths {
let p = path.unwrap();
// NOTE: For symlinks, metadata() traverses any symlinks and queries
// the metadata information from the destination.
let metadata = fs::metadata(p.path())?;
let file_type = metadata.file_type();

// Only process directories.
if !file_type.is_dir() {
continue;
}

// Ignore the "current" directory for installed theme list.
let current_dir = String::from("current");
let target_path = p.path();
if target_path
.file_name()
.unwrap()
.to_str()
.unwrap()
.eq(&current_dir)
{
continue;
}

// Extract only the theme name for the result.
let theme_name = target_path.file_name().unwrap();
result.push(String::from(theme_name.to_str().unwrap()));
}

Ok(result)
}
}

#[cfg(test)]
mod test {
use super::*;
use std::os::unix::fs as unix_fs;

#[test]
fn test_installed_themes() {
// Create a temporary directory as the config path and create the
// directory layout within it for themes.
let tmpdir = tempfile::tempdir().unwrap();
let themes_dir = tmpdir.path().join(THEMES_DIR);
let theme1 = themes_dir.join("test-theme1");
let theme2 = themes_dir.join("test-theme2");
let unrelated_file = themes_dir.join("some-file");
assert!(fs::create_dir_all(&theme1).is_ok());
assert!(fs::create_dir_all(&theme2).is_ok());
assert!(File::create(unrelated_file).is_ok());

// Create current theme as a symlink to an existing theme.
let current = themes_dir.join("current");
let src = theme2.to_str().unwrap();
let dst = current.to_str().unwrap();
assert!(unix_fs::symlink(src, dst).is_ok());

let config_dir = tmpdir.path().to_str().unwrap();
let result = Repo::installed_themes(String::from(config_dir));
assert!(result.is_ok());
assert_eq!(
result.unwrap(),
vec!["test-theme2".to_string(), "test-theme1".to_string(),],
)
}

#[test]
fn test_installed_themes_no_themes_dir() {
let tmpdir = tempfile::tempdir().unwrap();
let config_dir = tmpdir.path().to_str().unwrap();
assert!(Repo::installed_themes(String::from(config_dir)).is_ok());
}
}

0 comments on commit 6957c63

Please sign in to comment.