Module: Vivlio::Starter::CLI::CleanCommands
- Defined in:
- lib/vivlio/starter/cli/clean.rb
Overview
ビルド生成物のクリーンアップコマンド
オプション:
- (なし): 中間生成物を削除、最終 PDF は保持
- --purge: 最終 PDF も含めてすべて削除
- --cache: キャッシュディレクトリのみ削除
- --cover: 生成されたカバー画像のみ削除(マスターは保持)
- --all: 上記すべてを実行(開発者向け)
Constant Summary collapse
- CLEAN_DESC =
{ short: '不要ファイルやキャッシュを削除します', long: <<~DESC 生成物(HTML/中間PDF など)を削除する標準クリーンに加えて、 各オプションで特定のファイルのみを削除できます。 - `vs clean` : 生成物(HTML / 中間PDF 等)を削除(最終PDFは保持) - `vs clean --purge` : 最終PDFも含めてすべて削除 - `vs clean --cache` : キャッシュディレクトリのみ削除(生成物は保持) - `vs clean --cover` : 生成されたカバー画像のみを削除(マスターは保持) DESC }.freeze
Class Method Summary collapse
-
.add_dynamic_filename_patterns(patterns) ⇒ void
config/book.yml の project.name から動的ファイル名パターンを生成し追加する.
-
.clean_bundled_variant_images ⇒ void
bundled テーマ用に生成されたバリアント画像を削除する.
-
.clean_cover_files ⇒ void
生成されたカバー画像を削除する(マスター画像・ユーザーSVGは保持).
-
.clean_index_dictionaries ⇒ void
索引・用語集辞書データを削除する(確認プロンプトあり).
-
.execute_clean(option_hash) ⇒ void
クリーンアップ処理のエントリーポイント.
Class Method Details
.add_dynamic_filename_patterns(patterns) ⇒ void
This method returns an undefined value.
config/book.yml の project.name から動的ファイル名パターンを生成し追加する
生成されるパターン例(project.name が “vivlio_starter” の場合):
- vivlio_starter*.pdf
- vivlio_starter_v*.pdf(バージョン付き)
- vivlio_starter_print*.pdf(印刷用)
219 220 221 222 223 224 225 226 227 228 229 |
# File 'lib/vivlio/starter/cli/clean.rb', line 219 def add_dynamic_filename_patterns(patterns) config = Common::CONFIG project_name = config.dig('project', 'name') return unless project_name patterns << "#{project_name}*.pdf" patterns << "#{project_name}_v*.pdf" patterns << "#{project_name}_print*.pdf" patterns << "#{project_name}*.epub" patterns << "#{project_name}_v*.epub" end |
.clean_bundled_variant_images ⇒ void
This method returns an undefined value.
bundled テーマ用に生成されたバリアント画像を削除する
削除対象: stylesheets/images/bundled/ 内の *_portrait.webp, *_landscape.webp これらはビルド時に自動生成される派生画像であり、再生成可能
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 |
# File 'lib/vivlio/starter/cli/clean.rb', line 237 def clean_bundled_variant_images images_dir = File.join(Common::STYLESHEETS_DIR, 'images', 'bundled') unless Dir.exist?(images_dir) Common.log_info("bundled テーマ画像ディレクトリが存在しません: #{images_dir}") return end Common.log_action('bundled テーマバリアント画像を削除中...') patterns = ['*_portrait.webp', '*_landscape.webp'] deleted = 0 patterns.each do |pattern| Dir.glob(File.join(images_dir, pattern)).each do |file| next unless File.file?(file) FileUtils.rm_f(file) Common.log_info("#{file} を削除しました") deleted += 1 end end if deleted.zero? Common.log_info('削除対象の bundled バリアント画像はありませんでした') else Common.log_success("bundled テーマバリアントを削除しました(#{deleted}ファイル)") end rescue StandardError => e Common.log_warn("bundled テーマバリアント削除中にエラー: #{e.}") end |
.clean_cover_files ⇒ void
This method returns an undefined value.
生成されたカバー画像を削除する(マスター画像・ユーザーSVGは保持)
削除対象:
- covers/ 内の *.pdf, *.jpg(coverコマンドで生成されたファイル)
- covers/ 内の *_light.svg, *_dark.svg(bundledテンプレートから生成されたSVG)
- covers/ 内の *_rendered.svg(ユーザーSVGにプレースホルダー適用した中間ファイル)
保持対象:
- *.png(frontcover_master.png 等、利用者が用意した画像)
- *.key(Keynote ソースファイル)
- covers/bundled/ 内のファイル(テンプレート本体)
- light/dark 以外の *.svg(frontcover_floral.svg 等、利用者が用意したSVG)
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/vivlio/starter/cli/clean.rb', line 315 def clean_cover_files config = Common.load_config covers_dir = config.dig(:directories, :covers) || Common::COVERS_DIR unless File.directory?(covers_dir) Common.log_info("カバーディレクトリが存在しません: #{covers_dir}") return end Common.log_action('生成されたカバー画像を削除中...') deleted_count = 0 # PDF / JPG はすべて生成物として削除 %w[*.pdf *.jpg].each do |pattern| Dir.glob(File.join(covers_dir, pattern)).each do |file_path| next unless File.file?(file_path) FileUtils.rm_f(file_path) Common.log_info(" 削除: #{File.basename(file_path)}") deleted_count += 1 end end # SVG は bundled テンプレートから生成されたもの(light/dark)と # プレースホルダー適用済み中間ファイル(*_rendered.svg)のみ削除 # 利用者が用意した SVG(floral.svg 等)は保持する bundled_themes = %w[light dark] Dir.glob(File.join(covers_dir, '*.svg')).each do |file_path| next unless File.file?(file_path) basename = File.basename(file_path, '.svg') # 例: frontcover_dark # *_light.svg / *_dark.svg → bundled テンプレートからの生成物 is_bundled_generated = bundled_themes.any? { |t| basename.end_with?("_#{t}") } # *_rendered.svg → apply_text_placeholders_to_svg の中間ファイル is_rendered = basename.end_with?('_rendered') next unless is_bundled_generated || is_rendered FileUtils.rm_f(file_path) Common.log_info(" 削除: #{File.basename(file_path)}") deleted_count += 1 end if deleted_count.zero? Common.log_info('削除対象のカバー画像はありませんでした') else Common.log_success("カバー画像を削除しました(#{deleted_count}ファイル)") end end |
.clean_index_dictionaries ⇒ void
This method returns an undefined value.
索引・用語集辞書データを削除する(確認プロンプトあり)
削除対象:
- config/index_glossary_terms.yml(登録済み用語)
- config/index_glossary_rejected.yml(除外用語)
274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 |
# File 'lib/vivlio/starter/cli/clean.rb', line 274 def clean_index_dictionaries targets = [ File.join('config', 'index_glossary_terms.yml'), File.join('config', 'index_glossary_rejected.yml') ].select { |f| File.exist?(f) } if targets.empty? Common.log_info('削除対象の索引辞書ファイルはありませんでした') return end Common.log_always('⚠️ 以下の索引・用語集辞書データを削除しようとしています:') targets.each { |f| Common.log_always(" - #{f}") } Common.log_always('これらのファイルには著者が登録した用語データが含まれています。') $stdout.print('本当に削除しますか? [y/N]: ') ans = $stdin.gets unless ans && ans.strip.downcase == 'y' Common.log_info('索引辞書データの削除をキャンセルしました') return end targets.each do |f| FileUtils.rm_f(f) Common.log_success("削除しました: #{f}") end end |
.execute_clean(option_hash) ⇒ void
This method returns an undefined value.
クリーンアップ処理のエントリーポイント
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/vivlio/starter/cli/clean.rb', line 66 def execute_clean(option_hash) opts = option_hash || {} # --all は他のすべてのオプションを暗黙的に有効化する(--index-dictionaries は除く) all_mode = opts[:all] cover_requested = opts[:cover] || all_mode cache_requested = opts[:cache] || all_mode purge_requested = opts[:purge] || all_mode variant_cleanup_requested = opts[:generated_images] || all_mode index_dictionaries_requested = opts[:index_dictionaries] # --all には含めない # カバー画像の削除(マスター画像は保持) clean_cover_files if cover_requested # テーマ用の生成済みバリアント画像を削除 clean_bundled_variant_images if variant_cleanup_requested # 索引・用語集辞書データの削除(確認あり) clean_index_dictionaries if index_dictionaries_requested if cache_requested begin dir = begin Common.cache_dir rescue StandardError '.cache/vs' end if dir.nil? || dir.to_s.strip.empty? Common.log_warn('キャッシュディレクトリが不明のため中止します') return end if File.directory?(dir) Common.log_action("キャッシュディレクトリを削除中: #{dir}") FileUtils.rm_rf(dir) Common.log_success('キャッシュ削除が完了しました') else Common.log_info("キャッシュディレクトリは存在しません: #{dir}") end # metrics キャッシュも削除 metrics_cache = File.join('.cache', 'metrics') if File.directory?(metrics_cache) Common.log_action("metrics キャッシュを削除中: #{metrics_cache}") FileUtils.rm_rf(metrics_cache) Common.log_info("#{metrics_cache} を削除しました") end # 索引のキャッシュも削除 index_cache = '_index_matches.yml' if File.exist?(index_cache) FileUtils.rm_f(index_cache) Common.log_info("#{index_cache} を削除しました") end # 索引ページもキャッシュ削除時に削除対象とする index_page = '_indexpage.html' if File.exist?(index_page) FileUtils.rm_f(index_page) Common.log_info("#{index_page} を削除しました") end if File.directory?('.vivliostyle') Common.log_action('.vivliostyle ディレクトリを削除中...') FileUtils.rm_rf('.vivliostyle') Common.log_info('.vivliostyle ディレクトリを削除しました') else Common.log_info('.vivliostyle ディレクトリは存在しません') end rescue StandardError => e Common.log_warn("clean --cache 実行中にエラー: #{e}") end end # --cache または --cover のみが指定された場合は通常のクリーン処理をスキップ # --purge が指定されている、またはオプションなしの場合は通常のクリーン処理を実行 if (cache_requested || cover_requested) && !purge_requested # --cache または --cover のみの場合はここで終了 return end # BuildHelpers.clean_generated_files! と等価の処理をここに実装 Common.log_action('.vivliostyle ディレクトリを削除中...') FileUtils.rm_rf('.vivliostyle') Common.log_action('生成ファイルを削除中...') cleanup_patterns = [ # HTML/JS 中間生成物 '*.html', 'entries.js', # 生成される一時/補助的な Markdown(任意) '_toc.md', # pre_process によりプロジェクトルートへ展開される章系の Markdown のみ削除対象に限定 # 例: 11-install.md など(任意の *.md やドキュメントは削除しない) '[0-9][0-9]-*.md', # 内部 basename 方式の特殊ページ '_titlepage.md', '_legalpage.md', '_colophon.md', '_indexpage.html', '_index_matches.yml', '_index_review.md', '_index_glossary_review.md', # 中扉(Part Title Page) '_part*.md', # EPUB 中間ファイル 'vivliostyle.config.epub.js', 'entries.epub.js' ] intermediate_pdfs = [ # 内部名ベースの中間PDF '_titlepage.pdf', '_legalpage.pdf', '_colophon.pdf', '_titlepage_legalpage.pdf', '_sections.pdf', '00-preface.pdf', '_toc.pdf', 'blank_page.pdf', 'blank_frontmatter_insert.pdf', 'output_tmp*.pdf', # 入稿用 PDF の中間ファイル(Step 13) '_titlepage_legalpage_print.pdf', '_sections_print.pdf', '_colophon_print.pdf', '_blank_before_colophon.pdf', 'output_print.pdf' ] cleanup_patterns.concat(intermediate_pdfs) final_pdfs = [ Common::CONFIG.dig('pdf', 'output_file') || 'output.pdf', Common::CONFIG.dig('pdf', 'output_file_compressed') || 'output_compressed.pdf' ].uniq # --purge 指定時は最終PDFも削除対象に含める if purge_requested cleanup_patterns.concat(final_pdfs) # 単章PDF(例: 11-install.pdf, 81-install.pdf など)も削除 # 既に個別に列挙している中間PDFと重複しても問題ない cleanup_patterns << '[0-9][0-9]-*.pdf' # 単章EPUB(例: 01-life.epub, 02-history.epub など)も削除 cleanup_patterns << '[0-9][0-9]-*.epub' # 動的ファイル名のPDFおよびEPUBも削除対象に追加 add_dynamic_filename_patterns(cleanup_patterns) end cleanup_patterns.each do |pattern| Dir.glob(pattern).each do |file| next if File.directory?(file) FileUtils.rm_f(file) Common.log_info("#{file} を削除しました") end end Common.log_success('不要ファイルの削除が完了しました') end |