lib/command/diff.rb in narou-1.7.1 vs lib/command/diff.rb in narou-1.7.2

- old
+ new

@@ -1,280 +1,280 @@ -# -*- coding: utf-8 -*- -# -# Copyright 2013 whiteleaf. All rights reserved. -# - -require "yaml" -require "tempfile" -require "open3" -require_relative "../downloader" -require_relative "../database" -require_relative "../template" -require_relative "../inventory" -require_relative "../helper" - -module Command - class Diff < CommandBase - def self.oneline_help - "更新された小説の差分を表示します" - end - - def initialize - super("[<target>] [options]") - @opt.separator <<-EOS - - ・指定した小説の更新前後の変更点の差分を表示します。 - ・対象小説を指定しなかった場合は直前に更新した小説の差分を表示します。 - ・もし自分の好きな差分表示プログラムを使いたい場合、difftoolを設定して変更することが出来ます(下記参照) - - Examples: - narou diff # 直前に更新した小説の差分を表示 - narou diff 6 - narou diff 6 -n 2 # 最新から2番目の差分との比較 - narou diff 6 -2 # -n 2 の省略した記述方法 - narou diff 6 2013.02.21@01.39.46 # 差分を直接指定 - narou diff 6 -l # 過去にどの話数の差分があるのかを確認 - - # 自分の好きな差分表示プログラムを使う場合 - narou s difftool="C:\\Program Files\\WinMerge\\WinMergeU.exe" - narou s difftool=colordiff # コマンドラインツールを指定したり - # Narou.rbオリジナルの差分表示に戻す場合は設定を削除する - narou s difftool= - - # difftoolに渡す引数(指定しなければ単純に新旧ファイルを引数に呼び出す) - # 特殊な変数 %NEW : 最新データの差分用ファイルパス - # %OLD : 古い方の差分用ファイルパス - narou s difftool.arg='-e -x -ub -dl "OLD" -dr "NEW" %OLD %NEW' - narou s difftool.arg="-u %OLD %NEW" - - Options: - EOS - - @opt.on("-n NUM", "--number", "比較する差分を遡って指定する。最新のアップデートと直前のデータを比較するなら-n 1、2個前のアップデートなら-n 2。(デフォルトは-n 1)", Integer) { |number| - @options["number"] = number if number > 1 - } - @opt.on("-l", "--list", "指定した小説の差分一覧を表示する") { - @options["list"] = true - } - @opt.on("-c", "--clean", "指定した小説の差分データを全て削除する") { - @options["clean"] = true - } - @opt.on("--all-clean", "凍結済を除く全小説の差分データを削除する") { - @options["all-clean"] = true - } - end - - # 引数の中の -数字 オプション(-n 数字の省略形)を -n 数字 に変換する - def short_number_option_parse(argv) - argv.map! { |arg| - if arg =~ /^-(\d+)$/ - ["-n", $1.to_s] - else - arg - end - }.flatten! - end - - def execute(argv) - short_number_option_parse(argv) - super - @options["number"] = 1 unless @options["number"] - if argv.empty? - latest = Database.instance.sort_by_last_update.first - return unless latest - id = latest["id"] - else - target = argv.shift - id = Downloader.get_id_by_target(target) - end - unless id - error "#{target} は存在しません" - return - end - view_diff_version = argv.shift - if view_diff_version - if invalid_diff_version_string?(view_diff_version) - error "差分指定の書式が違います(正しい例:2013.02.21@01.39.46)" - return - end - @options["view_diff_version"] = view_diff_version - end - if @options["list"] - display_diff_list(id) - return - end - if @options["clean"] - clean_diff(id) - return - end - if @options["all-clean"] - clean_all_diff - return - end - @difftool = Inventory.load("global_setting", :global)["difftool"] - unless @difftool - display_diff_on_oneself(id) - return - #error "difftool が設定されていません。narou setting で difftool を設定して下さい" - #return - end - exec_difftool(id) - end - - def invalid_diff_version_string?(str) - str !~ /^\d{4}\.\d{2}\.\d{2}@\d{2}[;.]\d{2}[;.]\d{2}$/ - end - - def clean_diff(id) - cache_root_dir = Downloader.get_cache_root_dir(id) - print Database.instance.get_data("id", id)["title"] + " の" - unless File.exist?(cache_root_dir) - puts "差分はひとつもありません" - return - end - FileUtils.remove_entry_secure(cache_root_dir) - puts "差分を削除しました" - end - - def exec_difftool(id) - temp_paths = create_temp_files(id) or return - diff_cmd = create_difftool_command_string(*temp_paths.map { |temp| - path = temp.path - if Helper.os_windows? - path.encode!(Encoding::Windows_31J) - end - %!"#{path}"! - }) - begin - res = Helper::AsyncCommand.exec(diff_cmd) - rescue Errno::ENOENT => e - error e.message - exit 1 - ensure - temp_paths.map(&:delete) - end - puts res[0] unless res[0].empty? - error res[1] unless res[1].empty? - end - - def create_difftool_command_string(temp_old_path, temp_new_path) - diff_arg = Inventory.load("global_setting", :global)["difftool.arg"] - diff_cmd = %!"#{@difftool}" ! - if diff_arg - diff_arg.gsub!("%OLD", temp_old_path) - diff_arg.gsub!("%NEW", temp_new_path) - diff_cmd += diff_arg - else - diff_cmd += [temp_old_path, temp_new_path].join(" ") - end - diff_cmd - end - - def get_sorted_cache_list(id) - list = Downloader.get_cache_list(id) or return nil - list.sort_by { |v| File.basename(v) }.reverse - end - - def create_temp_files(id) - if @options["view_diff_version"] - cache_root_dir = Downloader.get_cache_root_dir(id) - if cache_root_dir - cache_dir = File.join(cache_root_dir, @options["view_diff_version"]) - cache_dir = nil unless File.exist?(cache_dir) - end - else - nth = @options["number"] - list = get_sorted_cache_list(id) - cache_dir = list ? list[nth - 1] : nil - end - unless cache_dir - puts "差分データがありません" - return nil - end - cache_section_list = Dir.glob("#{cache_dir}/*.yaml").sort_by { |path| - File.basename(path, ".yaml").split(" ", 2)[0].to_i - } - if cache_section_list.length == 0 - puts "最新話のみのアップデートのようです" - return nil - end - novel_dir = Downloader.get_novel_section_save_dir(Downloader.get_novel_data_dir_by_target(id)) - latest_novel_sections = [] - cache_sections = [] - cache_section_list.each do |path| - match_latest_path = File.join(novel_dir, File.basename(path)) - latest_novel_sections << YAML.load_file(match_latest_path) if File.exist?(match_latest_path) - cache_sections << YAML.load_file(path) - end - - novel_info = Database.instance[id] - temp_old = create_temp_by_sections("old", cache_sections, novel_info) - temp_new = create_temp_by_sections("new", latest_novel_sections, novel_info) - - [temp_old, temp_new] - end - - def create_temp_by_sections(temp_prefix, sections, novel_info) - html = HTML.new - sections.each do |section| - element = section["element"] - data_type = element.delete("data_type") || "text" - element.each do |text_type, elm_text| - if data_type == "html" - html.string = elm_text - element[text_type] = html.to_aozora - end - end - end - temp = Tempfile.open([temp_prefix, ".txt"]) - temp.write(Template.get("diff.txt", binding)) - temp.close - temp - end - - def display_diff_list(id) - cache_list = get_sorted_cache_list(id) - print Database.instance.get_data("id", id)["title"] + " の" - if cache_list.empty? - puts "差分はひとつもありません" - return - end - puts "差分一覧" - cache_list.each.with_index(1) do |cache_path, i| - puts "<bold><yellow>#{File.basename(cache_path)} -#{i}</yellow></bold>".termcolor - cache_section_list = Dir.glob(File.join(cache_path, "*.yaml")) - if cache_section_list.length > 0 - cache_section_list.map { |section_path| - File.basename(section_path, ".yaml").split(" ", 2) - }.sort_by { |v| v[0].to_i }.each { |index, subtitle| - puts " 第#{index}部分 #{subtitle}" - } - else - puts " (最新話のみのアップデート)" - end - end - end - - def clean_all_diff - Database.instance.each do |id, data| - next if Narou.novel_frozen?(id) - cache_root_dir = Downloader.get_cache_root_dir(id) - next unless File.exist?(cache_root_dir) - FileUtils.remove_entry_secure(cache_root_dir) - puts "#{data["title"]} の差分を削除しました" - end - end - - # - # diff-lcs を使って自力で差分表示 - # - def display_diff_on_oneself(id) - require_relative "../diffviewer" - temp_paths = create_temp_files(id) or return - title = Database.instance.get_data("id", id)["title"] - puts "#{title} の差分を表示します" - DiffViewer.new(*temp_paths).view - ensure - temp_paths.map(&:delete) if temp_paths - end - end -end +# -*- coding: utf-8 -*- +# +# Copyright 2013 whiteleaf. All rights reserved. +# + +require "yaml" +require "tempfile" +require "open3" +require_relative "../downloader" +require_relative "../database" +require_relative "../template" +require_relative "../inventory" +require_relative "../helper" + +module Command + class Diff < CommandBase + def self.oneline_help + "更新された小説の差分を表示します" + end + + def initialize + super("[<target>] [options]") + @opt.separator <<-EOS + + ・指定した小説の更新前後の変更点の差分を表示します。 + ・対象小説を指定しなかった場合は直前に更新した小説の差分を表示します。 + ・もし自分の好きな差分表示プログラムを使いたい場合、difftoolを設定して変更することが出来ます(下記参照) + + Examples: + narou diff # 直前に更新した小説の差分を表示 + narou diff 6 + narou diff 6 -n 2 # 最新から2番目の差分との比較 + narou diff 6 -2 # -n 2 の省略した記述方法 + narou diff 6 2013.02.21@01.39.46 # 差分を直接指定 + narou diff 6 -l # 過去にどの話数の差分があるのかを確認 + + # 自分の好きな差分表示プログラムを使う場合 + narou s difftool="C:\\Program Files\\WinMerge\\WinMergeU.exe" + narou s difftool=colordiff # コマンドラインツールを指定したり + # Narou.rbオリジナルの差分表示に戻す場合は設定を削除する + narou s difftool= + + # difftoolに渡す引数(指定しなければ単純に新旧ファイルを引数に呼び出す) + # 特殊な変数 %NEW : 最新データの差分用ファイルパス + # %OLD : 古い方の差分用ファイルパス + narou s difftool.arg='-e -x -ub -dl "OLD" -dr "NEW" %OLD %NEW' + narou s difftool.arg="-u %OLD %NEW" + + Options: + EOS + + @opt.on("-n NUM", "--number", "比較する差分を遡って指定する。最新のアップデートと直前のデータを比較するなら-n 1、2個前のアップデートなら-n 2。(デフォルトは-n 1)", Integer) { |number| + @options["number"] = number if number > 1 + } + @opt.on("-l", "--list", "指定した小説の差分一覧を表示する") { + @options["list"] = true + } + @opt.on("-c", "--clean", "指定した小説の差分データを全て削除する") { + @options["clean"] = true + } + @opt.on("--all-clean", "凍結済を除く全小説の差分データを削除する") { + @options["all-clean"] = true + } + end + + # 引数の中の -数字 オプション(-n 数字の省略形)を -n 数字 に変換する + def short_number_option_parse(argv) + argv.map! { |arg| + if arg =~ /^-(\d+)$/ + ["-n", $1.to_s] + else + arg + end + }.flatten! + end + + def execute(argv) + short_number_option_parse(argv) + super + @options["number"] = 1 unless @options["number"] + if argv.empty? + latest = Database.instance.sort_by_last_update.first + return unless latest + id = latest["id"] + else + target = argv.shift + id = Downloader.get_id_by_target(target) + end + unless id + error "#{target} は存在しません" + return + end + view_diff_version = argv.shift + if view_diff_version + if invalid_diff_version_string?(view_diff_version) + error "差分指定の書式が違います(正しい例:2013.02.21@01.39.46)" + return + end + @options["view_diff_version"] = view_diff_version + end + if @options["list"] + display_diff_list(id) + return + end + if @options["clean"] + clean_diff(id) + return + end + if @options["all-clean"] + clean_all_diff + return + end + @difftool = Inventory.load("global_setting", :global)["difftool"] + unless @difftool + display_diff_on_oneself(id) + return + #error "difftool が設定されていません。narou setting で difftool を設定して下さい" + #return + end + exec_difftool(id) + end + + def invalid_diff_version_string?(str) + str !~ /^\d{4}\.\d{2}\.\d{2}@\d{2}[;.]\d{2}[;.]\d{2}$/ + end + + def clean_diff(id) + cache_root_dir = Downloader.get_cache_root_dir(id) + print Database.instance.get_data("id", id)["title"] + " の" + unless File.exist?(cache_root_dir) + puts "差分はひとつもありません" + return + end + FileUtils.remove_entry_secure(cache_root_dir) + puts "差分を削除しました" + end + + def exec_difftool(id) + temp_paths = create_temp_files(id) or return + diff_cmd = create_difftool_command_string(*temp_paths.map { |temp| + path = temp.path + if Helper.os_windows? + path.encode!(Encoding::Windows_31J) + end + %!"#{path}"! + }) + begin + res = Helper::AsyncCommand.exec(diff_cmd) + rescue Errno::ENOENT => e + error e.message + exit 1 + ensure + temp_paths.map(&:delete) + end + puts res[0] unless res[0].empty? + error res[1] unless res[1].empty? + end + + def create_difftool_command_string(temp_old_path, temp_new_path) + diff_arg = Inventory.load("global_setting", :global)["difftool.arg"] + diff_cmd = %!"#{@difftool}" ! + if diff_arg + diff_arg.gsub!("%OLD", temp_old_path) + diff_arg.gsub!("%NEW", temp_new_path) + diff_cmd += diff_arg + else + diff_cmd += [temp_old_path, temp_new_path].join(" ") + end + diff_cmd + end + + def get_sorted_cache_list(id) + list = Downloader.get_cache_list(id) or return nil + list.sort_by { |v| File.basename(v) }.reverse + end + + def create_temp_files(id) + if @options["view_diff_version"] + cache_root_dir = Downloader.get_cache_root_dir(id) + if cache_root_dir + cache_dir = File.join(cache_root_dir, @options["view_diff_version"]) + cache_dir = nil unless File.exist?(cache_dir) + end + else + nth = @options["number"] + list = get_sorted_cache_list(id) + cache_dir = list ? list[nth - 1] : nil + end + unless cache_dir + puts "差分データがありません" + return nil + end + cache_section_list = Dir.glob("#{cache_dir}/*.yaml").sort_by { |path| + File.basename(path, ".yaml").split(" ", 2)[0].to_i + } + if cache_section_list.length == 0 + puts "最新話のみのアップデートのようです" + return nil + end + novel_dir = Downloader.get_novel_section_save_dir(Downloader.get_novel_data_dir_by_target(id)) + latest_novel_sections = [] + cache_sections = [] + cache_section_list.each do |path| + match_latest_path = File.join(novel_dir, File.basename(path)) + latest_novel_sections << YAML.load_file(match_latest_path) if File.exist?(match_latest_path) + cache_sections << YAML.load_file(path) + end + + novel_info = Database.instance[id] + temp_old = create_temp_by_sections("old", cache_sections, novel_info) + temp_new = create_temp_by_sections("new", latest_novel_sections, novel_info) + + [temp_old, temp_new] + end + + def create_temp_by_sections(temp_prefix, sections, novel_info) + html = HTML.new + sections.each do |section| + element = section["element"] + data_type = element.delete("data_type") || "text" + element.each do |text_type, elm_text| + if data_type == "html" + html.string = elm_text + element[text_type] = html.to_aozora + end + end + end + temp = Tempfile.open([temp_prefix, ".txt"]) + temp.write(Template.get("diff.txt", binding)) + temp.close + temp + end + + def display_diff_list(id) + cache_list = get_sorted_cache_list(id) + print Database.instance.get_data("id", id)["title"] + " の" + if cache_list.empty? + puts "差分はひとつもありません" + return + end + puts "差分一覧" + cache_list.each.with_index(1) do |cache_path, i| + puts "<bold><yellow>#{File.basename(cache_path)} -#{i}</yellow></bold>".termcolor + cache_section_list = Dir.glob(File.join(cache_path, "*.yaml")) + if cache_section_list.length > 0 + cache_section_list.map { |section_path| + File.basename(section_path, ".yaml").split(" ", 2) + }.sort_by { |v| v[0].to_i }.each { |index, subtitle| + puts " 第#{index}部分 #{subtitle}" + } + else + puts " (最新話のみのアップデート)" + end + end + end + + def clean_all_diff + Database.instance.each do |id, data| + next if Narou.novel_frozen?(id) + cache_root_dir = Downloader.get_cache_root_dir(id) + next unless File.exist?(cache_root_dir) + FileUtils.remove_entry_secure(cache_root_dir) + puts "#{data["title"]} の差分を削除しました" + end + end + + # + # diff-lcs を使って自力で差分表示 + # + def display_diff_on_oneself(id) + require_relative "../diffviewer" + temp_paths = create_temp_files(id) or return + title = Database.instance.get_data("id", id)["title"] + puts "#{title} の差分を表示します" + DiffViewer.new(*temp_paths).view + ensure + temp_paths.map(&:delete) if temp_paths + end + end +end