@tishlang/tish-format 3.10.11 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/tish-format +0 -0
- package/crates/tish_fmt/Cargo.toml +1 -1
- package/crates/tish_native/src/build.rs +110 -13
- package/crates/tish_runtime/src/fs_ext.rs +30 -1
- package/package.json +1 -1
- package/platform/darwin-arm64/tish-fmt +0 -0
- package/platform/darwin-x64/tish-fmt +0 -0
- package/platform/linux-arm64/tish-fmt +0 -0
- package/platform/linux-x64/tish-fmt +0 -0
- package/platform/win32-x64/tish-fmt.exe +0 -0
package/bin/tish-format
CHANGED
|
Binary file
|
|
@@ -45,6 +45,13 @@ fn runtime_features_for_cargo(features: &[String]) -> Vec<String> {
|
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
/// `[profile.release]` for nested `cargo build` of generated crates.
|
|
48
|
+
///
|
|
49
|
+
/// - default: fat LTO, one codegen unit — smallest and fastest binary, slowest to produce (the
|
|
50
|
+
/// final link is single-threaded and dominates a warm build of a large app).
|
|
51
|
+
/// - `TISH_FAST_NATIVE_BUILD=1`: iteration profile, no LTO, opt-level 1.
|
|
52
|
+
/// - `TISH_NATIVE_THIN_LTO=1`: thin LTO over 8 codegen units — keeps most of fat's size/speed win
|
|
53
|
+
/// while letting rustc parallelise the link. Same trade the GBA path offers via
|
|
54
|
+
/// `TISH_GBA_THIN_LTO`; for desktop apps this is the CI-friendly shipping profile.
|
|
48
55
|
fn nested_release_profile_toml() -> &'static str {
|
|
49
56
|
if std::env::var("TISH_FAST_NATIVE_BUILD").as_deref() == Ok("1") {
|
|
50
57
|
r#"[profile.release]
|
|
@@ -55,6 +62,13 @@ incremental = true
|
|
|
55
62
|
strip = false
|
|
56
63
|
debug = 0
|
|
57
64
|
panic = "abort"
|
|
65
|
+
"#
|
|
66
|
+
} else if std::env::var("TISH_NATIVE_THIN_LTO").as_deref() == Ok("1") {
|
|
67
|
+
r#"[profile.release]
|
|
68
|
+
strip = true
|
|
69
|
+
panic = "abort"
|
|
70
|
+
codegen-units = 8
|
|
71
|
+
lto = "thin"
|
|
58
72
|
"#
|
|
59
73
|
} else {
|
|
60
74
|
r#"[profile.release]
|
|
@@ -287,7 +301,9 @@ edition = "2021"
|
|
|
287
301
|
.parent()
|
|
288
302
|
.and_then(|p| p.parent())
|
|
289
303
|
.map(|ws| ws.join("target"));
|
|
290
|
-
let target_dir = workspace_target
|
|
304
|
+
let target_dir = workspace_target
|
|
305
|
+
.filter(|p| p.exists())
|
|
306
|
+
.or_else(shared_native_target_dir);
|
|
291
307
|
let cross = build_config.cargo_target.as_deref();
|
|
292
308
|
let release_sub = if let Some(triple) = cross {
|
|
293
309
|
format!("{triple}/release")
|
|
@@ -456,7 +472,10 @@ fn runtime_dep_toml(runtime_path: &str, features_str: &str) -> String {
|
|
|
456
472
|
if let Some(v) = released_compiler_version() {
|
|
457
473
|
format!("tishlang_runtime = {{ version = {:?}{} }}", v, features_str)
|
|
458
474
|
} else {
|
|
459
|
-
format!(
|
|
475
|
+
format!(
|
|
476
|
+
"tishlang_runtime = {{ path = {:?}{} }}",
|
|
477
|
+
runtime_path, features_str
|
|
478
|
+
)
|
|
460
479
|
}
|
|
461
480
|
}
|
|
462
481
|
|
|
@@ -693,8 +712,7 @@ tishlang_runtime = {{ path = {runtime:?}{version}{features} }}
|
|
|
693
712
|
fs::write(src_dir.join("generated_native.rs"), gen)
|
|
694
713
|
.map_err(|e| format!("Cannot write generated_native.rs: {}", e))?;
|
|
695
714
|
}
|
|
696
|
-
fs::write(src_dir.join("lib.rs"), lib_rs)
|
|
697
|
-
.map_err(|e| format!("Cannot write lib.rs: {}", e))?;
|
|
715
|
+
fs::write(src_dir.join("lib.rs"), lib_rs).map_err(|e| format!("Cannot write lib.rs: {}", e))?;
|
|
698
716
|
|
|
699
717
|
println!("Emitted Rust library crate: {}", output_path.display());
|
|
700
718
|
Ok(())
|
|
@@ -739,8 +757,7 @@ fn build_gba_rom(
|
|
|
739
757
|
// the source of truth. The generated ROM crate must depend on the SAME agb: a skew would pull in
|
|
740
758
|
// two agb crates and mismatch types at the sprite-registration boundary. Falls back to a known
|
|
741
759
|
// pin only if the line can't be read (never blocks the build on a parse miss).
|
|
742
|
-
let agb_version =
|
|
743
|
-
read_facade_agb_version(&facade_path).unwrap_or_else(|| "0.25.0".to_string());
|
|
760
|
+
let agb_version = read_facade_agb_version(&facade_path).unwrap_or_else(|| "0.25.0".to_string());
|
|
744
761
|
|
|
745
762
|
let out_stem = output_path
|
|
746
763
|
.file_stem()
|
|
@@ -816,11 +833,13 @@ agb = "{agb_version}"
|
|
|
816
833
|
// Only the channel is inherited. `components` stays `rust-src` because that is what build-std
|
|
817
834
|
// needs — copying a project's `clippy`/`rustfmt` entries in would fail the ROM build whenever
|
|
818
835
|
// the pinned toolchain lacks a component the ROM never uses.
|
|
819
|
-
let channel =
|
|
820
|
-
find_project_toolchain_channel(&base).unwrap_or_else(|| "nightly".to_string());
|
|
836
|
+
let channel = find_project_toolchain_channel(&base).unwrap_or_else(|| "nightly".to_string());
|
|
821
837
|
fs::write(
|
|
822
838
|
build_dir.join("rust-toolchain.toml"),
|
|
823
|
-
format!(
|
|
839
|
+
format!(
|
|
840
|
+
"[toolchain]\nchannel = \"{}\"\ncomponents = [\"rust-src\"]\n",
|
|
841
|
+
channel
|
|
842
|
+
),
|
|
824
843
|
)
|
|
825
844
|
.map_err(|e| format!("Cannot write rust-toolchain.toml: {}", e))?;
|
|
826
845
|
|
|
@@ -971,6 +990,30 @@ fn find_project_toolchain_channel(start: &Path) -> Option<String> {
|
|
|
971
990
|
None
|
|
972
991
|
}
|
|
973
992
|
|
|
993
|
+
/// `TISH_NATIVE_TARGET_DIR` — opt-in shared cargo target dir for native (desktop) builds.
|
|
994
|
+
///
|
|
995
|
+
/// Native builds compile the generated crate under a per-process temp dir that is deleted on
|
|
996
|
+
/// success (`cleanup_build_dir`), so nothing survives between two `tish build --target native`
|
|
997
|
+
/// invocations and CI recompiles every dependency each run. Inside the tish workspace the
|
|
998
|
+
/// workspace `target/` is shared automatically; a released compiler has no workspace, and this
|
|
999
|
+
/// env var is the equivalent for it: point it at a directory that persists (a CI cache) and
|
|
1000
|
+
/// cargo reuses the dependency artifacts across builds. Deliberately NOT the ambient
|
|
1001
|
+
/// `CARGO_TARGET_DIR` — see the GBA path for why that is scrubbed (`TISH_GBA_TARGET_DIR` is the
|
|
1002
|
+
/// same opt-in for ROM builds). The directory is created if missing.
|
|
1003
|
+
fn shared_native_target_dir() -> Option<PathBuf> {
|
|
1004
|
+
let dir = std::env::var_os("TISH_NATIVE_TARGET_DIR")
|
|
1005
|
+
.map(PathBuf::from)
|
|
1006
|
+
.filter(|p| !p.as_os_str().is_empty())?;
|
|
1007
|
+
if let Err(e) = fs::create_dir_all(&dir) {
|
|
1008
|
+
eprintln!(
|
|
1009
|
+
"warning: TISH_NATIVE_TARGET_DIR={} is not usable ({e}); building in the temp dir",
|
|
1010
|
+
dir.display()
|
|
1011
|
+
);
|
|
1012
|
+
return None;
|
|
1013
|
+
}
|
|
1014
|
+
Some(dir)
|
|
1015
|
+
}
|
|
1016
|
+
|
|
974
1017
|
/// Remove a finished build's per-PID source directory (#384). Called only on SUCCESS, after the
|
|
975
1018
|
/// binary is copied out — the dir is then disposable (it holds only the generated crate source;
|
|
976
1019
|
/// compiled artifacts live in the shared workspace `target/`). Left in place on any earlier error so a
|
|
@@ -1126,7 +1169,9 @@ edition = "2021"
|
|
|
1126
1169
|
.parent()
|
|
1127
1170
|
.and_then(|p| p.parent())
|
|
1128
1171
|
.map(|ws| ws.join("target"));
|
|
1129
|
-
let target_dir = workspace_target
|
|
1172
|
+
let target_dir = workspace_target
|
|
1173
|
+
.filter(|p| p.exists())
|
|
1174
|
+
.or_else(shared_native_target_dir);
|
|
1130
1175
|
let binary_dir = target_dir
|
|
1131
1176
|
.as_ref()
|
|
1132
1177
|
.map(|t| t.join("release"))
|
|
@@ -1148,6 +1193,7 @@ edition = "2021"
|
|
|
1148
1193
|
|
|
1149
1194
|
#[cfg(test)]
|
|
1150
1195
|
mod tests {
|
|
1196
|
+
use super::nested_release_profile_toml;
|
|
1151
1197
|
use super::runtime_features_for_cargo;
|
|
1152
1198
|
|
|
1153
1199
|
/// The generated ROM crate must inherit the project's pin, or GBA builds float against whatever
|
|
@@ -1188,14 +1234,62 @@ mod tests {
|
|
|
1188
1234
|
let _ = fs::remove_dir_all(&base);
|
|
1189
1235
|
}
|
|
1190
1236
|
|
|
1237
|
+
/// `TISH_NATIVE_THIN_LTO=1` selects thin LTO for native release builds; fast wins over it.
|
|
1238
|
+
#[test]
|
|
1239
|
+
fn native_release_profile_follows_env() {
|
|
1240
|
+
use std::sync::Mutex;
|
|
1241
|
+
static ENV_LOCK: Mutex<()> = Mutex::new(());
|
|
1242
|
+
let _g = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
|
1243
|
+
std::env::remove_var("TISH_FAST_NATIVE_BUILD");
|
|
1244
|
+
std::env::remove_var("TISH_NATIVE_THIN_LTO");
|
|
1245
|
+
assert!(nested_release_profile_toml().contains("lto = \"fat\""));
|
|
1246
|
+
std::env::set_var("TISH_NATIVE_THIN_LTO", "1");
|
|
1247
|
+
let thin = nested_release_profile_toml();
|
|
1248
|
+
assert!(thin.contains("lto = \"thin\"") && thin.contains("codegen-units = 8"));
|
|
1249
|
+
std::env::set_var("TISH_FAST_NATIVE_BUILD", "1");
|
|
1250
|
+
assert!(
|
|
1251
|
+
nested_release_profile_toml().contains("lto = false"),
|
|
1252
|
+
"fast wins over thin"
|
|
1253
|
+
);
|
|
1254
|
+
std::env::remove_var("TISH_FAST_NATIVE_BUILD");
|
|
1255
|
+
std::env::remove_var("TISH_NATIVE_THIN_LTO");
|
|
1256
|
+
}
|
|
1257
|
+
|
|
1258
|
+
/// `TISH_NATIVE_TARGET_DIR`: unset/empty → None (temp-dir build); set → that dir, created.
|
|
1259
|
+
#[test]
|
|
1260
|
+
fn shared_native_target_dir_follows_env() {
|
|
1261
|
+
use super::shared_native_target_dir;
|
|
1262
|
+
use std::fs;
|
|
1263
|
+
use std::path::PathBuf;
|
|
1264
|
+
// Only this test touches TISH_NATIVE_TARGET_DIR; the lock keeps it single-threaded anyway.
|
|
1265
|
+
use std::sync::Mutex;
|
|
1266
|
+
static ENV_LOCK: Mutex<()> = Mutex::new(());
|
|
1267
|
+
let _guard = ENV_LOCK.lock().unwrap_or_else(|e| e.into_inner());
|
|
1268
|
+
std::env::remove_var("TISH_NATIVE_TARGET_DIR");
|
|
1269
|
+
assert!(shared_native_target_dir().is_none());
|
|
1270
|
+
std::env::set_var("TISH_NATIVE_TARGET_DIR", "");
|
|
1271
|
+
assert!(shared_native_target_dir().is_none());
|
|
1272
|
+
// Scratch under the workspace target/ (never /tmp), unique per case.
|
|
1273
|
+
let dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"))
|
|
1274
|
+
.join("../../target/tmp_shared_target_test")
|
|
1275
|
+
.join(format!("t_{}", std::process::id()));
|
|
1276
|
+
let _ = fs::remove_dir_all(&dir);
|
|
1277
|
+
std::env::set_var("TISH_NATIVE_TARGET_DIR", &dir);
|
|
1278
|
+
let got = shared_native_target_dir().expect("set → Some");
|
|
1279
|
+
assert_eq!(got, dir);
|
|
1280
|
+
assert!(dir.is_dir(), "the shared target dir is created on demand");
|
|
1281
|
+
std::env::remove_var("TISH_NATIVE_TARGET_DIR");
|
|
1282
|
+
let _ = fs::remove_dir_all(dir.parent().unwrap());
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1191
1285
|
/// #384: `cleanup_build_dir` removes a finished build's dir by default, and preserves it under
|
|
1192
1286
|
/// `TISH_KEEP_BUILD_DIR=1`.
|
|
1193
1287
|
#[test]
|
|
1194
1288
|
fn cleanup_build_dir_removes_by_default_and_keeps_on_flag() {
|
|
1195
1289
|
use std::path::PathBuf;
|
|
1196
1290
|
// Scratch under the workspace target/ (never /tmp), unique per case.
|
|
1197
|
-
let base: PathBuf =
|
|
1198
|
-
.join("../../target/tmp_cleanup_test");
|
|
1291
|
+
let base: PathBuf =
|
|
1292
|
+
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("../../target/tmp_cleanup_test");
|
|
1199
1293
|
let removed = base.join("to_remove");
|
|
1200
1294
|
let kept = base.join("to_keep");
|
|
1201
1295
|
for d in [&removed, &kept] {
|
|
@@ -1209,7 +1303,10 @@ mod tests {
|
|
|
1209
1303
|
|
|
1210
1304
|
std::env::set_var("TISH_KEEP_BUILD_DIR", "1");
|
|
1211
1305
|
super::cleanup_build_dir(&kept);
|
|
1212
|
-
assert!(
|
|
1306
|
+
assert!(
|
|
1307
|
+
kept.exists(),
|
|
1308
|
+
"TISH_KEEP_BUILD_DIR=1 should preserve the build dir"
|
|
1309
|
+
);
|
|
1213
1310
|
std::env::remove_var("TISH_KEEP_BUILD_DIR");
|
|
1214
1311
|
|
|
1215
1312
|
let _ = std::fs::remove_dir_all(&base);
|
|
@@ -218,9 +218,25 @@ pub fn copy_file_core(args: &[Value]) -> Result<Value, Value> {
|
|
|
218
218
|
}
|
|
219
219
|
pub fn realpath_core(args: &[Value]) -> Result<Value, Value> {
|
|
220
220
|
std::fs::canonicalize(path_arg(args, 0))
|
|
221
|
-
.map(|p| Value::String(p.to_string_lossy().into()))
|
|
221
|
+
.map(|p| Value::String(strip_verbatim_prefix(&p.to_string_lossy()).into()))
|
|
222
222
|
.map_err(io_err)
|
|
223
223
|
}
|
|
224
|
+
|
|
225
|
+
/// `std::fs::canonicalize` on Windows returns the verbatim form — `\\?\C:\Users\…` for a drive
|
|
226
|
+
/// path, `\\?\UNC\server\share\…` for a network one. Node's `fs.realpath` never does: it hands
|
|
227
|
+
/// back `C:\Users\…` / `\\server\share\…`, and programs treat the result as a display / URL /
|
|
228
|
+
/// comparison string, not just an OS handle (Dune showed `\\?\C:\…` as its workspace title, and a
|
|
229
|
+
/// `?` inside a URL path starts the query string). Match Node. No-op on POSIX and for paths
|
|
230
|
+
/// that carry no prefix.
|
|
231
|
+
pub(crate) fn strip_verbatim_prefix(p: &str) -> String {
|
|
232
|
+
if let Some(rest) = p.strip_prefix("\\\\?\\UNC\\") {
|
|
233
|
+
format!("\\\\{rest}")
|
|
234
|
+
} else if let Some(rest) = p.strip_prefix("\\\\?\\") {
|
|
235
|
+
rest.to_string()
|
|
236
|
+
} else {
|
|
237
|
+
p.to_string()
|
|
238
|
+
}
|
|
239
|
+
}
|
|
224
240
|
pub fn readlink_core(args: &[Value]) -> Result<Value, Value> {
|
|
225
241
|
std::fs::read_link(path_arg(args, 0))
|
|
226
242
|
.map(|p| Value::String(p.to_string_lossy().into()))
|
|
@@ -393,3 +409,16 @@ pub fn constants() -> Value {
|
|
|
393
409
|
m.insert("X_OK".into(), Value::Number(1.0));
|
|
394
410
|
Value::object(m)
|
|
395
411
|
}
|
|
412
|
+
|
|
413
|
+
#[cfg(test)]
|
|
414
|
+
mod verbatim_prefix_tests {
|
|
415
|
+
use super::strip_verbatim_prefix;
|
|
416
|
+
|
|
417
|
+
#[test]
|
|
418
|
+
fn strips_windows_verbatim_prefixes_like_node() {
|
|
419
|
+
assert_eq!(strip_verbatim_prefix("\\\\?\\C:\\Users\\x\\ui"), "C:\\Users\\x\\ui");
|
|
420
|
+
assert_eq!(strip_verbatim_prefix("\\\\?\\UNC\\srv\\share\\d"), "\\\\srv\\share\\d");
|
|
421
|
+
assert_eq!(strip_verbatim_prefix("C:\\Users\\x"), "C:\\Users\\x");
|
|
422
|
+
assert_eq!(strip_verbatim_prefix("/Users/x/ui"), "/Users/x/ui");
|
|
423
|
+
}
|
|
424
|
+
}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|