@@ -780,11 +780,14 @@ def getClientSpec():
780
780
# dictionary of all client parameters
781
781
entry = specList [0 ]
782
782
783
+ # the //client/ name
784
+ client_name = entry ["Client" ]
785
+
783
786
# just the keys that start with "View"
784
787
view_keys = [ k for k in entry .keys () if k .startswith ("View" ) ]
785
788
786
789
# hold this new View
787
- view = View ()
790
+ view = View (client_name )
788
791
789
792
# append the lines, in order, to the view
790
793
for view_num in range (len (view_keys )):
@@ -1555,8 +1558,8 @@ def exportGitTags(self, gitTags):
1555
1558
for b in body :
1556
1559
labelTemplate += "\t " + b + "\n "
1557
1560
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
1560
1563
1561
1564
if self .dry_run :
1562
1565
print "Would create p4 label %s for tag" % name
@@ -1568,7 +1571,7 @@ def exportGitTags(self, gitTags):
1568
1571
1569
1572
# Use the label
1570
1573
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 ])
1572
1575
1573
1576
if verbose :
1574
1577
print "created p4 label for tag %s" % name
@@ -1796,117 +1799,16 @@ class View(object):
1796
1799
"""Represent a p4 view ("p4 help views"), and map files in a
1797
1800
repo according to the view."""
1798
1801
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 ):
1905
1803
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 = {}
1906
1807
1907
1808
def append (self , view_line ):
1908
1809
"""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."""
1910
1812
1911
1813
# Split the view line into exactly two words. P4 enforces
1912
1814
# structure on these lines that simplifies this quite a bit.
@@ -1934,76 +1836,62 @@ def append(self, view_line):
1934
1836
depot_side = view_line [0 :space_index ]
1935
1837
rhs_index = space_index + 1
1936
1838
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
-
1948
1839
# prefix + means overlay on previous mapping
1949
- overlay = False
1950
1840
if depot_side .startswith ("+" ):
1951
- overlay = True
1952
1841
depot_side = depot_side [1 :]
1953
1842
1954
- # prefix - means exclude this path
1843
+ # prefix - means exclude this path, leave out of mappings
1955
1844
exclude = False
1956
1845
if depot_side .startswith ("-" ):
1957
1846
exclude = True
1958
1847
depot_side = depot_side [1 :]
1959
1848
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 )
1962
1851
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 ):]
1967
1858
1968
- paths_filled = []
1969
- client_path = ""
1859
+ def update_client_spec_path_cache ( self , files ):
1860
+ """ Caching file paths by "p4 where" batch query " ""
1970
1861
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 ]
1973
1864
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
1976
1867
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" ])
1985
1879
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 ] = ""
2002
1884
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."""
2005
1889
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 ""
2007
1895
2008
1896
class P4Sync (Command , P4UserMap ):
2009
1897
delete_actions = ( "delete" , "move/delete" , "purge" )
@@ -2130,6 +2018,10 @@ def splitFilesIntoBranches(self, commit):
2130
2018
"""Look at each depotFile in the commit to figure out to what
2131
2019
branch it belongs."""
2132
2020
2021
+ if self .clientSpecDirs :
2022
+ files = self .extractFilesFromCommit (commit )
2023
+ self .clientSpecDirs .update_client_spec_path_cache (files )
2024
+
2133
2025
branches = {}
2134
2026
fnum = 0
2135
2027
while commit .has_key ("depotFile%s" % fnum ):
@@ -2379,6 +2271,9 @@ def commit(self, details, files, branch, parent = ""):
2379
2271
else :
2380
2272
sys .stderr .write ("Ignoring file outside of prefix: %s\n " % f ['path' ])
2381
2273
2274
+ if self .clientSpecDirs :
2275
+ self .clientSpecDirs .update_client_spec_path_cache (files )
2276
+
2382
2277
self .gitStream .write ("commit %s\n " % branch )
2383
2278
# gitStream.write("mark :%s\n" % details["change"])
2384
2279
self .committedChanges .add (int (details ["change" ]))
0 commit comments