Module: VivlioStarter::CLI::ScaffoldLock

Extended by:
ScaffoldLock
Included in:
ScaffoldLock
Defined in:
lib/vivlio_starter/cli/scaffold_lock.rb

Constant Summary collapse

LOCK_RELATIVE =
File.join('config', 'scaffold.lock')
AUTHOR_DATA_DIRS =

著者データ領域(§1.3): ハッシュ判定以前に一律で upgrade 対象外。 ディレクトリは最上位名で判定する。

%w[contents images covers codes data].freeze
AUTHOR_DATA_FILES =

著者データ領域のうち個別ファイル指定分。 辞書系 4 点は index:apply / vs lint --register が書き込む「著者の辞書」 であり、雛形サンプルで上書きすると著者データを破壊するため一律保護する。

[
  File.join('config', 'book.yml'),
  File.join('config', 'catalog.yml'),
  File.join('config', 'talk.yml'),
  File.join('config', 'index_glossary_terms.yml'),
  File.join('config', 'index_glossary_rejected.yml'),
  File.join('config', 'spellcheck_allowlist.yml'),
  File.join('config', 'textlint_allowlist.yml')
].freeze
IGNORED_BASENAMES =

展開・比較の対象にしない雛形内ファイル

%w[.DS_Store].freeze

Instance Method Summary collapse

Instance Method Details

#author_data?(relative) ⇒ Boolean

著者データ領域(一律 upgrade 対象外)かどうか

Parameters:

  • relative (String)

    プロジェクトルートからの相対パス

Returns:

  • (Boolean)


52
53
54
55
# File 'lib/vivlio_starter/cli/scaffold_lock.rb', line 52

def author_data?(relative)
  top = relative.split('/').first
  AUTHOR_DATA_DIRS.include?(top) || AUTHOR_DATA_FILES.include?(relative)
end

#digest_scaffold(scaffold_source) ⇒ Hash{String => String}

雛形全ファイルのハッシュ表を作る(lock の files 節)。 book.yml もプレースホルダー書き換え「前」の雛形原本ハッシュで記録する (比較対象は常に雛形原本。§2.1)。

Returns:

  • (Hash{String => String})

    relative → "sha256:…"



75
76
77
78
79
# File 'lib/vivlio_starter/cli/scaffold_lock.rb', line 75

def digest_scaffold(scaffold_source)
  scaffold_files(scaffold_source).to_h do |relative|
    [relative, file_digest(File.join(scaffold_source, relative))]
  end
end

#file_digest(path) ⇒ String

lock に記録するハッシュ表記(アルゴリズムを明示する prefix 付き)

Returns:

  • (String)

    例: "sha256:ab12…"



59
# File 'lib/vivlio_starter/cli/scaffold_lock.rb', line 59

def file_digest(path) = "sha256:#{Digest::SHA256.file(path).hexdigest}"

#generate!(project_root, scaffold_source:, version:) ⇒ Object

vs new の展開末尾から呼ぶ生成処理。 既存の lock があれば既存エントリを優先して残す(--add-missing で重ね展開した場合、 著者の手元ファイルの「展開時点ハッシュ」という意味を壊さないため)。



107
108
109
110
111
112
113
# File 'lib/vivlio_starter/cli/scaffold_lock.rb', line 107

def generate!(project_root, scaffold_source:, version:)
  files = digest_scaffold(scaffold_source)
  if (existing = read(project_root))
    files = files.merge(existing[:files])
  end
  write(project_root, version:, files:)
end

#read(project_root = '.') ⇒ Hash{Symbol => Object}?

lock を読み込む。存在しない・壊れている場合は nil(呼び出し側で lock なしフォールバック)

Parameters:

  • project_root (String) (defaults to: '.')

Returns:

  • (Hash{Symbol => Object}, nil)

    { version: String|nil, files: Hash }



84
85
86
87
88
89
90
91
92
93
94
# File 'lib/vivlio_starter/cli/scaffold_lock.rb', line 84

def read(project_root = '.')
  path = File.join(project_root, LOCK_RELATIVE)
  return nil unless File.file?(path)

  data = YAML.safe_load(File.read(path, encoding: 'utf-8'))
  return nil unless data.is_a?(Hash) && data['files'].is_a?(Hash)

  { version: data['scaffold_version'], files: data['files'] }
rescue StandardError
  nil
end

#scaffold_files(scaffold_source) ⇒ Array<String>

雛形ディレクトリ内の全ファイルの相対パスを列挙する(lock 対象外の残骸は除外)

Parameters:

  • scaffold_source (String)

    雛形ルートの絶対パス

Returns:

  • (Array<String>)


64
65
66
67
68
69
# File 'lib/vivlio_starter/cli/scaffold_lock.rb', line 64

def scaffold_files(scaffold_source)
  Dir.glob('**/*', File::FNM_DOTMATCH, base: scaffold_source)
     .reject { IGNORED_BASENAMES.include?(File.basename(it)) }
     .select { File.file?(File.join(scaffold_source, it)) }
     .sort
end

#write(project_root, version:, files:) ⇒ Object

lock を書き出す(自動生成ファイルである旨のヘッダ付き)

Parameters:

  • files (Hash{String => String})

    relative → "sha256:…"



98
99
100
101
102
# File 'lib/vivlio_starter/cli/scaffold_lock.rb', line 98

def write(project_root, version:, files:)
  content = +"# vs new / vs upgrade が管理する自動生成ファイル。手動編集しない。\n"
  content << YAML.dump({ 'scaffold_version' => version, 'files' => files.sort.to_h })
  File.write(File.join(project_root, LOCK_RELATIVE), content, encoding: 'utf-8')
end