#!/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 MISSING by
# the "p4 verify" command.
# 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 a 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 RcsType?(type)
result = false
if (type == "text" or type == "unicode" or type =="utf16" or
type == "utf16" or type == "ktext" or type == "xtext" or
type == "kxtext" or type == "xunicode" or type == "xutf16")
result = true
end
return result
end
def GzType?(type)
result = false
if (type == "binary" or type == "ctext" or type == "resource" or
type == "apple" or type == "cxtext" or type == "xbinary" or
type == "ctempobj")
result = true
end
return result
end
def CreateRCSFile(rcsFile, lbrRev)
success = 0
begin
# 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
success = 1
end
rescue
puts "error: cannot create " + File.dirname(rcsFile) + " or " + rcsFile
end
return success
end
def CreateGzipFile(gzFile)
success = 0
begin
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
success = 1
end
rescue
puts "error: cannot create " + File.dirname(gzFile) + " or " + gzFile
end
return success
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 (p4.server_level < 23)
puts "error: a Perforce server 2007.2 or greater is required"
exit(0)
elsif (!p4root.match( ABSOLUTEPATHRexp ))
puts("error: 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" ]
revFile = depotFile + "#" + depotRev
gzFile = depotMap.translate(lbrFile) + ",d/" + lbrRev + ".gz"
if RcsType?(lbrType)
# Fix missing rcs revision
rcsFile = depotMap.translate(lbrFile) + ",v"
bakFile = rcsFile + ".dummy"
if File.exist?(rcsFile)
# missing revision in an existing rcs file
File.rename(rcsFile, bakFile)
end
if CreateRCSFile(rcsFile, lbrRev) == 1
# Convert rcs file to gz file
p4.run_retype("-l", "-tctext", revFile + ",#" + depotRev)
# Force recalculation of checksum to prevent BAD verify errors
FixChecksum(p4, depotFile, depotRev, lazyCopyFile, lazyCopyRev)
puts "info: " + revFile + " was fixed (" + gzFile + " was created)"
else
puts "error: " + revFile + " (" + rcsFile + ") cannot be fixed"
end
if File.exist?(bakFile)
File.rename(bakFile, rcsFile)
end
elsif GzType?(lbrType)
# Fix missing gzipped revision
if File.exist?(gzFile)
# gzipped revision exist. Corruption?
begin
Zlib::GzipReader.open(gzFile) {
|gz|
gz.read
}
puts "info: " + revFile + " was not changed (" + gzFile + ") is not corrupted"
break
rescue
corruptedFile = gzFile + ".corrupted"
File.rename(gzFile, corruptedFile)
puts "info: " + revFile + " is corrupted" + " (" + corruptedFile + " was created)"
end
end
if CreateGzipFile(gzFile) == 1
# Force recalculation of checksum to prevent BAD verify errors
FixChecksum(p4, depotFile, depotRev, lazyCopyFile, lazyCopyRev)
puts "info: " + revFile + " was fixed (" + gzFile + " was created)"
else
puts "error: " + revFile + " (" + gzFile + ") cannot be fixed"
end
end
end
end
line = $<.gets
end
rescue P4Exception
p4.errors.each {
|e|
$stderr.puts( e )
}
raise
end
| # | Change | User | Description | Committed | |
|---|---|---|---|---|---|
| #8 | 8473 | Pascal Soccard |
- Fixed dummy.rb call as the system call did not work with a large data set (probably a buffer issue). dummy.rb can now run "p4 verify -q" command if a depot path is passed as an argument. - Added support for Ruby 1.9 - Fixed verify error capture as verify errors are reported as errors in 2013.1 or greater |
||
| #7 | 7835 | Pascal Soccard | Fixed text+F and tempobj storage type detection | ||
| #6 | 7834 | Pascal Soccard | ubinary and +F files are now processed | ||
| #5 | 7554 | Pascal Soccard |
Added support for librarian files manually deleted after obliterate (broken lazy copy) |
||
| #4 | 7543 | Pascal Soccard |
The script can now deal with lazy copies for which the librarian file has been manually deleted after the librarian depot file has been obliterated |
||
| #3 | 7537 | Pascal Soccard |
Took server case sensitivity into account. Requires P4Ruby 2009.2 |
||
| #2 | 7481 | Pascal Soccard |
Now can fix missing revision in an existing rcs file and fix corrupted gzipped revision |
||
| #1 | 7398 | Pascal Soccard |
Added script to create dummy revisions for files reported MISSING by "p4 verify" |