7
7
# 2007 Trolltech ASA
8
8
# License: MIT <http://www.opensource.org/licenses/mit-license.php>
9
9
#
10
-
11
10
import sys
12
11
if sys .hexversion < 0x02040000 :
13
12
# The limiter is the subprocess module
14
13
sys .stderr .write ("git-p4: requires Python 2.4 or later.\n " )
15
14
sys .exit (1 )
16
-
17
- import optparse , os , marshal , subprocess , shelve
18
- import tempfile , getopt , os .path , time , platform
19
- import re , shutil
15
+ import os
16
+ import optparse
17
+ import marshal
18
+ import subprocess
19
+ import tempfile
20
+ import time
21
+ import platform
22
+ import re
23
+ import shutil
24
+ import stat
20
25
21
26
try :
22
27
from subprocess import CalledProcessError
@@ -185,6 +190,22 @@ def p4_system(cmd):
185
190
if retcode :
186
191
raise CalledProcessError (retcode , real_cmd )
187
192
193
+ _p4_version_string = None
194
+ def p4_version_string ():
195
+ """Read the version string, showing just the last line, which
196
+ hopefully is the interesting version bit.
197
+
198
+ $ p4 -V
199
+ Perforce - The Fast Software Configuration Management System.
200
+ Copyright 1995-2011 Perforce Software. All rights reserved.
201
+ Rev. P4/NTX86/2011.1/393975 (2011/12/16).
202
+ """
203
+ global _p4_version_string
204
+ if not _p4_version_string :
205
+ a = p4_read_pipe_lines (["-V" ])
206
+ _p4_version_string = a [- 1 ].rstrip ()
207
+ return _p4_version_string
208
+
188
209
def p4_integrate (src , dest ):
189
210
p4_system (["integrate" , "-Dt" , wildcard_encode (src ), wildcard_encode (dest )])
190
211
@@ -558,18 +579,30 @@ def gitBranchExists(branch):
558
579
return proc .wait () == 0 ;
559
580
560
581
_gitConfig = {}
561
- def gitConfig (key , args = None ): # set args to "--bool", for instance
582
+
583
+ def gitConfig (key ):
584
+ if not _gitConfig .has_key (key ):
585
+ cmd = [ "git" , "config" , key ]
586
+ s = read_pipe (cmd , ignore_error = True )
587
+ _gitConfig [key ] = s .strip ()
588
+ return _gitConfig [key ]
589
+
590
+ def gitConfigBool (key ):
591
+ """Return a bool, using git config --bool. It is True only if the
592
+ variable is set to true, and False if set to false or not present
593
+ in the config."""
594
+
562
595
if not _gitConfig .has_key (key ):
563
- argsFilter = ""
564
- if args != None :
565
- argsFilter = "%s " % args
566
- cmd = "git config %s%s" % (argsFilter , key )
567
- _gitConfig [key ] = read_pipe (cmd , ignore_error = True ).strip ()
596
+ cmd = [ "git" , "config" , "--bool" , key ]
597
+ s = read_pipe (cmd , ignore_error = True )
598
+ v = s .strip ()
599
+ _gitConfig [key ] = v == "true"
568
600
return _gitConfig [key ]
569
601
570
602
def gitConfigList (key ):
571
603
if not _gitConfig .has_key (key ):
572
- _gitConfig [key ] = read_pipe ("git config --get-all %s" % key , ignore_error = True ).strip ().split (os .linesep )
604
+ s = read_pipe (["git" , "config" , "--get-all" , key ], ignore_error = True )
605
+ _gitConfig [key ] = s .strip ().split (os .linesep )
573
606
return _gitConfig [key ]
574
607
575
608
def p4BranchesInGit (branchesAreInRemotes = True ):
@@ -716,8 +749,7 @@ def p4PathStartsWith(path, prefix):
716
749
#
717
750
# we may or may not have a problem. If you have core.ignorecase=true,
718
751
# we treat DirA and dira as the same directory
719
- ignorecase = gitConfig ("core.ignorecase" , "--bool" ) == "true"
720
- if ignorecase :
752
+ if gitConfigBool ("core.ignorecase" ):
721
753
return path .lower ().startswith (prefix .lower ())
722
754
return path .startswith (prefix )
723
755
@@ -954,7 +986,7 @@ def __init__(self):
954
986
self .usage += " [name of git branch to submit into perforce depot]"
955
987
self .origin = ""
956
988
self .detectRenames = False
957
- self .preserveUser = gitConfig ("git-p4.preserveUser" ). lower () == "true"
989
+ self .preserveUser = gitConfigBool ("git-p4.preserveUser" )
958
990
self .dry_run = False
959
991
self .prepare_p4_only = False
960
992
self .conflict_behavior = None
@@ -1049,7 +1081,8 @@ def patchRCSKeywords(self, file, pattern):
1049
1081
def p4UserForCommit (self ,id ):
1050
1082
# Return the tuple (perforce user,git email) for a given git commit id
1051
1083
self .getUserMapFromPerforceServer ()
1052
- gitEmail = read_pipe ("git log --max-count=1 --format='%%ae' %s" % id )
1084
+ gitEmail = read_pipe (["git" , "log" , "--max-count=1" ,
1085
+ "--format=%ae" , id ])
1053
1086
gitEmail = gitEmail .strip ()
1054
1087
if not self .emails .has_key (gitEmail ):
1055
1088
return (None ,gitEmail )
@@ -1062,7 +1095,7 @@ def checkValidP4Users(self,commits):
1062
1095
(user ,email ) = self .p4UserForCommit (id )
1063
1096
if not user :
1064
1097
msg = "Cannot find p4 user for email %s in commit %s." % (email , id )
1065
- if gitConfig ( ' git-p4.allowMissingP4Users' ). lower () == "true" :
1098
+ if gitConfigBool ( " git-p4.allowMissingP4Users" ) :
1066
1099
print "%s" % msg
1067
1100
else :
1068
1101
die ("Error: %s\n Set git-p4.allowMissingP4Users to true to allow this." % msg )
@@ -1157,7 +1190,7 @@ def edit_template(self, template_file):
1157
1190
message. Return true if okay to continue with the submit."""
1158
1191
1159
1192
# if configured to skip the editing part, just submit
1160
- if gitConfig ("git-p4.skipSubmitEdit" ) == "true" :
1193
+ if gitConfigBool ("git-p4.skipSubmitEdit" ):
1161
1194
return True
1162
1195
1163
1196
# look at the modification time, to check later if the user saved
@@ -1173,7 +1206,7 @@ def edit_template(self, template_file):
1173
1206
1174
1207
# If the file was not saved, prompt to see if this patch should
1175
1208
# be skipped. But skip this verification step if configured so.
1176
- if gitConfig ("git-p4.skipSubmitEditCheck" ) == "true" :
1209
+ if gitConfigBool ("git-p4.skipSubmitEditCheck" ):
1177
1210
return True
1178
1211
1179
1212
# modification time updated means user saved the file
@@ -1231,6 +1264,9 @@ def applyCommit(self, id):
1231
1264
p4_edit (dest )
1232
1265
pureRenameCopy .discard (dest )
1233
1266
filesToChangeExecBit [dest ] = diff ['dst_mode' ]
1267
+ if self .isWindows :
1268
+ # turn off read-only attribute
1269
+ os .chmod (dest , stat .S_IWRITE )
1234
1270
os .unlink (dest )
1235
1271
editedFiles .add (dest )
1236
1272
elif modifier == "R" :
@@ -1249,6 +1285,8 @@ def applyCommit(self, id):
1249
1285
p4_edit (dest ) # with move: already open, writable
1250
1286
filesToChangeExecBit [dest ] = diff ['dst_mode' ]
1251
1287
if not self .p4HasMoveCommand :
1288
+ if self .isWindows :
1289
+ os .chmod (dest , stat .S_IWRITE )
1252
1290
os .unlink (dest )
1253
1291
filesToDelete .add (src )
1254
1292
editedFiles .add (dest )
@@ -1268,7 +1306,7 @@ def applyCommit(self, id):
1268
1306
1269
1307
# Patch failed, maybe it's just RCS keyword woes. Look through
1270
1308
# the patch to see if that's possible.
1271
- if gitConfig ("git-p4.attemptRCSCleanup" , "--bool" ) == "true" :
1309
+ if gitConfigBool ("git-p4.attemptRCSCleanup" ) :
1272
1310
file = None
1273
1311
pattern = None
1274
1312
kwfiles = {}
@@ -1289,6 +1327,10 @@ def applyCommit(self, id):
1289
1327
for file in kwfiles :
1290
1328
if verbose :
1291
1329
print "zapping %s with %s" % (line ,pattern )
1330
+ # File is being deleted, so not open in p4. Must
1331
+ # disable the read-only bit on windows.
1332
+ if self .isWindows and file not in editedFiles :
1333
+ os .chmod (file , stat .S_IWRITE )
1292
1334
self .patchRCSKeywords (file , kwfiles [file ])
1293
1335
fixed_rcs_keywords = True
1294
1336
@@ -1559,7 +1601,7 @@ def run(self, args):
1559
1601
sys .exit (128 )
1560
1602
1561
1603
self .useClientSpec = False
1562
- if gitConfig ("git-p4.useclientspec" , "--bool" ) == "true" :
1604
+ if gitConfigBool ("git-p4.useclientspec" ) :
1563
1605
self .useClientSpec = True
1564
1606
if self .useClientSpec :
1565
1607
self .clientSpecDirs = getClientSpec ()
@@ -1595,11 +1637,11 @@ def run(self, args):
1595
1637
self .check ()
1596
1638
1597
1639
commits = []
1598
- for line in read_pipe_lines ("git rev-list --no-merges %s..%s" % (self .origin , self .master )):
1640
+ for line in read_pipe_lines ([ "git" , " rev-list" , " --no-merges" , " %s..%s" % (self .origin , self .master )] ):
1599
1641
commits .append (line .strip ())
1600
1642
commits .reverse ()
1601
1643
1602
- if self .preserveUser or ( gitConfig ( "git-p4.skipUserNameCheck" ) == "true " ):
1644
+ if self .preserveUser or gitConfigBool ( "git-p4.skipUserNameCheck" ):
1603
1645
self .checkAuthorship = False
1604
1646
else :
1605
1647
self .checkAuthorship = True
@@ -1635,7 +1677,7 @@ def run(self, args):
1635
1677
else :
1636
1678
self .diffOpts += " -C%s" % detectCopies
1637
1679
1638
- if gitConfig ("git-p4.detectCopiesHarder" , "--bool" ) == "true" :
1680
+ if gitConfigBool ("git-p4.detectCopiesHarder" ) :
1639
1681
self .diffOpts += " --find-copies-harder"
1640
1682
1641
1683
#
@@ -1719,7 +1761,7 @@ def run(self, args):
1719
1761
"--format=format:%h %s" , c ])
1720
1762
print "You will have to do 'git p4 sync' and rebase."
1721
1763
1722
- if gitConfig ("git-p4.exportLabels" , "--bool" ) == "true" :
1764
+ if gitConfigBool ("git-p4.exportLabels" ) :
1723
1765
self .exportLabels = True
1724
1766
1725
1767
if self .exportLabels :
@@ -1989,7 +2031,6 @@ def __init__(self):
1989
2031
self .syncWithOrigin = True
1990
2032
self .importIntoRemotes = True
1991
2033
self .maxChanges = ""
1992
- self .isWindows = (platform .system () == "Windows" )
1993
2034
self .keepRepoPath = False
1994
2035
self .depotPaths = None
1995
2036
self .p4BranchesInGit = []
@@ -2134,7 +2175,14 @@ def streamOneP4File(self, file, contents):
2134
2175
# operations. utf16 is converted to ascii or utf8, perhaps.
2135
2176
# But ascii text saved as -t utf16 is completely mangled.
2136
2177
# Invoke print -o to get the real contents.
2178
+ #
2179
+ # On windows, the newlines will always be mangled by print, so put
2180
+ # them back too. This is not needed to the cygwin windows version,
2181
+ # just the native "NT" type.
2182
+ #
2137
2183
text = p4_read_pipe (['print' , '-q' , '-o' , '-' , file ['depotFile' ]])
2184
+ if p4_version_string ().find ("/NT" ) >= 0 :
2185
+ text = text .replace ("\r \n " , "\n " )
2138
2186
contents = [ text ]
2139
2187
2140
2188
if type_base == "apple" :
@@ -2150,15 +2198,6 @@ def streamOneP4File(self, file, contents):
2150
2198
print "\n Ignoring apple filetype file %s" % file ['depotFile' ]
2151
2199
return
2152
2200
2153
- # Perhaps windows wants unicode, utf16 newlines translated too;
2154
- # but this is not doing it.
2155
- if self .isWindows and type_base == "text" :
2156
- mangled = []
2157
- for data in contents :
2158
- data = data .replace ("\r \n " , "\n " )
2159
- mangled .append (data )
2160
- contents = mangled
2161
-
2162
2201
# Note that we do not try to de-mangle keywords on utf16 files,
2163
2202
# even though in theory somebody may want that.
2164
2203
pattern = p4_keywords_regexp_for_type (type_base , type_mods )
@@ -2636,7 +2675,8 @@ def importNewBranch(self, branch, maxChange):
2636
2675
2637
2676
def searchParent (self , parent , branch , target ):
2638
2677
parentFound = False
2639
- for blob in read_pipe_lines (["git" , "rev-list" , "--reverse" , "--no-merges" , parent ]):
2678
+ for blob in read_pipe_lines (["git" , "rev-list" , "--reverse" ,
2679
+ "--no-merges" , parent ]):
2640
2680
blob = blob .strip ()
2641
2681
if len (read_pipe (["git" , "diff-tree" , blob , target ])) == 0 :
2642
2682
parentFound = True
@@ -2707,7 +2747,7 @@ def importChanges(self, changes):
2707
2747
2708
2748
blob = None
2709
2749
if len (parent ) > 0 :
2710
- tempBranch = os . path . join ( self . tempBranchLocation , "% d" % (change ) )
2750
+ tempBranch = "%s/% d" % (self . tempBranchLocation , change )
2711
2751
if self .verbose :
2712
2752
print "Creating temporary branch: " + tempBranch
2713
2753
self .commit (description , filesForCommit , tempBranch )
@@ -2821,7 +2861,7 @@ def run(self, args):
2821
2861
# will use this after clone to set the variable
2822
2862
self .useClientSpec_from_options = True
2823
2863
else :
2824
- if gitConfig ("git-p4.useclientspec" , "--bool" ) == "true" :
2864
+ if gitConfigBool ("git-p4.useclientspec" ) :
2825
2865
self .useClientSpec = True
2826
2866
if self .useClientSpec :
2827
2867
self .clientSpecDirs = getClientSpec ()
@@ -3061,7 +3101,7 @@ def run(self, args):
3061
3101
sys .stdout .write ("%s " % b )
3062
3102
sys .stdout .write ("\n " )
3063
3103
3064
- if gitConfig ("git-p4.importLabels" , "--bool" ) == "true" :
3104
+ if gitConfigBool ("git-p4.importLabels" ) :
3065
3105
self .importLabels = True
3066
3106
3067
3107
if self .importLabels :
@@ -3179,6 +3219,7 @@ def run(self, args):
3179
3219
self .cloneExclude = ["/" + p for p in self .cloneExclude ]
3180
3220
for p in depotPaths :
3181
3221
if not p .startswith ("//" ):
3222
+ sys .stderr .write ('Depot paths must start with "//": %s\n ' % p )
3182
3223
return False
3183
3224
3184
3225
if not self .cloneDestination :
0 commit comments