Skip to content

Commit 2bca53d

Browse files
committed
rc0
1 parent 3cc15ee commit 2bca53d

15 files changed

+484
-175
lines changed

Cargo.lock

Lines changed: 115 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ serde = "1.0.101"
1414
dirs = "2.0.2"
1515
toml = "0.5.3"
1616
rpassword = "4.0.1"
17-
18-
# File system watcher
17+
zip = "0.5.3"
1918
crossbeam-channel = "0.3.8"
2019
# notify = {version = "5.0.0-pre.1", features = ["serde"] }
21-
notify = "4.0.14"
20+
notify = "5.0.0-pre.1"

LibraryLoader.example.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[settings]
22
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-
# <not implemented> watch_path = "watch" # Path to watch for zipped .epw files.
4-
# <not implemented> format = "" # What format should be saved? Eagle, kikad, ..
3+
# watch_path = "watch" # Path to watch for zipped .epw files.
4+
# format = "" # What format should be saved? Eagle, kikad, ..
55

66
# Component Search Engine Credentials
77
[profile]

cli.yml

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: "olback <libloader@olback.net>"
44
about: "Download libraries from componentsearchengine.com"
55
args:
66
- input:
7-
help: "Path to .eqw file"
7+
help: "Path to .eqw/.zip file"
88
# required: true
99
index: 1
1010
- id:
@@ -27,24 +27,50 @@ args:
2727
value_name: watch
2828
takes_value: true
2929
multiple: false
30+
conflicts_with:
31+
- id
32+
- generate
3033
- output:
3134
help: "Path to save output in"
3235
short: o
3336
long: output
3437
value_name: output
3538
takes_value: true
3639
multiple: false
37-
# Not implemented yet
38-
# - format:
39-
# help: "Specify which format to output"
40-
# short: f
41-
# long: format
42-
# value_name: format
43-
# takes_value: true
44-
# multiple: false
45-
# possible_values:
46-
# - eagle
47-
# # - kikad
40+
- format:
41+
help: "Specify which format to output"
42+
short: f
43+
long: format
44+
value_name: format
45+
takes_value: true
46+
multiple: false
47+
possible_values:
48+
# - 3d
49+
# - allegro
50+
# - altium
51+
# - cadstar
52+
# - capture
53+
# - circuitstudio
54+
# - cr_5000
55+
# - cr_8000
56+
# - dehdl
57+
# - designspark_pcb
58+
# - designspark_pcb_pro
59+
# - diptrace
60+
- eagle
61+
# - easyeda
62+
# - easy_pc
63+
# - ecadstar
64+
# - kicad
65+
# - orcad_allegro16
66+
# - pads
67+
# - proteus
68+
# - pulsonix
69+
# - solidworks_pcb
70+
# - target_3001
71+
# - xdx_designer
72+
# - xpedition
73+
- zip
4874
- generate:
4975
help: "Generate sample config"
5076
short: g

epw/ATMEGA328P-AU-pcb-part-libraries.epw

Lines changed: 0 additions & 9 deletions
This file was deleted.

src/config.rs

Lines changed: 36 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,39 @@ struct ParseSettings {
2020
format: Option<String> // If set, extract relevant files and place them in output_path
2121
}
2222

23-
#[derive(Debug)]
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+
48+
#[derive(Debug, Clone)]
2449
pub struct Settings {
2550
pub output_path: String,
2651
pub watch_path: Option<String>,
27-
pub format: Option<String>
52+
pub format: Format
2853
}
2954

30-
#[derive(Debug)]
55+
#[derive(Debug, Clone)]
3156
pub struct Config {
3257
pub settings: Settings,
3358
pub profile: Profile,
@@ -64,8 +89,8 @@ impl Config {
6489
None => None
6590
},
6691
format: match s.format {
67-
Some(v) => Some(String::from(v)),
68-
None => None
92+
Some(v) => Format::from(v),
93+
None => Self::default().settings.format
6994
},
7095
}
7196
},
@@ -93,7 +118,7 @@ impl Config {
93118
None => settings.watch_path
94119
},
95120
format: match matches.value_of("format") {
96-
Some(v) => Some(String::from(v)),
121+
Some(v) => Format::from(v),
97122
None => settings.format
98123
}
99124
},
@@ -119,7 +144,7 @@ impl Config {
119144
None => Self::default().settings.watch_path
120145
},
121146
format: match matches.value_of("format") {
122-
Some(v) => Some(String::from(v)),
147+
Some(v) => Format::from(v),
123148
None => Self::default().settings.format
124149
},
125150
},
@@ -141,7 +166,6 @@ impl Config {
141166
{
142167
println!("-- Debug info from {file}#{line} --", file = std::file!(), line = std::line!());
143168
println!("{:#?}", conf);
144-
println!("-- End debug info from {file}#{line} --", file = std::file!(), line = std::line!());
145169
}
146170

147171
conf
@@ -179,22 +203,21 @@ impl Config {
179203

180204
match conf {
181205
Some(c) => Ok(c),
182-
None => Err(LLError::new(format!("{} not found", LL_CONFIG)))
206+
None => Err(LLError::new(format!("{file}#{line}: {p} not found", file = std::file!(), line = std::line!(), p = LL_CONFIG)))
183207
}
184208

185209
}
186210

187211
pub fn generate(input: &String) -> LLResult<String> {
188212

189-
// let path = PathBuf::from(LL_CONFIG);
190213
let path = PathBuf::from(match input.trim().is_empty() {
191214
true => LL_CONFIG,
192215
false => input
193216
});
194217

195218
if path.clone().exists() {
196219

197-
return Err(LLError::new(format!("{} already exists", path.to_str().unwrap())))
220+
return Err(LLError::new(format!("{file}#{line}: {err} already exists", file = std::file!(), line = std::line!(), err = path.to_str().unwrap())))
198221

199222
}
200223

@@ -203,7 +226,7 @@ impl Config {
203226
let path_as_string = String::from(path.to_str().unwrap());
204227
Ok(path_as_string)
205228
},
206-
Err(e) => Err(LLError::new(format!("{}", e)))
229+
Err(e) => Err(LLError::new(format!("{}#{}: {}", std::file!(), std::line!(), e)))
207230
}
208231

209232
}
@@ -220,7 +243,7 @@ impl Default for Config {
220243
settings: Settings {
221244
output_path: String::from("download"),
222245
watch_path: None,
223-
format: None
246+
format: Format::ZIP
224247
},
225248
profile: profile,
226249
input: String::new(),

src/cse.rs

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,27 @@
1-
use super::profile::Profile;
1+
use super::config::{Config, Format};
22
use super::epw::Epw;
33
use super::error::{LLResult, LLError};
44
use super::cse_result::CSEResult;
5-
use reqwest::{self, header};
65
use super::consts::COMPONENT_SEARCH_ENGINE_URL;
6+
use std::{
7+
path::PathBuf,
8+
collections::HashMap,
9+
io::Read
10+
};
11+
use reqwest::{self, header};
12+
use zip;
713

814
pub struct CSE {
9-
auth: String
15+
auth: String,
16+
config: Config
1017
}
1118

1219
impl CSE {
1320

14-
pub fn new(profile: &Profile) -> Self {
21+
pub fn new(config: &Config) -> Self {
1522
CSE {
16-
auth: profile.to_base64()
23+
auth: config.profile.to_base64(),
24+
config: config.clone()
1725
}
1826
}
1927

@@ -43,9 +51,7 @@ impl CSE {
4351

4452
let mut body = Vec::<u8>::new();
4553
if res.copy_to(&mut body).is_err() {
46-
4754
return Err(LLError::new("Error copying data from response"))
48-
4955
}
5056

5157
let filename = match res.headers().get("content-disposition") {
@@ -73,9 +79,64 @@ impl CSE {
7379
println!("-- End debug info from {file}#{line} --", file = std::file!(), line = std::line!());
7480
}
7581

82+
if &self.config.settings.format == &Format::ZIP {
83+
84+
let mut files = HashMap::new();
85+
files.insert(filename, body);
86+
87+
Ok(CSEResult {
88+
output_path: self.config.settings.output_path.to_owned(),
89+
files: files
90+
})
91+
92+
} else {
93+
94+
let lib_name = match filename.starts_with("LIB_") {
95+
true => filename.as_str()[4..].replace(".zip", ""),
96+
false => filename.replace(".zip", "")
97+
};
98+
99+
self.unzip(lib_name, body)
100+
101+
}
102+
103+
}
104+
105+
fn unzip(&self, lib_name: String, data: Vec<u8>) -> LLResult<CSEResult> {
106+
107+
let reader = std::io::Cursor::new(&data);
108+
let mut archive = zip::ZipArchive::new(reader)?;
109+
let mut files = HashMap::<String, Vec<u8>>::new();
110+
111+
for i in 0..archive.len() {
112+
113+
let mut item = archive.by_index(i)?;
114+
let filename = item.name();
115+
116+
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+
},
127+
// ! NOTE: DO NOT ADD A _ => {} CATCHER HERE!
128+
Format::ZIP => {
129+
return Err(LLError::new("This should be unreachable!"))
130+
}
131+
};
132+
133+
}
134+
135+
let path = PathBuf::from(&self.config.settings.output_path).join(lib_name);
136+
76137
Ok(CSEResult {
77-
filename: filename,
78-
data: body
138+
output_path: path.to_string_lossy().to_string(),
139+
files: files
79140
})
80141

81142
}

src/cse_result.rs

Lines changed: 37 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,54 @@
11
use super::error::{LLResult, LLError};
2-
use std::{path::Path, fs};
3-
use super::config::Config;
2+
use std::{
3+
path::{Path, PathBuf},
4+
fs,
5+
collections::HashMap
6+
};
7+
8+
// pub struct CSEResult {
9+
// pub format: Format,
10+
// pub output_path: String,
11+
// pub filename: String,
12+
// pub data: Vec<u8>
13+
// }
414

515
pub struct CSEResult {
6-
pub filename: String,
7-
pub data: Vec<u8>
16+
pub output_path: String,
17+
pub files: HashMap<String, Vec<u8>>
818
}
919

1020
impl CSEResult {
1121

12-
pub fn save(&self, config: &Config) -> LLResult<String> {
22+
pub fn save(&self) -> LLResult<String> {
1323

14-
let save_dir = Path::new(&config.settings.output_path);
15-
let path = save_dir.join(&self.filename);
24+
let save_dir = Path::new(&self.output_path);
1625

1726
if !save_dir.exists() {
1827
fs::create_dir_all(save_dir)?;
1928
}
2029

21-
match fs::write(&path, &self.data) {
30+
if &self.files.len() > &0 {
31+
32+
for (filename, data) in &self.files {
33+
let path = save_dir.join(filename);
34+
Self::write(path, data.to_vec())?;
35+
}
36+
37+
Ok(save_dir.canonicalize()?.to_str().unwrap_or("").to_string())
38+
39+
} else {
40+
41+
Err(LLError::new("No files found for your specified library"))
42+
43+
}
44+
45+
}
46+
47+
fn write(path: PathBuf, data: Vec<u8>) -> LLResult<String> {
48+
49+
match fs::write(&path, &data) {
2250
Ok(_) => Ok(path.to_str().unwrap().to_string()),
23-
Err(e) => Err(LLError::new(format!("{}", e)))
51+
Err(e) => Err(LLError::new(format!("{}#{}: {}", std::file!(), std::line!(), e)))
2452
}
2553

2654
}

0 commit comments

Comments
 (0)