build.rs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // SPDX-FileCopyrightText: 2024 Christina Sørensen
  2. // SPDX-License-Identifier: EUPL-1.2
  3. //
  4. // SPDX-FileCopyrightText: 2023-2024 Christina Sørensen, eza contributors
  5. // SPDX-FileCopyrightText: 2014 Benjamin Sago
  6. // SPDX-License-Identifier: MIT
  7. /// The version string isn’t the simplest: we want to show the version,
  8. /// current Git hash, and compilation date when building *debug* versions, but
  9. /// just the version for *release* versions so the builds are reproducible.
  10. ///
  11. /// This script generates the string from the environment variables that Cargo
  12. /// adds (<http://doc.crates.io/environment-variables.html>) and runs `git` to
  13. /// get the SHA1 hash. It then writes the string into a file, which exa then
  14. /// includes at build-time.
  15. ///
  16. /// - <https://stackoverflow.com/q/43753491/3484614>
  17. /// - <https://crates.io/crates/vergen>
  18. use std::env;
  19. use std::fs::File;
  20. use std::io::{self, Write};
  21. use std::path::PathBuf;
  22. use chrono::prelude::*;
  23. /// The build script entry point.
  24. fn main() -> io::Result<()> {
  25. #![allow(clippy::write_with_newline)]
  26. let tagline = "eza - A modern, maintained replacement for ls";
  27. let url = "https://github.com/eza-community/eza";
  28. let ver = if is_debug_build() {
  29. format!(
  30. "{}\nv{} \\1;31m(pre-release debug build!)\\0m\n\\1;4;34m{}\\0m",
  31. tagline,
  32. version_string(),
  33. url
  34. )
  35. } else if is_development_version() {
  36. format!(
  37. "{}\nv{} [{}] built on {} \\1;31m(pre-release!)\\0m\n\\1;4;34m{}\\0m",
  38. tagline,
  39. version_string(),
  40. git_hash(),
  41. build_date(),
  42. url
  43. )
  44. } else {
  45. format!("{}\nv{}\n\\1;4;34m{}\\0m", tagline, version_string(), url)
  46. };
  47. // We need to create these files in the Cargo output directory.
  48. let out = PathBuf::from(env::var("OUT_DIR").unwrap());
  49. let path = &out.join("version_string.txt");
  50. // Bland version text
  51. let mut f =
  52. File::create(path).unwrap_or_else(|_| panic!("{}", path.to_string_lossy().to_string()));
  53. writeln!(f, "{}", strip_codes(&ver))?;
  54. Ok(())
  55. }
  56. /// Removes escape codes from a string.
  57. fn strip_codes(input: &str) -> String {
  58. input
  59. .replace("\\0m", "")
  60. .replace("\\1;31m", "")
  61. .replace("\\1;4;34m", "")
  62. }
  63. /// Retrieve the project’s current Git hash, as a string.
  64. fn git_hash() -> String {
  65. use std::process::Command;
  66. String::from_utf8_lossy(
  67. &Command::new("git")
  68. .args(["rev-parse", "--short", "HEAD"])
  69. .output()
  70. .unwrap()
  71. .stdout,
  72. )
  73. .trim()
  74. .to_string()
  75. }
  76. /// Whether we should show pre-release info in the version string.
  77. ///
  78. /// Both weekly releases and actual releases are --release releases,
  79. /// but actual releases will have a proper version number.
  80. fn is_development_version() -> bool {
  81. cargo_version().ends_with("-pre") || env::var("PROFILE").unwrap() == "debug"
  82. }
  83. /// Whether we are building in debug mode.
  84. fn is_debug_build() -> bool {
  85. env::var("PROFILE").unwrap() == "debug"
  86. }
  87. /// Retrieves the [package] version in Cargo.toml as a string.
  88. fn cargo_version() -> String {
  89. env::var("CARGO_PKG_VERSION").unwrap()
  90. }
  91. /// Returns the version and build parameters string.
  92. fn version_string() -> String {
  93. let mut ver = cargo_version();
  94. let feats = nonstandard_features_string();
  95. if !feats.is_empty() {
  96. ver.push_str(&format!(" [{}]", &feats));
  97. }
  98. ver
  99. }
  100. /// Finds whether a feature is enabled by examining the Cargo variable.
  101. fn feature_enabled(name: &str) -> bool {
  102. env::var(format!("CARGO_FEATURE_{name}"))
  103. .map(|e| !e.is_empty())
  104. .unwrap_or(false)
  105. }
  106. /// A comma-separated list of non-standard feature choices.
  107. fn nonstandard_features_string() -> String {
  108. let mut s = Vec::new();
  109. if feature_enabled("GIT") {
  110. s.push("+git");
  111. } else {
  112. s.push("-git");
  113. }
  114. s.join(", ")
  115. }
  116. /// Formats the current date as an ISO 8601 string.
  117. fn build_date() -> String {
  118. let now = Local::now();
  119. now.date_naive().format("%Y-%m-%d").to_string()
  120. }