@ape-egg/vibe-compiler 4.3.9 → 4.3.10
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.
|
Binary file
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ape-egg/vibe-compiler",
|
|
3
|
-
"version": "4.3.
|
|
3
|
+
"version": "4.3.10",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Optional Rust compiler for Vibe \u2014 pre-renders, inlines components, and optimizes iterations. The runtime never needs it.",
|
|
6
6
|
"homepage": "https://vibe.korte.kim",
|
package/src/Cargo.lock
CHANGED
|
@@ -1599,12 +1599,13 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
|
|
1599
1599
|
|
|
1600
1600
|
[[package]]
|
|
1601
1601
|
name = "vibe-compiler"
|
|
1602
|
-
version = "4.3.
|
|
1602
|
+
version = "4.3.10"
|
|
1603
1603
|
dependencies = [
|
|
1604
1604
|
"clap",
|
|
1605
1605
|
"colored",
|
|
1606
1606
|
"glob",
|
|
1607
1607
|
"html5ever",
|
|
1608
|
+
"libc",
|
|
1608
1609
|
"markup5ever",
|
|
1609
1610
|
"markup5ever_rcdom",
|
|
1610
1611
|
"notify",
|
package/src/Cargo.toml
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[package]
|
|
2
2
|
name = "vibe-compiler"
|
|
3
|
-
version = "4.3.
|
|
3
|
+
version = "4.3.10"
|
|
4
4
|
edition = "2021"
|
|
5
5
|
description = "Vibe framework compiler - compiles Vibe source files into optimized output"
|
|
6
6
|
authors = ["Kim Korte"]
|
|
@@ -30,6 +30,7 @@ swc_ecma_visit = "=0.107.0"
|
|
|
30
30
|
notify = "6.1"
|
|
31
31
|
notify-debouncer-full = "0.3"
|
|
32
32
|
rayon = "1.10"
|
|
33
|
+
libc = "0.2"
|
|
33
34
|
|
|
34
35
|
[profile.release]
|
|
35
36
|
opt-level = 3
|
package/src/compiler/mod.rs
CHANGED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
use std::path::PathBuf;
|
|
2
|
+
|
|
3
|
+
#[cfg(unix)]
|
|
4
|
+
const SIGNALS: [libc::c_int; 3] = [libc::SIGINT, libc::SIGTERM, libc::SIGHUP];
|
|
5
|
+
|
|
6
|
+
#[cfg(unix)]
|
|
7
|
+
fn signal_set() -> libc::sigset_t {
|
|
8
|
+
unsafe {
|
|
9
|
+
let mut set = std::mem::zeroed();
|
|
10
|
+
libc::sigemptyset(&mut set);
|
|
11
|
+
SIGNALS.iter().for_each(|&sig| {
|
|
12
|
+
libc::sigaddset(&mut set, sig);
|
|
13
|
+
});
|
|
14
|
+
set
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
#[cfg(unix)]
|
|
19
|
+
fn release(lock: &PathBuf, reason: &str, code: i32) -> ! {
|
|
20
|
+
let _ = std::fs::remove_file(lock);
|
|
21
|
+
eprintln!("{} — shutting down watcher", reason);
|
|
22
|
+
std::process::exit(code)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
#[cfg(unix)]
|
|
26
|
+
pub fn block() -> u32 {
|
|
27
|
+
unsafe { libc::pthread_sigmask(libc::SIG_BLOCK, &signal_set(), std::ptr::null_mut()) };
|
|
28
|
+
std::os::unix::process::parent_id()
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
#[cfg(target_os = "macos")]
|
|
32
|
+
pub fn release_on_exit(parent: u32, lock: PathBuf) {
|
|
33
|
+
let event = |ident: usize, filter: i16, fflags: u32| libc::kevent {
|
|
34
|
+
ident,
|
|
35
|
+
filter,
|
|
36
|
+
flags: libc::EV_ADD,
|
|
37
|
+
fflags,
|
|
38
|
+
data: 0,
|
|
39
|
+
udata: std::ptr::null_mut(),
|
|
40
|
+
};
|
|
41
|
+
let watched: Vec<libc::kevent> = SIGNALS
|
|
42
|
+
.iter()
|
|
43
|
+
.map(|&sig| event(sig as usize, libc::EVFILT_SIGNAL, 0))
|
|
44
|
+
.chain([event(parent as usize, libc::EVFILT_PROC, libc::NOTE_EXIT)])
|
|
45
|
+
.collect();
|
|
46
|
+
let queue = unsafe { libc::kqueue() };
|
|
47
|
+
let registered = unsafe {
|
|
48
|
+
libc::kevent(queue, watched.as_ptr(), watched.len() as i32, std::ptr::null_mut(), 0, std::ptr::null())
|
|
49
|
+
};
|
|
50
|
+
if registered == -1 || std::os::unix::process::parent_id() != parent {
|
|
51
|
+
release(&lock, "parent process exited", 0);
|
|
52
|
+
}
|
|
53
|
+
std::thread::spawn(move || {
|
|
54
|
+
let mut fired = event(0, 0, 0);
|
|
55
|
+
unsafe { libc::kevent(queue, std::ptr::null(), 0, &mut fired, 1, std::ptr::null()) };
|
|
56
|
+
match fired.filter {
|
|
57
|
+
libc::EVFILT_SIGNAL => release(&lock, "received shutdown signal", 128 + fired.ident as i32),
|
|
58
|
+
_ => release(&lock, "parent process exited", 0),
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
#[cfg(all(unix, not(target_os = "macos")))]
|
|
64
|
+
pub fn release_on_exit(parent: u32, lock: PathBuf) {
|
|
65
|
+
#[cfg(target_os = "linux")]
|
|
66
|
+
unsafe {
|
|
67
|
+
libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGHUP)
|
|
68
|
+
};
|
|
69
|
+
if std::os::unix::process::parent_id() != parent {
|
|
70
|
+
release(&lock, "parent process exited", 0);
|
|
71
|
+
}
|
|
72
|
+
std::thread::spawn(move || {
|
|
73
|
+
let mut sig = 0;
|
|
74
|
+
unsafe { libc::sigwait(&signal_set(), &mut sig) };
|
|
75
|
+
release(&lock, "received shutdown signal", 128 + sig)
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
#[cfg(not(unix))]
|
|
80
|
+
pub fn block() -> u32 {
|
|
81
|
+
0
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
#[cfg(not(unix))]
|
|
85
|
+
pub fn release_on_exit(_parent: u32, _lock: PathBuf) {}
|
package/src/compiler/watcher.rs
CHANGED
|
@@ -6,7 +6,7 @@ use colored::Colorize;
|
|
|
6
6
|
use notify_debouncer_full::{new_debouncer, notify::{RecursiveMode, Watcher}};
|
|
7
7
|
use regex::Regex;
|
|
8
8
|
|
|
9
|
-
use super::{Compiler, compile::should_skip_path};
|
|
9
|
+
use super::{Compiler, compile::should_skip_path, shutdown};
|
|
10
10
|
use crate::config::Config;
|
|
11
11
|
use crate::constants::{HYPERSPEED_DIR, MANIFEST_SUFFIX};
|
|
12
12
|
|
|
@@ -406,27 +406,6 @@ fn scan_directory(
|
|
|
406
406
|
Ok(())
|
|
407
407
|
}
|
|
408
408
|
|
|
409
|
-
/// A watcher whose spawning wrapper dies without unwinding (SIGKILL, crashed
|
|
410
|
-
/// dev server) is orphaned: it keeps watching and its lock blocks every future
|
|
411
|
-
/// `--watch` on the same output. Reparenting is the orphan signal — when the
|
|
412
|
-
/// parent pid changes (to init or a reaper), the owner is gone, so release the
|
|
413
|
-
/// lock and exit. `std::process::exit` skips Drop, hence the explicit remove.
|
|
414
|
-
#[cfg(unix)]
|
|
415
|
-
fn exit_when_orphaned(lock_path: PathBuf) {
|
|
416
|
-
let parent = std::os::unix::process::parent_id();
|
|
417
|
-
std::thread::spawn(move || loop {
|
|
418
|
-
std::thread::sleep(Duration::from_secs(2));
|
|
419
|
-
if std::os::unix::process::parent_id() != parent {
|
|
420
|
-
eprintln!("parent process exited — shutting down watcher");
|
|
421
|
-
let _ = std::fs::remove_file(&lock_path);
|
|
422
|
-
std::process::exit(0);
|
|
423
|
-
}
|
|
424
|
-
});
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
#[cfg(not(unix))]
|
|
428
|
-
fn exit_when_orphaned(_lock_path: PathBuf) {}
|
|
429
|
-
|
|
430
409
|
/// A config change invalidates every piece of watcher state — dependency
|
|
431
410
|
/// graph, compiler, parser, watch roots, output lock. The cleanest
|
|
432
411
|
/// expression is a fresh start: release the lock and exec the same binary
|
|
@@ -464,8 +443,9 @@ fn restart_with_fresh_config(lock: WatchLock) -> ! {
|
|
|
464
443
|
pub fn watch(config: Config, verbose: bool) -> std::result::Result<(), Box<dyn std::error::Error>> {
|
|
465
444
|
// Held for the watcher's whole lifetime; a second watcher on the same
|
|
466
445
|
// output exits loudly instead of silently racing this one.
|
|
446
|
+
let parent = shutdown::block();
|
|
467
447
|
let _watch_lock = WatchLock::acquire(&config.output)?;
|
|
468
|
-
|
|
448
|
+
shutdown::release_on_exit(parent, _watch_lock.path.clone());
|
|
469
449
|
|
|
470
450
|
println!("{}", "Building dependency graph...".cyan());
|
|
471
451
|
let mut graph = build_dependency_graph(&config)?;
|