/src/templates.rs

https://github.com/RustRPM/cargo-rpm · Rust · 137 lines · 98 code · 20 blank · 19 comment · 5 complexity · 1bfaba1bb0d1003410d35079f4272c69 MD5 · raw file

  1. //! Handlebars templates (for RPM specs, etc)
  2. use crate::{
  3. config::{CargoLicense, PackageConfig},
  4. error::{Error, ErrorKind},
  5. license,
  6. prelude::*,
  7. };
  8. use handlebars::Handlebars;
  9. use serde::Serialize;
  10. use std::{
  11. fs::File,
  12. io::Read,
  13. path::{Path, PathBuf},
  14. };
  15. /// Default RPM spec template (in toplevel `template/spec.hbs`)
  16. pub const DEFAULT_SPEC_TEMPLATE: &str = include_str!("../templates/spec.hbs");
  17. /// Default systemd service unit template (in toplevel `template/service.hbs`)
  18. pub const DEFAULT_SERVICE_TEMPLATE: &str = include_str!("../templates/service.hbs");
  19. /// Parameters passed to the RPM spec template
  20. #[derive(Serialize)]
  21. pub struct SpecParams {
  22. /// Name of the RPM, sans ".rpm", e.g. "ripgrep"
  23. pub name: String,
  24. /// Description of the RPM
  25. pub summary: String,
  26. /// License of the *binary* contents of the RPM
  27. pub license: String,
  28. /// URL to a home page for this package
  29. pub url: Option<String>,
  30. /// Name of a systemd service unit (if enabled)
  31. pub service: Option<String>,
  32. /// Are we placing targets in sbin instead of bin?
  33. pub use_sbin: bool,
  34. }
  35. impl SpecParams {
  36. /// Create a new set of RPM spec template parameters
  37. pub fn new(
  38. pkg_name: String,
  39. package: &PackageConfig,
  40. service: Option<String>,
  41. use_sbin: bool,
  42. ) -> Self {
  43. let rpm_license = license::convert(&package.license).unwrap_or_else(|e| {
  44. let default_lic = match package.license {
  45. CargoLicense::License(ref lic) => lic.to_owned(),
  46. CargoLicense::LicenseFile(ref name) => name.to_owned(),
  47. };
  48. status_warn!("couldn't parse license {:?}: {}", &default_lic, e);
  49. default_lic
  50. });
  51. Self {
  52. name: pkg_name,
  53. summary: package.description.to_owned(),
  54. license: rpm_license,
  55. url: package.homepage.to_owned(),
  56. service,
  57. use_sbin,
  58. }
  59. }
  60. /// Render an RPM spec template at the given path (or default)
  61. pub fn render(&self, template_path: Option<&Path>) -> Result<String, Error> {
  62. let name = match template_path {
  63. Some(p) => p.display().to_string(),
  64. None => "(default:spec.hbs)".to_owned(),
  65. };
  66. let template = load_template(template_path, DEFAULT_SPEC_TEMPLATE)?;
  67. render_template(&name, &template, self)
  68. }
  69. }
  70. /// Paramters passed to the systemd service unit template
  71. #[derive(Serialize)]
  72. pub struct ServiceParams {
  73. /// Description of the service
  74. pub description: String,
  75. /// Path to the binary for systemd to spawn (absolute)
  76. pub bin_path: PathBuf,
  77. }
  78. impl ServiceParams {
  79. /// Render a systemd service unit template at the given path (or default)
  80. pub fn render(&self, template_path: Option<&Path>) -> Result<String, Error> {
  81. let name = match template_path {
  82. Some(p) => p.display().to_string(),
  83. None => "(default:service.hbs)".to_owned(),
  84. };
  85. let template = load_template(template_path, DEFAULT_SERVICE_TEMPLATE)?;
  86. render_template(&name, &template, self)
  87. }
  88. }
  89. impl<'a> From<&'a PackageConfig> for ServiceParams {
  90. fn from(package: &'a PackageConfig) -> Self {
  91. Self {
  92. description: package.description.to_owned(),
  93. /// TODO: better handling of target binaries and their paths
  94. bin_path: PathBuf::from("/usr/sbin").join(&package.rpm_name()),
  95. }
  96. }
  97. }
  98. /// Load a template
  99. fn load_template(template_path: Option<&Path>, default_template: &str) -> Result<String, Error> {
  100. match template_path {
  101. Some(p) => {
  102. let mut file = File::open(p)?;
  103. let mut s = String::new();
  104. file.read_to_string(&mut s)?;
  105. Ok(s)
  106. }
  107. None => Ok(default_template.to_owned()),
  108. }
  109. }
  110. /// Render a template
  111. fn render_template<T: Serialize>(name: &str, template: &str, data: &T) -> Result<String, Error> {
  112. let mut handlebars = Handlebars::new();
  113. handlebars.register_template_string(name, template).unwrap();
  114. Ok(handlebars
  115. .render(name, data)
  116. .map_err(|e| format_err!(ErrorKind::Template, "Error rendering template: {}", e))?)
  117. }