[SCM]源码管理 - perforce python的使用

一 p4的API支持几乎所有的常用的语言
1)查看p4 API 主页: http://www.perforce.com/perforce/loadsupp.html#api (包含下载 和 p4script.pdf)

2)支持几乎所有的语言: 

Perforce C/C++ API
Perforce Java API
Perforce Perl API
Perforce Ruby API
Perforce Python API
Perforce PHP API
Perforce Objective-C API
P4COM, a COM Interface to the Perforce C++ API for Windows

 

二 p4python

1)安装(以windows为例)

下载和安装python2.6;(可以安装activepython)

下载和安装p4python26;(ftp://ftp.perforce.com/perforce/r09.2/bin.ntx86/p4python26.exe)

2)安装后(C:\Python26\Lib\site-packages)

文件:P4.py + P4.pyc + P4API.pyd + P4Python-2009.2-py2.6.egg-info。其中P4API.pyd为python对p4的extension模块,里面定义了 P4API.P4Adapter可惜看不到源码,P4.py 里面包含了p4 class的定义,p4class从P4API.P4Adapter继承。

3)p4.py

在p4.py中定义了

• P4
• P4Exception
• DepotFile
• Revision
• Integration
• MergeData
• Spec

其中主要的p4 class定义如下:

import  P4API

class  P4(P4API.P4Adapter):
    
""" Use this class to communicate with a Perforce server
    
    Instances of P4 will use the environment settings (including P4CONFIG)
    to determine the connection parameters such as P4CLIENT and P4PORT.
    
    This attributes can also be set separately before connecting.
    
    To run any Perforce commands, users of this class first need to run
    the connect() method.
    
    It is good practice to disconnect() after the program is complete.
    
"""
    
#  Constants useful for exception_level
     #  RAISE_ALL:     Errors and Warnings are raised as exceptions (default)
     #  RAISE_ERROR:   Only Errors are raised as exceptions
     #  RAISE_NONE:    No exceptions are raised, instead False is returned
    
    RAISE_ALL 
=  2
    RAISE_ERROR 
=  1
    RAISE_NONE 
=  0
    
    
def  __init__ (self,  * args,  ** kwlist): 
        P4API.P4Adapter.
__init__ (self,  * args,  ** kwlist)

    
def  __del__ (self):
        
if  self.debug  >  3 :
            
print  >> sys.stderr,  " P4.__del__() "
            
    
#  store the references to the created lambdas as a weakref to allow Python 
     #  to clean up the garbage. |The lambda as a closure stores a reference to self
     #  which causes a circular reference problem without the weakref
    
    
def  __getattr__ (self, name):
        
if  name.startswith( " run_ " ):
            cmd 
=  name[len( " run_ " ):]
            
return  lambda  * args: self.run(cmd,  * args)
        
elif  name.startswith( " delete_ " ):
            cmd 
=  name[len( " delete_ " ):]
            
return  lambda  * args: self.run(cmd,  " -d " * args)
        
elif  name.startswith( " fetch_ " ):
            cmd 
=  name[len( " fetch_ " ):]
            
return  lambda  * args: self.run(cmd,  " -o " * args)[0]
        
elif  name.startswith( " save_ " ):
            cmd 
=  name[len( " save_ " ):]
            
return  lambda  * args: self. __save (cmd,  * args)
        
elif  name.startswith( " parse_ " ):
            cmd 
=  name[len( " parse_ " ):]
            
return  lambda  * args: self.parse_spec(cmd,  * args)
        
elif  name.startswith( " format_ " ):
            cmd 
=  name[len( " format_ " ):]
            
return  lambda  * args: self.format_spec(cmd,  * args)
        
else :
            
raise  AttributeError, name
    
    
def  __save (self, cmd,  * args):
        self.input 
=  args[0]
        
return  self.run(cmd,  " -i " , args[ 1 :])
    
    
def  __repr__ (self):
        state 
=  " disconnected "
        
if  self.connected():
            state 
=  " connected "
            
        
return  " P4 [%s@%s %s] %s "  %  \
          (self.user, self.client, self.port, state)
    
    
def  identify(cls):
        
return  P4API.identify()
    identify 
=  classmethod(identify)
    
    
def  run(self,  * args):
        
" Generic run method "
        
return  P4API.P4Adapter.run(self,  * self. __flatten (args))
        
    
def  run_submit(self,  * args):
        
" Simplified submit - if any arguments is a dict, assume it to be the changeform "
        nargs 
=  list(args)
        form 
=  None
        
for  n, arg  in  enumerate(nargs):
            
if  isinstance( arg, dict):
                self.input 
=  arg
                nargs.pop(n)
                nargs.append(
" -i " )
                
break
        
return  self.run( " submit " * nargs)
    
    
def  run_login(self,  * args):
        
" Simple interface to make login easier "
        self.input 
=  self.password
        
return  self.run( " login " * args)

    
def  run_password( self, oldpass, newpass ):
        
" Simple interface to allow setting of the password "
        
if ( oldpass  and  len(oldpass)  >  0 ):
            self.input 
=  [ oldpass, newpass, newpass ]
        
else :
            self.input 
=  [ newpass, newpass ]
            
        
return  self.run(  " password "  )

    
#
     #  run_filelog: convert "p4 filelog" responses into objects with useful
     #               methods
     #
     #  Requires tagged output to be of any real use. If tagged output it not 
     #  enabled then you just get the raw data back
     #
     def  run_filelog( self,  * args ):
      raw 
=  self.run(  ' filelog ' , args )
      
if  ( not  self.tagged): 
          
#  untagged mode returns simple strings, which breaks the code below
           return  raw
      result 
=  []
      
for  h  in  raw:
          r 
=  None
          
if  isinstance( h, dict ):
              df 
=  DepotFile( h[  " depotFile "  ] )
              
for  n, rev  in  enumerate( h[  " rev "  ]):
                  
#  Create a new revision of this file ready for populating
                  r  =  df.new_revision()
                  
#  Populate the base attributes of each revision
                  r.rev  =  int( rev )
                  r.change 
=  int( h[  " change "  ][ n ] )
                  r.action 
=  h[  " action "  ][ n ] 
                  r.type 
=  h[  " type "  ][ n ]
                  r.time 
=  datetime.datetime.utcfromtimestamp( int( h[  " time "  ][ n ]) )
                  r.user 
=  h[  " user "  ][ n ]
                  r.client 
=  h[  " client "  ][ n ]
                  r.desc 
=  h[  " desc "  ][ n ]
                  
if  " digest "  in  h:
                    r.digest 
=  h[  " digest "  ][ n ]
                  
if  " fileSize "  in  h:
                    r.fileSize 
=  h[  " fileSize "  ][ n ]

                  
#  Now if there are any integration records for this revision,
                   #  add them in too
                  
                  
if  ( not  " how "  in  h)  or  (n  >=  len(h[ " how " ])  or  h[ " how " ][n]  ==  None):
                      
continue
                  
else :
                      
for  m, how  in  enumerate( h[  " how "  ][ n ] ):
                          file 
=  h[  " file "  ][ n ][ m ]
                          srev 
=  string.lstrip(h[  " srev "  ][ n ][ m ],  ' # ' )
                          erev 
=  string.lstrip(h[  " erev "  ][ n ][ m ],  ' # ' )
                          
                          
if  srev  ==  " none " :
                              srev 
=  0
                          
else :
                              srev 
=  int( srev )
                        
                          
if  erev  ==  " none " :
                              erev 
=  0
                          
else :
                              erev 
=  int( erev )
                              
                          r.integration( how, file, srev, erev )
          
else :
              r 
=  h
          result.append( df )
      
return  result

    
def  run_print(self,  * args):
      raw 
=  self.run( ' print ' , args)
      result 
=  [raw.pop(0),  "" ]
      
      
for  line  in  raw:
          result[
- 1 +=  line
      
return  result
    
    
def  run_resolve(self,  * args,  ** kargs):
        myResolver 
=  Resolver()
        
if  " resolver "  in  kargs: 
            myResolver 
=  kargs[ " resolver " ]
            
        savedResolver 
=  self.resolver
        self.resolver 
=  myResolver
        result 
=  self.run( " resolve " , args)
        self.resolver 
=  savedResolver
        
        
return  result
    
    
def  __flatten (self, args):
        result 
=  []
        
if  isinstance(args, tuple)  or  isinstance(args, list):
            
for  i  in  args:
                result.extend(self.
__flatten (i))
        
else :
            result.append(args)
        
return  tuple(result)

    
def  __enter__ ( self ):
        
return  self
        
    
def  __exit__ ( self, exc_type, exc_val, exc_tb ):
        
if  self.connected():
            self.disconnect()
        
return  True
        
    
def  connect( self ):
        P4API.P4Adapter.connect( self )
        
return  self
    
    @contextmanager
    
def  while_tagged( self, t ):
        old 
=  self.tagged
        self.tagged 
=  t
        
yield
        self.tagged 
=  old
    
    @contextmanager
    
def  at_exception_level( self, e ):
        old 
=  self.exception_level
        self.exception_level 
=  e
        
yield
        self.exception_level 
=  old
        
    @contextmanager
    
def  saved_context( self ,  ** kargs):
        
""" Saves the context of this p4 object and restores it again at the end of the block """
    
        saved_context 
=  {}
        
for  attr  in  self. __members__ :
            saved_context[attr] 
=  getattr(self, attr)
    
        
for  (k,v)  in  kargs.items():
            setattr( self, k, v)
        
        
yield
        
        
#  now restore the context again. Ignore AttributeError exception
         #  Exception is expected because some attributes only have getters, no setters
        
        
for  (k,v)  in  saved_context.items():
            
try :
                setattr( self, k, v )
            
except  AttributeError:
                
pass  #  expected for server_level and p4config_file

 

三 实例

1)p4info.py

from  P4  import  P4,P4Exception 

p4 
=  P4() 
p4.port 
=  " localhost:1666 "
p4.user 
=  " AAA "
p4.password 
=  " aaa "
p4.client 
=  " TestProject_AAA "  

try
  p4.connect() 
  info 
=  p4.run( " info "
  
for  key  in  info[0]: 
    
print  key,  " = " , info[0][key]
  p4.disconnect() 
except  P4Exception:
  
for  e  in  p4.errors: 
    
print  e

结果:

[SCM]源码管理 - perforce python的使用_第1张图片

 

2)p4sync.py 

from  P4  import  P4, P4Exception

p4 
=  P4() 
p4.port 
=  " localhost:1666 "
p4.user 
=  " AAA "
p4.password 
=  " aaa "
p4.client 
=  " TestProject_AAA "  

try :
  p4.connect()
  p4.exception_level 
=  1  #  ignore "File(s) up-to-date"
  files  =  p4.run_sync()
  
for  file  in  files:
    
for  key  in  file.keys():
      
print  key, " : " ,file[key]
    
print  " ---------- "
except  P4Exception:
  
for  e  in  p4.errors:
    
print  e
finally :
  p4.disconnect()

结果:

[SCM]源码管理 - perforce python的使用_第2张图片

 

3)p4submit.py

from  P4  import  P4

p4 
=  P4()
p4.host 
=  " localhost "
p4.port 
=  " 1666 "
p4.user 
=  " AAA "
p4.password 
=  " aaa "
p4.client 
=  " TestProject_AAA "

p4.connect()
changeSpec 
=  p4.run_change(  " -o "  )
change 
=  changeSpec[0]
change[
" Description " =  " Autosubmitted changelist "

p4.run_edit(
" //depot/TestProject/addfile.txt " )

change[
" Files " =  [ " //depot/TestProject/addfile.txt " ]
p4.input 
=  change
p4.run_submit( 
" -i "  )
p4.disconnect()

 

所有的p4 command 都可以使用p4.run_command()或p4.run(command)来调用。

 

四 超级详细的帮助文档:

http://www.perforce.com/perforce/doc.current/manuals/p4script/03_python.html
 

 

完!

你可能感兴趣的:([SCM]源码管理 - perforce python的使用)