Skip to content

Commit

Permalink
Probe for project configuration files in parent directories
Browse files Browse the repository at this point in the history
  • Loading branch information
rcook committed Apr 6, 2023
1 parent d12d223 commit cf55d49
Show file tree
Hide file tree
Showing 11 changed files with 122 additions and 58 deletions.
28 changes: 17 additions & 11 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::constants::RELEASES_URL;
use crate::object_model::{Asset, AssetMeta, EnvName, LastModified, RepositoryName};
use crate::object_model::{Asset, AssetMeta, EnvName, LastModified, Project, RepositoryName};
use crate::probe::find_project_config_path;
use crate::repository::{GitHubRepository, LocalRepository, Repository};
use crate::result::Result;
use crate::serialization::{
Expand All @@ -13,8 +14,6 @@ use md5::compute;
use std::fs::read_dir;
use std::path::{Path, PathBuf};

pub const PROJECT_CONFIG_FILE_NAME: &'static str = ".python-version.yaml";

pub struct RepositoryInfo {
pub name: RepositoryName,
pub repository: Box<dyn Repository>,
Expand Down Expand Up @@ -271,14 +270,21 @@ impl App {
Ok(uses)
}

pub fn get_project_config_path(&self) -> PathBuf {
self.cwd.join(PROJECT_CONFIG_FILE_NAME)
}

pub fn read_project_config(&self) -> Result<ProjectRecord> {
let project_config_path = self.get_project_config_path();
let project_record = read_yaml_file::<ProjectRecord, _>(&project_config_path)?;
Ok(project_record)
pub fn read_project<P>(&self, start_dir: P) -> Result<Option<Project>>
where
P: Into<PathBuf>,
{
Ok(match find_project_config_path(start_dir)? {
None => None,
Some(p) => {
let project_record = read_yaml_file::<ProjectRecord, _>(&p)?;
Some(Project {
config_path: p,
python_version: project_record.python_version,
tag: project_record.tag,
})
}
})
}

fn make_repository(
Expand Down
28 changes: 18 additions & 10 deletions src/commands/info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@ use crate::result::Result;
pub fn do_info(app: &App) -> Result<()> {
println!("Working directory: {}", app.cwd.display());
println!("isopy directory: {}", app.dir.display());
let project_record = app.read_project_config()?;
println!("python_version: {}", project_record.python_version);
println!(
"tag: {}",
project_record
.tag
.as_ref()
.map(Tag::to_string)
.unwrap_or(String::from("(none)"))
);
match app.read_project(&app.cwd)? {
Some(project) => {
println!(
"Project configuration file: {}",
project.config_path.display()
);
println!("python_version: {}", project.python_version);
println!(
"tag: {}",
project
.tag
.as_ref()
.map(Tag::to_string)
.unwrap_or(String::from("(none)"))
)
}
None => {}
}
Ok(())
}
24 changes: 16 additions & 8 deletions src/commands/init.rs
Original file line number Diff line number Diff line change
@@ -1,30 +1,38 @@
use crate::app::{App, PROJECT_CONFIG_FILE_NAME};
use crate::app::App;
use crate::helpers::{download_asset, get_asset};
use crate::result::Result;
use crate::object_model::Project;
use crate::probe::PROJECT_CONFIG_FILE_NAME;
use crate::result::{user, Result};
use crate::serialization::AnonymousEnvRecord;
use crate::util::{safe_write_file, unpack_file};
use std::path::PathBuf;

pub async fn do_init(app: &App) -> Result<()> {
let project_record = app.read_project_config()?;
match app.read_project(&app.cwd)? {
None => Err(user(format!(
"Could not find project configuration file {}",
PROJECT_CONFIG_FILE_NAME
))),
Some(project) => Ok(init_project(app, &project).await?),
}
}

async fn init_project(app: &App, project: &Project) -> Result<()> {
let assets = app.read_assets()?;
let asset = get_asset(&assets, &project_record.python_version, &project_record.tag)?;
let asset = get_asset(&assets, &project.python_version, &project.tag)?;

let mut asset_path = app.make_asset_path(&asset);
if !asset_path.is_file() {
asset_path = download_asset(app, asset).await?;
}

let anonymous_env_dir = app.anonymous_env_dir(&PROJECT_CONFIG_FILE_NAME)?;
let anonymous_env_dir = app.anonymous_env_dir(&project.config_path)?;
unpack_file(&asset_path, &anonymous_env_dir)?;

let project_config_path = app.get_project_config_path();

safe_write_file(
anonymous_env_dir.join("env.yaml"),
serde_yaml::to_string(&AnonymousEnvRecord {
config_path: project_config_path,
config_path: project.config_path.clone(),
python_dir: PathBuf::from("python"),
python_version: asset.meta.version.clone(),
tag: asset.tag.clone(),
Expand Down
3 changes: 2 additions & 1 deletion src/commands/new.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
use crate::app::App;
use crate::helpers::get_asset;
use crate::object_model::{Tag, Version};
use crate::probe::make_project_config_path;
use crate::result::Result;
use crate::serialization::ProjectRecord;
use crate::util::safe_write_file;

pub fn do_new(app: &App, version: &Version, tag: &Option<Tag>) -> Result<()> {
let project_config_path = app.get_project_config_path();
let project_config_path = make_project_config_path(&app.cwd);
let project_record = ProjectRecord {
python_version: version.clone(),
tag: tag.clone(),
Expand Down
35 changes: 18 additions & 17 deletions src/env_info.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::app::{App, PROJECT_CONFIG_FILE_NAME};
use crate::app::App;
use crate::object_model::EnvName;
use crate::result::{user, Result};
use crate::serialization::{AnonymousEnvRecord, NamedEnvRecord, UseRecord};
Expand Down Expand Up @@ -36,22 +36,23 @@ fn get_use_env_info(app: &App) -> Result<Option<EnvInfo>> {
}

fn get_project_env_info(app: &App) -> Result<Option<EnvInfo>> {
let project_config_path = app.get_project_config_path();
if !project_config_path.is_file() {
return Ok(None);
}

let anonymous_env_dir = app.anonymous_env_dir(&PROJECT_CONFIG_FILE_NAME)?;
let anonymous_env_config_path = anonymous_env_dir.join("env.yaml");
if !anonymous_env_config_path.is_file() {
return Ok(None);
}

let anonymous_env_record = read_yaml_file::<AnonymousEnvRecord, _>(&anonymous_env_config_path)?;
return Ok(Some(EnvInfo {
env_name: EnvName::parse("ANONYMOUS").expect("Must be a valid environment"),
full_python_dir: anonymous_env_dir.join(anonymous_env_record.python_dir),
}));
Ok(match app.read_project(&app.cwd)? {
None => None,
Some(project) => {
let anonymous_env_dir = app.anonymous_env_dir(&project.config_path)?;
let anonymous_env_config_path = anonymous_env_dir.join("env.yaml");
if anonymous_env_config_path.is_file() {
let anonymous_env_record =
read_yaml_file::<AnonymousEnvRecord, _>(&anonymous_env_config_path)?;
Some(EnvInfo {
env_name: EnvName::parse("ANONYMOUS").expect("Must be a valid environment"),
full_python_dir: anonymous_env_dir.join(anonymous_env_record.python_dir),
})
} else {
None
}
}
})
}

pub fn get_env_info(app: &App, env_name_opt: Option<&EnvName>) -> Result<EnvInfo> {
Expand Down
13 changes: 4 additions & 9 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod constants;
mod env_info;
mod helpers;
mod object_model;
mod probe;
mod repository;
mod result;
mod serialization;
Expand All @@ -18,21 +19,15 @@ use crate::commands::{
do_info, do_init, do_list, do_new, do_scratch, do_shell, do_use, do_wrap,
};
use crate::constants::{GENERAL_ERROR, OK, USAGE};
use crate::probe::default_isopy_dir;
use crate::result::{could_not_infer_isopy_dir, Error, Result};
use clap::Parser;
use colour::red_ln;
use std::env::current_dir;
use std::path::PathBuf;
use std::process::exit;
use tokio;

fn default_isopy_dir() -> Option<PathBuf> {
let home_dir = home::home_dir()?;
let isopy_dir = home_dir.join(".isopy");
Some(isopy_dir)
}

async fn main_inner() -> Result<()> {
async fn run() -> Result<()> {
let cwd = current_dir()?;
let args = Args::parse();
let dir = args
Expand Down Expand Up @@ -77,7 +72,7 @@ async fn main_inner() -> Result<()> {

#[tokio::main]
async fn main() {
exit(match main_inner().await {
exit(match run().await {
Ok(_) => OK,
Err(Error::User { message }) => {
red_ln!("{}", message);
Expand Down
2 changes: 2 additions & 0 deletions src/object_model/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod asset_meta;
mod attributes;
mod env_name;
mod last_modified;
mod project;
mod repository_name;
mod tag;
mod version;
Expand All @@ -14,6 +15,7 @@ pub use self::asset_meta::AssetMeta;
pub use self::attributes::{Arch, ArchiveType, Family, Flavour, Platform, Subflavour, Variant, OS};
pub use self::env_name::EnvName;
pub use self::last_modified::LastModified;
pub use self::project::Project;
pub use self::repository_name::RepositoryName;
pub use self::tag::Tag;
pub use self::version::Version;
8 changes: 8 additions & 0 deletions src/object_model/project.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use crate::object_model::{Tag, Version};
use std::path::PathBuf;

pub struct Project {
pub config_path: PathBuf,
pub python_version: Version,
pub tag: Option<Tag>,
}
35 changes: 35 additions & 0 deletions src/probe.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
use crate::result::Result;
use std::path::PathBuf;

pub const ISOPY_DIR_NAME: &'static str = ".isopy";

pub const PROJECT_CONFIG_FILE_NAME: &'static str = ".python-version.yaml";

pub fn default_isopy_dir() -> Option<PathBuf> {
let home_dir = home::home_dir()?;
let isopy_dir = home_dir.join(ISOPY_DIR_NAME);
Some(isopy_dir)
}

pub fn make_project_config_path<P>(project_dir: P) -> PathBuf
where
P: Into<PathBuf>,
{
project_dir.into().join(PROJECT_CONFIG_FILE_NAME)
}

pub fn find_project_config_path<P>(start_dir: P) -> Result<Option<PathBuf>>
where
P: Into<PathBuf>,
{
let mut dir = start_dir.into();
loop {
let project_config_path = make_project_config_path(&dir);
if project_config_path.is_file() {
return Ok(Some(project_config_path));
}
if !dir.pop() {
return Ok(None);
}
}
}
4 changes: 2 additions & 2 deletions src/serialization/mod.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
mod env;
mod helpers;
mod index;
mod project;
mod project_record;
mod repositories;
mod use_;

pub use self::env::{AnonymousEnvRecord, NamedEnvRecord};
pub use self::index::{AssetRecord, IndexRecord, PackageRecord};
pub use self::project::ProjectRecord;
pub use self::project_record::ProjectRecord;
pub use self::repositories::{RepositoriesRecord, RepositoryRecord};
pub use self::use_::UseRecord;
File renamed without changes.

0 comments on commit cf55d49

Please sign in to comment.