#!/usr/bin/ruby ################################################################################ # # Copyright (c) 2009, Perforce Software, Inc. All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # 1. Redistributions of source code must retain the above copyright # notice, this list of conditions and the following disclaimer. # # 2. Redistributions in binary form must reproduce the above copyright # notice, this list of conditions and the following disclaimer in the # documentation and/or other materials provided with the distribution. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL PERFORCE SOFTWARE, INC. BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. # # = Description # Create dummy revisions for file revisions reported as MISSING by # the "p4 verify" command. # Only dummy revisions for non existent ,v or .gz files are created. # All dummy revisions are stored as gzipped file, therefore they can be # easily replaced later on if a user has one of the missing revisions # in his workspace. # # = Usage # p4 verify -q //a_path/... | ruby dummy.rb # or # ruby dummy.rb verify_output_file # ################################################################################ require "P4" require "zlib" require "ftools" # Regular expression used for parsing the output of "p4 verify" MISSINGRexp = Regexp.new( '.*(//.*#\d+) -.*MISSING!' ) # Regular expression used for detecting absolute file path ABSOLUTEPATHRexp = Regexp.new( '\w:.*|^/.*') def InitialiseDepotMap(p4, p4root) depotMap = P4::Map.new() depots = p4.run_depots() depots.each do |d| path = d["map"] if !path.match( ABSOLUTEPATHRexp ) path = p4root + "/" + path end depotMap.insert( "//" + d[ "name" ].to_s + "/...", path ) end return depotMap end def CreateRCSFile(rcsFile, lbrRev) # Create the missing rcs file revision only if rcs file does not exist if !File.exist?(rcsFile) # The subdirectores may not exist File.makedirs(File.dirname(rcsFile)) unless File.directory?(File.dirname(rcsFile)) rcsFile = File.new(rcsFile, "w") rcsFile.puts "head " + lbrRev + ";" rcsFile.puts "access ;" rcsFile.puts "symbols ;" rcsFile.puts "locks ;comment @@;" rcsFile.puts lbrRev rcsFile.puts "date " + Time.now.strftime("%Y.%m.%d.%H.%M.%S") + "; author p4; state Exp;" rcsFile.puts "branches ;" rcsFile.puts "next ;" rcsFile.puts "desc" rcsFile.puts "@@" rcsFile.puts lbrRev rcsFile.puts "log" rcsFile.puts "@@" rcsFile.puts "text" rcsFile.puts "@This is a dummy revision.@" rcsFile.close return 1 end rescue puts "Cannot create " + File.dirname(rcsFile) + " or " + rcsFile return 0 end def CreateGzipFile(gzFile) if !File.exist?(gzFile) # The binary directory may not exist File.makedirs(File.dirname(gzFile)) unless File.directory?(File.dirname(gzFile)) # create a gzip dummy revision Zlib::GzipWriter.open(gzFile) do |gz| gz.write 'This is a dummy revision.' end return 1 end rescue puts "Cannot create " + File.dirname(gzFile) + " or " + gzFile return 0 end def FixChecksum(p4, depotFile, depotRev, lazyCopyFile, lazyCopyRev) p4.run_verify("-v", depotFile + "#" + depotRev + ",#" + depotRev) if lazyCopyFile for i in 0...lazyCopyFile.size p4.run_verify("-v", lazyCopyFile[i] + lazyCopyRev[i]) end end end begin p4 = P4.new p4.exception_level = P4::RAISE_ERRORS p4.connect p4info = p4.run_info().shift p4root = p4info [ "serverRoot" ] if (!p4root.match( ABSOLUTEPATHRexp )) puts("P4ROOT directroy must be set with an absolute path") exit ( 0 ) end depotMap = InitialiseDepotMap(p4, p4root) line = $<.gets while line if (md = MISSINGRexp.match(line)) fstat = p4.run_fstat("-Oc", "-Oz", md[1]).shift depotFile = fstat[ "depotFile" ] lbrFile = fstat[ "lbrFile" ] # Only fix non-lazy copy revision if (depotFile == lbrFile) depotRev = fstat[ "headRev" ] lbrRev = fstat[ "lbrRev" ] lbrType = fstat[ "lbrType" ] lazyCopyFile = fstat[ "lazyCopyFile" ] lazyCopyRev = fstat[ "lazyCopyRev" ] gzFile = depotMap.translate(lbrFile) + ",d/" + lbrRev + ".gz" # Fix missing rcs file if (lbrType == "text" or lbrType == "unicode" or lbrType =="utf16" or lbrType == "utf16" or lbrType == "ktext" or lbrType == "xtext" or lbrType == "kxtext" or lbrType == "xunicode" or lbrType == "xutf16") rcsFile = depotMap.translate(lbrFile) + ",v" # Create a dummy rcs file matching the missing rcs revision # Convert librarian file to ctext to simply how to deal with a whole # missing rcs file and it is easier to replace the dummy revsion if if CreateRCSFile(rcsFile, lbrRev) # necessary in the future p4.run_retype("-l", "-tctext", depotFile + "#" + depotRev + ",#" + depotRev) # Force recalculation of checksum to prevent BAD verify errors FixChecksum(p4, depotFile, depotRev, lazyCopyFile, lazyCopyRev) puts gzFile + " was created" else # rcs file exist and dummy revision needs to be inserted mannually puts rcsFile + " cannot be fixed" end end # Fix missing gzipped revision if (lbrType == "binary" or lbrType == "ctext" or lbrType == "resource" or lbrType == "apple" or lbrType == "cxtext" or lbrType == "xbinary" or lbrType == "ctempobj") if CreateGzipFile(gzFile) # Force recalculation of checksum to prevent BAD verify errors FixChecksum(p4, depotFile, depotRev, lazyCopyFile, lazyCopyRev) puts gzFile + " was created" else # gzip revision may be corrupted and need to be fixed mannually puts gzFile + " cannot be fixed" end end end end line = $<.gets end rescue P4Exception p4.errors.each { |e| $stderr.puts( e ) } raise end