assemble_core/project/
requests.rs1use crate::error::PayloadError;
4use crate::identifier::TaskId;
5use crate::project::error::{ProjectError, ProjectResult};
6use crate::project::finder::{ProjectFinder, ProjectPathBuf, TaskFinder, TaskPath, TaskPathBuf};
7use crate::project::shared::SharedProject;
8use crate::task::flags::{OptionsSlurper, WeakOptionsDecoder};
9use std::collections::{HashMap, VecDeque};
10
11#[derive(Debug)]
13pub struct TaskRequests {
14 task_to_weak_decoder: HashMap<TaskId, usize>,
15 weak_decoders: Vec<WeakOptionsDecoder>,
16 tasks: Vec<TaskId>,
17}
18
19impl TaskRequests {
20 pub fn build<I: IntoIterator<Item = S>, S: AsRef<TaskPath>>(
23 project: &SharedProject,
24 args: I,
25 ) -> ProjectResult<Self> {
26 let mut builder = TaskRequestsBuilder::new();
27 let mut reqs: VecDeque<TaskPathBuf> =
28 VecDeque::from_iter(args.into_iter().map(|s| s.as_ref().to_owned()));
29
30 if reqs.is_empty() {
31 project.with(|p| {
33 reqs.extend(p.default_tasks().iter().map(|s| s.clone().into()));
34 })
35 }
36
37 if reqs.is_empty() {
38 return Ok(builder.finish());
39 }
40
41 let task_finder = TaskFinder::new(project);
42 let proj_finder = ProjectFinder::new(project);
43
44 while let Some(task) = reqs.pop_front() {
45 let task_req: &TaskPath = task.as_ref();
46 debug!("attempting to find tasks for task path {:?}", task_req);
47
48 let ids: Option<Vec<TaskId>> = task_finder.find(task_req)?;
49
50 if let Some(ids) = ids {
51 let first = ids.first().unwrap();
52
53 let project = proj_finder
54 .find(ProjectPathBuf::from(first.project_id().unwrap()))
55 .unwrap();
56
57 let mut any_handle = project.get_task(first)?;
58 let resolved = any_handle.resolve_shared(&project)?;
59
60 if let Some(ops) = resolved.options_declarations() {
61 let slurper = OptionsSlurper::new(&ops);
62 let slice = reqs.make_contiguous();
63 let (weak, count) = slurper.slurp(slice).map_err(PayloadError::new)?;
64 builder.add_configured_tasks(ids, weak);
65 reqs.drain(..count);
66 } else {
67 builder.add_tasks(ids);
68 }
69 } else {
70 return Err(ProjectError::NoIdentifiersFound(task_req.to_string()).into());
71 }
72 }
73
74 Ok(builder.finish())
75 }
76
77 pub fn decoder(&self, id: &TaskId) -> Option<WeakOptionsDecoder> {
79 let index = self.task_to_weak_decoder.get(id)?;
80 Some(self.weak_decoders[*index].clone())
81 }
82
83 pub fn requested_tasks(&self) -> &[TaskId] {
85 &self.tasks[..]
86 }
87}
88
89struct TaskRequestsBuilder {
90 in_progress: TaskRequests,
91}
92
93impl TaskRequestsBuilder {
94 fn new() -> Self {
95 Self {
96 in_progress: TaskRequests {
97 task_to_weak_decoder: Default::default(),
98 weak_decoders: vec![],
99 tasks: vec![],
100 },
101 }
102 }
103
104 fn finish(self) -> TaskRequests {
105 self.in_progress
106 }
107
108 fn add_tasks<I>(&mut self, tasks: I)
109 where
110 I: IntoIterator<Item = TaskId>,
111 {
112 self.in_progress.tasks.extend(tasks)
113 }
114
115 fn add_configured_tasks<I>(&mut self, tasks: I, decoder: WeakOptionsDecoder)
116 where
117 I: IntoIterator<Item = TaskId>,
118 {
119 let index = self.in_progress.weak_decoders.len();
120 self.in_progress.weak_decoders.push(decoder);
121 for task in tasks {
122 self.in_progress.tasks.push(task.clone());
123 self.in_progress.task_to_weak_decoder.insert(task, index);
124 }
125 }
126}