use std::path::PathBuf;
use thiserror::Error;
use crate::{config::Config, options::DEFAULT_USER_DATA_DIR, utils};
#[derive(Error, Debug)]
pub enum InitializationError {
#[error("Failed to create directory: '{0}'. {1}")]
DirectoryCreation(PathBuf, String),
#[error("Failed to create file: '{0}'. {1}")]
FileCreation(PathBuf, String),
#[error("Failed to create symlink. {0}")]
Symlink(String),
}
pub enum InitializationState {
AlreadyInitialized,
Initialized,
}
pub fn init(config: &Config) -> Result<(), InitializationError> {
let state = setup_midenup(config)?;
match state {
InitializationState::Initialized => crate::info!(
"midenup was successfully initialized in: {}",
config.midenup_home.as_path().display()
),
InitializationState::AlreadyInitialized => {
crate::info!(
"midenup already initialized in: {}",
config.midenup_home.as_path().display()
)
},
}
Ok(())
}
pub fn setup_midenup(config: &Config) -> Result<InitializationState, InitializationError> {
let mut state = InitializationState::AlreadyInitialized;
let midenhome_dir = &config.midenup_home;
if !midenhome_dir.exists() {
std::fs::create_dir_all(midenhome_dir).map_err(|e| {
InitializationError::DirectoryCreation(midenhome_dir.clone(), e.to_string())
})?;
state = InitializationState::Initialized;
}
let toolchains_dir = crate::paths::toolchains_dir(&config.midenup_home);
if !toolchains_dir.exists() {
std::fs::create_dir_all(&toolchains_dir).map_err(|e| {
InitializationError::DirectoryCreation(toolchains_dir.clone(), e.to_string())
})?;
state = InitializationState::Initialized;
}
let publications_dir = crate::paths::publications_dir(&config.midenup_home);
if !publications_dir.exists() {
std::fs::create_dir_all(&publications_dir).map_err(|e| {
InitializationError::DirectoryCreation(publications_dir.clone(), e.to_string())
})?;
state = InitializationState::Initialized;
}
{
let cargo_bin = config.cargo_home.join("bin");
if !cargo_bin.exists() {
std::fs::create_dir_all(&cargo_bin).map_err(|e| {
InitializationError::DirectoryCreation(cargo_bin.clone(), e.to_string())
})?;
}
let current_exe =
std::env::current_exe().expect("unable to get location of current executable");
let miden_exe = cargo_bin.join("miden");
if !miden_exe.exists() {
utils::fs::symlink(&miden_exe, ¤t_exe)
.map_err(|e| InitializationError::Symlink(e.to_string()))?;
state = InitializationState::Initialized;
}
let miden_is_accessible = std::env::var_os("PATH")
.map(|path| {
std::env::split_paths(&path).any(|dir| {
let candidate = dir.join("miden");
std::fs::symlink_metadata(&candidate).is_ok() && candidate.exists()
})
})
.unwrap_or(false);
if !miden_is_accessible {
if std::env::var(DEFAULT_USER_DATA_DIR).is_err() {
state = InitializationState::Initialized;
}
crate::warn!(
"could not find the `miden` executable in the system's PATH.
The `miden` symlink was placed in $CARGO_HOME/bin ({cargo_bin_display}), which should already be \
in your PATH if you have Rust installed. If not, ensure $CARGO_HOME/bin is in \
your PATH.
Add the directory containing the `miden` symlink to your shell's profile file. For the default
Rust installation this is usually:
export PATH=\"{cargo_bin_display}:$PATH\"
On macOS with zsh, add that line to ~/.zprofile (create the file first if it does not exist),
then start a new shell or run:
source ~/.zprofile
",
cargo_bin_display = cargo_bin.display(),
);
}
}
Ok(state)
}