allow running commands in subfolder of project

This commit is contained in:
Moritz Hölting 2024-06-26 21:16:18 +02:00
parent 8c9e32e0ec
commit bc6975e52f
6 changed files with 71 additions and 26 deletions

View File

@ -43,3 +43,4 @@ inquire = { git = "https://github.com/moritz-hoelting/rust-inquire.git", branch
camino = "1.1.7" camino = "1.1.7"
human-panic = "2.0.0" human-panic = "2.0.0"
anyhow = "1.0.86" anyhow = "1.0.86"
pathdiff = "0.2.1"

View File

@ -10,6 +10,7 @@ use crate::{
config::ProjectConfig, config::ProjectConfig,
error::Error, error::Error,
terminal_output::{print_error, print_info, print_success, print_warning}, terminal_output::{print_error, print_info, print_success, print_warning},
util,
}; };
use std::{ use std::{
borrow::Cow, borrow::Cow,
@ -47,7 +48,7 @@ pub fn build(args: &BuildArgs) -> Result<()> {
return Err(Error::FeatureNotEnabledError("zip".to_string()).into()); return Err(Error::FeatureNotEnabledError("zip".to_string()).into());
} }
let path = args.path.as_path(); let path = util::get_project_path(&args.path).unwrap_or(args.path.clone());
let dist_path = args let dist_path = args
.output .output
.as_ref() .as_ref()
@ -56,12 +57,16 @@ pub fn build(args: &BuildArgs) -> Result<()> {
let and_package_msg = if args.zip { " and packaging" } else { "" }; let and_package_msg = if args.zip { " and packaging" } else { "" };
let mut path_display = format!("{}", path.display());
if path_display.is_empty() {
path_display.push('.');
}
print_info(format!( print_info(format!(
"Building{and_package_msg} project at {}", "Building{and_package_msg} project at {path_display}"
path.absolutize()?.display()
)); ));
let (project_config, toml_path) = get_pack_config(path)?; let (project_config, toml_path) = get_pack_config(&path)?;
let script_paths = get_script_paths( let script_paths = get_script_paths(
&toml_path &toml_path
@ -198,6 +203,7 @@ fn _get_script_paths(path: &Path, prefix: &str) -> std::io::Result<Vec<(String,
/// - If the specified path does not exist. /// - If the specified path does not exist.
/// - If the specified directory does not contain a pack.toml file. /// - If the specified directory does not contain a pack.toml file.
pub(super) fn get_pack_config(path: &Path) -> Result<(ProjectConfig, PathBuf)> { pub(super) fn get_pack_config(path: &Path) -> Result<(ProjectConfig, PathBuf)> {
let path = path.absolutize()?;
let toml_path = if !path.exists() { let toml_path = if !path.exists() {
print_error("The specified path does not exist."); print_error("The specified path does not exist.");
return Err(Error::PathNotFoundError(path.to_path_buf()))?; return Err(Error::PathNotFoundError(path.to_path_buf()))?;

View File

@ -1,9 +1,12 @@
use std::{borrow::Cow, path::PathBuf}; use std::{borrow::Cow, path::PathBuf};
use anyhow::Result; use anyhow::Result;
use path_absolutize::Absolutize; use path_absolutize::Absolutize as _;
use crate::terminal_output::{print_error, print_info, print_success}; use crate::{
terminal_output::{print_error, print_info, print_success},
util,
};
#[derive(Debug, clap::Args, Clone)] #[derive(Debug, clap::Args, Clone)]
pub struct CleanArgs { pub struct CleanArgs {
@ -26,7 +29,7 @@ pub struct CleanArgs {
pub fn clean(args: &CleanArgs) -> Result<()> { pub fn clean(args: &CleanArgs) -> Result<()> {
let verbose = args.verbose; let verbose = args.verbose;
let path = args.path.as_path(); let path = util::get_project_path(&args.path).unwrap_or(args.path.clone());
let dist_path = args let dist_path = args
.output .output
.as_ref() .as_ref()
@ -35,7 +38,7 @@ pub fn clean(args: &CleanArgs) -> Result<()> {
let mut delete_paths = Vec::new(); let mut delete_paths = Vec::new();
let (project_config, _) = super::build::get_pack_config(path)?; let (project_config, _) = super::build::get_pack_config(&path)?;
if args.all { if args.all {
if args.force { if args.force {
@ -50,7 +53,7 @@ pub fn clean(args: &CleanArgs) -> Result<()> {
print_info(format!( print_info(format!(
"Cleaning project at {}", "Cleaning project at {}",
path.absolutize_from(path)?.display() path.absolutize_from(&path)?.display()
)); ));
for delete_path in delete_paths { for delete_path in delete_paths {

View File

@ -4,7 +4,7 @@ use anyhow::Result;
use shulkerscript::base::FsProvider; use shulkerscript::base::FsProvider;
use std::path::PathBuf; use std::path::PathBuf;
use crate::config::PackConfig; use crate::{config::PackConfig, util};
#[derive(Debug, clap::Args, Clone)] #[derive(Debug, clap::Args, Clone)]
pub struct LangDebugArgs { pub struct LangDebugArgs {
@ -49,7 +49,11 @@ pub fn lang_debug(args: &LangDebugArgs) -> Result<()> {
} }
} }
DumpState::Datapack => { DumpState::Datapack => {
let program_paths = super::build::get_script_paths(&args.path.join("src"))?; let program_paths = super::build::get_script_paths(
&util::get_project_path(&args.path)
.unwrap_or(args.path.clone())
.join("src"),
)?;
let datapack = shulkerscript::transpile( let datapack = shulkerscript::transpile(
&file_provider, &file_provider,
PackConfig::DEFAULT_PACK_FORMAT, PackConfig::DEFAULT_PACK_FORMAT,

View File

@ -7,12 +7,14 @@ use std::{
}; };
use clap::Parser; use clap::Parser;
use colored::Colorize;
use notify_debouncer_mini::{new_debouncer, notify::*, DebounceEventResult}; use notify_debouncer_mini::{new_debouncer, notify::*, DebounceEventResult};
use crate::{ use crate::{
cli::Args, cli::Args,
error::Result, error::Result,
terminal_output::{print_error, print_info, print_warning}, terminal_output::{print_error, print_info, print_warning},
util,
}; };
#[derive(Debug, clap::Args, Clone)] #[derive(Debug, clap::Args, Clone)]
@ -57,7 +59,12 @@ pub struct WatchArgs {
} }
pub fn watch(args: &WatchArgs) -> Result<()> { pub fn watch(args: &WatchArgs) -> Result<()> {
print_info(format!("Watching project at {}", args.path.display())); let path = util::get_project_path(&args.path).unwrap_or(args.path.clone());
print_info(format!("Watching project at {}", path.display()));
print_info(format!(
"Press {} to stop watching",
"Ctrl-C".underline().blue()
));
let commands = args let commands = args
.execute .execute
@ -78,9 +85,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
env::current_dir().ok() env::current_dir().ok()
}; };
if !args.no_inital if !args.no_inital && (current_dir.is_none() || env::set_current_dir(&path).is_err()) {
&& (current_dir.is_none() || env::set_current_dir(args.path.as_path()).is_err())
{
print_warning("Failed to change working directory to project path. Commands may not work."); print_warning("Failed to change working directory to project path. Commands may not work.");
} }
@ -114,28 +119,25 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
env::set_current_dir(prev_cwd).expect("Failed to change working directory back"); env::set_current_dir(prev_cwd).expect("Failed to change working directory back");
} }
let assets_path = super::build::get_pack_config(&args.path) let assets_path = super::build::get_pack_config(&path)
.ok() .ok()
.and_then(|(conf, _)| conf.compiler.and_then(|c| c.assets)); .and_then(|(conf, _)| conf.compiler.and_then(|c| c.assets));
let watcher = debouncer.watcher(); let watcher = debouncer.watcher();
watcher watcher
.watch(args.path.join("src").as_path(), RecursiveMode::Recursive) .watch(path.join("src").as_path(), RecursiveMode::Recursive)
.expect("Failed to watch project src"); .expect("Failed to watch project src");
watcher watcher
.watch( .watch(path.join("pack.png").as_path(), RecursiveMode::NonRecursive)
args.path.join("pack.png").as_path(),
RecursiveMode::NonRecursive,
)
.expect("Failed to watch project pack.png"); .expect("Failed to watch project pack.png");
watcher watcher
.watch( .watch(
args.path.join("pack.toml").as_path(), path.join("pack.toml").as_path(),
RecursiveMode::NonRecursive, RecursiveMode::NonRecursive,
) )
.expect("Failed to watch project pack.toml"); .expect("Failed to watch project pack.toml");
if let Some(assets_path) = assets_path { if let Some(assets_path) = assets_path {
let full_assets_path = args.path.join(assets_path); let full_assets_path = path.join(assets_path);
if full_assets_path.exists() { if full_assets_path.exists() {
watcher watcher
.watch(full_assets_path.as_path(), RecursiveMode::Recursive) .watch(full_assets_path.as_path(), RecursiveMode::Recursive)
@ -147,7 +149,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
for path in args.watch.iter() { for path in args.watch.iter() {
if path.exists() { if path.exists() {
watcher watcher
.watch(path.as_path(), RecursiveMode::Recursive) .watch(path, RecursiveMode::Recursive)
.expect("Failed to watch custom path"); .expect("Failed to watch custom path");
} else { } else {
print_warning(format!( print_warning(format!(
@ -157,7 +159,7 @@ pub fn watch(args: &WatchArgs) -> Result<()> {
} }
} }
if env::set_current_dir(args.path.as_path()).is_err() { if env::set_current_dir(path).is_err() {
print_warning("Failed to change working directory to project path. Commands may not work."); print_warning("Failed to change working directory to project path. Commands may not work.");
} }

View File

@ -1,8 +1,37 @@
use std::collections::HashMap; use std::{
borrow::Cow,
collections::HashMap,
env,
path::{Path, PathBuf},
};
use camino::Utf8PathBuf; use camino::Utf8PathBuf;
use inquire::{autocompletion::Replacement, Autocomplete}; use inquire::{autocompletion::Replacement, Autocomplete};
use path_absolutize::Absolutize;
pub fn get_project_path<P>(base_path: P) -> Option<PathBuf>
where
P: AsRef<Path>,
{
let base_path = base_path.as_ref();
if base_path.is_absolute() {
Cow::Borrowed(base_path)
} else {
base_path.absolutize().ok()?
}
.ancestors()
.find(|p| p.join("pack.toml").exists())
.map(|p| relativize(p).unwrap_or_else(|| p.to_path_buf()))
}
pub fn relativize<P>(path: P) -> Option<PathBuf>
where
P: AsRef<Path>,
{
let cwd = env::current_dir().ok()?;
pathdiff::diff_paths(path, cwd)
}
#[derive(Debug, Clone, Default, PartialEq, Eq)] #[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct PathAutocomplete { pub struct PathAutocomplete {