Created
January 6, 2013 17:27
-
-
Save AlanQuatermain/4468801 to your computer and use it in GitHub Desktop.
I needed to go through a large number of Xcode-generated source-code files the other day, replacing the copyright line with a license header statement. Since there were lots of files in a nested structure I decided to use a script, and I added in a glob pattern to exclude certain files/folders— because there was some public domain source in ther…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
# This program is free software: you can redistribute it and/or modify | |
# it under the terms of the GNU General Public License as published by | |
# the Free Software Foundation, either version 3 of the License, or | |
# (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# A copy of the GNU General Public License can be found at | |
# <http://www.gnu.org/licenses/gpl-3.0.html>. | |
require 'optparse' | |
require 'fileutils' | |
require 'rubygems' | |
@@Verbose = 0 | |
@@DryRun = false | |
@@Exclude = '' | |
@@Template = nil | |
OptionParser.new do |opts| | |
opts.banner = "Usage: ChangeLicenses [OPTIONS] [-e exclusion_regex] [-c copyright_owner] -t template_file" | |
opts.separator "" | |
opts.separator "Scans recursively through the current folder (using an optional exclusion glob pattern) to" | |
opts.separator "locate all C/C++ header and source files, and then modifies their Xcode-style source" | |
opts.separator "headers to include the text from a named input file or stdin." | |
opts.separator "" | |
opts.separator "The appended text does not need to be prefixed with commenting characters; the program" | |
opts.separator "will do that for you, matching Xcode's standard double-spaced indents." | |
opts.separator "" | |
opts.separator "Options:" | |
opts.on_tail( "-h", "--help", "Show this message.", :NONE) do | |
puts opts | |
exit | |
end | |
opts.on("-v", "--verbose", | |
"Print information about the program's operation. Specify", | |
"up to three times, with each one increasing the amount", | |
"of data output.", :NONE) do | |
@@Verbose += 1 | |
end | |
opts.on("-d", "--dry-run", "Don't modify any files. Best used", | |
"with -vvv which will print out all new files. Optional.", :NONE) do |v| | |
@@DryRun = v | |
end | |
opts.on("-e", "--exclude", "Specifies a glob pattern. All files", | |
"whose sub-paths are matched by the pattern are ignored.", | |
"Optional.", :REQUIRED) do |v| | |
@@Exclude = v unless v == '' | |
end | |
opts.on("-t", "--template", "Specifies the path to a plain-", | |
"text file containing the template for the text to", | |
"insert into the document's leading header. If not", | |
"specified, the template text is read from stdin.", :REQUIRED) do |v| | |
fail "Error: File '#{arg}' not found." unless File.exists?(v) | |
fail "Error: File '#{arg}' unreadable." unless File.readable?(v) | |
@@Template = File.read(v, nil) | |
end | |
end.parse! | |
if @@Template.nil? | |
@@Template = STDIN.read | |
end | |
fail "Error: No template supplied." if @@Template == '' | |
@@CopyrightLineRegex = %r{^(// Copyright \(c\) \d+ ).*?(\. All rights reserved.)$} | |
# glob ALL THE THINGS | |
Dir.glob("**/*.{h,c,cpp}") do |filename| | |
# skip anything matched by the exclusion glob | |
if File.fnmatch(@@Exclude, filename) # File.fnmatch('something', '') always returns false | |
puts "* Ignoring #{filename}" if @@Verbose > 0 | |
next | |
end | |
puts "#{filename}" if @@Verbose > 0 | |
tmpname = "#{filename}.tmp" | |
File.open(tmpname, "w") do |tmpfile| | |
# after writing the copyright/license block, we ignore all further comments lines | |
# until we see a non-comment line | |
skipCommentLines = false | |
File.foreach(filename) do |line| | |
if line =~ @@CopyrightLineRegex | |
# this is the copyright line, which will be replaced with the license | |
# the license is expected to contain a copyright line already | |
# For each line of the license template, prefix it and write it out | |
@@Template.each_line do |template_line| | |
tmpfile.puts "// #{template_line}" | |
end | |
tmpfile.puts "//" | |
# skip any non-empty comment lines now | |
skipCommentLines = true | |
elsif line !~ %r{^//} || !skipCommentLines | |
skipCommentLines = false | |
# all remaining lines are output verbatim | |
tmpfile.puts line | |
end | |
end | |
end | |
if @@Verbose > 2 | |
File.foreach(tmpname) do |line| | |
puts line | |
end | |
end | |
unless @@DryRun | |
# move the original file to the side, and move the new file in, then delete old file | |
oldname = "#{filename}.old" | |
FileUtils.mv(filename, oldname) | |
FileUtils.mv(tmpname, filename) | |
FileUtils.rm(oldname) | |
else | |
# dry-run mode: delete the temp file | |
FileUtils.rm(tmpname) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment