#!/usr/bin/env ruby
#
# $Id: cvschk.rb,v 1.2 2005/12/31 07:23:17 aamine Exp $
#
# Lists filenames which are not under CVS control.
#
require 'optparse'
USE_ALL_CVSIGNORE = 2
USE_LOCAL_CVSIGNORE = 1
USE_NO_CVSIGNORE = 0
def main
ign_level = USE_ALL_CVSIGNORE
local = false
parser = OptionParser.new
parser.banner = "Usage: #{File.basename($0)} [-aAl] [
]"
parser.on('-a', '--almost', 'Turn off ~/.cvsignore, $CVSIGNORE, and builtin entries.') {
ign_level = USE_LOCAL_CVSIGNORE
}
parser.on('-A', '--all', "Turn off all cvsignores.") {
ign_level = USE_NO_CVSIGNORE
}
parser.on('-l', '--local', 'Process only local directory.') {
local = true
}
parser.on('--help', 'Prints this message and quit.') {
puts parser.help
exit 0
}
begin
parser.parse!
rescue OptionParser::ParseError => err
$stderr.puts err.message
$stderr.puts parser.help
exit 1
end
if ARGV.size > 1
$stderr.puts 'too many arguments'
$stderr.puts parser.help
exit 1
end
check((ARGV[0] || '.'), local, ign_level)
end
def check(dir, no_recursive, ignlevel)
unknown_files(dir, ignlevel).sort.each do |i|
puts i.sub(/\A\.\//, '')
end
return if no_recursive
cvsed_files(dir).each do |path|
next unless File.directory?(path)
next if File.symlink?(path)
check path, false, ignlevel
end
end
def unknown_files(dir, ignlevel)
reject_ignorefiles(all_entries(dir) - cvsed_files(dir), ignlevel, dir)
end
def reject_ignorefiles(pathes, level, dir)
ign_patterns = ignore_patterns(level, dir)
pathes.reject {|path|
ign_patterns.any? {|pat| File.fnmatch?(pat, File.basename(path)) }
}
end
def ignore_patterns(level, cwd)
case level
when USE_NO_CVSIGNORE
['CVS']
when USE_LOCAL_CVSIGNORE
['CVS'] + parse_cvsignore("#{cwd}/.cvsignore")
when USE_ALL_CVSIGNORE
['CVS'] + parse_cvsignore("#{cwd}/.cvsignore") + global_cvsignore()
else
raise 'must not happen'
end
end
BUILTIN_IGNORE = %w(
RCS SCCS CVS CVS.adm
RCSLOG cvslog.*
tags TAGS
.make.state .nse_depinfo
*~ #* .#* ,* _$* *$
*.old *.bak *.BAK *.orig *.rej .del-*
*.a *.olb *.o *.obj *.so *.exe
*.Z *.elc *.ln
core
)
def global_cvsignore
BUILTIN_IGNORE +
env_CVSIGNORE() +
parse_cvsignore(File.expand_path('~/.cvsignore'))
end
def env_CVSIGNORE
return [] unless ENV['CVSIGNORE']
ENV['CVSIGNORE'].split
end
def parse_cvsignore(path)
return [] unless File.file?(path)
File.read(path).split
end
def cvsed_files(dir)
read_CVS_Entries(dir) | cvsed_directories(dir)
end
def read_CVS_Entries(dir)
File.readlines(dir + '/CVS/Entries')\
.map {|line| line.slice(%r_\AD?/([^/]+)_, 1) }.compact\
.map {|ent| "#{dir}/#{ent}" }
rescue Errno::ENOENT
$stderr.puts "no CVS/: #{dir}"
exit 1
end
def cvsed_directories(dir)
Dir.glob(dir + '/*')\
.select {|path| File.directory?(path) }\
.select {|path| File.directory?(path + '/CVS') }
end
def all_entries(dir)
(Dir.entries(dir) - %w(. ..)).map {|ent| "#{dir}/#{ent}" }
end
main