--- /dev/null
+#!/usr/bin/ruby -w
+
+#
+# p4_check
+#
+# This is a script I wrote while I was using the perforce revision control
+# system. I later switched to mostly using git. This script might still be
+# useful to someone still using perforce, though.
+#
+# Given a perforce tree, this script:
+# 1. Verifies that none of the files in it have been
+# made writable without being checked out.
+# 2. Finds "phantom files" that exist in the filesystem but not in perforce
+#
+# Colin McCabe
+#
+
+require 'find'
+require 'optparse'
+require 'open3'
+require 'ostruct'
+require 'pp'
+
+##################### CLASSES #####################
+class MyOptionParse
+ def self.parse(args)
+ # default values
+ opts = OpenStruct.new
+
+ parser = OptionParser.new do |myparser|
+ myparser.banner = "Usage: p4_check [opts]"
+ myparser.separator "Specific options:"
+ #myparser.on("-i PATH", "--input-dir PATH",
+ #"The input directory") do |a|
+ #opts.input = a
+ #end
+ end
+
+ parser.parse!(args)
+ return opts
+ end
+end
+
+class NotOpened < RuntimeError
+end
+
+##################### FUNCTIONS #####################
+# Invoke perforce
+def p4_call(cmd)
+ # If we allow non-arrays to be passed to this function, they will be subject
+ # to yucky shell expansion.
+ if (! cmd.kind_of?(Array)) then
+ $stderr.puts "FATAL: sorry, you must pass an array to this function."
+ end
+
+ # p4 has the following calling convention:
+ # 1) exit code is always 0
+ # 2) errors are on stdout, output is on stderr
+ stdin, stdout, stderr = Open3.popen3(*cmd)
+ err = stderr.readlines
+ ret = stdout.readlines
+
+ # Take a look at the errors generated by p4.
+ # Some are always fatal; for others, we throw an exception
+ if (! err.empty?()) then
+ if (err[0] =~ /Perforce password (P4PASSWD) invalid or unset./) then
+ $stderr.puts "FATAL: #{err[0]}"
+ exit 1
+ elsif (err[0] =~ /Client \'.*\' unknown - use \'client\' \
+ command to create it./) then
+ $stderr.puts "FATAL: #{err[0]}"
+ exit 1
+ else
+ raise NotOpened.new
+ end
+ end
+
+ return ret
+end
+
+def validate_p4
+ lines = p4_call(["p4"])
+ lines.each do |line|
+ if (line =~ /Perforce -- the Fast Software Configuration \
+Management System/) then
+ return
+ end
+ end
+ throw "validate_p4: failed to validate p4 program: #{lines.join}"
+end
+
+##################### CODE #####################
+opts = MyOptionParse.parse(ARGV)
+#pp opts
+
+# verify
+validate_p4()
+
+# Look at all files in the tree
+Find.find( Dir.pwd ) do |fname|
+ #puts "fname = #{fname}"
+ if (File.file?(fname)) then
+ if (File.writable?(fname)) then
+ begin
+ p4_call(["p4", "opened", fname])
+ rescue NotOpened
+ puts "unknown writable: #{fname}"
+ end
+ end
+ end
+end