Skip to content

Commit 82eb25e

Browse files
committed
All features implemented
1 parent 2bca53d commit 82eb25e

File tree

10 files changed

+115
-62
lines changed

10 files changed

+115
-62
lines changed

LibraryLoader.example.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[settings]
2-
download_path = "download" # Path to download/save libs to. Paths can be absolute or relative. Relative paths are relative to the current working directory.
3-
# watch_path = "watch" # Path to watch for zipped .epw files.
2+
output_path = "download" # Path to download/save libs to. Paths can be absolute or relative. Relative paths are relative to the current working directory.
3+
# watch_path = "" # Path to watch for zipped .epw files.
44
# format = "" # What format should be saved? Eagle, kikad, ..
55

66
# Component Search Engine Credentials

TODO.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
* [x] [Code] See `src/cse.rs#66`
66
* [x] [Code] Implement `std::fmt::Display` for `error::LLError`
77
* [ ] ~~[Feature] Mass download~~
8-
* [ ] [Feature] File watcher for zipped epw (and epw??) files
9-
* [ ] [Feature] Auto unzip folder and copy lib to libs folder
8+
* [x] [Feature] File watcher for zipped epw (and epw??) files
9+
* [x] [Feature] Auto unzip folder and copy lib to libs folder
1010
* [ ] [Code] New struct for CLI-only options
1111
* [x] [Feature] When using `-g`, treat input as output path
12+
* [ ] [Code] Split extractor from format

src/config.rs

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use super::profile::Profile;
22
use super::consts::LL_CONFIG;
33
use super::error::{LLResult, LLError};
4+
use super::format::Format;
45
use serde::Deserialize;
56
use std::{fs, path::PathBuf};
67
use clap::{self, load_yaml, crate_version};
@@ -20,31 +21,6 @@ struct ParseSettings {
2021
format: Option<String> // If set, extract relevant files and place them in output_path
2122
}
2223

23-
#[derive(Debug, Clone, PartialEq)]
24-
pub enum Format {
25-
EAGLE,
26-
ZIP
27-
}
28-
29-
impl Format {
30-
31-
pub fn from<S: Into<String>>(format: S) -> Self {
32-
33-
let f = format.into().to_lowercase();
34-
35-
match f.as_str() {
36-
"eagle" => Self::EAGLE,
37-
"zip" => Self::ZIP,
38-
_ => {
39-
eprintln!("Unknown format. Defaulting to ZIP!");
40-
Self::ZIP
41-
}
42-
}
43-
44-
}
45-
46-
}
47-
4824
#[derive(Debug, Clone)]
4925
pub struct Settings {
5026
pub output_path: String,

src/cse.rs

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
use super::config::{Config, Format};
1+
use super::config::Config;
2+
use super::format::{self, Extractor, Format, Files};
23
use super::epw::Epw;
34
use super::error::{LLResult, LLError};
45
use super::cse_result::CSEResult;
56
use super::consts::COMPONENT_SEARCH_ENGINE_URL;
67
use std::{
78
path::PathBuf,
8-
collections::HashMap,
9-
io::Read
9+
collections::HashMap
1010
};
1111
use reqwest::{self, header};
1212
use zip;
@@ -81,7 +81,7 @@ impl CSE {
8181

8282
if &self.config.settings.format == &Format::ZIP {
8383

84-
let mut files = HashMap::new();
84+
let mut files: Files = HashMap::new();
8585
files.insert(filename, body);
8686

8787
Ok(CSEResult {
@@ -106,28 +106,17 @@ impl CSE {
106106

107107
let reader = std::io::Cursor::new(&data);
108108
let mut archive = zip::ZipArchive::new(reader)?;
109-
let mut files = HashMap::<String, Vec<u8>>::new();
109+
let mut files: Files = HashMap::new();
110110

111111
for i in 0..archive.len() {
112112

113113
let mut item = archive.by_index(i)?;
114-
let filename = item.name();
114+
let filename = String::from(item.name());
115115

116116
match &self.config.settings.format {
117-
Format::EAGLE => {
118-
if filename.to_lowercase().contains("eagle") {
119-
println!("Filename: {}", filename);
120-
let path = PathBuf::from(filename);
121-
let base_name = path.file_name().unwrap().to_string_lossy().to_string();
122-
let mut f_data = Vec::<u8>::new();
123-
item.read_to_end(&mut f_data)?;
124-
files.insert(base_name, f_data);
125-
}
126-
},
117+
Format::EAGLE => format::eagle::Extractor::extract(&mut files, filename, &mut item)?,
127118
// ! NOTE: DO NOT ADD A _ => {} CATCHER HERE!
128-
Format::ZIP => {
129-
return Err(LLError::new("This should be unreachable!"))
130-
}
119+
Format::ZIP => return Err(LLError::new("This should be unreachable!"))
131120
};
132121

133122
}

src/epw.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,10 @@ impl Epw {
4747

4848
let mut map = HashMap::<&str, &str>::new();
4949

50-
// let id = lines.next()?.parse::<u32>()?;
51-
5250
let id = match lines.next() {
5351
Some(v) => v.parse::<u32>()?,
5452
None => {
55-
return Err(LLError::new("No data in input file"))
53+
return Err(LLError::new("No data in file"))
5654
}
5755
};
5856

@@ -98,7 +96,11 @@ impl Epw {
9896

9997
fn from_zip(raw_data: Vec<u8>) -> LLResult<Self> {
10098

101-
// println!("{:?}", &raw_data);
99+
// The zip library crashes if the archive is empty,
100+
// lets prevent that.
101+
if raw_data.len() == 0 {
102+
return Err(LLError::new("Zip archive seems to be empty"))
103+
}
102104

103105
// If the last byte is 0x0A, which it always seems to
104106
// be when downloading from Mouser, pop it and continue.

src/format/eagle.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
use super::extractor_prelude::*;
2+
3+
pub struct Extractor;
4+
5+
impl ExtractorTrait for Extractor {
6+
7+
fn extract<S: Into<String>>(files: &mut Files, file_path: S, item: &mut ZipFile) -> LLResult<()> {
8+
9+
let fp = file_path.into();
10+
11+
if fp.to_lowercase().contains("eagle") {
12+
let path = PathBuf::from(fp);
13+
let base_name = path.file_name().unwrap().to_string_lossy().to_string();
14+
let mut f_data = Vec::<u8>::new();
15+
item.read_to_end(&mut f_data)?;
16+
files.insert(base_name, f_data);
17+
}
18+
19+
Ok(())
20+
}
21+
22+
}
23+

src/format/extractor_prelude.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use std::collections::HashMap;
2+
3+
pub(super) use zip::read::ZipFile;
4+
pub(super) use super::super::error::LLResult;
5+
pub(super) use std::{io::Read, path::PathBuf};
6+
7+
pub type Files = HashMap::<String, Vec<u8>>;
8+
9+
pub trait ExtractorTrait {
10+
fn extract<S: Into<String>>(files: &mut Files, filepath: S, file: &mut ZipFile) -> LLResult<()>;
11+
}
12+
13+

src/format/mod.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
pub mod eagle;
2+
3+
pub(super) mod extractor_prelude;
4+
pub use extractor_prelude::{
5+
ExtractorTrait as Extractor,
6+
Files
7+
};
8+
9+
#[derive(Debug, Clone, PartialEq)]
10+
pub enum Format {
11+
EAGLE,
12+
ZIP
13+
}
14+
15+
impl Format {
16+
17+
pub fn from<S: Into<String>>(format: S) -> Self {
18+
19+
let f = format.into().to_lowercase();
20+
21+
match f.as_str() {
22+
"eagle" => Self::EAGLE,
23+
"zip" => Self::ZIP,
24+
_ => {
25+
eprintln!("Unknown format. Defaulting to ZIP!");
26+
Self::ZIP
27+
}
28+
}
29+
30+
}
31+
32+
}

src/main.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ mod epw;
88
mod cse;
99
mod cse_result;
1010
mod config;
11+
mod format;
1112
mod consts;
1213
mod watcher;
1314

@@ -62,6 +63,11 @@ fn real_main() -> LLResult<()> {
6263
}
6364
});
6465

66+
println!("Watching {}", &conf.settings.watch_path.unwrap());
67+
println!("Saving to: {}", &conf.settings.output_path);
68+
println!("Saving in format: {:?}", &conf.settings.format);
69+
println!("Press <Enter> to exit");
70+
6571
w.start()?;
6672

6773
} else if conf.input.is_empty() {

src/watcher.rs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ impl Watcher {
3939

4040
pub fn start(&mut self) -> LLResult<()> {
4141

42-
println!("Watching {}...", &self.path.as_path().canonicalize()?.to_string_lossy());
42+
// println!("Watching {}...", &self.path.as_path().canonicalize()?.to_string_lossy());
43+
// println!("Press <Enter> to exit");
4344

44-
&self.watcher.watch(&self.path, notify::RecursiveMode::NonRecursive)?;
45+
&self.watcher.watch(&self.path, notify::RecursiveMode::Recursive)?;
46+
// &self.watcher.configure(notify::Config::OngoingEvents(Some(std::time::Duration::from_millis(500))));
4547

4648
loop {
4749

@@ -93,23 +95,30 @@ impl Watcher {
9395

9496
fn handle_event(&self, evt: notify::Event) {
9597

96-
println!("{:#?}", evt);
97-
9898
let event = evt.clone();
9999
let path = &event.paths[0];
100100

101-
println!("{:#?}", event);
102-
103101
match event.kind {
104102

105103
notify::EventKind::Create(create_kind) => {
106104

107-
// #[cfg(debug_assertions)]
108-
// println!("{:#?}", evt);
109-
110105
match create_kind {
111106

112-
// ! FIXME: TODO: Figure out why this just stopped working...
107+
notify::event::CreateKind::Any => {
108+
109+
if path.as_path().is_file() {
110+
111+
println!("=> Detected: {}", path.as_path().to_str().unwrap());
112+
113+
match &self.handle_file(path) {
114+
Ok(p) => println!("=> Success: Saved to {}", p),
115+
Err(e) => eprintln!("=> Error: {}", e)
116+
};
117+
118+
}
119+
120+
},
121+
113122
notify::event::CreateKind::File => {
114123

115124
match &self.handle_file(path) {
@@ -118,7 +127,9 @@ impl Watcher {
118127
};
119128

120129
},
130+
121131
_ => {}
132+
122133
};
123134

124135
},

0 commit comments

Comments
 (0)