Add manager script
This commit is contained in:
91
manager/src/linker.rs
Normal file
91
manager/src/linker.rs
Normal file
@ -0,0 +1,91 @@
|
||||
use crate::Opt;
|
||||
use async_recursion::async_recursion;
|
||||
use futures::future::join_all;
|
||||
use std::io::{self, ErrorKind};
|
||||
use std::path::PathBuf;
|
||||
use tokio::fs::{create_dir, read_dir, remove_file, symlink};
|
||||
use tokio::try_join;
|
||||
|
||||
pub async fn link_tree(opt: &Opt) -> io::Result<()> {
|
||||
dir(opt, PathBuf::new()).await
|
||||
}
|
||||
|
||||
#[async_recursion]
|
||||
async fn dir(opt: &Opt, relative: PathBuf) -> io::Result<()> {
|
||||
let build_path = opt.build_dir.join(&relative);
|
||||
let link_path = opt.link_dir.join(&relative);
|
||||
|
||||
info!("traversing {:?}", build_path);
|
||||
|
||||
match create_dir(&link_path).await {
|
||||
Ok(_) => {}
|
||||
Err(e) if e.kind() == ErrorKind::AlreadyExists => {}
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
|
||||
let mut walker = read_dir(&build_path).await?;
|
||||
|
||||
let mut dir_tasks = vec![];
|
||||
let mut file_tasks = vec![];
|
||||
|
||||
while let Some(entry) = walker.next_entry().await? {
|
||||
let meta = entry.metadata().await?;
|
||||
let new_relative = relative.join(entry.file_name());
|
||||
|
||||
if meta.is_dir() {
|
||||
dir_tasks.push(dir(opt, new_relative));
|
||||
} else if meta.is_file() {
|
||||
file_tasks.push(file(opt, new_relative));
|
||||
}
|
||||
}
|
||||
|
||||
let dirs = async {
|
||||
join_all(dir_tasks)
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
};
|
||||
|
||||
let files = async {
|
||||
join_all(file_tasks)
|
||||
.await
|
||||
.into_iter()
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
};
|
||||
|
||||
try_join!(dirs, files)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn file(opt: &Opt, relative: PathBuf) -> io::Result<()> {
|
||||
let build_path = opt.build_dir.join(&relative);
|
||||
let link_path = opt.link_dir.join(&relative);
|
||||
|
||||
match remove_file(&link_path).await {
|
||||
Ok(_) => {
|
||||
info!("removed existing file {:?}", link_path);
|
||||
}
|
||||
Err(e) if e.kind() == ErrorKind::NotFound => {}
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
|
||||
info!("linking {:?} to {:?}", link_path, build_path);
|
||||
let symlink_content = if build_path.is_absolute() {
|
||||
build_path
|
||||
} else {
|
||||
// TODO: this probably doesn't work for paths containing ".."
|
||||
// TODO: this doesn't work if link path is absolute
|
||||
let mut relative_symlink = PathBuf::new();
|
||||
for _ in link_path.iter().skip(1).filter(|&c| c == ".") {
|
||||
relative_symlink.push("..");
|
||||
}
|
||||
relative_symlink.push(&build_path);
|
||||
|
||||
relative_symlink
|
||||
};
|
||||
|
||||
symlink(symlink_content, link_path).await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user