cargo_zng/res/
built_in.rs1use std::{
4 env, fs,
5 io::{self, BufRead as _},
6 path::{Path, PathBuf},
7};
8
9use crate::util;
10
11pub const ZR_WORKSPACE_DIR: &str = "ZR_WORKSPACE_DIR";
15pub const ZR_SOURCE_DIR: &str = "ZR_SOURCE_DIR";
17pub const ZR_TARGET_DIR: &str = "ZR_TARGET_DIR";
22pub const ZR_CACHE_DIR: &str = "ZR_CACHE_DIR";
26
27pub const ZR_REQUEST: &str = "ZR_REQUEST";
29pub const ZR_REQUEST_DD: &str = "ZR_REQUEST_DD";
31pub const ZR_TARGET: &str = "ZR_TARGET";
35pub const ZR_TARGET_DD: &str = "ZR_TARGET_DD";
37
38pub const ZR_FINAL: &str = "ZR_FINAL";
40
41pub const ZR_HELP: &str = "ZR_HELP";
43
44pub const ZR_APP_ID: &str = "ZR_APP_ID";
46pub const ZR_APP: &str = "ZR_APP";
48pub const ZR_ORG: &str = "ZR_ORG";
50pub const ZR_VERSION: &str = "ZR_VERSION";
52pub const ZR_DESCRIPTION: &str = "ZR_DESCRIPTION";
54pub const ZR_HOMEPAGE: &str = "ZR_HOMEPAGE";
56pub const ZR_LICENSE: &str = "ZR_LICENSE";
58pub const ZR_PKG_NAME: &str = "ZR_PKG_NAME";
60pub const ZR_PKG_AUTHORS: &str = "ZR_PKG_AUTHORS";
62pub const ZR_CRATE_NAME: &str = "ZR_CRATE_NAME";
64pub const ZR_QUALIFIER: &str = "ZR_QUALIFIER";
66
67pub fn help(help: &str) {
69 if env::var(ZR_HELP).is_ok() {
70 println!("{help}");
71 std::process::exit(0);
72 };
73}
74
75pub fn path(var: &str) -> PathBuf {
77 env::var(var).unwrap_or_else(|_| panic!("missing {var}")).into()
78}
79
80pub fn display_path(p: &Path) -> String {
82 let base = path(ZR_WORKSPACE_DIR);
83 let r = if let Ok(local) = p.strip_prefix(base) {
84 local.display().to_string()
85 } else {
86 p.display().to_string()
87 };
88
89 #[cfg(windows)]
90 return r.replace('\\', "/");
91
92 #[cfg(not(windows))]
93 r
94}
95
96fn read_line(path: &Path, expected: &str) -> io::Result<String> {
97 match read_lines(path).next() {
98 Some(r) => r.map(|(_, l)| l),
99 None => Err(io::Error::new(
100 io::ErrorKind::InvalidInput,
101 format!("expected {expected} in tool file content"),
102 )),
103 }
104}
105
106fn read_lines(path: &Path) -> impl Iterator<Item = io::Result<(usize, String)>> {
107 enum State {
108 Open(io::Result<fs::File>),
109 Lines(usize, io::Lines<io::BufReader<fs::File>>),
110 End,
111 }
112 let mut state = State::Open(fs::File::open(path));
114 std::iter::from_fn(move || {
115 loop {
116 match std::mem::replace(&mut state, State::End) {
117 State::Lines(count, mut lines) => {
118 if let Some(l) = lines.next() {
119 match l {
120 Ok(l) => {
122 state = State::Lines(count + 1, lines);
123 let test = l.trim();
124 if !test.is_empty() && !test.starts_with('#') {
125 return Some(Ok((count, l)));
126 }
127 }
128 Err(e) => {
130 return Some(Err(e));
131 }
132 }
133 }
134 }
135 State::Open(r) => match r {
136 Ok(f) => state = State::Lines(1, io::BufReader::new(f).lines()),
138 Err(e) => return Some(Err(e)),
140 },
141 State::End => return None,
143 }
144 }
145 })
146}
147
148fn read_path(request_file: &Path) -> io::Result<PathBuf> {
149 read_line(request_file, "path").map(PathBuf::from)
150}
151
152pub(crate) fn symlink_warn(path: &Path) {
153 warn!("symlink ignored in `{}`, use zr-tools to 'link'", path.display());
154}
155
156pub const ENV_TOOL: &str = "ZNG_RES_TOOL";
157
158macro_rules! built_in {
159 ($($tool:tt),+ $(,)?) => {
160 $(
161 mod $tool;
162 use $tool::$tool;
163 )+
164
165 pub static BUILT_INS: &[&str] = &[
166 $(stringify!($tool),)+
167 ];
168 static BUILT_IN_FNS: &[fn()] = &[
169 $($tool,)+
170 ];
171 };
172}
173built_in! { copy, glob, rp, sh, shf, warn, fail, apk, l10n }
174
175pub(crate) use l10n::release_langs;
176pub(crate) use sh::sh_run;
177
178pub fn run() {
179 if let Ok(tool) = env::var(ENV_TOOL) {
180 unsafe {
184 env::remove_var(ENV_TOOL);
185 }
186
187 if let Some(i) = BUILT_INS.iter().position(|n| *n == tool.as_str()) {
188 (BUILT_IN_FNS[i])();
189 std::process::exit(0);
190 } else {
191 fatal!("`tool` is not a built-in tool");
192 }
193 }
194}