1use super::MinimalContext;
2use crate::apply::SystemState;
3use crate::requirements::Requirement;
4use crate::system::System;
5use crate::{
6 graph::{ApplyResult, Graph, Pending},
7 StateDirs,
8};
9use std::path::{Path, PathBuf};
10
11pub struct PreparedBuild<'d, R> {
12 contexts: Vec<MinimalContext>,
13 install: &'d StateDirs,
14 target_graph: Graph<R, Pending>,
15}
16
17impl<'d, R: Requirement> PreparedBuild<'d, R> {
18 pub fn new(
19 install: &'d StateDirs,
20 contexts: Vec<MinimalContext>,
21 graph: Graph<R, Pending>,
22 ) -> Self {
23 PreparedBuild {
24 contexts,
25 install,
26 target_graph: graph,
27 }
28 }
29
30 pub fn generate_files<'r, S: System>(
31 &self,
32 system: &mut S,
33 _prev: &SystemState<R>,
34 ) -> Result<&Graph<R, Pending>, ()> {
35 self.install.create_dirs(system).unwrap();
37
38 for config in self.contexts.iter().map(|c| c.files.iter()).flatten() {
40 let path = config.source.parent().unwrap();
41 println!(" prep : {}", config.source.display());
42 system.make_dir_all(&path).unwrap();
43 system
44 .put_file_contents(&config.source, &config.contents)
45 .unwrap();
46 }
47
48 for deleted in self
49 .contexts
50 .iter()
51 .map(|c| c.deleted_files.iter())
52 .flatten()
53 {
54 let path = deleted.save_to.parent().unwrap();
55 println!(" prep : {}", path.display());
56 system.make_dir_all(&path).unwrap();
57 }
58
59 for context in self.contexts.iter() {
62 for exposed in context.exposed.iter() {
63 println!(" expose: {:?}", exposed.source);
64 let metadata = exposed.source.symlink_metadata().unwrap();
65 if metadata.file_type().is_dir() {
66 system.make_dir_all(&exposed.target).unwrap();
67 copy(system, &exposed.source, &exposed.target).unwrap();
68 } else {
69 copy_file(system, &exposed.source, &exposed.target).unwrap();
70 }
71 }
72 }
73
74 Ok(&self.target_graph)
75 }
76
77 pub fn save<S: System>(
78 self,
79 system: &mut S,
80 result: ApplyResult,
81 ) -> Result<SystemState<R>, ()> {
82 let state = SystemState {
83 graph: self.target_graph.apply_execution_results(result),
84 };
85
86 self.install.write_dbs(system, &state).unwrap();
87 Ok(state)
88 }
89}
90
91pub fn copy<S: System, U: AsRef<Path>, V: AsRef<Path>>(
92 system: &mut S,
93 from: U,
94 to: V,
95) -> Result<(), S::Error> {
96 let mut stack = Vec::new();
97 stack.push(PathBuf::from(from.as_ref()));
98
99 let output_root = PathBuf::from(to.as_ref());
100 let input_root = PathBuf::from(from.as_ref()).components().count();
101
102 while let Some(working_path) = stack.pop() {
103 let src: PathBuf = working_path.components().skip(input_root).collect();
105
106 let dest = if src.components().count() == 0 {
108 output_root.clone()
109 } else {
110 output_root.join(&src)
111 };
112
113 if !system.path_exists(&dest)? {
114 system.make_dir_all(&dest)?;
115 }
116
117 for entry in system.read_dir(&working_path)? {
118 let path = working_path.join(entry);
119 if path.is_dir() {
120 stack.push(path);
121 } else {
122 match path.file_name() {
123 Some(filename) => {
124 let dest_path = dest.join(filename);
125 copy_file(system, &path, &dest_path)?;
126 }
127 None => {
128 panic!("failed to copy: {:?}", path);
129 }
130 }
131 }
132 }
133 }
134
135 Ok(())
136}
137
138fn copy_file<S: System>(system: &mut S, path: &PathBuf, dest: &PathBuf) -> Result<(), S::Error> {
139 Ok(system.copy_file(&path, &dest)?)
141}