Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

615 lines
23 KiB

  1. #!/usr/bin/env python
  2. #
  3. # build "my current enlistment" remotely
  4. # does a handful of steps:
  5. # 1. makes sure the users has ssh key auth setup to the target host (as automatic as possible)
  6. # 2. creates a p4 client on the remote host that's a mirror of their local client
  7. # 3. sync's the remote client to the same (submitted) change as the local client
  8. # 4. pickles up local changes, scp's them to the remote host, and applies them to the remote client
  9. # 5. runs vpc and make, reporting status/errors to the user
  10. #
  11. import getopt
  12. import getpass
  13. import marshal
  14. import os
  15. import p4helpers
  16. import stat
  17. import sys
  18. import subprocess
  19. import tempfile
  20. ##### Don't merge this block to another branch, this section needs to be altered to match the requirements
  21. ##### of the p4 branch you are merging into!!
  22. g_Branch = "//ValveGames/staging"
  23. # branchspec needs the leading \t to make the p4 formatting happy when making a changelist
  24. g_BranchSpec = "\t//ValveGames/staging/src/... //%s/src/..."
  25. g_VPCCommand = { 'linux' : "dedicated /dedicated /f /tf /dod /cstrike /hl2mp" , 'osx' : "port /tf /dod /portal /hl2 /episodic /hl2mp /cstrike" }
  26. #####
  27. #### merge block ends
  28. ####
  29. g_bVerbose = True
  30. g_bDebugVerbose = False
  31. g_bBatchMode = False
  32. g_bSimulateOnly = False
  33. g_lRemotePlatforms = [ 'linux', 'osx' ]
  34. g_lBuildConfigs = [ 'debug', 'release' ]
  35. g_szSSHBin = 'ssh'
  36. g_szSCPBin = 'scp'
  37. g_szVCodePickle = os.path.join( "src", "devtools", "vcodepickle.py" )
  38. g_szMoreBin = 'less'
  39. g_szSSHKeyDir = '.ssh'
  40. g_szSSHAgentAddKeyCmd = 'ssh-add'
  41. g_szCleanTarget = ''
  42. if sys.platform == 'win32':
  43. # relative to the top of the enlistment
  44. g_szSSHBin = 'src\\devtools\\bin\\putty\\plink.exe'
  45. g_szSCPBin = 'src\\devtools\\bin\\putty\\pscp.exe'
  46. g_szMoreBin = '%WINDIR%\\notepad.exe'
  47. g_szSSHKeyDir = 'ssh'
  48. g_szSSHKeyConvertCmd = 'start /wait src\\devtools\\bin\\putty\\puttygen.exe'
  49. g_szSSHAgentAddKeyCmd = 'src\\devtools\\bin\\putty\\pageant.exe'
  50. g_mapPlatformToBuildHostInfo = { "linux" : { "hostname" : "linuxpiston.valvesoftware.com",
  51. "sshkey" : { "win32" : { "regkey" : "Software\\SimonTatham\\Putty\\SshHostKeys",
  52. "valueName" : "rsa2@22:linuxpiston.valvesoftware.com",
  53. "value" : "0x23,0xb9a05c086f2b8fd5ffcb5270f4d4479e2462459cf6716e297bcf15aef2696f29ac28661f45b8a427e1e9e224eba3a96ceb88f821fddfba950722bcd1bcb46fca3a1065f5e17270d1de605091cc77ee839acbcb8ac09e6c36d10f517f294e9b033bc52f969511cfc2157a2c711de8d4a54ef8eab46d6aed7b38b0ddf3a35dd2412b48ab91378415d9a01c5d0ff2423ea059d8c5d38b342c106cc860989c65607887b552d599a018baee98f382d03a733ad0c26a91d9366df3b43bab72ea030856a85721379e71521f38280aa9aad36455810e3ac1c9ea53a829a92a92c3d6dbb7ee075618c1931ff075798e284e6c7871588e64abc9719d159819cfb729fb517d" },
  54. "posix": "linuxpiston.valvesoftware.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAuaBcCG8rj9X/y1Jw9NRHniRiRZz2cW4pe88VrvJpbymsKGYfRbikJ+Hp4iTro6ls64j4If3fupUHIrzRvLRvyjoQZfXhcnDR3mBQkcx37oOay8uKwJ5sNtEPUX8pTpsDO8UvlpURz8IVeixxHejUpU746rRtau17OLDd86Nd0kErSKuRN4QV2aAcXQ/yQj6gWdjF04s0LBBsyGCYnGVgeIe1UtWZoBi67pjzgtA6czrQwmqR2TZt87Q7q3LqAwhWqFchN55xUh84KAqpqtNkVYEOOsHJ6lOoKakqksPW27fuB1YYwZMf8HV5jihObHhxWI5kq8lxnRWYGc+3KftRfQ==" } },
  55. "osx" : { "hostname" : "macslave01.valvesoftware.com",
  56. "sshkey" : { "win32" : { "regkey" : "Software\\SimonTatham\\Putty\\SshHostKeys",
  57. "valueName" : "rsa2@22:macslave01.valvesoftware.com",
  58. "value" : "0x23,0xc50ecfe57fef329f442a652566fc8734fcf42f7c20beb2593ee55ce05c432a5047887ee28d6f24f3c60c5d6daf582fcd8d074f20de467893ad858ffa6809cc59427cde2c86536bf6c98810dc374b7afceb49a69b607fb29ce7eaa28751fcd78d45b59b409e665800e91b09a0615b16118bfbfebb638ef63d9bdd23a66a1cda493e17d529b4d9fcf96a8c73c947e86a0a41936b236c798a35620af65ae50459f4602ef1434f06f596cffa8dbebf985e588335e00a9f67e52c97e9d9b0cf420a04e92f56c124f430be4dc72e701244bbf005d361da048b9e8d3d56ce5d3fc45b083ded2315a7692bcd1ab7c197dd588fd695993442371aa6db863f17a3d0fbb1f9" },
  59. "posix": "macslave01.valvesoftware.com ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAxQ7P5X/vMp9EKmUlZvyHNPz0L3wgvrJZPuVc4FxDKlBHiH7ijW8k88YMXW2vWC/NjQdPIN5GeJOthY/6aAnMWUJ83iyGU2v2yYgQ3DdLevzrSaabYH+ynOfqoodR/NeNRbWbQJ5mWADpGwmgYVsWEYv7/rtjjvY9m90jpmoc2kk+F9UptNn8+WqMc8lH6GoKQZNrI2x5ijViCvZa5QRZ9GAu8UNPBvWWz/qNvr+YXliDNeAKn2flLJfp2bDPQgoE6S9WwST0ML5Nxy5wEkS78AXTYdoEi56NPVbOXT/EWwg97SMVp2krzRq3wZfdWI/WlZk0QjcaptuGPxej0Pux+Q==" } } }
  60. g_szFetchSSHPrivateKeyScriptlet = '''
  61. export LANG="C";
  62. KEYFILE=~/.ssh/id_rsa;
  63. if [ -f ${KEYFILE} -a -f ${KEYFILE}.pub ]; then
  64. echo "using existing ssh private/public key" >&2;
  65. else
  66. echo "generating ssh keypair" >&2;
  67. mkdir -p ~/.ssh;
  68. ssh-keygen -t rsa -b 1024 -f ${KEYFILE} -q -N "";
  69. fi;
  70. grep -q "`head -2 ${KEYFILE}.pub | tail -1`" ~/.ssh/authorized_keys;
  71. if [ $? -ne 0 ]; then
  72. echo "adding key to authorized keys file" >&2;
  73. cat ${KEYFILE}.pub >> ~/.ssh/authorized_keys;
  74. fi;
  75. cat ${KEYFILE};
  76. exit $?;'''
  77. g_szCreateClientScriptletTemplate = '''
  78. export LANG="C";
  79. export P4CLIENT=%(P4CLIENT)s;
  80. export P4PORT=perforce.valvesoftware.com:1666;
  81. mkdir -p P4Clients/${P4CLIENT};
  82. cd P4Clients/${P4CLIENT};
  83. echo "creating p4 client ${P4CLIENT}" >&2;
  84. p4 client -i << EOF
  85. Client: ${P4CLIENT}
  86. Owner: ${USER}
  87. Root: ${PWD}
  88. Options: noallwrite clobber nocompress unlocked nomodtime rmdir
  89. SubmitOptions: revertunchanged
  90. LineEnd: local
  91. View:
  92. %(VIEWSPEC)s
  93. EOF
  94. RET=$?;
  95. if [ $RET -ne 0 ]; then
  96. echo "client creation failed" >&2;
  97. exit $RET;
  98. fi;
  99. '''
  100. g_szRemoteP4ScriptletTemplate = '''
  101. export LANG="C";
  102. export P4CLIENT=%(P4CLIENT)s;
  103. export P4PORT=perforce.valvesoftware.com:1666;
  104. mkdir -p P4Clients/${P4CLIENT};
  105. cd P4Clients/${P4CLIENT};
  106. p4 %(P4COMMAND)s;
  107. exit $?;
  108. '''
  109. g_szRemoteUnpickleScriptletTemplate = '''
  110. export LANG="C";
  111. export P4CLIENT=%(P4CLIENT)s;
  112. export P4PORT=perforce.valvesoftware.com:1666;
  113. mkdir -p P4Clients/${P4CLIENT};
  114. cd P4Clients/${P4CLIENT};
  115. /usr/bin/env python ./src/devtools/vcodepickle.py --restore --file %(PICKLEFILE)s;
  116. exit $?;
  117. '''
  118. g_szRemoteBuildScriptletTemplate = '''
  119. export LANG="C";
  120. export P4CLIENT=%(P4CLIENT)s;
  121. export P4PORT=perforce.valvesoftware.com:1666;
  122. export BUILDLOG=remote_build.log
  123. export CRITWARNLOG=critical_warnings.log
  124. export SOLUTION=remote_build
  125. mkdir -p P4Clients/${P4CLIENT};
  126. cd P4Clients/${P4CLIENT}/src;
  127. cp /dev/null ${BUILDLOG}
  128. ./devtools/bin/vpc /mksln ${SOLUTION} +%(VPCGROUP)s >> ${BUILDLOG} 2>> ${BUILDLOG};
  129. echo -e "\n\n\n=================== Starting %(CONFIG)s Build ===================\n" >> ${BUILDLOG};
  130. make -f ${SOLUTION}.mak CFG=%(CONFIG)s -k %(TARGET)s >> ${BUILDLOG} 2>> ${BUILDLOG};
  131. BUILDFAIL=$?
  132. # look for warnings we promote to errors - needs to be kept
  133. # in sync with the buildbot rules
  134. grep "call will abort" ${BUILDLOG} > ${CRITWARNLOG};
  135. let "NOCRITICALWARNINGS=$?";
  136. grep "is used uninitialized" ${BUILDLOG} >> ${CRITWARNLOG};
  137. let "NOCRITICALWARNINGS=$NOCRITICALWARNINGS & $?";
  138. RET=1;
  139. if [ $BUILDFAIL -eq 0 -a $NOCRITICALWARNINGS -eq 1 ]; then
  140. RET=0;
  141. echo "BUILD SUCCESS";
  142. else
  143. echo "BUILD FAILED";
  144. fi;
  145. if [ $NOCRITICALWARNINGS -eq 0 ]; then
  146. echo "!!! The following warnings will be promoted to errors !!!" >&2
  147. echo >&2;
  148. cat ${CRITWARNLOG} >&2
  149. echo >&2
  150. fi;
  151. cat ${BUILDLOG} >&2
  152. exit $RET
  153. '''
  154. g_szRemoteVsignTestTemplate = '''
  155. export P4CLIENT=%(P4CLIENT)s;
  156. cd P4Clients/${P4CLIENT}/src;
  157. cp ./devtools/bin/vsign ./devtools/bin/vsign_test;
  158. chmod +w ./devtools/bin/vsign_test
  159. ./devtools/bin/vsign -signvalve ./devtools/bin/vsign_test;
  160. exit $?;
  161. '''
  162. g_szRemoteVsignSetPassphraseTemplate = '''
  163. export P4CLIENT=%(P4CLIENT)s;
  164. cd P4Clients/${P4CLIENT}/src;
  165. mkdir -p ~/Library/Application\ Support/Steam;
  166. ./devtools/bin/vsign -set_passphrase CodeSignature %(PASSPHRASE)s;
  167. exit $?;
  168. '''
  169. def usage():
  170. global g_mapPlatformToBuildHostInfo
  171. print "usage: ", sys.argv[0], " [options]"
  172. print ""
  173. print "-p,--platform= %s" % g_mapPlatformToBuildHostInfo.keys()
  174. print "-c,--config= [ 'debug', 'release' ] (default builds both )"
  175. print "-e,--exhaustive build all build configurations on all platforms"
  176. print "--rebuild do a clean build"
  177. print "-b,--batch supress user prompts"
  178. print "-r,--root= if you have a strange p4 client spec (cough, JoeR, cough)"
  179. print " specify the directory *containing* src"
  180. print "output related options:"
  181. print "-q,--quiet reduce spew"
  182. print "-d,--debug debug level spew"
  183. print "-s,--simulate dry-run"
  184. def runLocalCommand( szCommand, bWait=True ):
  185. global g_bSimulateOnly
  186. global g_bDebugVerbose
  187. if g_bDebugVerbose:
  188. print ">>> runLocalCommand( %s )\n" % szCommand
  189. if g_bSimulateOnly:
  190. return( 0, None, None )
  191. po = subprocess.Popen( szCommand, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=sys.stdin )
  192. if bWait:
  193. ( stdout, stderr ) = po.communicate()
  194. if g_bDebugVerbose:
  195. print stdout
  196. print stderr
  197. return ( po.returncode, stdout, stderr )
  198. else:
  199. return ( 0, "", "" )
  200. def runRemoteCommand( szRemoteUser, szRemoteHost, szCommand, bPromptForPasswd = False, bCheckReturn = True ):
  201. global g_bSimulateOnly
  202. global g_bDebugVerbose
  203. global g_bBatchMode
  204. global g_szSSHBin
  205. global g_mapPlatformToBuildHostInfo
  206. szSSHCmd = g_szSSHBin
  207. if bPromptForPasswd and g_bBatchMode:
  208. raise RuntimeError( "can't prompt for password in batch mode" )
  209. if sys.platform == 'win32':
  210. szSSHCmd += " -agent -batch"
  211. if bPromptForPasswd:
  212. szPasswd = getpass.getpass( "password for %s@%s: " % (szRemoteUser, szRemoteHost) )
  213. szSSHCmd += ' -pw "%s"' % szPasswd
  214. cmd = '%s %s@%s' % ( szSSHCmd,
  215. szRemoteUser,
  216. szRemoteHost )
  217. fd = fname = None
  218. if sys.platform == 'win32':
  219. # windows shell FTW
  220. (fd, fname) = tempfile.mkstemp()
  221. os.write( fd, szCommand )
  222. os.close( fd )
  223. cmd += " -m %s" % fname
  224. if g_bDebugVerbose: print "tmpfile %s contains %s" % ( fname, szCommand )
  225. else:
  226. cmd += " '%s'" % szCommand
  227. if g_bDebugVerbose:
  228. print ">>> runRemoteCommand( %s )\n" % cmd
  229. if g_bSimulateOnly:
  230. return ( 0, "simulation mode", "" )
  231. po = subprocess.Popen( cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=sys.stdin )
  232. ( stdout, stderr ) = po.communicate()
  233. if fd is not None:
  234. os.unlink( fname )
  235. if po.returncode != 0 and bCheckReturn:
  236. print "looks like something went wrong with a remote command"
  237. print ">>> %s " % cmd
  238. print "returned %d" % po.returncode
  239. if sys.platform == 'win32':
  240. print "tempfile contains %s" % szCommand
  241. print "produced stdout:"
  242. print stdout
  243. print ""
  244. print "produced stderr:"
  245. print stderr
  246. raise RuntimeError( "runRemoteCommand returned non-zero result" )
  247. if g_bDebugVerbose: print "return: %d\nstdout: %s\nstderr: %s" % ( po.returncode, stdout, stderr )
  248. return ( po.returncode, stdout, stderr )
  249. def addHostKeyToKnownHostKeys( szPlatformName ):
  250. global g_mapPlatformToBuildHostInfo
  251. global g_bDebugVerbose
  252. if sys.platform == 'win32':
  253. mapRegKeyInfo = g_mapPlatformToBuildHostInfo[ szPlatformName ][ 'sshkey' ][ 'win32' ]
  254. import _winreg
  255. try:
  256. knownHostsKey = _winreg.OpenKey( _winreg.HKEY_CURRENT_USER,
  257. mapRegKeyInfo[ 'regkey' ],
  258. sam = _winreg.KEY_SET_VALUE )
  259. if g_bDebugVerbose: print "OpenKey %s succeeded" % mapRegKeyInfo[ 'regkey' ]
  260. except:
  261. knownHostsKey = _winreg.CreateKey( _winreg.HKEY_CURRENT_USER,
  262. mapRegKeyInfo[ 'regkey' ] )
  263. if g_bDebugVerbose: print "CreateKey %s succeeded" % mapRegKeyInfo[ 'regkey' ]
  264. try:
  265. value, type = _winreg.QueryValueEx( knownHostsKey, mapRegKeyInfo[ 'valueName' ] )
  266. assert( type == _winreg.REG_SZ and value == mapRegKeyInfo[ 'value' ] )
  267. if g_bDebugVerbose: print "QueryValueEx %s succeeded" % mapRegKeyInfo[ 'valueName' ]
  268. except:
  269. _winreg.SetValueEx( knownHostsKey,
  270. mapRegKeyInfo[ 'valueName' ], False,
  271. _winreg.REG_SZ, mapRegKeyInfo[ 'value' ] )
  272. if g_bDebugVerbose: print "SetValueEx %s=%s succeeded" % ( mapRegKeyInfo[ 'valueName' ],
  273. mapRegKeyInfo[ 'value' ] )
  274. try:
  275. _winreg.CloseKey( knownHostsKey )
  276. if g_bDebugVerbose: print "CloseKey succeeded"
  277. except:
  278. pass
  279. else:
  280. assert( "implement addHostKeyToKnownKeys" )
  281. def calculateRemoteView( mapClientInfo, szRemoteClientName, szBranchName ):
  282. global g_BranchSpec
  283. szRemoteView = g_BranchSpec % ( szRemoteClientName )
  284. return szRemoteView
  285. def main():
  286. global g_bVerbose
  287. global g_bDebugVerbose
  288. global g_bSimulateOnly
  289. global g_bBatchMode
  290. global g_lRemotePlatforms
  291. global g_lBuildConfigs
  292. global g_szSSHKeyDir
  293. global g_szSSHAddKeyCmd
  294. global g_szCleanTarget
  295. global g_szSSHKeyConvertCmd
  296. global g_szVCodePickle
  297. global g_szMoreBin
  298. global g_szFetchSSHPrivateKeyScriptlet
  299. global g_szCreateClientScriptletTemplate
  300. global g_szRemoteP4ScriptletTemplate
  301. global g_szRemoteBuildScriptletTemplate
  302. global g_mapPlatformToBuildHostInfo
  303. global g_VPCCommand
  304. global g_Branch
  305. bSetBuildConfigs = False
  306. bSetBuildPlatform = False
  307. szBranchName = ""
  308. szUserName = getpass.getuser()
  309. szP4ChangeToSync = "all"
  310. clientInfo = p4helpers.GetClientInfo()
  311. szLocalClientName = clientInfo[ 'Client' ]
  312. szLocalClientRoot = clientInfo[ 'Root' ]
  313. try:
  314. opts, args = getopt.getopt( sys.argv[1:], "bdsvqp:c:r:e?l", [ "change=", "batch", "config=", "exhaustive", "debug", "simulate", "verbose", "quiet", "platform=", "root=", "rebuild", "limited-sync" ] )
  315. except getopt.GetoptError, e:
  316. print ""
  317. print "Argument error: ", e
  318. print ""
  319. usage()
  320. sys.exit(1)
  321. for o, a in opts:
  322. if o in ( "-?" ):
  323. usage()
  324. sys.exit(1)
  325. if o in ( "-b", "--batch" ):
  326. g_bBatchMode = True
  327. if o in ( "--rebuild" ):
  328. g_szCleanTarget = "clean"
  329. if o in ( "-c", "--config" ):
  330. if a not in [ 'debug', 'release' ]:
  331. raise RuntimeError( "configuration '%s' not understood" % a )
  332. g_lBuildConfigs = [ a ]
  333. bSetBuildConfigs = True;
  334. if o in ( "-r", "--root" ):
  335. szLocalClientRoot = a
  336. if o in ( "-e", "--exhaustive" ):
  337. g_lRemotePlatforms = g_mapPlatformToBuildHostInfo.keys()
  338. if o in ( "-p", "--platform" ):
  339. if a not in g_mapPlatformToBuildHostInfo.keys():
  340. raise RuntimeError( "platform '%s' not supported" % a )
  341. g_lRemotePlatforms = [ a ]
  342. bSetBuildPlatform = True
  343. if o in ( "-v", "--verbose" ):
  344. g_bVerbose = True
  345. if o in ( "-q", "--quiet" ):
  346. g_bVerbose = False
  347. g_bDebugVerbose = False
  348. if o in ( "-d", "--debug" ):
  349. g_bDebugVerbose = True
  350. if o in ( "-s", "--simulate" ):
  351. g_bSimulateOnly = True
  352. if o in ( "--change" ):
  353. szP4ChangeToSync = a
  354. if not os.getcwd().lower().startswith( clientInfo[ 'Root' ].lower() ):
  355. print ""
  356. print "I need to be run from the root (%s)" % szLocalClientRoot
  357. print "or any subdirectory of your p4 client (%s)" % szLocalClientName
  358. print ""
  359. print "If these values look wrong, make sure you have p4 configured"
  360. print "correctly for command-line use."
  361. sys.exit(1)
  362. try:
  363. p4path = p4helpers.P4Where( os.path.join( szLocalClientRoot, "src\..." ) )
  364. except:
  365. try:
  366. # try the cwd as the place src/ is to support "interesting" client specs
  367. szLocalClientRoot = os.path.split( os.getcwd() )[0]
  368. p4path = p4helpers.P4Where( os.path.join( szLocalClientRoot, "src\..." ) )
  369. except:
  370. print "couldn't find src where I expected it, perhaps you need the -r option?"
  371. usage()
  372. sys.exit(1)
  373. # on source only build release by default
  374. if ( bSetBuildConfigs == False ):
  375. g_lBuildConfigs = ['release' ]
  376. if not p4path.lower().startswith( g_Branch ):
  377. raise RunTimeError( "couldn't map local enlistment to staging branch" )
  378. # do everything relative to the client root directory
  379. os.chdir( szLocalClientRoot )
  380. if g_bVerbose: print "building configuration(s) %s on platform(s) %s" % ( g_lBuildConfigs, g_lRemotePlatforms )
  381. szLocallySyncedRevision = p4helpers.GetSyncedRevision( szLocalClientRoot )
  382. szPickleFile = 'vcodepickle_%s.zip' % szLocalClientName
  383. if g_bVerbose: print "pickling local changes to %s..." % szPickleFile,
  384. ( ret, stdout, stderr ) = runLocalCommand( '%s --backup --file %s -c %s --exclude "*.exe" --exclude "*.dll" --exclude "*.pdb" --include "*/src/*"' % ( g_szVCodePickle, szPickleFile, szP4ChangeToSync ) )
  385. if g_bVerbose: sys.stdout.flush(); print "done."
  386. for platform in g_lRemotePlatforms:
  387. if g_bVerbose: print "\nbuilding on platform %s\n" % ( platform )
  388. szRemoteHost = g_mapPlatformToBuildHostInfo[ platform ][ 'hostname' ]
  389. szRemoteClientName = "%s_%s_remote_build_%s" % ( szUserName, g_Branch.replace( "//", "" ).replace( "/", "_" ), szRemoteHost[ : szRemoteHost.find(".") ] )
  390. # figure out where the private key for this host would be, if we were to have one
  391. absKeyDirPath = os.path.join( os.path.expanduser("~"), g_szSSHKeyDir )
  392. szSSHPrivKeyFile = os.path.join( absKeyDirPath, 'id_rsa_%s@%s' % ( szUserName, szRemoteHost ) )
  393. if sys.platform == 'win32':
  394. szSSHPrivKeyFile += '.ppk'
  395. if g_bDebugVerbose: print "adding remote host key for %s to known keys..." % platform
  396. addHostKeyToKnownHostKeys( platform )
  397. # if we don't have a key for this host, run the scriptlet to create one
  398. if not os.path.exists( szSSHPrivKeyFile ):
  399. if not os.path.exists( absKeyDirPath ):
  400. os.makedirs( absKeyDirPath )
  401. if g_bVerbose: print "creating ssh public/private keypair..."
  402. ( ret, stdout, stderr ) = runRemoteCommand( szUserName, szRemoteHost, g_szFetchSSHPrivateKeyScriptlet, bPromptForPasswd = True )
  403. if not g_bSimulateOnly:
  404. assert( len( stdout ) )
  405. assert( not g_bBatchMode )
  406. f = open( szSSHPrivKeyFile, "w" )
  407. f.write( stdout )
  408. f.close()
  409. if sys.platform == 'win32':
  410. os.rename( szSSHPrivKeyFile, szSSHPrivKeyFile + ".tmp" )
  411. # let's assume we need to convert their key into putty format
  412. print ""
  413. print " !!!!! ACHTUNG !!!!!"
  414. print ""
  415. print "your private key doesn't seem to be in putty format (yet)."
  416. print ""
  417. print "I'm going to launch puttygen, which should present a dialog"
  418. print "saying it's successfully imported the key, and that you need"
  419. print "to save it in putty format before use."
  420. print ""
  421. print "1. click OK to dismiss this dialog"
  422. print "2. Choose File->Save Private Key"
  423. print "3. Confirm saving the key without a passphrase"
  424. print "4. paste this path into the save dialog:"
  425. print " %s" % szSSHPrivKeyFile.replace( "/", "\\" )
  426. print "5. quit puttygen"
  427. print ""
  428. raw_input( "Press return to continue: " )
  429. runLocalCommand( "%s %s" % ( g_szSSHKeyConvertCmd, szSSHPrivKeyFile + ".tmp" ) )
  430. os.remove( szSSHPrivKeyFile + ".tmp" )
  431. else:
  432. # on posix, ssh wants the keyfile to be tightly controlled
  433. os.chmod( szSSHPrivKeyFile, stat.S_IRUSR | stat.S_IWUSR )
  434. # try loading the ssh key into their agent
  435. if g_bDebugVerbose: print "adding private key to ssh authentication agent..."
  436. ( ret, stdout, stderr ) = runLocalCommand( "%s %s" % ( g_szSSHAgentAddKeyCmd, szSSHPrivKeyFile ), bWait = False )
  437. # figure out what the remote view should look like
  438. if g_bDebugVerbose: print "calculating remote view..."
  439. szRemoteView = calculateRemoteView( clientInfo, szRemoteClientName, szBranchName )
  440. if g_bDebugVerbose: print "remote view: %s" % szRemoteView
  441. # do the magic substituion on the client create scriptlet
  442. if g_bVerbose: print "syncing remote p4 client spec...",
  443. szClientCreateScriptlet = g_szCreateClientScriptletTemplate % { "P4CLIENT" : szRemoteClientName,
  444. "VIEWSPEC" : szRemoteView,
  445. "REVISION" : szLocallySyncedRevision }
  446. ( ret, stdout, stderr ) = runRemoteCommand( szUserName, szRemoteHost, szClientCreateScriptlet )
  447. if g_bVerbose: sys.stdout.flush(); print "done."
  448. if platform == "osx":
  449. if g_bVerbose: print "checking if vsign is set up...",
  450. szRemoteCheckVsignScriptlet = g_szRemoteVsignTestTemplate % { "P4CLIENT" : szRemoteClientName }
  451. ( ret, stdout, stderr ) = runRemoteCommand( szUserName, szRemoteHost, szRemoteCheckVsignScriptlet, False, False )
  452. if g_bVerbose: sys.stdout.flush(); print "done."
  453. if( ret != 0 ):
  454. passphrase = raw_input("Please enter code signature passphrase for public universe: ")
  455. if g_bVerbose: print "setting vsign passphrase...",
  456. szremoteSetVsignPassphraseScriptlet = g_szRemoteVsignSetPassphraseTemplate % { "P4CLIENT" : szRemoteClientName,
  457. "PASSPHRASE": passphrase}
  458. ( ret, stdout, stderr ) = runRemoteCommand( szUserName, szRemoteHost, szremoteSetVsignPassphraseScriptlet, False, False )
  459. if g_bVerbose: sys.stdout.flush(); print "done."
  460. if g_bVerbose: print "reverting any open files on remote p4client...",
  461. szClientSyncScriptlet = g_szRemoteP4ScriptletTemplate % { "P4CLIENT" : szRemoteClientName,
  462. "P4COMMAND": 'revert ...' }
  463. ( ret, stdout, stderr ) = runRemoteCommand( szUserName, szRemoteHost, szClientSyncScriptlet )
  464. if g_bVerbose: sys.stdout.flush(); print "done."
  465. if g_bVerbose: print "syncing remote p4client to changelist %s (this could take a while)..." % szLocallySyncedRevision,
  466. szClientSyncScriptlet = g_szRemoteP4ScriptletTemplate % { "P4CLIENT" : szRemoteClientName,
  467. "P4COMMAND": 'sync @%s' % szLocallySyncedRevision }
  468. ( ret, stdout, stderr ) = runRemoteCommand( szUserName, szRemoteHost, szClientSyncScriptlet )
  469. if g_bVerbose: sys.stdout.flush(); print "done."
  470. if g_bVerbose: print "transferring pickled changes...",
  471. ( ret, stdout, stderr ) = runLocalCommand( "%s %s %s@%s:P4Clients/%s/" % ( g_szSCPBin, szPickleFile, szUserName, szRemoteHost, szRemoteClientName ) )
  472. if g_bVerbose: sys.stdout.flush(); print "done."
  473. if g_bVerbose: print "applying changes to remote client...",
  474. szUnpickleScriptlet = g_szRemoteUnpickleScriptletTemplate % { "P4CLIENT" : szRemoteClientName,
  475. "PICKLEFILE": szPickleFile }
  476. ( ret, stdout, stderr ) = runRemoteCommand( szUserName, szRemoteHost, szUnpickleScriptlet )
  477. if g_bVerbose: sys.stdout.flush(); print "done."
  478. for buildConfig in g_lBuildConfigs:
  479. if g_bVerbose: print "running remote %s build..." % buildConfig,
  480. szBuildScriptlet = g_szRemoteBuildScriptletTemplate % { "P4CLIENT" : szRemoteClientName,
  481. "VPCGROUP" : g_VPCCommand[ platform ],
  482. "CONFIG" : buildConfig,
  483. "TARGET" : "%s all" % g_szCleanTarget }
  484. ( ret, stdout, stderr ) = runRemoteCommand( szUserName, szRemoteHost, szBuildScriptlet, bCheckReturn = False )
  485. if g_bVerbose: sys.stdout.flush(); print "done."
  486. if len(stderr):
  487. # figure out the correct newline character - can't we all just get along?
  488. NL = "\n"
  489. if sys.platform == "win32":
  490. NL = "\r\n"
  491. # look for a couple common cases
  492. errlines = stderr.split( "\n" )
  493. (fd, name) = tempfile.mkstemp( suffix=".txt" )
  494. os.write( fd, NL.join( errlines ) )
  495. os.close( fd )
  496. print "build output in file://%s" % name
  497. bFoundErrors = False
  498. for errline in errlines:
  499. if errline.lower().find( "error:" ) >= 0:
  500. bFoundErrors = True
  501. print " " + errline
  502. if ret !=0 and not bFoundErrors:
  503. iLines = 5
  504. print "first %d lines of build log:" % iLines
  505. print NL.join( errlines[ :iLines ] )
  506. if len(errlines) > iLines:
  507. print "..."
  508. if ret != 0:
  509. if not g_bBatchMode:
  510. resp = raw_input( "display full build log (Y/N)? " )
  511. if resp.lower() == "y":
  512. cmd = "%s %s" % ( g_szMoreBin, name )
  513. runLocalCommand( cmd )
  514. print stdout
  515. if ret != 0:
  516. break;
  517. if __name__ == '__main__':
  518. main()