Skip to content

Commit

Permalink
code refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
azomDev committed Nov 26, 2024
1 parent 007d124 commit 5a74e8f
Show file tree
Hide file tree
Showing 16 changed files with 184 additions and 190 deletions.
10 changes: 4 additions & 6 deletions src/commands/env_add.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
use crate::{
env_utils::{
download_package, find_config, find_matching_package_version, read_config, write_config,
},
utils::{abort, get_package_path},
use crate::utils::{
abort, download_package, find_matching_package_version, get_package_path, get_project_root,
read_config, write_config,
};
use semver::VersionReq;
use std::fs;

pub fn env_add(name: &str, version: &VersionReq) {
let projet_path = find_config();
let projet_path = get_project_root();
let mut config = read_config(&projet_path);

let package = find_matching_package_version(name, version);
Expand Down
11 changes: 5 additions & 6 deletions src/commands/env_init.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use crate::utils::{abort, write_config, Config};
use semver::Version;

use crate::{
env_utils::{create_config, write_config},
utils::abort,
};
use std::{env, fs};

pub fn env_init(version: Version) {
let config = create_config(version);
let config = Config {
python: version,
packages: toml::Table::new(),
};

let project_path = match env::current_dir() {
Ok(dir) => dir,
Expand Down
4 changes: 2 additions & 2 deletions src/commands/env_pkgs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::env_utils::{find_config, read_config};
use crate::utils::{get_project_root, read_config};

pub fn env_pkgs() {
let project_path = find_config();
let project_path = get_project_root();

let config = read_config(&project_path);

Expand Down
6 changes: 3 additions & 3 deletions src/commands/env_sync.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
use crate::constants::ENV_DIR_NAME;
use crate::env_utils::{create_virtual_env, find_config, read_config};
use crate::utils::{create_or_update_virtual_env, get_project_root, read_config};

pub fn env_sync() {
let projet_path = find_config();
let projet_path = get_project_root();
let config = read_config(&projet_path);

create_virtual_env(config, &projet_path.join(ENV_DIR_NAME));
create_or_update_virtual_env(config, &projet_path.join(ENV_DIR_NAME));

println!("Installation complete!");
}
10 changes: 4 additions & 6 deletions src/commands/pen_activate.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
use crate::constants::ENV_DIR_NAME;
use crate::{
env_utils::{find_config, read_config},
utils::abort,
};
use crate::utils::{abort, get_project_root, read_config};
use std::process;

pub fn pen_activate() {
let project_path = find_config();
let project_path = get_project_root();
let config = read_config(&project_path);

let command = format!(
Expand Down Expand Up @@ -34,10 +31,11 @@ pub fn pen_activate() {
$SHELL
"#,
project_path.join(ENV_DIR_NAME).to_string_lossy(),
project_path.join(ENV_DIR_NAME).to_string_lossy(), // todo .display() instead???
config.python
);

// todo make it work with plain sh
match process::Command::new("bash").arg("-c").arg(command).spawn() {
Ok(mut child) => child.wait().expect("Child process wasn't running."),
Err(e) => abort("Failed to start shell.", Some(&e)),
Expand Down
3 changes: 1 addition & 2 deletions src/constants.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
#![allow(dead_code)]

use crate::utils::abort;
use home;
use std::{path::PathBuf, sync::LazyLock};

pub static ENV_DIR_NAME: &str = ".venv";
pub static CONFIG_FILE_NAME: &str = "pen.toml";
// pub static UPDATE_SCRIPT_URL: &str = "todo";

pub static HOME_DIR: LazyLock<PathBuf> = LazyLock::new(|| match home::home_dir() {
Expand Down
2 changes: 0 additions & 2 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ use utils::abort;

mod commands;
mod constants;
mod env_utils;
mod py_utils;
mod utils;

// todo a big question i have is should we not use abort and instead return errors and not exit whenever in the program?
Expand Down
39 changes: 6 additions & 33 deletions src/env_utils/config.rs → src/utils/env_utils/config.rs
Original file line number Diff line number Diff line change
@@ -1,44 +1,17 @@
use semver::Version;
use serde::{Deserialize, Serialize};
use std::fs;
use std::path::PathBuf;
use std::{env, fs};
use toml;

use crate::constants::CONFIG_FILE_NAME;
use crate::utils::abort;

// todo docstring
pub fn create_config(py_version: Version) -> Config {
Config {
python: py_version,
packages: toml::Table::new(),
}
}

// todo docstring
pub fn find_config() -> PathBuf {
let mut dir = match env::current_dir() {
Ok(dir) => dir,
Err(e) => abort("Failed to get current working directory.", Some(&e)),
};

loop {
match fs::exists(dir.join("pen.toml")) {
Ok(true) => return dir,
Ok(false) => {
if !dir.pop() {
abort("Couldn't find a pen.toml file.", None);
}
}
Err(e) => abort("Failed to find a pen.toml file.", Some(&e)),
};
}
}

// todo docstring
pub fn read_config(project_path: &PathBuf) -> Config {
let config_path = project_path.join("pen.toml");
let config_path = project_path.join(&*CONFIG_FILE_NAME);
match fs::read_to_string(&config_path) {
Ok(contents) => match toml::de::from_str::<Config>(&contents) {
Ok(contents) => match toml::from_str::<Config>(&contents) {
Ok(toml) => toml,
Err(e) => abort(
&format!("Couldn't parse {}.", config_path.display()),
Expand All @@ -54,7 +27,7 @@ pub fn read_config(project_path: &PathBuf) -> Config {

// todo docstring
pub fn write_config(project_path: PathBuf, config: Config) {
match toml::ser::to_string_pretty(&config) {
match toml::to_string_pretty(&config) {
Ok(toml) => {
if let Err(e) = fs::write(project_path.join("pen.toml"), toml) {
abort(
Expand All @@ -75,6 +48,6 @@ pub fn write_config(project_path: PathBuf, config: Config) {

#[derive(Serialize, Deserialize)]
pub struct Config {
pub python: Version,
pub python: Version, // todo do we want to have instead a VersionReq?
pub packages: toml::Table,
}
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ pub fn find_matching_package_version(name: &str, version_requirements: &VersionR
};

Package {
name: String::from(&json.info.name),
name: String::from(&json.info.name), // todo why is this not just name?
version: best_version,
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
use semver::{Version, VersionReq};

use crate::{
env_utils::{download_package, find_matching_package_version, Config, Package},
py_utils::py_install_algo_v1,
utils::{self, abort},
use crate::utils::{
self, abort, download_package, find_matching_package_version, py_install_algo_v1, Config,
Package,
};
use std::{fs, os::unix, path::PathBuf};

pub fn create_virtual_env(config: Config, destination_path: &PathBuf) {
pub fn create_or_update_virtual_env(config: Config, destination_path: &PathBuf) {
let py_dir = utils::get_python_path(&config.python);
let py_version_short = format!("{}.{}", config.python.major, config.python.minor);

Expand All @@ -16,7 +15,7 @@ pub fn create_virtual_env(config: Config, destination_path: &PathBuf) {
}
if let Err(e) = fs::write(
destination_path.join("pyvenv.cfg"),
// todo this pyenv.cfg file, when writen, has some spacing before the paragraph, needs fixing
// todo this pyenv.cfg file, when writen, has some spacing beforeeach line of the paragraph, needs fixing
format!(
r#" # Created using pen
home = {0}/bin
Expand Down
7 changes: 7 additions & 0 deletions src/utils/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,9 @@
mod env_utils;
mod path;
mod py_utils;
mod utils;

pub use env_utils::*;
pub use path::*;
pub use py_utils::*;
pub use utils::*;
145 changes: 145 additions & 0 deletions src/utils/path.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
use crate::constants::{PYTHON_PACKAGES_DIR, PYTHON_VERSIONS_DIR, TMP_DIR};
use crate::utils::{abort, Package};
use semver::Version;
use std::{env, fs, io, path::PathBuf};

/// Constructs the path to the directory for a specified Python version without validating the format of the version string.
///
/// # Arguments
/// - `py_version`: A string slice representing the Python version, which has been
/// validated to conform to the expected format (major.minor.patch).
///
/// # Output
/// - A `PathBuf` pointing to the directory associated with the specified Python version.
///
/// # Termination
/// - This function does not terminate.
///
/// # Guarantees
/// - The returned path will be correctly formed if `py_version` is well formatted.
///
/// # Limitations
/// - The function does not validate the contents of the constructed path or its existence.
pub fn get_python_path(version: &Version) -> PathBuf {
PYTHON_VERSIONS_DIR.join(format!(
"{}.{}.{}",
version.major, version.minor, version.patch
))
}

// todo docstring
pub fn get_package_path(package: &Package) -> PathBuf {
PYTHON_PACKAGES_DIR.join(format!(
"{}_{}.{}.{}",
package.name, package.version.major, package.version.minor, package.version.patch
))
}

// todo docstring
pub fn get_project_root() -> PathBuf {
// todo this should probably be in a more global utils file
let mut dir = match env::current_dir() {
Ok(dir) => dir,
Err(e) => abort("Failed to get current working directory.", Some(&e)),
};

loop {
match fs::exists(dir.join("pen.toml")) {
Ok(true) => return dir,
Ok(false) => {
if !dir.pop() {
abort("Couldn't find a pen.toml file.", None);
}
}
Err(e) => abort("Failed to find a pen.toml file.", Some(&e)),
};
}
}

/// Attempts to delete a specified directory.
///
/// # Arguments
/// - `dir_path`: A `PathBuf` representing the directory to delete.
///
/// # Output
/// - Returns `Ok(())` if the directory was successfully deleted or if it was already empty.
/// - Returns an `Err` if the directory still exists after attempting deletion.
///
/// # Termination
/// - This function does not terminate.
///
/// # Guarantees
/// - If this function returns `Ok(())`, it guarantees that the directory no longer exists.
pub fn try_deleting_dir(dir_path: &PathBuf) -> Result<(), std::io::Error> {
let delete_path = TMP_DIR.join("delete_path");
return try_deleting_dir_to_temp(dir_path, &delete_path);
}

pub fn try_deleting_dir_to_temp(
dir_path: &PathBuf,
temp_dir: &PathBuf,
) -> Result<(), std::io::Error> {
if let Ok(exists) = dir_path.try_exists() {
if !exists {
return Ok(());
}
}
match temp_dir.try_exists() {
Ok(true) => fs::remove_dir_all(&temp_dir)?,
Ok(false) => (),
Err(e) => abort(
&format!("Unable to know if {} exists", temp_dir.display()),
Some(&e),
),
}
fs::rename(&dir_path, &temp_dir)?;
if dir_path.try_exists()? {
Err(io::Error::new(
io::ErrorKind::Other,
"Directory still exists",
))
} else {
Ok(())
}
}

/// Clears and recreates the temporary directory.
///
/// # Input
/// - None.
///
/// # Output
/// - None.
///
/// # Termination
/// - If either removal or creation operations fail, the function prints an error message and terminates the process.
pub fn clear_temp() {
let temp_is_empty = match (&*TMP_DIR).read_dir() {
Ok(mut read_dir) => read_dir.next().is_none(),
Err(e) => abort(
&format!(
"Failed to check contents of directory {}",
(*TMP_DIR).display()
),
Some(&e),
),
};

if temp_is_empty {
return;
}

if let Err(e) = fs::remove_dir_all(&*TMP_DIR) {
abort(
&format!("Failed to clear directory {}", (*TMP_DIR).display()),
Some(&e),
)
}

if let Err(e) = fs::create_dir(&*TMP_DIR) {
abort(
&format!("Failed to create directory {}", (*TMP_DIR).display()),
Some(&e),
)
}
}
File renamed without changes.
File renamed without changes.
Loading

0 comments on commit 5a74e8f

Please sign in to comment.