Skip to content

Instantly share code, notes, and snippets.

@miau
Created April 27, 2011 21:00
Show Gist options
  • Select an option

  • Save miau/945203 to your computer and use it in GitHub Desktop.

Select an option

Save miau/945203 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
# 外部から送られたファイルをそれらしく SVN に取り込むスクリプト
#
# Windows での使用例
# set EDITOR=C:/sakura/sakura.exe
# ruby fetch_third_party_file.rb 201104027 current
# OS の判定処理
def windows?
RUBY_PLATFORM.downcase =~ /mswin(?!ce)|mingw|cygwin|bccwin/
end
# 文字コード変換を簡単に行うためのヘルパメソッド
#
# 基本的に UTF-8 で統一したいが、ファイルシステムとのやりとりは Shift_JIS なので。
# "あいう".sjis で Shift_JIS に、"あいう".utf8 で UTF-8 に変換する
require 'nkf'
class String
def sjis; NKF.nkf('-Ws', self); end
def utf8; NKF.nkf('-Sw', self); end
def decode_sys; windows? ? self.utf8 : self; end
def encode_sys; windows? ? self.sjis : self; end
end
# windows の場合は Shift_JIS に変換してから stdout に出力する
if windows?
class StdoutHook
def write(str)
STDOUT.write str.to_s.sjis
end
$> = new
end
end
# ファイル名確認のためにエディタを起動する
def prompt_files(files_txt, from_files, svn_files, to_files)
# ファイルの一覧を作成
File.open(files_txt, "wb") {|f|
f.write to_files.map{|file| "#{file}\n"}
f.puts "#"
f.puts "# ↓元ファイルの一覧です。この順で格納先のファイル名を記載してください。"
f.puts "#  「#」で始まる行は無視されます。"
f.puts "#"
f.write from_files.map{|file| "# #{file}\n"}
f.puts "#"
f.puts "# ↓SVN ディレクトリのファイル一覧です。参考にしてください。"
f.puts "#"
f.write svn_files.map{|file| "# #{file}\n"}
}
# エディタを起動してユーザに編集してもらう
system $editor, files_txt
# 編集後のファイルを読み込む
to_files = nil
File.open(files_txt, "rb") {|f|
to_files = f.readlines.reject{|line| line.match(/^#/)}.map{|line| line.chomp}
}
# 内容が変更されていない場合はエディタの起動に失敗したとみなして警告表示して終了
if to_files == from_files
puts "ファイルが変更されていません。"
puts "・環境変数 EDITOR が正しく設定されていることを確認してください。(EDITOR: #{ENV['EDITOR']})"
puts "・ファイル編集完了までブロックしないエディタを利用している場合は、エディタの設定を変更してください。"
exit
end
to_files
end
# ファイルの移動詳細を表示し、ユーザに確認を求める
def prompt_changes(from_files, to_files)
from_files.zip(to_files) do|from, to|
puts from
if File.exist?(to.encode_sys)
# 既存ファイルの編集
unless File.file?(to.encode_sys)
puts "移動先がファイルではありません。再度編集してください。"
puts "\tFrom(#{File.ftype(from.encode_sys)}): #{from}"
puts "\tTo(#{File.ftype(to.encode_sys)}): #{to}"
return false
end
puts " [Edit] #{to}"
else
puts " [Add] #{to}"
end
end
input = ""
until input.match(/^[yn]/i)
puts "\n変更内容に間違いはありませんか?([Add] は新規ファイル、[Edit] は既存ファイル)"
print "[y/n]: "
input = STDIN.gets
end
return input.match(/^[Yy]/)
end
# SVN 作業ディレクトリの更新
def update_svn_files(from_files, to_files)
from_files.zip(to_files) do|from, to|
puts from
# 格納先のディレクトリを作成しておく
dirname = File.dirname(to)
FileUtils.mkdir_p dirname.encode_sys
# ファイルのコピー
FileUtils.copy(from.encode_sys, to.encode_sys)
# svn add も実行しておく
system("svn", "add", "--parents", to.encode_sys) or print "svn add failed: #{to}"
end
end
# 元ディレクトリの更新
def update_from_files(from_files, to_files)
added = {} # svn add を実行したディレクトリを記憶するためのハッシュ
from_files.zip(to_files) do|from, to|
puts to
# 格納先のディレクトリを作成しておく
dirname = File.dirname(from)
FileUtils.mkdir_p dirname.encode_sys
# ディレクトリを svn add しておく
unless added.has_key?(dirname)
system("svn", "add", "--parents", "--depth=empty", dirname.encode_sys) or print "svn add failed: #{dirname}"
added[dirname] = true
end
# コピー先にファイルがあると失敗するので削除しておく
File.unlink(from.encode_sys)
# svn copy でファイルをリネーム&コピー
system("svn", "copy", to.encode_sys, from.encode_sys) or print "svn copy failed: #{to} => #{from}"
end
end
# メイン処理
require "fileutils"
# autoflush 設定
STDOUT.sync = true
# 使用するエディタの設定
$editor = ENV["EDITOR"]
if $editor.nil?
puts "ファイル一覧の編集に使うエディタのパスを環境変数 EDITOR を設定してください。"
exit
end
# 引数のチェック
if ARGV.length != 2
print "usage: #{$0} <directory_to_import> <svn_base_directory>"
exit
end
from_dir, svn_dir = ARGV.map{|arg| arg.decode_sys}
# 元ファイルのディレクトリ、SVN ディレクトリのファイル一覧を取得
from_files = Dir.glob("#{from_dir.encode_sys}/**/*").select{|file| File.file?(file) }.map{|file| file.decode_sys }
svn_files = Dir.glob("#{svn_dir.encode_sys}/**/*").select{|file| File.file?(file) }.map{|file| file.decode_sys }
svn_files = [svn_dir] if svn_files.empty?
# 編集後のファイル。ひとまず元ファイル名を入れておく
to_files = from_files
# ファイル名の編集に利用する一時ファイル
files_txt = "_fetch_third_party_files.txt";
loop do
# ユーザ入力の取得
to_files = prompt_files(files_txt, from_files, svn_files, to_files)
# 内容が不正な場合はやり直し
if to_files.length != from_files.length
puts "ファイル数が異なっています。再度編集してください。"
elsif prompt_changes(from_files, to_files)
# ユーザ確認が OK だった場合のみループをぬける
break
end
end
# SVN 作業ディレクトリの更新
update_svn_files(from_files, to_files)
puts "#{svn_dir} が更新されました。問題なければ svn commit を実行してください。"
puts "svn commit が完了したら Enter を押下してください。引き続き #{from_dir} の更新が行われます。"
input = STDIN.gets
# 元ディレクトリの更新
update_from_files(from_files, to_files)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment