feat: respect .iliasignore files in parent folder

see #38
This commit is contained in:
FliegendeWurst 2022-11-23 15:09:55 +01:00
parent 07dc3a9be2
commit cc7dcd6f9d
3 changed files with 76 additions and 13 deletions

View File

@ -4,14 +4,13 @@ use std::{collections::HashMap, error::Error as _, io::Write, sync::Arc};
use anyhow::{anyhow, Context, Result}; use anyhow::{anyhow, Context, Result};
use cookie_store::CookieStore; use cookie_store::CookieStore;
use ignore::gitignore::Gitignore;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use reqwest::{Client, IntoUrl, Proxy, Url}; use reqwest::{Client, IntoUrl, Proxy, Url};
use reqwest_cookie_store::CookieStoreMutex; use reqwest_cookie_store::CookieStoreMutex;
use scraper::{ElementRef, Html, Selector}; use scraper::{ElementRef, Html, Selector};
use serde_json::json; use serde_json::json;
use crate::{cli::Opt, queue, util::wrap_html, ILIAS_URL}; use crate::{cli::Opt, queue, util::wrap_html, ILIAS_URL, iliasignore::IliasIgnore};
pub mod course; pub mod course;
pub mod exercise; pub mod exercise;
@ -35,7 +34,7 @@ static CONTAINER_ITEM_TITLE: Lazy<Selector> =
pub struct ILIAS { pub struct ILIAS {
pub opt: Opt, pub opt: Opt,
pub ignore: Gitignore, pub ignore: IliasIgnore,
client: Client, client: Client,
cookies: Arc<CookieStoreMutex>, cookies: Arc<CookieStoreMutex>,
pub course_names: HashMap<String, String>, pub course_names: HashMap<String, String>,
@ -61,7 +60,7 @@ impl ILIAS {
pub async fn with_session( pub async fn with_session(
opt: Opt, opt: Opt,
session: Arc<CookieStoreMutex>, session: Arc<CookieStoreMutex>,
ignore: Gitignore, ignore: IliasIgnore,
course_names: HashMap<String, String>, course_names: HashMap<String, String>,
) -> Result<Self> { ) -> Result<Self> {
let mut builder = Client::builder() let mut builder = Client::builder()
@ -88,7 +87,7 @@ impl ILIAS {
opt: Opt, opt: Opt,
user: &str, user: &str,
pass: &str, pass: &str,
ignore: Gitignore, ignore: IliasIgnore,
course_names: HashMap<String, String>, course_names: HashMap<String, String>,
) -> Result<Self> { ) -> Result<Self> {
let cookie_store = CookieStore::default(); let cookie_store = CookieStore::default();

66
src/iliasignore.rs Normal file
View File

@ -0,0 +1,66 @@
use std::{path::{Path, PathBuf, Component}, ffi::OsString};
use anyhow::Result;
use ignore::gitignore::Gitignore;
#[derive(Clone, Debug)]
pub struct IliasIgnore {
ignores: Vec<IgnoreFile>
}
impl IliasIgnore {
pub fn load(mut path: PathBuf) -> Result<Self> {
let mut ignores = Vec::new();
let mut prefix = Vec::new();
// example scenario:
// path = /KIT/ILIAS/SS 23/Next Generation Internet
// iliasignore in ILIAS/.iliasignore: prefix = SS 23/Next Generation Internet
// iliasignore in Next Generation Internet/.iliasignore: prefix = ""
loop {
let (ignore, error) = Gitignore::new(path.join(".iliasignore"));
if let Some(err) = error {
warning!(err);
}
if ignore.len() > 0 {
ignores.push(IgnoreFile {
ignore,
prefix: prefix.iter().fold(OsString::new(), |mut acc, el| {
acc.push(el);
acc.push("/");
acc
})
});
}
if let Some(last) = path.components().last() {
match last {
Component::Normal(name) => prefix.insert(0, name.to_owned()),
_ => break
}
}
path.pop();
}
Ok(IliasIgnore {
ignores
})
}
pub fn should_ignore(&self, path: &Path, is_dir: bool) -> bool {
for ignore_file in &self.ignores {
let mut full_path = ignore_file.prefix.clone();
full_path.push(path.as_os_str());
let matched = ignore_file.ignore.matched(&full_path, is_dir);
if matched.is_whitelist() {
return false;
} else if matched.is_ignore() {
return true;
}
}
false
}
}
#[derive(Clone, Debug)]
struct IgnoreFile {
ignore: Gitignore,
prefix: OsString
}

View File

@ -25,6 +25,8 @@ mod cli;
use cli::*; use cli::*;
mod ilias; mod ilias;
use ilias::*; use ilias::*;
mod iliasignore;
use iliasignore::*;
use Object::*; use Object::*;
mod queue; mod queue;
mod util; mod util;
@ -38,7 +40,7 @@ async fn main() {
} }
} }
async fn try_to_load_session(opt: Opt, ignore: Gitignore, course_names: HashMap<String, String>) -> Result<ILIAS> { async fn try_to_load_session(opt: Opt, ignore: IliasIgnore, course_names: HashMap<String, String>) -> Result<ILIAS> {
let session_path = opt.output.join(".iliassession"); let session_path = opt.output.join(".iliassession");
let meta = tokio::fs::metadata(&session_path).await?; let meta = tokio::fs::metadata(&session_path).await?;
let modified = meta.modified()?; let modified = meta.modified()?;
@ -58,7 +60,7 @@ async fn try_to_load_session(opt: Opt, ignore: Gitignore, course_names: HashMap<
} }
} }
async fn login(opt: Opt, ignore: Gitignore, course_names: HashMap<String, String>) -> Result<ILIAS> { async fn login(opt: Opt, ignore: IliasIgnore, course_names: HashMap<String, String>) -> Result<ILIAS> {
// load .iliassession file // load .iliassession file
if opt.keep_session { if opt.keep_session {
match try_to_load_session(opt.clone(), ignore.clone(), course_names.clone()) match try_to_load_session(opt.clone(), ignore.clone(), course_names.clone())
@ -117,7 +119,7 @@ async fn real_main(mut opt: Opt) -> Result<()> {
.context("failed to canonicalize output directory")?; .context("failed to canonicalize output directory")?;
// load .iliasignore file // load .iliasignore file
let (ignore, error) = Gitignore::new(opt.output.join(".iliasignore")); let ignore = IliasIgnore::load(opt.output.clone())?;
// Load course_names.toml file // Load course_names.toml file
let course_names_path = opt.output.join("course_names.toml"); let course_names_path = opt.output.join("course_names.toml");
@ -134,10 +136,6 @@ async fn real_main(mut opt: Opt) -> Result<()> {
HashMap::new() HashMap::new()
}; };
if let Some(err) = error {
warning!(err);
}
queue::set_download_rate(opt.rate); queue::set_download_rate(opt.rate);
let ilias = login(opt, ignore, course_names).await?; let ilias = login(opt, ignore, course_names).await?;
@ -235,7 +233,7 @@ async fn process(ilias: Arc<ILIAS>, path: PathBuf, obj: Object) -> Result<()> {
} }
} }
// root path should not be matched // root path should not be matched
if relative_path.parent().is_some() && ilias.ignore.matched(relative_path, obj.is_dir()).is_ignore() { if relative_path.parent().is_some() && ilias.ignore.should_ignore(relative_path, obj.is_dir()) {
log!(1, "Ignored {}", relative_path.to_string_lossy()); log!(1, "Ignored {}", relative_path.to_string_lossy());
return Ok(()); return Ok(());
} }