ace-support-items 0.15.5 → 0.15.6

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ada51daf0c8206e7f3361c173324569468b5cd71c5a78b813fc50f9d570a212a
4
- data.tar.gz: 0ebe5ba5e4a96c1a8d10303dd05b341e1753dca986e099b4d9fc25646484ae03
3
+ metadata.gz: 2087dba6ece279d58921d98a503866b9b71bee16454bf087a73e475f3f9867d3
4
+ data.tar.gz: cea39cc5db5a8841731e4407256bfae628fd80ff69c9e34d5225273a30e73562
5
5
  SHA512:
6
- metadata.gz: e1380dae7a2ba521878f40dcdd5143149fe343ec33f1f20e97538f7a2768008f69b417093ab8b546f5fb795cbcf8f76e98f5f76b10532084d3cb4443fd5e850d
7
- data.tar.gz: a7a416f48468c984b33137255b7ec2a03ef8e8547efdf4d47ef34330d6a6407a645820c9f1cb1f7431cadec901750ba5285b3f526401402ae6c768fa29508685
6
+ metadata.gz: 97701a1dbb3bd4664c05178cae3a712b0f520d72f20a46df9e4d2ddba323780a5e765327b5ce328703091b1210bbe18927f69258aed858fff0fe04618f5b38a8
7
+ data.tar.gz: 97d6a6b1d537a8e0f07c1268e624b618ca116a25f12a02ebdc5b197d2d543d2e421ee2598ca662086c2129d888ac1e7d09afc85abafc54a77e014791bb96da4b
data/CHANGELOG.md CHANGED
@@ -7,6 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.15.6] - 2026-03-29
11
+
12
+ ### Fixed
13
+ - `FieldUpdater`: serialize same-file frontmatter mutations with an exclusive lock across the full read-modify-write cycle so concurrent updates do not silently lose one writer's changes.
14
+
15
+ ### Technical
16
+ - Added a cross-process regression that proves frontmatter updates wait on the file lock and preserve the latest locked-file edits before applying their own mutation.
10
17
 
11
18
  ## [0.15.5] - 2026-03-29
12
19
 
@@ -20,19 +20,24 @@ module Ace
20
20
  # @param remove [Hash] Fields to remove from arrays (key => value or array of values).
21
21
  # @return [Hash] Updated frontmatter hash
22
22
  def self.update(file_path, set: {}, add: {}, remove: {})
23
- content = File.read(file_path)
24
- frontmatter, body = Atoms::FrontmatterParser.parse(content)
25
- # Strip leading newline from body so rebuild doesn't double-space
26
- body = body.sub(/\A\n/, "")
23
+ File.open(file_path, File::RDWR) do |file|
24
+ file.flock(File::LOCK_EX)
27
25
 
28
- apply_set(frontmatter, set)
29
- apply_add(frontmatter, add)
30
- apply_remove(frontmatter, remove)
26
+ file.rewind
27
+ content = file.read
28
+ frontmatter, body = Atoms::FrontmatterParser.parse(content)
29
+ # Strip leading newline from body so rebuild doesn't double-space
30
+ body = body.sub(/\A\n/, "")
31
31
 
32
- new_content = Atoms::FrontmatterSerializer.rebuild(frontmatter, body)
33
- atomic_write(file_path, new_content)
32
+ apply_set(frontmatter, set)
33
+ apply_add(frontmatter, add)
34
+ apply_remove(frontmatter, remove)
34
35
 
35
- frontmatter
36
+ new_content = Atoms::FrontmatterSerializer.rebuild(frontmatter, body)
37
+ rewrite_locked_file(file, new_content)
38
+
39
+ frontmatter
40
+ end
36
41
  end
37
42
 
38
43
  # Apply --set operations (supports nested dot-key paths).
@@ -102,17 +107,18 @@ module Ace
102
107
  target[parts.last] = value
103
108
  end
104
109
 
105
- # Write content atomically using temp file + rename.
106
- def self.atomic_write(file_path, content)
107
- tmp_path = "#{file_path}.tmp.#{Process.pid}"
108
- File.write(tmp_path, content)
109
- File.rename(tmp_path, file_path)
110
- rescue
111
- File.unlink(tmp_path) if tmp_path && File.exist?(tmp_path)
112
- raise
110
+ # Rewrite content in-place on a locked file descriptor.
111
+ # This preserves the lock across the full read-modify-write cycle so
112
+ # concurrent updaters serialize instead of losing one writer's changes.
113
+ def self.rewrite_locked_file(file, content)
114
+ file.rewind
115
+ file.truncate(0)
116
+ file.write(content)
117
+ file.flush
118
+ file.fsync
113
119
  end
114
120
 
115
- private_class_method :apply_nested_set, :atomic_write
121
+ private_class_method :apply_nested_set, :rewrite_locked_file
116
122
  end
117
123
  end
118
124
  end
@@ -3,7 +3,7 @@
3
3
  module Ace
4
4
  module Support
5
5
  module Items
6
- VERSION = '0.15.5'
6
+ VERSION = '0.15.6'
7
7
  end
8
8
  end
9
9
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ace-support-items
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.15.5
4
+ version: 0.15.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michal Czyz