Add p4_check.rb script
authorColin McCabe <cmccabe@alumni.cmu.edu>
Mon, 14 Dec 2009 00:01:41 +0000 (16:01 -0800)
committerColin McCabe <cmccabe@alumni.cmu.edu>
Mon, 14 Dec 2009 00:01:41 +0000 (16:01 -0800)
p4_check.rb [new file with mode: 0755]

diff --git a/p4_check.rb b/p4_check.rb
new file mode 100755 (executable)
index 0000000..33fd045
--- /dev/null
@@ -0,0 +1,111 @@
+#!/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