Skip to content

Commit 7259b36

Browse files
committed
Merge branch 'fix/proctable-on-macos'
2 parents 4f9d724 + 1bfa39e commit 7259b36

File tree

6 files changed

+70
-7
lines changed

6 files changed

+70
-7
lines changed

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,13 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/)
66
and this project adheres to [Semantic Versioning](http://semver.org/).
77

8+
## 16.4.1 - 2026-01-06
9+
10+
### Changed
11+
12+
* Modified lockfile creation to handle macOS.
13+
* Removed handling of (ancient) version 2 configuration files.
14+
815
## 16.4.0 - 2026-01-01
916

1017
### Changed

lib/imap/backup/account/locker.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ def with_lock(&block)
2828
Account::FolderEnsurer.new(account: account).run
2929
end
3030

31-
lockfile.with_lock do
31+
begin
32+
lockfile.with_lock do
33+
block.call
34+
end
35+
rescue Lockfile::ProcessStartTimeUnavailableError
3236
block.call
3337
end
3438
end

lib/imap/backup/lockfile.rb

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module Imap::Backup
77
class Lockfile
88
# An error that is thrown if a lockfile already exists
99
class LockfileExistsError < StandardError; end
10+
class ProcessStartTimeUnavailableError < StandardError; end
1011

1112
attr_reader :path
1213

@@ -53,7 +54,9 @@ def stale?
5354

5455
return true if proc_table_entry.nil?
5556

56-
proc_table_entry.starttime != starttime
57+
other_starttime = starttime(proc_table_entry)
58+
59+
other_starttime != starttime
5760
end
5861

5962
private
@@ -62,9 +65,11 @@ def create
6265
pid = Process.pid
6366
proc_table_entry = Sys::ProcTable.ps(pid: pid)
6467

65-
raise "Unable to get process info for PID #{pid}" if proc_table_entry.nil?
68+
if proc_table_entry.nil?
69+
raise ProcessStartTimeUnavailableError, "Unable to get process info for PID #{pid}"
70+
end
6671

67-
starttime = proc_table_entry.starttime
72+
starttime = starttime(proc_table_entry)
6873

6974
data = {
7075
pid: pid,
@@ -74,5 +79,16 @@ def create
7479
json_data = JSON.generate(data)
7580
File.write(path, json_data)
7681
end
82+
83+
def starttime(proc_table_entry)
84+
case
85+
when proc_table_entry.respond_to?(:starttime)
86+
proc_table_entry.starttime
87+
when proc_table_entry.respond_to?(:start_tvsec)
88+
proc_table_entry.start_tvsec
89+
else
90+
raise ProcessStartTimeUnavailableError, "Proctable entry structure unknown"
91+
end
92+
end
7793
end
7894
end

lib/imap/backup/version.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ module Imap::Backup
66
# @private
77
MINOR = 4
88
# @private
9-
REVISION = 0
9+
REVISION = 1
1010
# @private
1111
PRE = nil
1212
# The application version

spec/unit/account/locker_spec.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,18 @@ module Backup
9494
end.to raise_error("Lockfile '#{account.lockfile_path}' exists and is not stale.")
9595
end
9696
end
97+
98+
context "when the process start time is unavailable" do
99+
it "calls the supplied block" do
100+
allow(lockfile).to receive(:with_lock).
101+
and_raise(Lockfile::ProcessStartTimeUnavailableError)
102+
103+
yielded = false
104+
subject.with_lock { yielded = true }
105+
106+
expect(yielded).to be true
107+
end
108+
end
97109
end
98110
end
99111
end

spec/unit/lockfile_spec.rb

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,14 @@ module Imap::Backup
77
let(:lockfile_path) { "test.lock" }
88
# We don't mock Process.pid because we want to use the real value in Process.kill
99
let(:pid) { Process.pid }
10-
let(:proc_info) { instance_double(Struct::ProcTableStruct, starttime: starttime) }
10+
let(:proc_info) do
11+
case RUBY_PLATFORM
12+
when /darwin/
13+
instance_double(Struct::ProcTableStruct, start_tvsec: starttime)
14+
else
15+
instance_double(Struct::ProcTableStruct, starttime: starttime)
16+
end
17+
end
1118
let(:starttime) { 456 }
1219

1320
before do
@@ -45,6 +52,16 @@ module Imap::Backup
4552
end
4653
end
4754

55+
context "when starttime is not available" do
56+
let(:proc_info) { "Unknown platform's proc info" }
57+
58+
it "raises" do
59+
expect do
60+
subject.with_lock {}
61+
end.to raise_error(Lockfile::ProcessStartTimeUnavailableError)
62+
end
63+
end
64+
4865
it "creates the lockfile" do
4966
subject.with_lock {}
5067

@@ -140,7 +157,14 @@ module Imap::Backup
140157
end
141158

142159
context "when the PID exists with a different starttime" do
143-
let(:other_proc_info) { instance_double(Struct::ProcTableStruct, starttime: starttime + 1) }
160+
let(:other_proc_info) do
161+
case RUBY_PLATFORM
162+
when /darwin/
163+
instance_double(Struct::ProcTableStruct, start_tvsec: starttime + 1)
164+
else
165+
instance_double(Struct::ProcTableStruct, starttime: starttime + 1)
166+
end
167+
end
144168

145169
before do
146170
allow(Sys::ProcTable).to receive(:ps).with(pid: pid) { other_proc_info }

0 commit comments

Comments
 (0)