Skip to content
Browse files

Merge branch 'develop'

  • Loading branch information...
2 parents 0bbed84 + 4e92c06 commit cf99cbf803730395ee019c60f85aabf7d1c2535f @ongaeshi committed
View
23 HISTORY.ja.rdoc
@@ -1,3 +1,26 @@
+=== 0.9.3 2012/10/06
+
+* milk web
+ * Webインターフェースからのアップデートに対応
+
+* milk info
+ * ファイル数、行数、breakdown(種類別) 表示
+ * テーブル形式で表示 (-t)
+ * 全てのパッケージを表示 (-a)
+ * 種類別詳細表示 (-b)
+
+* milk
+ * milk plugins: add Milkode_Sublime
+ * milk add: --no-auto-ignore の短縮形 -n を追加
+
+* database
+ * Add Updater
+ * IgnoreChecker の require忘れ
+
+* common
+ * grenfiletest.rb: Add ignore suffix
+ * Add PlgnDetector
+
=== 0.9.2 2012/09/07
* etc
View
20 HISTORY.rdoc
@@ -1,3 +1,23 @@
+=== 0.9.3 2012/10/06
+
+* milk web
+ * Update from web interface
+
+* milk info
+ * file_count, line_count, breakdown
+ * -a(--all), -t(--table), -b(--breakdown)
+
+* milk
+ * milk plugins: add Milkode_Sublime
+ * milk add: add -n(--no-auto-ignore)
+
+* database
+ * Add Updater
+
+* common
+ * grenfiletest.rb: Add ignore suffix
+ * Add PlgnDetector
+
=== 0.9.2 2012/09/07
* etc
View
2 VERSION
@@ -1 +1 @@
-0.9.2
+0.9.3
View
2 bin/gmilk
@@ -6,5 +6,5 @@
require 'rubygems'
require 'milkode/grep/cli_grep'
-Version = "0.9.2"
+Version = "0.9.3"
Milkode::CLI_Grep.execute(STDOUT, ARGV)
View
2 bin/milk
@@ -6,5 +6,5 @@
require 'rubygems'
require 'milkode/cli'
-Version = "0.9.2"
+Version = "0.9.3"
Milkode::CLI.start(ARGV)
View
375 lib/milkode/cdstk/cdstk.rb
@@ -23,6 +23,8 @@
require 'milkode/database/groonga_database'
require 'milkode/database/document_record'
require 'milkode/common/array_diff'
+require 'milkode/database/updater'
+require 'milkode/common/plang_detector'
module Milkode
class IgnoreError < RuntimeError ; end
@@ -386,11 +388,12 @@ def list(args, options)
@out.puts str
- # print information
- if args.empty?
- milkode_info
- else
- list_info(match_p) unless match_p.empty?
+ if Util.pipe? $stdout
+ if args.empty?
+ milkode_info
+ else
+ list_info(match_p) unless match_p.empty?
+ end
end
end
@@ -638,8 +641,207 @@ def mcd(options)
end
end
- def info
- milkode_info
+ def info(args, options)
+ db_open
+
+ if options[:all]
+ info_format(@yaml.contents, select_format(options, :table))
+ milkode_info
+ return
+ end
+
+ packages = find_packages(args)
+ packages.compact!
+ return if (packages.empty?)
+
+ info_format(packages, select_format(options, :detail))
+ end
+
+ def select_format(options, default_value)
+ format = default_value
+ format = :detail if options[:detail]
+ format = :table if options[:table]
+ format = :breakdown if options[:breakdown]
+ format = :unknown if options[:unknown]
+ format
+ end
+
+ def info_format(packages, format)
+ case format
+ when :detail
+ info_format_detail(packages)
+ when :table
+ info_format_table(packages)
+ when :breakdown
+ info_format_breakdown(packages)
+ when :unknown
+ info_format_unknown(packages)
+ end
+ end
+
+ def info_format_detail(packages)
+ packages.each_with_index do |package, index|
+ records = package_records(package.name)
+
+ r = []
+ r.push "Name: #{package.name}"
+ r.push "Ignore: #{package.ignore}" unless package.ignore.empty?
+ r.push "Options: #{package.options}" unless package.options.empty?
+ r.push "Records: #{records.size}"
+ r.push "Breakdown: #{breakdown_shorten(records)}"
+ r.push "Linecount: #{linecount_total(records)}"
+ r.push ""
+
+ @out.puts if index != 0
+ @out.puts r.join("\n")
+ end
+ end
+
+ NAME = 'Name'
+ TOTAL = 'Total'
+
+ def info_format_table(packages)
+ max = packages.map{|p| p.name.length}.max
+ max = NAME.length if max < NAME.length
+
+ @out.puts <<EOF.chomp
+#{NAME.ljust(max)} Records Linecount
+#{'=' * max}========================
+EOF
+
+ packages.each do |package|
+ records = package_records(package.name)
+ @out.puts "#{package.name.ljust(max)} #{records.size.to_s.rjust(10)} #{linecount_total(records).to_s.rjust(10)}"
+ end
+ end
+
+ def info_format_breakdown(packages)
+ packages.each_with_index do |package, index|
+ records = package_records(package.name)
+ plangs = sorted_plangs(records)
+
+ # column1's width
+ plang_names = plangs.map{|v| v[0]}
+ max = (plang_names + [package.name, TOTAL]).map{|name| name.length}.max
+
+ @out.puts if index != 0
+ @out.puts <<EOF.chomp
+#{package.name.ljust(max)} files rate
+#{'=' * max}=============
+#{breakdown_detail(package_records(package.name), max)}
+#{'-' * max}-------------
+#{sprintf("%-#{max}s %5d %3d%%", TOTAL, records.size, 100)}
+EOF
+ end
+ end
+
+ def info_format_unknown(packages)
+ packages.each_with_index do |package, index|
+ @out.puts if index != 0
+
+ package_records(package.name).each do |record|
+ path = record.restpath
+ @out.puts path if PlangDetector.new(path).unknown?
+ end
+ end
+ end
+
+ def package_records(name)
+ @documents.search(:strict_packages => [name])
+ end
+
+ def linecount_total(records)
+ records.reduce(0) do |total, record|
+ begin
+ unless record.content.nil?
+ total + record.content.count($/) + 1
+ else
+ total
+ end
+ rescue ArgumentError
+ warning_alert("invalid byte sequence : #{record.path}")
+ total
+ end
+ end
+ end
+
+ def sorted_plangs(records)
+ total = {}
+
+ records.each do |record|
+ lang = PlangDetector.new(record.restpath)
+
+ if total[lang.name]
+ total[lang.name] += 1
+ else
+ total[lang.name] = 1
+ end
+ end
+
+ total.map {|name, count|
+ [name, count]
+ }.sort {|a, b|
+ if (a[0] == PlangDetector::UNKNOWN)
+ -1
+ elsif (b[0] == PlangDetector::UNKNOWN)
+ 1
+ else
+ a[1] <=> b[1]
+ end
+ }.reverse
+ end
+
+ def calc_percent(count, size)
+ (count.to_f / size * 100).to_i
+ end
+
+ def breakdown_shorten(records)
+ plangs = sorted_plangs(records)
+
+ plangs = plangs.reduce([]) {|array, plang|
+ name, count = plang
+ percent = calc_percent(count, records.size)
+
+ if percent == 0
+ if array.empty? || array[-1][0] != 'other'
+ array << ['other', count]
+ else
+ array[-1][1] += count
+ end
+ else
+ array << plang
+ end
+
+ array
+ }
+
+ plangs.map {|name, count|
+ percent = calc_percent(count, records.size)
+ "#{name}:#{count}(#{percent}%)"
+ }.join(', ')
+ end
+
+ def breakdown_detail(records, name_width)
+ sorted_plangs(records).map {|name, count|
+ percent = (count.to_f / records.size * 100).to_i
+ sprintf("%-#{name_width}s %5d %3d%%", name, count, percent)
+ }.join("\n")
+ end
+
+ # 引数が指定されている時は名前にマッチするパッケージを、未指定の時は現在位置から見つける
+ def find_packages(args)
+ unless args.empty?
+ args.map do |v|
+ r = @yaml.find_name(v)
+ @out.puts "Not found package '#{v}'." if r.nil?
+ r
+ end
+ else
+ dir = File.expand_path('.')
+ r = @yaml.package_root(dir)
+ @out.puts "Not registered '#{dir}'." if r.nil?
+ [r]
+ end
end
def ignore(args, options)
@@ -697,6 +899,19 @@ def ignore(args, options)
end
end
+ def files(args)
+ packages = find_packages(args)
+ return if (packages.empty?)
+
+ db_open
+
+ packages.each do |package|
+ package_records(package.name).each do |record|
+ @out.puts record.restpath
+ end
+ end
+ end
+
private
def db_file
@@ -712,37 +927,38 @@ def yaml_file
end
def update_package_in(package, options)
- if package.options[:update_with_git_pull]
- Dir.chdir(package.directory) { system("git pull") }
- end
-
- unless options[:no_clean]
- cleanup_package_in(package)
- end
-
- update_dir_in(package.directory)
- end
-
- def cleanup_package_in(package)
- db_open
- @documents.cleanup_package_name(package.name)
+ updater_exec(package, package.options[:update_with_git_pull], options[:no_clean])
end
def update_dir_in(dir)
- alert("package", File.basename(dir) )
- @package_count += 1
-
dir = File.expand_path(dir)
if (!FileTest.exist?(dir))
- @out.puts "[WARNING] : #{dir} (Not found, skip)"
- elsif (FileTest.directory? dir)
- db_add_dir(dir)
+ warning_alert("#{dir} (Not found, skip)")
else
- db_add_file(STDOUT, File.dirname(dir), File.basename(dir), File.basename(dir)) # .bashrc/.bashrc のようになる
+ package = @yaml.package_root(dir)
+ updater_exec(package, false, false)
end
end
+ def updater_exec(package, is_update_with_git_pull, is_no_clean)
+ alert("package", package.name )
+
+ updater = Updater.new(@grndb, package.name)
+ updater.set_package_ignore IgnoreSetting.new("/", package.ignore)
+ updater.enable_no_auto_ignore if package.options[:no_auto_ignore]
+ updater.enable_silent_mode if @is_silent
+ updater.enable_display_info if @is_display_info
+ updater.enable_update_with_git_pull if is_update_with_git_pull
+ updater.enable_no_clean if is_no_clean
+ updater.exec
+
+ @package_count += 1
+ @file_count += updater.result.file_count
+ @add_count += updater.result.add_count
+ @update_count += updater.result.update_count
+ end
+
def remove_dir(dir, no_yaml = false)
unless (no_yaml)
package = @yaml.find_dir(dir)
@@ -790,7 +1006,6 @@ def result_info
r << "#{@file_count} records" if @file_count > 0
r << "#{@add_count} add" if @add_count > 0
r << "#{@update_count} update" if @update_count > 0
- r.join(', ')
alert('result', "#{r.join(', ')}. (#{Gren::Util::time_s(time)})")
end
@@ -835,108 +1050,6 @@ def db_delete
end
end
- def db_add_dir(dir)
- @current_package = @yaml.package_root(dir)
- @current_ignore = IgnoreChecker.new
- @current_ignore.add IgnoreSetting.new("/", @current_package.ignore) # 手動設定
- searchDirectory(STDOUT, dir, @current_package.name, "/", 0)
- end
- private :db_add_dir
-
- def db_add_file(stdout, package_dir, restpath, package_name = nil)
- # サイレントモード
- return if @is_silent
-
- # データベースには先頭の'/'を抜いて登録する
- # 最初から'/'を抜いておけば高速化の余地あり?
- # ignore設定との互換性保持が必要
- restpath = restpath.sub(/^\//, "")
-
- # パッケージ名を設定
- package_name = package_name || File.basename(package_dir)
-
- # レコードの追加
- result = @documents.add(package_dir, restpath, package_name)
-
- # メッセージの表示
- case result
- when :newfile
- @add_count += 1
- alert_info("add_record", File.join(package_dir, restpath))
- when :update
- @grndb.packages.touch(package_name, :updatetime)
- @update_count += 1
- alert_info("update", File.join(package_dir, restpath))
- end
- end
-
- def searchDirectory(stdout, dirname, packname, path, depth)
- # 現在位置に.gitignoreがあれば無視設定に加える
- add_current_gitignore(dirname, path) unless @current_package.options[:no_auto_ignore]
-
- # 子の要素を追加
- Dir.foreach(File.join(dirname, path)) do |name|
- next if (name == '.' || name == '..')
-
- next_path = File.join(path, name)
- fpath = File.join(dirname, next_path)
- shortpath = File.join(packname, next_path)
-
- # 除外ディレクトリならばパス
- next if ignoreDir?(fpath, next_path)
-
- # 読み込み不可ならばパス
- next unless FileTest.readable?(fpath)
-
- # ファイルならば中身を探索、ディレクトリならば再帰
- case File.ftype(fpath)
- when "directory"
- searchDirectory(stdout, dirname, packname, next_path, depth + 1)
- when "file"
- unless ignoreFile?(fpath, next_path)
- db_add_file(stdout, dirname, next_path) # shortpathの先頭に'/'が付いているのが気になる
- @file_count += 1
- # @out.puts "file_count : #{@file_count}" if (@file_count % 100 == 0)
- end
- end
- end
- end
-
- def add_current_gitignore(dirname, path)
- git_ignore = File.join(dirname, path, ".gitignore")
-
- if File.exist? git_ignore
- alert_info("add_ignore", git_ignore)
-
- open(git_ignore) do |f|
- @current_ignore.add IgnoreSetting.create_from_gitignore(path, f.read)
- end
- end
- end
-
- def package_ignore?(fpath, mini_path)
- if @current_ignore.ignore?(mini_path)
- alert_info("ignore", fpath)
- true
- else
- false
- end
- end
-
- def ignoreDir?(fpath, mini_path)
- FileTest.directory?(fpath) &&
- (GrenFileTest::ignoreDir?(fpath) ||
- package_ignore?(fpath, mini_path))
- end
- private :ignoreDir?
-
- def ignoreFile?(fpath, mini_path)
- GrenFileTest::ignoreFile?(fpath) ||
- GrenFileTest::binary?(fpath) ||
- package_ignore?(fpath, mini_path)
- end
- private :ignoreFile?
-
def alert(title, msg)
if (Util::platform_win?)
@out.puts "#{title.ljust(10)} : #{Kconv.kconv(msg, Kconv::SJIS)}"
View
51 lib/milkode/cdweb/app.rb
@@ -22,7 +22,7 @@
get '/' do
@setting = WebSetting.new
- @version = "0.9.2"
+ @version = "0.9.3"
@package_num = Database.instance.yaml_package_num
@file_num = Database.instance.totalRecords
@package_list = PackageList.new(Database.instance.grndb)
@@ -62,6 +62,20 @@ def package_path(path)
end
end
+post '/command' do
+ case params[:kind]
+ when 'update'
+ before = Time.now
+ if (params[:name] == '')
+ result = Database.instance.update_all
+ update_result_str(result, before)
+ else
+ result = Database.instance.update(params[:name])
+ update_result_str(result, before)
+ end
+ end
+end
+
get '/home*' do |path|
before = Time.now
path = path.sub(/^\//, "")
@@ -158,11 +172,35 @@ def create_checkbox(name, value, label)
def create_headmenu(path, query, flistpath = '')
href = Mkurl.new('/home/' + path, params).inherit_query_shead
flist = File.join("/home/#{path}", flistpath)
+
+ package_name = ""
+ modal_body = "全てのパッケージを更新しますか?"
+
+ if (path != "")
+ package_name = path.split('/')[0]
+ modal_body = "#{package_name} を更新しますか?"
+ end
+
<<EOF
- #{headicon('go-home-5.png')} <a href="/home" class="headmenu">全てのパッケージ</a>
+ #{headicon('go-home-5.png')} <a href="/home" class="headmenu">ホーム</a>
#{headicon('document-new-4.png')} <a href="#{href}" class="headmenu" onclick="window.open('#{href}'); return false;">新しい検索</a>
#{headicon('directory.png')} <a href="#{flist}" class="headmenu">ディレクトリ</a>
+ #{headicon('view-refresh-4.png')} <a href="#updateModal" class="headmenu" data-toggle="modal">パッケージを更新</a>
#{headicon('help.png')} <a href="/help" class="headmenu">ヘルプ</a>
+
+ <div id="updateModal" class="modal hide fade">
+ <div class="modal-header">
+ <a href="#" class="close" data-dismiss="modal">&times;</a>
+ <h3>パッケージを更新</h3>
+ </div>
+ <div class="modal-body">
+ <h4>#{modal_body}</h4>
+ </div>
+ <div class="modal-footer">
+ <a href="#" id="updateCancel" class="btn" data-dismiss="modal">Cancel</a>
+ <a href="#" id="updateOk" class="btn btn-primary" data-loading-text="Updating..." milkode-package-name="#{package_name}"">OK</a>
+ </div>
+ </div>
EOF
end
@@ -224,6 +262,15 @@ def path_title(path)
def filelist_title(path)
(path == "") ? "Package List" : path
end
+
+ def update_result_str(result, before)
+ r = []
+ r << "#{result.package_count} packages" if result.package_count > 1
+ r << "#{result.file_count} records"
+ r << "#{result.add_count} add"
+ r << "#{result.update_count} update"
+ "#{r.join(', ')} (#{Time.now - before} sec)"
+ end
end
class Array
View
24 lib/milkode/cdweb/lib/database.rb
@@ -13,6 +13,7 @@
require 'milkode/cdstk/yaml_file_wrapper'
require 'milkode/database/groonga_database'
require 'milkode/common/util'
+require 'milkode/database/updater'
include Milkode
module Milkode
@@ -168,6 +169,20 @@ def touch_viewtime(path)
package, restpath = Util::divide_shortpath(path)
@grndb.packages.touch_if(package, :viewtime) if package
end
+
+ def update(name)
+ result = Updater::ResultAccumulator.new
+ result << update_in(yaml_load.find_name(name))
+ result
+ end
+
+ def update_all
+ result = Updater::ResultAccumulator.new
+ yaml_load.contents.each do |package|
+ result << update_in(package)
+ end
+ result
+ end
private
@@ -175,5 +190,14 @@ def yaml_load
YamlFileWrapper.load_if(Database.dbdir)
end
+ def update_in(package)
+ updater = Updater.new(@grndb, package.name)
+ updater.set_package_ignore IgnoreSetting.new("/", package.ignore)
+ updater.enable_no_auto_ignore if package.options[:no_auto_ignore]
+ updater.enable_update_with_git_pull if package.options[:update_with_git_pull]
+ updater.exec
+ updater.result
+ end
+
end
end
View
BIN lib/milkode/cdweb/public/images/view-refresh-4.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
BIN lib/milkode/cdweb/public/images/waiting.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
25 lib/milkode/cdweb/public/js/milkode.js
@@ -84,5 +84,30 @@ $(document).ready(function(){
selectedList: 1,
height: 350
}).multiselectfilter();
+
+ $("#updateOk").click(function (e) {
+ update_package($("#updateOk").attr("milkode-package-name"));
+ return false;
+ });
});
+function update_package(package_name)
+{
+ // click button
+ $("#updateModal .modal-body").html("<h4>更新中... <img src='/images/waiting.gif'/></h4>");
+ $("#updateCancel").addClass("hide");
+ $("#updateOk").button('loading').off('click');
+
+ // update end
+ $.post(
+ '/command',
+ {
+ kind: 'update',
+ name: package_name
+ },
+ function (data) {
+ $("#updateModal .modal-body").html("<h4>実行結果</h4>" + "<p>" + data + "</p>");
+ $("#updateOk").button('reset').attr("data-dismiss", "modal").text("Close").on('click', function () { location.reload(); });
+ }
+ );
+}
View
1 lib/milkode/cdweb/views/layout.haml
@@ -20,6 +20,7 @@
%script(type='text/javascript' src='/js/jquery-ui-1.8.22.custom.min.js')
%script(type='text/javascript' src='/js/jquery.multiselect.min.js')
%script(type='text/javascript' src='/js/jquery.multiselect.filter.min.js')
+ %script(type='text/javascript' src='/js/bootstrap.min.js')
%script(type='text/javascript' src='/js/milkode.js')
-# GoogleAnalyticsを使いたい場合はここにコードを挿入して下さい。
View
31 lib/milkode/cli.rb
@@ -32,7 +32,7 @@ def init(db_dir = nil)
milk add git://github.com/ongaeshi/milkode.git
EOF
option :ignore, :type => :array, :aliases => '-i', :desc => 'Ignore path.'
- option :no_auto_ignore, :type => :boolean, :desc => 'Disable auto ignore (.gitignore).'
+ option :no_auto_ignore, :type => :boolean, :aliases => '-n', :desc => 'Disable auto ignore (.gitignore).'
option :verbose, :type => :boolean, :aliases => '-v', :desc => 'Be verbose.'
def add(*args)
@@ -108,9 +108,15 @@ def mcd
cdstk.mcd(options)
end
- desc "info", "Information of milkode status"
- def info
- cdstk.info
+ desc "info [package]", "Display package information"
+ option :all, :type => :boolean, :aliases => '-a', :desc => 'Display all packages'
+ option :detail, :type => :boolean, :aliases => '-d', :desc => 'Detail format'
+ option :table, :type => :boolean, :aliases => '-t', :desc => 'Table format'
+ option :breakdown, :type => :boolean, :aliases => '-b', :desc => 'Breakdown format'
+ option :unknown, :type => :boolean, :aliases => '-u', :desc => 'Display unknown files'
+
+ def info(*args)
+ cdstk.info(args_or_pipe(args, $stdin), options)
end
desc "ignore [path ...]", "Ignore a file or directory"
@@ -169,10 +175,16 @@ def plugins(*args)
$stdout.puts <<EOF
Gitomb https://github.com/tomykaira/gitomb
redmine_milkode https://github.com/suer/redmine_milkode
+Milkode_Sublime https://github.com/tsurushuu/Milkode_Sublime
emacs-milkode https://github.com/ongaeshi/emacs-milkode
EOF
end
+ desc "files", "Display package files"
+ def files(*args)
+ cdstk.files(args)
+ end
+
# --------------------------------------------------------------------------
no_tasks do
@@ -208,5 +220,16 @@ def db_dir
end
end
+ # 引数が空の場合はパイプ(標準入力)を受け取る
+ def args_or_pipe(args, stdin)
+ if !args.empty?
+ args
+ elsif File.pipe?(stdin)
+ stdin.readlines.map{|v| v.chomp}
+ else
+ []
+ end
+ end
+
end
end
View
2 lib/milkode/common/grenfiletest.rb
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
module GrenFileTest
- IGNORE_FILE = /(\A#.*#\Z)|(~\Z)|(\A\.#)|(\.d\Z)|(\.map\Z)|(\.MAP\Z)/
+ IGNORE_FILE = /(\A#.*#\Z)|(~\Z)|(\A\.#)|(\.d\Z)|(\.map\Z)|(\.MAP\Z)|(\.xbm\Z)|(\.ppm\Z)|(\.ai\Z)|(\.png\Z)|(\.webarchive\Z)/
IGNORE_DIR = /(\A\.svn\Z)|(\A\.git\Z)|(\ACVS\Z)/
def self.ignoreDir?(fpath)
View
111 lib/milkode/common/plang_detector.rb
@@ -0,0 +1,111 @@
+# -*- coding: utf-8 -*-
+#
+# @file
+# @brief Programming Language Detector
+# @author ongaeshi
+# @date 2012/09/29
+
+module Milkode
+ class PlangDetector
+ LANGUAGES =
+ [
+ # high priority
+ { :name => 'README' , :filepatterns => ['README', 'readme'] },
+
+ # normal priority
+ { :name => 'ActionScript' , :suffixs => ['as'] },
+ { :name => 'Autotools' , :suffixs => ['am', 'in'] },
+ { :name => 'AWK' , :suffixs => ['awk'] },
+ { :name => 'Batch File' , :suffixs => ['bat'] },
+ { :name => 'Bundler' , :filenames => ['Gemfile', 'Gemfile.lock'] },
+ { :name => 'C' , :suffixs => ['c', 'h'] },
+ { :name => 'C#' , :suffixs => ['cs'] },
+ { :name => 'C++' , :suffixs => ['cc', 'cpp', 'hpp'] },
+ { :name => 'CGI' , :suffixs => ['cgi'] },
+ { :name => 'ChangeLog' , :filenames => ['ChangeLog'] },
+ { :name => 'Common Lisp' , :suffixs => ['cl'] },
+ { :name => 'CSS' , :suffixs => ['css'] },
+ { :name => 'CSV' , :suffixs => ['csv'] },
+ { :name => 'Diff' , :suffixs => ['diff'] },
+ { :name => 'Emacs Lisp' , :suffixs => ['el'] },
+ { :name => 'Erlang' , :suffixs => ['erl'] },
+ { :name => 'eRuby' , :suffixs => ['erb', 'rhtml'] },
+ { :name => 'gitignore' , :filenames => ['.gitignore'] },
+ { :name => 'Haml' , :suffixs => ['haml'] },
+ { :name => 'Haskell' , :suffixs => ['hs'] },
+ { :name => 'HTML' , :suffixs => ['html'] },
+ { :name => 'Java' , :suffixs => ['java'] },
+ { :name => 'JavaScript' , :suffixs => ['js'] },
+ { :name => 'JSON' , :suffixs => ['json'] },
+ { :name => 'Lua' , :suffixs => ['lua'] },
+ { :name => 'Makefile' , :suffixs => ['mk'] , :filenames => ['Makefile', 'makefile'] },
+ { :name => 'Markdown' , :suffixs => ['md', 'markdown'] },
+ { :name => 'M4' , :suffixs => ['m4'] },
+ { :name => 'Objective-C' , :suffixs => ['m', 'mm'] },
+ { :name => 'PEM' , :suffixs => ['pem'] },
+ { :name => 'Perl' , :suffixs => ['pl', 'PL', 'pm', 't'] },
+ { :name => 'POD' , :suffixs => ['pod'] },
+ { :name => 'PHP' , :suffixs => ['php'] },
+ { :name => 'Python' , :suffixs => ['py'] },
+ { :name => 'Rackup' , :suffixs => ['ru'] },
+ { :name => 'Rakefile' , :suffixs => ['rake'] , :filenames => ['Rakefile'] },
+ { :name => 'RD' , :suffixs => ['rd'] , :filepatterns => [/rd.ja\Z/] },
+ { :name => 'RDoc' , :suffixs => ['rdoc'] },
+ { :name => 'Ruby' , :suffixs => ['rb'] },
+ { :name => 'RubyGems' , :suffixs => ['gemspec'] },
+ { :name => 'Scheme' , :suffixs => ['scm'] },
+ { :name => 'sed' , :suffixs => ['sed'] },
+ { :name => 'Shell' , :suffixs => ['sh'] },
+ { :name => 'SVG' , :suffixs => ['svg'] },
+ { :name => 'Tcl' , :suffixs => ['tcl'] },
+ { :name => 'Text' , :suffixs => ['txt'] },
+ { :name => 'XML' , :suffixs => ['xml'] },
+ { :name => 'Yaml' , :suffixs => ['yml', 'yaml'] },
+ # { :name => '' , :suffixs => [] , :filenames => [] },
+ ]
+
+ UNKNOWN = 'unknown'
+ UNKNOWN_LANGUAGE = {:name => UNKNOWN}
+
+ def initialize(filename)
+ suffix = File.extname(filename)
+ suffix = suffix[1..-1]
+
+ filename = File.basename(filename)
+
+ @lang = LANGUAGES.find {|v|
+ is_found = false
+
+ if v[:suffixs]
+ is_found = v[:suffixs].include?(suffix)
+ end
+
+ if !is_found && v[:filenames]
+ is_found = v[:filenames].include?(filename)
+ end
+
+ if !is_found && v[:filepatterns]
+ v[:filepatterns].each do |pattern|
+ if filename.match pattern
+ is_found = true
+ break
+ end
+ end
+ end
+
+ is_found
+ }
+
+ @lang ||= UNKNOWN_LANGUAGE
+ end
+
+ def name
+ @lang[:name]
+ end
+
+ def unknown?
+ name == UNKNOWN
+ end
+ end
+end
+
View
11 lib/milkode/common/util.rb
@@ -89,7 +89,11 @@ def filename_to_utf8(str_from_file)
end
def larger_than_oneline(content)
- content && content.count($/) > 1
+ begin
+ content && content.count($/) > 1
+ rescue ArgumentError
+ true
+ end
end
def normalize_filename(str)
@@ -174,6 +178,11 @@ def divide_shortpath(shortpath)
def git_url?(src)
(src =~ /^(:?git[:@])|(:?ssh:)/) != nil
end
+
+ # StringIO patch
+ def pipe?(io)
+ !io.instance_of?(IO) || !File.pipe?(io)
+ end
end
end
View
8 lib/milkode/database/groonga_database.rb
@@ -9,9 +9,9 @@
require 'groonga'
require 'milkode/common/dbdir'
require 'fileutils'
-require 'milkode/database/package_table.rb'
-require 'milkode/database/document_table.rb'
-require 'milkode/database/document_record.rb'
+require 'milkode/database/package_table'
+require 'milkode/database/document_table'
+require 'milkode/database/document_record'
module Milkode
class GroongaDatabase
@@ -91,7 +91,7 @@ def compatible?(filename, no_exit = nil)
true
end
end
-
+
private
def define_schema
View
242 lib/milkode/database/updater.rb
@@ -0,0 +1,242 @@
+# -*- coding: utf-8 -*-
+#
+# @file
+# @brief
+# @author ongaeshi
+# @date 2012/09/15
+
+require 'milkode/database/groonga_database'
+require 'milkode/common/grenfiletest'
+require 'milkode/common/ignore_checker'
+require 'kconv'
+
+module Milkode
+ class Updater
+ attr_reader :result
+
+ def initialize(grndb, package_name)
+ @grndb = grndb
+ @package_name = package_name
+ @package = @grndb.packages[@package_name]
+ @result = Result.new
+ @current_ignore = IgnoreChecker.new
+ @options = {}
+ @out = $stdout
+ end
+
+ def exec
+ # git pull
+ if @options[:update_with_git_pull]
+ Dir.chdir(@package.directory) { system("git pull") }
+ end
+
+ # cleanup
+ unless @options[:no_clean]
+ @grndb.documents.cleanup_package_name(@package_name)
+ end
+
+ # update
+ update_dir(@package.directory)
+
+ # 更新時刻の更新
+ @grndb.packages.touch(@package_name, :updatetime)
+ end
+
+ def set_package_ignore(ignore_setting)
+ @current_ignore.add ignore_setting
+ end
+
+ def enable_no_auto_ignore
+ @options[:no_auto_ignore] = true
+ end
+
+ def enable_silent_mode
+ @options[:silent_mode] = true
+ end
+
+ def enable_display_info
+ @options[:display_info] = true
+ end
+
+ def enable_update_with_git_pull
+ @options[:update_with_git_pull] = true
+ end
+
+ def enable_no_clean
+ @options[:no_clean] = true
+ end
+
+ class Result
+ attr_reader :file_count
+ attr_reader :add_count
+ attr_reader :update_count
+
+ def initialize
+ @file_count = 0
+ @add_count = 0
+ @update_count = 0
+ end
+
+ def inc_file_count
+ @file_count += 1
+ end
+
+ def inc_add_count
+ @add_count += 1
+ end
+
+ def inc_update_count
+ @update_count += 1
+ end
+ end
+
+ class ResultAccumulator
+ attr_reader :package_count
+ attr_reader :file_count
+ attr_reader :add_count
+ attr_reader :update_count
+
+ def initialize
+ @package_count = 0
+ @file_count = 0
+ @add_count = 0
+ @update_count = 0
+ end
+
+ def <<(result)
+ @package_count += 1
+ @file_count += result.file_count
+ @add_count += result.add_count
+ @update_count += result.update_count
+ end
+ end
+
+ # ---------------------------------------------------------
+ private
+
+ def update_dir(dir)
+ if (!FileTest.exist?(dir))
+ warning_alert("#{dir} (Not found, skip)")
+ elsif (FileTest.directory? dir)
+ db_add_dir(dir)
+ else
+ db_add_file(File.dirname(dir), File.basename(dir), File.basename(dir)) # .bashrc/.bashrc のようになる
+ end
+ end
+
+ def db_add_dir(dir)
+ searchDirectory(dir, @package_name, "/", 0)
+ end
+
+ def db_add_file(package_dir, restpath, package_name = nil)
+ # サイレントモード
+ return if @options[:silent_mode]
+
+ # データベースには先頭の'/'を抜いて登録する
+ # 最初から'/'を抜いておけば高速化の余地あり?
+ # ignore設定との互換性保持が必要
+ restpath = restpath.sub(/^\//, "")
+
+ # パッケージ名を設定
+ package_name = package_name || File.basename(package_dir)
+
+ # レコードの追加
+ result = @grndb.documents.add(package_dir, restpath, package_name)
+
+ # メッセージの表示
+ case result
+ when :newfile
+ @result.inc_add_count
+ alert_info("add_record", File.join(package_dir, restpath))
+ when :update
+ # @grndb.packages.touch(package_name, :updatetime)
+ @result.inc_update_count
+ alert_info("update", File.join(package_dir, restpath))
+ end
+ end
+
+ def searchDirectory(dirname, packname, path, depth)
+ # 現在位置に.gitignoreがあれば無視設定に加える
+ add_current_gitignore(dirname, path) unless @options[:no_auto_ignore]
+
+ # 子の要素を追加
+ Dir.foreach(File.join(dirname, path)) do |name|
+ next if (name == '.' || name == '..')
+
+ next_path = File.join(path, name)
+ fpath = File.join(dirname, next_path)
+ shortpath = File.join(packname, next_path)
+
+ # 除外ディレクトリならばパス
+ next if ignoreDir?(fpath, next_path)
+
+ # 読み込み不可ならばパス
+ next unless FileTest.readable?(fpath)
+
+ # ファイルならば中身を探索、ディレクトリならば再帰
+ case File.ftype(fpath)
+ when "directory"
+ searchDirectory(dirname, packname, next_path, depth + 1)
+ when "file"
+ unless ignoreFile?(fpath, next_path)
+ db_add_file(dirname, next_path) # shortpathの先頭に'/'が付いているのが気になる
+ @result.inc_file_count
+ # @out.puts "file_count : #{@file_count}" if (@file_count % 100 == 0)
+ end
+ end
+ end
+ end
+
+ def ignoreDir?(fpath, mini_path)
+ FileTest.directory?(fpath) &&
+ (GrenFileTest::ignoreDir?(fpath) ||
+ package_ignore?(fpath, mini_path))
+ end
+
+ def ignoreFile?(fpath, mini_path)
+ GrenFileTest::ignoreFile?(fpath) ||
+ GrenFileTest::binary?(fpath) ||
+ package_ignore?(fpath, mini_path)
+ end
+
+ def package_ignore?(fpath, mini_path)
+ if @current_ignore.ignore?(mini_path)
+ alert_info("ignore", fpath)
+ true
+ else
+ false
+ end
+ end
+
+ def add_current_gitignore(dirname, path)
+ git_ignore = File.join(dirname, path, ".gitignore")
+
+ if File.exist? git_ignore
+ alert_info("add_ignore", git_ignore)
+
+ open(git_ignore) do |f|
+ @current_ignore.add IgnoreSetting.create_from_gitignore(path, f.read)
+ end
+ end
+ end
+
+ def alert_info(title, msg)
+ alert(title, msg) if @options[:display_info]
+ end
+
+ def alert(title, msg)
+ if (Util::platform_win?)
+ @out.puts "#{title.ljust(10)} : #{Kconv.kconv(msg, Kconv::SJIS)}"
+ else
+ @out.puts "#{title.ljust(10)} : #{msg}"
+ end
+ end
+
+ def warning_alert(msg)
+ @out.puts "[warning] #{msg}"
+ end
+
+ end
+end
+
+
View
12 milkode.gemspec
@@ -5,11 +5,11 @@
Gem::Specification.new do |s|
s.name = %q{milkode}
- s.version = "0.9.2"
+ s.version = "0.9.3"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["ongaeshi"]
- s.date = %q{2012-09-07}
+ s.date = %q{2012-10-06}
s.description = %q{Line based local source code search engine & grep-command & web-app.}
s.email = %q{ongaeshi0621@gmail.com}
s.executables = ["gmilk", "milk"]
@@ -75,6 +75,8 @@ Gem::Specification.new do |s|
"lib/milkode/cdweb/public/images/file.png",
"lib/milkode/cdweb/public/images/go-home-5.png",
"lib/milkode/cdweb/public/images/help.png",
+ "lib/milkode/cdweb/public/images/view-refresh-4.png",
+ "lib/milkode/cdweb/public/images/waiting.gif",
"lib/milkode/cdweb/public/img/glyphicons-halflings-white.png",
"lib/milkode/cdweb/public/img/glyphicons-halflings.png",
"lib/milkode/cdweb/public/js/bootstrap.min.js",
@@ -103,6 +105,7 @@ Gem::Specification.new do |s|
"lib/milkode/common/grensnip.rb",
"lib/milkode/common/ignore_checker.rb",
"lib/milkode/common/ignore_setting.rb",
+ "lib/milkode/common/plang_detector.rb",
"lib/milkode/common/platform.rb",
"lib/milkode/common/string_snip.rb",
"lib/milkode/common/util.rb",
@@ -110,6 +113,7 @@ Gem::Specification.new do |s|
"lib/milkode/database/document_table.rb",
"lib/milkode/database/groonga_database.rb",
"lib/milkode/database/package_table.rb",
+ "lib/milkode/database/updater.rb",
"lib/milkode/findgrep/findgrep.rb",
"lib/milkode/findgrep/result.rb",
"lib/milkode/grep/cli_grep.rb",
@@ -130,6 +134,8 @@ Gem::Specification.new do |s|
"test/data/c_project/c.txt",
"test/data/c_project/cc.txt",
"test/data/c_project/to/file.rb",
+ "test/data/ignore_test/.gitignore",
+ "test/data/ignore_test/a.txt",
"test/data/no_auto_ignore/.gitignore",
"test/data/no_auto_ignore/a.txt",
"test/data/nodir_abc.zip",
@@ -162,8 +168,10 @@ Gem::Specification.new do |s|
"test/test_package.rb",
"test/test_package_list.rb",
"test/test_package_table.rb",
+ "test/test_plang_detector.rb",
"test/test_query.rb",
"test/test_string_snip.rb",
+ "test/test_updater.rb",
"test/test_util.rb",
"test/test_yaml_file_wrapper.rb"
]
View
1 test/data/ignore_test/.gitignore
@@ -0,0 +1 @@
+*.bak
View
1 test/data/ignore_test/a.txt
@@ -0,0 +1 @@
+a
View
3 test/test_cli.rb
@@ -34,7 +34,8 @@ def test_mcd
end
def test_info
- assert_match /.*packages.*records/, command("info")
+ # assert_match /.*packages.*records/, command("info")
+ assert_match /Not registered/, command("info")
end
def test_setdb_no_arg_disp
View
32 test/test_plang_detector.rb
@@ -0,0 +1,32 @@
+# -*- coding: utf-8 -*-
+#
+# @file
+# @brief
+# @author ongaeshi
+# @date 2012/09/29
+
+require 'milkode/common/plang_detector'
+require 'test_helper'
+
+module Milkode
+ class TestPlangDetector < Test::Unit::TestCase
+ def test_name
+ assert_equal 'ActionScript', PlangDetector.new('Dummy.as').name
+ assert_equal 'C' , PlangDetector.new('a.c').name
+ assert_equal 'C' , PlangDetector.new('a.h').name
+ assert_equal 'C#' , PlangDetector.new('AssemblyInfo.cs').name
+ assert_equal 'C++' , PlangDetector.new('path/to/file.hpp').name
+ assert_equal 'Ruby' , PlangDetector.new('template.rb').name
+ assert_equal 'README' , PlangDetector.new('readme.txt').name
+ assert_equal 'JavaScript' , PlangDetector.new('main.js').name
+ end
+
+ def test_unknown
+ assert_equal 'unknown', PlangDetector.new('').name
+ assert_equal 'unknown', PlangDetector.new('.').name
+ assert_equal 'unknown', PlangDetector.new('abcdefg').name
+ end
+ end
+end
+
+
View
121 test/test_updater.rb
@@ -0,0 +1,121 @@
+# -*- coding: utf-8 -*-
+#
+# @file
+# @brief
+# @author ongaeshi
+# @date 2012/09/12
+
+require 'test_helper'
+require 'milkode/database/updater'
+require 'milkode_test_work'
+require 'fileutils'
+require 'milkode/common/ignore_checker'
+
+module Milkode
+ class TestUpdater < Test::Unit::TestCase
+ def setup
+ @work = MilkodeTestWork.new({:default_db => true})
+
+ FileUtils.cp_r @work.expand_path("../data/a_project"), @work.expand_path("a_project")
+ @work.add_package "db1", @work.expand_path("a_project")
+
+ FileUtils.cp_r @work.expand_path("../data/ignore_test"), @work.expand_path(".")
+ @work.add_package "db1", @work.expand_path("ignore_test")
+
+ @grndb = GroongaDatabase.new
+ @grndb.open(@work.expand_path("db1"))
+ end
+
+ def test_update
+ t_pre_check
+ t_update
+ t_add_file
+ t_update_file
+ t_local_gitignore
+ t_global_ignore
+ t_no_auto_ignore
+ t_silent_mode
+ # t_display_info # ONにすると標準出力されてしまうため
+ end
+
+ def teardown
+ @work.teardown
+ end
+
+ private
+
+ def t_pre_check
+ assert_equal 2, @grndb.packages.size
+ assert_not_nil @grndb.packages['a_project']
+ end
+
+ def t_update
+ updater = Updater.new(@grndb, 'a_project')
+ updater.exec
+ result_test updater.result, 3, 0, 0
+ end
+
+ def t_add_file
+ FileUtils.touch(@work.expand_path("a_project/aaa"), :mtime => Time.now - 1)
+ updater = Updater.new(@grndb, 'a_project')
+ updater.exec
+ result_test updater.result, 4, 1, 0
+ end
+
+ def t_update_file
+ FileUtils.copy @work.expand_path("../data/c_project/a.txt"), @work.expand_path("a_project/aaa")
+ FileUtils.touch(@work.expand_path("a_project/aaa"))
+ updater = Updater.new(@grndb, 'a_project')
+ updater.exec
+ result_test updater.result, 4, 0, 1
+ end
+
+ def t_local_gitignore
+ FileUtils.touch(@work.expand_path("ignore_test/b.bak")) # *.bak は除外対象
+ FileUtils.touch(@work.expand_path("ignore_test/b.txt"))
+ updater = Updater.new(@grndb, 'ignore_test')
+ updater.exec
+ result_test updater.result, 3, 1, 0
+ end
+
+ def t_global_ignore
+ FileUtils.touch(@work.expand_path("ignore_test/c.txt"))
+
+ updater = Updater.new(@grndb, 'ignore_test')
+ updater.exec
+ result_test updater.result, 4, 1, 0
+
+ updater = Updater.new(@grndb, 'ignore_test')
+ updater.set_package_ignore(IgnoreSetting.new("/", ["*.txt"])) # *.txt を除外設定
+ updater.exec
+ result_test updater.result, 1, 0, 0
+ end
+
+ def t_no_auto_ignore
+ updater = Updater.new(@grndb, 'ignore_test')
+ updater.enable_no_auto_ignore
+ updater.exec
+ result_test updater.result, 6, 2, 0
+ end
+
+ def t_silent_mode
+ updater = Updater.new(@grndb, 'ignore_test')
+ updater.enable_silent_mode
+ updater.exec
+ result_test updater.result, 4, 0, 0
+ end
+
+ def t_display_info
+ updater = Updater.new(@grndb, 'ignore_test')
+ updater.enable_display_info
+ updater.exec
+ result_test updater.result, 4, 0, 0
+ end
+
+ def result_test(result, file_count, add_count, update_count)
+ assert_equal file_count, result.file_count
+ assert_equal add_count, result.add_count
+ assert_equal update_count, result.update_count
+ end
+ end
+end

0 comments on commit cf99cbf

Please sign in to comment.
Something went wrong with that request. Please try again.