Skip to main content

pray_core/
render.rs

1use crate::paths::validate_destination_path;
2use crate::resolve::ResolvedProject;
3use crate::{PrayError, PrayResult};
4use std::path::PathBuf;
5
6#[derive(Debug, Clone)]
7pub struct RenderedTarget {
8    pub path: PathBuf,
9    pub content: String,
10    pub managed_spans: Vec<crate::lockfile::ManagedSpanRecord>,
11}
12
13pub fn render_project(project: &ResolvedProject) -> PrayResult<Vec<RenderedTarget>> {
14    let mut rendered = Vec::new();
15    for target in &project.manifest.targets {
16        for output in &target.outputs {
17            let relative = validate_destination_path(output)?;
18            let rendered_target =
19                crate::render_compose::render_target(project, target, relative.as_path())?;
20            if let Some(max_bytes) = target.max_bytes {
21                let size = rendered_target.content.len() as u64;
22                if size > max_bytes {
23                    return Err(PrayError::Render(format!(
24                        "target `{}` output `{}` is {size} bytes; max_bytes is {max_bytes}",
25                        target.name, output
26                    )));
27                }
28            }
29            rendered.push(rendered_target);
30        }
31    }
32    Ok(rendered)
33}
34
35pub use crate::render_write::{
36    layout_rendered_targets, write_rendered_targets, write_rendered_targets_with_previous_lockfile,
37};
38
39pub use crate::render_dest::{
40    materialize_provisioned_exports, provisioned_destination_status,
41    provisioned_destination_statuses, provisioned_lock_records, ProvisionedDestinationStatus,
42};
43pub use crate::render_provisioned::{
44    expected_provisioned_bytes, planned_provisioned_files, PlannedProvisionedFile,
45};
46
47pub use crate::render_file::read_destination_text;
48
49#[cfg(test)]
50mod patch_tests {
51    use crate::render_patch::patch_rendered_content;
52
53    #[test]
54    fn preserves_unmarked_text_and_updates_managed_body() {
55        let existing = "\
56## Shared instructions
57
58User note: keep this line.
59
60<!-- pray:abc123 -->
61old body
62<!-- pray:abc123 -->
63";
64        let fresh = "\
65## Shared instructions
66
67<!-- pray:abc123 -->
68new body
69<!-- pray:abc123 -->
70";
71        let patched = patch_rendered_content(existing, fresh);
72        assert!(patched.contains("User note: keep this line."));
73        assert!(patched.contains("new body"));
74        assert!(!patched.contains("old body"));
75    }
76
77    #[test]
78    fn rewrites_wholesale_when_existing_has_no_managed_overlap() {
79        let existing = "broken rendered output\n";
80        let fresh = "\
81<!-- pray:abc123 -->
82new body
83<!-- pray:abc123 -->
84";
85        assert_eq!(patch_rendered_content(existing, fresh), fresh);
86    }
87
88    #[test]
89    fn inserts_leading_managed_span_from_fresh_and_drops_stale_unmarked_embed() {
90        let existing = "\
91header
92
93old local body
94
95<!-- pray:abc123 -->
96package body
97<!-- pray:abc123 -->
98";
99        let fresh = "\
100header
101
102<!-- pray:local001 -->
103new local body
104<!-- pray:local001 -->
105
106<!-- pray:abc123 -->
107package body
108<!-- pray:abc123 -->
109";
110        let patched = patch_rendered_content(existing, fresh);
111        assert!(patched.contains("new local body"));
112        assert!(!patched.contains("old local body"));
113        assert!(patched.contains("<!-- pray:local001 -->"));
114        assert!(patched.contains("package body"));
115    }
116
117    #[test]
118    fn appends_trailing_managed_span_with_intervening_blank_line_from_fresh() {
119        let existing = "\
120<!-- pray:abc123 -->
121package body
122<!-- pray:abc123 -->
123";
124        let fresh = "\
125<!-- pray:abc123 -->
126package body
127<!-- pray:abc123 -->
128
129<!-- pray:local001 -->
130new local body
131<!-- pray:local001 -->
132";
133        assert_eq!(patch_rendered_content(existing, fresh), fresh);
134    }
135
136    #[test]
137    fn restores_missing_blank_line_between_adjacent_managed_spans() {
138        let existing = "\
139<!-- pray:abc123 -->
140package body
141<!-- pray:abc123 -->
142<!-- pray:local001 -->
143new local body
144<!-- pray:local001 -->
145";
146        let fresh = "\
147<!-- pray:abc123 -->
148package body
149<!-- pray:abc123 -->
150
151<!-- pray:local001 -->
152new local body
153<!-- pray:local001 -->
154";
155        assert_eq!(patch_rendered_content(existing, fresh), fresh);
156    }
157}