Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 237 additions & 0 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,7 @@ serde = "1.0.101"
dirs = "2.0.2"
toml = "0.5.3"
rpassword = "4.0.1"
zip = "0.5.3"
crossbeam-channel = "0.3.8"
# notify = {version = "5.0.0-pre.1", features = ["serde"] }
notify = "5.0.0-pre.1"
6 changes: 3 additions & 3 deletions LibraryLoader.example.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[settings]
download_path = "download" # Path to download/save libs to. Paths can be absolute or relative. Relative paths are relative to the current working directory.
# <not implemented> watch_path = "watch" # Path to watch for zipped .epw files.
# <not implemented> format = "" # What format should be saved? Eagle, kikad, ..
output_path = "download" # Path to download/save libs to. Paths can be absolute or relative. Relative paths are relative to the current working directory.
# watch_path = "" # Path to watch for zipped .epw files.
# format = "" # What format should be saved? Eagle, kikad, ..

# Component Search Engine Credentials
[profile]
Expand Down
10 changes: 8 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
# [WIP] Library Loader :books:
# Library Loader :books:

[![CircleCI](https://circleci.com/gh/olback/library-loader/tree/master.svg?style=svg)](https://circleci.com/gh/olback/library-loader/tree/master)
![Screenshot](libloader.png)

OS/Platform | Status
----------- | ------
Linux x86_64 | [![CircleCI](https://circleci.com/gh/olback/library-loader/tree/master.svg?style=svg)](https://circleci.com/gh/olback/library-loader/tree/master)
Windows | WIP
Mac | WIP

Rust implementation of [https://www.samacsys.com/library-loader/](https://www.samacsys.com/library-loader/).

Expand Down
9 changes: 7 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
* [x] [Code] See `src/cse.rs#66`
* [x] [Code] Implement `std::fmt::Display` for `error::LLError`
* [ ] ~~[Feature] Mass download~~
* [ ] [Feature] File watcher for zipped epw (and epw??) files
* [ ] [Feature] Auto unzip folder and copy lib to libs folder
* [x] [Feature] File watcher for zipped epw (and epw??) files
* [x] [Feature] Auto unzip folder and copy lib to libs folder
* [ ] [Code] New struct for CLI-only options
* [x] [Feature] When using `-g`, treat input as output path
* [ ] [Code] Split extractor from format
* [ ] [Docs] Proper documentation
* [ ] [Code] Document the code...
* [ ] [Feature] Show Desktop Notification?
* [ ] [Feature] Additional flag for `-g` to save in uses config dir.
64 changes: 45 additions & 19 deletions cli.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ author: "olback <libloader@olback.net>"
about: "Download libraries from componentsearchengine.com"
args:
- input:
help: "Path to .eqw file"
help: "Path to .eqw/.zip file"
# required: true
index: 1
- id:
Expand All @@ -20,31 +20,57 @@ args:
value_name: config
takes_value: true
multiple: false
# - watch:
# help: "Path to watch for .epw files. Setting this will enable watch-mode"
# short: w
# long: watch
# value_name: watch
# takes_value: true
# multiple: false
- watch:
help: "Path to watch for .epw files. Setting this will enable watch-mode"
short: w
long: watch
value_name: watch
takes_value: true
multiple: false
conflicts_with:
- id
- generate
- output:
help: "Path to save output in"
short: o
long: output
value_name: output
takes_value: true
multiple: false
# Not implemented yet
# - format:
# help: "Specify which format to output"
# short: f
# long: format
# value_name: format
# takes_value: true
# multiple: false
# possible_values:
# - eagle
# # - kikad
- format:
help: "Specify which format to output"
short: f
long: format
value_name: format
takes_value: true
multiple: false
possible_values:
# - 3d
# - allegro
# - altium
# - cadstar
# - capture
# - circuitstudio
# - cr_5000
# - cr_8000
# - dehdl
# - designspark_pcb
# - designspark_pcb_pro
# - diptrace
- eagle
# - easyeda
# - easy_pc
# - ecadstar
# - kicad
# - orcad_allegro16
# - pads
# - proteus
# - pulsonix
# - solidworks_pcb
# - target_3001
# - xdx_designer
# - xpedition
- zip
- generate:
help: "Generate sample config"
short: g
Expand Down
9 changes: 0 additions & 9 deletions epw/ATMEGA328P-AU-pcb-part-libraries.epw

This file was deleted.

Binary file added libloader.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 12 additions & 13 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use super::profile::Profile;
use super::consts::LL_CONFIG;
use super::error::{LLResult, LLError};
use super::format::Format;
use serde::Deserialize;
use std::{fs, path::PathBuf};
use clap::{self, load_yaml, crate_version};
Expand All @@ -20,14 +21,14 @@ struct ParseSettings {
format: Option<String> // If set, extract relevant files and place them in output_path
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Settings {
pub output_path: String,
pub watch_path: Option<String>,
pub format: Option<String>
pub format: Format
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Config {
pub settings: Settings,
pub profile: Profile,
Expand Down Expand Up @@ -64,8 +65,8 @@ impl Config {
None => None
},
format: match s.format {
Some(v) => Some(String::from(v)),
None => None
Some(v) => Format::from(v),
None => Self::default().settings.format
},
}
},
Expand Down Expand Up @@ -93,7 +94,7 @@ impl Config {
None => settings.watch_path
},
format: match matches.value_of("format") {
Some(v) => Some(String::from(v)),
Some(v) => Format::from(v),
None => settings.format
}
},
Expand All @@ -119,7 +120,7 @@ impl Config {
None => Self::default().settings.watch_path
},
format: match matches.value_of("format") {
Some(v) => Some(String::from(v)),
Some(v) => Format::from(v),
None => Self::default().settings.format
},
},
Expand All @@ -141,7 +142,6 @@ impl Config {
{
println!("-- Debug info from {file}#{line} --", file = std::file!(), line = std::line!());
println!("{:#?}", conf);
println!("-- End debug info from {file}#{line} --", file = std::file!(), line = std::line!());
}

conf
Expand Down Expand Up @@ -179,22 +179,21 @@ impl Config {

match conf {
Some(c) => Ok(c),
None => Err(LLError::new(format!("{} not found", LL_CONFIG)))
None => Err(LLError::new(format!("{file}#{line}: {p} not found", file = std::file!(), line = std::line!(), p = LL_CONFIG)))
}

}

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

// let path = PathBuf::from(LL_CONFIG);
let path = PathBuf::from(match input.trim().is_empty() {
true => LL_CONFIG,
false => input
});

if path.clone().exists() {

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

}

Expand All @@ -203,7 +202,7 @@ impl Config {
let path_as_string = String::from(path.to_str().unwrap());
Ok(path_as_string)
},
Err(e) => Err(LLError::new(format!("{}", e)))
Err(e) => Err(LLError::new(format!("{}#{}: {}", std::file!(), std::line!(), e)))
}

}
Expand All @@ -220,7 +219,7 @@ impl Default for Config {
settings: Settings {
output_path: String::from("download"),
watch_path: None,
format: None
format: Format::ZIP
},
profile: profile,
input: String::new(),
Expand Down
68 changes: 59 additions & 9 deletions src/cse.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
use super::profile::Profile;
use super::config::Config;
use super::format::{self, Extractor, Format, Files};
use super::epw::Epw;
use super::error::{LLResult, LLError};
use super::cse_result::CSEResult;
use reqwest::{self, header};
use super::consts::COMPONENT_SEARCH_ENGINE_URL;
use std::{
path::PathBuf,
collections::HashMap
};
use reqwest::{self, header};
use zip;

pub struct CSE {
auth: String
auth: String,
config: Config
}

impl CSE {

pub fn new(profile: &Profile) -> Self {
pub fn new(config: &Config) -> Self {
CSE {
auth: profile.to_base64()
auth: config.profile.to_base64(),
config: config.clone()
}
}

Expand Down Expand Up @@ -43,9 +51,7 @@ impl CSE {

let mut body = Vec::<u8>::new();
if res.copy_to(&mut body).is_err() {

return Err(LLError::new("Error copying data from response"))

}

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

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

let mut files: Files = HashMap::new();
files.insert(filename, body);

Ok(CSEResult {
output_path: self.config.settings.output_path.to_owned(),
files: files
})

} else {

let lib_name = match filename.starts_with("LIB_") {
true => filename.as_str()[4..].replace(".zip", ""),
false => filename.replace(".zip", "")
};

self.unzip(lib_name, body)

}

}

fn unzip(&self, lib_name: String, data: Vec<u8>) -> LLResult<CSEResult> {

let reader = std::io::Cursor::new(&data);
let mut archive = zip::ZipArchive::new(reader)?;
let mut files: Files = HashMap::new();

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

let mut item = archive.by_index(i)?;
let filename = String::from(item.name());

match &self.config.settings.format {
Format::EAGLE => format::eagle::Extractor::extract(&mut files, filename, &mut item)?,
// ! NOTE: DO NOT ADD A _ => {} CATCHER HERE!
Format::ZIP => return Err(LLError::new("This should be unreachable!"))
};

}

let path = PathBuf::from(&self.config.settings.output_path).join(lib_name);

Ok(CSEResult {
filename: filename,
data: body
output_path: path.to_string_lossy().to_string(),
files: files
})

}
Expand Down
Loading