Skip to content

Commit d86df6d

Browse files
committed
refactor resource discovery code to use new helper functions
1 parent 9073d00 commit d86df6d

File tree

2 files changed

+44
-132
lines changed

2 files changed

+44
-132
lines changed

dsc_lib/src/discovery/command_discovery.rs

Lines changed: 40 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::ffi::OsStr;
1717
use std::fs::File;
1818
use std::io::BufReader;
1919
use std::path::{Path, PathBuf};
20-
use tracing::{debug, error, info, trace, warn, warn_span, Span};
20+
use tracing::{debug, info, trace, warn, warn_span};
2121
use tracing_indicatif::span_ext::IndicatifSpanExt;
2222

2323
pub struct CommandDiscovery {
@@ -273,144 +273,52 @@ impl ResourceDiscovery for CommandDiscovery {
273273
Ok(resources)
274274
}
275275

276-
#[allow(clippy::too_many_lines)]
276+
// TODO: handle version requirements
277277
fn find_resources(&mut self, required_resource_types: &[String]) -> Result<BTreeMap<String, DscResource>, DscError>
278278
{
279279
debug!("Searching for resources: {:?}", required_resource_types);
280+
self.discover_resources("*")?;
280281

281-
let pb_span = warn_span!("");
282-
pb_span.pb_set_style(&ProgressStyle::with_template(
283-
"{spinner:.green} [{elapsed_precise:.cyan}] [{bar:40.cyan/blue}] {pos:>7}/{len:7} {msg:.yellow}"
284-
)?);
285-
pb_span.pb_set_message("Searching for resources");
286-
let _ = pb_span.enter();
287-
288-
let mut resources: BTreeMap<String, DscResource> = BTreeMap::new();
289-
let mut adapter_resources: BTreeMap<String, DscResource> = BTreeMap::new();
282+
let mut found_resources = BTreeMap::<String, DscResource>::new();
290283
let mut remaining_required_resource_types = required_resource_types.to_owned();
291284

292-
if let Ok(paths) = CommandDiscovery::get_resource_paths() {
293-
for path in paths {
294-
debug!("Searching in {:?}", path);
295-
if path.exists() && path.is_dir() {
296-
for entry in path.read_dir().unwrap() {
297-
let entry = entry.unwrap();
298-
let path = entry.path();
299-
if path.is_file() {
300-
let file_name = path.file_name().unwrap().to_str().unwrap();
301-
let file_name_lowercase = file_name.to_lowercase();
302-
if file_name_lowercase.ends_with(".dsc.resource.json") ||
303-
file_name_lowercase.ends_with(".dsc.resource.yaml") ||
304-
file_name_lowercase.ends_with(".dsc.resource.yml") {
305-
let resource = match load_manifest(&path)
306-
{
307-
Ok(r) => r,
308-
Err(e) => {
309-
/* In case of non-list resource/config operations:
310-
At this point we can't determine whether or not the bad manifest contains resource that is requested by resource/config operation
311-
if it is, then "ResouceNotFound" error will be issued later
312-
and here we just record the error into debug stream.*/
313-
debug!("{}", e);
314-
continue;
315-
},
316-
};
285+
for (resource_name, resources) in self.resources.iter() {
286+
let Some(resource ) = resources.first() else {
287+
// skip if no resources
288+
continue;
289+
};
317290

318-
if let Some(ref manifest) = resource.manifest {
319-
let manifest = import_manifest(manifest.clone())?;
320-
if manifest.kind == Some(Kind::Adapter) {
321-
adapter_resources.insert(resource.type_name.to_lowercase(), resource.clone());
322-
resources.insert(resource.type_name.to_lowercase(), resource.clone());
323-
}
324-
}
325-
if remaining_required_resource_types.contains(&resource.type_name.to_lowercase())
326-
{
327-
remaining_required_resource_types.retain(|x| *x != resource.type_name.to_lowercase());
328-
debug!("Found {} in {}", &resource.type_name, path.display());
329-
Span::current().pb_inc(1);
330-
resources.insert(resource.type_name.to_lowercase(), resource);
331-
if remaining_required_resource_types.is_empty()
332-
{
333-
return Ok(resources);
334-
}
335-
}
336-
}
337-
}
338-
}
291+
if remaining_required_resource_types.contains(&resource_name.to_lowercase())
292+
{
293+
// remove the resource from the list of required resources
294+
remaining_required_resource_types.retain(|x| *x != resource_name.to_lowercase());
295+
found_resources.insert(resource_name.to_lowercase(), resource.clone());
296+
if remaining_required_resource_types.is_empty()
297+
{
298+
return Ok(found_resources);
339299
}
340300
}
341301
}
342-
debug!("Found {} matching non-adapter-based resources", resources.len());
302+
debug!("Found {} matching non-adapter-based resources", found_resources.len());
343303

344304
// now go through the adapter resources and add them to the list of resources
345-
for adapter in adapter_resources {
346-
debug!("Enumerating resources for adapter '{}'", adapter.1.type_name);
347-
let pb_adapter_span = warn_span!("");
348-
pb_adapter_span.pb_set_style(&ProgressStyle::with_template(
349-
"{spinner:.green} [{elapsed_precise:.cyan}] {msg:.white}"
350-
)?);
351-
pb_adapter_span.pb_set_message(format!("Enumerating resources for adapter '{}'", adapter.1.type_name).as_str());
352-
let _ = pb_adapter_span.enter();
353-
let adapter_resource = adapter.1;
354-
let adapter_type_name = adapter_resource.type_name.clone();
355-
let manifest = if let Some(manifest) = adapter_resource.manifest {
356-
if let Ok(manifest) = import_manifest(manifest) {
357-
manifest
358-
} else {
359-
return Err(DscError::Operation(format!("Failed to import manifest for '{}'", adapter_resource.type_name.clone())));
360-
}
361-
} else {
362-
return Err(DscError::MissingManifest(adapter_resource.type_name.clone()));
305+
for (adapted_name, adapted_resource) in self.adapted_resources.iter() {
306+
let Some(adapted_resource) = adapted_resource.first() else {
307+
// skip if no resources
308+
continue;
363309
};
364-
let mut adapter_resources_count = 0;
365-
// invoke the list command
366-
let list_command = manifest.adapter.unwrap().list;
367-
let (exit_code, stdout, stderr) = match invoke_command(&list_command.executable, list_command.args, None, Some(&adapter_resource.directory), None)
368-
{
369-
Ok((exit_code, stdout, stderr)) => (exit_code, stdout, stderr),
370-
Err(e) => {
371-
/* In case of non-list resource/config operations:
372-
print failure from adapter as error because this adapter was specifically requested by current resource/config operation*/
373-
error!("Could not start {}: {}", list_command.executable, e);
374-
continue;
375-
},
376-
};
377-
log_resource_traces(&stderr);
378310

379-
if exit_code != 0 {
380-
/* In case of non-list resource/config operations:
381-
print failure from adapter as error because this adapter was specifically requested by current resource/config operation*/
382-
error!("Adapter failed to list resources with exit code {exit_code}: {stderr}");
383-
}
384-
385-
for line in stdout.lines() {
386-
match serde_json::from_str::<DscResource>(line){
387-
Result::Ok(resource) => {
388-
if resource.require_adapter.is_none() {
389-
error!("{}", DscError::MissingRequires(adapter.0.clone(), resource.type_name.clone()).to_string());
390-
continue;
391-
}
392-
if remaining_required_resource_types.contains(&resource.type_name.to_lowercase())
393-
{
394-
remaining_required_resource_types.retain(|x| *x != resource.type_name.to_lowercase());
395-
debug!("Found {} in {}", &resource.type_name, &resource.path);
396-
resources.insert(resource.type_name.to_lowercase(), resource);
397-
adapter_resources_count += 1;
398-
if remaining_required_resource_types.is_empty()
399-
{
400-
return Ok(resources);
401-
}
402-
}
403-
},
404-
Result::Err(err) => {
405-
error!("Failed to parse resource: {line} -> {err}");
406-
continue;
407-
}
408-
};
311+
if remaining_required_resource_types.contains(&adapted_name.to_lowercase())
312+
{
313+
remaining_required_resource_types.retain(|x| *x != adapted_name.to_lowercase());
314+
found_resources.insert(adapted_name.to_lowercase(), adapted_resource.clone());
315+
if remaining_required_resource_types.is_empty()
316+
{
317+
return Ok(found_resources);
318+
}
409319
}
410-
411-
debug!("Adapter '{}' listed {} matching resources", adapter_type_name, adapter_resources_count);
412320
}
413-
Ok(resources)
321+
Ok(found_resources)
414322
}
415323
}
416324

@@ -423,8 +331,15 @@ fn insert_resource(resources: &mut BTreeMap<String, Vec<DscResource>>, resource:
423331
};
424332
// compare the resource versions and insert newest to oldest using semver
425333
let mut insert_index = resource_versions.len();
426-
for (index, resource_version) in resource_versions.iter().enumerate() {
427-
if Version::parse(&resource_version.version)? < Version::parse(&resource.version)? {
334+
for (index, resource_instance) in resource_versions.iter().enumerate() {
335+
let resource_instance_version = Version::parse(&resource_instance.version)?;
336+
let resource_version = Version::parse(&resource.version)?;
337+
// if the version already exists, we skip
338+
if resource_instance_version == resource_version {
339+
return Ok(());
340+
}
341+
342+
if resource_instance_version < resource_version {
428343
insert_index = index;
429344
break;
430345
}

dsc_lib/src/discovery/mod.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ impl Discovery {
2727
}
2828

2929
/// List operation.
30-
#[allow(clippy::missing_panics_doc)] // false positive in clippy; this function will never panic
3130
pub fn list_available_resources(&mut self, type_name_filter: &str, adapter_name_filter: &str) -> Vec<DscResource> {
3231
let discovery_types: Vec<Box<dyn ResourceDiscovery>> = vec![
3332
Box::new(command_discovery::CommandDiscovery::new()),
@@ -45,12 +44,10 @@ impl Discovery {
4544
}
4645
};
4746

48-
for (_resource_name, resource) in discovered_resources {
49-
let Some(resource) = resource.first() else {
50-
continue;
51-
};
52-
53-
resources.push(resource.clone());
47+
for (_resource_name, found_resources) in discovered_resources {
48+
for resource in found_resources {
49+
resources.push(resource.clone());
50+
}
5451
};
5552
}
5653

0 commit comments

Comments
 (0)