i2-cli-subscription-file (#16)
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful

Closes kemitix/podal#2

Reviewed-on: #16
Co-authored-by: Paul Campbell <pcampbell@kemitix.net>
Co-committed-by: Paul Campbell <pcampbell@kemitix.net>
This commit is contained in:
Paul Campbell 2023-08-07 09:43:13 +01:00 committed by Paul Campbell
parent 304ae6740d
commit d305a2bb1b
11 changed files with 46 additions and 12 deletions

7
Cargo.lock generated
View file

@ -84,6 +84,12 @@ dependencies = [
"windows-sys", "windows-sys",
] ]
[[package]]
name = "anyhow"
version = "1.0.72"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
[[package]] [[package]]
name = "atom_syndication" name = "atom_syndication"
version = "0.12.1" version = "0.12.1"
@ -1039,6 +1045,7 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
name = "podal" name = "podal"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"anyhow",
"atom_syndication", "atom_syndication",
"bytes", "bytes",
"clap", "clap",

View file

@ -11,6 +11,7 @@ reqwest = { version = "0.11.18", features = ["json", "blocking"] }
scraper = "0.17.1" scraper = "0.17.1"
clap = {version = "4.3.19", features = ["derive"]} clap = {version = "4.3.19", features = ["derive"]}
bytes = "1.4.0" bytes = "1.4.0"
anyhow = "1.0.72"
[dev-dependencies] [dev-dependencies]
tempfile = "*" tempfile = "*"

View file

@ -13,6 +13,14 @@ impl Error {
} }
} }
} }
impl From<anyhow::Error> for Error {
fn from(value: anyhow::Error) -> Self {
Self {
details: value.to_string(),
source: value.source().unwrap().to_string(),
}
}
}
impl From<Utf8Error> for Error { impl From<Utf8Error> for Error {
fn from(value: Utf8Error) -> Self { fn from(value: Utf8Error) -> Self {
Self { Self {

View file

@ -1,3 +1,5 @@
use anyhow::Context;
use crate::params::Args; use crate::params::Args;
use crate::prelude::*; use crate::prelude::*;
@ -19,7 +21,9 @@ impl FileEnv {
Self { Self {
open: Box::new(move |file_name| { open: Box::new(move |file_name| {
let path = format!("{}/{}", &open_dir, file_name); let path = format!("{}/{}", &open_dir, file_name);
let file = File::open(path)?; let file = File::open(&path).with_context(|| {
format!("FileEnv::open: file_name={file_name}, path={path}")
})?;
Ok(file) Ok(file)
}), }),
append_line: Box::new(move |file_name, line| { append_line: Box::new(move |file_name, line| {

View file

@ -33,6 +33,7 @@ mod tests {
let file_env = FileEnv::create(&Args { let file_env = FileEnv::create(&Args {
downloads: dir.path().to_string_lossy().to_string(), downloads: dir.path().to_string_lossy().to_string(),
history: "downloaded.txt".to_string(), history: "downloaded.txt".to_string(),
subscriptions: file_name.to_string(),
}); });
//when //when
@ -55,6 +56,7 @@ mod tests {
let file_env = FileEnv::create(&Args { let file_env = FileEnv::create(&Args {
downloads: dir.path().to_string_lossy().to_string(), downloads: dir.path().to_string_lossy().to_string(),
history: "downloaded.txt".to_string(), history: "downloaded.txt".to_string(),
subscriptions: file_name.to_string(),
}); });
//when //when
@ -77,6 +79,7 @@ mod tests {
let file_env = FileEnv::create(&Args { let file_env = FileEnv::create(&Args {
downloads: dir.path().to_string_lossy().to_string(), downloads: dir.path().to_string_lossy().to_string(),
history: "downloaded.txt".to_string(), history: "downloaded.txt".to_string(),
subscriptions: file_name.to_string(),
}); });
//when //when

View file

@ -42,6 +42,7 @@ mod tests {
&FileEnv::create(&Args { &FileEnv::create(&Args {
downloads: dir.path().to_string_lossy().to_string(), downloads: dir.path().to_string_lossy().to_string(),
history: "downloaded.txt".to_string(), history: "downloaded.txt".to_string(),
subscriptions: "subscriptions.txt".to_string(),
}), }),
)?; )?;
@ -76,6 +77,7 @@ mod tests {
&FileEnv::create(&Args { &FileEnv::create(&Args {
downloads: dir.path().to_string_lossy().to_string(), downloads: dir.path().to_string_lossy().to_string(),
history: "downloaded.txt".to_string(), history: "downloaded.txt".to_string(),
subscriptions: "subscriptions.txt".to_string(),
}), }),
)?; )?;

View file

@ -41,6 +41,7 @@ mod test {
&FileEnv::create(&Args { &FileEnv::create(&Args {
downloads: dir.path().to_string_lossy().to_string(), downloads: dir.path().to_string_lossy().to_string(),
history: "downloaded.txt".to_string(), history: "downloaded.txt".to_string(),
subscriptions: "subscriptions.txt".to_string(),
}), }),
)?; )?;
@ -76,6 +77,7 @@ mod test {
&FileEnv::create(&Args { &FileEnv::create(&Args {
downloads: dir.path().to_string_lossy().to_string(), downloads: dir.path().to_string_lossy().to_string(),
history: "downloaded.txt".to_string(), history: "downloaded.txt".to_string(),
subscriptions: "subscriptions.txt".to_string(),
}), }),
)?; )?;
@ -111,6 +113,7 @@ mod test {
&FileEnv::create(&Args { &FileEnv::create(&Args {
downloads: dir.path().to_string_lossy().to_string(), downloads: dir.path().to_string_lossy().to_string(),
history: "downloaded.txt".to_string(), history: "downloaded.txt".to_string(),
subscriptions: "subscriptions.txt".to_string(),
}), }),
)?; )?;

View file

@ -20,8 +20,8 @@ pub struct Env {
pub file: FileEnv, pub file: FileEnv,
} }
pub fn run(subscriptions: &str, site: &str, a: &Args, e: Env) -> Result<()> { pub fn run(site: &str, a: &Args, e: Env) -> Result<()> {
for channel_name in file::read::lines_from(subscriptions, &e.file)? { for channel_name in file::read::lines_from(&a.subscriptions, &e.file)? {
println!("Channel: {}", channel_name); println!("Channel: {}", channel_name);
let feed_url = feed::find(site, &channel_name, &e.network)?; let feed_url = feed::find(site, &channel_name, &e.network)?;
for entry in feed::get(&feed_url, &e.network)?.entries() { for entry in feed::get(&feed_url, &e.network)?.entries() {
@ -62,6 +62,8 @@ mod tests {
let subs_file_name = "subs"; let subs_file_name = "subs";
let subs_dir = let subs_dir =
create_text_file(subs_file_name, "@channel1\nignore me\n@channel2".as_bytes())?; create_text_file(subs_file_name, "@channel1\nignore me\n@channel2".as_bytes())?;
let subs_file_name = format!("{}/{}", subs_dir.path().to_string_lossy(), subs_file_name);
// one item from each channel is already listed in the downloads.txt file // one item from each channel is already listed in the downloads.txt file
let history_file_name = "history"; let history_file_name = "history";
let history_dir = create_text_file(history_file_name, "c1-f2\nc2-f3".as_bytes())?; let history_dir = create_text_file(history_file_name, "c1-f2\nc2-f3".as_bytes())?;
@ -74,6 +76,7 @@ mod tests {
let args = Args { let args = Args {
downloads: subs_dir.path().to_string_lossy().to_string(), downloads: subs_dir.path().to_string_lossy().to_string(),
history: history_file_name.clone(), history: history_file_name.clone(),
subscriptions: subs_file_name.clone(),
}; };
let env = Env { let env = Env {
network: NetworkEnv { network: NetworkEnv {
@ -95,10 +98,7 @@ mod tests {
}, },
file: FileEnv { file: FileEnv {
open: mock_file_open(HashMap::from([ open: mock_file_open(HashMap::from([
( (subs_file_name.to_string(), subs_file_name),
subs_file_name.to_string(),
format!("{}/{}", subs_dir.path().to_string_lossy(), subs_file_name),
),
(history_file_name.to_string(), history_file_name), (history_file_name.to_string(), history_file_name),
])), ])),
append_line: mock_file_append_line(), append_line: mock_file_append_line(),
@ -106,7 +106,7 @@ mod tests {
}; };
//when //when
run(subs_file_name, site, &args, env)?; run(site, &args, env)?;
//then //then
drop(subs_dir); drop(subs_dir);
drop(history_dir); drop(history_dir);

View file

@ -6,13 +6,11 @@ use podal::prelude::*;
fn main() -> Result<()> { fn main() -> Result<()> {
println!("Podal"); println!("Podal");
let subscriptions = "subscriptions.txt";
let site = "https://www.youtube.com/"; let site = "https://www.youtube.com/";
let args = Args::parse(); let args = Args::parse();
podal::run( podal::run(
subscriptions,
site, site,
&args, &args,
podal::Env { podal::Env {

View file

@ -12,4 +12,9 @@ pub struct Args {
/// Defaults to "downloaded.txt" located in the downloads directory. /// Defaults to "downloaded.txt" located in the downloads directory.
#[arg(long, default_value = "downloaded.txt")] #[arg(long, default_value = "downloaded.txt")]
pub history: String, pub history: String,
/// The name of the subscriptions file.
/// Defaults to "subscriptions.txt" located in the downloads directory.
#[arg(long, default_value = "subscriptions.txt")]
pub subscriptions: String,
} }

View file

@ -7,6 +7,7 @@ use std::{
sync::mpsc::Sender, sync::mpsc::Sender,
}; };
use anyhow::Context;
use tempfile::{tempdir, TempDir}; use tempfile::{tempdir, TempDir};
use crate::{ use crate::{
@ -63,10 +64,12 @@ pub fn mock_network_fetch_as_bytes_with_rss_entries(
pub fn mock_file_open(real_paths: HashMap<String, String>) -> FileOpenFn { pub fn mock_file_open(real_paths: HashMap<String, String>) -> FileOpenFn {
Box::new(move |path: &str| { Box::new(move |path: &str| {
if let Some(real_path) = real_paths.get(&path.to_string()) { if let Some(real_path) = real_paths.get(&path.to_string()) {
Ok(File::open(real_path)?) Ok(File::open(real_path).with_context(|| {
format!("test_utils/mock_file_open: path={path}, real_path={real_path}, path_map=[{:?}]", real_paths)
})?)
} else { } else {
Err(Error::message( Err(Error::message(
format!("Not implemented: file_open: {}", path).as_str(), format!("Not implemented: test_utils/mock_file_open: {}", path).as_str(),
)) ))
} }
}) })