Merge branch 'ks/p4-view-spec'
* ks/p4-view-spec: git p4: implement view spec wildcards with "p4 where" git p4 test: sanitize P4CHARSET
This commit is contained in:
commit
34022ba21a
225
git-p4.py
225
git-p4.py
@ -780,11 +780,14 @@ def getClientSpec():
|
|||||||
# dictionary of all client parameters
|
# dictionary of all client parameters
|
||||||
entry = specList[0]
|
entry = specList[0]
|
||||||
|
|
||||||
|
# the //client/ name
|
||||||
|
client_name = entry["Client"]
|
||||||
|
|
||||||
# just the keys that start with "View"
|
# just the keys that start with "View"
|
||||||
view_keys = [ k for k in entry.keys() if k.startswith("View") ]
|
view_keys = [ k for k in entry.keys() if k.startswith("View") ]
|
||||||
|
|
||||||
# hold this new View
|
# hold this new View
|
||||||
view = View()
|
view = View(client_name)
|
||||||
|
|
||||||
# append the lines, in order, to the view
|
# append the lines, in order, to the view
|
||||||
for view_num in range(len(view_keys)):
|
for view_num in range(len(view_keys)):
|
||||||
@ -1555,8 +1558,8 @@ class P4Submit(Command, P4UserMap):
|
|||||||
for b in body:
|
for b in body:
|
||||||
labelTemplate += "\t" + b + "\n"
|
labelTemplate += "\t" + b + "\n"
|
||||||
labelTemplate += "View:\n"
|
labelTemplate += "View:\n"
|
||||||
for mapping in clientSpec.mappings:
|
for depot_side in clientSpec.mappings:
|
||||||
labelTemplate += "\t%s\n" % mapping.depot_side.path
|
labelTemplate += "\t%s\n" % depot_side
|
||||||
|
|
||||||
if self.dry_run:
|
if self.dry_run:
|
||||||
print "Would create p4 label %s for tag" % name
|
print "Would create p4 label %s for tag" % name
|
||||||
@ -1568,7 +1571,7 @@ class P4Submit(Command, P4UserMap):
|
|||||||
|
|
||||||
# Use the label
|
# Use the label
|
||||||
p4_system(["tag", "-l", name] +
|
p4_system(["tag", "-l", name] +
|
||||||
["%s@%s" % (mapping.depot_side.path, changelist) for mapping in clientSpec.mappings])
|
["%s@%s" % (depot_side, changelist) for depot_side in clientSpec.mappings])
|
||||||
|
|
||||||
if verbose:
|
if verbose:
|
||||||
print "created p4 label for tag %s" % name
|
print "created p4 label for tag %s" % name
|
||||||
@ -1796,117 +1799,16 @@ class View(object):
|
|||||||
"""Represent a p4 view ("p4 help views"), and map files in a
|
"""Represent a p4 view ("p4 help views"), and map files in a
|
||||||
repo according to the view."""
|
repo according to the view."""
|
||||||
|
|
||||||
class Path(object):
|
def __init__(self, client_name):
|
||||||
"""A depot or client path, possibly containing wildcards.
|
|
||||||
The only one supported is ... at the end, currently.
|
|
||||||
Initialize with the full path, with //depot or //client."""
|
|
||||||
|
|
||||||
def __init__(self, path, is_depot):
|
|
||||||
self.path = path
|
|
||||||
self.is_depot = is_depot
|
|
||||||
self.find_wildcards()
|
|
||||||
# remember the prefix bit, useful for relative mappings
|
|
||||||
m = re.match("(//[^/]+/)", self.path)
|
|
||||||
if not m:
|
|
||||||
die("Path %s does not start with //prefix/" % self.path)
|
|
||||||
prefix = m.group(1)
|
|
||||||
if not self.is_depot:
|
|
||||||
# strip //client/ on client paths
|
|
||||||
self.path = self.path[len(prefix):]
|
|
||||||
|
|
||||||
def find_wildcards(self):
|
|
||||||
"""Make sure wildcards are valid, and set up internal
|
|
||||||
variables."""
|
|
||||||
|
|
||||||
self.ends_triple_dot = False
|
|
||||||
# There are three wildcards allowed in p4 views
|
|
||||||
# (see "p4 help views"). This code knows how to
|
|
||||||
# handle "..." (only at the end), but cannot deal with
|
|
||||||
# "%%n" or "*". Only check the depot_side, as p4 should
|
|
||||||
# validate that the client_side matches too.
|
|
||||||
if re.search(r'%%[1-9]', self.path):
|
|
||||||
die("Can't handle %%n wildcards in view: %s" % self.path)
|
|
||||||
if self.path.find("*") >= 0:
|
|
||||||
die("Can't handle * wildcards in view: %s" % self.path)
|
|
||||||
triple_dot_index = self.path.find("...")
|
|
||||||
if triple_dot_index >= 0:
|
|
||||||
if triple_dot_index != len(self.path) - 3:
|
|
||||||
die("Can handle only single ... wildcard, at end: %s" %
|
|
||||||
self.path)
|
|
||||||
self.ends_triple_dot = True
|
|
||||||
|
|
||||||
def ensure_compatible(self, other_path):
|
|
||||||
"""Make sure the wildcards agree."""
|
|
||||||
if self.ends_triple_dot != other_path.ends_triple_dot:
|
|
||||||
die("Both paths must end with ... if either does;\n" +
|
|
||||||
"paths: %s %s" % (self.path, other_path.path))
|
|
||||||
|
|
||||||
def match_wildcards(self, test_path):
|
|
||||||
"""See if this test_path matches us, and fill in the value
|
|
||||||
of the wildcards if so. Returns a tuple of
|
|
||||||
(True|False, wildcards[]). For now, only the ... at end
|
|
||||||
is supported, so at most one wildcard."""
|
|
||||||
if self.ends_triple_dot:
|
|
||||||
dotless = self.path[:-3]
|
|
||||||
if test_path.startswith(dotless):
|
|
||||||
wildcard = test_path[len(dotless):]
|
|
||||||
return (True, [ wildcard ])
|
|
||||||
else:
|
|
||||||
if test_path == self.path:
|
|
||||||
return (True, [])
|
|
||||||
return (False, [])
|
|
||||||
|
|
||||||
def match(self, test_path):
|
|
||||||
"""Just return if it matches; don't bother with the wildcards."""
|
|
||||||
b, _ = self.match_wildcards(test_path)
|
|
||||||
return b
|
|
||||||
|
|
||||||
def fill_in_wildcards(self, wildcards):
|
|
||||||
"""Return the relative path, with the wildcards filled in
|
|
||||||
if there are any."""
|
|
||||||
if self.ends_triple_dot:
|
|
||||||
return self.path[:-3] + wildcards[0]
|
|
||||||
else:
|
|
||||||
return self.path
|
|
||||||
|
|
||||||
class Mapping(object):
|
|
||||||
def __init__(self, depot_side, client_side, overlay, exclude):
|
|
||||||
# depot_side is without the trailing /... if it had one
|
|
||||||
self.depot_side = View.Path(depot_side, is_depot=True)
|
|
||||||
self.client_side = View.Path(client_side, is_depot=False)
|
|
||||||
self.overlay = overlay # started with "+"
|
|
||||||
self.exclude = exclude # started with "-"
|
|
||||||
assert not (self.overlay and self.exclude)
|
|
||||||
self.depot_side.ensure_compatible(self.client_side)
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
c = " "
|
|
||||||
if self.overlay:
|
|
||||||
c = "+"
|
|
||||||
if self.exclude:
|
|
||||||
c = "-"
|
|
||||||
return "View.Mapping: %s%s -> %s" % \
|
|
||||||
(c, self.depot_side.path, self.client_side.path)
|
|
||||||
|
|
||||||
def map_depot_to_client(self, depot_path):
|
|
||||||
"""Calculate the client path if using this mapping on the
|
|
||||||
given depot path; does not consider the effect of other
|
|
||||||
mappings in a view. Even excluded mappings are returned."""
|
|
||||||
matches, wildcards = self.depot_side.match_wildcards(depot_path)
|
|
||||||
if not matches:
|
|
||||||
return ""
|
|
||||||
client_path = self.client_side.fill_in_wildcards(wildcards)
|
|
||||||
return client_path
|
|
||||||
|
|
||||||
#
|
|
||||||
# View methods
|
|
||||||
#
|
|
||||||
def __init__(self):
|
|
||||||
self.mappings = []
|
self.mappings = []
|
||||||
|
self.client_prefix = "//%s/" % client_name
|
||||||
|
# cache results of "p4 where" to lookup client file locations
|
||||||
|
self.client_spec_path_cache = {}
|
||||||
|
|
||||||
def append(self, view_line):
|
def append(self, view_line):
|
||||||
"""Parse a view line, splitting it into depot and client
|
"""Parse a view line, splitting it into depot and client
|
||||||
sides. Append to self.mappings, preserving order."""
|
sides. Append to self.mappings, preserving order. This
|
||||||
|
is only needed for tag creation."""
|
||||||
|
|
||||||
# Split the view line into exactly two words. P4 enforces
|
# Split the view line into exactly two words. P4 enforces
|
||||||
# structure on these lines that simplifies this quite a bit.
|
# structure on these lines that simplifies this quite a bit.
|
||||||
@ -1934,76 +1836,62 @@ class View(object):
|
|||||||
depot_side = view_line[0:space_index]
|
depot_side = view_line[0:space_index]
|
||||||
rhs_index = space_index + 1
|
rhs_index = space_index + 1
|
||||||
|
|
||||||
if view_line[rhs_index] == '"':
|
|
||||||
# Second word is double quoted. Make sure there is a
|
|
||||||
# double quote at the end too.
|
|
||||||
if not view_line.endswith('"'):
|
|
||||||
die("View line with rhs quote should end with one: %s" %
|
|
||||||
view_line)
|
|
||||||
# skip the quotes
|
|
||||||
client_side = view_line[rhs_index+1:-1]
|
|
||||||
else:
|
|
||||||
client_side = view_line[rhs_index:]
|
|
||||||
|
|
||||||
# prefix + means overlay on previous mapping
|
# prefix + means overlay on previous mapping
|
||||||
overlay = False
|
|
||||||
if depot_side.startswith("+"):
|
if depot_side.startswith("+"):
|
||||||
overlay = True
|
|
||||||
depot_side = depot_side[1:]
|
depot_side = depot_side[1:]
|
||||||
|
|
||||||
# prefix - means exclude this path
|
# prefix - means exclude this path, leave out of mappings
|
||||||
exclude = False
|
exclude = False
|
||||||
if depot_side.startswith("-"):
|
if depot_side.startswith("-"):
|
||||||
exclude = True
|
exclude = True
|
||||||
depot_side = depot_side[1:]
|
depot_side = depot_side[1:]
|
||||||
|
|
||||||
m = View.Mapping(depot_side, client_side, overlay, exclude)
|
if not exclude:
|
||||||
self.mappings.append(m)
|
self.mappings.append(depot_side)
|
||||||
|
|
||||||
|
def convert_client_path(self, clientFile):
|
||||||
|
# chop off //client/ part to make it relative
|
||||||
|
if not clientFile.startswith(self.client_prefix):
|
||||||
|
die("No prefix '%s' on clientFile '%s'" %
|
||||||
|
(self.client_prefix, clientFile))
|
||||||
|
return clientFile[len(self.client_prefix):]
|
||||||
|
|
||||||
|
def update_client_spec_path_cache(self, files):
|
||||||
|
""" Caching file paths by "p4 where" batch query """
|
||||||
|
|
||||||
|
# List depot file paths exclude that already cached
|
||||||
|
fileArgs = [f['path'] for f in files if f['path'] not in self.client_spec_path_cache]
|
||||||
|
|
||||||
|
if len(fileArgs) == 0:
|
||||||
|
return # All files in cache
|
||||||
|
|
||||||
|
where_result = p4CmdList(["-x", "-", "where"], stdin=fileArgs)
|
||||||
|
for res in where_result:
|
||||||
|
if "code" in res and res["code"] == "error":
|
||||||
|
# assume error is "... file(s) not in client view"
|
||||||
|
continue
|
||||||
|
if "clientFile" not in res:
|
||||||
|
die("No clientFile from 'p4 where %s'" % depot_path)
|
||||||
|
if "unmap" in res:
|
||||||
|
# it will list all of them, but only one not unmap-ped
|
||||||
|
continue
|
||||||
|
self.client_spec_path_cache[res['depotFile']] = self.convert_client_path(res["clientFile"])
|
||||||
|
|
||||||
|
# not found files or unmap files set to ""
|
||||||
|
for depotFile in fileArgs:
|
||||||
|
if depotFile not in self.client_spec_path_cache:
|
||||||
|
self.client_spec_path_cache[depotFile] = ""
|
||||||
|
|
||||||
def map_in_client(self, depot_path):
|
def map_in_client(self, depot_path):
|
||||||
"""Return the relative location in the client where this
|
"""Return the relative location in the client where this
|
||||||
depot file should live. Returns "" if the file should
|
depot file should live. Returns "" if the file should
|
||||||
not be mapped in the client."""
|
not be mapped in the client."""
|
||||||
|
|
||||||
paths_filled = []
|
if depot_path in self.client_spec_path_cache:
|
||||||
client_path = ""
|
return self.client_spec_path_cache[depot_path]
|
||||||
|
|
||||||
# look at later entries first
|
die( "Error: %s is not found in client spec path" % depot_path )
|
||||||
for m in self.mappings[::-1]:
|
return ""
|
||||||
|
|
||||||
# see where will this path end up in the client
|
|
||||||
p = m.map_depot_to_client(depot_path)
|
|
||||||
|
|
||||||
if p == "":
|
|
||||||
# Depot path does not belong in client. Must remember
|
|
||||||
# this, as previous items should not cause files to
|
|
||||||
# exist in this path either. Remember that the list is
|
|
||||||
# being walked from the end, which has higher precedence.
|
|
||||||
# Overlap mappings do not exclude previous mappings.
|
|
||||||
if not m.overlay:
|
|
||||||
paths_filled.append(m.client_side)
|
|
||||||
|
|
||||||
else:
|
|
||||||
# This mapping matched; no need to search any further.
|
|
||||||
# But, the mapping could be rejected if the client path
|
|
||||||
# has already been claimed by an earlier mapping (i.e.
|
|
||||||
# one later in the list, which we are walking backwards).
|
|
||||||
already_mapped_in_client = False
|
|
||||||
for f in paths_filled:
|
|
||||||
# this is View.Path.match
|
|
||||||
if f.match(p):
|
|
||||||
already_mapped_in_client = True
|
|
||||||
break
|
|
||||||
if not already_mapped_in_client:
|
|
||||||
# Include this file, unless it is from a line that
|
|
||||||
# explicitly said to exclude it.
|
|
||||||
if not m.exclude:
|
|
||||||
client_path = p
|
|
||||||
|
|
||||||
# a match, even if rejected, always stops the search
|
|
||||||
break
|
|
||||||
|
|
||||||
return client_path
|
|
||||||
|
|
||||||
class P4Sync(Command, P4UserMap):
|
class P4Sync(Command, P4UserMap):
|
||||||
delete_actions = ( "delete", "move/delete", "purge" )
|
delete_actions = ( "delete", "move/delete", "purge" )
|
||||||
@ -2130,6 +2018,10 @@ class P4Sync(Command, P4UserMap):
|
|||||||
"""Look at each depotFile in the commit to figure out to what
|
"""Look at each depotFile in the commit to figure out to what
|
||||||
branch it belongs."""
|
branch it belongs."""
|
||||||
|
|
||||||
|
if self.clientSpecDirs:
|
||||||
|
files = self.extractFilesFromCommit(commit)
|
||||||
|
self.clientSpecDirs.update_client_spec_path_cache(files)
|
||||||
|
|
||||||
branches = {}
|
branches = {}
|
||||||
fnum = 0
|
fnum = 0
|
||||||
while commit.has_key("depotFile%s" % fnum):
|
while commit.has_key("depotFile%s" % fnum):
|
||||||
@ -2383,6 +2275,9 @@ class P4Sync(Command, P4UserMap):
|
|||||||
else:
|
else:
|
||||||
sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
|
sys.stderr.write("Ignoring file outside of prefix: %s\n" % f['path'])
|
||||||
|
|
||||||
|
if self.clientSpecDirs:
|
||||||
|
self.clientSpecDirs.update_client_spec_path_cache(files)
|
||||||
|
|
||||||
self.gitStream.write("commit %s\n" % branch)
|
self.gitStream.write("commit %s\n" % branch)
|
||||||
# gitStream.write("mark :%s\n" % details["change"])
|
# gitStream.write("mark :%s\n" % details["change"])
|
||||||
self.committedChanges.add(int(details["change"]))
|
self.committedChanges.add(int(details["change"]))
|
||||||
|
@ -48,7 +48,8 @@ P4DPORT=$((10669 + ($testid - $git_p4_test_start)))
|
|||||||
P4PORT=localhost:$P4DPORT
|
P4PORT=localhost:$P4DPORT
|
||||||
P4CLIENT=client
|
P4CLIENT=client
|
||||||
P4EDITOR=:
|
P4EDITOR=:
|
||||||
export P4PORT P4CLIENT P4EDITOR
|
unset P4CHARSET
|
||||||
|
export P4PORT P4CLIENT P4EDITOR P4CHARSET
|
||||||
|
|
||||||
db="$TRASH_DIRECTORY/db"
|
db="$TRASH_DIRECTORY/db"
|
||||||
cli="$TRASH_DIRECTORY/cli"
|
cli="$TRASH_DIRECTORY/cli"
|
||||||
|
Loading…
Reference in New Issue
Block a user