Module: Vivlio::Starter::CLI::BuildCommands::BuildLock

Defined in:
lib/vivlio/starter/cli/build/build_lock.rb

Overview

同一プロジェクトでの vs build 多重実行を防ぐ排他ロック機構。.cache/vs/.build.lock に対し File::LOCK_EX | File::LOCK_NB でフロックを取得し、競合時は AlreadyLockedError を送出する。

Defined Under Namespace

Classes: AlreadyLockedError

Constant Summary collapse

LOCK_FILENAME =
'.build.lock'

Class Method Summary collapse

Class Method Details

.build_conflict_message(lock_path, existing) ⇒ Object



80
81
82
83
84
85
86
87
88
# File 'lib/vivlio/starter/cli/build/build_lock.rb', line 80

def build_conflict_message(lock_path, existing)
  hint = existing.to_s.strip
  hint_section = hint.empty? ? '' : "\n  既存ロック情報:\n#{hint.lines.map { "    #{it}" }.join}"
  <<~MSG.strip
    別の vs build プロセスがこのプロジェクトで実行中です。
      ロックファイル: #{lock_path}#{hint_section}
      完了を待ってから再実行するか、該当プロセスを終了してください。
  MSG
end

.read_lock_info(file) ⇒ Object



66
67
68
69
70
71
# File 'lib/vivlio/starter/cli/build/build_lock.rb', line 66

def read_lock_info(file)
  file.rewind
  file.read
rescue StandardError
  ''
end

.with_lock { ... } ⇒ Object

ロックを取得してブロックを実行する。終了時に自動で解放する。

Yields:

  • ロック取得中に実行するブロック

Returns:

  • (Object)

    ブロックの戻り値

Raises:



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/vivlio/starter/cli/build/build_lock.rb', line 44

def with_lock
  lock_path = File.join(Vivlio::Starter::CLI::Common.ensure_cache_dir!, LOCK_FILENAME)
  # ブロック形式は flock を yield 越しに保持できないため使用しない
  file = File.open(lock_path, File::RDWR | File::CREAT, 0o644) # rubocop:disable Style/FileOpen

  unless file.flock(File::LOCK_EX | File::LOCK_NB)
    existing = read_lock_info(file)
    file.close
    raise AlreadyLockedError, build_conflict_message(lock_path, existing)
  end

  write_lock_info(file)

  begin
    yield
  ensure
    file.flock(File::LOCK_UN)
    file.close
    FileUtils.rm_f(lock_path)
  end
end

.write_lock_info(file) ⇒ Object



73
74
75
76
77
78
# File 'lib/vivlio/starter/cli/build/build_lock.rb', line 73

def write_lock_info(file)
  file.truncate(0)
  file.rewind
  file.write("pid=#{Process.pid}\nstarted=#{Time.now.iso8601}\n")
  file.flush
end