1use crate::CargoToml;
4use crate::types::{Dependency, LibTarget, NonLibTarget, PatchSet, Profile};
5use crate::error::Error;
6
7use toml_edit::{self, Array, ArrayOfTables, Document, InlineTable, Item, Table, Value};
8
9const DEFAULT_VERSION: &'static str = "0.1.0";
10
11pub(crate) struct TomlOutput(CargoToml);
12
13impl TomlOutput {
14 pub(crate) fn new(c: &CargoToml) -> TomlOutput {
15 TomlOutput(c.clone())
16 }
17
18
19 pub(crate) fn document(&self) -> Result<Document, Error> {
20 let mut doc = Document::new();
21 let mut root_table = Table::new();
22
23 self.package(&mut root_table)?;
24 self.badges(&mut root_table)?;
25 self.features(&mut root_table)?;
26 self.targets(&mut root_table)?;
27 self.dependencies(&mut root_table)?;
28 self.build_dependencies(&mut root_table)?;
29 self.dev_dependencies(&mut root_table)?;
30 self.target_dependencies(&mut root_table)?;
31 self.profiles(&mut root_table)?;
32 self.workspace(&mut root_table)?;
33 self.patches(&mut root_table)?;
34 self.replace(&mut root_table)?;
35
36 doc.root = Item::Table(root_table);
37 Ok(doc)
38 }
39
40 fn package(&self, root: &mut Table) -> Result<(), Error> {
42 let mut table = Table::new();
43
44 if let Some(ref name) = self.0.name {
46 insert_str(&mut table, "name", name);
47 } else {
48 return Err("must have a name".into());
49 }
50
51 let version = itemize(if let Some(ref version) = self.0.version {
53 version.as_str()
54 } else {
55 DEFAULT_VERSION
56 });
57 insert(&mut table, "version", version);
58
59 if let Some(ref authors) = self.0.authors {
61 let arr = slice_to_arr(&authors);
62 insert(&mut table, "authors", arr);
63 } else {
64 return Err("must have an author".into());
65 }
66
67 maybe_insert_str(&mut table, "build", &self.0.build_script);
69
70 maybe_insert_str(&mut table, "documentation", &self.0.documentation);
72
73 maybe_insert_arr(&mut table, "exclude", &self.0.exclude);
75
76 maybe_insert_arr(&mut table, "include", &self.0.include);
78
79 if let Some(publish) = self.0.publish {
81 insert(&mut table, "publish", itemize(publish));
82 }
83
84 maybe_insert_str(&mut table, "workspace", &self.0.workspace_root);
86
87 maybe_insert_str(&mut table, "description", &self.0.description);
89
90 maybe_insert_str(&mut table, "homepage", &self.0.homepage);
92
93 maybe_insert_str(&mut table, "repository", &self.0.repository);
95
96 maybe_insert_str(&mut table, "readme", &self.0.readme);
98
99 maybe_insert_arr(&mut table, "keywords", &self.0.keywords);
101
102 maybe_insert_arr(&mut table, "categories", &self.0.categories);
104
105 if let Some(ref licenses) = self.0.licenses {
107 let s = licenses.iter().map(|l| l.to_string()).collect::<Vec<_>>().join("/");
108 insert_str(&mut table, "license", &s);
109 }
110
111 maybe_insert_str(&mut table, "license-file", &self.0.license_file);
113
114 self.metadata(&mut table)?;
115 insert(root, "package", Item::Table(table));
116 Ok(())
117 }
118
119 fn metadata(&self, root: &mut Table) -> Result<(), Error> {
120 if let Some(ref tables) = self.0.metadata {
121 let mut package_metadata_table = Table::new();
122 package_metadata_table.set_implicit(true);
123
124 for metadata_table in tables.iter() {
125 let mut table = Table::new();
126 for (key, value) in metadata_table.data.iter() {
127 insert(&mut table, key, itemize(value.as_str()));
128 }
129 insert(&mut package_metadata_table, &metadata_table.label, Item::Table(table));
130 }
131
132 insert(root, "metadata", Item::Table(package_metadata_table));
133 }
134 Ok(())
135 }
136
137 fn badges(&self, root: &mut Table) -> Result<(), Error> {
151 let mut table = Table::new();
152
153 if let Some(ref appveyor) = self.0.appveyor {
155 let mut t = InlineTable::default();
156 insert_inline(&mut t, "repository", appveyor.repository.as_str());
157 if let Some(ref branch) = appveyor.branch {
158 insert_inline(&mut t, "branch", branch.as_str());
159 }
160 if let Some(ref service) = appveyor.service {
161 insert_inline(&mut t, "service", service.to_string());
162 }
163 insert(&mut table, "appveyor", itemize(Value::InlineTable(t)));
164 }
165
166 if let Some(ref circle_ci) = self.0.circle_ci {
168 let mut t = InlineTable::default();
169 insert_inline(&mut t, "repository", circle_ci.repository.as_str());
170 if let Some(ref branch) = circle_ci.branch {
171 insert_inline(&mut t, "branch", branch.as_str());
172 }
173 insert(&mut table, "circle-ci", itemize(Value::InlineTable(t)));
174 }
175
176 if let Some(ref gitlab) = self.0.gitlab {
178 let mut t = InlineTable::default();
179 insert_inline(&mut t, "repository", gitlab.repository.as_str());
180 if let Some(ref branch) = gitlab.branch {
181 insert_inline(&mut t, "branch", branch.as_str());
182 }
183 insert(&mut table, "gitlab", itemize(Value::InlineTable(t)));
184 }
185
186 if let Some(ref travis_ci) = self.0.travis_ci {
188 let mut t = InlineTable::default();
189 insert_inline(&mut t, "repository", travis_ci.repository.as_str());
190 if let Some(ref branch) = travis_ci.branch {
191 insert_inline(&mut t, "branch", branch.as_str());
192 }
193 insert(&mut table, "travis-ci", itemize(Value::InlineTable(t)));
194 }
195
196 if let Some(ref codecov) = self.0.codecov {
198 let mut t = InlineTable::default();
199 insert_inline(&mut t, "repository", codecov.repository.as_str());
200 if let Some(ref branch) = codecov.branch {
201 insert_inline(&mut t, "branch", branch.as_str());
202 }
203 if let Some(ref service) = codecov.service {
204 insert_inline(&mut t, "service", service.to_string());
205 }
206 insert(&mut table, "codecov", itemize(Value::InlineTable(t)));
207 }
208
209 if let Some(ref coveralls) = self.0.coveralls {
211 let mut t = InlineTable::default();
212 insert_inline(&mut t, "repository", coveralls.repository.as_str());
213 if let Some(ref branch) = coveralls.branch {
214 insert_inline(&mut t, "branch", branch.as_str());
215 }
216 if let Some(ref service) = coveralls.service {
217 insert_inline(&mut t, "service", service.to_string());
218 }
219 insert(&mut table, "coveralls", itemize(Value::InlineTable(t)));
220 }
221
222 if let Some(ref is_it_maintained_time) = self.0.is_it_maintained_time {
224 let mut t = InlineTable::default();
225 insert_inline(&mut t, "repository", is_it_maintained_time.as_str());
226 insert(&mut table, "is-it-maintained-issue-resolution", itemize(Value::InlineTable(t)));
227 }
228
229 if let Some(ref is_it_maintained_issues) = self.0.is_it_maintained_issues {
231 let mut t = InlineTable::default();
232 insert_inline(&mut t, "repository", is_it_maintained_issues.as_str());
233 insert(&mut table, "is-it-maintained-open-issues", itemize(Value::InlineTable(t)));
234 }
235
236 if let Some(ref maintenance) = self.0.maintenance {
238 let mut t = InlineTable::default();
239 insert_inline(&mut t, "status", maintenance.status.to_string());
240 insert(&mut table, "maintenance", itemize(Value::InlineTable(t)));
241 }
242
243 if !table.is_empty() {
244 insert(root, "badges", Item::Table(table));
245 }
246 Ok(())
247 }
248
249 fn dependencies(&self, root: &mut Table) -> Result<(), Error> {
251 let mut iters = Vec::new();
252 if let Some(ref dependencies) = self.0.dependencies {
253 let clone = dependencies.clone();
254 iters.push(clone.into_iter());
255 };
256
257 if let Some(ref features) = self.0.features {
258 for feature in features {
259 let clone = feature.deps.clone().into_iter().map(|mut d| d.optional(true).build()).collect::<Vec<_>>();
260 iters.push(clone.into_iter());
261 }
262 }
263
264 let iters = iters.into_iter().flat_map(|i| i.clone());
265 let deps: Vec<Dependency> = iters.collect();
266 if let Err(..) = self.dependency_table(root, "dependencies", &deps) {
267 insert(root, "dependencies", Item::Table(Table::new()));
268 }
269 Ok(())
270 }
271
272 fn build_dependencies(&self, root: &mut Table) -> Result<(), Error> {
274 if let Some(ref build_dependencies) = self.0.build_dependencies {
275 let _ = self.dependency_table(root, "build-dependencies", build_dependencies);
276 }
277 Ok(())
278 }
279
280 fn dev_dependencies(&self, root: &mut Table) -> Result<(), Error> {
282 if let Some(ref dev_dependencies) = self.0.dev_dependencies {
283 let _ = self.dependency_table(root, "dev-dependencies", dev_dependencies);
284 }
285 Ok(())
286 }
287
288 fn target_dependencies(&self, root: &mut Table) -> Result<(), Error> {
290 if let Some(ref target_dependencies) = self.0.target_dependencies {
291 let mut target_table = Table::new();
292 target_table.set_implicit(true);
293 for (label, deps) in target_dependencies {
294 let mut label_table = Table::new();
295 label_table.set_implicit(true);
296
297 self.dependency_table(&mut label_table, "dependencies", deps)?;
298
299 insert(&mut target_table, label, Item::Table(label_table));
300 }
301
302 insert(root, "target", Item::Table(target_table));
303 }
304 Ok(())
305 }
306
307 fn dependency_table(&self, root: &mut Table, label: &str, dependencies: &[Dependency]) -> Result<(), Error> {
308 let no_deps = dependencies.is_empty();
309 if no_deps {
310 return Err("dependencies is empty".into());
311 }
312
313 let iter = dependencies.iter();
330 let (inline, noninline): (Vec<_>, Vec<_>) = iter.partition(|d| d.is_inline());
331
332 let mut dep_table = self.dependencies_table(&inline);
333 dep_table.set_implicit(true);
334
335 for dep in noninline.into_iter() {
336 let item = Table::from(dep);
337 insert(&mut dep_table, &dep.label, Item::Table(item));
338 }
339
340 insert(root, label, Item::Table(dep_table));
341 Ok(())
342 }
343
344 fn dependencies_table(&self, dependencies: &[&Dependency]) -> Table {
345 let mut table = Table::new();
346 for dep in dependencies {
347 dep.render_into(&mut table);
348 }
349 table
350 }
351
352 fn profiles(&self, root_table: &mut Table) -> Result<(), Error> {
353 let mut profile_table = Table::new();
354 profile_table.set_implicit(true);
355 self.profile_dev(&mut profile_table)?;
356 self.profile_release(&mut profile_table)?;
357 self.profile_test(&mut profile_table)?;
358 self.profile_bench(&mut profile_table)?;
359 self.profile_doc(&mut profile_table)?;
360 insert(root_table, "profile", Item::Table(profile_table));
361 Ok(())
362 }
363
364 fn profile_dev(&self, profile_table: &mut Table) -> Result<(), Error> {
365 if let Some(ref profile_dev) = self.0.profile_dev {
366 let table = profile_to_table(profile_dev);
367 insert(profile_table, "dev", Item::Table(table));
368 }
369 Ok(())
370 }
371
372 fn profile_release(&self, profile_table: &mut Table) -> Result<(), Error> {
373 if let Some(ref profile_release) = self.0.profile_release {
374 let table = profile_to_table(profile_release);
375 insert(profile_table, "release", Item::Table(table));
376 }
377 Ok(())
378 }
379
380 fn profile_test(&self, profile_table: &mut Table) -> Result<(), Error> {
381 if let Some(ref profile_test) = self.0.profile_test {
382 let table = profile_to_table(profile_test);
383 insert(profile_table, "test", Item::Table(table));
384 }
385 Ok(())
386 }
387
388 fn profile_bench(&self, profile_table: &mut Table) -> Result<(), Error> {
389 if let Some(ref profile_bench) = self.0.profile_bench {
390 let table = profile_to_table(profile_bench);
391 insert(profile_table, "bench", Item::Table(table));
392 }
393 Ok(())
394 }
395
396 fn profile_doc(&self, profile_table: &mut Table) -> Result<(), Error> {
397 if let Some(ref profile_doc) = self.0.profile_doc {
398 let table = profile_to_table(profile_doc);
399 insert(profile_table, "doc", Item::Table(table));
400 }
401 Ok(())
402 }
403
404 fn features(&self, root_table: &mut Table) -> Result<(), Error> {
405 if let Some(ref features) = self.0.features {
406 let mut feature_table = Table::new();
407 for feature in features {
408 let mut labels = Vec::new();
409 for dep in &feature.deps {
410 labels.push(dep.label.to_string())
411 }
412 labels.extend(feature.features.iter().map(|s| s.to_string()));
413 let arr = slice_to_arr(&labels);
414 insert(&mut feature_table, &feature.label, arr);
415 }
416 insert(root_table, "features", Item::Table(feature_table));
417 }
418 Ok(())
419 }
420
421 fn workspace(&self, root_table: &mut Table) -> Result<(), Error> {
423 if let Some(ref workspace) = self.0.workspace {
424 let mut table = Table::new();
425 if let Some(ref members) = workspace.members {
426 let arr = slice_to_arr(members);
427 insert(&mut table, "members", arr);
428 }
429 if let Some(ref exclude) = workspace.exclude {
430 let arr = slice_to_arr(exclude);
431 insert(&mut table, "exclude", arr);
432 }
433 insert(root_table, "workspace", Item::Table(table));
434 }
435 Ok(())
436 }
437
438 fn targets(&self, root_table: &mut Table) -> Result<(), Error> {
440 if let Some(ref bins) = self.0.bins {
441 let item = nonlib_targets_to_item(bins);
442 insert(root_table, "bin", item);
443 }
444 if let Some(ref benches) = self.0.benches {
445 let item = nonlib_targets_to_item(benches);
446 insert(root_table, "bench", item);
447 }
448 if let Some(ref examples) = self.0.examples {
449 let item = nonlib_targets_to_item(examples);
450 insert(root_table, "example", item);
451 }
452 if let Some(ref tests) = self.0.tests {
453 let item = nonlib_targets_to_item(tests);
454 insert(root_table, "test", item);
455 }
456 if let Some(ref lib) = self.0.lib {
457 let table = Table::from(lib);
458 insert(root_table, "lib", Item::Table(table));
459 }
460 Ok(())
461 }
462
463 fn patches(&self, root_table: &mut Table) -> Result<(), Error> {
465 let mut patch_table = Table::new();
466 patch_table.set_implicit(true);
467
468 if let Some(ref patches) = self.0.patches {
469 for patchset in patches {
470 let table = self.patchset_to_table(&patchset);
471 insert(&mut patch_table, &patchset.label, table);
472 }
473 }
474
475 insert(root_table, "patch", Item::Table(patch_table));
476 Ok(())
477 }
478
479 fn patchset_to_table(&self, patchset: &PatchSet) -> Item {
480 let mut table = Table::new();
481 for dep in patchset.patches.iter() {
482 dep.render_into(&mut table);
483 }
484 Item::Table(table)
485 }
486
487 fn replace(&self, root_table: &mut Table) -> Result<(), Error> {
489 if let Some(ref replacements) = self.0.replacements {
490 let mut table = Table::new();
491 for rep in replacements.iter() {
492 rep.0.render_into(&mut table);
493 }
494 insert(root_table, "replace", Item::Table(table));
495 }
496 Ok(())
497 }
498}
499
500fn nonlib_targets_to_item(targets: &[NonLibTarget]) -> Item {
501 let mut array = ArrayOfTables::new();
502 for target in targets.iter() {
503 let t = Table::from(target);
504 array.append(t);
505 }
506 Item::ArrayOfTables(array)
507}
508
509impl<'a> From<&'a LibTarget> for Table {
510 fn from(t: &'a LibTarget) -> Table {
511 let mut table = Table::new();
512 if let Some(ref name) = t.name() {
513 insert(&mut table, "name", itemize(name.as_str()));
514 }
515 if let Some(ref path) = t.path() {
516 insert(&mut table, "path", itemize(path.as_str()));
517 }
518 if let Some(test) = t.test() {
519 insert(&mut table, "test", itemize(test));
520 }
521 if let Some(doctest) = t.doctest() {
522 insert(&mut table, "doctest", itemize(doctest));
523 }
524 if let Some(bench) = t.bench() {
525 insert(&mut table, "bench", itemize(bench));
526 }
527 if let Some(doc) = t.doc() {
528 insert(&mut table, "doc", itemize(doc));
529 }
530 if let Some(plugin) = t.plugin() {
531 insert(&mut table, "plugin", itemize(plugin));
532 }
533 if let Some(proc_macro) = t.proc_macro() {
534 insert(&mut table, "proc-macro", itemize(proc_macro));
535 }
536 if let Some(harness) = t.harness() {
537 insert(&mut table, "harness", itemize(harness));
538 }
539 if let Some(ref crate_type) = t.crate_type() {
540 insert(&mut table, "crate-type", itemize(crate_type.to_string()));
541 }
542 table
543 }
544}
545
546impl<'a> From<&'a NonLibTarget> for Table {
547 fn from(t: &'a NonLibTarget) -> Table {
548 let mut table = Table::new();
549 if let Some(ref name) = t.name() {
550 insert(&mut table, "name", itemize(name.as_str()));
551 }
552 if let Some(ref path) = t.path() {
553 insert(&mut table, "path", itemize(path.as_str()));
554 }
555 if let Some(test) = t.test() {
556 insert(&mut table, "test", itemize(test));
557 }
558 if let Some(doctest) = t.doctest() {
559 insert(&mut table, "doctest", itemize(doctest));
560 }
561 if let Some(bench) = t.bench() {
562 insert(&mut table, "bench", itemize(bench));
563 }
564 if let Some(doc) = t.doc() {
565 insert(&mut table, "doc", itemize(doc));
566 }
567 if let Some(plugin) = t.plugin() {
568 insert(&mut table, "plugin", itemize(plugin));
569 }
570 if let Some(proc_macro) = t.proc_macro() {
571 insert(&mut table, "proc-macro", itemize(proc_macro));
572 }
573 if let Some(harness) = t.harness() {
574 insert(&mut table, "harness", itemize(harness));
575 }
576 if let Some(ref required_features) = t.required_features() {
577 let arr = slice_to_arr(required_features);
578 insert(&mut table, "required-features", arr);
579 }
580 table
581 }
582}
583
584fn profile_to_table(profile: &Profile) -> Table {
585 let mut table = Table::new();
595 if let Some(opt_level) = profile.opt_level {
596 insert(&mut table, "opt-level", itemize(opt_level as i64));
597 }
598 if let Some(debug) = profile.debug {
599 insert(&mut table, "debug", itemize(debug));
600 }
601 if let Some(rpath) = profile.rpath {
602 insert(&mut table, "rpath", itemize(rpath));
603 }
604 if let Some(lto) = profile.lto {
605 insert(&mut table, "lto", itemize(lto));
606 }
607 if let Some(debug_assertions) = profile.debug_assertions {
608 insert(&mut table, "debug-assertions", itemize(debug_assertions));
609 }
610 if let Some(codegen_units) = profile.codegen_units {
611 insert(&mut table, "codegen-units", itemize(codegen_units as i64));
612 }
613 if let Some(ref panic) = profile.panic {
614 insert(&mut table, "panic", itemize(panic.to_string()));
615 }
616 table
617}
618
619fn itemize<T: Into<Value>>(ty: T) -> Item {
620 toml_edit::value(ty.into())
621}
622
623fn insert_inline<V: Into<Value>>(table: &mut InlineTable, key: &str, val: V) {
624 table.get_or_insert(key, val);
625}
626
627fn insert(table: &mut Table, key: &str, item: Item) {
628 *table.entry(key) = item;
629}
630
631fn insert_str(table: &mut Table, key: &str, s: &str) {
632 let item = itemize(s);
633 insert(table, key, item);
634}
635
636fn maybe_insert_str(table: &mut Table, key: &str, s: &Option<String>) {
637 if let &Some(ref s) = s {
638 insert_str(table, key, s);
639 }
640}
641
642fn maybe_insert_arr(table: &mut Table, key: &str, maybe_vec: &Option<Vec<String>>) {
643 if let &Some(ref slice) = maybe_vec {
644 let arr = slice_to_arr(&slice);
645 insert(table, key, arr);
646 }
647}
648
649fn slice_to_arr(v: &[String]) -> Item {
650 let mut arr = Array::default();
651 for el in v.iter() {
652 arr.push(el.as_str());
653 }
654 itemize(arr)
655}
656
657#[cfg(test)]
658mod tests {
659 use crate::CargoToml;
660
661 #[test]
662 fn test_basics() {
663 let c = CargoToml::builder()
664 .name("my-project")
665 .version("0.1.1")
666 .author("Foo <foo@bar>")
667 .build().expect("Couldn't build toml");
668 let d = c.to_string();
669 assert_eq!(d, r#"
670[package]
671name = "my-project"
672version = "0.1.1"
673authors = ["Foo <foo@bar>"]
674
675[dependencies]
676"#);
677 }
678}