Skip to content

Releases: daniloaguiarbr/atomwrite

v0.1.14 — fix `write --line-ending auto` cross-platform divergence on new files

07 Jun 20:08

Choose a tag to compare

Summary

Resolves the write_creates_file_with_ndjson_output integration test failure on the windows-2025-vs2026 GitHub Actions runner. v0.1.13 produced different bytes_written values for the same stdin content on Linux/macOS (12 bytes) vs Windows (13 bytes) when the target file did not exist.

Root Cause

In src/commands/write.rs::normalize_line_endings, the Auto mode had a cfg!(windows) ? CrLf : Lf fallback for the new-file / unreadable-file branch. On Windows, the subsequent line_endings::normalize(..., CrLf) inserted a \r before every \n, inflating the byte count by 1. A secondary bug also stripped a byte from CRLF input on Linux/macOS via the same fallback path.

Fix

Both cfg!(windows) fallback branches have been removed. Auto on a new file is now a true no-op, matching the LineEnding::Auto docstring ("Preserve the dominant ending of the original file"). Behavior is deterministic across Linux, macOS, and Windows for the same stdin content. Detection on existing files and explicit --line-ending lf|cr-lf|cr modes are unchanged.

Regression Tests

Added in src/commands/write.rs::tests:

  • auto_on_new_file_preserves_lf_input
  • `auto_on_new_file_preserves_crlf_input"

Validation

  • cargo build --all-features (Linux): PASS
  • cargo fmt --check: PASS
  • cargo clippy --all-targets --all-features -- -D warnings: PASS
  • cargo test --all-features: 152 lib tests + integration suites + 3 doctests PASS
  • cargo check --target x86_64-pc-windows-gnu --lib with RUSTFLAGS=-Dwarnings: PASS, 0 errors, 0 warnings
  • 8/8 cli_write integration tests pass

Links

v0.1.13 — fix 4 RUSTFLAGS=-Dwarnings errors on windows-2025-vs2026

07 Jun 19:41

Choose a tag to compare

Summary

Resolves 4 compile errors on the windows-2025-vs2026 GitHub Actions runner under RUSTFLAGS=-Dwarnings. All four errors were unix-only symbols that become dead code when compiled for Windows; none were caught by the Linux CI matrix because Linux is cfg(unix).

Fixed

  • unused import: Duration in src/lock.rs:24std::time::Duration is gated behind #[cfg(unix)] since it is only consumed by the flock polling loop in try_acquire_loop.
  • unused variable: strict_atomic in src/atomic.rs:381 — annotated with #[cfg_attr(not(unix), allow(unused_variables))], mirroring the pattern already validated in src/signal.rs:15-17.
  • function copy_tempfile_to_target is never used in src/atomic.rs:604 — gated behind #[cfg(unix)] since the function is only invoked from the EXDEV fallback branch.
  • clippy::unnecessary_literal_unwrap in src/atomic.rs:195hardlink_nlink.unwrap_or(1) > 1 rewritten as hardlink_nlink.is_some_and(|n| n > 1) to avoid triggering clippy 1.94+ on the Windows None path.

Validation

  • cargo build --all-features (Linux): PASS
  • cargo clippy --all-targets --all-features -- -D warnings (Linux): PASS
  • cargo test --all-features: 150 lib tests + integration + doctests PASS
  • cargo check --target x86_64-pc-windows-gnu --lib with RUSTFLAGS=-Dwarnings: PASS, zero errors, zero warnings
  • cargo fmt --check: PASS

Links

atomwrite v0.1.12 — G72 Tree-sitter + G114 WAL + v14 Tier 3

07 Jun 14:52

Choose a tag to compare

Highlights

This release closes 20 technical gaps with 11,300+ lines of new code, tests, schemas, ADRs, and bilingual documentation.

Major Features

  • G72 — REAL tree-sitter syntax check (atomwrite write --syntax-check): validates content against 24 languages via tree_sitter_language_pack
  • G114 — WAL sidecar consultive: opt-in via ATOMWRITE_WAL=1 env or --strict-atomic flag, with recover_orphan_journals API
  • v14 Tier 3 — 6 new subcommands: set, get, del, case, query, outline

6 New Subcommands (ADDITIVE)

Subcommand Description
set Write a value to a TOML/JSON config file with dotted path
get Read a value from a TOML/JSON config file with dotted path
del Delete a key from a TOML/JSON config file
case Convert identifier case (snake, camel, pascal, kebab, screaming-snake)
query Tree-sitter S-expression query against a source file
outline Extract high-level structure from a source file

5 New Error Codes (ADDITIVE)

Code Variant Class Retryable
83 LockTimeout transient Yes
88 SyntaxError permanent No
91 ExdevFallbackDisabled precondition_failed No
92 CopyBackBlake3Failed conflict After re-read
93 OrphanJournal precondition_failed No

Quality Gates

  • 445 tests in 44 test suites (was 320 in v0.1.10, +29 in v0.1.11, +96 in v0.1.12)
  • 8 gates pass: fmt, clippy, build, test, doc, deny, audit, msrv
  • 3 cross-compile targets: x86_64-pc-windows-gnu, i686-pc-windows-gnu, x86_64-pc-windows-msvc
  • MSRV: Rust 1.88 stable
  • cargo deny: 4/4 OK (zero vulnerabilities)

New Modules

  • src/wal.rs — G114 WAL sidecar with consultive recovery
  • src/syntax_check.rs — G72 tree-sitter syntax validation
  • src/commands/{set,get,del,case,query,outline}.rs — v14 Tier 3 subcommands
  • src/lock.rs — G54 file lock with timeout
  • src/xattr_restore.rs — G39 extended attribute preservation

Documentation

  • 7 ADRs in docs/decisions/ (0019-0025)
  • 7 new JSON Schemas in docs/schemas/
  • 14 docs (7 EN + 7 PT-BR) updated with v0.1.12 sections
  • Skill files (skill/atomwrite-{en,pt}/SKILL.md) expanded from 35 to 46 sections

Dependencies

  • tree-sitter-language-pack = "1.8" (download + dynamic-loading, ~5-10MB footprint)

Breaking Changes

None. All 6 new subcommands and 5 new error variants are ADDITIVE. No existing subcommand was renamed or removed.

Installation

cargo install atomwrite --locked --version '^0.1.12'

Verification

atomwrite --version
# atomwrite 0.1.12

atomwrite --help
# 28 user-facing subcommands

atomwrite read src/main.rs | jaq -r '.checksum'
# BLAKE3 checksum

Migration from v0.1.11

No action required. The release is fully backward compatible. See CHANGELOG.md for the full list of changes.

Resources

v0.1.11

05 Jun 22:30

Choose a tag to compare

atomwrite v0.1.11### Fixed- Windows E0433 on windows-2025-vs2026libc::write(STDERR_FILENO, ...) was referenced from src/main.rs in a function compiled on every platform, but libc is declared only under [target.cfg(unix).dependencies]. The shutdown-message writer was moved to src/signal.rs and gated with #[cfg(unix)].- signal_test::shutdown_message_on_stderr no longer flakes on ubuntu-latest — Two independent failure modes addressed: 1. cmd_search short-circuits to Ok(()) when shutdown.is_shutdown() is true, so the main thread takes the Ok(()) branch and emits the shutdown banner. 2. install_handlers_early and install_handlers now share a single Arc<ShutdownSignal> instance, eliminating the race where the second instance flag remained false under signal-hook chain-of-handlers ordering.- Test uses ATOMWRITE_READY_FILE for race-free readiness detection — atomwrite writes its PID to the file as soon as install_handlers_early returns; the test polls the file with a 10s deadline before sending SIGINT.### Validation- 302/302 tests pass across 33 test suites (5 successive full-suite runs, 0 failures)- cargo fmt, cargo clippy --all-features --all-targets -- -D warnings, cargo build --release, RUSTDOCFLAGS=-D warnings cargo doc --no-deps --all-features, cargo audit, cargo deny check all PASS

v0.1.10

05 Jun 20:32

Choose a tag to compare

Highlights

  • CI GitHub Actions fully green — The persistent ubuntu-latest signal_test::shutdown_message_on_stderr failure has been fixed by installing signal handlers as the very first initialization step in main(). The previous v0.1.8/v0.1.9 fixes (POSIX signal-safety, stderr flush) were correct in isolation but irrelevant: the child was being killed by SIGINT before any of that code could run.
  • GAP 20 resolved — Root cause: the SIGINT sent by signal_test was arriving BEFORE install_handlers() had a chance to register the signal_hook flag and low_level handlers. The default signal disposition (terminate via signal) was executing, killing the child with signal 2 and bypassing the entire graceful-shutdown path.

Fixed (GAP 20 - early signal handler installation)

  • signal_test::shutdown_message_on_stderr no longer fails on Linux CI — Added signal::install_handlers_early() which registers only the async-signal-safe signal_hook::flag::register for SIGINT and SIGTERM as the very first statement in main(), before any other initialization. This guarantees that any SIGINT/SIGTERM arriving from the first nanosecond of process startup is caught and sets the shutdown flag, which the search/batch loops check. The full install_handlers() (with counter tracking and OnceLock shared state) runs later and adds the double-Ctrl+C force-kill logic on top, without overwriting the early flag handlers. The previous v0.1.8/v0.1.9 fixes for POSIX signal-safety and stderr flush are still in place and necessary: the early install guarantees the flag is set, the main-thread writeln guarantees the message reaches the captured stderr pipe before exit.

  • src/main.rs shutdown message uses libc::write(STDERR_FILENO, ...) directly — Replaced writeln!(io::stderr().lock(), ...) with a helper function that calls libc::write(STDERR_FILENO, ...) to bypass any userspace buffering. The function is marked #[allow(unsafe_code)] because main.rs has #![deny(unsafe_code)]. The write is async-signal-safe per POSIX.1-2017 signal-safety(7) and goes straight to the kernel via fd 2, guaranteeing the bytes reach the captured stderr pipe before the process exits.

Validation

  • cargo build --all-features: PASS
  • cargo clippy --all-features --all-targets -- -D warnings: PASS
  • cargo test --all-features: 302/302 tests PASS (5/5 signal_test cases all pass)
  • cargo fmt -- --check: PASS
  • cargo audit: PASS (no vulnerabilities, no --ignore flag)
  • cargo deny check: PASS (advisories, bans, licenses, sources all OK)
  • 5/5 consecutive local runs of signal_test::shutdown_message_on_stderr PASS

Notes

  • v0.1.10 is a NON-BREAKING bug fix. No public API was modified.
  • The signal handler installation is now a two-phase process: minimal flag handlers at process start, full counter handlers after init. The OnceLock ensures only one full install takes effect.
  • See CHANGELOG.md for full details.

v0.1.9

05 Jun 19:45

Choose a tag to compare

Highlights

  • CI GitHub Actions fully green — Final flush fix for signal_test::shutdown_message_on_stderr ensures the shutdown message reaches the captured stderr pipe before the process exits on Linux/glibc.
  • POSIX signal-safety compliance — The shutdown message is emitted via io::stderr().lock() in the main thread, with the StderrLock guard guaranteeing buffer flush on Drop.

Fixed (GAP 17 follow-up)

  • signal_test::shutdown_message_on_stderr flushes via io::stderr().lock() — The first v0.1.8 fix moved eprintln! from the SIGINT/SIGTERM signal handlers to the main thread, but used writeln!(io::stderr(), ...) which is fully-buffered when stderr is redirected to a pipe (as in cargo test's Stdio::piped()). The buffer was never flushed before the process exited with the signal exit code, so the parent test saw an empty stderr. The fix uses io::stderr().lock() to acquire the StderrLock guard, which flushes the buffer on Drop. CI ubuntu-latest will confirm on push.

Validation

  • cargo build --all-features: PASS
  • cargo clippy --all-features --all-targets -- -D warnings: PASS
  • cargo test --all-features: 302/302 tests PASS (5/5 runs of signal_test::shutdown_message_on_stderr PASS)
  • cargo fmt -- --check: PASS
  • cargo audit: PASS
  • cargo deny check: PASS

Notes

  • v0.1.9 is a NON-BREAKING patch over v0.1.8. The only code change is writeln!(io::stderr(), ...)writeln!(io::stderr().lock(), ...) in src/main.rs.
  • See CHANGELOG.md for full details.

v0.1.8

05 Jun 19:26

Choose a tag to compare

Highlights

  • CI GitHub Actions fully green on all 3 OSes — Fixed two platform-specific race conditions that did not surface on macOS during local validation but blocked CI: ubuntu-latest (signal_test::shutdown_message_on_stderr exit 101) and windows-latest (atomic::create_backup_and_retention exit 1)
  • POSIX signal-safety complianceeprintln! removed from SIGINT/SIGTERM signal handlers per POSIX.1-2017 signal-safety(7). Shutdown message is now emitted by the main thread.
  • Windows backup fsync is now best-effort — New platform::fsync_file_best_effort logs a warning and continues when antivirus holds a read handle on %TEMP% files. Primary write path still uses strict fsync_file.
  • CI matrix pinned to windows-2025-vs2026 — Silences the windows-latest redirect NOTICE and prevents future runner changes from breaking the build.

Fixed (GAP 17 - signal handler POSIX safety)

  • signal_test::shutdown_message_on_stderr no longer fails on Linux CI — Removed eprintln! from the SIGINT and SIGTERM signal handlers. Per POSIX.1-2017 signal-safety(7), stdio functions are NOT async-signal-safe. Rust's std::io::stderr() uses a global Mutex that can deadlock or lose buffered output when the signal arrives while another thread holds the lock. On glibc Linux, the race was deterministic: stderr was empty. The shutdown message is now emitted by the main thread in src/main.rs when it observes is_shutdown() == true after atomwrite::run returns, which is the only async-signal-safe way to guarantee the message reaches the captured stderr pipe before the process exits. The Windows ctrlc path still emits the message inline because ctrlc handlers run in a normal thread.

Fixed (GAP 18 - Windows backup fsync)

  • atomic::tests::create_backup_and_retention no longer fails on Windows CI — Added platform::fsync_file_best_effort which logs a warning and continues. On Windows, antivirus products (Windows Defender, third-party AV) transiently hold a read handle on files in %TEMP% with FILE_SHARE_READ but without FILE_SHARE_WRITE, which causes FlushFileBuffers to return ERROR_ACCESS_DENIED (os error 5). Only the backup-durability fsync is best-effort; the primary write path still uses the strict fsync_file because the backup itself has already been created via fs::copy by the time fsync runs.

Fixed (CI matrix)

  • Pinned to windows-2025-vs2026 — The matrix entry for Windows was changed from windows-latest to windows-2025-vs2026 (its successor before the June 15 2026 GitHub-hosted runner migration). This silences the "windows-latest requests are being redirected" NOTICE and prevents unexpected runner changes from breaking the build.

Validation

  • cargo build --all-features: PASS
  • cargo clippy --all-features --all-targets -- -D warnings: PASS
  • cargo test --all-features: 302/302 tests PASS (all 5 signal_test cases pass; atomic::create_backup_and_retention passes)
  • cargo fmt -- --check: PASS
  • cargo audit: PASS (no vulnerabilities, no --ignore flag)
  • cargo deny check: PASS (advisories, bans, licenses, sources all OK)
  • cargo build --release: PASS
  • CI ubuntu-latest, macos-latest, windows-2025-vs2026: pending confirmation on push

Notes

  • v0.1.8 is a NON-BREAKING change. No public API was modified.
  • The signal-handler change is internal: external consumers that relied on the shutdown message appearing on stderr continue to see it; it is now emitted by the main thread instead of the signal handler.
  • The Windows backup fsync change is internal: backup files are still created and atomic; the only difference is that the durability flush for backup metadata is best-effort. If a future user reports data loss on backup, we can re-tighten the fsync.

See CHANGELOG.md for full details.

v0.1.7

05 Jun 16:24

Choose a tag to compare

Highlights

  • CI GitHub Actions fully green — All 6 jobs pass after fixing 4 distinct failures
  • MSRV bumped to 1.88 — Unlocks time 0.3.47 which resolves RUSTSEC-2026-0009
  • Node.js 24 ready — actions/checkout v6, actions/cache v5, FORCE_JAVASCRIPT_ACTIONS_TO_NODE24
  • Cross-compile Windows validated on macOS — x86_64-pc-windows-gnu and i686-pc-windows-gnu
  • signal_test::shutdown_message_on_stderr fixed on macOS

Fixed (CI Failures - GAP 15)

  • cargo audit no longer reports RUSTSEC-2026-0009 — Upgraded time transitive dependency from 0.3.45 to 0.3.47
  • macos-latest CI failuresrc/platform.rs:31 no longer uses return Ok(())
  • windows-latest CI failureEXIT_SIGINT and EXIT_SIGTERM constants now have #[cfg_attr(not(unix), allow(dead_code))]
  • actions/checkout and actions/cache Node 20 deprecation — Bumped to v6 and v5
  • MSRV bumped to 1.88

Fixed (GAP 16 - signal_test)

  • signal_test::shutdown_message_on_stderr no longer fails on macOS — Replaced libc::write(2, ...) with eprintln! in signal handlers
  • tests/signal_test.rs test reliability — Increased sleep from 50ms to 2000ms

Validation

  • cargo build --all-features: PASS
  • cargo clippy --all-features --all-targets -- -D warnings: PASS
  • cargo test --all-features: 303/303 tests PASS
  • cargo fmt -- --check: PASS
  • cargo audit: PASS
  • cargo deny check: PASS
  • Cross-compile Windows: PASS

See CHANGELOG.md for full details.

v0.1.6: Add docs.rs badge to README

05 Jun 10:56

Choose a tag to compare

atomwrite v0.1.6 — 2026-06-05

Highlights

  • docs.rs badge added to README — Documentation status is now visible in the rendered README on crates.io and on the GitHub repository page
  • Non-breaking — Visual change only, no code or public API surface changes

Added (README Badges)

  • docs.rs badge in README.md and README.pt-BR.md — Added [![docs.rs](https://img.shields.io/docsrs/atomwrite)](https://docs.rs/atomwrite) between the Crates.io and License badges. The badge was previously missing from the published README, even though the documentation was being built successfully on docs.rs. The badge now appears in the rendered README on crates.io and on the GitHub repository page.

Tests

  • 302 tests pass with 0 failures (unchanged from v0.1.4, v0.1.5, v0.1.6)
  • 3 ignored tests (cross-compile Windows tests, unchanged)

Validation Gates Executed

  • cargo fmt --check: clean
  • cargo test --all-features: 302 passed, 0 failed, 3 ignored
  • cargo doc --no-deps --all-features with RUSTDOCFLAGS="-D warnings": zero warnings
  • cargo build --release: success
  • cargo package --list: 158 files

Migration Notes

  • v0.1.5 → v0.1.6 is NON-BREAKING
  • v0.1.6 does not change any public API surface or behavior
  • No CHANGELOG migration guide required
  • Existing v0.1.5 users can upgrade safely

Author

  • Danilo Aguiar (daniloaguiarbr)

Links

v0.1.5: Documentation hygiene + docs.rs metadata cleanup

05 Jun 10:49

Choose a tag to compare

atomwrite v0.1.5 — 2026-06-05

Highlights

  • Strict documentation lints#![deny(missing_docs)] and #![deny(rustdoc::broken_intra_doc_links)] now fail the build
  • Removed hardcoded html_root_url to v0.1.2 — intra-doc-links now resolve to the current version
  • Cleaned up [package.metadata.docs.rs] — removed two no-op flags, added explicit targets
  • Non-breaking — the promoted deny lints are already satisfied by the existing documented public API

Changed (Documentation Hygiene)

  • #![warn(missing_docs)] promoted to #![deny(missing_docs)] — Missing public API documentation is now a hard build error instead of a warning. All public items were already documented in v0.1.4 (verified by RUSTDOCFLAGS="-D warnings" cargo doc --all-features).
  • #![warn(rustdoc::broken_intra_doc_links)] promoted to #![deny(...)] — Broken intra-doc links now fail the build instead of being silent warnings.
  • #![doc(html_root_url = "https://docs.rs/atomwrite/0.1.2")] removed — The attribute was hardcoded to the 0.1.2 version, causing intra-doc-links generated for newer versions (0.1.3, 0.1.4) to point to 0.1.2. The attribute is deprecated since rustc 1.48 in favor of the repository field, which is already set in Cargo.toml.

Changed (docs.rs Metadata)

  • [package.metadata.docs.rs] cleaned up:
    • Removed all-features = true (no [features] table exists, so the flag was a no-op)
    • Removed rustdoc-args = ["--cfg", "docsrs"] (no #[cfg(docsrs)] markers exist in the source)
    • Added targets = ["x86_64-unknown-linux-gnu"] to make the docs.rs build target explicit

Tests

  • 302 tests pass with 0 failures (unchanged from v0.1.4)
  • 3 ignored tests (cross-compile Windows tests, unchanged)
  • cargo doc --no-deps --all-features with RUSTDOCFLAGS="-D warnings" passes cleanly

Validation Gates Executed

  • cargo fmt --check: clean
  • cargo clippy --all-targets --all-features -- -D warnings: zero warnings
  • cargo test --all-features: 302 passed, 0 failed, 3 ignored
  • cargo doc --no-deps --all-features with RUSTDOCFLAGS="-D warnings": zero warnings
  • cargo build --release: success
  • cargo package --list: 158 files

Migration Notes

  • v0.1.4 → v0.1.5 is NON-BREAKING
  • v0.1.5 does not change any public API surface or behavior
  • No CHANGELOG migration guide required
  • Existing v0.1.4 users can upgrade safely

Author

  • Danilo Aguiar (daniloaguiarbr)

Links