Skip to content

Commit 8c34b46

Browse files
committed
Version output changes
• Bring what's shown in the version string in line with my other projects (URL, description, git hash and date for release-mode non-final builds only, potential for colours in the future) • Show +git or -git depending on feature status • Tests for the above, and for checking that the command-line flag is warned about
1 parent b051ac9 commit 8c34b46

File tree

5 files changed

+116
-28
lines changed

5 files changed

+116
-28
lines changed

Justfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,12 @@ all-release: build-release test-release
7979
command -v cargo-hack >/dev/null || (echo "cargo-hack not installed" && exit 1)
8080
cargo hack check --feature-powerset
8181

82+
# build exa and run extended tests with features disabled
83+
@feature-checks *args:
84+
cargo build --no-default-features
85+
specsheet xtests/features/none.toml -shide {{args}} \
86+
-O cmd.target.exa="${CARGO_TARGET_DIR:-../../target}/debug/exa"
87+
8288
# print versions of the necessary build tools
8389
@versions:
8490
rustc --version

build.rs

Lines changed: 81 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,50 @@
1010
/// - https://stackoverflow.com/q/43753491/3484614
1111
/// - https://crates.io/crates/vergen
1212
13-
extern crate datetime;
1413
use std::env;
15-
use std::io;
14+
use std::fs::File;
15+
use std::io::{self, Write};
16+
use std::path::PathBuf;
1617

18+
use datetime::{LocalDateTime, ISO};
1719

20+
21+
/// The build script entry point.
22+
fn main() -> io::Result<()> {
23+
#![allow(clippy::write_with_newline)]
24+
25+
let tagline = "exa - list files on the command-line";
26+
let url = "https://the.exa.website/";
27+
28+
let ver =
29+
if is_debug_build() {
30+
format!("{}\nv{} \\1;31m(pre-release debug build!)\\0m\n\\1;4;34m{}\\0m", tagline, version_string(), url)
31+
}
32+
else if is_development_version() {
33+
format!("{}\nv{} [{}] built on {} \\1;31m(pre-release!)\\0m\n\\1;4;34m{}\\0m", tagline, version_string(), git_hash(), build_date(), url)
34+
}
35+
else {
36+
format!("{}\nv{}\n\\1;4;34m{}\\0m", tagline, version_string(), url)
37+
};
38+
39+
// We need to create these files in the Cargo output directory.
40+
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
41+
42+
// Bland version text
43+
let mut f = File::create(&out.join("version_string.txt"))?;
44+
writeln!(f, "{}", strip_codes(&ver))?;
45+
46+
Ok(())
47+
}
48+
49+
/// Removes escape codes from a string.
50+
fn strip_codes(input: &str) -> String {
51+
input.replace("\\0m", "")
52+
.replace("\\1;31m", "")
53+
.replace("\\1;4;34m", "")
54+
}
55+
56+
/// Retrieve the project’s current Git hash, as a string.
1857
fn git_hash() -> String {
1958
use std::process::Command;
2059

@@ -25,40 +64,59 @@ fn git_hash() -> String {
2564
.stdout).trim().to_string()
2665
}
2766

28-
fn main() {
29-
write_statics().unwrap();
30-
}
31-
67+
/// Whether we should show pre-release info in the version string.
68+
///
69+
/// Both weekly releases and actual releases are --release releases,
70+
/// but actual releases will have a proper version number.
3271
fn is_development_version() -> bool {
33-
// Both weekly releases and actual releases are --release releases,
34-
// but actual releases will have a proper version number
3572
cargo_version().ends_with("-pre") || env::var("PROFILE").unwrap() == "debug"
3673
}
3774

75+
/// Whether we are building in debug mode.
76+
fn is_debug_build() -> bool {
77+
env::var("PROFILE").unwrap() == "debug"
78+
}
79+
80+
/// Retrieves the [package] version in Cargo.toml as a string.
3881
fn cargo_version() -> String {
3982
env::var("CARGO_PKG_VERSION").unwrap()
4083
}
4184

42-
fn build_date() -> String {
43-
use datetime::{LocalDateTime, ISO};
85+
/// Returns the version and build parameters string.
86+
fn version_string() -> String {
87+
let mut ver = cargo_version();
4488

45-
let now = LocalDateTime::now();
46-
format!("{}", now.date().iso())
89+
let feats = nonstandard_features_string();
90+
if ! feats.is_empty() {
91+
ver.push_str(&format!(" [{}]", &feats));
92+
}
93+
94+
ver
95+
}
96+
97+
/// Finds whether a feature is enabled by examining the Cargo variable.
98+
fn feature_enabled(name: &str) -> bool {
99+
env::var(&format!("CARGO_FEATURE_{}", name))
100+
.map(|e| ! e.is_empty())
101+
.unwrap_or(false)
47102
}
48103

49-
fn write_statics() -> io::Result<()> {
50-
use std::fs::File;
51-
use std::io::Write;
52-
use std::path::PathBuf;
104+
/// A comma-separated list of non-standard feature choices.
105+
fn nonstandard_features_string() -> String {
106+
let mut s = Vec::new();
53107

54-
let ver = if is_development_version() {
55-
format!("exa v{} ({} built on {})", cargo_version(), git_hash(), build_date())
108+
if feature_enabled("GIT") {
109+
s.push("+git");
56110
}
57111
else {
58-
format!("exa v{}", cargo_version())
59-
};
112+
s.push("-git");
113+
}
60114

61-
let out = PathBuf::from(env::var("OUT_DIR").unwrap());
62-
let mut f = File::create(&out.join("version_string.txt"))?;
63-
write!(f, "{:?}", ver)
115+
s.join(", ")
116+
}
117+
118+
/// Formats the current date as an ISO 8601 string.
119+
fn build_date() -> String {
120+
let now = LocalDateTime::now();
121+
format!("{}", now.date().iso())
64122
}

src/options/version.rs

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,7 @@ impl VersionString {
3131

3232
impl fmt::Display for VersionString {
3333
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
34-
writeln!(
35-
f,
36-
"{} (git support: {})",
37-
include!(concat!(env!("OUT_DIR"), "/version_string.txt")),
38-
if cfg!(feature = "git") { "enabled" } else { "disabled" })
34+
write!(f, "{}", include_str!(concat!(env!("OUT_DIR"), "/version_string.txt")))
3935
}
4036
}
4137

xtests/features/none.toml

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# These tests are meant to be run against an exa binary compiled with
2+
# `--no-default-features`. They will fail otherwise.
3+
4+
5+
[[cmd]]
6+
name = "The missing features are documented in the version"
7+
shell = "exa --version"
8+
stdout = { string = "[-git]" }
9+
stderr = { empty = true }
10+
status = 0
11+
tags = [ 'features' ]
12+
13+
[[cmd]]
14+
name = "The ‘--git’ option is not accepted when the feature is disabled"
15+
shell = "exa --git"
16+
stdout = { empty = true }
17+
stderr = { file = "outputs/disabled_git.txt" }
18+
status = 3
19+
tags = [ 'features' ]
20+
21+
[[cmd]]
22+
name = "The ‘--git-ignore option is not accepted when the feature is disabled"
23+
shell = "exa --git-ignore"
24+
stdout = { empty = true }
25+
stderr = { file = "outputs/disabled_git.txt" }
26+
status = 3
27+
tags = [ 'features' ]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exa: Options --git and --git-ignore can't be used because `git` feature was disabled in this build of exa

0 commit comments

Comments
 (0)