mirror of
https://gerrit.googlesource.com/git-repo
synced 2026-10-23 13:48:23 +00:00
sync: Add GetApprovedManifestV2 with named request options
Smart sync calls GetApprovedManifest(branch[, target]) over XML-RPC,
which only supports positional arguments. Adding new request options
that way does not scale.
Add a GetApprovedManifestV2 method that takes a single struct of named
options and returns a struct:
request: {branch, target?, best_effort?}
response: {success, manifest_xml?, error_message?}
Servers must ignore unknown options, so new options (e.g. criteria for
selecting a good build) can be added without another method.
The first new option is `best_effort`. repo sets it when smart sync was
enabled implicitly by the manifest's sync-smartsync="true" default
rather than by -s. The server may decline a best_effort request (e.g.
for rollout or cohort gating) by returning success=false. The client
still owns the fallback policy: declined implicit requests fall back to
a regular sync, while explicit -s requests fail as before.
If the server does not implement GetApprovedManifestV2, repo falls back
to the legacy GetApprovedManifest call.
Bug: 545137090
Test: ./run_tests
Change-Id: I9297b728df26516012cb93dffc91d39c1fb0458f
Reviewed-on: https://gerrit-review.googlesource.com/c/git-repo/+/636623
Reviewed-by: Mike Frysinger <vapier@google.com>
Commit-Queue: Rahul Yadav <yadavrah@google.com>
Tested-by: Rahul Yadav <yadavrah@google.com>
This commit is contained in:
1 parent
a110680ff3
commit
3448df3954
3 files changed
+274
-29
No files matched your search
+71
-7
@@ -98,6 +98,69 @@ _BLOAT_SIZE_GARBAGE_THRESHOLD_KB = 1 * 1024 * 1024 # 1 GiB in KiB
|
||||
|
||||
logger = RepoLogger(__file__)
|
||||
|
||||
# Manifest server RPC that takes a single struct of named options. Servers
|
||||
# that do not implement it are called via the positional GetApprovedManifest.
|
||||
_GET_APPROVED_MANIFEST_V2 = "GetApprovedManifestV2"
|
||||
|
||||
|
||||
def _IsMethodNotFoundFault(fault: xmlrpc.client.Fault, method: str) -> bool:
|
||||
"""Whether |fault| means the server does not implement |method|."""
|
||||
if fault.faultCode == xmlrpc.client.METHOD_NOT_FOUND:
|
||||
return True
|
||||
# Python's SimpleXMLRPCDispatcher uses faultCode 1 with this message.
|
||||
return f'method "{method}" is not supported' in str(fault.faultString)
|
||||
|
||||
|
||||
def _GetApprovedManifest(
|
||||
server: xmlrpc.client.ServerProxy,
|
||||
branch: str,
|
||||
target: Optional[str],
|
||||
best_effort: bool,
|
||||
) -> Tuple[bool, str]:
|
||||
"""Requests the approved manifest from the manifest server.
|
||||
|
||||
Args:
|
||||
server: The manifest server proxy.
|
||||
branch: The manifest branch.
|
||||
target: The build target, if any.
|
||||
best_effort: The client can proceed without a manifest (e.g. by
|
||||
falling back to ToT), so the server may decline the request.
|
||||
|
||||
Returns:
|
||||
A (success, manifest XML or error message) tuple.
|
||||
"""
|
||||
request = {"branch": branch}
|
||||
if target:
|
||||
request["target"] = target
|
||||
if best_effort:
|
||||
request["best_effort"] = True
|
||||
|
||||
try:
|
||||
response = server.GetApprovedManifestV2(request)
|
||||
except xmlrpc.client.Fault as e:
|
||||
if not _IsMethodNotFoundFault(e, _GET_APPROVED_MANIFEST_V2):
|
||||
raise
|
||||
# Older server: |best_effort| has no equivalent and is dropped.
|
||||
if target:
|
||||
success, manifest_str = server.GetApprovedManifest(branch, target)
|
||||
else:
|
||||
success, manifest_str = server.GetApprovedManifest(branch)
|
||||
return success, manifest_str
|
||||
|
||||
if not isinstance(response, dict):
|
||||
raise SmartSyncError(
|
||||
f"error: invalid {_GET_APPROVED_MANIFEST_V2} response: {response!r}"
|
||||
)
|
||||
if response.get("success"):
|
||||
manifest_xml = response.get("manifest_xml")
|
||||
if not isinstance(manifest_xml, str):
|
||||
raise SmartSyncError(
|
||||
f"error: {_GET_APPROVED_MANIFEST_V2} response has invalid "
|
||||
f"manifest_xml: {manifest_xml!r}"
|
||||
)
|
||||
return True, manifest_xml
|
||||
return False, response.get("error_message", "unknown error")
|
||||
|
||||
|
||||
def _SafeCheckoutOrder(checkouts: List[Project]) -> List[List[Project]]:
|
||||
"""Generate a sequence of checkouts that is safe to perform.
|
||||
@@ -2094,6 +2157,7 @@ later is required to fix a server side protocol bug.
|
||||
opt: optparse.Values,
|
||||
smart_sync_manifest_path: str,
|
||||
manifest: XmlManifest,
|
||||
best_effort: bool = False,
|
||||
) -> str:
|
||||
if not manifest.manifest_server:
|
||||
raise SmartSyncError(
|
||||
@@ -2140,12 +2204,9 @@ later is required to fix a server side protocol bug.
|
||||
os.environ["TARGET_BUILD_VARIANT"],
|
||||
)
|
||||
|
||||
if target:
|
||||
[success, manifest_str] = server.GetApprovedManifest(
|
||||
branch, target
|
||||
)
|
||||
else:
|
||||
[success, manifest_str] = server.GetApprovedManifest(branch)
|
||||
success, manifest_str = _GetApprovedManifest(
|
||||
server, branch, target, best_effort
|
||||
)
|
||||
else:
|
||||
assert opt.smart_tag
|
||||
[success, manifest_str] = server.GetManifest(opt.smart_tag)
|
||||
@@ -2519,7 +2580,10 @@ later is required to fix a server side protocol bug.
|
||||
if opt.smart_sync or opt.smart_tag:
|
||||
try:
|
||||
manifest_name = self._SmartSyncSetup(
|
||||
opt, smart_sync_manifest_path, manifest
|
||||
opt,
|
||||
smart_sync_manifest_path,
|
||||
manifest,
|
||||
best_effort=implicit_smart_sync,
|
||||
)
|
||||
except (SmartSyncError, ManifestParseError) as e:
|
||||
if not implicit_smart_sync:
|
||||
|
||||
Reference in new issue
Block a user