rust_version_info_file/lib.rs
1#![allow(clippy::needless_doctest_main)]
2/*!
3output rust version info into a file
4
5This crate is the presents, the file output of rustc --version and cargo tree command.
6
7# Features
8
9- minimum support rustc 1.58.1 (db9d1b20b 2022-01-20)
10
11# Examples
12
13Please write the following code in the build.rs:
14
15```rust
16use rust_version_info_file::rust_version_info_file;
17
18fn main() {
19 rust_version_info_file("target/rust-version-info.txt", "Cargo.toml");
20}
21```
22
23And you get the file as result it.
24
25```text
26cat target/rust-version-info-file.txt
27```
28
29# On debian package
30
31In Cargo.toml
32
33```text
34[package.metadata.deb]
35assets = [
36 ["target/rust-version-info.txt", "usr/share/doc/your_package/", "644"],
37 ["README.md", "usr/share/doc/your_package/", "644"],
38]
39```
40
41# Output sample
42
43```text
44$ cat target/rust-version-info-aki-gsub.txt
45```
46
47```text
48rustc 1.61.0 (fe5b13d68 2022-05-18)
49aki-gsub v0.1.34
50├── anyhow v1.0.57
51├── atty v0.2.14
52│ └── libc v0.2.126
53├── flood-tide v0.2.4
54├── memx-cdy v0.1.7
55│ ├── libc v0.2.126
56│ └── memx v0.1.20
57│ [build-dependencies]
58│ └── rustc_version v0.4.0
59│ └── semver v1.0.10
60├── regex v1.5.6
61│ ├── aho-corasick v0.7.18
62│ │ └── memchr v2.5.0
63│ ├── memchr v2.5.0
64│ └── regex-syntax v0.6.26
65└── runnel v0.3.10
66 [build-dependencies]
67 └── rustc_version v0.4.0 (*)
68[build-dependencies]
69├── rust-version-info-file v0.1.5
70└── rustc_version v0.4.0 (*)
71[dev-dependencies]
72├── exec-target v0.2.6
73└── indoc v1.0.6 (proc-macro)
74```
75*/
76use std::fs::OpenOptions;
77use std::io::{Read, Write};
78use std::path::Path;
79
80/// output rust version info into a file
81pub fn rust_version_info_file<T: AsRef<Path>>(dst: T, cargo_toml_file: &str) {
82 let dst_path: &Path = dst.as_ref();
83 let old_s = read_file(dst_path);
84 let curr_s = format!(
85 "{}\n{}\n",
86 rustc_version_info(),
87 tree_version_info(cargo_toml_file),
88 );
89 if old_s != curr_s {
90 let mut fo = match OpenOptions::new()
91 .create(true)
92 .write(true)
93 .truncate(true)
94 .open(dst_path)
95 {
96 Ok(fo) => fo,
97 Err(_) => return,
98 };
99 let _ = fo.write_fmt(format_args!("{curr_s}"));
100 let _ = fo.flush();
101 }
102}
103
104fn read_file(path: &Path) -> String {
105 match OpenOptions::new().create(false).read(true).open(path) {
106 Ok(mut fi) => {
107 let mut s = String::new();
108 let _ = fi.read_to_string(&mut s);
109 s
110 }
111 Err(_) => String::new(),
112 }
113}
114
115fn rustc_version_info() -> String {
116 let cmd = std::env::var_os("RUSTC").unwrap_or_else(|| std::ffi::OsString::from("rustc"));
117 let out = std::process::Command::new(cmd)
118 .arg("--version")
119 .output()
120 .unwrap();
121 let v = out.stdout;
122 let v_len = v.len();
123 let v = if v_len > 0 && v[v_len - 1] == b'\n' {
124 &v[0..v_len - 1]
125 } else {
126 &v[0..v_len]
127 };
128 String::from_utf8(v.to_vec()).unwrap()
129}
130
131fn tree_version_info(cargo_toml_file: &str) -> String {
132 let cmd = "cargo";
133 let out = std::process::Command::new(cmd)
134 .arg("tree")
135 .arg("--manifest-path")
136 .arg(cargo_toml_file)
137 .output()
138 .unwrap();
139 let v = out.stdout;
140 let v_len = v.len();
141 let v = if v_len > 0 && v[v_len - 1] == b'\n' {
142 &v[0..v_len - 1]
143 } else {
144 &v[0..v_len]
145 };
146 //
147 let string = String::from_utf8(v.to_vec()).unwrap();
148 //
149 let string = match string.find(" (") {
150 Some(pos1) => {
151 let (s1, s2) = string.split_at(pos1);
152 match s2.find(')') {
153 Some(pos2) => {
154 let (_s2, s3) = s2.split_at(pos2 + 1);
155 s1.to_owned() + s3
156 }
157 None => string,
158 }
159 }
160 None => string,
161 };
162 //
163 string
164}