Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,10 +437,10 @@ pub struct Cli {

/// Enable verbose logging for debugging purposes.
///
/// Levels: error, warn, info (default), debug, trace
/// Levels: error, warn (default), info, debug, trace
/// Example: utpm -v trace prj link
#[arg(
default_value = "info",
default_value = "warn",
short = 'v',
long,
global = true,
Expand Down
142 changes: 67 additions & 75 deletions src/commands/link.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use ecow::EcoVec;
use ignore::{WalkBuilder, overrides::OverrideBuilder};
use std::fs::{copy, create_dir_all};
use std::path::PathBuf;
Expand Down Expand Up @@ -55,93 +56,84 @@ pub async fn run(cmd: &LinkArgs, path: &Option<String>, pt: bool) -> Result<bool
};

// Check if the package already exists at the destination.
if check_path_dir(&destination) && !cmd.force {
let exists = check_path_dir(&destination);
if exists && !cmd.force {
utpm_bail!(AlreadyExist, name.to_string(), version, "Info:".to_string());
}

if !get_dry_run() {
fs::create_dir_all(destination.parent().unwrap())?
};
if exists {
fs::remove_dir_all(&destination)?;
}
fs::create_dir_all(destination.parent().unwrap())?;

// If force is used, remove the existing directory.
if cmd.force && !get_dry_run() {
fs::remove_dir_all(&destination)?
if cmd.no_copy {
symlink_all(&curr, &destination)?;
} else {
copy_tree(&curr, &destination, cmd, Extra::from(config.tool).exclude)?;
}
}

// Create a symlink or copy the directory.
if cmd.no_copy {
if !get_dry_run() {
symlink_all(&curr, &destination)?
};
if pt {
utpm_log!(
info,
"Project linked to: {}\nTry importing with: \n#import \"@{}/{}:{}\": *",
destination.display(),
namespace,
name,
version
);
}
} else {
if !get_dry_run() {
// Use WalkBuilder to respect ignore files.
let mut wb: WalkBuilder = WalkBuilder::new(&curr);
let mut overr: OverrideBuilder = OverrideBuilder::new(&curr);
if pt {
utpm_log!(
info,
"Project linked to: {}\nTry importing with: \n#import \"@{}/{}:{}\": *",
destination.display(),
namespace,
name,
version
);
}
Ok(true)
}

// Add excludes from the manifest to the override builder.
if let Some(excludes) = Extra::from(config.tool).exclude {
for exclude in excludes.iter() {
overr.add(&format!("!{}", exclude))?;
}
}
wb.overrides(overr.build()?);
/// Copies `curr` into `destination`, honoring ignore files and manifest excludes.
fn copy_tree(
curr: &Path,
destination: &Path,
cmd: &LinkArgs,
excludes: Option<EcoVec<String>>,
) -> Result<()> {
let mut wb: WalkBuilder = WalkBuilder::new(curr);
let mut overr: OverrideBuilder = OverrideBuilder::new(curr);

// Configure which ignore files to use.
wb.ignore(cmd.ignore)
.git_ignore(cmd.git_ignore)
.git_global(cmd.git_global_ignore)
.git_exclude(cmd.git_exclude);
utpm_log!(info,
"git_ignore" => cmd.git_ignore,
"git_global_ignore" => cmd.git_global_ignore,
"git_exclude" => cmd.git_exclude
);
if let Some(excludes) = excludes {
for exclude in excludes.iter() {
overr.add(&format!("!{}", exclude))?;
}
}
wb.overrides(overr.build()?);

// Add .typstignore if it exists and is enabled.
if cmd.typst_ignore {
let pathbuf = curr.join(".typstignore");
if check_path_file(pathbuf) {
utpm_log!(info, "Added .typstignore");
wb.add_custom_ignore_filename(".typstignore");
}
}
wb.ignore(cmd.ignore)
.git_ignore(cmd.git_ignore)
.git_global(cmd.git_global_ignore)
.git_exclude(cmd.git_exclude);
utpm_log!(info,
"git_ignore" => cmd.git_ignore,
"git_global_ignore" => cmd.git_global_ignore,
"git_exclude" => cmd.git_exclude
);

// --- Copy Files ---
for result in wb.build().collect::<std::result::Result<Vec<_>, _>>()? {
if let Some(file_type) = result.file_type() {
let path: &Path = result.path();
let relative = path.strip_prefix(&curr).unwrap();
let dest_path = destination.join(relative);
utpm_log!("{}", dest_path.display());
if file_type.is_dir() {
create_dir_all(&dest_path)?;
} else {
copy(path, &dest_path)?;
}
}
if cmd.typst_ignore {
let pathbuf = curr.join(".typstignore");
if check_path_file(pathbuf) {
utpm_log!(info, "Added .typstignore");
wb.add_custom_ignore_filename(".typstignore");
}
}

for result in wb.build().collect::<std::result::Result<Vec<_>, _>>()? {
if let Some(file_type) = result.file_type() {
let path: &Path = result.path();
let relative = path.strip_prefix(curr).unwrap();
let dest_path = destination.join(relative);
utpm_log!("{}", dest_path.display());
if file_type.is_dir() {
create_dir_all(&dest_path)?;
} else {
copy(path, &dest_path)?;
}
};
if pt {
utpm_log!(
info,
"Project linked to: {}\nTry importing with: \n#import \"@{}/{}:{}\": *",
destination.display(),
namespace,
name,
version
);
}
}
Ok(true)
Ok(())
}