Skip to content

Commit

Permalink
feat(homebrew operation): ✨ update PATH with installed formulae (#259)
Browse files Browse the repository at this point in the history
This allows to make sure that any tool installed for a given repository
is made available in the context of that repository. Prior to this
change, it was expected that the homebrew bin path was loaded in the
PATH environment variable by the user.

This slightly changes the update cache format to store the formulae bin
paths. A new `--no-cache` parameter has been added to `omni up` in order
to allow running `omni up` without taking the cache into account. This
option only works for homebrew for now.

Closes #256
  • Loading branch information
xaf authored Dec 6, 2023
1 parent 81625c6 commit 50b7df3
Show file tree
Hide file tree
Showing 13 changed files with 523 additions and 159 deletions.
201 changes: 167 additions & 34 deletions src/internal/cache/homebrew_operation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ use crate::internal::cache::handler::exclusive;
use crate::internal::cache::handler::shared;
use crate::internal::cache::loaders::get_homebrew_operation_cache;
use crate::internal::cache::loaders::set_homebrew_operation_cache;
use crate::internal::cache::offsetdatetime_hashmap;
use crate::internal::cache::utils;
use crate::internal::cache::utils::Empty;
use crate::internal::cache::CacheObject;
Expand Down Expand Up @@ -96,6 +95,16 @@ impl HomebrewOperationCache {
inserted
}

pub fn homebrew_bin_path(&self) -> Option<String> {
self.update_cache.homebrew_bin_path()
}

pub fn set_homebrew_bin_path(&mut self, bin_path: String) {
self.update_cache
.set_homebrew_bin_path(bin_path.to_string());
self.updated();
}

pub fn updated_homebrew(&mut self) {
self.update_cache.updated_homebrew();
self.updated();
Expand All @@ -106,6 +115,32 @@ impl HomebrewOperationCache {
self.update_cache.should_update_homebrew(Duration::days(1))
}

pub fn homebrew_install_bin_path(
&self,
install_name: &str,
install_version: Option<String>,
is_cask: bool,
) -> Option<String> {
self.update_cache
.homebrew_install_bin_path(install_name, install_version, is_cask)
}

pub fn set_homebrew_install_bin_path(
&mut self,
install_name: &str,
install_version: Option<String>,
is_cask: bool,
bin_path: String,
) {
self.update_cache.set_homebrew_install_bin_path(
install_name,
install_version,
is_cask,
bin_path.to_string(),
);
self.updated();
}

pub fn updated_install(
&mut self,
install_name: &str,
Expand Down Expand Up @@ -154,7 +189,7 @@ impl HomebrewOperationCache {
install_version,
is_cask,
// TODO: add configuration option for the duration?
Duration::minutes(5),
Duration::hours(12),
)
}
}
Expand Down Expand Up @@ -220,31 +255,19 @@ pub struct HomebrewTapped {
#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HomebrewOperationUpdateCache {
#[serde(
default = "utils::origin_of_time",
with = "time::serde::rfc3339",
skip_serializing_if = "utils::is_origin_of_time"
default = "HomebrewOperationUpdateCacheHomebrew::new",
skip_serializing_if = "HomebrewOperationUpdateCacheHomebrew::is_empty"
)]
pub homebrew_updated_at: OffsetDateTime,
#[serde(
default = "HashMap::new",
skip_serializing_if = "HashMap::is_empty",
with = "offsetdatetime_hashmap"
)]
pub install_updated_at: HashMap<String, OffsetDateTime>,
#[serde(
default = "HashMap::new",
skip_serializing_if = "HashMap::is_empty",
with = "offsetdatetime_hashmap"
)]
pub install_checked_at: HashMap<String, OffsetDateTime>,
pub homebrew: HomebrewOperationUpdateCacheHomebrew,
#[serde(default = "HashMap::new", skip_serializing_if = "HashMap::is_empty")]
pub install: HashMap<String, HomebrewOperationUpdateCacheInstall>,
}

impl HomebrewOperationUpdateCache {
pub fn new() -> Self {
Self {
homebrew_updated_at: utils::origin_of_time(),
install_updated_at: HashMap::new(),
install_checked_at: HashMap::new(),
homebrew: HomebrewOperationUpdateCacheHomebrew::new(),
install: HashMap::new(),
}
}

Expand All @@ -267,11 +290,50 @@ impl HomebrewOperationUpdateCache {
}

pub fn updated_homebrew(&mut self) {
self.homebrew_updated_at = OffsetDateTime::now_utc();
self.homebrew.updated_at = OffsetDateTime::now_utc();
}

pub fn should_update_homebrew(&self, expire_after: Duration) -> bool {
(self.homebrew_updated_at + expire_after) < OffsetDateTime::now_utc()
(self.homebrew.updated_at + expire_after) < OffsetDateTime::now_utc()
}

pub fn homebrew_bin_path(&self) -> Option<String> {
self.homebrew.bin_path.clone()
}

pub fn set_homebrew_bin_path(&mut self, bin_path: String) {
self.homebrew.bin_path = Some(bin_path);
}

pub fn homebrew_install_bin_path(
&self,
install_name: &str,
install_version: Option<String>,
is_cask: bool,
) -> Option<String> {
let key = self.install_key(install_name, install_version, is_cask);
if let Some(install) = self.install.get(&key) {
install.bin_path.clone()
} else {
None
}
}

pub fn set_homebrew_install_bin_path(
&mut self,
install_name: &str,
install_version: Option<String>,
is_cask: bool,
bin_path: String,
) {
let key = self.install_key(install_name, install_version, is_cask);
if let Some(install) = self.install.get_mut(&key) {
install.bin_path = Some(bin_path);
} else {
let mut install = HomebrewOperationUpdateCacheInstall::new();
install.bin_path = Some(bin_path);
self.install.insert(key, install);
}
}

pub fn updated_homebrew_install(
Expand All @@ -281,8 +343,13 @@ impl HomebrewOperationUpdateCache {
is_cask: bool,
) {
let key = self.install_key(install_name, install_version, is_cask);
self.install_updated_at
.insert(key, OffsetDateTime::now_utc());
if let Some(install) = self.install.get_mut(&key) {
install.updated_at = OffsetDateTime::now_utc();
} else {
let mut install = HomebrewOperationUpdateCacheInstall::new();
install.updated_at = OffsetDateTime::now_utc();
self.install.insert(key, install);
}
}

pub fn should_update_homebrew_install(
Expand All @@ -293,8 +360,8 @@ impl HomebrewOperationUpdateCache {
expire_after: Duration,
) -> bool {
let key = self.install_key(install_name, install_version, is_cask);
if let Some(install_updated_at) = self.install_updated_at.get(&key) {
(*install_updated_at + expire_after) < OffsetDateTime::now_utc()
if let Some(install) = self.install.get(&key) {
(install.updated_at + expire_after) < OffsetDateTime::now_utc()
} else {
true
}
Expand All @@ -307,8 +374,13 @@ impl HomebrewOperationUpdateCache {
is_cask: bool,
) {
let key = self.install_key(install_name, install_version, is_cask);
self.install_checked_at
.insert(key, OffsetDateTime::now_utc());
if let Some(install) = self.install.get_mut(&key) {
install.checked_at = OffsetDateTime::now_utc();
} else {
let mut install = HomebrewOperationUpdateCacheInstall::new();
install.checked_at = OffsetDateTime::now_utc();
self.install.insert(key, install);
}
}

pub fn should_check_homebrew_install(
Expand All @@ -319,8 +391,8 @@ impl HomebrewOperationUpdateCache {
expire_after: Duration,
) -> bool {
let key = self.install_key(install_name, install_version, is_cask);
if let Some(install_checked_at) = self.install_checked_at.get(&key) {
(*install_checked_at + expire_after) < OffsetDateTime::now_utc()
if let Some(install) = self.install.get(&key) {
(install.checked_at + expire_after) < OffsetDateTime::now_utc()
} else {
true
}
Expand All @@ -329,8 +401,69 @@ impl HomebrewOperationUpdateCache {

impl Empty for HomebrewOperationUpdateCache {
fn is_empty(&self) -> bool {
self.install_updated_at.is_empty()
&& self.install_checked_at.is_empty()
&& self.homebrew_updated_at == utils::origin_of_time()
self.install.is_empty() && self.homebrew.is_empty()
}
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HomebrewOperationUpdateCacheHomebrew {
#[serde(
default = "utils::origin_of_time",
with = "time::serde::rfc3339",
skip_serializing_if = "utils::is_origin_of_time"
)]
pub updated_at: OffsetDateTime,
#[serde(skip_serializing_if = "Option::is_none")]
pub bin_path: Option<String>,
}

impl HomebrewOperationUpdateCacheHomebrew {
pub fn new() -> Self {
Self {
updated_at: utils::origin_of_time(),
bin_path: None,
}
}
}

impl Empty for HomebrewOperationUpdateCacheHomebrew {
fn is_empty(&self) -> bool {
self.updated_at == utils::origin_of_time()
}
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct HomebrewOperationUpdateCacheInstall {
#[serde(
default = "utils::origin_of_time",
with = "time::serde::rfc3339",
skip_serializing_if = "utils::is_origin_of_time"
)]
pub updated_at: OffsetDateTime,
#[serde(
default = "utils::origin_of_time",
with = "time::serde::rfc3339",
skip_serializing_if = "utils::is_origin_of_time"
)]
pub checked_at: OffsetDateTime,
#[serde(skip_serializing_if = "Option::is_none")]
pub bin_path: Option<String>,
}

impl HomebrewOperationUpdateCacheInstall {
pub fn new() -> Self {
Self {
updated_at: utils::origin_of_time(),
checked_at: utils::origin_of_time(),
bin_path: None,
}
}
}

impl Empty for HomebrewOperationUpdateCacheInstall {
fn is_empty(&self) -> bool {
self.updated_at == utils::origin_of_time()
&& self.checked_at == utils::origin_of_time()
&& self.bin_path.is_none()
}
}
31 changes: 26 additions & 5 deletions src/internal/cache/up_environments.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::collections::BTreeMap;
use std::collections::BTreeSet;
use std::collections::HashMap;
use std::io;
use std::path::PathBuf;

use serde::Deserialize;
use serde::Serialize;
Expand All @@ -26,6 +27,10 @@ pub struct UpEnvironmentsCache {
}

impl UpEnvironmentsCache {
fn updated(&mut self) {
self.updated_at = OffsetDateTime::now_utc();
}

pub fn set_env_vars(&mut self, workdir_id: &str, env_vars: HashMap<String, String>) -> bool {
if let Some(env) = self.env.get_mut(workdir_id) {
env.env_vars = env_vars;
Expand All @@ -34,7 +39,7 @@ impl UpEnvironmentsCache {
env.env_vars = env_vars;
self.env.insert(workdir_id.to_string(), env);
}
self.updated_at = OffsetDateTime::now_utc();
self.updated();
true
}

Expand All @@ -46,7 +51,20 @@ impl UpEnvironmentsCache {
env.env_vars.insert(key.to_string(), value.to_string());
self.env.insert(workdir_id.to_string(), env);
}
self.updated_at = OffsetDateTime::now_utc();
self.updated();
true
}

pub fn add_path(&mut self, workdir_id: &str, path: PathBuf) -> bool {
if let Some(env) = self.env.get_mut(workdir_id) {
env.paths.retain(|p| p != &path);
env.paths.push(path);
} else {
let mut env = UpEnvironment::new();
env.paths.push(path);
self.env.insert(workdir_id.to_string(), env);
}
self.updated();
true
}

Expand Down Expand Up @@ -91,8 +109,7 @@ impl UpEnvironmentsCache {
});
}

self.updated_at = OffsetDateTime::now_utc();

self.updated();
true
}

Expand All @@ -110,7 +127,8 @@ impl UpEnvironmentsCache {
}

self.env.remove(workdir_id);
self.updated_at = OffsetDateTime::now_utc();

self.updated();
true
}
}
Expand Down Expand Up @@ -152,6 +170,8 @@ impl CacheObject for UpEnvironmentsCache {
pub struct UpEnvironment {
#[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")]
pub versions: Vec<UpVersion>,
#[serde(default = "Vec::new", skip_serializing_if = "Vec::is_empty")]
pub paths: Vec<PathBuf>,
#[serde(default = "HashMap::new", skip_serializing_if = "HashMap::is_empty")]
pub env_vars: HashMap<String, String>,
}
Expand All @@ -160,6 +180,7 @@ impl UpEnvironment {
pub fn new() -> Self {
Self {
versions: Vec::new(),
paths: Vec::new(),
env_vars: HashMap::new(),
}
}
Expand Down
Loading

0 comments on commit 50b7df3

Please sign in to comment.