@@ -780,11 +780,14 @@ def getClientSpec():
780780 # dictionary of all client parameters
781781 entry = specList [0 ]
782782
783+ # the //client/ name
784+ client_name = entry ["Client" ]
785+
783786 # just the keys that start with "View"
784787 view_keys = [ k for k in entry .keys () if k .startswith ("View" ) ]
785788
786789 # hold this new View
787- view = View ()
790+ view = View (client_name )
788791
789792 # append the lines, in order, to the view
790793 for view_num in range (len (view_keys )):
@@ -1555,8 +1558,8 @@ def exportGitTags(self, gitTags):
15551558 for b in body :
15561559 labelTemplate += "\t " + b + "\n "
15571560 labelTemplate += "View:\n "
1558- for mapping in clientSpec .mappings :
1559- labelTemplate += "\t %s\n " % mapping . depot_side . path
1561+ for depot_side in clientSpec .mappings :
1562+ labelTemplate += "\t %s\n " % depot_side
15601563
15611564 if self .dry_run :
15621565 print "Would create p4 label %s for tag" % name
@@ -1568,7 +1571,7 @@ def exportGitTags(self, gitTags):
15681571
15691572 # Use the label
15701573 p4_system (["tag" , "-l" , name ] +
1571- ["%s@%s" % (mapping . depot_side . path , changelist ) for mapping in clientSpec .mappings ])
1574+ ["%s@%s" % (depot_side , changelist ) for depot_side in clientSpec .mappings ])
15721575
15731576 if verbose :
15741577 print "created p4 label for tag %s" % name
@@ -1796,117 +1799,16 @@ class View(object):
17961799 """Represent a p4 view ("p4 help views"), and map files in a
17971800 repo according to the view."""
17981801
1799- class Path (object ):
1800- """A depot or client path, possibly containing wildcards.
1801- The only one supported is ... at the end, currently.
1802- Initialize with the full path, with //depot or //client."""
1803-
1804- def __init__ (self , path , is_depot ):
1805- self .path = path
1806- self .is_depot = is_depot
1807- self .find_wildcards ()
1808- # remember the prefix bit, useful for relative mappings
1809- m = re .match ("(//[^/]+/)" , self .path )
1810- if not m :
1811- die ("Path %s does not start with //prefix/" % self .path )
1812- prefix = m .group (1 )
1813- if not self .is_depot :
1814- # strip //client/ on client paths
1815- self .path = self .path [len (prefix ):]
1816-
1817- def find_wildcards (self ):
1818- """Make sure wildcards are valid, and set up internal
1819- variables."""
1820-
1821- self .ends_triple_dot = False
1822- # There are three wildcards allowed in p4 views
1823- # (see "p4 help views"). This code knows how to
1824- # handle "..." (only at the end), but cannot deal with
1825- # "%%n" or "*". Only check the depot_side, as p4 should
1826- # validate that the client_side matches too.
1827- if re .search (r'%%[1-9]' , self .path ):
1828- die ("Can't handle %%n wildcards in view: %s" % self .path )
1829- if self .path .find ("*" ) >= 0 :
1830- die ("Can't handle * wildcards in view: %s" % self .path )
1831- triple_dot_index = self .path .find ("..." )
1832- if triple_dot_index >= 0 :
1833- if triple_dot_index != len (self .path ) - 3 :
1834- die ("Can handle only single ... wildcard, at end: %s" %
1835- self .path )
1836- self .ends_triple_dot = True
1837-
1838- def ensure_compatible (self , other_path ):
1839- """Make sure the wildcards agree."""
1840- if self .ends_triple_dot != other_path .ends_triple_dot :
1841- die ("Both paths must end with ... if either does;\n " +
1842- "paths: %s %s" % (self .path , other_path .path ))
1843-
1844- def match_wildcards (self , test_path ):
1845- """See if this test_path matches us, and fill in the value
1846- of the wildcards if so. Returns a tuple of
1847- (True|False, wildcards[]). For now, only the ... at end
1848- is supported, so at most one wildcard."""
1849- if self .ends_triple_dot :
1850- dotless = self .path [:- 3 ]
1851- if test_path .startswith (dotless ):
1852- wildcard = test_path [len (dotless ):]
1853- return (True , [ wildcard ])
1854- else :
1855- if test_path == self .path :
1856- return (True , [])
1857- return (False , [])
1858-
1859- def match (self , test_path ):
1860- """Just return if it matches; don't bother with the wildcards."""
1861- b , _ = self .match_wildcards (test_path )
1862- return b
1863-
1864- def fill_in_wildcards (self , wildcards ):
1865- """Return the relative path, with the wildcards filled in
1866- if there are any."""
1867- if self .ends_triple_dot :
1868- return self .path [:- 3 ] + wildcards [0 ]
1869- else :
1870- return self .path
1871-
1872- class Mapping (object ):
1873- def __init__ (self , depot_side , client_side , overlay , exclude ):
1874- # depot_side is without the trailing /... if it had one
1875- self .depot_side = View .Path (depot_side , is_depot = True )
1876- self .client_side = View .Path (client_side , is_depot = False )
1877- self .overlay = overlay # started with "+"
1878- self .exclude = exclude # started with "-"
1879- assert not (self .overlay and self .exclude )
1880- self .depot_side .ensure_compatible (self .client_side )
1881-
1882- def __str__ (self ):
1883- c = " "
1884- if self .overlay :
1885- c = "+"
1886- if self .exclude :
1887- c = "-"
1888- return "View.Mapping: %s%s -> %s" % \
1889- (c , self .depot_side .path , self .client_side .path )
1890-
1891- def map_depot_to_client (self , depot_path ):
1892- """Calculate the client path if using this mapping on the
1893- given depot path; does not consider the effect of other
1894- mappings in a view. Even excluded mappings are returned."""
1895- matches , wildcards = self .depot_side .match_wildcards (depot_path )
1896- if not matches :
1897- return ""
1898- client_path = self .client_side .fill_in_wildcards (wildcards )
1899- return client_path
1900-
1901- #
1902- # View methods
1903- #
1904- def __init__ (self ):
1802+ def __init__ (self , client_name ):
19051803 self .mappings = []
1804+ self .client_prefix = "//%s/" % client_name
1805+ # cache results of "p4 where" to lookup client file locations
1806+ self .client_spec_path_cache = {}
19061807
19071808 def append (self , view_line ):
19081809 """Parse a view line, splitting it into depot and client
1909- sides. Append to self.mappings, preserving order."""
1810+ sides. Append to self.mappings, preserving order. This
1811+ is only needed for tag creation."""
19101812
19111813 # Split the view line into exactly two words. P4 enforces
19121814 # structure on these lines that simplifies this quite a bit.
@@ -1934,76 +1836,62 @@ def append(self, view_line):
19341836 depot_side = view_line [0 :space_index ]
19351837 rhs_index = space_index + 1
19361838
1937- if view_line [rhs_index ] == '"' :
1938- # Second word is double quoted. Make sure there is a
1939- # double quote at the end too.
1940- if not view_line .endswith ('"' ):
1941- die ("View line with rhs quote should end with one: %s" %
1942- view_line )
1943- # skip the quotes
1944- client_side = view_line [rhs_index + 1 :- 1 ]
1945- else :
1946- client_side = view_line [rhs_index :]
1947-
19481839 # prefix + means overlay on previous mapping
1949- overlay = False
19501840 if depot_side .startswith ("+" ):
1951- overlay = True
19521841 depot_side = depot_side [1 :]
19531842
1954- # prefix - means exclude this path
1843+ # prefix - means exclude this path, leave out of mappings
19551844 exclude = False
19561845 if depot_side .startswith ("-" ):
19571846 exclude = True
19581847 depot_side = depot_side [1 :]
19591848
1960- m = View . Mapping ( depot_side , client_side , overlay , exclude )
1961- self .mappings .append (m )
1849+ if not exclude :
1850+ self .mappings .append (depot_side )
19621851
1963- def map_in_client (self , depot_path ):
1964- """Return the relative location in the client where this
1965- depot file should live. Returns "" if the file should
1966- not be mapped in the client."""
1852+ def convert_client_path (self , clientFile ):
1853+ # chop off //client/ part to make it relative
1854+ if not clientFile .startswith (self .client_prefix ):
1855+ die ("No prefix '%s' on clientFile '%s'" %
1856+ (self .client_prefix , clientFile ))
1857+ return clientFile [len (self .client_prefix ):]
19671858
1968- paths_filled = []
1969- client_path = ""
1859+ def update_client_spec_path_cache ( self , files ):
1860+ """ Caching file paths by "p4 where" batch query " ""
19701861
1971- # look at later entries first
1972- for m in self .mappings [:: - 1 ]:
1862+ # List depot file paths exclude that already cached
1863+ fileArgs = [ f [ 'path' ] for f in files if f [ 'path' ] not in self .client_spec_path_cache ]
19731864
1974- # see where will this path end up in the client
1975- p = m . map_depot_to_client ( depot_path )
1865+ if len ( fileArgs ) == 0 :
1866+ return # All files in cache
19761867
1977- if p == "" :
1978- # Depot path does not belong in client. Must remember
1979- # this, as previous items should not cause files to
1980- # exist in this path either. Remember that the list is
1981- # being walked from the end, which has higher precedence.
1982- # Overlap mappings do not exclude previous mappings.
1983- if not m .overlay :
1984- paths_filled .append (m .client_side )
1868+ where_result = p4CmdList (["-x" , "-" , "where" ], stdin = fileArgs )
1869+ for res in where_result :
1870+ if "code" in res and res ["code" ] == "error" :
1871+ # assume error is "... file(s) not in client view"
1872+ continue
1873+ if "clientFile" not in res :
1874+ die ("No clientFile from 'p4 where %s'" % depot_path )
1875+ if "unmap" in res :
1876+ # it will list all of them, but only one not unmap-ped
1877+ continue
1878+ self .client_spec_path_cache [res ['depotFile' ]] = self .convert_client_path (res ["clientFile" ])
19851879
1986- else :
1987- # This mapping matched; no need to search any further.
1988- # But, the mapping could be rejected if the client path
1989- # has already been claimed by an earlier mapping (i.e.
1990- # one later in the list, which we are walking backwards).
1991- already_mapped_in_client = False
1992- for f in paths_filled :
1993- # this is View.Path.match
1994- if f .match (p ):
1995- already_mapped_in_client = True
1996- break
1997- if not already_mapped_in_client :
1998- # Include this file, unless it is from a line that
1999- # explicitly said to exclude it.
2000- if not m .exclude :
2001- client_path = p
1880+ # not found files or unmap files set to ""
1881+ for depotFile in fileArgs :
1882+ if depotFile not in self .client_spec_path_cache :
1883+ self .client_spec_path_cache [depotFile ] = ""
20021884
2003- # a match, even if rejected, always stops the search
2004- break
1885+ def map_in_client (self , depot_path ):
1886+ """Return the relative location in the client where this
1887+ depot file should live. Returns "" if the file should
1888+ not be mapped in the client."""
20051889
2006- return client_path
1890+ if depot_path in self .client_spec_path_cache :
1891+ return self .client_spec_path_cache [depot_path ]
1892+
1893+ die ( "Error: %s is not found in client spec path" % depot_path )
1894+ return ""
20071895
20081896class P4Sync (Command , P4UserMap ):
20091897 delete_actions = ( "delete" , "move/delete" , "purge" )
@@ -2130,6 +2018,10 @@ def splitFilesIntoBranches(self, commit):
21302018 """Look at each depotFile in the commit to figure out to what
21312019 branch it belongs."""
21322020
2021+ if self .clientSpecDirs :
2022+ files = self .extractFilesFromCommit (commit )
2023+ self .clientSpecDirs .update_client_spec_path_cache (files )
2024+
21332025 branches = {}
21342026 fnum = 0
21352027 while commit .has_key ("depotFile%s" % fnum ):
@@ -2383,6 +2275,9 @@ def commit(self, details, files, branch, parent = ""):
23832275 else :
23842276 sys .stderr .write ("Ignoring file outside of prefix: %s\n " % f ['path' ])
23852277
2278+ if self .clientSpecDirs :
2279+ self .clientSpecDirs .update_client_spec_path_cache (files )
2280+
23862281 self .gitStream .write ("commit %s\n " % branch )
23872282# gitStream.write("mark :%s\n" % details["change"])
23882283 self .committedChanges .add (int (details ["change" ]))
0 commit comments