pstore 0.2.1 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 581505ed1677d161bfeab6b72527336b3593726a2ef3e354155e944c0189bf8b
4
- data.tar.gz: 29a99aead3e82f72c1bbcf821a39dbba0601f58d93cbc8649d6d522da938e8c0
3
+ metadata.gz: be4c744cb12983612ebef3ae585d25571252869cfef51a8799a0c3328be339c8
4
+ data.tar.gz: 9527c38bdea78cfee23874de9ecfdfee3ce9beefb541bd6e26abfa3ba55e3a3c
5
5
  SHA512:
6
- metadata.gz: 2713ed297961e320cc23a3ae9659f233bff05769878312f0516dbdd207dac8bcd6f979ca082717ba5ca65dd7b39c129149b7bcb269b39e243dac4294270353b2
7
- data.tar.gz: f3833ca460fe0406a9bb1d21c8b19dfd515a0b5706aa91cfc4114b2f62696962cbad1773b8bfe62701a24321d77aa15d0e96aabbbf91586ca82284dd5d412a84
6
+ metadata.gz: 7fa202004bbd5761b8a457fda173f69d2b0574d1b995ef3e2800c2881213719fb6e9cacd4d0cccfb29b0864c28f149a0520b4102f0172ecfccf7ae277367d023
7
+ data.tar.gz: b2724f28ea0ede1bac0675f77bc00665771b88b6e946da3dfd00ab0e946adef9589a350bcce05732c4568b867714b98fc7133810083a5af60ee62fdd67936efc
@@ -0,0 +1,4 @@
1
+ changelog:
2
+ exclude:
3
+ labels:
4
+ - dependencies # Added by Dependabot
@@ -23,11 +23,11 @@ jobs:
23
23
 
24
24
  steps:
25
25
  - name: Harden Runner
26
- uses: step-security/harden-runner@5ef0c079ce82195b2a36a210272d6b661572d83e # v2.14.2
26
+ uses: step-security/harden-runner@ccd8616d44fd3846e67624a50d5aad6d37bf2d25 # v2.22.1
27
27
  with:
28
28
  egress-policy: audit
29
29
 
30
- - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
30
+ - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
31
31
 
32
32
  - name: Set up Ruby
33
33
  uses: ruby/setup-ruby@d5126b9b3579e429dd52e51e68624dda2e05be25 # v1.267.0
@@ -36,7 +36,7 @@ jobs:
36
36
  ruby-version: ruby
37
37
 
38
38
  - name: Publish to RubyGems
39
- uses: rubygems/release-gem@1c162a739e8b4cb21a676e97b087e8268d8fc40b # v1.1.2
39
+ uses: rubygems/release-gem@7f9650160c1a4e7989fdc9855807bdbd421d8b6b # v1.4.1
40
40
 
41
41
  - name: Create GitHub release
42
42
  run: |
@@ -25,7 +25,7 @@ jobs:
25
25
  - { os: windows-latest, ruby: mswin }
26
26
  runs-on: ${{ matrix.os }}
27
27
  steps:
28
- - uses: actions/checkout@v6
28
+ - uses: actions/checkout@v7
29
29
  - name: Set up Ruby
30
30
  uses: ruby/setup-ruby@v1
31
31
  with:
data/lib/pstore.rb CHANGED
@@ -327,12 +327,13 @@ require "digest"
327
327
  #
328
328
  class PStore
329
329
  # :stopdoc:
330
- VERSION = "0.2.1"
330
+ VERSION = "0.3.0"
331
331
 
332
- RDWR_ACCESS = {mode: IO::RDWR | IO::CREAT | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
333
- RD_ACCESS = {mode: IO::RDONLY | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
334
- WR_ACCESS = {mode: IO::WRONLY | IO::CREAT | IO::TRUNC | IO::BINARY, encoding: Encoding::ASCII_8BIT}.freeze
335
- private_constant :RDWR_ACCESS, :RD_ACCESS, :WR_ACCESS
332
+ RDWR_ACCESS = IO::RDWR | IO::CREAT | IO::BINARY
333
+ RD_ACCESS = IO::RDONLY | IO::BINARY
334
+ WR_ACCESS = IO::WRONLY | IO::CREAT | IO::TRUNC | IO::BINARY
335
+ NOFOLLOW = IO.const_defined?(:NOFOLLOW) ? IO::NOFOLLOW : 0
336
+ private_constant :RDWR_ACCESS, :RD_ACCESS, :WR_ACCESS, :NOFOLLOW
336
337
  # :startdoc:
337
338
 
338
339
  # The error type thrown by all PStore methods.
@@ -367,12 +368,26 @@ class PStore
367
368
  #
368
369
  # A \PStore object is
369
370
  # {reentrant}[https://en.wikipedia.org/wiki/Reentrancy_(computing)].
370
- # If argument +thread_safe+ is given as +true+,
371
+ # If argument or keyword argument +thread_safe+ is given as +true+,
371
372
  # the object is also thread-safe (at the cost of a small performance penalty):
372
373
  #
373
374
  # store = PStore.new(path, true)
375
+ # store = PStore.new(path, thread_safe: true)
374
376
  #
375
- def initialize(file, thread_safe = false)
377
+ # If keyword argument +ultra_safe+ is given as +true+, the object is
378
+ # set to +ultra_safe+ mode.
379
+ #
380
+ # store = PStore.new(path, ultra_safe: true)
381
+ #
382
+ # If keyword argument +follow_symlink+ is given as +false+, the store file
383
+ # itself must not be a symbolic link. This option has no effect on platforms
384
+ # that do not support IO::NOFOLLOW. Symbolic links in parent directories are
385
+ # not affected.
386
+ #
387
+ # store = PStore.new(path, follow_symlink: false)
388
+ #
389
+ def initialize(file, _thread_safe = false, thread_safe: _thread_safe,
390
+ ultra_safe: false, follow_symlink: true)
376
391
  dir = File::dirname(file)
377
392
  unless File::directory? dir
378
393
  raise PStore::Error, format("directory %s does not exist", dir)
@@ -380,16 +395,17 @@ class PStore
380
395
  if File::exist? file and not File::readable? file
381
396
  raise PStore::Error, format("file %s not readable", file)
382
397
  end
383
- @filename = file
398
+ @filename = File.path(file)
384
399
  @abort = false
385
- @ultra_safe = false
400
+ @ultra_safe = ultra_safe
386
401
  @thread_safe = thread_safe
402
+ @nofollow = follow_symlink ? 0 : NOFOLLOW
387
403
  @lock = Thread::Mutex.new
388
404
  end
389
405
 
390
406
  # Raises PStore::Error if the calling code is not in a PStore#transaction.
391
407
  def in_transaction
392
- raise PStore::Error, "not in transaction" unless @lock.locked?
408
+ raise PStore::Error, "not in transaction" unless @lock.owned?
393
409
  end
394
410
  #
395
411
  # Raises PStore::Error if the calling code is not in a PStore#transaction or
@@ -439,7 +455,7 @@ class PStore
439
455
  def fetch(key, default=PStore::Error)
440
456
  in_transaction
441
457
  unless @table.key? key
442
- if default == PStore::Error
458
+ if PStore::Error.equal?(default)
443
459
  raise PStore::Error, format("undefined key '%s'", key)
444
460
  else
445
461
  return default
@@ -527,7 +543,7 @@ class PStore
527
543
  def commit
528
544
  in_transaction
529
545
  @abort = false
530
- throw :pstore_abort_transaction
546
+ throw self
531
547
  end
532
548
 
533
549
  # Exits the current transaction block, discarding any changes
@@ -538,7 +554,7 @@ class PStore
538
554
  def abort
539
555
  in_transaction
540
556
  @abort = true
541
- throw :pstore_abort_transaction
557
+ throw self
542
558
  end
543
559
 
544
560
  # Opens a transaction block for the store.
@@ -570,7 +586,7 @@ class PStore
570
586
  begin
571
587
  @table, checksum, original_data_size = load_data(file, read_only)
572
588
 
573
- catch(:pstore_abort_transaction) do
589
+ catch(self) do
574
590
  value = yield(self)
575
591
  end
576
592
 
@@ -583,7 +599,7 @@ class PStore
583
599
  else
584
600
  # This can only occur if read_only == true.
585
601
  @table = {}
586
- catch(:pstore_abort_transaction) do
602
+ catch(self) do
587
603
  value = yield(self)
588
604
  end
589
605
  end
@@ -621,23 +637,26 @@ class PStore
621
637
  # All exceptions are propagated.
622
638
  #
623
639
  def open_and_lock_file(filename, read_only)
624
- if read_only
625
- begin
626
- file = File.new(filename, **RD_ACCESS)
640
+ filename = File.path(filename)
641
+ loop do
642
+ if read_only
627
643
  begin
628
- file.flock(File::LOCK_SH)
629
- return file
630
- rescue
631
- file.close
632
- raise
644
+ file = File.new(filename, mode: RD_ACCESS | @nofollow, encoding: Encoding::ASCII_8BIT)
645
+ rescue Errno::ENOENT
646
+ return nil
633
647
  end
634
- rescue Errno::ENOENT
635
- return nil
648
+ else
649
+ file = File.new(filename, mode: RDWR_ACCESS | @nofollow, encoding: Encoding::ASCII_8BIT)
650
+ end
651
+ current = false
652
+ begin
653
+ file.flock(read_only ? File::LOCK_SH : File::LOCK_EX)
654
+ # An atomic save may have replaced the file while this lock was pending.
655
+ current = File.identical?(file, filename)
656
+ return file if current
657
+ ensure
658
+ file.close unless current
636
659
  end
637
- else
638
- file = File.new(filename, **RDWR_ACCESS)
639
- file.flock(File::LOCK_EX)
640
- return file
641
660
  end
642
661
  end
643
662
 
@@ -651,6 +670,7 @@ class PStore
651
670
  table = load(file)
652
671
  raise Error, "PStore file seems to be corrupted." unless table.is_a?(Hash)
653
672
  rescue EOFError
673
+ raise unless file.size == 0
654
674
  # This seems to be a newly-created file.
655
675
  table = {}
656
676
  end
@@ -694,13 +714,14 @@ class PStore
694
714
 
695
715
  def save_data_with_atomic_file_rename_strategy(data, file)
696
716
  temp_filename = "#{@filename}.tmp.#{Process.pid}.#{rand 1000000}"
697
- temp_file = File.new(temp_filename, **WR_ACCESS)
717
+ temp_file = File.new(temp_filename, mode: WR_ACCESS | @nofollow, encoding: Encoding::ASCII_8BIT, perm: 0o000)
698
718
  begin
699
719
  temp_file.flock(File::LOCK_EX)
700
720
  temp_file.write(data)
701
721
  temp_file.flush
722
+ temp_file.chmod(file.stat.mode)
702
723
  File.rename(temp_filename, @filename)
703
- rescue
724
+ rescue Exception
704
725
  File.unlink(temp_file) rescue nil
705
726
  raise
706
727
  ensure
data/pstore.gemspec CHANGED
@@ -17,6 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.description = spec.summary
18
18
  spec.homepage = "https://github.com/ruby/pstore"
19
19
  spec.licenses = ["Ruby", "BSD-2-Clause"]
20
+ spec.required_ruby_version = ">= 2.4"
20
21
 
21
22
  spec.metadata["homepage_uri"] = spec.homepage
22
23
  spec.metadata["source_code_uri"] = "https://github.com/ruby/pstore"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pstore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yukihiro Matsumoto
@@ -18,6 +18,7 @@ extra_rdoc_files: []
18
18
  files:
19
19
  - ".document"
20
20
  - ".github/dependabot.yml"
21
+ - ".github/release.yml"
21
22
  - ".github/workflows/push_gem.yml"
22
23
  - ".github/workflows/test.yml"
23
24
  - ".gitignore"
@@ -44,7 +45,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
44
45
  requirements:
45
46
  - - ">="
46
47
  - !ruby/object:Gem::Version
47
- version: '0'
48
+ version: '2.4'
48
49
  required_rubygems_version: !ruby/object:Gem::Requirement
49
50
  requirements:
50
51
  - - ">="