Skip to content
This repository was archived by the owner on Nov 9, 2017. It is now read-only.

Commit 34022ba

Browse files
committed
Merge branch 'ks/p4-view-spec'
* ks/p4-view-spec: git p4: implement view spec wildcards with "p4 where" git p4 test: sanitize P4CHARSET
2 parents 6c34560 + 9d57c4a commit 34022ba

File tree

2 files changed

+61
-165
lines changed

2 files changed

+61
-165
lines changed

git-p4.py

Lines changed: 59 additions & 164 deletions
Original file line numberDiff line numberDiff line change
@@ -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

20081896
class 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"]))

t/lib-git-p4.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
4848
P4PORT=localhost:$P4DPORT
4949
P4CLIENT=client
5050
P4EDITOR=:
51-
export P4PORT P4CLIENT P4EDITOR
51+
unset P4CHARSET
52+
export P4PORT P4CLIENT P4EDITOR P4CHARSET
5253

5354
db="$TRASH_DIRECTORY/db"
5455
cli="$TRASH_DIRECTORY/cli"

0 commit comments

Comments
 (0)