1extern crate clap;
2extern crate pbr;
3
4use anyhow::Error;
5use clap::{App, Arg, ArgMatches, SubCommand};
6use pbr::ProgressBar;
7use std::io::Stdout;
8use std::path::Path;
9use std::sync::{Arc, Mutex};
10
11extern crate cmsis_pack;
12use cmsis_pack::pdsc::{dump_devices, Component, FileRef, Package};
13use cmsis_pack::update::{install, update, DownloadProgress};
14use cmsis_pack::utils::FromElem;
15
16mod config;
17
18pub use config::Config;
19
20struct CliProgress(Arc<Mutex<ProgressBar<Stdout>>>);
21
22impl DownloadProgress for CliProgress {
23 fn size(&self, files: usize) {
24 if let Ok(mut inner) = self.0.lock() {
25 inner.total = files as u64;
26 inner.show_speed = false;
27 inner.show_bar = true;
28 }
29 }
30 fn progress(&self, _: usize) {}
31 fn complete(&self) {
32 if let Ok(mut inner) = self.0.lock() {
33 inner.inc();
34 }
35 }
36 fn for_file(&self, _: &str) -> Self {
37 CliProgress(self.0.clone())
38 }
39}
40
41impl CliProgress {
42 fn new() -> Self {
43 let mut progress = ProgressBar::new(363);
44 progress.show_speed = false;
45 progress.show_time_left = false;
46 progress.format("[#> ]");
47 progress.message("Downloading Packs ");
48 CliProgress(Arc::new(Mutex::new(progress)))
49 }
50}
51
52pub fn install_args() -> App<'static, 'static> {
53 SubCommand::with_name("install")
54 .about("Install a CMSIS Pack file")
55 .version("0.1.0")
56 .arg(
57 Arg::with_name("PDSC")
58 .required(true)
59 .takes_value(true)
60 .index(1)
61 .multiple(true),
62 )
63}
64
65pub fn install_command(conf: &Config, args: &ArgMatches<'_>) -> Result<(), Error> {
66 let pdsc_list: Vec<_> = args
67 .values_of("PDSC")
68 .unwrap()
69 .filter_map(|input| Package::from_path(Path::new(input)).ok())
70 .collect();
71 let progress = CliProgress::new();
72 let updated = install(conf, pdsc_list.iter(), progress)?;
73 let num_updated = updated.iter().map(|_| 1).sum::<u32>();
74 match num_updated {
75 0 => {
76 log::info!("Already up to date");
77 }
78 1 => {
79 log::info!("Updated 1 package");
80 }
81 _ => {
82 log::info!("Updated {} package", num_updated);
83 }
84 }
85 Ok(())
86}
87
88pub fn update_args<'a, 'b>() -> App<'a, 'b> {
89 SubCommand::with_name("update")
90 .about("Update CMSIS PDSC files for indexing")
91 .version("0.1.0")
92}
93
94pub fn update_command(conf: &Config, _: &ArgMatches<'_>) -> Result<(), Error> {
95 let vidx_list = conf.read_vidx_list();
96 for url in vidx_list.iter() {
97 log::info!("Updating registry from `{}`", url);
98 }
99 let progress = CliProgress::new();
100 let updated = update(conf, vidx_list, progress)?;
101 let num_updated = updated.iter().map(|_| 1).sum::<u32>();
102 match num_updated {
103 0 => {
104 log::info!("Already up to date");
105 }
106 1 => {
107 log::info!("Updated 1 package");
108 }
109 _ => {
110 log::info!("Updated {} package", num_updated);
111 }
112 }
113 Ok(())
114}
115
116pub fn dump_devices_args<'a, 'b>() -> App<'a, 'b> {
117 SubCommand::with_name("dump-devices")
118 .about("Dump devices as json")
119 .version("0.1.0")
120 .arg(
121 Arg::with_name("devices")
122 .short("d")
123 .takes_value(true)
124 .help("Dump JSON in the specified file"),
125 )
126 .arg(
127 Arg::with_name("boards")
128 .short("b")
129 .takes_value(true)
130 .help("Dump JSON in the specified file"),
131 )
132 .arg(
133 Arg::with_name("INPUT")
134 .help("Input file to dump devices from")
135 .index(1),
136 )
137}
138
139pub fn dump_devices_command(c: &Config, args: &ArgMatches<'_>) -> Result<(), Error> {
140 let files = args
141 .value_of("INPUT")
142 .map(|input| vec![Path::new(input).to_path_buf()]);
143 let filenames = files
144 .or_else(|| {
145 c.pack_store.read_dir().ok().map(|rd| {
146 rd.flat_map(|dirent| dirent.into_iter().map(|p| p.path()))
147 .collect()
148 })
149 })
150 .unwrap();
151 let pdscs = filenames
152 .into_iter()
153 .flat_map(|filename| match Package::from_path(&filename) {
154 Ok(c) => Some(c),
155 Err(e) => {
156 log::error!("parsing {:?}: {}", filename, e);
157 None
158 }
159 })
160 .collect::<Vec<Package>>();
161 let to_ret = dump_devices(&pdscs, args.value_of("devices"), args.value_of("boards"));
162 log::debug!("exiting");
163 to_ret
164}
165
166pub fn check_args<'a, 'b>() -> App<'a, 'b> {
167 SubCommand::with_name("check")
168 .about("Check a project or pack for correct usage of the CMSIS standard")
169 .version("0.1.0")
170 .arg(
171 Arg::with_name("INPUT")
172 .help("Input file to check")
173 .required(true)
174 .index(1),
175 )
176}
177
178pub fn check_command(_: &Config, args: &ArgMatches<'_>) -> Result<(), Error> {
179 let filename = args.value_of("INPUT").unwrap();
180 match Package::from_path(Path::new(filename)) {
181 Ok(c) => {
182 log::info!("Parsing succedded");
183 log::info!("{} Valid Conditions", c.conditions.0.len());
184 let cond_lookup = c.make_condition_lookup();
185 let mut num_components = 0;
186 let mut num_files = 0;
187 for Component {
188 class,
189 group,
190 condition,
191 files,
192 ..
193 } in c.make_components().iter()
194 {
195 num_components += 1;
196 num_files += files.len();
197 if let Some(ref cond_name) = condition {
198 if !cond_lookup.contains_key(cond_name.as_str()) {
199 log::warn!(
200 "Component {}::{} references an unknown condition '{}'",
201 class,
202 group,
203 cond_name
204 );
205 }
206 }
207 for FileRef {
208 path, condition, ..
209 } in files.iter()
210 {
211 if let Some(ref cond_name) = condition {
212 if !cond_lookup.contains_key(cond_name.as_str()) {
213 log::warn!(
214 "File {:?} Component {}::{} references an unknown condition '{}'",
215 path,
216 class,
217 group,
218 cond_name
219 );
220 }
221 }
222 }
223 }
224 log::info!("{} Valid Devices", c.devices.0.len());
225 log::info!("{} Valid Software Components", num_components);
226 log::info!("{} Valid Files References", num_files);
227 }
228 Err(e) => {
229 log::error!("parsing {}: {}", filename, e);
230 }
231 }
232 log::debug!("exiting");
233 Ok(())
234}