3 # First, try to load our files from the source tree
4 $: << "#{File.dirname(__FILE__)}/../lib"
7 # Failing that, try to load from a gem
12 class OhcountCommandLine
15 def initialize(args=[])
16 args = args.clone # Because shift is destructive
17 set_option(args.shift) while args.first =~ /^-/
18 assign_paths_and_files(args)
21 def assign_paths_and_files(args)
24 args.each do |file_or_path|
25 if File.directory?(file_or_path)
26 @paths << file_or_path
28 @files << file_or_path
31 @paths = ['.'] if @files.empty? && @paths.empty?
35 @source_file_list ||= Ohcount::SourceFileList.new(:paths => @paths, :files => @files)
39 source_file_list.each_source_file do |s|
40 s.parse do |language, semantic, line|
41 puts "#{language}\t#{semantic}\t#{line}"
46 # Find all source code files
48 source_file_list.each_source_file do |s|
49 puts "#{s.polyglot}\t#{s.filename}"
55 source_file_list.each_source_file do |s|
56 next unless s.licenses.any?
57 symbols = s.licenses.collect { |l| Ohcount::LicenseSniffer::LicenseMap.instance.map[l].symbol }.join(",")
58 puts "#{symbols}\t#{s.filename}"
62 def analyze_with_progress(what)
64 source_file_list.analyze(what) do |s|
75 platforms = source_file_list.gestalt_facts.platforms
76 platforms = platforms.any? ? platforms.collect { |p| p.to_s.split('::').last }.join(", ") : 'None'
77 puts "Platforms detected: #{ platforms }"
79 tools = source_file_list.gestalt_facts.tools
80 tools = tools.any? ? tools.collect { |p| p.to_s.split('::').last }.join(", ") : 'None'
81 puts "Tools detected: #{ tools }"
86 analyze_with_progress(:gestalt)
91 source_file_list.each_source_file do |s|
92 s.raw_entities do |language, entity, s, e|
93 puts "#{language}\t#{entity}\t#{s}\t#{e}"
100 Usage: ohcount [option] [paths...]
102 Ohloh source code line counter command line tool.
103 http://www.ohloh.net/
105 [option] can be one of the following:
112 -a, --annotate Show annotated source code
114 The contents of all source code files found within the given
115 paths will be emitted to stdout. Each line will be prefixed with
116 a tab-delimited language name and semantic categorization (code,
119 -d, --detect Find source code files
121 Recursively find all source code files within the given paths.
122 For each source code file found, the file name will be emitted to
123 stdout prefixed with a tab-delimited language name.
125 -h, --help Display this message
127 -g, --gestalt Project Properties
129 Inspects project contents to determine what platform(s) the project
130 runs on, as well as any detected tools/IDEs used to develop it.
132 -i, --individual Count lines of code per file
134 Count lines in all source code files within the given paths, and
135 emit a report of the lines of code, comments, and blanks in each
140 Displays detected licensing information contained in each source
145 Prints raw entity information to the screen (mainly for debugging).
147 -s, --summary Count lines of code (default)
149 Count lines in all source code files within the given paths, and
150 emit a report of the total number of lines of code, comments,
151 and blanks in each language. This is the default action.
153 [paths] can refer to any number of individual files or directories.
154 Directories will be probed recursively. If no path is given,
155 the current directory will be used.
161 STDOUT.write "Examining #{source_file_list.size} file(s)"
164 puts "Ohloh Line Count".center(76)
165 puts "Language Code Comment Comment % Blank Total File"
166 puts "---------------- --------- --------- --------- --------- --------- -----------------------------------------------"
168 source_file_list.analyze(:language) do |s|
169 s.language_breakdowns.sort {|l1,l2| l2.name <=> l1.name}.each do |lb|
170 write_individual_row(s.filename, lb.name, lb.code_count, lb.comment_count, lb.blanks)
175 def write_individual_row(file, name, code, comment, blank)
178 printf(" %10d",comment)
180 printf(" %9.1f%%", comment.to_f / (comment+code).to_f * 100.0)
184 printf(" %10d",blank)
185 printf(" %10d",code+comment+blank)
186 printf(" %s\n", file)
190 puts "Parsing one file repeatedly. Watch your RAM vanish...."
191 s = Ohcount::SourceCode.new(files.first, :filenames => files)
198 STDOUT.write "Examining #{source_file_list.size} file(s)"
200 analyze_with_progress(:*)
203 puts "Ohloh Line Count Summary".center(76)
206 puts "Language Files Code Comment Comment % Blank Total"
207 puts "---------------- ----- --------- --------- --------- --------- ---------"
209 source_file_list.loc_list.locs.sort { |a,b| b.code <=> a.code}.each do |loc|
210 write_summary_row(loc.language, loc.filecount, loc.code, loc.comments, loc.blanks)
213 puts "---------------- ----- --------- --------- --------- --------- ---------"
214 write_summary_row('Total',
215 source_file_list.loc_list.filecount,
216 source_file_list.loc_list.code,
217 source_file_list.loc_list.comments,
218 source_file_list.loc_list.blanks)
225 def write_summary_row(name, file_count, code, comment, blank)
226 printf("%-16s", name)
227 printf(" %6d", file_count)
228 printf(" %10d", code)
229 printf(" %10d", comment)
231 printf(" %9.1f%%", comment.to_f / (comment+code).to_f * 100.0)
235 printf(" %10d", blank)
236 printf(" %10d\n", code+comment+blank)
241 STDERR.puts "Error: Multiple commands specified."
252 def set_option(option)
254 when '-s', '--summary'
255 self.subcommand = :summary
256 when '-d', '--detect'
257 self.subcommand = :detect
258 when '-a', '--annotate'
259 self.subcommand = :annotate
260 when '-g', '--gestalt'
261 self.subcommand = :gestalt
262 when '-i', '--individual'
263 self.subcommand = :individual
264 when '-l', '--licenses'
265 self.subcommand = :licenses
266 when '-m', '--memoryleak'
267 self.subcommand = :memoryleak
268 when '-e', '--entities'
269 self.subcommand = :entities
271 self.subcommand = :raw_entities
274 # @entities << $1.to_sym
275 # self.subcommand = :entities unless @subcommand
276 when '-?', '-h', '--help'
277 self.subcommand = :help
279 STDERR.puts "Type 'ohcount -?' for usage."
285 self.subcommand ||= :summary
286 if self.respond_to?(self.subcommand)
287 self.send(self.subcommand)
289 STDERR.puts "Type 'ohcount -?' for usage."
295 OhcountCommandLine.new(ARGV).run!