Thomas Denney

Checking Apache licenses on Objective-C files

At the moment I’m putting together an open-source library based off of some classes that I’ve been sharing between some of my iOS apps for a while. I wanted to check that I had the Apache license at the top of each file, and that it followed this format:

// Filename.h/Filename.m
//
// Copyright 2013/2014 Programming Thomas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

I could have checked through each file individually, however I decided that I probably ought to get round to trying Ruby at some point, so I ended up putting together this simple script:

def copyright(fname, year, programmer)
  return "// #{fname}
//
// Copyright #{year} #{programmer}
//
// Licensed under the Apache License, Version 2.0 (the \"License\");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an \"AS IS\" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License."
end

def file_matches(path, years, programmers)
  file = File.open(path, "rb")
  contents = file.read
  basename = File.basename(path)
  file.close
  if not years.respond_to?("each")
    years = [years]
  end
  if not programmers.respond_to?("each")
    programmers = [programmers]
  end
  
  programmers.each do |programmer|
    years.each do |year|
      if contents.start_with?(copyright(basename, year, programmer))
        return true
      end
    end
  end
  return false
end

def walk(dir, years, programmers)
  if File.readable?(dir)
    Dir.foreach(dir) do |basename|
      next if basename == '.'or basename == '..'
      fullname = File.join(dir, basename)
      if File.directory?(fullname)
        walk(fullname, years, programmers)
      elsif basename.end_with?('.h', '.m', '.pch')
        if File.readable?(fullname)
          if not file_matches(fullname, years, programmers)
            puts basename
          end
        end
      end
    end
  end
end

if ARGV.length == 3
  directory = ARGV[0]
  programmers = ARGV[1].split(',')
  years = ARGV[2].split(',')
  walk(directory, years, programmers)
else 
  puts "Usage: ruby apache.rb directory programmers,by,comma years,by,comma"
end

Overall Ruby was pretty easy to pick up (although I imagine the above looks awful to a seasoned Rubyist) and so I was able to quickly check over the source files :).