1use crate::recipe::*;
4use std::fmt::Write;
5
6pub trait Renderer {
8 fn render(&self, recipe: &Recipe) -> String;
9}
10
11pub struct MetaYamlRenderer;
13
14impl Renderer for MetaYamlRenderer {
15 fn render(&self, recipe: &Recipe) -> String {
16 let mut out = String::new();
17 self.render_preamble(&mut out, &recipe.preamble);
18 self.render_package(&mut out);
19 self.render_source(&mut out, &recipe.source);
20 self.render_build(&mut out, &recipe.build);
21 self.render_requirements(&mut out, &recipe.requirements);
22 self.render_test(&mut out, &recipe.test);
23 self.render_about(&mut out, &recipe.about);
24 self.render_extra(&mut out, &recipe.extra);
25 let trimmed = out.trim_end_matches('\n');
27 format!("{trimmed}\n")
28 }
29}
30
31impl MetaYamlRenderer {
32 fn render_preamble(&self, out: &mut String, preamble: &Preamble) {
33 writeln!(out, "{{% set name = \"{}\" %}}", preamble.name).unwrap();
34 writeln!(out, "{{% set version = \"{}\" %}}", preamble.version).unwrap();
35 writeln!(out).unwrap();
36 }
37
38 fn render_package(&self, out: &mut String) {
39 writeln!(out, "package:").unwrap();
40 writeln!(out, " name: {{{{ name }}}}").unwrap();
41 writeln!(out, " version: {{{{ version }}}}").unwrap();
42 writeln!(out).unwrap();
43 }
44
45 fn render_source(&self, out: &mut String, source: &Source) {
46 writeln!(out, "source:").unwrap();
47 writeln!(out, " url: {}", source.url).unwrap();
48 if !source.filename.is_empty() {
53 writeln!(out, " fn: {}", source.filename).unwrap();
54 }
55 writeln!(out, " sha256: {}", source.sha256).unwrap();
56 writeln!(out).unwrap();
57 }
58
59 fn render_build(&self, out: &mut String, build: &Build) {
60 writeln!(out, "build:").unwrap();
61 writeln!(out, " number: 0").unwrap();
62 if let Some(script) = &build.script {
63 if script.contains('\n') {
64 writeln!(out, " script: |").unwrap();
65 for line in script.lines() {
66 writeln!(out, " {line}").unwrap();
67 }
68 } else {
69 writeln!(out, " script: {script}").unwrap();
70 }
71 }
72 if build.with_run_exports {
73 writeln!(out, " run_exports:").unwrap();
74 writeln!(
75 out,
76 " - {{{{ pin_subpackage(\"{}\", max_pin=\"{}\") }}}}",
77 build.name, build.max_pin
78 )
79 .unwrap();
80 }
81 writeln!(out).unwrap();
82 }
83
84 fn render_requirement(&self, out: &mut String, req: &Requirement) {
85 match (&req.version, &req.selector) {
86 (None, None) => writeln!(out, " - {}", req.name).unwrap(),
87 (Some(ver), None) => writeln!(out, " - {} {}", req.name, ver).unwrap(),
88 (None, Some(sel)) => writeln!(out, " - {} # [{sel}]", req.name).unwrap(),
89 (Some(ver), Some(sel)) => {
90 writeln!(out, " - {} {} # [{sel}]", req.name, ver).unwrap()
91 }
92 }
93 }
94
95 fn render_requirements(&self, out: &mut String, requirements: &Requirements) {
96 writeln!(out, "requirements:").unwrap();
97 if !requirements.build.is_empty() {
98 writeln!(out, " build:").unwrap();
99 for req in &requirements.build {
100 self.render_requirement(out, req);
101 }
102 }
103 if !requirements.host.is_empty() {
104 writeln!(out, " host:").unwrap();
105 for req in &requirements.host {
106 self.render_requirement(out, req);
107 }
108 }
109 if !requirements.run.is_empty() {
110 writeln!(out, " run:").unwrap();
111 for req in &requirements.run {
112 self.render_requirement(out, req);
113 }
114 }
115 writeln!(out).unwrap();
116 }
117
118 fn render_test(&self, out: &mut String, test: &Test) {
119 if test.commands.is_empty() {
120 return;
121 }
122 writeln!(out, "test:").unwrap();
123 writeln!(out, " commands:").unwrap();
124 for command in &test.commands {
125 writeln!(out, " - {command}").unwrap();
126 }
127 writeln!(out).unwrap();
128 }
129
130 fn render_about(&self, out: &mut String, about: &About) {
131 writeln!(out, "about:").unwrap();
132 if let Some(home) = &about.home {
133 writeln!(out, " home: {home}").unwrap();
134 }
135 if let Some(license) = &about.license {
136 writeln!(out, " license: {license}").unwrap();
137 }
138 if let Some(license_family) = &about.license_family {
139 writeln!(out, " license_family: {license_family}").unwrap();
140 }
141 match about.license_file.len() {
142 0 => {}
143 1 => writeln!(out, " license_file: {}", about.license_file[0]).unwrap(),
144 _ => {
145 writeln!(out, " license_file:").unwrap();
146 for f in &about.license_file {
147 writeln!(out, " - {f}").unwrap();
148 }
149 }
150 }
151 if let Some(summary) = &about.summary {
152 writeln!(out, " summary: {summary}").unwrap();
153 }
154 if let Some(dev_url) = &about.dev_url {
155 writeln!(out, " dev_url: {dev_url}").unwrap();
156 }
157 if let Some(doc_url) = &about.doc_url {
158 writeln!(out, " doc_url: {doc_url}").unwrap();
159 }
160 writeln!(out).unwrap();
161 }
162
163 fn render_extra(&self, out: &mut String, extra: &Extra) {
164 if extra.additional_platforms.is_empty()
165 && extra.recipe_maintainers.is_empty()
166 && extra.identifiers.is_empty()
167 && extra.skip_platforms.is_empty()
168 {
169 return;
170 }
171 writeln!(out, "extra:").unwrap();
172 if !extra.additional_platforms.is_empty() {
173 writeln!(out, " additional-platforms:").unwrap();
174 for plat in &extra.additional_platforms {
175 writeln!(out, " - {plat}").unwrap();
176 }
177 }
178 if !extra.recipe_maintainers.is_empty() {
179 writeln!(out, " recipe-maintainers:").unwrap();
180 for m in &extra.recipe_maintainers {
181 writeln!(out, " - {m}").unwrap();
182 }
183 }
184 if !extra.identifiers.is_empty() {
185 writeln!(out, " identifiers:").unwrap();
186 for id in &extra.identifiers {
187 writeln!(out, " - {id}").unwrap();
188 }
189 }
190 if !extra.skip_platforms.is_empty() {
191 writeln!(out, " skip-platforms:").unwrap();
192 for plat in &extra.skip_platforms {
193 writeln!(out, " - {plat}").unwrap();
194 }
195 }
196 writeln!(out).unwrap();
197 }
198}