diff --git a/.hgtags b/.hgtags index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_LmhndGFncw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_LmhndGFncw== 100644 --- a/.hgtags +++ b/.hgtags @@ -62,3 +62,14 @@ e5a02e0abd62fe3b9f6bd33ac1882ecbc2cd545c 0.33.2 7e815fe93113f89496846fc87498ee246caab4e5 0.33.3 9f5a999855c4f54e656a7cb27dd931b5149bf4bc 0.33.4 +d33263b080e179fcc0636b567ab2a952cd1e5405 0.34.0 +4066eb34a329cd8a91b2880a6fa873fc1609feba 0.35.0 +e29ee359b3c2b7f68ea9af072ee4723fde0238c8 0.36.0 +28e88c3e1f8375c13ec90b9d1aaca586b6e8a8cd 0.37.0 +1015845afe27043b6dab5e05a868c093cc4eb01c 0.38.0 +d106c9a3eb27c1854a5d7cd78c1f6253d0df2185 0.39.0 +e4a01ac4d5902136f4e683efe71a8b9ee87be7b5 0.39.1 +6341000c08fe7160fdba4106a83e2e331558d094 0.40.0 +d924b81496e212c7898c47269aff3afe10cfcfda 0.40.1 +6ce174b1c7593857e4e65b9f03981d581d075b95 0.40.2 +c31dbf702896e10dc0c33caf48a357bc8cfecbf1 0.40.3 diff --git a/conftest.py b/conftest.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_Y29uZnRlc3QucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_Y29uZnRlc3QucHk= 100644 --- a/conftest.py +++ b/conftest.py @@ -8,6 +8,7 @@ from hgitaly.service.ref import RefServicer from hgitaly.service.diff import DiffServicer from hgitaly.service.mercurial_changeset import MercurialChangesetServicer +from hgitaly.service.mercurial_operations import MercurialOperationsServicer from hgitaly.service.mercurial_repository import MercurialRepositoryServicer from hgitaly.service.repository import RepositoryServicer from hgitaly.service.server import ServerServicer @@ -21,6 +22,9 @@ from hgitaly.stub.mercurial_changeset_pb2_grpc import ( add_MercurialChangesetServiceServicer_to_server ) +from hgitaly.stub.mercurial_operations_pb2_grpc import ( + add_MercurialOperationsServiceServicer_to_server +) from hgitaly.stub.mercurial_repository_pb2_grpc import ( add_MercurialRepositoryServiceServicer_to_server ) @@ -51,6 +55,9 @@ add_MercurialChangesetServiceServicer_to_server( MercurialChangesetServicer(storages), _grpc_server) + add_MercurialOperationsServiceServicer_to_server( + MercurialOperationsServicer(storages), + _grpc_server) add_MercurialRepositoryServiceServicer_to_server( MercurialRepositoryServicer(storages), _grpc_server) diff --git a/generate-stubs b/generate-stubs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_Z2VuZXJhdGUtc3R1YnM=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_Z2VuZXJhdGUtc3R1YnM= 100755 --- a/generate-stubs +++ b/generate-stubs @@ -5,7 +5,7 @@ PROTOS_DIR=./protos STUBS_DIR=hgitaly/stub -for PROTO in lint shared errors blob commit diff ref repository server mercurial-repository mercurial-changeset; do +for PROTO in lint shared errors blob commit diff ref repository server mercurial-repository mercurial-changeset mercurial-operations; do python -m grpc_tools.protoc \ -I${PROTOS_DIR} \ --python_out=${STUBS_DIR} \ diff --git a/hgext3rd/hgitaly/__init__.py b/hgext3rd/hgitaly/__init__.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdleHQzcmQvaGdpdGFseS9fX2luaXRfXy5weQ==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdleHQzcmQvaGdpdGFseS9fX2luaXRfXy5weQ== 100644 --- a/hgext3rd/hgitaly/__init__.py +++ b/hgext3rd/hgitaly/__init__.py @@ -10,6 +10,7 @@ error, pycompat, registrar, + util, ) from hgitaly.server import ( @@ -20,6 +21,13 @@ ) from . import revset +if util.safehasattr(registrar, 'configitem'): + + configtable = {} + configitem = registrar.configitem(configtable) + configitem(b'hgitaly', b'tokei-executable', b'tokei') + + cmdtable = {} command = registrar.command(cmdtable) diff --git a/hgitaly/VERSION b/hgitaly/VERSION index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9WRVJTSU9O..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9WRVJTSU9O 100644 --- a/hgitaly/VERSION +++ b/hgitaly/VERSION @@ -1,1 +1,1 @@ -0.33.5dev0 +0.40.4dev0 diff --git a/hgitaly/branch.py b/hgitaly/branch.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9icmFuY2gucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9icmFuY2gucHk= 100644 --- a/hgitaly/branch.py +++ b/hgitaly/branch.py @@ -29,6 +29,7 @@ ensure_gitlab_branches as hg_git_ensure_gitlab_branches, ) from .gitlab_ref import ( + path_match_any, sort_key_ref_changeset_date_asc, sort_key_ref_changeset_date_desc, ) @@ -288,7 +289,7 @@ yield key, repo[node] -def iter_gitlab_branches_as_refs(repo, **kwargs): +def iter_gitlab_branches_as_refs(repo, patterns=None, **kwargs): """Same as :func:`iter_gitlab_branches`, yielding full Git ref paths. """ for branch, target in iter_gitlab_branches(repo, **kwargs): @@ -292,6 +293,10 @@ """Same as :func:`iter_gitlab_branches`, yielding full Git ref paths. """ for branch, target in iter_gitlab_branches(repo, **kwargs): + ref_path = gitlab_branch_ref(branch) + if patterns and not path_match_any(ref_path, patterns): + continue + yield gitlab_branch_ref(branch), target diff --git a/hgitaly/changelog.py b/hgitaly/changelog.py new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9jaGFuZ2Vsb2cucHk= --- /dev/null +++ b/hgitaly/changelog.py @@ -0,0 +1,23 @@ +# Copyright 2023 Georges Racinet <georges.racinet@octobus.net> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. +# +# SPDX-License-Identifier: GPL-2.0-or-later +"""Various changelog operations + +These are utilities involving several changesets, either in the arguments or +in the response. +""" + + +def ancestor(cs1, cs2): + """Greatest common ancestor of two changesets.""" + return cs1.repo().revs("ancestor(%s, %s)", cs1, cs2).first() + + +def merge_content(source, target): + """Iterator of changeset contexts for the merge of source into target.""" + repo = source.repo() + for rev in repo.revs("only(%s, %s)", source, target): + yield repo[rev] diff --git a/hgitaly/gitlab_ref.py b/hgitaly/gitlab_ref.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9naXRsYWJfcmVmLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9naXRsYWJfcmVmLnB5 100644 --- a/hgitaly/gitlab_ref.py +++ b/hgitaly/gitlab_ref.py @@ -12,6 +12,15 @@ `refs/some/thing` and not yet refined to a given type, such as branches or tags. """ +from fnmatch import fnmatch + +from heptapod.gitlab.branch import gitlab_branch_ref +from heptapod.gitlab.tag import gitlab_tag_ref +from hgext3rd.heptapod.branch import ( + gitlab_branches, + get_default_gitlab_branch, +) +from hgext3rd.heptapod.tag import gitlab_tags from hgext3rd.heptapod import ensure_gitlab_special_refs from hgext3rd.heptapod import ensure_gitlab_keep_arounds from hgext3rd.heptapod.special_ref import ( @@ -46,5 +55,42 @@ return repo.unfiltered()[sha] -def iter_gitlab_special_refs_as_refs(repo, deref=True): +def path_match(path_segments, pattern_segments): + # special case for prefix_matching + if pattern_segments[-1] == b'': + # direct equality could have issues comparing lists to tuples + return all( + path_segment == pat_segment + for path_segment, pat_segment in zip(path_segments, + pattern_segments[:-1])) + + return (len(pattern_segments) == len(path_segments) + and all( + fnmatch(path_segment, pat_segment) + for path_segment, pat_segment in zip(path_segments, + pattern_segments) + )) + + +def path_match_any(path, patterns): + """Tell if path matches at least one of the given glob-like patterns. + + The matching is done as in `git-for-each-ref`, that is either as in + `fnmatch(3)` (C stdlib function, matches segment by segment of the path) + or as a direct prefix if pattern ends + with a slash. + + Because Python's :func:`fnmatch` does not match per slash-separated + segment, but on the whole string, considering the slash to be an ordinary + character, we implement the segmentation, and hence need patterns to + come pre-split at slashes. + + :param patterns: iterable of patterns, each pattern being an iterable + of segment level patterns, e.g., ``[b'refs', b'heads', b'branch', b'*']`` + """ + path_segments = path.split(b'/') + return any(path_match(path_segments, pat) for pat in patterns) + + +def iter_gitlab_special_refs_as_refs(repo, deref=True, patterns=None): """Iterate on special refs, yielding full ref paths and target hashes. @@ -50,4 +96,6 @@ """Iterate on special refs, yielding full ref paths and target hashes. + + :param patterns: as in :func:`path_match_any` (presplit) """ all_special_refs = special_refs(repo) if all_special_refs is GITLAB_TYPED_REFS_MISSING: @@ -56,7 +104,10 @@ all_special_refs = ensure_special_refs(repo) for sref, sha in all_special_refs.items(): - yield b'refs/' + sref, (repo[sha] if deref else sha.decode('ascii')) + ref_path = b'refs/' + sref + if patterns and not path_match_any(ref_path, patterns): + continue + yield ref_path, (repo[sha] if deref else sha.decode('ascii')) def ensure_special_refs(repo): @@ -82,9 +133,9 @@ return b'refs/keep-around/' + sha -def iter_keep_arounds_as_refs(repo, deref=True): +def iter_keep_arounds_as_refs(repo, deref=True, patterns=None): for sha in iter_keep_arounds(repo): if sha is GITLAB_TYPED_REFS_MISSING: ensure_gitlab_keep_arounds(repo.ui, repo) yield from iter_keep_arounds_as_refs(repo, deref=deref) return @@ -86,10 +137,13 @@ for sha in iter_keep_arounds(repo): if sha is GITLAB_TYPED_REFS_MISSING: ensure_gitlab_keep_arounds(repo.ui, repo) yield from iter_keep_arounds_as_refs(repo, deref=deref) return - yield (keep_around_ref_path(sha), - (repo[sha] if deref else sha.decode('ascii'))) + ref_path = keep_around_ref_path(sha) + if patterns and not path_match_any(ref_path, patterns): + continue + + yield (ref_path, (repo[sha] if deref else sha.decode('ascii'))) def sort_key_ref_changeset_date_asc(ref_chgset): @@ -106,3 +160,36 @@ :param ref_chgset: a pair made of ref name and changeset (changectx) """ return -ref_chgset[1].date()[0] + + +def reverse_refs(repo): + reverse_refs = getattr(repo, '_hgitaly_reverse_refs', None) + if reverse_refs is not None: + return reverse_refs + + reverse_refs = {} + tags = gitlab_tags(repo) + if tags is not GITLAB_TYPED_REFS_MISSING: + for tag_name, target in tags.items(): + reverse_refs.setdefault(target, []).append( + gitlab_tag_ref(tag_name)) + special = special_refs(repo) + branches = gitlab_branches(repo) + if branches is not GITLAB_TYPED_REFS_MISSING: + for branch_name, target in branches.items(): + reverse_refs.setdefault(target, []).append( + gitlab_branch_ref(branch_name)) + if special is not GITLAB_TYPED_REFS_MISSING: + for ref_name, target in special.items(): + reverse_refs.setdefault(target, []).append(b'refs/' + ref_name) + default_branch = get_default_gitlab_branch(repo) + if ( + default_branch is not None + and branches is not GITLAB_TYPED_REFS_MISSING + ): + target = branches.get(default_branch) + if target is not None: + reverse_refs.setdefault(target, []).append(b'HEAD') + + repo._hgitaly_reverse_refs = reverse_refs + return reverse_refs diff --git a/hgitaly/linguist/__init__.py b/hgitaly/linguist/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9saW5ndWlzdC9fX2luaXRfXy5weQ== --- /dev/null +++ b/hgitaly/linguist/__init__.py @@ -0,0 +1,196 @@ +# Copyright 2023 Georges Racinet <georges.racinet@octobus.net> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. +# +# SPDX-License-Identifier: GPL-2.0-or-later +from hashlib import sha256 +import json +import re +import subprocess + +from grpc import StatusCode +from importlib_resources import files + + +def read_linguist_languages(path): + res = {} + with path.open() as langf: + for name, details in json.load(langf).items(): + color = details.get('color') + if color is not None: + res[name] = color + return res + + +LANGUAGE_COLORS = read_linguist_languages( + files(__name__).joinpath('languages.json')) + +TOKEI_VERSION_RX = re.compile(r'tokei (\d+)\.(\d+)\.(\d+)(\s|$)') +TOKEI_VERSIONS = {} + + +def language_color(lang_name): + """Perform the same defaulting as in Gitaly. + + This is not thread-safe, because it actually updates + :data:`LANGUAGE_COLORS` due to defaulting in case the detected language + does not have a color there. That is not a problem: HGitaly is not + multithreaded (or rather uses a unique service thread at a given time, + out of the pool still created by grpcio). + + As of this writing, go-enry v2.8.3 (already used by Gitaly to return the + color) defaults to `#cccccc`: + + // GetColor returns a HTML color code of a given language. + func GetColor(language string) string { + if color, ok := data.LanguagesColor[language]; ok { + return color + } + + if color, ok := data.LanguagesColor[GetLanguageGroup(language)]; ok { + return color + } + + return "#cccccc" + } + + Gitaly then concludes with (from internal/gitaly/linguist/linguist.go) :: + + // Color returns the color Linguist has assigned to language. + func Color(language string) string { + if color := enry.GetColor(language); color != "#cccccc" { + return color + } + + colorSha := sha256.Sum256([]byte(language)) + return fmt.Sprintf("#%x", colorSha[0:3]) + } + """ + color = LANGUAGE_COLORS.get(lang_name) + if color is not None: + return color + + color_sha = sha256(lang_name.encode('utf-8')).hexdigest() + color = '#' + color_sha[:6] + LANGUAGE_COLORS[lang_name] = color + return color + + +class TokeiVersionParseError(RuntimeError): + """Indicates that `tokei --version` could not be parsed. + + It is possible that the executable is just not Tokei + """ + + +def parse_tokei_version(out): + """Parse the given ``out``, expected to be output of ``tokei --version`` + + :returns: a triple of integers + :raises: :class:TokeiVersionParseError + + Currently tested versions:: + + >>> parse_tokei_version("tokei 12.0.4") + (12, 0, 4) + >>> parse_tokei_version("tokei 12.1.2") + (12, 1, 2) + + Errors:: + + >>> try: parse_tokei_version("Unrelated") + ... except Exception as exc: print(repr(exc)) + TokeiVersionParseError('Unrelated') + """ + match = TOKEI_VERSION_RX.search(out) + if match is None: + raise TokeiVersionParseError(out) + return tuple(int(match.group(i)) for i in (1, 2, 3)) + + +def tokei_version(bin_path): + version = TOKEI_VERSIONS.get(bin_path) + if version is not None: + return version + + tokei = subprocess.run((bin_path, '--version'), + encoding='utf-8', + check=True, + capture_output=True + ) + version = parse_tokei_version(tokei.stdout.strip()) + TOKEI_VERSIONS[bin_path] = version + return version + + +def language_stats(bin_path, path, context): + """Return the full language stats working directory at given path. + + :param str bin_path: path to the Tokei executable + :param path: the directory to analyze as a :class:`pathlib.Path` instance. + """ + try: + version = tokei_version(bin_path) # may invoke Tokei + options = [] + if version >= (12, 1): + options.append('--compact') + + cmd = [bin_path] + cmd.extend(options) + cmd.extend(('-o', 'json', path)) + tokei = subprocess.run( + cmd, + encoding='utf-8', + check=True, + capture_output=True, + ) + except subprocess.CalledProcessError as exc: + # in Gitaly 15.5, the resulting error code is 'INTERNAL', with + # details 'language stats: waiting for linguist: exit status %d' + context.abort( + StatusCode.INTERNAL, + "CommitLanguages: tokei error status code=%d stderr=%r" % ( + exc.returncode, exc.stderr)) + except FileNotFoundError: + # in Gitaly 15.5, if `gitaly-linguist` cannot be found, the resulting + # error code is `INTERNAL`, with details 'language stats: waiting + # for linguist: exit status 127' (same as rewrapping in a shell) + context.abort( + StatusCode.INTERNAL, + "language stats: tokei executable '%s' not found" % bin_path) + except PermissionError: + # Gitaly 15.5 behaves similarly in this case as in the not found case, + # only with exit status 126 in details (same as in a shell, again) + context.abort( + StatusCode.INTERNAL, + "language stats: permission denied to run " + "tokei executable '%s'" % bin_path) + except TokeiVersionParseError as exc: + context.abort( + StatusCode.INTERNAL, + "language stats: could not parse Tokei version for executable " + "'%s' (got %r). Is it even Tokei?" % (bin_path, exc.args[0])) + + # overriding variable also to free buffer immediately, as it can be + # fairly big, e.g. 10MB for heptapod-rails + tokei = json.loads(tokei.stdout) + + stats = {} + total = 0 + + for lang_name, details in tokei.items(): + # We can't use the `Total` entry because the ratios we have + # to produce are expressed in bytes, not lines. + if lang_name == 'Total': + continue + + per_file = details['reports'] + total_bytes = 0 + for report in per_file: + total_bytes += (path / report['name']).stat().st_size + stats[lang_name] = dict(files=len(per_file), + total_bytes=total_bytes, + ) + total += total_bytes + return stats, total diff --git a/hgitaly/linguist/languages.json b/hgitaly/linguist/languages.json new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9saW5ndWlzdC9sYW5ndWFnZXMuanNvbg== --- /dev/null +++ b/hgitaly/linguist/languages.json @@ -0,0 +1,1 @@ +{"1C Enterprise":{"type":"programming","color":"#814CCC","extensions":[".bsl",".os"],"tm_scope":"source.bsl","ace_mode":"text","language_id":0},"2-Dimensional Array":{"type":"data","color":"#38761D","extensions":[".2da"],"tm_scope":"source.2da","ace_mode":"text","language_id":387204628},"4D":{"type":"programming","color":"#004289","extensions":[".4dm"],"tm_scope":"source.4dm","ace_mode":"text","language_id":577529595},"ABAP":{"type":"programming","color":"#E8274B","extensions":[".abap"],"tm_scope":"source.abap","ace_mode":"abap","language_id":1},"ABAP CDS":{"type":"programming","color":"#555e25","extensions":[".asddls"],"tm_scope":"source.abapcds","language_id":452681853,"ace_mode":"text"},"ABNF":{"type":"data","ace_mode":"text","extensions":[".abnf"],"tm_scope":"source.abnf","language_id":429},"AGS Script":{"type":"programming","color":"#B9D9FF","aliases":["ags"],"extensions":[".asc",".ash"],"tm_scope":"source.c++","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","language_id":2},"AIDL":{"type":"programming","color":"#34EB6B","tm_scope":"source.aidl","extensions":[".aidl"],"ace_mode":"text","interpreters":["aidl"],"language_id":451700185},"AL":{"type":"programming","color":"#3AA2B5","extensions":[".al"],"tm_scope":"source.al","ace_mode":"text","language_id":658971832},"AMPL":{"type":"programming","color":"#E6EFBB","extensions":[".ampl",".mod"],"tm_scope":"source.ampl","ace_mode":"text","language_id":3},"ANTLR":{"type":"programming","color":"#9DC3FF","extensions":[".g4"],"tm_scope":"source.antlr","ace_mode":"text","language_id":4},"API Blueprint":{"type":"markup","color":"#2ACCA8","ace_mode":"markdown","extensions":[".apib"],"tm_scope":"text.html.markdown.source.gfm.apib","language_id":5},"APL":{"type":"programming","color":"#5A8164","extensions":[".apl",".dyalog"],"interpreters":["apl","aplx","dyalog"],"tm_scope":"source.apl","ace_mode":"text","codemirror_mode":"apl","codemirror_mime_type":"text/apl","language_id":6},"ASL":{"type":"programming","ace_mode":"text","extensions":[".asl",".dsl"],"tm_scope":"source.asl","language_id":124996147},"ASN.1":{"type":"data","extensions":[".asn",".asn1"],"tm_scope":"source.asn","ace_mode":"text","codemirror_mode":"asn.1","codemirror_mime_type":"text/x-ttcn-asn","language_id":7},"ASP.NET":{"type":"programming","tm_scope":"text.html.asp","color":"#9400ff","aliases":["aspx","aspx-vb"],"extensions":[".asax",".ascx",".ashx",".asmx",".aspx",".axd"],"ace_mode":"text","codemirror_mode":"htmlembedded","codemirror_mime_type":"application/x-aspx","language_id":564186416},"ATS":{"type":"programming","color":"#1ac620","aliases":["ats2"],"extensions":[".dats",".hats",".sats"],"tm_scope":"source.ats","ace_mode":"ocaml","language_id":9},"ActionScript":{"type":"programming","tm_scope":"source.actionscript.3","color":"#882B0F","aliases":["actionscript 3","actionscript3","as3"],"extensions":[".as"],"ace_mode":"actionscript","language_id":10},"Ada":{"type":"programming","color":"#02f88c","extensions":[".adb",".ada",".ads"],"aliases":["ada95","ada2005"],"tm_scope":"source.ada","ace_mode":"ada","language_id":11},"Adobe Font Metrics":{"type":"data","color":"#fa0f00","tm_scope":"source.afm","extensions":[".afm"],"aliases":["acfm","adobe composite font metrics","adobe multiple font metrics","amfm"],"ace_mode":"text","language_id":147198098},"Agda":{"type":"programming","color":"#315665","extensions":[".agda"],"tm_scope":"source.agda","ace_mode":"text","language_id":12},"Alloy":{"type":"programming","color":"#64C800","extensions":[".als"],"tm_scope":"source.alloy","ace_mode":"text","language_id":13},"Alpine Abuild":{"type":"programming","color":"#0D597F","group":"Shell","aliases":["abuild","apkbuild"],"filenames":["APKBUILD"],"tm_scope":"source.shell","ace_mode":"sh","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":14},"Altium Designer":{"type":"data","color":"#A89663","aliases":["altium"],"extensions":[".OutJob",".PcbDoc",".PrjPCB",".SchDoc"],"tm_scope":"source.ini","ace_mode":"ini","language_id":187772328},"AngelScript":{"type":"programming","color":"#C7D7DC","extensions":[".as",".angelscript"],"tm_scope":"source.angelscript","ace_mode":"text","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","language_id":389477596},"Ant Build System":{"type":"data","color":"#A9157E","tm_scope":"text.xml.ant","filenames":["ant.xml","build.xml"],"ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"application/xml","language_id":15},"ApacheConf":{"type":"data","color":"#d12127","aliases":["aconf","apache"],"extensions":[".apacheconf",".vhost"],"filenames":[".htaccess","apache2.conf","httpd.conf"],"tm_scope":"source.apache-config","ace_mode":"apache_conf","language_id":16},"Apex":{"type":"programming","color":"#1797c0","extensions":[".cls"],"tm_scope":"source.java","ace_mode":"java","codemirror_mode":"clike","codemirror_mime_type":"text/x-java","language_id":17},"Apollo Guidance Computer":{"type":"programming","color":"#0B3D91","group":"Assembly","extensions":[".agc"],"tm_scope":"source.agc","ace_mode":"assembly_x86","language_id":18},"AppleScript":{"type":"programming","aliases":["osascript"],"extensions":[".applescript",".scpt"],"interpreters":["osascript"],"tm_scope":"source.applescript","ace_mode":"applescript","color":"#101F1F","language_id":19},"Arc":{"type":"programming","color":"#aa2afe","extensions":[".arc"],"tm_scope":"none","ace_mode":"text","language_id":20},"AsciiDoc":{"type":"prose","color":"#73a0c5","ace_mode":"asciidoc","wrap":true,"extensions":[".asciidoc",".adoc",".asc"],"tm_scope":"text.html.asciidoc","language_id":22},"AspectJ":{"type":"programming","color":"#a957b0","extensions":[".aj"],"tm_scope":"source.aspectj","ace_mode":"text","language_id":23},"Assembly":{"type":"programming","color":"#6E4C13","aliases":["asm","nasm"],"extensions":[".asm",".a51",".i",".inc",".nasm"],"tm_scope":"source.assembly","ace_mode":"assembly_x86","language_id":24},"Astro":{"type":"markup","color":"#ff5a03","extensions":[".astro"],"tm_scope":"source.astro","ace_mode":"html","codemirror_mode":"jsx","codemirror_mime_type":"text/jsx","language_id":578209015},"Asymptote":{"type":"programming","color":"#ff0000","extensions":[".asy"],"interpreters":["asy"],"tm_scope":"source.c++","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-kotlin","language_id":591605007},"Augeas":{"type":"programming","color":"#9CC134","extensions":[".aug"],"tm_scope":"none","ace_mode":"text","language_id":25},"AutoHotkey":{"type":"programming","color":"#6594b9","aliases":["ahk"],"extensions":[".ahk",".ahkl"],"tm_scope":"source.ahk","ace_mode":"autohotkey","language_id":26},"AutoIt":{"type":"programming","color":"#1C3552","aliases":["au3","AutoIt3","AutoItScript"],"extensions":[".au3"],"tm_scope":"source.autoit","ace_mode":"autohotkey","language_id":27},"Avro IDL":{"type":"data","color":"#0040FF","extensions":[".avdl"],"tm_scope":"source.avro","ace_mode":"text","language_id":785497837},"Awk":{"type":"programming","color":"#c30e9b","extensions":[".awk",".auk",".gawk",".mawk",".nawk"],"interpreters":["awk","gawk","mawk","nawk"],"tm_scope":"source.awk","ace_mode":"text","language_id":28},"BASIC":{"type":"programming","extensions":[".bas"],"tm_scope":"source.basic","ace_mode":"text","color":"#ff0000","language_id":28923963},"Ballerina":{"type":"programming","extensions":[".bal"],"tm_scope":"source.ballerina","ace_mode":"text","color":"#FF5000","language_id":720859680},"Batchfile":{"type":"programming","aliases":["bat","batch","dosbatch","winbatch"],"extensions":[".bat",".cmd"],"tm_scope":"source.batchfile","ace_mode":"batchfile","color":"#C1F12E","language_id":29},"Beef":{"type":"programming","color":"#a52f4e","extensions":[".bf"],"tm_scope":"source.cs","ace_mode":"csharp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csharp","language_id":545626333},"Befunge":{"type":"programming","extensions":[".befunge"],"tm_scope":"source.befunge","ace_mode":"text","language_id":30},"Berry":{"type":"programming","extensions":[".be"],"tm_scope":"source.berry","ace_mode":"text","color":"#15A13C","aliases":["be"],"language_id":121855308},"BibTeX":{"type":"markup","color":"#778899","group":"TeX","extensions":[".bib",".bibtex"],"tm_scope":"text.bibtex","ace_mode":"tex","codemirror_mode":"stex","codemirror_mime_type":"text/x-stex","language_id":982188347},"Bicep":{"type":"programming","color":"#519aba","extensions":[".bicep"],"tm_scope":"source.bicep","ace_mode":"text","language_id":321200902},"Bison":{"type":"programming","color":"#6A463F","group":"Yacc","tm_scope":"source.yacc","extensions":[".bison"],"ace_mode":"text","language_id":31},"BitBake":{"type":"programming","color":"#00bce4","tm_scope":"none","extensions":[".bb"],"ace_mode":"text","language_id":32},"Blade":{"type":"markup","color":"#f7523f","extensions":[".blade",".blade.php"],"tm_scope":"text.html.php.blade","ace_mode":"text","language_id":33},"BlitzBasic":{"type":"programming","color":"#00FFAE","aliases":["b3d","blitz3d","blitzplus","bplus"],"extensions":[".bb",".decls"],"tm_scope":"source.blitzmax","ace_mode":"text","language_id":34},"BlitzMax":{"type":"programming","color":"#cd6400","extensions":[".bmx"],"aliases":["bmax"],"tm_scope":"source.blitzmax","ace_mode":"text","language_id":35},"Bluespec":{"type":"programming","color":"#12223c","extensions":[".bsv"],"tm_scope":"source.bsv","ace_mode":"verilog","language_id":36},"Boo":{"type":"programming","color":"#d4bec1","extensions":[".boo"],"ace_mode":"text","tm_scope":"source.boo","language_id":37},"Boogie":{"type":"programming","color":"#c80fa0","extensions":[".bpl"],"interpreters":["boogie"],"tm_scope":"source.boogie","ace_mode":"text","language_id":955017407},"Brainfuck":{"type":"programming","color":"#2F2530","extensions":[".b",".bf"],"tm_scope":"source.bf","ace_mode":"text","codemirror_mode":"brainfuck","codemirror_mime_type":"text/x-brainfuck","language_id":38},"Brightscript":{"type":"programming","color":"#662D91","extensions":[".brs"],"tm_scope":"source.brightscript","ace_mode":"text","language_id":39},"Browserslist":{"type":"data","color":"#ffd539","filenames":[".browserslistrc","browserslist"],"tm_scope":"text.browserslist","ace_mode":"text","language_id":153503348},"C":{"type":"programming","color":"#555555","extensions":[".c",".cats",".h",".idc"],"interpreters":["tcc"],"tm_scope":"source.c","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":41},"C#":{"type":"programming","ace_mode":"csharp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csharp","tm_scope":"source.cs","color":"#178600","aliases":["csharp","cake","cakescript"],"extensions":[".cs",".cake",".csx",".linq"],"language_id":42},"C++":{"type":"programming","tm_scope":"source.c++","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","color":"#f34b7d","aliases":["cpp"],"extensions":[".cpp",".c++",".cc",".cp",".cxx",".h",".h++",".hh",".hpp",".hxx",".inc",".inl",".ino",".ipp",".ixx",".re",".tcc",".tpp"],"language_id":43},"C-ObjDump":{"type":"data","extensions":[".c-objdump"],"tm_scope":"objdump.x86asm","ace_mode":"assembly_x86","language_id":44},"C2hs Haskell":{"type":"programming","group":"Haskell","aliases":["c2hs"],"extensions":[".chs"],"tm_scope":"source.haskell","ace_mode":"haskell","codemirror_mode":"haskell","codemirror_mime_type":"text/x-haskell","language_id":45},"CIL":{"type":"data","tm_scope":"source.cil","extensions":[".cil"],"ace_mode":"text","language_id":29176339},"CLIPS":{"type":"programming","color":"#00A300","extensions":[".clp"],"tm_scope":"source.clips","ace_mode":"text","language_id":46},"CMake":{"type":"programming","color":"#DA3434","extensions":[".cmake",".cmake.in"],"filenames":["CMakeLists.txt"],"tm_scope":"source.cmake","ace_mode":"text","codemirror_mode":"cmake","codemirror_mime_type":"text/x-cmake","language_id":47},"COBOL":{"type":"programming","extensions":[".cob",".cbl",".ccp",".cobol",".cpy"],"tm_scope":"source.cobol","ace_mode":"cobol","codemirror_mode":"cobol","codemirror_mime_type":"text/x-cobol","language_id":48},"CODEOWNERS":{"type":"data","filenames":["CODEOWNERS"],"tm_scope":"text.codeowners","ace_mode":"gitignore","language_id":321684729},"COLLADA":{"type":"data","color":"#F1A42B","extensions":[".dae"],"tm_scope":"text.xml","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":49},"CSON":{"type":"data","color":"#244776","tm_scope":"source.coffee","ace_mode":"coffee","codemirror_mode":"coffeescript","codemirror_mime_type":"text/x-coffeescript","extensions":[".cson"],"language_id":424},"CSS":{"type":"markup","tm_scope":"source.css","ace_mode":"css","codemirror_mode":"css","codemirror_mime_type":"text/css","color":"#563d7c","extensions":[".css"],"language_id":50},"CSV":{"type":"data","color":"#237346","ace_mode":"text","tm_scope":"none","extensions":[".csv"],"language_id":51},"CUE":{"type":"programming","extensions":[".cue"],"tm_scope":"source.cue","ace_mode":"text","color":"#5886E1","language_id":356063509},"CWeb":{"type":"programming","color":"#00007a","extensions":[".w"],"tm_scope":"none","ace_mode":"text","language_id":657332628},"Cabal Config":{"type":"data","color":"#483465","aliases":["Cabal"],"extensions":[".cabal"],"filenames":["cabal.config","cabal.project"],"ace_mode":"haskell","codemirror_mode":"haskell","codemirror_mime_type":"text/x-haskell","tm_scope":"source.cabal","language_id":677095381},"Cadence":{"type":"programming","color":"#00ef8b","ace_mode":"text","tm_scope":"source.cadence","extensions":[".cdc"],"language_id":270184138},"Cairo":{"type":"programming","color":"#ff4a48","ace_mode":"text","tm_scope":"source.cairo","extensions":[".cairo"],"language_id":620599567},"CameLIGO":{"type":"programming","color":"#3be133","extensions":[".mligo"],"tm_scope":"source.mligo","ace_mode":"ocaml","codemirror_mode":"mllike","codemirror_mime_type":"text/x-ocaml","group":"LigoLANG","language_id":829207807},"Cap'n Proto":{"type":"programming","color":"#c42727","tm_scope":"source.capnp","extensions":[".capnp"],"ace_mode":"text","language_id":52},"CartoCSS":{"type":"programming","aliases":["Carto"],"extensions":[".mss"],"ace_mode":"text","tm_scope":"source.css.mss","language_id":53},"Ceylon":{"type":"programming","color":"#dfa535","extensions":[".ceylon"],"tm_scope":"source.ceylon","ace_mode":"text","language_id":54},"Chapel":{"type":"programming","color":"#8dc63f","aliases":["chpl"],"extensions":[".chpl"],"tm_scope":"source.chapel","ace_mode":"text","language_id":55},"Charity":{"type":"programming","extensions":[".ch"],"tm_scope":"none","ace_mode":"text","language_id":56},"ChucK":{"type":"programming","color":"#3f8000","extensions":[".ck"],"tm_scope":"source.java","ace_mode":"java","codemirror_mode":"clike","codemirror_mime_type":"text/x-java","language_id":57},"Cirru":{"type":"programming","color":"#ccccff","tm_scope":"source.cirru","ace_mode":"cirru","extensions":[".cirru"],"language_id":58},"Clarion":{"type":"programming","color":"#db901e","ace_mode":"text","extensions":[".clw"],"tm_scope":"source.clarion","language_id":59},"Clarity":{"type":"programming","color":"#5546ff","ace_mode":"lisp","extensions":[".clar"],"tm_scope":"source.clar","language_id":91493841},"Classic ASP":{"type":"programming","color":"#6a40fd","tm_scope":"text.html.asp","aliases":["asp"],"extensions":[".asp"],"ace_mode":"text","language_id":8},"Clean":{"type":"programming","color":"#3F85AF","extensions":[".icl",".dcl"],"tm_scope":"source.clean","ace_mode":"text","language_id":60},"Click":{"type":"programming","color":"#E4E6F3","extensions":[".click"],"tm_scope":"source.click","ace_mode":"text","language_id":61},"Clojure":{"type":"programming","tm_scope":"source.clojure","ace_mode":"clojure","codemirror_mode":"clojure","codemirror_mime_type":"text/x-clojure","color":"#db5855","extensions":[".clj",".boot",".cl2",".cljc",".cljs",".cljs.hl",".cljscm",".cljx",".hic"],"filenames":["riemann.config"],"language_id":62},"Closure Templates":{"type":"markup","color":"#0d948f","ace_mode":"soy_template","codemirror_mode":"soy","codemirror_mime_type":"text/x-soy","aliases":["soy"],"extensions":[".soy"],"tm_scope":"text.html.soy","language_id":357046146},"Cloud Firestore Security Rules":{"type":"data","color":"#FFA000","ace_mode":"less","codemirror_mode":"css","codemirror_mime_type":"text/css","tm_scope":"source.firestore","filenames":["firestore.rules"],"language_id":407996372},"CoNLL-U":{"type":"data","extensions":[".conllu",".conll"],"tm_scope":"text.conllu","ace_mode":"text","aliases":["CoNLL","CoNLL-X"],"language_id":421026389},"CodeQL":{"type":"programming","color":"#140f46","extensions":[".ql",".qll"],"tm_scope":"source.ql","ace_mode":"text","language_id":424259634,"aliases":["ql"]},"CoffeeScript":{"type":"programming","tm_scope":"source.coffee","ace_mode":"coffee","codemirror_mode":"coffeescript","codemirror_mime_type":"text/x-coffeescript","color":"#244776","aliases":["coffee","coffee-script"],"extensions":[".coffee","._coffee",".cake",".cjsx",".iced"],"filenames":["Cakefile"],"interpreters":["coffee"],"language_id":63},"ColdFusion":{"type":"programming","ace_mode":"coldfusion","color":"#ed2cd6","aliases":["cfm","cfml","coldfusion html"],"extensions":[".cfm",".cfml"],"tm_scope":"text.html.cfm","language_id":64},"ColdFusion CFC":{"type":"programming","color":"#ed2cd6","group":"ColdFusion","ace_mode":"coldfusion","aliases":["cfc"],"extensions":[".cfc"],"tm_scope":"source.cfscript","language_id":65},"Common Lisp":{"type":"programming","tm_scope":"source.lisp","color":"#3fb68b","aliases":["lisp"],"extensions":[".lisp",".asd",".cl",".l",".lsp",".ny",".podsl",".sexp"],"interpreters":["lisp","sbcl","ccl","clisp","ecl"],"ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","language_id":66},"Common Workflow Language":{"aliases":["cwl"],"type":"programming","ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","extensions":[".cwl"],"interpreters":["cwl-runner"],"color":"#B5314C","tm_scope":"source.cwl","language_id":988547172},"Component Pascal":{"type":"programming","color":"#B0CE4E","extensions":[".cp",".cps"],"tm_scope":"source.pascal","ace_mode":"pascal","codemirror_mode":"pascal","codemirror_mime_type":"text/x-pascal","language_id":67},"Cool":{"type":"programming","extensions":[".cl"],"tm_scope":"source.cool","ace_mode":"text","language_id":68},"Coq":{"type":"programming","color":"#d0b68c","extensions":[".coq",".v"],"tm_scope":"source.coq","ace_mode":"text","language_id":69},"Cpp-ObjDump":{"type":"data","extensions":[".cppobjdump",".c++-objdump",".c++objdump",".cpp-objdump",".cxx-objdump"],"tm_scope":"objdump.x86asm","aliases":["c++-objdump"],"ace_mode":"assembly_x86","language_id":70},"Creole":{"type":"prose","wrap":true,"extensions":[".creole"],"tm_scope":"text.html.creole","ace_mode":"text","language_id":71},"Crystal":{"type":"programming","color":"#000100","extensions":[".cr"],"ace_mode":"ruby","codemirror_mode":"crystal","codemirror_mime_type":"text/x-crystal","tm_scope":"source.crystal","interpreters":["crystal"],"language_id":72},"Csound":{"type":"programming","color":"#1a1a1a","aliases":["csound-orc"],"extensions":[".orc",".udo"],"tm_scope":"source.csound","ace_mode":"csound_orchestra","language_id":73},"Csound Document":{"type":"programming","color":"#1a1a1a","aliases":["csound-csd"],"extensions":[".csd"],"tm_scope":"source.csound-document","ace_mode":"csound_document","language_id":74},"Csound Score":{"type":"programming","color":"#1a1a1a","aliases":["csound-sco"],"extensions":[".sco"],"tm_scope":"source.csound-score","ace_mode":"csound_score","language_id":75},"Cuda":{"type":"programming","extensions":[".cu",".cuh"],"tm_scope":"source.cuda-c++","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","color":"#3A4E3A","language_id":77},"Cue Sheet":{"type":"data","extensions":[".cue"],"tm_scope":"source.cuesheet","ace_mode":"text","language_id":942714150},"Curry":{"type":"programming","color":"#531242","extensions":[".curry"],"tm_scope":"source.curry","ace_mode":"haskell","language_id":439829048},"Cycript":{"type":"programming","extensions":[".cy"],"tm_scope":"source.js","ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"text/javascript","language_id":78},"Cython":{"type":"programming","color":"#fedf5b","extensions":[".pyx",".pxd",".pxi"],"aliases":["pyrex"],"tm_scope":"source.cython","ace_mode":"text","codemirror_mode":"python","codemirror_mime_type":"text/x-cython","language_id":79},"D":{"type":"programming","color":"#ba595e","aliases":["Dlang"],"extensions":[".d",".di"],"tm_scope":"source.d","ace_mode":"d","codemirror_mode":"d","codemirror_mime_type":"text/x-d","language_id":80},"D-ObjDump":{"type":"data","extensions":[".d-objdump"],"tm_scope":"objdump.x86asm","ace_mode":"assembly_x86","language_id":81},"DIGITAL Command Language":{"type":"programming","aliases":["dcl"],"extensions":[".com"],"tm_scope":"none","ace_mode":"text","language_id":82},"DM":{"type":"programming","color":"#447265","extensions":[".dm"],"aliases":["byond"],"tm_scope":"source.dm","ace_mode":"c_cpp","language_id":83},"DNS Zone":{"type":"data","extensions":[".zone",".arpa"],"tm_scope":"text.zone_file","ace_mode":"text","language_id":84},"DTrace":{"type":"programming","aliases":["dtrace-script"],"extensions":[".d"],"interpreters":["dtrace"],"tm_scope":"source.c","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":85},"Dafny":{"type":"programming","color":"#FFEC25","extensions":[".dfy"],"interpreters":["dafny"],"tm_scope":"text.dfy.dafny","ace_mode":"text","language_id":969323346},"Darcs Patch":{"type":"data","color":"#8eff23","aliases":["dpatch"],"extensions":[".darcspatch",".dpatch"],"tm_scope":"none","ace_mode":"text","language_id":86},"Dart":{"type":"programming","color":"#00B4AB","extensions":[".dart"],"interpreters":["dart"],"tm_scope":"source.dart","ace_mode":"dart","codemirror_mode":"dart","codemirror_mime_type":"application/dart","language_id":87},"DataWeave":{"type":"programming","color":"#003a52","extensions":[".dwl"],"ace_mode":"text","tm_scope":"source.data-weave","language_id":974514097},"Debian Package Control File":{"type":"data","color":"#D70751","extensions":[".dsc"],"tm_scope":"source.deb-control","ace_mode":"text","language_id":527438264},"DenizenScript":{"type":"programming","color":"#FBEE96","ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","extensions":[".dsc"],"tm_scope":"source.denizenscript","language_id":435000929},"Dhall":{"type":"programming","color":"#dfafff","extensions":[".dhall"],"tm_scope":"source.haskell","ace_mode":"haskell","codemirror_mode":"haskell","codemirror_mime_type":"text/x-haskell","language_id":793969321},"Diff":{"type":"data","extensions":[".diff",".patch"],"aliases":["udiff"],"tm_scope":"source.diff","ace_mode":"diff","codemirror_mode":"diff","codemirror_mime_type":"text/x-diff","language_id":88},"DirectX 3D File":{"type":"data","color":"#aace60","extensions":[".x"],"ace_mode":"text","tm_scope":"none","language_id":201049282},"Dockerfile":{"type":"programming","aliases":["Containerfile"],"color":"#384d54","tm_scope":"source.dockerfile","extensions":[".dockerfile"],"filenames":["Containerfile","Dockerfile"],"ace_mode":"dockerfile","codemirror_mode":"dockerfile","codemirror_mime_type":"text/x-dockerfile","language_id":89},"Dogescript":{"type":"programming","color":"#cca760","extensions":[".djs"],"tm_scope":"none","ace_mode":"text","language_id":90},"Dylan":{"type":"programming","color":"#6c616e","extensions":[".dylan",".dyl",".intr",".lid"],"tm_scope":"source.dylan","ace_mode":"text","codemirror_mode":"dylan","codemirror_mime_type":"text/x-dylan","language_id":91},"E":{"type":"programming","color":"#ccce35","extensions":[".e"],"interpreters":["rune"],"tm_scope":"none","ace_mode":"text","language_id":92},"E-mail":{"type":"data","aliases":["email","eml","mail","mbox"],"extensions":[".eml",".mbox"],"tm_scope":"text.eml.basic","ace_mode":"text","codemirror_mode":"mbox","codemirror_mime_type":"application/mbox","language_id":529653389},"EBNF":{"type":"data","extensions":[".ebnf"],"tm_scope":"source.ebnf","ace_mode":"text","codemirror_mode":"ebnf","codemirror_mime_type":"text/x-ebnf","language_id":430},"ECL":{"type":"programming","color":"#8a1267","extensions":[".ecl",".eclxml"],"tm_scope":"source.ecl","ace_mode":"text","codemirror_mode":"ecl","codemirror_mime_type":"text/x-ecl","language_id":93},"ECLiPSe":{"type":"programming","color":"#001d9d","group":"prolog","extensions":[".ecl"],"tm_scope":"source.prolog.eclipse","ace_mode":"prolog","language_id":94},"EJS":{"type":"markup","color":"#a91e50","extensions":[".ejs",".ect",".ejs.t",".jst"],"tm_scope":"text.html.js","ace_mode":"ejs","language_id":95},"EQ":{"type":"programming","color":"#a78649","extensions":[".eq"],"tm_scope":"source.cs","ace_mode":"csharp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csharp","language_id":96},"Eagle":{"type":"data","extensions":[".sch",".brd"],"tm_scope":"text.xml","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":97},"Earthly":{"type":"programming","aliases":["Earthfile"],"color":"#2af0ff","tm_scope":"source.earthfile","ace_mode":"text","filenames":["Earthfile"],"language_id":963512632},"Easybuild":{"type":"data","color":"#069406","group":"Python","ace_mode":"python","codemirror_mode":"python","codemirror_mime_type":"text/x-python","tm_scope":"source.python","extensions":[".eb"],"language_id":342840477},"Ecere Projects":{"type":"data","color":"#913960","group":"JavaScript","extensions":[".epj"],"tm_scope":"source.json","ace_mode":"json","codemirror_mode":"javascript","codemirror_mime_type":"application/json","language_id":98},"EditorConfig":{"type":"data","color":"#fff1f2","group":"INI","filenames":[".editorconfig"],"aliases":["editor-config"],"ace_mode":"ini","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","tm_scope":"source.editorconfig","language_id":96139566},"Edje Data Collection":{"type":"data","extensions":[".edc"],"tm_scope":"source.c++","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","language_id":342840478},"Eiffel":{"type":"programming","color":"#4d6977","extensions":[".e"],"tm_scope":"source.eiffel","ace_mode":"eiffel","codemirror_mode":"eiffel","codemirror_mime_type":"text/x-eiffel","language_id":99},"Elixir":{"type":"programming","color":"#6e4a7e","extensions":[".ex",".exs"],"tm_scope":"source.elixir","ace_mode":"elixir","filenames":["mix.lock"],"interpreters":["elixir"],"language_id":100},"Elm":{"type":"programming","color":"#60B5CC","extensions":[".elm"],"tm_scope":"source.elm","ace_mode":"elm","codemirror_mode":"elm","codemirror_mime_type":"text/x-elm","language_id":101},"Emacs Lisp":{"type":"programming","tm_scope":"source.emacs.lisp","color":"#c065db","aliases":["elisp","emacs"],"filenames":[".abbrev_defs",".emacs",".emacs.desktop",".gnus",".spacemacs",".viper","Cask","Project.ede","_emacs","abbrev_defs"],"extensions":[".el",".emacs",".emacs.desktop"],"ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","language_id":102},"EmberScript":{"type":"programming","color":"#FFF4F3","extensions":[".em",".emberscript"],"tm_scope":"source.coffee","ace_mode":"coffee","codemirror_mode":"coffeescript","codemirror_mime_type":"text/x-coffeescript","language_id":103},"Erlang":{"type":"programming","color":"#B83998","extensions":[".erl",".app.src",".es",".escript",".hrl",".xrl",".yrl"],"filenames":["Emakefile","rebar.config","rebar.config.lock","rebar.lock"],"tm_scope":"source.erlang","ace_mode":"erlang","codemirror_mode":"erlang","codemirror_mime_type":"text/x-erlang","interpreters":["escript"],"language_id":104},"Euphoria":{"type":"programming","color":"#FF790B","extensions":[".e",".ex"],"interpreters":["eui","euiw"],"ace_mode":"text","tm_scope":"source.euphoria","language_id":880693982},"F#":{"type":"programming","color":"#b845fc","aliases":["fsharp"],"extensions":[".fs",".fsi",".fsx"],"tm_scope":"source.fsharp","ace_mode":"text","codemirror_mode":"mllike","codemirror_mime_type":"text/x-fsharp","language_id":105},"F*":{"fs_name":"Fstar","type":"programming","color":"#572e30","aliases":["fstar"],"extensions":[".fst"],"tm_scope":"source.fstar","ace_mode":"text","language_id":336943375},"FIGlet Font":{"type":"data","color":"#FFDDBB","aliases":["FIGfont"],"extensions":[".flf"],"tm_scope":"source.figfont","ace_mode":"text","language_id":686129783},"FLUX":{"type":"programming","color":"#88ccff","extensions":[".fx",".flux"],"tm_scope":"none","ace_mode":"text","language_id":106},"Factor":{"type":"programming","color":"#636746","extensions":[".factor"],"filenames":[".factor-boot-rc",".factor-rc"],"tm_scope":"source.factor","ace_mode":"text","codemirror_mode":"factor","codemirror_mime_type":"text/x-factor","language_id":108},"Fancy":{"type":"programming","color":"#7b9db4","extensions":[".fy",".fancypack"],"filenames":["Fakefile"],"tm_scope":"source.fancy","ace_mode":"text","language_id":109},"Fantom":{"type":"programming","color":"#14253c","extensions":[".fan"],"tm_scope":"source.fan","ace_mode":"text","language_id":110},"Faust":{"type":"programming","color":"#c37240","extensions":[".dsp"],"tm_scope":"source.faust","ace_mode":"text","language_id":622529198},"Fennel":{"type":"programming","tm_scope":"source.fnl","ace_mode":"text","color":"#fff3d7","interpreters":["fennel"],"extensions":[".fnl"],"language_id":239946126},"Filebench WML":{"type":"programming","color":"#F6B900","extensions":[".f"],"tm_scope":"none","ace_mode":"text","language_id":111},"Filterscript":{"type":"programming","group":"RenderScript","extensions":[".fs"],"tm_scope":"none","ace_mode":"text","language_id":112},"Fluent":{"type":"programming","color":"#ffcc33","extensions":[".ftl"],"tm_scope":"source.ftl","ace_mode":"text","language_id":206353404},"Formatted":{"type":"data","extensions":[".for",".eam.fs"],"tm_scope":"none","ace_mode":"text","language_id":113},"Forth":{"type":"programming","color":"#341708","extensions":[".fth",".4th",".f",".for",".forth",".fr",".frt",".fs"],"tm_scope":"source.forth","ace_mode":"forth","codemirror_mode":"forth","codemirror_mime_type":"text/x-forth","language_id":114},"Fortran":{"group":"Fortran","type":"programming","color":"#4d41b1","extensions":[".f",".f77",".for",".fpp"],"tm_scope":"source.fortran","ace_mode":"text","codemirror_mode":"fortran","codemirror_mime_type":"text/x-fortran","language_id":107},"Fortran Free Form":{"group":"Fortran","color":"#4d41b1","type":"programming","extensions":[".f90",".f03",".f08",".f95"],"tm_scope":"source.fortran.modern","ace_mode":"text","codemirror_mode":"fortran","codemirror_mime_type":"text/x-fortran","language_id":761352333},"FreeBasic":{"type":"programming","color":"#867db1","extensions":[".bi",".bas"],"tm_scope":"source.vbnet","aliases":["fb"],"ace_mode":"text","codemirror_mode":"vb","codemirror_mime_type":"text/x-vb","language_id":472896659},"FreeMarker":{"type":"programming","color":"#0050b2","aliases":["ftl"],"extensions":[".ftl"],"tm_scope":"text.html.ftl","ace_mode":"ftl","language_id":115},"Frege":{"type":"programming","color":"#00cafe","extensions":[".fr"],"tm_scope":"source.haskell","ace_mode":"haskell","language_id":116},"Futhark":{"type":"programming","color":"#5f021f","extensions":[".fut"],"tm_scope":"source.futhark","ace_mode":"text","language_id":97358117},"G-code":{"type":"programming","color":"#D08CF2","extensions":[".g",".cnc",".gco",".gcode"],"tm_scope":"source.gcode","ace_mode":"gcode","language_id":117},"GAML":{"type":"programming","color":"#FFC766","extensions":[".gaml"],"tm_scope":"none","ace_mode":"text","language_id":290345951},"GAMS":{"type":"programming","color":"#f49a22","extensions":[".gms"],"tm_scope":"none","ace_mode":"text","language_id":118},"GAP":{"type":"programming","color":"#0000cc","extensions":[".g",".gap",".gd",".gi",".tst"],"tm_scope":"source.gap","ace_mode":"text","language_id":119},"GCC Machine Description":{"type":"programming","color":"#FFCFAB","extensions":[".md"],"tm_scope":"source.lisp","ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","language_id":121},"GDB":{"type":"programming","extensions":[".gdb",".gdbinit"],"tm_scope":"source.gdb","ace_mode":"text","language_id":122},"GDScript":{"type":"programming","color":"#355570","extensions":[".gd"],"tm_scope":"source.gdscript","ace_mode":"text","language_id":123},"GEDCOM":{"type":"data","color":"#003058","ace_mode":"text","extensions":[".ged"],"tm_scope":"source.gedcom","language_id":459577965},"GLSL":{"type":"programming","color":"#5686a5","extensions":[".glsl",".fp",".frag",".frg",".fs",".fsh",".fshader",".geo",".geom",".glslf",".glslv",".gs",".gshader",".rchit",".rmiss",".shader",".tesc",".tese",".vert",".vrx",".vsh",".vshader"],"tm_scope":"source.glsl","ace_mode":"glsl","language_id":124},"GN":{"type":"data","extensions":[".gn",".gni"],"interpreters":["gn"],"filenames":[".gn"],"tm_scope":"source.gn","ace_mode":"python","codemirror_mode":"python","codemirror_mime_type":"text/x-python","language_id":302957008},"GSC":{"type":"programming","color":"#FF6800","extensions":[".gsc",".csc",".gsh"],"tm_scope":"source.gsc","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":257856279},"Game Maker Language":{"type":"programming","color":"#71b417","extensions":[".gml"],"tm_scope":"source.c++","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","language_id":125},"Gemfile.lock":{"type":"data","color":"#701516","searchable":false,"tm_scope":"source.gemfile-lock","ace_mode":"text","filenames":["Gemfile.lock"],"language_id":907065713},"Genero":{"type":"programming","color":"#63408e","extensions":[".4gl"],"tm_scope":"source.genero","ace_mode":"text","language_id":986054050},"Genero Forms":{"type":"markup","color":"#d8df39","extensions":[".per"],"tm_scope":"source.genero-forms","ace_mode":"text","language_id":902995658},"Genie":{"type":"programming","ace_mode":"text","extensions":[".gs"],"color":"#fb855d","tm_scope":"none","language_id":792408528},"Genshi":{"type":"programming","color":"#951531","extensions":[".kid"],"tm_scope":"text.xml.genshi","aliases":["xml+genshi","xml+kid"],"ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":126},"Gentoo Ebuild":{"type":"programming","color":"#9400ff","group":"Shell","extensions":[".ebuild"],"tm_scope":"source.shell","ace_mode":"sh","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":127},"Gentoo Eclass":{"type":"programming","color":"#9400ff","group":"Shell","extensions":[".eclass"],"tm_scope":"source.shell","ace_mode":"sh","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":128},"Gerber Image":{"type":"data","color":"#d20b00","aliases":["rs-274x"],"extensions":[".gbr",".cmp",".gbl",".gbo",".gbp",".gbs",".gko",".gml",".gpb",".gpt",".gtl",".gto",".gtp",".gts",".ncl",".sol"],"interpreters":["gerbv","gerbview"],"tm_scope":"source.gerber","ace_mode":"text","language_id":404627610},"Gettext Catalog":{"type":"prose","aliases":["pot"],"extensions":[".po",".pot"],"tm_scope":"source.po","ace_mode":"text","language_id":129},"Gherkin":{"type":"programming","extensions":[".feature",".story"],"tm_scope":"text.gherkin.feature","aliases":["cucumber"],"ace_mode":"text","color":"#5B2063","language_id":76},"Git Attributes":{"type":"data","color":"#F44D27","group":"INI","aliases":["gitattributes"],"filenames":[".gitattributes"],"tm_scope":"source.gitattributes","ace_mode":"gitignore","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":956324166},"Git Config":{"type":"data","color":"#F44D27","group":"INI","aliases":["gitconfig","gitmodules"],"extensions":[".gitconfig"],"filenames":[".gitconfig",".gitmodules"],"ace_mode":"ini","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","tm_scope":"source.gitconfig","language_id":807968997},"Gleam":{"type":"programming","color":"#ffaff3","ace_mode":"text","extensions":[".gleam"],"tm_scope":"source.gleam","language_id":1054258749},"Glyph":{"type":"programming","color":"#c1ac7f","extensions":[".glf"],"tm_scope":"source.tcl","ace_mode":"tcl","codemirror_mode":"tcl","codemirror_mime_type":"text/x-tcl","language_id":130},"Glyph Bitmap Distribution Format":{"type":"data","extensions":[".bdf"],"tm_scope":"source.bdf","ace_mode":"text","language_id":997665271},"Gnuplot":{"type":"programming","color":"#f0a9f0","extensions":[".gp",".gnu",".gnuplot",".p",".plot",".plt"],"interpreters":["gnuplot"],"tm_scope":"source.gnuplot","ace_mode":"text","language_id":131},"Go":{"type":"programming","color":"#00ADD8","aliases":["golang"],"extensions":[".go"],"tm_scope":"source.go","ace_mode":"golang","codemirror_mode":"go","codemirror_mime_type":"text/x-go","language_id":132},"Go Checksums":{"type":"data","color":"#00ADD8","aliases":["go.sum","go sum"],"filenames":["go.sum"],"tm_scope":"go.sum","ace_mode":"text","language_id":1054391671},"Go Module":{"type":"data","color":"#00ADD8","aliases":["go.mod","go mod"],"filenames":["go.mod"],"tm_scope":"go.mod","ace_mode":"text","language_id":947461016},"Golo":{"type":"programming","color":"#88562A","extensions":[".golo"],"tm_scope":"source.golo","ace_mode":"text","language_id":133},"Gosu":{"type":"programming","color":"#82937f","extensions":[".gs",".gst",".gsx",".vark"],"tm_scope":"source.gosu.2","ace_mode":"text","language_id":134},"Grace":{"type":"programming","color":"#615f8b","extensions":[".grace"],"tm_scope":"source.grace","ace_mode":"text","language_id":135},"Gradle":{"type":"data","color":"#02303a","extensions":[".gradle"],"tm_scope":"source.groovy.gradle","ace_mode":"text","language_id":136},"Grammatical Framework":{"type":"programming","aliases":["gf"],"extensions":[".gf"],"color":"#ff0000","tm_scope":"source.gf","ace_mode":"haskell","codemirror_mode":"haskell","codemirror_mime_type":"text/x-haskell","language_id":137},"Graph Modeling Language":{"type":"data","extensions":[".gml"],"tm_scope":"none","ace_mode":"text","language_id":138},"GraphQL":{"type":"data","color":"#e10098","extensions":[".graphql",".gql",".graphqls"],"tm_scope":"source.graphql","ace_mode":"text","language_id":139},"Graphviz (DOT)":{"type":"data","color":"#2596be","tm_scope":"source.dot","extensions":[".dot",".gv"],"ace_mode":"text","language_id":140},"Groovy":{"type":"programming","tm_scope":"source.groovy","ace_mode":"groovy","codemirror_mode":"groovy","codemirror_mime_type":"text/x-groovy","color":"#4298b8","extensions":[".groovy",".grt",".gtpl",".gvy"],"interpreters":["groovy"],"filenames":["Jenkinsfile"],"language_id":142},"Groovy Server Pages":{"type":"programming","color":"#4298b8","group":"Groovy","aliases":["gsp","java server page"],"extensions":[".gsp"],"tm_scope":"text.html.jsp","ace_mode":"jsp","codemirror_mode":"htmlembedded","codemirror_mime_type":"application/x-jsp","language_id":143},"HAProxy":{"type":"data","color":"#106da9","extensions":[".cfg"],"filenames":["haproxy.cfg"],"tm_scope":"source.haproxy-config","ace_mode":"text","language_id":366607477},"HCL":{"type":"programming","extensions":[".hcl",".nomad",".tf",".tfvars",".workflow"],"aliases":["HashiCorp Configuration Language","terraform"],"ace_mode":"ruby","codemirror_mode":"ruby","codemirror_mime_type":"text/x-ruby","tm_scope":"source.terraform","language_id":144},"HLSL":{"type":"programming","color":"#aace60","extensions":[".hlsl",".cginc",".fx",".fxh",".hlsli"],"ace_mode":"text","tm_scope":"source.hlsl","language_id":145},"HTML":{"type":"markup","tm_scope":"text.html.basic","ace_mode":"html","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","color":"#e34c26","aliases":["xhtml"],"extensions":[".html",".hta",".htm",".html.hl",".inc",".xht",".xhtml"],"language_id":146},"HTML+ECR":{"type":"markup","color":"#2e1052","tm_scope":"text.html.ecr","group":"HTML","aliases":["ecr"],"extensions":[".ecr"],"ace_mode":"text","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","language_id":148},"HTML+EEX":{"type":"markup","color":"#6e4a7e","tm_scope":"text.html.elixir","group":"HTML","aliases":["eex","heex","leex"],"extensions":[".eex",".html.heex",".html.leex"],"ace_mode":"text","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","language_id":149},"HTML+ERB":{"type":"markup","color":"#701516","tm_scope":"text.html.erb","group":"HTML","aliases":["erb","rhtml","html+ruby"],"extensions":[".erb",".erb.deface",".rhtml"],"ace_mode":"text","codemirror_mode":"htmlembedded","codemirror_mime_type":"application/x-erb","language_id":150},"HTML+PHP":{"type":"markup","color":"#4f5d95","tm_scope":"text.html.php","group":"HTML","extensions":[".phtml"],"ace_mode":"php","codemirror_mode":"php","codemirror_mime_type":"application/x-httpd-php","language_id":151},"HTML+Razor":{"type":"markup","color":"#512be4","tm_scope":"text.html.cshtml","group":"HTML","aliases":["razor"],"extensions":[".cshtml",".razor"],"ace_mode":"razor","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","language_id":479039817},"HTTP":{"type":"data","color":"#005C9C","extensions":[".http"],"tm_scope":"source.httpspec","ace_mode":"text","codemirror_mode":"http","codemirror_mime_type":"message/http","language_id":152},"HXML":{"type":"data","color":"#f68712","ace_mode":"text","extensions":[".hxml"],"tm_scope":"source.hxml","language_id":786683730},"Hack":{"type":"programming","ace_mode":"php","codemirror_mode":"php","codemirror_mime_type":"application/x-httpd-php","extensions":[".hack",".hh",".hhi",".php"],"tm_scope":"source.hack","color":"#878787","language_id":153},"Haml":{"type":"markup","color":"#ece2a9","extensions":[".haml",".haml.deface"],"tm_scope":"text.haml","ace_mode":"haml","codemirror_mode":"haml","codemirror_mime_type":"text/x-haml","language_id":154},"Handlebars":{"type":"markup","color":"#f7931e","aliases":["hbs","htmlbars"],"extensions":[".handlebars",".hbs"],"tm_scope":"text.html.handlebars","ace_mode":"handlebars","language_id":155},"Harbour":{"type":"programming","color":"#0e60e3","extensions":[".hb"],"tm_scope":"source.harbour","ace_mode":"text","language_id":156},"Haskell":{"type":"programming","color":"#5e5086","extensions":[".hs",".hs-boot",".hsc"],"interpreters":["runghc","runhaskell","runhugs"],"tm_scope":"source.haskell","ace_mode":"haskell","codemirror_mode":"haskell","codemirror_mime_type":"text/x-haskell","language_id":157},"Haxe":{"type":"programming","ace_mode":"haxe","codemirror_mode":"haxe","codemirror_mime_type":"text/x-haxe","color":"#df7900","extensions":[".hx",".hxsl"],"tm_scope":"source.hx","language_id":158},"HiveQL":{"type":"programming","extensions":[".q",".hql"],"color":"#dce200","tm_scope":"source.hql","ace_mode":"sql","language_id":931814087},"HolyC":{"type":"programming","color":"#ffefaf","extensions":[".hc"],"tm_scope":"source.hc","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":928121743},"Hy":{"type":"programming","ace_mode":"text","color":"#7790B2","extensions":[".hy"],"interpreters":["hy"],"aliases":["hylang"],"tm_scope":"source.hy","language_id":159},"HyPhy":{"type":"programming","ace_mode":"text","extensions":[".bf"],"tm_scope":"none","language_id":160},"IDL":{"type":"programming","color":"#a3522f","extensions":[".pro",".dlm"],"tm_scope":"source.idl","ace_mode":"text","codemirror_mode":"idl","codemirror_mime_type":"text/x-idl","language_id":161},"IGOR Pro":{"type":"programming","color":"#0000cc","extensions":[".ipf"],"aliases":["igor","igorpro"],"tm_scope":"source.igor","ace_mode":"text","language_id":162},"INI":{"type":"data","color":"#d1dbe0","extensions":[".ini",".cfg",".dof",".lektorproject",".prefs",".pro",".properties",".url"],"filenames":[".flake8","buildozer.spec"],"tm_scope":"source.ini","aliases":["dosini"],"ace_mode":"ini","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","language_id":163},"IRC log":{"type":"data","aliases":["irc","irc logs"],"extensions":[".irclog",".weechatlog"],"tm_scope":"none","ace_mode":"text","codemirror_mode":"mirc","codemirror_mime_type":"text/mirc","language_id":164},"Idris":{"type":"programming","color":"#b30000","extensions":[".idr",".lidr"],"ace_mode":"text","tm_scope":"source.idris","language_id":165},"Ignore List":{"type":"data","color":"#000000","group":"INI","aliases":["ignore","gitignore","git-ignore"],"extensions":[".gitignore"],"filenames":[".atomignore",".babelignore",".bzrignore",".coffeelintignore",".cvsignore",".dockerignore",".eleventyignore",".eslintignore",".gitignore",".markdownlintignore",".nodemonignore",".npmignore",".prettierignore",".stylelintignore",".vercelignore",".vscodeignore","gitignore-global","gitignore_global"],"ace_mode":"gitignore","tm_scope":"source.gitignore","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":74444240},"ImageJ Macro":{"type":"programming","color":"#99AAFF","aliases":["ijm"],"extensions":[".ijm"],"ace_mode":"text","tm_scope":"none","language_id":575143428},"Inform 7":{"type":"programming","wrap":true,"extensions":[".ni",".i7x"],"tm_scope":"source.inform7","aliases":["i7","inform7"],"ace_mode":"text","language_id":166},"Inno Setup":{"type":"programming","color":"#264b99","extensions":[".iss",".isl"],"tm_scope":"source.inno","ace_mode":"text","language_id":167},"Io":{"type":"programming","color":"#a9188d","extensions":[".io"],"interpreters":["io"],"tm_scope":"source.io","ace_mode":"io","language_id":168},"Ioke":{"type":"programming","color":"#078193","extensions":[".ik"],"interpreters":["ioke"],"tm_scope":"source.ioke","ace_mode":"text","language_id":169},"Isabelle":{"type":"programming","color":"#FEFE00","extensions":[".thy"],"tm_scope":"source.isabelle.theory","ace_mode":"text","language_id":170},"Isabelle ROOT":{"type":"programming","color":"#FEFE00","group":"Isabelle","filenames":["ROOT"],"tm_scope":"source.isabelle.root","ace_mode":"text","language_id":171},"J":{"type":"programming","color":"#9EEDFF","extensions":[".ijs"],"interpreters":["jconsole"],"tm_scope":"source.j","ace_mode":"text","language_id":172},"JAR Manifest":{"type":"data","color":"#b07219","filenames":["MANIFEST.MF"],"tm_scope":"source.yaml","ace_mode":"text","language_id":447261135},"JFlex":{"type":"programming","color":"#DBCA00","group":"Lex","extensions":[".flex",".jflex"],"tm_scope":"source.jflex","ace_mode":"text","language_id":173},"JSON":{"type":"data","color":"#292929","tm_scope":"source.json","ace_mode":"json","codemirror_mode":"javascript","codemirror_mime_type":"application/json","extensions":[".json",".avsc",".geojson",".gltf",".har",".ice",".JSON-tmLanguage",".jsonl",".mcmeta",".tfstate",".tfstate.backup",".topojson",".webapp",".webmanifest",".yy",".yyp"],"filenames":[".arcconfig",".auto-changelog",".c8rc",".htmlhintrc",".imgbotconfig",".nycrc",".tern-config",".tern-project",".watchmanconfig","Pipfile.lock","composer.lock","mcmod.info"],"language_id":174},"JSON with Comments":{"type":"data","color":"#292929","group":"JSON","tm_scope":"source.js","ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"text/javascript","aliases":["jsonc"],"extensions":[".jsonc",".code-snippets",".sublime-build",".sublime-commands",".sublime-completions",".sublime-keymap",".sublime-macro",".sublime-menu",".sublime-mousemap",".sublime-project",".sublime-settings",".sublime-theme",".sublime-workspace",".sublime_metrics",".sublime_session"],"filenames":[".babelrc",".eslintrc.json",".jscsrc",".jshintrc",".jslintrc","api-extractor.json","devcontainer.json","jsconfig.json","language-configuration.json","tsconfig.json","tslint.json"],"language_id":423},"JSON5":{"type":"data","color":"#267CB9","extensions":[".json5"],"tm_scope":"source.js","ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"application/json","language_id":175},"JSONLD":{"type":"data","color":"#0c479c","extensions":[".jsonld"],"tm_scope":"source.js","ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"application/json","language_id":176},"JSONiq":{"color":"#40d47e","type":"programming","ace_mode":"jsoniq","codemirror_mode":"javascript","codemirror_mime_type":"application/json","extensions":[".jq"],"tm_scope":"source.jsoniq","language_id":177},"Janet":{"type":"programming","color":"#0886a5","extensions":[".janet"],"tm_scope":"source.janet","ace_mode":"scheme","codemirror_mode":"scheme","codemirror_mime_type":"text/x-scheme","interpreters":["janet"],"language_id":1028705371},"Jasmin":{"type":"programming","color":"#d03600","ace_mode":"java","extensions":[".j"],"tm_scope":"source.jasmin","language_id":180},"Java":{"type":"programming","tm_scope":"source.java","ace_mode":"java","codemirror_mode":"clike","codemirror_mime_type":"text/x-java","color":"#b07219","extensions":[".java",".jav"],"language_id":181},"Java Properties":{"type":"data","color":"#2A6277","extensions":[".properties"],"tm_scope":"source.java-properties","ace_mode":"properties","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","language_id":519377561},"Java Server Pages":{"type":"programming","color":"#2A6277","group":"Java","aliases":["jsp"],"extensions":[".jsp"],"tm_scope":"text.html.jsp","ace_mode":"jsp","codemirror_mode":"htmlembedded","codemirror_mime_type":"application/x-jsp","language_id":182},"JavaScript":{"type":"programming","tm_scope":"source.js","ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"text/javascript","color":"#f1e05a","aliases":["js","node"],"extensions":[".js","._js",".bones",".cjs",".es",".es6",".frag",".gs",".jake",".javascript",".jsb",".jscad",".jsfl",".jslib",".jsm",".jspre",".jss",".jsx",".mjs",".njs",".pac",".sjs",".ssjs",".xsjs",".xsjslib"],"filenames":["Jakefile"],"interpreters":["chakra","d8","gjs","js","node","nodejs","qjs","rhino","v8","v8-shell"],"language_id":183},"JavaScript+ERB":{"type":"programming","color":"#f1e05a","tm_scope":"source.js","group":"JavaScript","extensions":[".js.erb"],"ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"application/javascript","language_id":914318960},"Jest Snapshot":{"type":"data","color":"#15c213","tm_scope":"source.jest.snap","extensions":[".snap"],"ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"application/javascript","language_id":774635084},"Jinja":{"type":"markup","color":"#a52a22","aliases":["django","html+django","html+jinja","htmldjango"],"extensions":[".jinja",".j2",".jinja2"],"tm_scope":"text.html.django","ace_mode":"django","codemirror_mode":"django","codemirror_mime_type":"text/x-django","language_id":147},"Jison":{"type":"programming","color":"#56b3cb","group":"Yacc","extensions":[".jison"],"tm_scope":"source.jison","ace_mode":"text","language_id":284531423},"Jison Lex":{"type":"programming","color":"#56b3cb","group":"Lex","extensions":[".jisonlex"],"tm_scope":"source.jisonlex","ace_mode":"text","language_id":406395330},"Jolie":{"type":"programming","extensions":[".ol",".iol"],"interpreters":["jolie"],"color":"#843179","ace_mode":"text","tm_scope":"source.jolie","language_id":998078858},"Jsonnet":{"color":"#0064bd","type":"programming","ace_mode":"text","extensions":[".jsonnet",".libsonnet"],"tm_scope":"source.jsonnet","language_id":664885656},"Julia":{"type":"programming","extensions":[".jl"],"interpreters":["julia"],"color":"#a270ba","tm_scope":"source.julia","ace_mode":"julia","codemirror_mode":"julia","codemirror_mime_type":"text/x-julia","language_id":184},"Jupyter Notebook":{"type":"markup","ace_mode":"json","codemirror_mode":"javascript","codemirror_mime_type":"application/json","tm_scope":"source.json","color":"#DA5B0B","extensions":[".ipynb"],"filenames":["Notebook"],"aliases":["IPython Notebook"],"language_id":185},"KRL":{"type":"programming","color":"#28430A","extensions":[".krl"],"tm_scope":"none","ace_mode":"text","language_id":186},"Kaitai Struct":{"type":"programming","aliases":["ksy"],"ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","color":"#773b37","extensions":[".ksy"],"tm_scope":"source.yaml","language_id":818804755},"KakouneScript":{"type":"programming","color":"#6f8042","tm_scope":"source.kakscript","aliases":["kak","kakscript"],"extensions":[".kak"],"filenames":["kakrc"],"ace_mode":"text","language_id":603336474},"KiCad Layout":{"type":"data","color":"#2f4aab","aliases":["pcbnew"],"extensions":[".kicad_pcb",".kicad_mod",".kicad_wks"],"filenames":["fp-lib-table"],"tm_scope":"source.pcb.sexp","ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","language_id":187},"KiCad Legacy Layout":{"type":"data","color":"#2f4aab","extensions":[".brd"],"tm_scope":"source.pcb.board","ace_mode":"text","language_id":140848857},"KiCad Schematic":{"type":"data","color":"#2f4aab","aliases":["eeschema schematic"],"extensions":[".sch"],"tm_scope":"source.pcb.schematic","ace_mode":"text","language_id":622447435},"Kit":{"type":"markup","ace_mode":"html","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","extensions":[".kit"],"tm_scope":"text.html.basic","language_id":188},"Kotlin":{"type":"programming","color":"#A97BFF","extensions":[".kt",".ktm",".kts"],"tm_scope":"source.kotlin","ace_mode":"text","codemirror_mode":"clike","codemirror_mime_type":"text/x-kotlin","language_id":189},"Kusto":{"type":"data","extensions":[".csl"],"tm_scope":"source.kusto","ace_mode":"text","language_id":225697190},"LFE":{"type":"programming","color":"#4C3023","extensions":[".lfe"],"tm_scope":"source.lisp","ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","language_id":190},"LLVM":{"type":"programming","extensions":[".ll"],"tm_scope":"source.llvm","ace_mode":"text","color":"#185619","language_id":191},"LOLCODE":{"type":"programming","extensions":[".lol"],"color":"#cc9900","tm_scope":"none","ace_mode":"text","language_id":192},"LSL":{"type":"programming","tm_scope":"source.lsl","ace_mode":"lsl","extensions":[".lsl",".lslp"],"interpreters":["lsl"],"color":"#3d9970","language_id":193},"LTspice Symbol":{"type":"data","extensions":[".asy"],"tm_scope":"source.ltspice.symbol","ace_mode":"text","codemirror_mode":"spreadsheet","codemirror_mime_type":"text/x-spreadsheet","language_id":1013566805},"LabVIEW":{"type":"programming","color":"#fede06","extensions":[".lvproj",".lvlib"],"tm_scope":"text.xml","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":194},"Lark":{"type":"data","color":"#2980B9","extensions":[".lark"],"tm_scope":"source.lark","ace_mode":"text","codemirror_mode":"ebnf","codemirror_mime_type":"text/x-ebnf","language_id":758480799},"Lasso":{"type":"programming","color":"#999999","extensions":[".lasso",".las",".lasso8",".lasso9"],"tm_scope":"file.lasso","aliases":["lassoscript"],"ace_mode":"text","language_id":195},"Latte":{"type":"markup","color":"#f2a542","extensions":[".latte"],"tm_scope":"text.html.smarty","ace_mode":"smarty","codemirror_mode":"smarty","codemirror_mime_type":"text/x-smarty","language_id":196},"Lean":{"type":"programming","extensions":[".lean",".hlean"],"tm_scope":"source.lean","ace_mode":"text","language_id":197},"Less":{"type":"markup","color":"#1d365d","aliases":["less-css"],"extensions":[".less"],"tm_scope":"source.css.less","ace_mode":"less","codemirror_mode":"css","codemirror_mime_type":"text/css","language_id":198},"Lex":{"type":"programming","color":"#DBCA00","aliases":["flex"],"extensions":[".l",".lex"],"filenames":["Lexer.x","lexer.x"],"tm_scope":"source.lex","ace_mode":"text","language_id":199},"LigoLANG":{"type":"programming","color":"#0e74ff","extensions":[".ligo"],"tm_scope":"source.ligo","ace_mode":"pascal","codemirror_mode":"pascal","codemirror_mime_type":"text/x-pascal","group":"LigoLANG","language_id":1040646257},"LilyPond":{"type":"programming","color":"#9ccc7c","extensions":[".ly",".ily"],"tm_scope":"source.lilypond","ace_mode":"text","language_id":200},"Limbo":{"type":"programming","extensions":[".b",".m"],"tm_scope":"none","ace_mode":"text","language_id":201},"Linker Script":{"type":"data","extensions":[".ld",".lds",".x"],"filenames":["ld.script"],"tm_scope":"none","ace_mode":"text","language_id":202},"Linux Kernel Module":{"type":"data","extensions":[".mod"],"tm_scope":"none","ace_mode":"text","language_id":203},"Liquid":{"type":"markup","color":"#67b8de","extensions":[".liquid"],"tm_scope":"text.html.liquid","ace_mode":"liquid","language_id":204},"Literate Agda":{"type":"programming","color":"#315665","group":"Agda","extensions":[".lagda"],"tm_scope":"none","ace_mode":"text","language_id":205},"Literate CoffeeScript":{"type":"programming","color":"#244776","tm_scope":"source.litcoffee","group":"CoffeeScript","ace_mode":"text","wrap":true,"aliases":["litcoffee"],"extensions":[".litcoffee",".coffee.md"],"language_id":206},"Literate Haskell":{"type":"programming","color":"#5e5086","group":"Haskell","aliases":["lhaskell","lhs"],"extensions":[".lhs"],"tm_scope":"text.tex.latex.haskell","ace_mode":"text","codemirror_mode":"haskell-literate","codemirror_mime_type":"text/x-literate-haskell","language_id":207},"LiveScript":{"type":"programming","color":"#499886","aliases":["live-script","ls"],"extensions":[".ls","._ls"],"filenames":["Slakefile"],"tm_scope":"source.livescript","ace_mode":"livescript","codemirror_mode":"livescript","codemirror_mime_type":"text/x-livescript","language_id":208},"Logos":{"type":"programming","extensions":[".xm",".x",".xi"],"ace_mode":"text","tm_scope":"source.logos","language_id":209},"Logtalk":{"type":"programming","color":"#295b9a","extensions":[".lgt",".logtalk"],"tm_scope":"source.logtalk","ace_mode":"text","language_id":210},"LookML":{"type":"programming","ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","color":"#652B81","extensions":[".lookml",".model.lkml",".view.lkml"],"tm_scope":"source.yaml","language_id":211},"LoomScript":{"type":"programming","extensions":[".ls"],"tm_scope":"source.loomscript","ace_mode":"text","language_id":212},"Lua":{"type":"programming","tm_scope":"source.lua","ace_mode":"lua","codemirror_mode":"lua","codemirror_mime_type":"text/x-lua","color":"#000080","extensions":[".lua",".fcgi",".nse",".p8",".pd_lua",".rbxs",".rockspec",".wlua"],"filenames":[".luacheckrc"],"interpreters":["lua"],"language_id":213},"M":{"type":"programming","aliases":["mumps"],"extensions":[".mumps",".m"],"ace_mode":"text","codemirror_mode":"mumps","codemirror_mime_type":"text/x-mumps","language_id":214,"tm_scope":"none"},"M4":{"type":"programming","extensions":[".m4",".mc"],"tm_scope":"source.m4","ace_mode":"text","language_id":215},"M4Sugar":{"type":"programming","group":"M4","aliases":["autoconf"],"extensions":[".m4"],"filenames":["configure.ac"],"tm_scope":"source.m4","ace_mode":"text","language_id":216},"MATLAB":{"type":"programming","color":"#e16737","aliases":["octave"],"extensions":[".matlab",".m"],"tm_scope":"source.matlab","ace_mode":"matlab","codemirror_mode":"octave","codemirror_mime_type":"text/x-octave","language_id":225},"MAXScript":{"type":"programming","color":"#00a6a6","extensions":[".ms",".mcr"],"tm_scope":"source.maxscript","ace_mode":"text","language_id":217},"MLIR":{"type":"programming","color":"#5EC8DB","extensions":[".mlir"],"tm_scope":"source.mlir","ace_mode":"text","language_id":448253929},"MQL4":{"type":"programming","color":"#62A8D6","extensions":[".mq4",".mqh"],"tm_scope":"source.mql5","ace_mode":"c_cpp","language_id":426},"MQL5":{"type":"programming","color":"#4A76B8","extensions":[".mq5",".mqh"],"tm_scope":"source.mql5","ace_mode":"c_cpp","language_id":427},"MTML":{"type":"markup","color":"#b7e1f4","extensions":[".mtml"],"tm_scope":"text.html.basic","ace_mode":"html","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","language_id":218},"MUF":{"type":"programming","group":"Forth","extensions":[".muf",".m"],"tm_scope":"none","ace_mode":"forth","codemirror_mode":"forth","codemirror_mime_type":"text/x-forth","language_id":219},"Macaulay2":{"type":"programming","extensions":[".m2"],"aliases":["m2"],"interpreters":["M2"],"ace_mode":"text","tm_scope":"source.m2","color":"#d8ffff","language_id":34167825},"Makefile":{"type":"programming","color":"#427819","aliases":["bsdmake","make","mf"],"extensions":[".mak",".d",".make",".makefile",".mk",".mkfile"],"filenames":["BSDmakefile","GNUmakefile","Kbuild","Makefile","Makefile.am","Makefile.boot","Makefile.frag","Makefile.in","Makefile.inc","Makefile.wat","makefile","makefile.sco","mkfile"],"interpreters":["make"],"tm_scope":"source.makefile","ace_mode":"makefile","codemirror_mode":"cmake","codemirror_mime_type":"text/x-cmake","language_id":220},"Mako":{"type":"programming","color":"#7e858d","extensions":[".mako",".mao"],"tm_scope":"text.html.mako","ace_mode":"text","language_id":221},"Markdown":{"type":"prose","color":"#083fa1","aliases":["pandoc"],"ace_mode":"markdown","codemirror_mode":"gfm","codemirror_mime_type":"text/x-gfm","wrap":true,"extensions":[".md",".markdown",".mdown",".mdwn",".mdx",".mkd",".mkdn",".mkdown",".ronn",".scd",".workbook"],"filenames":["contents.lr"],"tm_scope":"source.gfm","language_id":222},"Marko":{"type":"markup","color":"#42bff2","tm_scope":"text.marko","extensions":[".marko"],"aliases":["markojs"],"ace_mode":"text","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","language_id":932782397},"Mask":{"type":"markup","color":"#f97732","ace_mode":"mask","extensions":[".mask"],"tm_scope":"source.mask","language_id":223},"Mathematica":{"type":"programming","color":"#dd1100","extensions":[".mathematica",".cdf",".m",".ma",".mt",".nb",".nbp",".wl",".wlt"],"aliases":["mma","wolfram","wolfram language","wolfram lang","wl"],"tm_scope":"source.mathematica","ace_mode":"text","codemirror_mode":"mathematica","codemirror_mime_type":"text/x-mathematica","language_id":224},"Maven POM":{"type":"data","group":"XML","tm_scope":"text.xml.pom","filenames":["pom.xml"],"ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":226},"Max":{"type":"programming","color":"#c4a79c","aliases":["max/msp","maxmsp"],"extensions":[".maxpat",".maxhelp",".maxproj",".mxt",".pat"],"tm_scope":"source.json","ace_mode":"json","codemirror_mode":"javascript","codemirror_mime_type":"application/json","language_id":227},"Mercury":{"type":"programming","color":"#ff2b2b","ace_mode":"prolog","interpreters":["mmi"],"extensions":[".m",".moo"],"tm_scope":"source.mercury","language_id":229},"Meson":{"type":"programming","color":"#007800","filenames":["meson.build","meson_options.txt"],"tm_scope":"source.meson","ace_mode":"text","language_id":799141244},"Metal":{"type":"programming","color":"#8f14e9","extensions":[".metal"],"tm_scope":"source.c++","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","language_id":230},"Microsoft Developer Studio Project":{"type":"data","extensions":[".dsp"],"tm_scope":"none","ace_mode":"text","language_id":800983837},"Microsoft Visual Studio Solution":{"type":"data","extensions":[".sln"],"tm_scope":"source.solution","ace_mode":"text","language_id":849523096},"MiniD":{"type":"programming","extensions":[".minid"],"tm_scope":"none","ace_mode":"text","language_id":231},"MiniYAML":{"type":"data","color":"#ff1111","tm_scope":"source.miniyaml","extensions":[".yaml"],"ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","language_id":4896465},"Mint":{"type":"programming","extensions":[".mint"],"ace_mode":"text","color":"#02b046","tm_scope":"source.mint","language_id":968740319},"Mirah":{"type":"programming","color":"#c7a938","extensions":[".druby",".duby",".mirah"],"tm_scope":"source.ruby","ace_mode":"ruby","codemirror_mode":"ruby","codemirror_mime_type":"text/x-ruby","language_id":232},"Modelica":{"type":"programming","color":"#de1d31","extensions":[".mo"],"tm_scope":"source.modelica","ace_mode":"text","codemirror_mode":"modelica","codemirror_mime_type":"text/x-modelica","language_id":233},"Modula-2":{"type":"programming","color":"#10253f","extensions":[".mod"],"tm_scope":"source.modula2","ace_mode":"text","language_id":234},"Modula-3":{"type":"programming","extensions":[".i3",".ig",".m3",".mg"],"color":"#223388","ace_mode":"text","tm_scope":"source.modula-3","language_id":564743864},"Module Management System":{"type":"programming","extensions":[".mms",".mmk"],"filenames":["descrip.mmk","descrip.mms"],"tm_scope":"none","ace_mode":"text","language_id":235},"Monkey":{"type":"programming","extensions":[".monkey",".monkey2"],"ace_mode":"text","tm_scope":"source.monkey","language_id":236},"Monkey C":{"type":"programming","color":"#8D6747","extensions":[".mc"],"tm_scope":"source.mc","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":231751931},"Moocode":{"type":"programming","extensions":[".moo"],"tm_scope":"none","ace_mode":"text","language_id":237},"MoonScript":{"type":"programming","color":"#ff4585","extensions":[".moon"],"interpreters":["moon"],"tm_scope":"source.moonscript","ace_mode":"text","language_id":238},"Motoko":{"type":"programming","color":"#fbb03b","extensions":[".mo"],"tm_scope":"source.mo","ace_mode":"text","language_id":202937027},"Motorola 68K Assembly":{"type":"programming","color":"#005daa","group":"Assembly","aliases":["m68k"],"extensions":[".asm",".i",".inc",".s",".x68"],"tm_scope":"source.m68k","ace_mode":"assembly_x86","language_id":477582706},"Muse":{"type":"prose","extensions":[".muse"],"tm_scope":"text.muse","ace_mode":"text","wrap":true,"language_id":474864066,"aliases":["amusewiki","emacs muse"]},"Mustache":{"type":"markup","color":"#724b3b","extensions":[".mustache"],"tm_scope":"text.html.smarty","ace_mode":"smarty","codemirror_mode":"smarty","codemirror_mime_type":"text/x-smarty","language_id":638334590},"Myghty":{"type":"programming","extensions":[".myt"],"tm_scope":"none","ace_mode":"text","language_id":239},"NASL":{"type":"programming","extensions":[".nasl",".inc"],"tm_scope":"source.nasl","ace_mode":"text","language_id":171666519},"NCL":{"type":"programming","color":"#28431f","extensions":[".ncl"],"tm_scope":"source.ncl","ace_mode":"text","language_id":240},"NEON":{"type":"data","extensions":[".neon"],"tm_scope":"source.neon","ace_mode":"text","aliases":["nette object notation","ne-on"],"language_id":481192983},"NL":{"type":"data","extensions":[".nl"],"tm_scope":"none","ace_mode":"text","language_id":241},"NPM Config":{"type":"data","color":"#cb3837","group":"INI","aliases":["npmrc"],"filenames":[".npmrc"],"tm_scope":"source.ini.npmrc","ace_mode":"text","language_id":685022663},"NSIS":{"type":"programming","extensions":[".nsi",".nsh"],"tm_scope":"source.nsis","ace_mode":"text","codemirror_mode":"nsis","codemirror_mime_type":"text/x-nsis","language_id":242},"NWScript":{"type":"programming","color":"#111522","extensions":[".nss"],"tm_scope":"source.c.nwscript","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":731233819},"Nearley":{"type":"programming","ace_mode":"text","color":"#990000","extensions":[".ne",".nearley"],"tm_scope":"source.ne","language_id":521429430},"Nemerle":{"type":"programming","color":"#3d3c6e","extensions":[".n"],"tm_scope":"source.nemerle","ace_mode":"text","language_id":243},"NetLinx":{"type":"programming","color":"#0aa0ff","extensions":[".axs",".axi"],"tm_scope":"source.netlinx","ace_mode":"text","language_id":244},"NetLinx+ERB":{"type":"programming","color":"#747faa","extensions":[".axs.erb",".axi.erb"],"tm_scope":"source.netlinx.erb","ace_mode":"text","language_id":245},"NetLogo":{"type":"programming","color":"#ff6375","extensions":[".nlogo"],"tm_scope":"source.lisp","ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","language_id":246},"NewLisp":{"type":"programming","color":"#87AED7","extensions":[".nl",".lisp",".lsp"],"interpreters":["newlisp"],"tm_scope":"source.lisp","ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","language_id":247},"Nextflow":{"type":"programming","ace_mode":"groovy","tm_scope":"source.nextflow","color":"#3ac486","extensions":[".nf"],"filenames":["nextflow.config"],"interpreters":["nextflow"],"language_id":506780613},"Nginx":{"type":"data","color":"#009639","extensions":[".nginx",".nginxconf",".vhost"],"filenames":["nginx.conf"],"tm_scope":"source.nginx","aliases":["nginx configuration file"],"ace_mode":"text","codemirror_mode":"nginx","codemirror_mime_type":"text/x-nginx-conf","language_id":248},"Nim":{"type":"programming","color":"#ffc200","extensions":[".nim",".nim.cfg",".nimble",".nimrod",".nims"],"filenames":["nim.cfg"],"ace_mode":"text","tm_scope":"source.nim","language_id":249},"Ninja":{"type":"data","tm_scope":"source.ninja","extensions":[".ninja"],"ace_mode":"text","language_id":250},"Nit":{"type":"programming","color":"#009917","extensions":[".nit"],"tm_scope":"source.nit","ace_mode":"text","language_id":251},"Nix":{"type":"programming","color":"#7e7eff","extensions":[".nix"],"aliases":["nixos"],"tm_scope":"source.nix","ace_mode":"nix","language_id":252},"Nu":{"type":"programming","color":"#c9df40","aliases":["nush"],"extensions":[".nu"],"filenames":["Nukefile"],"tm_scope":"source.nu","ace_mode":"scheme","codemirror_mode":"scheme","codemirror_mime_type":"text/x-scheme","interpreters":["nush"],"language_id":253},"NumPy":{"type":"programming","color":"#9C8AF9","group":"Python","extensions":[".numpy",".numpyw",".numsc"],"tm_scope":"none","ace_mode":"text","codemirror_mode":"python","codemirror_mime_type":"text/x-python","language_id":254},"Nunjucks":{"type":"markup","color":"#3d8137","extensions":[".njk"],"aliases":["njk"],"tm_scope":"text.html.nunjucks","ace_mode":"nunjucks","language_id":461856962},"OCaml":{"type":"programming","ace_mode":"ocaml","codemirror_mode":"mllike","codemirror_mime_type":"text/x-ocaml","color":"#3be133","extensions":[".ml",".eliom",".eliomi",".ml4",".mli",".mll",".mly"],"interpreters":["ocaml","ocamlrun","ocamlscript"],"tm_scope":"source.ocaml","language_id":255},"ObjDump":{"type":"data","extensions":[".objdump"],"tm_scope":"objdump.x86asm","ace_mode":"assembly_x86","language_id":256},"Object Data Instance Notation":{"type":"data","extensions":[".odin"],"tm_scope":"source.odin-ehr","ace_mode":"text","language_id":985227236},"ObjectScript":{"type":"programming","extensions":[".cls"],"language_id":202735509,"tm_scope":"source.objectscript","color":"#424893","ace_mode":"text"},"Objective-C":{"type":"programming","tm_scope":"source.objc","color":"#438eff","aliases":["obj-c","objc","objectivec"],"extensions":[".m",".h"],"ace_mode":"objectivec","codemirror_mode":"clike","codemirror_mime_type":"text/x-objectivec","language_id":257},"Objective-C++":{"type":"programming","tm_scope":"source.objc++","color":"#6866fb","aliases":["obj-c++","objc++","objectivec++"],"extensions":[".mm"],"ace_mode":"objectivec","codemirror_mode":"clike","codemirror_mime_type":"text/x-objectivec","language_id":258},"Objective-J":{"type":"programming","color":"#ff0c5a","aliases":["obj-j","objectivej","objj"],"extensions":[".j",".sj"],"tm_scope":"source.js.objj","ace_mode":"text","language_id":259},"Odin":{"type":"programming","color":"#60AFFE","aliases":["odinlang","odin-lang"],"extensions":[".odin"],"tm_scope":"source.odin","ace_mode":"text","language_id":889244082},"Omgrofl":{"type":"programming","extensions":[".omgrofl"],"color":"#cabbff","tm_scope":"none","ace_mode":"text","language_id":260},"Opa":{"type":"programming","extensions":[".opa"],"tm_scope":"source.opa","ace_mode":"text","language_id":261},"Opal":{"type":"programming","color":"#f7ede0","extensions":[".opal"],"tm_scope":"source.opal","ace_mode":"text","language_id":262},"Open Policy Agent":{"type":"programming","color":"#7d9199","ace_mode":"text","extensions":[".rego"],"language_id":840483232,"tm_scope":"source.rego"},"OpenCL":{"type":"programming","color":"#ed2e2d","group":"C","extensions":[".cl",".opencl"],"tm_scope":"source.c","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":263},"OpenEdge ABL":{"type":"programming","color":"#5ce600","aliases":["progress","openedge","abl"],"extensions":[".p",".cls",".w"],"tm_scope":"source.abl","ace_mode":"text","language_id":264},"OpenQASM":{"type":"programming","extensions":[".qasm"],"color":"#AA70FF","tm_scope":"source.qasm","ace_mode":"text","language_id":153739399},"OpenRC runscript":{"type":"programming","group":"Shell","aliases":["openrc"],"interpreters":["openrc-run"],"tm_scope":"source.shell","ace_mode":"sh","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":265},"OpenSCAD":{"type":"programming","color":"#e5cd45","extensions":[".scad"],"tm_scope":"source.scad","ace_mode":"scad","language_id":266},"OpenStep Property List":{"type":"data","extensions":[".plist",".glyphs"],"tm_scope":"source.plist","ace_mode":"text","language_id":598917541},"OpenType Feature File":{"type":"data","aliases":["AFDKO"],"extensions":[".fea"],"tm_scope":"source.opentype","ace_mode":"text","language_id":374317347},"Org":{"type":"prose","color":"#77aa99","wrap":true,"extensions":[".org"],"tm_scope":"none","ace_mode":"text","language_id":267},"Ox":{"type":"programming","extensions":[".ox",".oxh",".oxo"],"tm_scope":"source.ox","ace_mode":"text","language_id":268},"Oxygene":{"type":"programming","color":"#cdd0e3","extensions":[".oxygene"],"tm_scope":"none","ace_mode":"text","language_id":269},"Oz":{"type":"programming","color":"#fab738","extensions":[".oz"],"tm_scope":"source.oz","ace_mode":"text","codemirror_mode":"oz","codemirror_mime_type":"text/x-oz","language_id":270},"P4":{"type":"programming","color":"#7055b5","extensions":[".p4"],"tm_scope":"source.p4","ace_mode":"text","language_id":348895984},"PEG.js":{"type":"programming","color":"#234d6b","extensions":[".pegjs"],"tm_scope":"source.pegjs","ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"text/javascript","language_id":81442128},"PHP":{"type":"programming","tm_scope":"text.html.php","ace_mode":"php","codemirror_mode":"php","codemirror_mime_type":"application/x-httpd-php","color":"#4F5D95","extensions":[".php",".aw",".ctp",".fcgi",".inc",".php3",".php4",".php5",".phps",".phpt"],"filenames":[".php",".php_cs",".php_cs.dist","Phakefile"],"interpreters":["php"],"aliases":["inc"],"language_id":272},"PLSQL":{"type":"programming","ace_mode":"sql","codemirror_mode":"sql","codemirror_mime_type":"text/x-plsql","tm_scope":"none","color":"#dad8d8","extensions":[".pls",".bdy",".ddl",".fnc",".pck",".pkb",".pks",".plb",".plsql",".prc",".spc",".sql",".tpb",".tps",".trg",".vw"],"language_id":273},"PLpgSQL":{"type":"programming","color":"#336790","ace_mode":"pgsql","codemirror_mode":"sql","codemirror_mime_type":"text/x-sql","tm_scope":"source.sql","extensions":[".pgsql",".sql"],"language_id":274},"POV-Ray SDL":{"type":"programming","color":"#6bac65","aliases":["pov-ray","povray"],"extensions":[".pov",".inc"],"tm_scope":"source.pov-ray sdl","ace_mode":"text","language_id":275},"Pan":{"type":"programming","color":"#cc0000","extensions":[".pan"],"tm_scope":"source.pan","ace_mode":"text","language_id":276},"Papyrus":{"type":"programming","color":"#6600cc","extensions":[".psc"],"tm_scope":"source.papyrus.skyrim","ace_mode":"text","language_id":277},"Parrot":{"type":"programming","color":"#f3ca0a","extensions":[".parrot"],"tm_scope":"none","ace_mode":"text","language_id":278},"Parrot Assembly":{"group":"Parrot","type":"programming","aliases":["pasm"],"extensions":[".pasm"],"interpreters":["parrot"],"tm_scope":"none","ace_mode":"text","language_id":279},"Parrot Internal Representation":{"group":"Parrot","tm_scope":"source.parrot.pir","type":"programming","aliases":["pir"],"extensions":[".pir"],"interpreters":["parrot"],"ace_mode":"text","language_id":280},"Pascal":{"type":"programming","color":"#E3F171","aliases":["delphi","objectpascal"],"extensions":[".pas",".dfm",".dpr",".inc",".lpr",".pascal",".pp"],"interpreters":["instantfpc"],"tm_scope":"source.pascal","ace_mode":"pascal","codemirror_mode":"pascal","codemirror_mime_type":"text/x-pascal","language_id":281},"Pawn":{"type":"programming","color":"#dbb284","extensions":[".pwn",".inc",".sma"],"tm_scope":"source.pawn","ace_mode":"text","language_id":271},"Pep8":{"type":"programming","color":"#C76F5B","extensions":[".pep"],"ace_mode":"text","tm_scope":"source.pep8","language_id":840372442},"Perl":{"type":"programming","tm_scope":"source.perl","ace_mode":"perl","codemirror_mode":"perl","codemirror_mime_type":"text/x-perl","color":"#0298c3","extensions":[".pl",".al",".cgi",".fcgi",".perl",".ph",".plx",".pm",".psgi",".t"],"filenames":["Makefile.PL","Rexfile","ack","cpanfile"],"interpreters":["cperl","perl"],"aliases":["cperl"],"language_id":282},"Pic":{"type":"markup","group":"Roff","tm_scope":"source.pic","extensions":[".pic",".chem"],"ace_mode":"text","codemirror_mode":"troff","codemirror_mime_type":"text/troff","language_id":425},"Pickle":{"type":"data","extensions":[".pkl"],"tm_scope":"none","ace_mode":"text","language_id":284},"PicoLisp":{"type":"programming","color":"#6067af","extensions":[".l"],"interpreters":["picolisp","pil"],"tm_scope":"source.lisp","ace_mode":"lisp","language_id":285},"PigLatin":{"type":"programming","color":"#fcd7de","extensions":[".pig"],"tm_scope":"source.pig_latin","ace_mode":"text","language_id":286},"Pike":{"type":"programming","color":"#005390","extensions":[".pike",".pmod"],"interpreters":["pike"],"tm_scope":"source.pike","ace_mode":"text","language_id":287},"PlantUML":{"type":"data","extensions":[".puml",".iuml",".plantuml"],"tm_scope":"source.wsd","ace_mode":"text","language_id":833504686},"Pod":{"type":"prose","ace_mode":"perl","codemirror_mode":"perl","codemirror_mime_type":"text/x-perl","wrap":true,"extensions":[".pod"],"interpreters":["perl"],"tm_scope":"none","language_id":288},"Pod 6":{"type":"prose","ace_mode":"perl","tm_scope":"source.raku","wrap":true,"extensions":[".pod",".pod6"],"interpreters":["perl6"],"language_id":155357471},"PogoScript":{"type":"programming","color":"#d80074","extensions":[".pogo"],"tm_scope":"source.pogoscript","ace_mode":"text","language_id":289},"Pony":{"type":"programming","extensions":[".pony"],"tm_scope":"source.pony","ace_mode":"text","language_id":290},"PostCSS":{"type":"markup","color":"#dc3a0c","tm_scope":"source.postcss","group":"CSS","extensions":[".pcss",".postcss"],"ace_mode":"text","language_id":262764437},"PostScript":{"type":"markup","color":"#da291c","extensions":[".ps",".eps",".epsi",".pfa"],"tm_scope":"source.postscript","aliases":["postscr"],"ace_mode":"text","language_id":291},"PowerBuilder":{"type":"programming","color":"#8f0f8d","extensions":[".pbt",".sra",".sru",".srw"],"tm_scope":"none","ace_mode":"text","language_id":292},"PowerShell":{"type":"programming","color":"#012456","tm_scope":"source.powershell","ace_mode":"powershell","codemirror_mode":"powershell","codemirror_mime_type":"application/x-powershell","aliases":["posh","pwsh"],"extensions":[".ps1",".psd1",".psm1"],"interpreters":["pwsh"],"language_id":293},"Prisma":{"type":"data","color":"#0c344b","extensions":[".prisma"],"tm_scope":"source.prisma","ace_mode":"text","language_id":499933428},"Processing":{"type":"programming","color":"#0096D8","extensions":[".pde"],"tm_scope":"source.processing","ace_mode":"text","language_id":294},"Procfile":{"type":"programming","color":"#3B2F63","filenames":["Procfile"],"tm_scope":"source.procfile","ace_mode":"batchfile","language_id":305313959},"Proguard":{"type":"data","extensions":[".pro"],"tm_scope":"none","ace_mode":"text","language_id":716513858},"Prolog":{"type":"programming","color":"#74283c","extensions":[".pl",".pro",".prolog",".yap"],"interpreters":["swipl","yap"],"tm_scope":"source.prolog","ace_mode":"prolog","language_id":295},"Promela":{"type":"programming","color":"#de0000","tm_scope":"source.promela","ace_mode":"text","extensions":[".pml"],"language_id":441858312},"Propeller Spin":{"type":"programming","color":"#7fa2a7","extensions":[".spin"],"tm_scope":"source.spin","ace_mode":"text","language_id":296},"Protocol Buffer":{"type":"data","aliases":["protobuf","Protocol Buffers"],"extensions":[".proto"],"tm_scope":"source.proto","ace_mode":"protobuf","codemirror_mode":"protobuf","codemirror_mime_type":"text/x-protobuf","language_id":297},"Protocol Buffer Text Format":{"type":"data","aliases":["text proto","protobuf text format"],"extensions":[".textproto",".pbt",".pbtxt"],"tm_scope":"source.textproto","ace_mode":"text","language_id":436568854},"Public Key":{"type":"data","extensions":[".asc",".pub"],"tm_scope":"none","ace_mode":"text","codemirror_mode":"asciiarmor","codemirror_mime_type":"application/pgp","language_id":298},"Pug":{"type":"markup","color":"#a86454","extensions":[".jade",".pug"],"tm_scope":"text.jade","ace_mode":"jade","codemirror_mode":"pug","codemirror_mime_type":"text/x-pug","language_id":179},"Puppet":{"type":"programming","color":"#302B6D","extensions":[".pp"],"filenames":["Modulefile"],"ace_mode":"text","codemirror_mode":"puppet","codemirror_mime_type":"text/x-puppet","tm_scope":"source.puppet","language_id":299},"Pure Data":{"type":"data","extensions":[".pd"],"tm_scope":"none","ace_mode":"text","language_id":300},"PureBasic":{"type":"programming","color":"#5a6986","extensions":[".pb",".pbi"],"tm_scope":"none","ace_mode":"text","language_id":301},"PureScript":{"type":"programming","color":"#1D222D","extensions":[".purs"],"tm_scope":"source.purescript","ace_mode":"haskell","codemirror_mode":"haskell","codemirror_mime_type":"text/x-haskell","language_id":302},"Python":{"type":"programming","tm_scope":"source.python","ace_mode":"python","codemirror_mode":"python","codemirror_mime_type":"text/x-python","color":"#3572A5","extensions":[".py",".cgi",".fcgi",".gyp",".gypi",".lmi",".py3",".pyde",".pyi",".pyp",".pyt",".pyw",".rpy",".smk",".spec",".tac",".wsgi",".xpy"],"filenames":[".gclient","DEPS","SConscript","SConstruct","Snakefile","wscript"],"interpreters":["python","python2","python3"],"aliases":["python3","rusthon"],"language_id":303},"Python console":{"type":"programming","color":"#3572A5","group":"Python","aliases":["pycon"],"tm_scope":"text.python.console","ace_mode":"text","language_id":428},"Python traceback":{"type":"data","color":"#3572A5","group":"Python","extensions":[".pytb"],"tm_scope":"text.python.traceback","ace_mode":"text","language_id":304},"Q#":{"type":"programming","extensions":[".qs"],"aliases":["qsharp"],"color":"#fed659","ace_mode":"text","tm_scope":"source.qsharp","language_id":697448245},"QML":{"type":"programming","color":"#44a51c","extensions":[".qml",".qbs"],"tm_scope":"source.qml","ace_mode":"text","language_id":305},"QMake":{"type":"programming","extensions":[".pro",".pri"],"interpreters":["qmake"],"tm_scope":"source.qmake","ace_mode":"text","language_id":306},"Qt Script":{"type":"programming","ace_mode":"javascript","codemirror_mode":"javascript","codemirror_mime_type":"text/javascript","extensions":[".qs"],"filenames":["installscript.qs","toolchain_installscript.qs"],"color":"#00b841","tm_scope":"source.js","language_id":558193693},"Quake":{"type":"programming","filenames":["m3makefile","m3overrides"],"color":"#882233","ace_mode":"text","tm_scope":"source.quake","language_id":375265331},"R":{"type":"programming","color":"#198CE7","aliases":["R","Rscript","splus"],"extensions":[".r",".rd",".rsx"],"filenames":[".Rprofile","expr-dist"],"interpreters":["Rscript"],"tm_scope":"source.r","ace_mode":"r","codemirror_mode":"r","codemirror_mime_type":"text/x-rsrc","language_id":307},"RAML":{"type":"markup","ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","tm_scope":"source.yaml","color":"#77d9fb","extensions":[".raml"],"language_id":308},"RDoc":{"type":"prose","color":"#701516","ace_mode":"rdoc","wrap":true,"extensions":[".rdoc"],"tm_scope":"text.rdoc","language_id":309},"REALbasic":{"type":"programming","extensions":[".rbbas",".rbfrm",".rbmnu",".rbres",".rbtbar",".rbuistate"],"tm_scope":"source.vbnet","ace_mode":"text","language_id":310},"REXX":{"type":"programming","color":"#d90e09","aliases":["arexx"],"extensions":[".rexx",".pprx",".rex"],"interpreters":["regina","rexx"],"tm_scope":"source.rexx","ace_mode":"text","language_id":311},"RMarkdown":{"type":"prose","color":"#198ce7","wrap":true,"ace_mode":"markdown","codemirror_mode":"gfm","codemirror_mime_type":"text/x-gfm","extensions":[".qmd",".rmd"],"tm_scope":"source.gfm","language_id":313},"RPC":{"type":"programming","aliases":["rpcgen","oncrpc","xdr"],"ace_mode":"c_cpp","extensions":[".x"],"tm_scope":"source.c","language_id":1031374237},"RPGLE":{"type":"programming","ace_mode":"text","color":"#2BDE21","aliases":["ile rpg","sqlrpgle"],"extensions":[".rpgle",".sqlrpgle"],"tm_scope":"source.rpgle","language_id":609977990},"RPM Spec":{"type":"data","tm_scope":"source.rpm-spec","extensions":[".spec"],"aliases":["specfile"],"ace_mode":"text","codemirror_mode":"rpm","codemirror_mime_type":"text/x-rpm-spec","language_id":314},"RUNOFF":{"type":"markup","color":"#665a4e","extensions":[".rnh",".rno"],"wrap":true,"tm_scope":"text.runoff","ace_mode":"text","language_id":315},"Racket":{"type":"programming","color":"#3c5caa","extensions":[".rkt",".rktd",".rktl",".scrbl"],"interpreters":["racket"],"tm_scope":"source.racket","ace_mode":"lisp","language_id":316},"Ragel":{"type":"programming","color":"#9d5200","extensions":[".rl"],"aliases":["ragel-rb","ragel-ruby"],"tm_scope":"none","ace_mode":"text","language_id":317},"Raku":{"type":"programming","color":"#0000fb","extensions":[".6pl",".6pm",".nqp",".p6",".p6l",".p6m",".pl",".pl6",".pm",".pm6",".raku",".rakumod",".t"],"interpreters":["perl6","raku","rakudo"],"aliases":["perl6","perl-6"],"tm_scope":"source.raku","ace_mode":"perl","codemirror_mode":"perl","codemirror_mime_type":"text/x-perl","language_id":283},"Rascal":{"type":"programming","color":"#fffaa0","extensions":[".rsc"],"tm_scope":"source.rascal","ace_mode":"text","language_id":173616037},"Raw token data":{"type":"data","aliases":["raw"],"extensions":[".raw"],"tm_scope":"none","ace_mode":"text","language_id":318},"ReScript":{"type":"programming","color":"#ed5051","ace_mode":"rust","codemirror_mode":"rust","codemirror_mime_type":"text/x-rustsrc","extensions":[".res"],"interpreters":["ocaml"],"tm_scope":"source.rescript","language_id":501875647},"Readline Config":{"type":"data","group":"INI","aliases":["inputrc","readline"],"filenames":[".inputrc","inputrc"],"tm_scope":"source.inputrc","ace_mode":"text","language_id":538732839},"Reason":{"type":"programming","color":"#ff5847","ace_mode":"rust","codemirror_mode":"rust","codemirror_mime_type":"text/x-rustsrc","extensions":[".re",".rei"],"tm_scope":"source.reason","language_id":869538413},"ReasonLIGO":{"type":"programming","color":"#ff5847","ace_mode":"rust","codemirror_mode":"rust","codemirror_mime_type":"text/x-rustsrc","group":"LigoLANG","extensions":[".religo"],"tm_scope":"source.religo","language_id":319002153},"Rebol":{"type":"programming","color":"#358a5b","extensions":[".reb",".r",".r2",".r3",".rebol"],"ace_mode":"text","tm_scope":"source.rebol","language_id":319},"Record Jar":{"type":"data","filenames":["language-subtag-registry.txt"],"tm_scope":"source.record-jar","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","ace_mode":"text","color":"#0673ba","language_id":865765202},"Red":{"type":"programming","color":"#f50000","extensions":[".red",".reds"],"aliases":["red/system"],"tm_scope":"source.red","ace_mode":"text","language_id":320},"Redcode":{"type":"programming","extensions":[".cw"],"tm_scope":"none","ace_mode":"text","language_id":321},"Redirect Rules":{"type":"data","aliases":["redirects"],"filenames":["_redirects"],"tm_scope":"source.redirects","ace_mode":"text","language_id":1020148948},"Regular Expression":{"type":"data","color":"#009a00","extensions":[".regexp",".regex"],"aliases":["regexp","regex"],"ace_mode":"text","tm_scope":"source.regexp","language_id":363378884},"Ren'Py":{"type":"programming","aliases":["renpy"],"color":"#ff7f7f","extensions":[".rpy"],"tm_scope":"source.renpy","ace_mode":"python","language_id":322},"RenderScript":{"type":"programming","extensions":[".rs",".rsh"],"tm_scope":"none","ace_mode":"text","language_id":323},"Rich Text Format":{"type":"markup","extensions":[".rtf"],"tm_scope":"text.rtf","ace_mode":"text","language_id":51601661},"Ring":{"type":"programming","color":"#2D54CB","extensions":[".ring"],"tm_scope":"source.ring","ace_mode":"text","language_id":431},"Riot":{"type":"markup","color":"#A71E49","ace_mode":"html","extensions":[".riot"],"tm_scope":"text.html.riot","language_id":878396783},"RobotFramework":{"type":"programming","color":"#00c0b5","extensions":[".robot"],"tm_scope":"text.robot","ace_mode":"text","language_id":324},"Roff":{"type":"markup","color":"#ecdebe","extensions":[".roff",".1",".1in",".1m",".1x",".2",".3",".3in",".3m",".3p",".3pm",".3qt",".3x",".4",".5",".6",".7",".8",".9",".l",".man",".mdoc",".me",".ms",".n",".nr",".rno",".tmac"],"filenames":["eqnrc","mmn","mmt","troffrc","troffrc-end"],"tm_scope":"text.roff","aliases":["groff","man","manpage","man page","man-page","mdoc","nroff","troff"],"wrap":true,"ace_mode":"text","codemirror_mode":"troff","codemirror_mime_type":"text/troff","language_id":141},"Roff Manpage":{"type":"markup","color":"#ecdebe","group":"Roff","extensions":[".1",".1in",".1m",".1x",".2",".3",".3in",".3m",".3p",".3pm",".3qt",".3x",".4",".5",".6",".7",".8",".9",".man",".mdoc"],"wrap":true,"tm_scope":"text.roff","ace_mode":"text","codemirror_mode":"troff","codemirror_mime_type":"text/troff","language_id":612669833},"Rouge":{"type":"programming","ace_mode":"clojure","codemirror_mode":"clojure","codemirror_mime_type":"text/x-clojure","color":"#cc0088","extensions":[".rg"],"tm_scope":"source.clojure","language_id":325},"Ruby":{"type":"programming","tm_scope":"source.ruby","ace_mode":"ruby","codemirror_mode":"ruby","codemirror_mime_type":"text/x-ruby","color":"#701516","aliases":["jruby","macruby","rake","rb","rbx"],"extensions":[".rb",".builder",".eye",".fcgi",".gemspec",".god",".jbuilder",".mspec",".pluginspec",".podspec",".prawn",".rabl",".rake",".rbi",".rbuild",".rbw",".rbx",".ru",".ruby",".spec",".thor",".watchr"],"interpreters":["ruby","macruby","rake","jruby","rbx"],"filenames":[".irbrc",".pryrc",".simplecov","Appraisals","Berksfile","Brewfile","Buildfile","Capfile","Dangerfile","Deliverfile","Fastfile","Gemfile","Guardfile","Jarfile","Mavenfile","Podfile","Puppetfile","Rakefile","Snapfile","Steepfile","Thorfile","Vagrantfile","buildfile"],"language_id":326},"Rust":{"type":"programming","aliases":["rs"],"color":"#dea584","extensions":[".rs",".rs.in"],"tm_scope":"source.rust","ace_mode":"rust","codemirror_mode":"rust","codemirror_mime_type":"text/x-rustsrc","language_id":327},"SAS":{"type":"programming","color":"#B34936","extensions":[".sas"],"tm_scope":"source.sas","ace_mode":"text","codemirror_mode":"sas","codemirror_mime_type":"text/x-sas","language_id":328},"SCSS":{"type":"markup","color":"#c6538c","tm_scope":"source.css.scss","ace_mode":"scss","codemirror_mode":"css","codemirror_mime_type":"text/x-scss","extensions":[".scss"],"language_id":329},"SELinux Policy":{"aliases":["SELinux Kernel Policy Language","sepolicy"],"type":"data","tm_scope":"source.sepolicy","extensions":[".te"],"filenames":["file_contexts","genfs_contexts","initial_sids","port_contexts","security_classes"],"ace_mode":"text","language_id":880010326},"SMT":{"type":"programming","extensions":[".smt2",".smt"],"interpreters":["boolector","cvc4","mathsat5","opensmt","smtinterpol","smt-rat","stp","verit","yices2","z3"],"tm_scope":"source.smt","ace_mode":"text","language_id":330},"SPARQL":{"type":"data","color":"#0C4597","tm_scope":"source.sparql","ace_mode":"text","codemirror_mode":"sparql","codemirror_mime_type":"application/sparql-query","extensions":[".sparql",".rq"],"language_id":331},"SQF":{"type":"programming","color":"#3F3F3F","extensions":[".sqf",".hqf"],"tm_scope":"source.sqf","ace_mode":"text","language_id":332},"SQL":{"type":"data","color":"#e38c00","tm_scope":"source.sql","ace_mode":"sql","codemirror_mode":"sql","codemirror_mime_type":"text/x-sql","extensions":[".sql",".cql",".ddl",".inc",".mysql",".prc",".tab",".udf",".viw"],"language_id":333},"SQLPL":{"type":"programming","color":"#e38c00","ace_mode":"sql","codemirror_mode":"sql","codemirror_mime_type":"text/x-sql","tm_scope":"source.sql","extensions":[".sql",".db2"],"language_id":334},"SRecode Template":{"type":"markup","color":"#348a34","tm_scope":"source.lisp","ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","extensions":[".srt"],"language_id":335},"SSH Config":{"type":"data","group":"INI","filenames":["ssh-config","ssh_config","sshconfig","sshconfig.snip","sshd-config","sshd_config"],"ace_mode":"text","tm_scope":"source.ssh-config","language_id":554920715},"STON":{"type":"data","group":"Smalltalk","extensions":[".ston"],"tm_scope":"source.smalltalk","ace_mode":"text","language_id":336},"SVG":{"type":"data","color":"#ff9900","extensions":[".svg"],"tm_scope":"text.xml.svg","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":337},"SWIG":{"type":"programming","extensions":[".i"],"tm_scope":"source.c++","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","language_id":1066250075},"Sage":{"type":"programming","extensions":[".sage",".sagews"],"tm_scope":"source.python","ace_mode":"python","codemirror_mode":"python","codemirror_mime_type":"text/x-python","language_id":338},"SaltStack":{"type":"programming","color":"#646464","aliases":["saltstate","salt"],"extensions":[".sls"],"tm_scope":"source.yaml.salt","ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","language_id":339},"Sass":{"type":"markup","color":"#a53b70","tm_scope":"source.sass","extensions":[".sass"],"ace_mode":"sass","codemirror_mode":"sass","codemirror_mime_type":"text/x-sass","language_id":340},"Scala":{"type":"programming","tm_scope":"source.scala","ace_mode":"scala","codemirror_mode":"clike","codemirror_mime_type":"text/x-scala","color":"#c22d40","extensions":[".scala",".kojo",".sbt",".sc"],"interpreters":["scala"],"language_id":341},"Scaml":{"type":"markup","color":"#bd181a","extensions":[".scaml"],"tm_scope":"source.scaml","ace_mode":"text","language_id":342},"Scheme":{"type":"programming","color":"#1e4aec","extensions":[".scm",".sch",".sld",".sls",".sps",".ss"],"interpreters":["scheme","guile","bigloo","chicken","csi","gosh","r6rs"],"tm_scope":"source.scheme","ace_mode":"scheme","codemirror_mode":"scheme","codemirror_mime_type":"text/x-scheme","language_id":343},"Scilab":{"type":"programming","color":"#ca0f21","extensions":[".sci",".sce",".tst"],"tm_scope":"source.scilab","ace_mode":"text","language_id":344},"Self":{"type":"programming","color":"#0579aa","extensions":[".self"],"tm_scope":"none","ace_mode":"text","language_id":345},"ShaderLab":{"type":"programming","color":"#222c37","extensions":[".shader"],"ace_mode":"text","tm_scope":"source.shaderlab","language_id":664257356},"Shell":{"type":"programming","color":"#89e051","aliases":["sh","shell-script","bash","zsh"],"extensions":[".sh",".bash",".bats",".cgi",".command",".env",".fcgi",".ksh",".sh.in",".tmux",".tool",".zsh",".zsh-theme"],"filenames":[".bash_aliases",".bash_history",".bash_logout",".bash_profile",".bashrc",".cshrc",".env",".env.example",".flaskenv",".kshrc",".login",".profile",".zlogin",".zlogout",".zprofile",".zshenv",".zshrc","9fs","PKGBUILD","bash_aliases","bash_logout","bash_profile","bashrc","cshrc","gradlew","kshrc","login","man","profile","zlogin","zlogout","zprofile","zshenv","zshrc"],"interpreters":["ash","bash","dash","ksh","mksh","pdksh","rc","sh","zsh"],"tm_scope":"source.shell","ace_mode":"sh","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":346},"ShellCheck Config":{"type":"data","color":"#cecfcb","filenames":[".shellcheckrc"],"aliases":["shellcheckrc"],"tm_scope":"source.shellcheckrc","ace_mode":"ini","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","language_id":687511714},"ShellSession":{"type":"programming","extensions":[".sh-session"],"aliases":["bash session","console"],"tm_scope":"text.shell-session","ace_mode":"sh","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":347},"Shen":{"type":"programming","color":"#120F14","extensions":[".shen"],"tm_scope":"source.shen","ace_mode":"text","language_id":348},"Sieve":{"type":"programming","tm_scope":"source.sieve","ace_mode":"text","extensions":[".sieve"],"codemirror_mode":"sieve","codemirror_mime_type":"application/sieve","language_id":208976687},"Singularity":{"type":"programming","color":"#64E6AD","tm_scope":"source.singularity","filenames":["Singularity"],"ace_mode":"text","language_id":987024632},"Slash":{"type":"programming","color":"#007eff","extensions":[".sl"],"tm_scope":"text.html.slash","ace_mode":"text","language_id":349},"Slice":{"type":"programming","color":"#003fa2","tm_scope":"source.slice","ace_mode":"text","extensions":[".ice"],"language_id":894641667},"Slim":{"type":"markup","color":"#2b2b2b","extensions":[".slim"],"tm_scope":"text.slim","ace_mode":"text","codemirror_mode":"slim","codemirror_mime_type":"text/x-slim","language_id":350},"SmPL":{"type":"programming","extensions":[".cocci"],"aliases":["coccinelle"],"ace_mode":"text","tm_scope":"source.smpl","color":"#c94949","language_id":164123055},"Smali":{"type":"programming","extensions":[".smali"],"ace_mode":"text","tm_scope":"source.smali","language_id":351},"Smalltalk":{"type":"programming","color":"#596706","extensions":[".st",".cs"],"aliases":["squeak"],"tm_scope":"source.smalltalk","ace_mode":"text","codemirror_mode":"smalltalk","codemirror_mime_type":"text/x-stsrc","language_id":352},"Smarty":{"type":"programming","color":"#f0c040","extensions":[".tpl"],"ace_mode":"smarty","codemirror_mode":"smarty","codemirror_mime_type":"text/x-smarty","tm_scope":"text.html.smarty","language_id":353},"Solidity":{"type":"programming","color":"#AA6746","ace_mode":"text","tm_scope":"source.solidity","extensions":[".sol"],"language_id":237469032},"Soong":{"type":"data","tm_scope":"source.bp","ace_mode":"text","filenames":["Android.bp"],"language_id":222900098},"SourcePawn":{"type":"programming","color":"#f69e1d","aliases":["sourcemod"],"extensions":[".sp",".inc"],"tm_scope":"source.sourcepawn","ace_mode":"text","language_id":354},"Spline Font Database":{"type":"data","extensions":[".sfd"],"tm_scope":"text.sfd","ace_mode":"yaml","language_id":767169629},"Squirrel":{"type":"programming","color":"#800000","extensions":[".nut"],"tm_scope":"source.nut","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-c++src","language_id":355},"Stan":{"type":"programming","color":"#b2011d","extensions":[".stan"],"ace_mode":"text","tm_scope":"source.stan","language_id":356},"Standard ML":{"type":"programming","color":"#dc566d","aliases":["sml"],"extensions":[".ml",".fun",".sig",".sml"],"tm_scope":"source.ml","ace_mode":"text","codemirror_mode":"mllike","codemirror_mime_type":"text/x-ocaml","language_id":357},"Starlark":{"type":"programming","tm_scope":"source.python","ace_mode":"python","codemirror_mode":"python","codemirror_mime_type":"text/x-python","color":"#76d275","extensions":[".bzl"],"filenames":["BUCK","BUILD","BUILD.bazel","Tiltfile","WORKSPACE"],"aliases":["bazel","bzl"],"language_id":960266174},"Stata":{"type":"programming","color":"#1a5f91","extensions":[".do",".ado",".doh",".ihlp",".mata",".matah",".sthlp"],"tm_scope":"source.stata","ace_mode":"text","language_id":358},"StringTemplate":{"type":"markup","color":"#3fb34f","extensions":[".st"],"tm_scope":"source.string-template","ace_mode":"html","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","language_id":89855901},"Stylus":{"type":"markup","color":"#ff6347","extensions":[".styl"],"tm_scope":"source.stylus","ace_mode":"stylus","language_id":359},"SubRip Text":{"type":"data","color":"#9e0101","extensions":[".srt"],"ace_mode":"text","tm_scope":"text.srt","language_id":360},"SugarSS":{"type":"markup","color":"#2fcc9f","tm_scope":"source.css.postcss.sugarss","group":"CSS","extensions":[".sss"],"ace_mode":"text","language_id":826404698},"SuperCollider":{"type":"programming","color":"#46390b","extensions":[".sc",".scd"],"interpreters":["sclang","scsynth"],"tm_scope":"source.supercollider","ace_mode":"text","language_id":361},"Svelte":{"type":"markup","color":"#ff3e00","tm_scope":"source.svelte","ace_mode":"html","codemirror_mode":"htmlmixed","codemirror_mime_type":"text/html","extensions":[".svelte"],"language_id":928734530},"Swift":{"type":"programming","color":"#F05138","extensions":[".swift"],"tm_scope":"source.swift","ace_mode":"text","codemirror_mode":"swift","codemirror_mime_type":"text/x-swift","language_id":362},"SystemVerilog":{"type":"programming","color":"#DAE1C2","extensions":[".sv",".svh",".vh"],"tm_scope":"source.systemverilog","ace_mode":"verilog","codemirror_mode":"verilog","codemirror_mime_type":"text/x-systemverilog","language_id":363},"TI Program":{"type":"programming","ace_mode":"text","color":"#A0AA87","extensions":[".8xp",".8xk",".8xk.txt",".8xp.txt"],"language_id":422,"tm_scope":"none"},"TLA":{"type":"programming","color":"#4b0079","extensions":[".tla"],"tm_scope":"source.tla","ace_mode":"text","language_id":364},"TOML":{"type":"data","color":"#9c4221","extensions":[".toml"],"filenames":["Cargo.lock","Gopkg.lock","Pipfile","poetry.lock"],"tm_scope":"source.toml","ace_mode":"toml","codemirror_mode":"toml","codemirror_mime_type":"text/x-toml","language_id":365},"TSQL":{"type":"programming","color":"#e38c00","extensions":[".sql"],"ace_mode":"sql","tm_scope":"source.tsql","language_id":918334941},"TSV":{"type":"data","color":"#237346","ace_mode":"text","tm_scope":"source.generic-db","extensions":[".tsv"],"language_id":1035892117},"TSX":{"type":"programming","color":"#2b7489","group":"TypeScript","extensions":[".tsx"],"tm_scope":"source.tsx","ace_mode":"javascript","codemirror_mode":"jsx","codemirror_mime_type":"text/jsx","language_id":94901924},"TXL":{"type":"programming","color":"#0178b8","extensions":[".txl"],"tm_scope":"source.txl","ace_mode":"text","language_id":366},"Talon":{"type":"programming","ace_mode":"text","color":"#333333","extensions":[".talon"],"tm_scope":"source.talon","language_id":959889508},"Tcl":{"type":"programming","color":"#e4cc98","extensions":[".tcl",".adp",".tcl.in",".tm"],"filenames":["owh","starfield"],"interpreters":["tclsh","wish"],"tm_scope":"source.tcl","ace_mode":"tcl","codemirror_mode":"tcl","codemirror_mime_type":"text/x-tcl","language_id":367},"Tcsh":{"type":"programming","group":"Shell","extensions":[".tcsh",".csh"],"interpreters":["tcsh","csh"],"tm_scope":"source.shell","ace_mode":"sh","codemirror_mode":"shell","codemirror_mime_type":"text/x-sh","language_id":368},"TeX":{"type":"markup","color":"#3D6117","ace_mode":"tex","codemirror_mode":"stex","codemirror_mime_type":"text/x-stex","tm_scope":"text.tex.latex","wrap":true,"aliases":["latex"],"extensions":[".tex",".aux",".bbx",".cbx",".cls",".dtx",".ins",".lbx",".ltx",".mkii",".mkiv",".mkvi",".sty",".toc"],"language_id":369},"Tea":{"type":"markup","extensions":[".tea"],"tm_scope":"source.tea","ace_mode":"text","language_id":370},"Terra":{"type":"programming","extensions":[".t"],"color":"#00004c","tm_scope":"source.terra","ace_mode":"lua","codemirror_mode":"lua","codemirror_mime_type":"text/x-lua","interpreters":["lua"],"language_id":371},"Texinfo":{"type":"prose","wrap":true,"extensions":[".texinfo",".texi",".txi"],"ace_mode":"text","tm_scope":"text.texinfo","interpreters":["makeinfo"],"language_id":988020015},"Text":{"type":"prose","wrap":true,"aliases":["fundamental","plain text"],"extensions":[".txt",".fr",".nb",".ncl",".no"],"filenames":["CITATION","CITATIONS","COPYING","COPYING.regex","COPYRIGHT.regex","FONTLOG","INSTALL","INSTALL.mysql","LICENSE","LICENSE.mysql","NEWS","README.me","README.mysql","README.nss","click.me","delete.me","keep.me","package.mask","package.use.mask","package.use.stable.mask","read.me","readme.1st","test.me","use.mask","use.stable.mask"],"tm_scope":"none","ace_mode":"text","language_id":372},"TextMate Properties":{"type":"data","color":"#df66e4","aliases":["tm-properties"],"filenames":[".tm_properties"],"ace_mode":"properties","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","tm_scope":"source.tm-properties","language_id":981795023},"Textile":{"type":"prose","color":"#ffe7ac","ace_mode":"textile","codemirror_mode":"textile","codemirror_mime_type":"text/x-textile","wrap":true,"extensions":[".textile"],"tm_scope":"none","language_id":373},"Thrift":{"type":"programming","color":"#D12127","tm_scope":"source.thrift","extensions":[".thrift"],"ace_mode":"text","language_id":374},"Turing":{"type":"programming","color":"#cf142b","extensions":[".t",".tu"],"tm_scope":"source.turing","ace_mode":"text","language_id":375},"Turtle":{"type":"data","extensions":[".ttl"],"tm_scope":"source.turtle","ace_mode":"text","codemirror_mode":"turtle","codemirror_mime_type":"text/turtle","language_id":376},"Twig":{"type":"markup","color":"#c1d026","extensions":[".twig"],"tm_scope":"text.html.twig","ace_mode":"twig","codemirror_mode":"twig","codemirror_mime_type":"text/x-twig","language_id":377},"Type Language":{"type":"data","aliases":["tl"],"extensions":[".tl"],"tm_scope":"source.tl","ace_mode":"text","language_id":632765617},"TypeScript":{"type":"programming","color":"#2b7489","aliases":["ts"],"interpreters":["deno","ts-node"],"extensions":[".ts"],"tm_scope":"source.ts","ace_mode":"typescript","codemirror_mode":"javascript","codemirror_mime_type":"application/typescript","language_id":378},"Unified Parallel C":{"type":"programming","color":"#4e3617","group":"C","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","extensions":[".upc"],"tm_scope":"source.c","language_id":379},"Unity3D Asset":{"type":"data","color":"#222c37","ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","extensions":[".anim",".asset",".mask",".mat",".meta",".prefab",".unity"],"tm_scope":"source.yaml","language_id":380},"Unix Assembly":{"type":"programming","group":"Assembly","extensions":[".s",".ms"],"tm_scope":"source.x86","ace_mode":"assembly_x86","language_id":120},"Uno":{"type":"programming","color":"#9933cc","extensions":[".uno"],"ace_mode":"csharp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csharp","tm_scope":"source.cs","language_id":381},"UnrealScript":{"type":"programming","color":"#a54c4d","extensions":[".uc"],"tm_scope":"source.java","ace_mode":"java","codemirror_mode":"clike","codemirror_mime_type":"text/x-java","language_id":382},"UrWeb":{"type":"programming","color":"#ccccee","aliases":["Ur/Web","Ur"],"extensions":[".ur",".urs"],"tm_scope":"source.ur","ace_mode":"text","language_id":383},"V":{"type":"programming","color":"#4f87c4","aliases":["vlang"],"extensions":[".v"],"tm_scope":"source.v","ace_mode":"golang","codemirror_mode":"go","codemirror_mime_type":"text/x-go","language_id":603371597},"VBA":{"type":"programming","color":"#867db1","extensions":[".bas",".cls",".frm",".frx",".vba"],"tm_scope":"source.vbnet","aliases":["vb6","visual basic 6","visual basic for applications"],"ace_mode":"text","codemirror_mode":"vb","codemirror_mime_type":"text/x-vb","language_id":399230729},"VBScript":{"type":"programming","color":"#15dcdc","extensions":[".vbs"],"tm_scope":"source.vbnet","ace_mode":"text","codemirror_mode":"vbscript","codemirror_mime_type":"text/vbscript","language_id":408016005},"VCL":{"type":"programming","color":"#148AA8","extensions":[".vcl"],"tm_scope":"source.varnish.vcl","ace_mode":"text","language_id":384},"VHDL":{"type":"programming","color":"#adb2cb","extensions":[".vhdl",".vhd",".vhf",".vhi",".vho",".vhs",".vht",".vhw"],"tm_scope":"source.vhdl","ace_mode":"vhdl","codemirror_mode":"vhdl","codemirror_mime_type":"text/x-vhdl","language_id":385},"Vala":{"type":"programming","color":"#a56de2","extensions":[".vala",".vapi"],"tm_scope":"source.vala","ace_mode":"vala","language_id":386},"Valve Data Format":{"type":"data","color":"#f26025","aliases":["keyvalues","vdf"],"extensions":[".vdf"],"ace_mode":"text","tm_scope":"source.keyvalues","language_id":544060961},"Verilog":{"type":"programming","color":"#b2b7f8","extensions":[".v",".veo"],"tm_scope":"source.verilog","ace_mode":"verilog","codemirror_mode":"verilog","codemirror_mime_type":"text/x-verilog","language_id":387},"Vim Help File":{"type":"prose","color":"#199f4b","aliases":["help","vimhelp"],"extensions":[".txt"],"tm_scope":"text.vim-help","ace_mode":"text","language_id":508563686},"Vim Script":{"type":"programming","color":"#199f4b","tm_scope":"source.viml","aliases":["vim","viml","nvim"],"extensions":[".vim",".vba",".vimrc",".vmb"],"filenames":[".exrc",".gvimrc",".nvimrc",".vimrc","_vimrc","gvimrc","nvimrc","vimrc"],"ace_mode":"text","language_id":388},"Vim Snippet":{"type":"markup","color":"#199f4b","aliases":["SnipMate","UltiSnip","UltiSnips","NeoSnippet"],"extensions":[".snip",".snippet",".snippets"],"tm_scope":"source.vim-snippet","ace_mode":"text","language_id":81265970},"Visual Basic .NET":{"type":"programming","color":"#945db7","extensions":[".vb",".vbhtml"],"aliases":["visual basic","vbnet","vb .net","vb.net"],"tm_scope":"source.vbnet","ace_mode":"text","codemirror_mode":"vb","codemirror_mime_type":"text/x-vb","language_id":389},"Volt":{"type":"programming","color":"#1F1F1F","extensions":[".volt"],"tm_scope":"source.d","ace_mode":"d","codemirror_mode":"d","codemirror_mime_type":"text/x-d","language_id":390},"Vue":{"type":"markup","color":"#41b883","extensions":[".vue"],"tm_scope":"text.html.vue","ace_mode":"html","language_id":391},"Vyper":{"type":"programming","extensions":[".vy"],"color":"#2980b9","ace_mode":"text","tm_scope":"source.vyper","language_id":1055641948},"Wavefront Material":{"type":"data","extensions":[".mtl"],"tm_scope":"source.wavefront.mtl","ace_mode":"text","language_id":392},"Wavefront Object":{"type":"data","extensions":[".obj"],"tm_scope":"source.wavefront.obj","ace_mode":"text","language_id":393},"Web Ontology Language":{"type":"data","color":"#5b70bd","extensions":[".owl"],"tm_scope":"text.xml","ace_mode":"xml","language_id":394},"WebAssembly":{"type":"programming","color":"#04133b","extensions":[".wast",".wat"],"aliases":["wast","wasm"],"tm_scope":"source.webassembly","ace_mode":"lisp","codemirror_mode":"commonlisp","codemirror_mime_type":"text/x-common-lisp","language_id":956556503},"WebIDL":{"type":"programming","extensions":[".webidl"],"tm_scope":"source.webidl","ace_mode":"text","codemirror_mode":"webidl","codemirror_mime_type":"text/x-webidl","language_id":395},"WebVTT":{"type":"data","wrap":true,"extensions":[".vtt"],"tm_scope":"source.vtt","ace_mode":"text","language_id":658679714},"Wget Config":{"type":"data","group":"INI","aliases":["wgetrc"],"filenames":[".wgetrc"],"tm_scope":"source.wgetrc","ace_mode":"text","language_id":668457123},"Wikitext":{"type":"prose","color":"#fc5757","wrap":true,"aliases":["mediawiki","wiki"],"extensions":[".mediawiki",".wiki",".wikitext"],"tm_scope":"text.html.mediawiki","ace_mode":"text","language_id":228},"Win32 Message File":{"type":"data","extensions":[".mc"],"tm_scope":"source.win32-messages","ace_mode":"ini","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","language_id":950967261},"Windows Registry Entries":{"type":"data","color":"#52d5ff","extensions":[".reg"],"tm_scope":"source.reg","ace_mode":"ini","codemirror_mode":"properties","codemirror_mime_type":"text/x-properties","language_id":969674868},"Witcher Script":{"type":"programming","color":"#ff0000","extensions":[".ws"],"ace_mode":"text","tm_scope":"source.witcherscript","language_id":686821385},"Wollok":{"type":"programming","color":"#a23738","extensions":[".wlk"],"ace_mode":"text","tm_scope":"source.wollok","language_id":632745969},"World of Warcraft Addon Data":{"type":"data","color":"#f7e43f","extensions":[".toc"],"tm_scope":"source.toc","ace_mode":"text","language_id":396},"X BitMap":{"type":"data","group":"C","aliases":["xbm"],"extensions":[".xbm"],"ace_mode":"c_cpp","tm_scope":"source.c","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":782911107},"X Font Directory Index":{"type":"data","filenames":["encodings.dir","fonts.alias","fonts.dir","fonts.scale"],"tm_scope":"source.fontdir","ace_mode":"text","language_id":208700028},"X PixMap":{"type":"data","group":"C","aliases":["xpm"],"extensions":[".xpm",".pm"],"ace_mode":"c_cpp","tm_scope":"source.c","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":781846279},"X10":{"type":"programming","aliases":["xten"],"ace_mode":"text","extensions":[".x10"],"color":"#4B6BEF","tm_scope":"source.x10","language_id":397},"XC":{"type":"programming","color":"#99DA07","extensions":[".xc"],"tm_scope":"source.xc","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":398},"XCompose":{"type":"data","filenames":[".XCompose","XCompose","xcompose"],"tm_scope":"config.xcompose","ace_mode":"text","language_id":225167241},"XML":{"type":"data","color":"#0060ac","tm_scope":"text.xml","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","aliases":["rss","xsd","wsdl"],"extensions":[".xml",".adml",".admx",".ant",".axaml",".axml",".builds",".ccproj",".ccxml",".clixml",".cproject",".cscfg",".csdef",".csl",".csproj",".ct",".depproj",".dita",".ditamap",".ditaval",".dll.config",".dotsettings",".filters",".fsproj",".fxml",".glade",".gml",".gmx",".grxml",".gst",".hzp",".iml",".ivy",".jelly",".jsproj",".kml",".launch",".mdpolicy",".mjml",".mm",".mod",".mxml",".natvis",".ncl",".ndproj",".nproj",".nuspec",".odd",".osm",".pkgproj",".pluginspec",".proj",".props",".ps1xml",".psc1",".pt",".rdf",".res",".resx",".rs",".rss",".sch",".scxml",".sfproj",".shproj",".srdf",".storyboard",".sublime-snippet",".targets",".tml",".ts",".tsx",".ui",".urdf",".ux",".vbproj",".vcxproj",".vsixmanifest",".vssettings",".vstemplate",".vxml",".wixproj",".workflow",".wsdl",".wsf",".wxi",".wxl",".wxs",".x3d",".xacro",".xaml",".xib",".xlf",".xliff",".xmi",".xml.dist",".xmp",".xproj",".xsd",".xspec",".xul",".zcml"],"filenames":[".classpath",".cproject",".project","App.config","NuGet.config","Settings.StyleCop","Web.Debug.config","Web.Release.config","Web.config","packages.config"],"language_id":399},"XML Property List":{"type":"data","color":"#0060ac","group":"XML","extensions":[".plist",".stTheme",".tmCommand",".tmLanguage",".tmPreferences",".tmSnippet",".tmTheme"],"tm_scope":"text.xml.plist","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":75622871},"XPages":{"type":"data","extensions":[".xsp-config",".xsp.metadata"],"tm_scope":"text.xml","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":400},"XProc":{"type":"programming","extensions":[".xpl",".xproc"],"tm_scope":"text.xml","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","language_id":401},"XQuery":{"type":"programming","color":"#5232e7","extensions":[".xquery",".xq",".xql",".xqm",".xqy"],"ace_mode":"xquery","codemirror_mode":"xquery","codemirror_mime_type":"application/xquery","tm_scope":"source.xq","language_id":402},"XS":{"type":"programming","extensions":[".xs"],"tm_scope":"source.c","ace_mode":"c_cpp","codemirror_mode":"clike","codemirror_mime_type":"text/x-csrc","language_id":403},"XSLT":{"type":"programming","aliases":["xsl"],"extensions":[".xslt",".xsl"],"tm_scope":"text.xml.xsl","ace_mode":"xml","codemirror_mode":"xml","codemirror_mime_type":"text/xml","color":"#EB8CEB","language_id":404},"Xojo":{"type":"programming","color":"#81bd41","extensions":[".xojo_code",".xojo_menu",".xojo_report",".xojo_script",".xojo_toolbar",".xojo_window"],"tm_scope":"source.xojo","ace_mode":"text","language_id":405},"Xonsh":{"type":"programming","color":"#285EEF","extensions":[".xsh"],"tm_scope":"source.python","ace_mode":"text","codemirror_mode":"python","codemirror_mime_type":"text/x-python","language_id":614078284},"Xtend":{"type":"programming","color":"#24255d","extensions":[".xtend"],"tm_scope":"source.xtend","ace_mode":"text","language_id":406},"YAML":{"type":"data","color":"#cb171e","tm_scope":"source.yaml","aliases":["yml"],"extensions":[".yml",".mir",".reek",".rviz",".sublime-syntax",".syntax",".yaml",".yaml-tmlanguage",".yaml.sed",".yml.mysql"],"filenames":[".clang-format",".clang-tidy",".gemrc","CITATION.cff","glide.lock","yarn.lock"],"ace_mode":"yaml","codemirror_mode":"yaml","codemirror_mime_type":"text/x-yaml","language_id":407},"YANG":{"type":"data","extensions":[".yang"],"tm_scope":"source.yang","ace_mode":"text","language_id":408},"YARA":{"type":"programming","color":"#220000","ace_mode":"text","extensions":[".yar",".yara"],"tm_scope":"source.yara","language_id":805122868},"YASnippet":{"type":"markup","aliases":["snippet","yas"],"color":"#32AB90","extensions":[".yasnippet"],"tm_scope":"source.yasnippet","ace_mode":"text","language_id":378760102},"Yacc":{"type":"programming","extensions":[".y",".yacc",".yy"],"tm_scope":"source.yacc","ace_mode":"text","color":"#4B6C4B","language_id":409},"ZAP":{"type":"programming","color":"#0d665e","extensions":[".zap",".xzap"],"tm_scope":"source.zap","ace_mode":"text","language_id":952972794},"ZIL":{"type":"programming","color":"#dc75e5","extensions":[".zil",".mud"],"tm_scope":"source.zil","ace_mode":"text","language_id":973483626},"Zeek":{"type":"programming","aliases":["bro"],"extensions":[".zeek",".bro"],"tm_scope":"source.zeek","ace_mode":"text","language_id":40},"ZenScript":{"type":"programming","color":"#00BCD1","extensions":[".zs"],"tm_scope":"source.zenscript","ace_mode":"text","language_id":494938890},"Zephir":{"type":"programming","color":"#118f9e","extensions":[".zep"],"tm_scope":"source.php.zephir","ace_mode":"php","language_id":410},"Zig":{"type":"programming","color":"#ec915c","extensions":[".zig"],"tm_scope":"source.zig","ace_mode":"text","language_id":646424281},"Zimpl":{"type":"programming","color":"#d67711","extensions":[".zimpl",".zmpl",".zpl"],"tm_scope":"none","ace_mode":"text","language_id":411},"cURL Config":{"type":"data","group":"INI","aliases":["curlrc"],"filenames":[".curlrc","_curlrc"],"tm_scope":"source.curlrc","ace_mode":"text","language_id":992375436},"desktop":{"type":"data","extensions":[".desktop",".desktop.in",".service"],"tm_scope":"source.desktop","ace_mode":"text","language_id":412},"dircolors":{"type":"data","extensions":[".dircolors"],"filenames":[".dir_colors",".dircolors","DIR_COLORS","_dir_colors","_dircolors","dir_colors"],"tm_scope":"source.dircolors","ace_mode":"text","language_id":691605112},"eC":{"type":"programming","color":"#913960","extensions":[".ec",".eh"],"tm_scope":"source.c.ec","ace_mode":"text","language_id":413},"edn":{"type":"data","ace_mode":"clojure","codemirror_mode":"clojure","codemirror_mime_type":"text/x-clojure","extensions":[".edn"],"tm_scope":"source.clojure","language_id":414},"fish":{"type":"programming","color":"#4aae47","group":"Shell","interpreters":["fish"],"extensions":[".fish"],"tm_scope":"source.fish","ace_mode":"text","language_id":415},"hoon":{"type":"programming","color":"#00b171","tm_scope":"source.hoon","ace_mode":"text","extensions":[".hoon"],"language_id":560883276},"jq":{"color":"#c7254e","ace_mode":"text","type":"programming","extensions":[".jq"],"tm_scope":"source.jq","language_id":905371884},"kvlang":{"type":"markup","ace_mode":"text","extensions":[".kv"],"color":"#1da6e0","tm_scope":"source.python.kivy","language_id":970675279},"mIRC Script":{"type":"programming","color":"#3d57c3","extensions":[".mrc"],"tm_scope":"source.msl","ace_mode":"text","language_id":517654727},"mcfunction":{"type":"programming","color":"#E22837","extensions":[".mcfunction"],"tm_scope":"source.mcfunction","ace_mode":"text","language_id":462488745},"mupad":{"type":"programming","color":"#244963","extensions":[".mu"],"tm_scope":"source.mupad","ace_mode":"text","language_id":416},"nanorc":{"type":"data","color":"#2d004d","group":"INI","extensions":[".nanorc"],"filenames":[".nanorc","nanorc"],"tm_scope":"source.nanorc","ace_mode":"text","language_id":775996197},"nesC":{"type":"programming","color":"#94B0C7","extensions":[".nc"],"ace_mode":"text","tm_scope":"source.nesc","language_id":417},"ooc":{"type":"programming","color":"#b0b77e","extensions":[".ooc"],"tm_scope":"source.ooc","ace_mode":"text","language_id":418},"q":{"type":"programming","extensions":[".q"],"tm_scope":"source.q","ace_mode":"text","color":"#0040cd","language_id":970539067},"reStructuredText":{"type":"prose","color":"#141414","wrap":true,"aliases":["rst"],"extensions":[".rst",".rest",".rest.txt",".rst.txt"],"tm_scope":"text.restructuredtext","ace_mode":"text","codemirror_mode":"rst","codemirror_mime_type":"text/x-rst","language_id":419},"robots.txt":{"type":"data","aliases":["robots","robots txt"],"filenames":["robots.txt"],"ace_mode":"text","tm_scope":"text.robots-txt","language_id":674736065},"sed":{"type":"programming","color":"#64b970","extensions":[".sed"],"interpreters":["gsed","minised","sed","ssed"],"ace_mode":"text","tm_scope":"source.sed","language_id":847830017},"wdl":{"type":"programming","color":"#42f1f4","extensions":[".wdl"],"tm_scope":"source.wdl","ace_mode":"text","language_id":374521672},"wisp":{"type":"programming","ace_mode":"clojure","codemirror_mode":"clojure","codemirror_mime_type":"text/x-clojure","color":"#7582D1","extensions":[".wisp"],"tm_scope":"source.clojure","language_id":420},"xBase":{"type":"programming","color":"#403a40","aliases":["advpl","clipper","foxpro"],"extensions":[".prg",".ch",".prw"],"tm_scope":"source.harbour","ace_mode":"text","language_id":421}} diff --git a/hgitaly/manifest.py b/hgitaly/manifest.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9tYW5pZmVzdC5weQ==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9tYW5pZmVzdC5weQ== 100644 --- a/hgitaly/manifest.py +++ b/hgitaly/manifest.py @@ -20,6 +20,8 @@ of the core manifest object it works on. """ import attr +from mercurial.context import filectx +from mercurial.utils.stringutil import binary as is_binary @attr.s @@ -146,9 +148,47 @@ to be very different, since it lists full paths to leaf (non-directory) files. In particular, there are no empty directories. - The interpretation (would have to be formally proven) is that - the "flat path" is the longest common directory ancestor of all file - entries that are inside the considered directory entry. + The interpretation is that the "flat path" is the longest + common directory ancestor of all file entries that are inside the + considered directory entry. Here is a proof (can certainly be much + simplified in a direct reasoning not involving reductio at absurdum, + but writing it down was enough to convince ourselves). + + 0. Assumptions and conventions: + + + there is no empty directory (guaranteed by the manifest data + structure in the Mercurial case). + + by X≤Y, we mean that Y is a path ancestor of X (inclusive) + + let E be the considered directory entry and Fp its flat path + as computed by the Golang implementation + + 1. Fp is a common directory ancestor of all file entries f such that + f≤E + + Let G be the greatest common ancestor of Fp and f. + The crawling performed by the implementation went through G, + since Fp≤G, so let's see what happened then. + If f is a direct child of G, then Fp=G. If not, then let h be the + direct child of G such that f≤h. h cannot be the only directory + child of g: otherwise we would have Fp≤h, and h would be a greater + common ancestor of Fp and f. Therefore the crawling stopped at G, + hence Fp=G. + + 2. Let G be the greatest common directory ancestor of all file entries + f such that f≤E are ancestors of Fp. + + By derinition of "greatest", G≤Fp because Fp is a common directory + ancestor. + Let's see what the crawling implementation did at G if G≠Fp: + + Because of the halting condition of the implementation, + either Fp has a file child and is therefore the greatest common + directory ancestor, or Fp has at least two distinct directory + children. Obviously, Only one of those can be an ancestor of G. + So let h be a child of Fp such that G≤h is false. There is at least + a file entry k such that k≤h, because directory entries cannot be + empty. G is not an ancestor of k, contradicting its definition, + so G must be equal to Fp. This implementation relies on manifest to emit paths in sorted manner. """ @@ -207,6 +247,17 @@ yield file_path + def iter_files_with_content(self, exclude_binary=False): + manifest = self.changeset.manifest() + repo = self.changeset.repo().unfiltered() + for file_path, file_node, flags in manifest.iterentries(): + # filectx has a `isbinary` method, but it would actually + # read the data once more (not cached on self) + content = filectx(repo, file_path, fileid=file_node).data() + if exclude_binary and is_binary(content): + continue + yield file_path, content, flags + def miner(changeset): """Return an appropriate manifest extractor for the given changeset. diff --git a/hgitaly/message.py b/hgitaly/message.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9tZXNzYWdlLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9tZXNzYWdlLnB5 100644 --- a/hgitaly/message.py +++ b/hgitaly/message.py @@ -38,6 +38,7 @@ diff_opts, chunk_stats, ) +from .gitlab_ref import reverse_refs LONG_BYTES_TRUNCATION = 50 @@ -148,7 +149,28 @@ return CommitStatInfo(additions=adds, deletions=dels, changed_files=files) -def commit(ctx, with_short_stats=False): +def ref_segments_match(ref, pattern): + """Tell if given ref first segments are exactly as in pattern.""" + pat_split = pattern.rstrip(b'/').split(b'/') + ref_split = ref.split(b'/', len(pat_split)) + for r, p in zip(ref_split, pat_split): + if r != p: + return False + return True + + +def commit_referenced_by(ctx, patterns): + """Return references to the given commit, as full ref paths.""" + if not patterns: + return + + repo = ctx.repo() + refs = reverse_refs(repo).get(ctx.hex(), ()) + return [r for r in refs + if any(ref_segments_match(r, pat) for pat in patterns)] + + +def commit(ctx, with_short_stats=False, include_referenced_by=()): """Return :class:`GitCommit` object from Mercurial :class:`changectx`. :param bool with_short_stats: if ``True``, fill-in the ``short_stats`` @@ -185,6 +207,7 @@ descr = ctx.description() author = commit_author(ctx) short_stats = commit_stats(ctx) if with_short_stats else None + referenced_by = commit_referenced_by(ctx, include_referenced_by) return GitCommit(id=ctx.hex(), subject=descr.split(b'\n', 1)[0].rstrip(b'\r\n'), body=descr, @@ -195,6 +218,7 @@ author=author, committer=author, short_stats=short_stats, + referenced_by=referenced_by, ) diff --git a/hgitaly/server/mono.py b/hgitaly/server/mono.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2ZXIvbW9uby5weQ==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2ZXIvbW9uby5weQ== 100644 --- a/hgitaly/server/mono.py +++ b/hgitaly/server/mono.py @@ -32,6 +32,7 @@ from ..service.ref import RefServicer from ..service.diff import DiffServicer from ..service.mercurial_changeset import MercurialChangesetServicer +from ..service.mercurial_operations import MercurialOperationsServicer from ..service.mercurial_repository import MercurialRepositoryServicer from ..service.repository import RepositoryServicer from ..service.server import ServerServicer @@ -46,6 +47,9 @@ from ..stub.mercurial_changeset_pb2_grpc import ( add_MercurialChangesetServiceServicer_to_server ) +from ..stub.mercurial_operations_pb2_grpc import ( + add_MercurialOperationsServiceServicer_to_server +) from ..stub.mercurial_repository_pb2_grpc import ( add_MercurialRepositoryServiceServicer_to_server ) @@ -91,6 +95,8 @@ add_DiffServiceServicer_to_server(DiffServicer(storages), server) add_MercurialChangesetServiceServicer_to_server( MercurialChangesetServicer(storages), server) + add_MercurialOperationsServiceServicer_to_server( + MercurialOperationsServicer(storages), server) add_MercurialRepositoryServiceServicer_to_server( MercurialRepositoryServicer(storages), server) add_RepositoryServiceServicer_to_server( diff --git a/hgitaly/service/commit.py b/hgitaly/service/commit.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL2NvbW1pdC5weQ==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL2NvbW1pdC5weQ== 100644 --- a/hgitaly/service/commit.py +++ b/hgitaly/service/commit.py @@ -34,6 +34,10 @@ from ..git import ( OBJECT_MODE_TREE, ) +from ..linguist import ( + language_color, + language_stats, +) from ..logging import LoggerAdapter from ..oid import ( tree_oid, @@ -163,10 +167,8 @@ repo = self.load_repo(request.repository, context).unfiltered() changeset = gitlab_revision_changeset(repo, request.revision) if changeset is None: - # in case of unknown revision, Gitaly error details are - # still about the path only (as of v15.4.6) - context.abort(StatusCode.NOT_FOUND, - 'not found: ' + os.fsdecode(request.path)) + # As of v15.8.0, Gitaly error details don't give up anything + context.abort(StatusCode.NOT_FOUND, "tree entry not found") sha = changeset.hex().decode('ascii') # early testing shows that even for leaf files, Gitaly ignores @@ -193,7 +195,7 @@ if max_size != 0 and size > request.max_size: context.abort( StatusCode.FAILED_PRECONDITION, - "TreeEntry: object size (%d) is bigger than the maximum " + "object size (%d) is bigger than the maximum " "allowed size (%d)" % (size, max_size)) data = filectx.data() @@ -221,8 +223,7 @@ subtrees, file_paths = manifest.miner(changeset).ls_dir(path) if not subtrees and not file_paths: - context.abort(StatusCode.NOT_FOUND, - 'not found: ' + os.fsdecode(path)) + context.abort(StatusCode.NOT_FOUND, "tree entry not found") # path is an actual directory @@ -417,7 +418,7 @@ if entry_oid(path, is_dir) == page_token: break else: - context.abort(StatusCode.UNKNOWN, + context.abort(StatusCode.INTERNAL, "could not find starting OID: %s" % page_token) entries = entries[offset+1:] @@ -572,5 +573,7 @@ if request.all: revs = repo.revs(b"reverse(%ld)", revs) + incl_ref_by = request.include_referenced_by + with_short_stats = request.include_shortstat for chunk in chunked(revs): @@ -575,6 +578,4 @@ with_short_stats = request.include_shortstat for chunk in chunked(revs): - if not chunk: - continue yield FindCommitsResponse( commits=(message.commit(repo[rev], @@ -579,7 +580,8 @@ yield FindCommitsResponse( commits=(message.commit(repo[rev], + include_referenced_by=incl_ref_by, with_short_stats=with_short_stats) for rev in chunk)) def CommitLanguages(self, request: CommitLanguagesRequest, context) -> CommitLanguagesResponse: @@ -581,12 +583,33 @@ with_short_stats=with_short_stats) for rev in chunk)) def CommitLanguages(self, request: CommitLanguagesRequest, context) -> CommitLanguagesResponse: - not_implemented(context, issue=12) # pragma no cover + repo = self.load_repo(request.repository, context) + changeset = gitlab_revision_changeset(repo, request.revision) + tokei_bin_path = os.fsdecode( + repo.ui.config(b'hgitaly', b'tokei-executable') + ) + with self.working_dir(gl_repo=request.repository, + repo=repo, + context=context, + changeset=changeset) as wd: + + stats, total = language_stats(tokei_bin_path, wd.path, context) + Language = CommitLanguagesResponse.Language + resp_langs = [] + for lang_name, lang_stats in stats.items(): + resp_langs.append(Language( + name=lang_name, + share=100 * lang_stats['total_bytes'] / total, + bytes=lang_stats['total_bytes'], + color=language_color(lang_name), + )) + resp_langs.sort(key=lambda lang: -lang.share) + return CommitLanguagesResponse(languages=resp_langs) def RawBlame(self, request: RawBlameRequest, context) -> RawBlameResponse: repo = self.load_repo(request.repository, context) filepath = request.path if not filepath: @@ -587,10 +610,10 @@ def RawBlame(self, request: RawBlameRequest, context) -> RawBlameResponse: repo = self.load_repo(request.repository, context) filepath = request.path if not filepath: - context.abort(StatusCode.INVALID_ARGUMENT, "RawBlame: empty Path") + context.abort(StatusCode.INVALID_ARGUMENT, "empty Path") revision = pycompat.sysbytes(request.revision) ctx = gitlab_revision_changeset(repo, revision) @@ -606,4 +629,7 @@ repo = self.load_repo(request.repository, context) revision, path = request.revision, request.path ctx = gitlab_revision_changeset(repo, revision) + if ctx is None: + return LastCommitForPathResponse() + changeset = latest_changeset_for_path(path, ctx) @@ -609,4 +635,5 @@ changeset = latest_changeset_for_path(path, ctx) + # TODO global_options.literal_pathspecs return LastCommitForPathResponse(commit=message.commit(changeset)) def ListLastCommitsForTree(self, request: ListLastCommitsForTreeRequest, @@ -642,5 +669,16 @@ # subtrees first, then regular files, each one in lexicographical order subtrees, file_paths = manifest.miner(from_ctx).ls_dir(req_path) + end = offset + limit + nb_subtrees = len(subtrees) + if nb_subtrees > end: + subtrees = subtrees[offset:end] + file_paths = () + else: + subtrees = subtrees[offset:end] + file_paths = file_paths[max(offset-nb_subtrees, 0):end-nb_subtrees] + + changesets = latest_changesets_for_paths(subtrees, file_paths, + from_ctx) all_paths = subtrees all_paths.extend(file_paths) @@ -645,7 +683,6 @@ all_paths = subtrees all_paths.extend(file_paths) - - for chunk in chunked(all_paths[offset:offset + limit]): + for chunk in chunked(all_paths): yield ListLastCommitsForTreeResponse( commits=[ message.commit_for_tree( @@ -649,7 +686,7 @@ yield ListLastCommitsForTreeResponse( commits=[ message.commit_for_tree( - latest_changeset_for_path(path, from_ctx), + changesets[path], path ) for path in chunk @@ -991,9 +1028,14 @@ return dt.isoformat() +def ancestors_inclusive(changeset): + yield changeset + yield from changeset.ancestors() + + def latest_changeset_for_path(path, seen_from): """Return latest ancestor of ``seen_from`` that touched the given path. :param bytes path: subdir or file :param seen_from: changectx """ @@ -994,20 +1036,66 @@ def latest_changeset_for_path(path, seen_from): """Return latest ancestor of ``seen_from`` that touched the given path. :param bytes path: subdir or file :param seen_from: changectx """ - # gracinet: just hoping that performance wise, this does the right - # thing, i.e do any scanning from the end - # While we can be reasonably confident that the file exists - # in the given revision, there are cases where deduplication implies - # that the filelog() predicate would not see any new file revision - # in some subgraph, because it's identical to another one that's not - # in that subgraph. Hence using the slower `file` is the only way - # to go. - repo = seen_from.repo() - rev = repo.revs('file(%s) and ::%s', b'path:' + path, seen_from).last() - return None if rev is None else repo[rev] + if not path or path in (b'.', b'/', b'./'): + # interpeted as a directory, this would be the repository root, which + # all changesets change. + return seen_from + + if path.endswith(b'/'): + dir_prefix = path + else: + dir_prefix = path + b'/' + + for changeset in ancestors_inclusive(seen_from): + files = changeset.files() + # TODO some performance improvement possible with a binary + # search if changeset files are guaranteed to be sorted + # but it'd probably make more of a difference in a Rust impl + for fpath in files: + if fpath == path or fpath.startswith(dir_prefix): + return changeset + + +def latest_changesets_for_paths(subdirs, file_paths, seen_from): + """Return latest ancestor of ``seen_from`` that touched the given path. + + :param bytes path: subdir or file + :param seen_from: changectx + """ + dir_prefixes = set(d.rstrip(b'/') + b'/' for d in subdirs) + file_paths = set(file_paths) + + latest_changesets = {} + + for changeset in ancestors_inclusive(seen_from): + if not dir_prefixes and not file_paths: + break + + for cfp in changeset.files(): + # TODO some performance improvement possible with a binary + # search if changeset files are guaranteed to be sorted + # but it'd probably make more of a difference in a Rust impl + for dp in dir_prefixes: + if cfp.startswith(dp): + latest_changesets[dp.rstrip(b'/')] = changeset + dir_prefixes.discard(dp) + break + else: + for fp in file_paths: + if fp == cfp: + latest_changesets[fp] = changeset + break + else: + continue + file_paths.discard(fp) + continue + + dir_prefixes.discard(dp) + + return latest_changesets def blamelines(repo, ctx, file): diff --git a/hgitaly/service/diff.py b/hgitaly/service/diff.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL2RpZmYucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL2RpZmYucHk= 100644 --- a/hgitaly/service/diff.py +++ b/hgitaly/service/diff.py @@ -25,6 +25,7 @@ chunk_stats, diff_opts, ) +from ..errors import not_implemented from ..git import ( NULL_BLOB_OID, EMPTY_TREE_OID, @@ -51,6 +52,8 @@ CommitDeltaResponse, FindChangedPathsRequest, FindChangedPathsResponse, + GetPatchIDRequest, + GetPatchIDResponse, RawDiffRequest, RawDiffResponse, RawPatchRequest, @@ -266,8 +269,7 @@ parsed_request = parse_diff_request(self, request, context) parsed, repo, ctx_from, ctx_to = parsed_request if not parsed: - context.abort(StatusCode.UNAVAILABLE, - "CommitDiff: exit status 128") + context.abort(StatusCode.UNAVAILABLE, "exit status 128") m = None if request.paths: @@ -338,8 +340,7 @@ parsed_request = parse_diff_request(self, request, context) _parsed, repo, ctx_from, ctx_to = parsed_request if not _parsed: - context.abort(StatusCode.UNAVAILABLE, - "CommitDelta: exit status 128") + context.abort(StatusCode.UNAVAILABLE, "exit status 128") m = None if request.paths: m = scmutil.matchfiles(repo, request.paths) @@ -386,7 +387,7 @@ parsed_request = parse_diff_request(self, request, context) _parsed, repo, ctx_from, ctx_to = parsed_request if not _parsed: - context.abort(StatusCode.UNKNOWN, "exit status 128") + context.abort(StatusCode.INTERNAL, "exit status 128") opts = {b'git': True} overrides = { (b'experimental', b'extendedheader.similarity'): True, @@ -418,7 +419,7 @@ parsed_request = parse_diff_request(self, request, context) _parsed, repo, ctx_from, ctx_to = parsed_request if not _parsed: - context.abort(StatusCode.UNKNOWN, "exit status 128") + context.abort(StatusCode.INTERNAL, "exit status 128") opts = {b'git': True} diffopts = diffutil.diffallopts(repo.ui, opts) ui = repo.ui @@ -439,7 +440,7 @@ parsed_request = parse_diff_request(self, request, context) _parsed, repo, ctx_from, ctx_to = parsed_request if not _parsed: - context.abort(StatusCode.UNAVAILABLE, "DiffStats: exit status 128") + context.abort(StatusCode.UNAVAILABLE, "exit status 128") diffchunks = ctx_to.diff(ctx_from, opts=diff_opts(repo)) @@ -508,6 +509,10 @@ for path in changed_paths(repo, *extr)): yield FindChangedPathsResponse(paths=paths) + def GetPatchID(self, request: GetPatchIDRequest, + context) -> GetPatchIDResponse: + not_implemented(context, issue=131) # pragma no cover + def fcp_resolve_commit(context, repo, revision): ctx = gitlab_revision_changeset( diff --git a/hgitaly/service/mercurial_operations.py b/hgitaly/service/mercurial_operations.py new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL21lcmN1cmlhbF9vcGVyYXRpb25zLnB5 --- /dev/null +++ b/hgitaly/service/mercurial_operations.py @@ -0,0 +1,124 @@ +# Copyright 2023 Georges Racinet <georges.racinet@octobus.net> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. +# +# SPDX-License-Identifier: GPL-2.0-or-later +from grpc import StatusCode +import logging + +from mercurial.merge import merge +from mercurial.phases import ( + public as PUBLIC, +) + +from .. import message +from ..changelog import ( + ancestor, + merge_content, +) +from ..logging import LoggerAdapter +from ..revision import ( + gitlab_revision_changeset, +) + +from ..stub.mercurial_operations_pb2 import ( + MergeAnalysisRequest, + MergeAnalysisResponse, +) +from ..stub.mercurial_operations_pb2_grpc import ( + MercurialOperationsServiceServicer, +) +from ..servicer import HGitalyServicer + +base_logger = logging.getLogger(__name__) + +MERGE_CONFLICTS_LABELS = [b'working copy', b'merge rev', b'common ancestor'] + + +class MercurialOperationsServicer(MercurialOperationsServiceServicer, + HGitalyServicer): + """MercurialOperationService implementation. + + The ordering of methods in this source file is the same as in the proto + file. + """ + def MergeAnalysis(self, + request: MergeAnalysisRequest, + context) -> MergeAnalysisResponse: + logger = LoggerAdapter(base_logger, context) + repo = self.load_repo(request.repository, context) + source_cs = gitlab_revision_changeset(repo, request.source_revision) + if source_cs is None: + context.abort( + StatusCode.INVALID_ARGUMENT, + "Source revision %r not found" % request.source_revision) + target_cs = gitlab_revision_changeset(repo, request.target_revision) + if target_cs is None: + context.abort( + StatusCode.INVALID_ARGUMENT, + "Target revision %r not found" % request.target_revision) + + source_branch = source_cs.branch() + target_branch = target_cs.branch() + logger.info("Merge Analysis: source branch %r, target branch %r", + source_branch, target_branch) + is_ff = (ancestor(source_cs, target_cs) == target_cs.rev() + and source_branch == target_branch) + + has_obsolete = has_unstable = False + for cs in merge_content(source_cs, target_cs): + if not has_obsolete: + has_obsolete = cs.obsolete() + if not has_unstable: + has_unstable = cs.isunstable() + if has_obsolete and has_unstable: + break + + has_conflicts = False + if not (is_ff + or has_obsolete or has_unstable + or request.skip_conflicts_check): + with self.working_dir(gl_repo=request.repository, + repo=repo, + context=context, + changeset=target_cs) as wd: + has_conflicts = not wd_merge(wd, source_cs) + + res = MergeAnalysisResponse( + is_fast_forward=is_ff, + has_obsolete_changesets=has_obsolete, + has_unstable_changesets=has_unstable, + has_conflicts=has_conflicts, + target_is_public=target_cs.phase() == PUBLIC, + target_node_id=target_cs.hex().decode('ascii'), + target_branch=target_cs.branch(), + target_topic=target_cs.topic(), + source_node_id=source_cs.hex().decode('ascii'), + source_branch=source_cs.branch(), + source_topic=source_cs.topic(), + ) + logger.info("MergeAnalysis result %r", message.Logging(res)) + return res + + +def wd_merge(working_dir, source_cs): + """Merge source_cs in the given a working directory (repo share). + + :source_cs: a :class:`changectx`, usually not tied to ``working_dir`` but + to its share source or a share sibling. + :return: whether it suceeded + """ + # re-evalutate the changectx in the context of working_dir, + # as `merge()` will read the repo from it + repo = working_dir.repo + source_for_wd = repo[source_cs.rev()] + + overrides = {(b'ui', b'forcemerge'): b'internal:merge3', + (b'ui', b'interactive'): b'off'} + with repo.ui.configoverride(overrides, b'merge'): + # not sure labels are really necessary, but it is + # possible that the merge tools require them. + stats = merge(source_for_wd, + labels=MERGE_CONFLICTS_LABELS) + return not stats.unresolvedcount diff --git a/hgitaly/service/ref.py b/hgitaly/service/ref.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL3JlZi5weQ==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL3JlZi5weQ== 100644 --- a/hgitaly/service/ref.py +++ b/hgitaly/service/ref.py @@ -8,6 +8,7 @@ from grpc import StatusCode from heptapod.gitlab.branch import ( + GITLAB_BRANCH_REF_PREFIX, gitlab_branch_from_ref, gitlab_branch_ref, ) @@ -11,6 +12,9 @@ gitlab_branch_from_ref, gitlab_branch_ref, ) +from heptapod.gitlab.tag import ( + GITLAB_TAG_REF_PREFIX, +) from hgext3rd.heptapod.branch import get_default_gitlab_branch from hgext3rd.heptapod.typed_ref import GITLAB_TYPED_REFS_MISSING from hgext3rd.heptapod.special_ref import ( @@ -26,10 +30,9 @@ not_implemented, structured_abort, ) -from .. import feature from ..logging import LoggerAdapter from ..pagination import ( extract_limit, ) from ..stub.shared_pb2 import ( Branch, @@ -30,10 +33,9 @@ from ..logging import LoggerAdapter from ..pagination import ( extract_limit, ) from ..stub.shared_pb2 import ( Branch, - GitCommit, SortDirection, ) from ..stub.errors_pb2 import ( @@ -47,8 +49,6 @@ FindAllTagNamesRequest, FindAllTagNamesResponse, FindLocalBranchesRequest, - FindLocalBranchCommitAuthor, - FindLocalBranchResponse, FindLocalBranchesResponse, FindAllBranchesRequest, FindAllBranchesResponse, @@ -137,5 +137,4 @@ # used in the hg_fixup_default_branch in PostReceive… # TODO now that we have richer notifications, make a clear one # for that case - branch = b'' logger.warning("FindDefaultBranchName: no information stored " @@ -141,6 +140,7 @@ logger.warning("FindDefaultBranchName: no information stored " - "for repo at %r, returning harcoded default %r", - repo, branch) + "for repo at %r, returning hempty response", + repo) + return FindDefaultBranchNameResponse() return FindDefaultBranchNameResponse(name=gitlab_branch_ref(branch)) @@ -177,16 +177,8 @@ after = after.encode('utf-8') if after else None sort_by = FIND_LOCAL_BRANCHES_SORT_BY_TO_INNER.get(request.sort_by) - if feature.is_enabled(context, - 'simplify-find-local-branches-response'): - resp_key = 'local_branches' - branch_resp = message.branch - else: - resp_key = 'branches' - branch_resp = find_local_branch_response - for chunk in chunked(sorted_gitlab_branches_as_refs(repo, sort_by=sort_by, after=after), limit=limit): yield FindLocalBranchesResponse( @@ -188,10 +180,11 @@ for chunk in chunked(sorted_gitlab_branches_as_refs(repo, sort_by=sort_by, after=after), limit=limit): yield FindLocalBranchesResponse( - **{resp_key: (branch_resp(name, head) for name, head in chunk) - }) + local_branches=(message.branch(name, head) + for name, head in chunk) + ) def FindAllBranches(self, request: FindAllBranchesRequest, @@ -290,8 +283,7 @@ refs = request.refs if refs and except_prefix: context.abort(StatusCode.INVALID_ARGUMENT, - "DeleteRefs: ExceptWithPrefix and Refs are " - "mutually exclusive") + "ExceptWithPrefix and Refs are mutually exclusive") repo = self.load_repo(request.repository, context) srefs = special_refs(repo) @@ -447,4 +439,5 @@ Reference = ListRefsResponse.Reference repo = self.load_repo(request.repository, context) + patterns = request.patterns @@ -450,9 +443,10 @@ - refs = [(b'ALL', ZERO_SHA_STR)] if len(repo) else [] - refs.extend(iter_gitlab_branches_as_refs(repo, deref=False)) + refs = [] + if patterns == [b'refs/'] and len(repo): + refs.append((b'ALL', ZERO_SHA_STR)) if request.head: branch = get_default_gitlab_branch(repo) if branch is not None: head = gitlab_branch_head(repo, branch) if head is not None: refs.append((b'HEAD', head.hex().decode('ascii'))) @@ -453,10 +447,26 @@ if request.head: branch = get_default_gitlab_branch(repo) if branch is not None: head = gitlab_branch_head(repo, branch) if head is not None: refs.append((b'HEAD', head.hex().decode('ascii'))) - refs.extend(iter_gitlab_tags_as_refs(repo, deref=False)) - refs.extend(iter_gitlab_special_refs_as_refs(repo, deref=False)) - refs.extend(iter_keep_arounds_as_refs(repo, deref=False)) + if patterns == [GITLAB_BRANCH_REF_PREFIX]: + refs.extend(iter_gitlab_branches_as_refs(repo, deref=False)) + elif patterns == [GITLAB_TAG_REF_PREFIX]: + refs.extend(iter_gitlab_tags_as_refs(repo, deref=False)) + else: + if patterns: + patterns = tuple(pat.split(b'/') for pat in patterns) + refs.extend(iter_gitlab_branches_as_refs(repo, + deref=False, + patterns=patterns)) + refs.extend(iter_gitlab_tags_as_refs(repo, + deref=False, + patterns=patterns)) + refs.extend(iter_gitlab_special_refs_as_refs(repo, + deref=False, + patterns=patterns)) + refs.extend(iter_keep_arounds_as_refs(repo, + deref=False, + patterns=patterns)) @@ -462,5 +472,23 @@ - if not refs: + pointing_at = request.pointing_at_oids + if pointing_at: + refs = [r for r in refs + if r[1].encode('ascii') in pointing_at or r[0] == b'HEAD'] + + # ignore `peel_tags`: + # Mercurial has no real equivalent of Git's annotated tags. The + # closest notion would be the tagging changeset, but that is not + # well-defined. Hence Mercurial tags always point to the target commit. + # We could force the `peeled_target` attribute of the `Reference` + # messages, but that would not bring us to better compliance: the + # protocol comment states explicitely that it should stay empty if + # the object is not an annotated tag, and this is confirmed by + # Gitaly Comparison tests (tag created by hg-git in this case). + # On the contrary, filling-in `peeled_target` could very well make + # clients believe that the tag is annotated, leading to dedicated + # actions that can only go wrong. + + if len(refs) < (2 if request.head else 1): # avoid yielding an empty response, as Gitaly does not. # TODO consider doing that in the `chunked()` helper, # this looks to be rather systematic. @@ -464,6 +492,12 @@ # avoid yielding an empty response, as Gitaly does not. # TODO consider doing that in the `chunked()` helper, # this looks to be rather systematic. + # also in this case, even if `head` is `True`, in the Gitaly + # impl, it looks like nothing being read from Git does not + # trigger any sending, even though the sender created by + # `newListRefsWriter` would emit HEAD first in any case… if it + # emitted anything. See Gitaly Comparison test for validation of + # this. return refs.sort() @@ -478,29 +512,4 @@ not_implemented(context, issue=89) # pragma no cover -def flbr_author(commit: GitCommit): - """Extract commit intro specific fields of FindLocalBranchCommitAuthor.""" - return FindLocalBranchCommitAuthor( - name=commit.name, - email=commit.email, - date=commit.date, - timezone=commit.timezone, - ) - - -def find_local_branch_response(name, head): - commit = message.commit(head) - return FindLocalBranchResponse( - name=name, - commit_id=commit.id, - commit_subject=commit.subject, - commit_author=flbr_author(commit.author), - commit_committer=flbr_author(commit.committer), - commit=commit, - ) - - -TAG_REF_PREFIX = b'refs/tags/' - - def gitlab_tag_from_ref(ref): @@ -506,6 +515,6 @@ def gitlab_tag_from_ref(ref): - if ref.startswith(TAG_REF_PREFIX): - return ref[len(TAG_REF_PREFIX):] + if ref.startswith(GITLAB_TAG_REF_PREFIX): + return ref[len(GITLAB_TAG_REF_PREFIX):] def remove_special_refs(special_refs, to_remove): diff --git a/hgitaly/service/repository.py b/hgitaly/service/repository.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL3JlcG9zaXRvcnkucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL3JlcG9zaXRvcnkucHk= 100644 --- a/hgitaly/service/repository.py +++ b/hgitaly/service/repository.py @@ -6,6 +6,7 @@ # SPDX-License-Identifier: GPL-2.0-or-later import gc from grpc import StatusCode +from io import BytesIO import itertools import logging import os @@ -9,6 +10,8 @@ import itertools import logging import os +from pathlib import Path +from collections import deque import re import shutil import tempfile @@ -94,9 +97,11 @@ FullPathResponse, GetRawChangesRequest, GetRawChangesResponse, + GetCustomHooksRequest, + GetCustomHooksResponse, RepositoryExistsRequest, RepositoryExistsResponse, GetArchiveRequest, GetArchiveResponse, HasLocalBranchesRequest, HasLocalBranchesResponse, @@ -97,9 +102,11 @@ RepositoryExistsRequest, RepositoryExistsResponse, GetArchiveRequest, GetArchiveResponse, HasLocalBranchesRequest, HasLocalBranchesResponse, + RemoveAllRequest, + RemoveAllResponse, RemoveRepositoryRequest, RemoveRepositoryResponse, RestoreCustomHooksRequest, @@ -108,6 +115,8 @@ SearchFilesByContentResponse, SearchFilesByNameRequest, SearchFilesByNameResponse, + SetCustomHooksRequest, + SetCustomHooksResponse, SetFullPathRequest, SetFullPathResponse, WriteRefRequest, @@ -152,7 +161,7 @@ repo = self.load_repo(request.repository, context) if len(request.revisions) < 2: context.abort(StatusCode.INVALID_ARGUMENT, - 'FindMergeBase: at least 2 revisions are required') + 'at least 2 revisions are required') ctxs = [] for rev in request.revisions: @@ -354,11 +363,10 @@ rx = None else: if len(filt) > SEARCH_FILES_FILTER_MAX_LENGTH: - context.abort( - StatusCode.INVALID_ARGUMENT, - "SearchFilesByName: filter exceeds maximum length") + context.abort(StatusCode.INVALID_ARGUMENT, + "filter exceeds maximum length") # TODO what to do for invalid Regexp? Especially with incoming # format being Golang's try: rx = re.compile(filt.encode('utf8')) except re.error as exc: @@ -360,12 +368,10 @@ # TODO what to do for invalid Regexp? Especially with incoming # format being Golang's try: rx = re.compile(filt.encode('utf8')) except re.error as exc: - context.abort( - StatusCode.INVALID_ARGUMENT, - f"SearchFilesByName: filter did not compile: {exc})" - ) + context.abort(StatusCode.INVALID_ARGUMENT, + f"filter did not compile: {exc})") start = request.offset end = None if request.limit == 0 else start + request.limit @@ -373,9 +379,10 @@ for paths in chunked( itertools.islice( miner.file_names_by_regexp(rx, subdir), - start, end) + start, end), + force_if_empty=True, ): yield SearchFilesByNameResponse(files=paths) def SearchFilesByContent(self, request: SearchFilesByContentRequest, context) -> SearchFilesByContentResponse: @@ -377,7 +384,29 @@ ): yield SearchFilesByNameResponse(files=paths) def SearchFilesByContent(self, request: SearchFilesByContentRequest, context) -> SearchFilesByContentResponse: - not_implemented(context, issue=80) # pragma no cover + """Almost straight results from `git grep` + + this part of the protocol is totally undocumented, but here is what + Gitaly does: + + - each match is sent with two lines of context before and after + - in case of overlapping matches (including context), they are sent + as one + - sending a match means cutting it in chunkd of `WRITE_BUFFER_SIZE`. + - after the full sending of each match aa with the end_of_match` + boolean set to true and no data is sent. + + (see also Comparison Tests for validatation of this). + """ + repo = self.load_repo(request.repository, context) + query = request.query + if not query: + context.abort(StatusCode.INVALID_ARGUMENT, "no query given") + + ref = request.ref + changeset = gitlab_revision_changeset(repo, ref) + if changeset is None: + return @@ -383,6 +412,42 @@ - def RestoreCustomHooks(self, request: RestoreCustomHooksRequest, - context) -> RestoreCustomHooksResponse: + # TODO filtermaxlen? + rx = re.compile(query.encode('utf-8'), flags=re.IGNORECASE) + # TODO chunked_response (not used by Rails app) + match_data = BytesIO() + miner = manifest.miner(changeset) + for path, content, _flags in miner.iter_files_with_content( + exclude_binary=True): + # TODO rx options. Here's Gitaly reference (Golang), arguments + # passed to `git grep`): + # (with const surroundContext = 2) + # + # git.Flag{Name: "--ignore-case"}, + # git.Flag{Name: "-I"}, + # (ignore binary files) + # git.Flag{Name: "--line-number"}, + # git.Flag{Name: "--null"}, + # (use null as delimiter between path, line number and + # matching line in the output, hence avoiding the need + # to escape) + # git.ValueFlag{Name: "--before-context", + # Value: surroundContext}, + # git.ValueFlag{Name: "--after-context", Value: surroundContext}, + # git.Flag{Name: "--perl-regexp"}, + # git.Flag{Name: "-e"}, + # Gitaly does not fill in `matches` field any more + # (surely deprecated) and the Rails client does not read it + # TODO cheaper iteration on a window of lines (note that + # splitlines() takes care of `\r\n` and even `\r` EOLs.) + for matching_lines in grep_file(rx, content): + render_git_grep_matches( + match_data, + ref, path, + matching_lines) + yield from iter_sfbc_resps(match_data) + match_data.truncate(0) + match_data.seek(0) + + def set_custom_hooks(self, request, context): def load_repo(req, context): return self.load_repo(req.repository, context) @@ -386,4 +451,18 @@ def load_repo(req, context): return self.load_repo(req.repository, context) + with streaming_request_tempfile_extract( + request, context, + first_request_handler=load_repo + ) as (repo, tmpf): + tmpf.flush() + try: + restore_additional(repo.ui, repo, + tmpf.name.encode('ascii')) + except Exception as exc: + context.abort(StatusCode.INTERNAL, + "Error in tarball application: %r" % exc) + + def RestoreCustomHooks(self, request: RestoreCustomHooksRequest, + context) -> RestoreCustomHooksResponse: try: @@ -389,15 +468,5 @@ try: - with streaming_request_tempfile_extract( - request, context, - first_request_handler=load_repo - ) as (repo, tmpf): - tmpf.flush() - try: - restore_additional(repo.ui, repo, - tmpf.name.encode('ascii')) - except Exception as exc: - context.abort(StatusCode.INTERNAL, - "Error in tarball application: %r" % exc) + self.set_custom_hooks(request, context) finally: return RestoreCustomHooksResponse() @@ -401,8 +470,14 @@ finally: return RestoreCustomHooksResponse() - def BackupCustomHooks(self, request: BackupCustomHooksRequest, - context) -> BackupCustomHooksResponse: + def SetCustomHooks(self, request: SetCustomHooksRequest, + context) -> SetCustomHooksResponse: + try: + self.set_custom_hooks(request, context) + finally: + return SetCustomHooksResponse() + + def get_custom_hooks(self, request, context, resp_cls): repo = self.load_repo(request.repository, context) with tempfile.NamedTemporaryFile( mode='wb+', @@ -417,7 +492,17 @@ data = tmpf.read(WRITE_BUFFER_SIZE) if not data: break - yield BackupCustomHooksResponse(data=data) + yield resp_cls(data=data) + + def BackupCustomHooks(self, request: BackupCustomHooksRequest, + context) -> BackupCustomHooksResponse: + yield from self.get_custom_hooks( + request, context, BackupCustomHooksResponse) + + def GetCustomHooks(self, request: GetCustomHooksRequest, + context) -> GetCustomHooksResponse: + yield from self.get_custom_hooks( + request, context, GetCustomHooksResponse) def RemoveRepository(self, request: RemoveRepositoryRequest, context) -> RemoveRepositoryResponse: @@ -605,6 +690,38 @@ gc.collect() return CreateRepositoryFromBundleResponse() + def RemoveAll(self, request: RemoveAllRequest, + context) -> RemoveAllResponse: + """Remove everything in the given storage. + + This is exactly what Gitaly v15.9 does, hence including all temporary + files etc. + """ + storage = request.storage_name + root_dir = self.storages.get(storage) + if root_dir is None: + context.abort( + StatusCode.INVALID_ARGUMENT, + 'remove all: GetStorageByName: ' + 'no such storage: "%s"' % storage + ) + + root_dir = Path(os.fsdecode(root_dir)).resolve() + # it would obviously be simpler to use shutil.rmtree() on root_dir + # and recreate the storage afterwards *but* + # - permission not guaranteed on the root dir + # - risky on error recovery + try: + for sub in root_dir.iterdir(): + if sub.is_dir() and not sub.is_symlink(): + shutil.rmtree(sub) + else: + # also works with broken symlinks (even loops) + sub.unlink() + except Exception as exc: + context.abort(StatusCode.INTERNAL, "remove all: %s" % exc) + return RemoveAllResponse() + def hg_init_repository(self, repository: Repository, context): """Initialize a mercurial repository from a request object. @@ -637,3 +754,87 @@ context.set_details("hg_init_repository(%r): %r" % (repo_path, exc)) raise RepositoryCreationError(repository) + + +def render_git_grep_matches(buf, ref, path, enum_lines): + """Render a slice of lines as git grep does. + + :param enum_lines: iterable of pairs `(line_no, line)` + """ + for lineno, line in enum_lines: + buf.write(b'%s:%s\x00%d\x00%s\n' % (ref, path, lineno, line)) + + +SPLITLINES_RX = re.compile(br'(.*?)(\r\n?|\n|\Z)', re.MULTILINE) + + +def grep_file(rx, data, context_width=2): + """Iterator yielding matches the given regular expression with context + + This implementation avoids duplicating the data in memory. + + :param int context_width: number of lines before and after to include + if possible (same as `grep -C`) + :returns: pairs `(line_no, line)` + """ + prev_match_line_no = None + current_window = deque() # current line and up to 2 lines before + match_lines = [] + # According the the best ranked answer for + # https://stackoverflow.com/questions/3054604, + # this regexp-based splitting for lines can be a bit slower than + # `iter(splitlines)` (things may have changes since then, though). + # Yet, our biggest concern is to avoid exhausting HGitaly's RAM budget + # if this happens to run on large files. + # Unfortunately, we already have to load the entire data in RAM because + # it is typically Mercurial file content, we don't want to do it once + # more in the form of lines. In both cases a bytes string + # is allocated for each line, but that is harder to prevent and they + # should be deallocated at each iteration (no cycles). + # Unless there is a bug in the current approach, it is not worth the + # effort to try and further improve memory efficiency: implementing + # in RHGitaly would be the way to go. + for line_idx, line_m in enumerate(SPLITLINES_RX.finditer(data)): + line = line_m.group(1) + if not line: + continue + line_no = line_idx + 1 + current_window.append((line_no, line)) + if rx.search(line): + if ( + prev_match_line_no is None + or line_no - prev_match_line_no > 2 * context_width + ): + match_lines = list(current_window) + else: + match_lines.append((line_no, line)) + prev_match_line_no = line_no + elif ( + prev_match_line_no is not None + and line_no <= prev_match_line_no + context_width + ): + match_lines.append((line_no, line)) + elif match_lines: + yield match_lines + match_lines = [] + + if len(current_window) > context_width: + current_window.popleft() + if match_lines: + yield match_lines + + +def iter_sfbc_resps(match_data: BytesIO): + """Yield SearchFilesByContentResponse messages for the given match_data. + """ + value = match_data.getvalue() + match_len = len(value) + sent = 0 # actually rounded to the upper WRITE_BUFFER_SIZE + while sent < match_len: + yield SearchFilesByContentResponse( + match_data=value[sent:sent + WRITE_BUFFER_SIZE]) + sent += WRITE_BUFFER_SIZE + + match_data.truncate(0) + match_data.seek(0) + yield SearchFilesByContentResponse(end_of_match=True) diff --git a/hgitaly/service/tests/test_commit.py b/hgitaly/service/tests/test_commit.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfY29tbWl0LnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfY29tbWl0LnB5 100644 --- a/hgitaly/service/tests/test_commit.py +++ b/hgitaly/service/tests/test_commit.py @@ -14,7 +14,16 @@ as_bytes, ) from google.protobuf.timestamp_pb2 import Timestamp -from hgext3rd.heptapod.branch import set_default_gitlab_branch +from hgext3rd.heptapod.branch import ( + set_default_gitlab_branch, + write_gitlab_branches, +) +from hgext3rd.heptapod.branch import ( + write_gitlab_tags, +) +from hgext3rd.heptapod.special_ref import ( + write_special_refs, +) from hgitaly.oid import ( tree_oid, @@ -29,6 +38,8 @@ from hgitaly.stub.commit_pb2 import ( CommitIsAncestorRequest, CommitsByMessageRequest, + CommitLanguagesRequest, + CommitLanguagesResponse, CommitStatsRequest, CountCommitsRequest, CountDivergingCommitsRequest, @@ -132,6 +143,10 @@ resp = self.stub.ListCommits(request) return [c.id.encode('ascii') for chunk in resp for c in chunk.commits] + def commit_languages(self, **kw): + request = CommitLanguagesRequest(repository=self.grpc_repo, **kw) + return list(self.stub.CommitLanguages(request).languages) + @pytest.fixture def commit_fixture_empty_repo(grpc_channel, server_repos_root): @@ -315,6 +330,8 @@ utc_timestamp=timestamp+20) sha0, sha1, sha2, sha3, sha4 = (ctx0.hex(), ctx1.hex(), ctx2.hex(), ctx3.hex(), ctx4.hex()) + # symbolic revision + assert find_commits_ids(revision=b'branch/stable') == [sha3, sha0] # with follow; test that it follows renames assert find_commits_ids(paths=[b'zoo'], follow=True) == [sha2, sha0] # with follow and Git Range Notation, it does not **currently** follow @@ -377,6 +394,35 @@ sha5 = ctx5.hex() assert find_commits_ids(all=True, order=FindCommitsRequest.Order.TOPO) == [ sha0, sha2, sha3, sha4, sha1, sha5] + # with include_referenced_by + assert fixture.find_commits( # without state files empty instead of crash + revision=sha3, + include_referenced_by=[b'refs'] + )[0].referenced_by == [] + write_gitlab_branches(wrapper.repo, {b'branch/stable': sha3}) + assert fixture.find_commits( + revision=sha3, + include_referenced_by=[b'refs'] + )[0].referenced_by == [b'refs/heads/branch/stable'] + assert fixture.find_commits( + revision=sha3, + include_referenced_by=[b'refs/tags'] + )[0].referenced_by == [] + write_gitlab_tags(wrapper.repo, {b'release': sha3}) + assert fixture.find_commits( + revision=sha3, + include_referenced_by=[b'refs/tags'] + )[0].referenced_by == [b'refs/tags/release'] + write_special_refs(wrapper.repo, {b'pipelines/12': sha3}) + assert fixture.find_commits( + revision=sha3, + include_referenced_by=[b'refs/pipelines/'] + )[0].referenced_by == [b'refs/pipelines/12'] + set_default_gitlab_branch(wrapper.repo, b'branch/stable') + assert fixture.find_commits( + revision=sha3, + include_referenced_by=[b'HEAD', b'refs/heads'] + )[0].referenced_by == [b'refs/heads/branch/stable', b'HEAD'] # tests with obsolete changesets wrapper.amend_file('foo') @@ -636,6 +682,10 @@ return pycompat.sysbytes( grpc_stub.LastCommitForPath(request).commit.id) + # case with path resolving to the repo root + assert do_rpc(revision=b'branch/other', path=b'/') == ctx2.hex() + assert do_rpc(revision=b'branch/other', path=b'') == ctx2.hex() + assert do_rpc(revision=b'branch/default', path=b'foo') == ctx1.hex() assert do_rpc(revision=b'branch/other', path=b'foo') == ctx.hex() assert do_rpc(revision=ctx2.hex(), path=b'foo') == ctx.hex() @@ -644,9 +694,11 @@ # recursive directory matching (see Rails tests for validation # that we must match on directories) assert do_rpc(revision=b'branch/other', path=b'sub') == ctx2.hex() + # with trailing slash already provided + assert do_rpc(revision=b'branch/other', path=b'sub/') == ctx2.hex() # with obsolescence wrapper.command('amend', message=b'amended') assert ctx2.obsolete() assert do_rpc(revision=ctx2.hex(), path=b'foo') == ctx.hex() @@ -647,9 +699,19 @@ # with obsolescence wrapper.command('amend', message=b'amended') assert ctx2.obsolete() assert do_rpc(revision=ctx2.hex(), path=b'foo') == ctx.hex() + # with a removal + (wrapper.path / 'sub/bar').unlink() + ctx_rm = wrapper.commit(rel_paths=['sub/bar'], message="removed", + add_remove=True) + wrapper.commit_file('foo2') + assert do_rpc(revision=b'branch/other', path=b'sub') == ctx_rm.hex() + + # empty response for unresolvable revision + assert do_rpc(revision=b'unknown', path=b'foo') == b'' + def test_list_commits_by_oid(grpc_channel, server_repos_root): grpc_stub = CommitServiceStub(grpc_channel) @@ -952,7 +1014,7 @@ invalid_cursor = 'this is not an OID' with pytest.raises(grpc.RpcError) as exc_info: get_tree_entries(b'.', revision=sha1, page_token=invalid_cursor) - assert exc_info.value.code() == grpc.StatusCode.UNKNOWN + assert exc_info.value.code() == grpc.StatusCode.INTERNAL assert invalid_cursor in exc_info.value.details() # with skip_flat_paths, even non recursive calls give empty flat paths @@ -1078,6 +1140,27 @@ (b'foo', sha3), ] + # case when we don't have to walk the entire changelog + (wrapper.path / 'more').mkdir() + sha5 = wrapper.commit_file('more/foo').hex().decode() + assert do_rpc(sha5, b'more/') == [ + (b'more/foo', sha5), + ] + + # case of limit smaller than number of subtrees, now that sha5 created + # a second one + assert do_rpc(sha5, b'', limit=1) == [ + (b'more', sha5), + ] + # some more to double check offset by one potential errors + assert do_rpc(sha5, b'', offset=1, limit=1) == [ + (b'sub', sha1), + ] + assert do_rpc(sha5, b'', offset=1, limit=2) == [ + (b'sub', sha1), + (b'foo', sha3), + ] + def test_raw_blame(grpc_channel, server_repos_root): grpc_stub = CommitServiceStub(grpc_channel) @@ -1138,7 +1221,7 @@ with pytest.raises(grpc.RpcError) as exc_info: do_rpc(sha0, b'') assert exc_info.value.code() == grpc.StatusCode.INVALID_ARGUMENT - assert 'RawBlame: empty Path' in exc_info.value.details() + assert 'empty Path' in exc_info.value.details() # with obsolescence wrapper.command('amend', message=b'amended') @@ -1255,3 +1338,47 @@ wrapper.command('amend', message=b'amended') assert ctx4.obsolete() assert list_commits(sha4, limit=2) == [sha4, sha3] + + +def test_commit_languages(commit_fixture_empty_repo): + fixture = commit_fixture_empty_repo + wrapper = fixture.repo_wrapper + + # a Python file with valid content, including a blank line + wrapper.commit_file('foo.py', + content="import sys\n\nprint(sys.version)\n", + message="Some Python", + ) + # a Ruby file with valid content, with a comment + wrapper.commit_file('bar.rb', + content=("# frozen_string_literal: true\n" + "\n" + "module Bar\n" + "def f(x)\n" + " x+1\n" + ), + message="Some Ruby", + ) + + Language = CommitLanguagesResponse.Language + assert fixture.commit_languages() == [ + Language(name='Ruby', + bytes=57, + share=64.7727279663086, + color="#701516"), + Language(name='Python', + bytes=31, + share=35.227272033691406, + color="#3572A5"), + ] + + # color defaulting: COBOL does not have a color in github-linguist's + # `languages.json` + wrapper.commit_file( + 'truc.cob', + content="Not really pretending to be COBOL, " + "extension should be enough") + assert fixture.commit_languages()[0] == Language(name='COBOL', + bytes=61, + share=40.939598083496094, + color="#d29900") diff --git a/hgitaly/service/tests/test_default_branch.py b/hgitaly/service/tests/test_default_branch.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfZGVmYXVsdF9icmFuY2gucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfZGVmYXVsdF9icmFuY2gucHk= 100644 --- a/hgitaly/service/tests/test_default_branch.py +++ b/hgitaly/service/tests/test_default_branch.py @@ -10,7 +10,10 @@ from hgitaly.tests.common import make_empty_repo -from hgitaly.stub.ref_pb2 import FindDefaultBranchNameRequest +from hgitaly.stub.ref_pb2 import ( + FindDefaultBranchNameRequest, + FindDefaultBranchNameResponse +) from hgitaly.stub.ref_pb2_grpc import RefServiceStub from hgitaly.stub.repository_pb2 import WriteRefRequest from hgitaly.stub.repository_pb2_grpc import RepositoryServiceStub @@ -26,7 +29,7 @@ request = FindDefaultBranchNameRequest(repository=grpc_repo) response = ref_stub.FindDefaultBranchName(request) - assert response.name == b'refs/heads/' + assert response == FindDefaultBranchNameResponse() wreq = WriteRefRequest(repository=grpc_repo, ref=b'HEAD', diff --git a/hgitaly/service/tests/test_diff.py b/hgitaly/service/tests/test_diff.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfZGlmZi5weQ==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfZGlmZi5weQ== 100644 --- a/hgitaly/service/tests/test_diff.py +++ b/hgitaly/service/tests/test_diff.py @@ -222,8 +222,8 @@ # varient 1 with pytest.raises(grpc.RpcError) as exc_info: raw_diff(sha0, sha_not_exists) - assert exc_info.value.code() == grpc.StatusCode.UNKNOWN + assert exc_info.value.code() == grpc.StatusCode.INTERNAL assert 'exit status 128' in exc_info.value.details() # varient 2 with pytest.raises(grpc.RpcError) as exc_info: raw_diff(sha_not_exists, sha0) @@ -226,8 +226,8 @@ assert 'exit status 128' in exc_info.value.details() # varient 2 with pytest.raises(grpc.RpcError) as exc_info: raw_diff(sha_not_exists, sha0) - assert exc_info.value.code() == grpc.StatusCode.UNKNOWN + assert exc_info.value.code() == grpc.StatusCode.INTERNAL assert 'exit status 128' in exc_info.value.details() @@ -339,8 +339,8 @@ # varient 1 with pytest.raises(grpc.RpcError) as exc_info: raw_patch(sha0, sha_not_exists) - assert exc_info.value.code() == grpc.StatusCode.UNKNOWN + assert exc_info.value.code() == grpc.StatusCode.INTERNAL assert 'exit status 128' in exc_info.value.details() # varient 2 with pytest.raises(grpc.RpcError) as exc_info: raw_patch(sha_not_exists, sha0) @@ -343,8 +343,8 @@ assert 'exit status 128' in exc_info.value.details() # varient 2 with pytest.raises(grpc.RpcError) as exc_info: raw_patch(sha_not_exists, sha0) - assert exc_info.value.code() == grpc.StatusCode.UNKNOWN + assert exc_info.value.code() == grpc.StatusCode.INTERNAL assert 'exit status 128' in exc_info.value.details() diff --git a/hgitaly/service/tests/test_mercurial_operations.py b/hgitaly/service/tests/test_mercurial_operations.py new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfbWVyY3VyaWFsX29wZXJhdGlvbnMucHk= --- /dev/null +++ b/hgitaly/service/tests/test_mercurial_operations.py @@ -0,0 +1,169 @@ +# Copyright 2022 Georges Racinet <georges.racinet@octobus.net> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. +# +# SPDX-License-Identifier: GPL-2.0-or-later +from grpc import ( + RpcError, + StatusCode, +) +import pytest + +from hgitaly.stub.mercurial_operations_pb2 import ( + MergeAnalysisRequest, + MergeAnalysisResponse, +) +from hgitaly.stub.mercurial_operations_pb2_grpc import ( + MercurialOperationsServiceStub, +) + +from .fixture import ServiceFixture + + +class OperationsFixture(ServiceFixture): + + stub_cls = MercurialOperationsServiceStub + + def merge_analysis(self, **kw): + return self.stub.MergeAnalysis(MergeAnalysisRequest( + repository=self.grpc_repo, **kw)) + + +@pytest.fixture +def operations_fixture(grpc_channel, server_repos_root): + with OperationsFixture(grpc_channel, server_repos_root) as fixture: + yield fixture + + +def test_merge_analysis_ff(operations_fixture): + repo_wrapper = operations_fixture.repo_wrapper + commit_file = repo_wrapper.commit_file + default_ctx = commit_file('foo') + default_sha = default_ctx.hex().decode() + topic_ctx = commit_file('foo', parent=default_ctx, topic='zetop') + topic_first_hex = topic_ctx.hex() + topic_first_sha = topic_first_hex.decode() + + merge_analysis = operations_fixture.merge_analysis + assert ( + merge_analysis(source_revision=b'topic/default/zetop', + target_revision=b'branch/default') + == + MergeAnalysisResponse(is_fast_forward=True, + source_node_id=topic_first_sha, + source_branch=b'default', + source_topic=b'zetop', + target_node_id=default_sha, + target_branch=b'default', + target_topic=b'', + target_is_public=False, + ) + ) + newtop_sha = commit_file('foo', + parent=topic_ctx, + topic='newtop').hex().decode() + repo_wrapper.update(topic_ctx) + repo_wrapper.amend_file('foo').hex() + + assert ( + merge_analysis(source_revision=b'topic/default/newtop', + target_revision=b'branch/default') + == + MergeAnalysisResponse(is_fast_forward=True, + has_obsolete_changesets=True, + has_unstable_changesets=True, + source_node_id=newtop_sha, + source_branch=b'default', + source_topic=b'newtop', + target_node_id=default_sha, + target_branch=b'default', + target_topic=b'', + target_is_public=False, + ) + ) + assert ( + merge_analysis(source_revision=topic_first_hex, + target_revision=b'branch/default') + == + MergeAnalysisResponse(is_fast_forward=True, + has_obsolete_changesets=True, + has_unstable_changesets=False, + source_node_id=topic_first_sha, + source_branch=b'default', + source_topic=b'zetop', + target_node_id=default_sha, + target_branch=b'default', + target_topic=b'', + target_is_public=False, + ) + ) + + # error cases + with pytest.raises(RpcError) as exc_info: + merge_analysis(source_revision=b'unknown', + target_revision=b'branch/default') + assert exc_info.value.code() == StatusCode.INVALID_ARGUMENT + assert 'source revision' in exc_info.value.details().lower() + + with pytest.raises(RpcError) as exc_info: + merge_analysis(source_revision=b'topic/default/zetop', + target_revision=b'unknownn') + assert exc_info.value.code() == StatusCode.INVALID_ARGUMENT + assert 'target revision' in exc_info.value.details().lower() + + +def test_merge_analysis_conflict(operations_fixture): + repo_wrapper = operations_fixture.repo_wrapper + commit_file = repo_wrapper.commit_file + ctx0 = commit_file('foo') + default_sha = commit_file('foo', content="default").hex().decode() + repo_wrapper.set_phase('public', ['.']) # also testing `target_is_public` + topic_first_sha = commit_file('foo', parent=ctx0, + topic='zetop', content="top" + ).hex().decode() + + merge_analysis = operations_fixture.merge_analysis + assert ( + merge_analysis(source_revision=b'topic/default/zetop', + target_revision=b'branch/default') + == + MergeAnalysisResponse(is_fast_forward=False, + has_conflicts=True, + source_node_id=topic_first_sha, + source_branch=b'default', + source_topic=b'zetop', + target_node_id=default_sha, + target_branch=b'default', + target_topic=b'', + target_is_public=True, + ) + ) + + # same without the conflicts check + conflicts_check_skipped = merge_analysis( + skip_conflicts_check=True, + source_revision=b'topic/default/zetop', + target_revision=b'branch/default', + ) + assert conflicts_check_skipped.is_fast_forward is False + assert conflicts_check_skipped.has_conflicts is False # was really skipped + + # solving the conflict + topic_fixed_sha = commit_file('foo', topic='zetop', + content="default").hex().decode() + assert ( + merge_analysis(source_revision=b'topic/default/zetop', + target_revision=b'branch/default') + == + MergeAnalysisResponse(is_fast_forward=False, + has_conflicts=False, + source_node_id=topic_fixed_sha, + source_branch=b'default', + source_topic=b'zetop', + target_node_id=default_sha, + target_branch=b'default', + target_topic=b'', + target_is_public=True, + ) + ) diff --git a/hgitaly/service/tests/test_ref.py b/hgitaly/service/tests/test_ref.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfcmVmLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfcmVmLnB5 100644 --- a/hgitaly/service/tests/test_ref.py +++ b/hgitaly/service/tests/test_ref.py @@ -94,7 +94,9 @@ def list_refs(self, patterns=(b"refs/", ), **kw): return [(ref.name, ref.target) for resp in self.stub.ListRefs( - ListRefsRequest(repository=self.grpc_repo, **kw)) + ListRefsRequest(repository=self.grpc_repo, + patterns=patterns, + **kw)) for ref in resp.references] @@ -201,16 +203,6 @@ def test_find_local_branches(ref_fixture): ctx = ref_fixture.commit_file('foo', message="Ze subject") - resp = ref_fixture.find_local_branches( - pagination_params=PaginationParameter(limit=-1)) - branches = [br for chunk in resp for br in chunk.branches] - assert len(branches) == 1 - assert branches[0].name == b'refs/heads/branch/default' - target = branches[0].commit - assert target.id == ctx.hex().decode() - assert branches[0].commit_subject == b"Ze subject" - - # now with the new style ref_fixture.feature_flags = [ ('simplify-find-local-branches-response', True), ] @@ -219,7 +211,9 @@ branches = [br for chunk in resp for br in chunk.local_branches] assert len(branches) == 1 assert branches[0].name == b'refs/heads/branch/default' - assert branches[0].target_commit == target + target = branches[0].target_commit + assert target.id == ctx.hex().decode() + assert target.subject == b"Ze subject" def test_find_local_branches_pagination(ref_fixture): @@ -233,8 +227,8 @@ assert len(resp) == 0 # but no pagination_params does mean unlimited - assert sum(len(resp.branches) + assert sum(len(resp.local_branches) for resp in ref_fixture.find_local_branches()) == 22 resp = list(ref_fixture.find_local_branches( pagination_params=PaginationParameter(limit=21))) @@ -237,6 +231,6 @@ for resp in ref_fixture.find_local_branches()) == 22 resp = list(ref_fixture.find_local_branches( pagination_params=PaginationParameter(limit=21))) - assert len(resp[0].branches) == 20 + assert len(resp[0].local_branches) == 20 # cursor aka page token is (not yet) returned @@ -242,5 +236,6 @@ # cursor aka page token is (not yet) returned - assert [br.name for br in resp[1].branches] == [b'refs/heads/branch/br20'] + assert [br.name for br in resp[1].local_branches] == [ + b'refs/heads/branch/br20'] # but we can infer it resp = list(ref_fixture.find_local_branches( @@ -248,7 +243,8 @@ limit=6, page_token='refs/heads/branch/br20'))) assert len(resp) == 1 - assert [br.name for br in resp[0].branches] == [b'refs/heads/branch/br21'] + assert [br.name for br in resp[0].local_branches] == [ + b'refs/heads/branch/br21'] def test_find_local_branches_sort_by(ref_fixture): @@ -272,7 +268,7 @@ sort_by=by, pagination_params=pagination_params ) - for br in resp.branches + for br in resp.local_branches ] == [b'refs/heads/branch/' + ex for ex in expected] assert_branches_sorted_by(SortBy.NAME, [b'aaa', b'bbb', b'ccc']) @@ -563,3 +559,57 @@ (b'refs/keep-around/' + ctx1.hex(), sha1), (b'refs/tags/v1.4', sha1), ] + + # pattern used by gitaly-backup + assert fixture.list_refs(patterns=[b'refs/']) == [ + PSEUDO_REF_ALL, + (special_ref, sha2), + (b'refs/heads/branch/aaa', tagging_sha), + (b'refs/heads/branch/default', sha1), + (b'refs/keep-around/' + ctx1.hex(), sha1), + (b'refs/tags/v1.4', sha1), + ] + + # pattern used by Rails app for queries about branches and tags + assert fixture.list_refs(patterns=[b'refs/heads/']) == [ + (b'refs/heads/branch/aaa', tagging_sha), + (b'refs/heads/branch/default', sha1), + ] + assert fixture.list_refs(patterns=[b'refs/tags/']) == [ + (b'refs/tags/v1.4', sha1), + ] + + # more general patterns + assert fixture.list_refs(patterns=[b'refs/heads/branch/a*']) == [ + (b'refs/heads/branch/aaa', tagging_sha), + ] + assert fixture.list_refs(patterns=[b'refs/t*/*']) == [ + (b'refs/tags/v1.4', sha1), + ] + assert fixture.list_refs(patterns=[b'refs/e*/*']) == [ + (special_ref, sha2), + ] + assert fixture.list_refs(patterns=[b'refs/heads/*/a*']) == [ + (b'refs/heads/branch/aaa', tagging_sha), + ] + # number of segments has to match + assert fixture.list_refs(patterns=[b'*/a*']) == [] + assert fixture.list_refs(patterns=[b'refs/heads/br*']) == [] + assert fixture.list_refs(patterns=[b'refs/heads/br*/*']) == [ + (b'refs/heads/branch/aaa', tagging_sha), + (b'refs/heads/branch/default', sha1), + ] + assert fixture.list_refs( + patterns=[b'refs/keep-around/%s*' % ctx1.hex()[0:2]] + ) == [ + (b'refs/keep-around/' + ctx1.hex(), sha1), + ] + + # pointing_at_oids + assert fixture.list_refs(pointing_at_oids=[ctx2.hex()]) == [ + (b'refs/environments/17', sha2) + ] + assert fixture.list_refs(head=True, pointing_at_oids=[ctx2.hex()]) == [ + (b'HEAD', sha1), + (b'refs/environments/17', sha2) + ] diff --git a/hgitaly/service/tests/test_repository_service.py b/hgitaly/service/tests/test_repository_service.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfcmVwb3NpdG9yeV9zZXJ2aWNlLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zZXJ2aWNlL3Rlc3RzL3Rlc3RfcmVwb3NpdG9yeV9zZXJ2aWNlLnB5 100644 --- a/hgitaly/service/tests/test_repository_service.py +++ b/hgitaly/service/tests/test_repository_service.py @@ -29,6 +29,7 @@ from hgitaly.repository import ( GITLAB_PROJECT_FULL_PATH_FILENAME, ) +from hgitaly.stream import WRITE_BUFFER_SIZE from hgitaly.testing import TEST_DATA_DIR from hgitaly.testing.bundle import list_bundle_contents @@ -45,4 +46,5 @@ FindMergeBaseRequest, FullPathRequest, GetArchiveRequest, + GetCustomHooksRequest, HasLocalBranchesRequest, @@ -48,5 +50,6 @@ HasLocalBranchesRequest, + RemoveAllRequest, RemoveRepositoryRequest, RepositoryExistsRequest, RestoreCustomHooksRequest, SearchFilesByNameRequest, @@ -49,5 +52,7 @@ RemoveRepositoryRequest, RepositoryExistsRequest, RestoreCustomHooksRequest, SearchFilesByNameRequest, + SearchFilesByContentRequest, + SearchFilesByContentResponse, SetFullPathRequest, @@ -53,4 +58,5 @@ SetFullPathRequest, + SetCustomHooksRequest, WriteRefRequest, ) from hgitaly.stub.repository_pb2_grpc import RepositoryServiceStub @@ -61,6 +67,10 @@ ) from .fixture import ServiceFixture +parametrize = pytest.mark.parametrize + +END_OF_MATCH = SearchFilesByContentResponse(end_of_match=True) + @attr.s class RepositoryFixture(ServiceFixture): @@ -125,6 +135,28 @@ )) for path in resp.files] + def search_files_by_content(self, ref=b'branch/default', + aggregate_splitlines=True, + **kwargs): + stream = self.stub.SearchFilesByContent(SearchFilesByContentRequest( + repository=self.grpc_repo, + ref=ref, + **kwargs, + )) + if not aggregate_splitlines: + return list(stream) + + res = [] + match_data = BytesIO() + for resp in stream: + if resp.end_of_match: + res.append(match_data.getvalue().split(b'\n')) + match_data = BytesIO() # deliberately not as in tested code + res.append(resp) + else: + match_data.write(resp.match_data) + return res + def restore_custom_hooks(self, tarball_path, grpc_repo=None, nb_chunks=2, @@ -137,9 +169,21 @@ for chunk in stream.slice_binary_file(tarball_path, nb_chunks) ) + def set_custom_hooks(self, tarball_path, + grpc_repo=None, + nb_chunks=2, + **kw): + if grpc_repo is None: + grpc_repo = self.grpc_repo + + return self.stub.SetCustomHooks( + SetCustomHooksRequest(repository=grpc_repo, data=chunk) + for chunk in stream.slice_binary_file(tarball_path, nb_chunks) + ) + def backup_custom_hooks(self, save_path): with open(save_path, 'wb') as fobj: for chunk in self.stub.BackupCustomHooks(BackupCustomHooksRequest( repository=self.grpc_repo)): fobj.write(chunk.data) @@ -140,9 +184,15 @@ def backup_custom_hooks(self, save_path): with open(save_path, 'wb') as fobj: for chunk in self.stub.BackupCustomHooks(BackupCustomHooksRequest( repository=self.grpc_repo)): fobj.write(chunk.data) + def get_custom_hooks(self, save_path): + with open(save_path, 'wb') as fobj: + for chunk in self.stub.GetCustomHooks(GetCustomHooksRequest( + repository=self.grpc_repo)): + fobj.write(chunk.data) + def remove_repository(self, grpc_repo=None): if grpc_repo is None: grpc_repo = self.grpc_repo @@ -207,6 +257,9 @@ get_request_iter(ref_patterns)): fobj.write(chunk.data) + def remove_all(self, storage_name): + return self.stub.RemoveAll(RemoveAllRequest(storage_name=storage_name)) + def assert_compare_repos(self, target_repo_path): """Compare the fixture repo with another one. """ @@ -452,7 +505,7 @@ assert ( exc_info.value.details() == - 'FindMergeBase: at least 2 revisions are required' + 'at least 2 revisions are required' ) sha_not_exists = b'deadnode' * 5 @@ -581,7 +634,7 @@ assert search(ref=b'unknown', query='.') == [] -def test_restore_custom_hooks(fixture_with_repo, tmpdir): +def test_search_files_by_content(fixture_with_repo): fixture = fixture_with_repo wrapper = fixture.repo_wrapper @@ -585,6 +638,120 @@ fixture = fixture_with_repo wrapper = fixture.repo_wrapper + wrapper.write_commit('afoo', message="Some foo") + sub = (wrapper.path / 'sub') + sub.mkdir() + (sub / 'bar').write_text('line1\nline2\nbar content\nline4\nline5') + (sub / 'ba2').write_text('line1\nba2 content') + (sub / 'ba3').write_text('ba3 content\nline2') + # this one has Windows and MacOS Classic line endings: + (sub / 'ba4').write_text('l1\nl2\r\nl3\rba4 content\nl5') + (sub / 'ba5').write_text('m1\nm2\nm3\nm4\nm5\nm6\nba5 content\n') + long_content = 'very large content\n' * 3000 + shutil.copy2(TEST_DATA_DIR / 'backup_additional_no_git.tar', + wrapper.path / 'bin') + (wrapper.path / 'large').write_text(long_content) + + wrapper.commit(rel_paths=['bin', 'sub/bar', 'sub/ba2', 'sub/ba3', + 'sub/ba4', 'sub/ba5', 'large'], + message="zebar", add_remove=True) + search = fixture.search_files_by_content + + # cases not matching + assert not search(query='no match for this one') + assert not search(query='PaxHeader') # tarfile is excluded + assert not search(ref=b"no/such/fref", query='foo') + + # simple case: match, with two lines of content before and after + assert search(query="^bar.c") == [ + [b'branch/default:sub/bar\x001\x00line1', + b'branch/default:sub/bar\x002\x00line2', + b'branch/default:sub/bar\x003\x00bar content', + b'branch/default:sub/bar\x004\x00line4', + b'branch/default:sub/bar\x005\x00line5', + b'', + ], + END_OF_MATCH, + ] + + # with only one line if file before and after match + assert search(query="^ba2.c") == [ + [b'branch/default:sub/ba2\x001\x00line1', + b'branch/default:sub/ba2\x002\x00ba2 content', + b'', + ], + END_OF_MATCH, + ] + assert search(query="^ba3.c") == [ + [b'branch/default:sub/ba3\x001\x00ba3 content', + b'branch/default:sub/ba3\x002\x00line2', + b'', + ], + END_OF_MATCH, + ] + + # more than two lines before match + assert search(query="^ba4.c") == [ + [b'branch/default:sub/ba4\x002\x00l2', + b'branch/default:sub/ba4\x003\x00l3', + b'branch/default:sub/ba4\x004\x00ba4 content', + b'branch/default:sub/ba4\x005\x00l5', + b'', + ], + END_OF_MATCH, + ] + + # two matches, with overlapping context or not + assert search(query="^l1|ba4.c") == [ + [b'branch/default:sub/ba4\x001\x00l1', + b'branch/default:sub/ba4\x002\x00l2', + b'branch/default:sub/ba4\x003\x00l3', + b'branch/default:sub/ba4\x004\x00ba4 content', + b'branch/default:sub/ba4\x005\x00l5', + b'', + ], + END_OF_MATCH, + ] + assert search(query="^m1|ba5.c") == [ + [b'branch/default:sub/ba5\x001\x00m1', + b'branch/default:sub/ba5\x002\x00m2', + b'branch/default:sub/ba5\x003\x00m3', + b'', + ], + END_OF_MATCH, + [ + b'branch/default:sub/ba5\x005\x00m5', + b'branch/default:sub/ba5\x006\x00m6', + b'branch/default:sub/ba5\x007\x00ba5 content', + b'' + ], + END_OF_MATCH, + ] + # several matching files, with case insensitivity + assert len(search(query='ConTent')) == 6 * 2 + + # long match requiring several responses + long_match = search(query='^very', aggregate_splitlines=False) + assert len(long_match) == 3 + assert long_match[-1] == END_OF_MATCH + assert len(long_match[0].match_data) == WRITE_BUFFER_SIZE + + # error cases + with pytest.raises(grpc.RpcError) as exc_info: + search() + assert exc_info.value.code() == grpc.StatusCode.INVALID_ARGUMENT + + +@parametrize('rpc_name', ['restore', 'set']) +def test_set_custom_hooks(fixture_with_repo, tmpdir, rpc_name): + fixture = fixture_with_repo + wrapper = fixture.repo_wrapper + + if rpc_name == 'restore': + meth = fixture.restore_custom_hooks + else: + meth = fixture.set_custom_hooks + # this is a valid tar file with the minimal `hgrc` used in these tests # the underlying restoration function from py-heptapod is itself tested, # and Heptapod backup tests will further exercise this. @@ -593,7 +760,7 @@ hgrc_path = wrapper.path / '.hg/hgrc' os.unlink(hgrc_path) - fixture.restore_custom_hooks(tarball_path) + meth(tarball_path) assert hgrc_path.read_text() # TODO test unknown storage and repo @@ -603,7 +770,7 @@ invalid_tarball_path = tmpdir / 'invalid.tgz' invalid_tarball_path.write("something else") with pytest.raises(grpc.RpcError) as exc_info: - fixture.restore_custom_hooks(invalid_tarball_path) + meth(invalid_tarball_path) assert exc_info.value.code() == grpc.StatusCode.INTERNAL @@ -607,5 +774,6 @@ assert exc_info.value.code() == grpc.StatusCode.INTERNAL -def test_backup_custom_hooks(fixture_with_repo, tmpdir): +@parametrize('rpc_name', ['backup', 'get']) +def test_backup_custom_hooks(fixture_with_repo, tmpdir, rpc_name): fixture = fixture_with_repo @@ -611,3 +779,7 @@ fixture = fixture_with_repo + if rpc_name == 'backup': + meth = fixture.backup_custom_hooks + else: + meth = fixture.get_custom_hooks tarball_path = tmpdir / 'hg_aditional.tgz' @@ -612,6 +784,7 @@ tarball_path = tmpdir / 'hg_aditional.tgz' - fixture.backup_custom_hooks(tarball_path) + meth(tarball_path) + assert tarball_path.exists() def test_remove_repository(fixture_with_repo): @@ -972,3 +1145,25 @@ # is not in the incremental bundle # TODO do better and assert phases.public assert unbundled_repo[sha1].phase() == phases.draft + + +def test_remove_all(fixture_with_repo): + fixture = fixture_with_repo + storage_path = fixture.storage_path('default') + (storage_path / 'foo').write_bytes(b'something') + (storage_path / 'bar').symlink_to('foo') + (storage_path / 'broken').symlink_to('missing') + fixture.remove_all(storage_name='default') + + assert list(storage_path.iterdir()) == [] + + with pytest.raises(grpc.RpcError) as exc_info: + fixture.remove_all(storage_name='unknown') + assert exc_info.value.code() == grpc.StatusCode.INVALID_ARGUMENT + + storage_path.rmdir() # create error condition by removing the root dir + with pytest.raises(grpc.RpcError) as exc_info: + fixture.remove_all(storage_name='default') + exc = exc_info.value + assert exc.code() == grpc.StatusCode.INTERNAL + assert "No such file or directory: '%s'" % storage_path in exc.details() diff --git a/hgitaly/stub/commit_pb2.py b/hgitaly/stub/commit_pb2.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zdHViL2NvbW1pdF9wYjIucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL2NvbW1pdF9wYjIucHk= 100644 --- a/hgitaly/stub/commit_pb2.py +++ b/hgitaly/stub/commit_pb2.py @@ -22,7 +22,7 @@ syntax='proto3', serialized_options=b'Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0c\x63ommit.proto\x12\x06gitaly\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\nlint.proto\x1a\x0cshared.proto\"\xd4\x03\n\x12ListCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\trevisions\x18\x02 \x03(\t\x12\x36\n\x11pagination_params\x18\x03 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\x12/\n\x05order\x18\x04 \x01(\x0e\x32 .gitaly.ListCommitsRequest.Order\x12\x0f\n\x07reverse\x18\x0b \x01(\x08\x12\x13\n\x0bmax_parents\x18\x05 \x01(\r\x12\x14\n\x0c\x64isable_walk\x18\x06 \x01(\x08\x12\x14\n\x0c\x66irst_parent\x18\x07 \x01(\x08\x12)\n\x05\x61\x66ter\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12*\n\x06\x62\x65\x66ore\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0e\n\x06\x61uthor\x18\n \x01(\x0c\x12\x13\n\x0bignore_case\x18\x0c \x01(\x08\x12\x1f\n\x17\x63ommit_message_patterns\x18\r \x03(\x0c\"%\n\x05Order\x12\x08\n\x04NONE\x10\x00\x12\x08\n\x04TOPO\x10\x01\x12\x08\n\x04\x44\x41TE\x10\x02\"9\n\x13ListCommitsResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"}\n\x15ListAllCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x36\n\x11pagination_params\x18\x02 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\"<\n\x16ListAllCommitsResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"T\n\x12\x43ommitStatsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\"H\n\x13\x43ommitStatsResponse\x12\x0b\n\x03oid\x18\x01 \x01(\t\x12\x11\n\tadditions\x18\x02 \x01(\x05\x12\x11\n\tdeletions\x18\x03 \x01(\x05\"n\n\x17\x43ommitIsAncestorRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x0b\x61ncestor_id\x18\x02 \x01(\t\x12\x10\n\x08\x63hild_id\x18\x03 \x01(\t\")\n\x18\x43ommitIsAncestorResponse\x12\r\n\x05value\x18\x01 \x01(\x08\"\x81\x01\n\x10TreeEntryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\r\n\x05limit\x18\x04 \x01(\x03\x12\x10\n\x08max_size\x18\x05 \x01(\x03\"\xb5\x01\n\x11TreeEntryResponse\x12\x32\n\x04type\x18\x01 \x01(\x0e\x32$.gitaly.TreeEntryResponse.ObjectType\x12\x0b\n\x03oid\x18\x02 \x01(\t\x12\x0c\n\x04size\x18\x03 \x01(\x03\x12\x0c\n\x04mode\x18\x04 \x01(\x05\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\x0c\"5\n\nObjectType\x12\n\n\x06\x43OMMIT\x10\x00\x12\x08\n\x04\x42LOB\x10\x01\x12\x08\n\x04TREE\x10\x02\x12\x07\n\x03TAG\x10\x03\"\x9f\x02\n\x13\x43ountCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12)\n\x05\x61\x66ter\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12*\n\x06\x62\x65\x66ore\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04path\x18\x05 \x01(\x0c\x12\x11\n\tmax_count\x18\x06 \x01(\x05\x12\x0b\n\x03\x61ll\x18\x07 \x01(\x08\x12\x14\n\x0c\x66irst_parent\x18\x08 \x01(\x08\x12-\n\x0eglobal_options\x18\t \x01(\x0b\x32\x15.gitaly.GlobalOptions\"%\n\x14\x43ountCommitsResponse\x12\r\n\x05\x63ount\x18\x01 \x01(\x05\"\x8b\x01\n\x1c\x43ountDivergingCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x66rom\x18\x02 \x01(\x0c\x12\n\n\x02to\x18\x03 \x01(\x0c\x12\x11\n\tmax_count\x18\x07 \x01(\x05J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07\"H\n\x1d\x43ountDivergingCommitsResponse\x12\x12\n\nleft_count\x18\x01 \x01(\x05\x12\x13\n\x0bright_count\x18\x02 \x01(\x05\"\xc5\x01\n\tTreeEntry\x12\x0b\n\x03oid\x18\x01 \x01(\t\x12\x10\n\x08root_oid\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12)\n\x04type\x18\x04 \x01(\x0e\x32\x1b.gitaly.TreeEntry.EntryType\x12\x0c\n\x04mode\x18\x05 \x01(\x05\x12\x12\n\ncommit_oid\x18\x06 \x01(\t\x12\x11\n\tflat_path\x18\x07 \x01(\x0c\"+\n\tEntryType\x12\x08\n\x04\x42LOB\x10\x00\x12\x08\n\x04TREE\x10\x01\x12\n\n\x06\x43OMMIT\x10\x03\"\xa5\x02\n\x15GetTreeEntriesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\x11\n\trecursive\x18\x04 \x01(\x08\x12\x32\n\x04sort\x18\x05 \x01(\x0e\x32$.gitaly.GetTreeEntriesRequest.SortBy\x12\x36\n\x11pagination_params\x18\x06 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\x12\x17\n\x0fskip_flat_paths\x18\x07 \x01(\x08\"&\n\x06SortBy\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x0f\n\x0bTREES_FIRST\x10\x01\"q\n\x16GetTreeEntriesResponse\x12\"\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x11.gitaly.TreeEntry\x12\x33\n\x11pagination_cursor\x18\x02 \x01(\x0b\x32\x18.gitaly.PaginationCursor\"R\n\x10ListFilesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\"\"\n\x11ListFilesResponse\x12\r\n\x05paths\x18\x01 \x03(\x0c\"e\n\x11\x46indCommitRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x10\n\x08trailers\x18\x03 \x01(\x08\"7\n\x12\x46indCommitResponse\x12!\n\x06\x63ommit\x18\x01 \x01(\x0b\x32\x11.gitaly.GitCommit\"T\n\x17ListCommitsByOidRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03oid\x18\x02 \x03(\t\">\n\x18ListCommitsByOidResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"^\n\x1bListCommitsByRefNameRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tref_names\x18\x02 \x03(\x0c\"\xb1\x01\n\x1cListCommitsByRefNameResponse\x12\x46\n\x0b\x63ommit_refs\x18\x02 \x03(\x0b\x32\x31.gitaly.ListCommitsByRefNameResponse.CommitForRef\x1a\x43\n\x0c\x43ommitForRef\x12!\n\x06\x63ommit\x18\x01 \x01(\x0b\x32\x11.gitaly.GitCommit\x12\x10\n\x08ref_name\x18\x02 \x01(\x0cJ\x04\x08\x01\x10\x02\"\xd3\x01\n\x15\x46indAllCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x11\n\tmax_count\x18\x03 \x01(\x05\x12\x0c\n\x04skip\x18\x04 \x01(\x05\x12\x32\n\x05order\x18\x05 \x01(\x0e\x32#.gitaly.FindAllCommitsRequest.Order\"%\n\x05Order\x12\x08\n\x04NONE\x10\x00\x12\x08\n\x04TOPO\x10\x01\x12\x08\n\x04\x44\x41TE\x10\x02\"<\n\x16\x46indAllCommitsResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"\xf1\x03\n\x12\x46indCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\r\n\x05limit\x18\x03 \x01(\x05\x12\x0e\n\x06offset\x18\x04 \x01(\x05\x12\r\n\x05paths\x18\x05 \x03(\x0c\x12\x0e\n\x06\x66ollow\x18\x06 \x01(\x08\x12\x13\n\x0bskip_merges\x18\x07 \x01(\x08\x12\x14\n\x0c\x64isable_walk\x18\x08 \x01(\x08\x12)\n\x05\x61\x66ter\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12*\n\x06\x62\x65\x66ore\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0b\n\x03\x61ll\x18\x0b \x01(\x08\x12\x14\n\x0c\x66irst_parent\x18\x0c \x01(\x08\x12\x0e\n\x06\x61uthor\x18\r \x01(\x0c\x12/\n\x05order\x18\x0e \x01(\x0e\x32 .gitaly.FindCommitsRequest.Order\x12-\n\x0eglobal_options\x18\x0f \x01(\x0b\x32\x15.gitaly.GlobalOptions\x12\x10\n\x08trailers\x18\x10 \x01(\x08\x12\x19\n\x11include_shortstat\x18\x11 \x01(\x08\"\x1b\n\x05Order\x12\x08\n\x04NONE\x10\x00\x12\x08\n\x04TOPO\x10\x01\"9\n\x13\x46indCommitsResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"X\n\x16\x43ommitLanguagesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\"\xb1\x01\n\x17\x43ommitLanguagesResponse\x12;\n\tlanguages\x18\x01 \x03(\x0b\x32(.gitaly.CommitLanguagesResponse.Language\x1aY\n\x08Language\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05share\x18\x02 \x01(\x02\x12\r\n\x05\x63olor\x18\x03 \x01(\t\x12\x12\n\nfile_count\x18\x04 \x01(\r\x12\r\n\x05\x62ytes\x18\x05 \x01(\x04\"n\n\x0fRawBlameRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\r\n\x05range\x18\x04 \x01(\x0c\" \n\x10RawBlameResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\xb1\x01\n\x18LastCommitForPathRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\x18\n\x10literal_pathspec\x18\x04 \x01(\x08\x12-\n\x0eglobal_options\x18\x05 \x01(\x0b\x32\x15.gitaly.GlobalOptions\">\n\x19LastCommitForPathResponse\x12!\n\x06\x63ommit\x18\x01 \x01(\x0b\x32\x11.gitaly.GitCommit\"\xd9\x01\n\x1dListLastCommitsForTreeRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\r\n\x05limit\x18\x04 \x01(\x05\x12\x0e\n\x06offset\x18\x05 \x01(\x05\x12\x1c\n\x10literal_pathspec\x18\x06 \x01(\x08\x42\x02\x18\x01\x12-\n\x0eglobal_options\x18\x07 \x01(\x0b\x32\x15.gitaly.GlobalOptions\"\xbb\x01\n\x1eListLastCommitsForTreeResponse\x12\x45\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x34.gitaly.ListLastCommitsForTreeResponse.CommitForTree\x1aR\n\rCommitForTree\x12!\n\x06\x63ommit\x18\x02 \x01(\x0b\x32\x11.gitaly.GitCommit\x12\x12\n\npath_bytes\x18\x04 \x01(\x0cJ\x04\x08\x01\x10\x02J\x04\x08\x03\x10\x04\"\xc4\x01\n\x17\x43ommitsByMessageRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0e\n\x06offset\x18\x03 \x01(\x05\x12\r\n\x05limit\x18\x04 \x01(\x05\x12\x0c\n\x04path\x18\x05 \x01(\x0c\x12\r\n\x05query\x18\x06 \x01(\t\x12-\n\x0eglobal_options\x18\x07 \x01(\x0b\x32\x15.gitaly.GlobalOptions\">\n\x18\x43ommitsByMessageResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"]\n\x1f\x46ilterShasWithSignaturesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04shas\x18\x02 \x03(\x0c\"0\n FilterShasWithSignaturesResponse\x12\x0c\n\x04shas\x18\x01 \x03(\x0c\"`\n\x1d\x45xtractCommitSignatureRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tcommit_id\x18\x02 \x01(\t\"H\n\x1e\x45xtractCommitSignatureResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x13\n\x0bsigned_text\x18\x02 \x01(\x0c\"^\n\x1aGetCommitSignaturesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x12\n\ncommit_ids\x18\x02 \x03(\t\"X\n\x1bGetCommitSignaturesResponse\x12\x11\n\tcommit_id\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x13\n\x0bsigned_text\x18\x03 \x01(\x0c\"\\\n\x18GetCommitMessagesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x12\n\ncommit_ids\x18\x02 \x03(\t\"?\n\x19GetCommitMessagesResponse\x12\x11\n\tcommit_id\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\x0c\"[\n\x18\x43heckObjectsExistRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\trevisions\x18\x02 \x03(\x0c\"\x96\x01\n\x19\x43heckObjectsExistResponse\x12\x46\n\trevisions\x18\x01 \x03(\x0b\x32\x33.gitaly.CheckObjectsExistResponse.RevisionExistence\x1a\x31\n\x11RevisionExistence\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x0e\n\x06\x65xists\x18\x02 \x01(\x08\x32\xf1\x10\n\rCommitService\x12P\n\x0bListCommits\x12\x1a.gitaly.ListCommitsRequest\x1a\x1b.gitaly.ListCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12Y\n\x0eListAllCommits\x12\x1d.gitaly.ListAllCommitsRequest\x1a\x1e.gitaly.ListAllCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12]\n\x10\x43ommitIsAncestor\x12\x1f.gitaly.CommitIsAncestorRequest\x1a .gitaly.CommitIsAncestorResponse\"\x06\xfa\x97(\x02\x08\x02\x12J\n\tTreeEntry\x12\x18.gitaly.TreeEntryRequest\x1a\x19.gitaly.TreeEntryResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12Q\n\x0c\x43ountCommits\x12\x1b.gitaly.CountCommitsRequest\x1a\x1c.gitaly.CountCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x12l\n\x15\x43ountDivergingCommits\x12$.gitaly.CountDivergingCommitsRequest\x1a%.gitaly.CountDivergingCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x12Y\n\x0eGetTreeEntries\x12\x1d.gitaly.GetTreeEntriesRequest\x1a\x1e.gitaly.GetTreeEntriesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12J\n\tListFiles\x12\x18.gitaly.ListFilesRequest\x1a\x19.gitaly.ListFilesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12K\n\nFindCommit\x12\x19.gitaly.FindCommitRequest\x1a\x1a.gitaly.FindCommitResponse\"\x06\xfa\x97(\x02\x08\x02\x12N\n\x0b\x43ommitStats\x12\x1a.gitaly.CommitStatsRequest\x1a\x1b.gitaly.CommitStatsResponse\"\x06\xfa\x97(\x02\x08\x02\x12Y\n\x0e\x46indAllCommits\x12\x1d.gitaly.FindAllCommitsRequest\x1a\x1e.gitaly.FindAllCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12P\n\x0b\x46indCommits\x12\x1a.gitaly.FindCommitsRequest\x1a\x1b.gitaly.FindCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12Z\n\x0f\x43ommitLanguages\x12\x1e.gitaly.CommitLanguagesRequest\x1a\x1f.gitaly.CommitLanguagesResponse\"\x06\xfa\x97(\x02\x08\x02\x12G\n\x08RawBlame\x12\x17.gitaly.RawBlameRequest\x1a\x18.gitaly.RawBlameResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12`\n\x11LastCommitForPath\x12 .gitaly.LastCommitForPathRequest\x1a!.gitaly.LastCommitForPathResponse\"\x06\xfa\x97(\x02\x08\x02\x12q\n\x16ListLastCommitsForTree\x12%.gitaly.ListLastCommitsForTreeRequest\x1a&.gitaly.ListLastCommitsForTreeResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10\x43ommitsByMessage\x12\x1f.gitaly.CommitsByMessageRequest\x1a .gitaly.CommitsByMessageResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10ListCommitsByOid\x12\x1f.gitaly.ListCommitsByOidRequest\x1a .gitaly.ListCommitsByOidResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12k\n\x14ListCommitsByRefName\x12#.gitaly.ListCommitsByRefNameRequest\x1a$.gitaly.ListCommitsByRefNameResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12y\n\x18\x46ilterShasWithSignatures\x12\'.gitaly.FilterShasWithSignaturesRequest\x1a(.gitaly.FilterShasWithSignaturesResponse\"\x06\xfa\x97(\x02\x08\x02(\x01\x30\x01\x12h\n\x13GetCommitSignatures\x12\".gitaly.GetCommitSignaturesRequest\x1a#.gitaly.GetCommitSignaturesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x62\n\x11GetCommitMessages\x12 .gitaly.GetCommitMessagesRequest\x1a!.gitaly.GetCommitMessagesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x64\n\x11\x43heckObjectsExist\x12 .gitaly.CheckObjectsExistRequest\x1a!.gitaly.CheckObjectsExistResponse\"\x06\xfa\x97(\x02\x08\x02(\x01\x30\x01\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' + serialized_pb=b'\n\x0c\x63ommit.proto\x12\x06gitaly\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\nlint.proto\x1a\x0cshared.proto\"\xd4\x03\n\x12ListCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\trevisions\x18\x02 \x03(\t\x12\x36\n\x11pagination_params\x18\x03 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\x12/\n\x05order\x18\x04 \x01(\x0e\x32 .gitaly.ListCommitsRequest.Order\x12\x0f\n\x07reverse\x18\x0b \x01(\x08\x12\x13\n\x0bmax_parents\x18\x05 \x01(\r\x12\x14\n\x0c\x64isable_walk\x18\x06 \x01(\x08\x12\x14\n\x0c\x66irst_parent\x18\x07 \x01(\x08\x12)\n\x05\x61\x66ter\x18\x08 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12*\n\x06\x62\x65\x66ore\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0e\n\x06\x61uthor\x18\n \x01(\x0c\x12\x13\n\x0bignore_case\x18\x0c \x01(\x08\x12\x1f\n\x17\x63ommit_message_patterns\x18\r \x03(\x0c\"%\n\x05Order\x12\x08\n\x04NONE\x10\x00\x12\x08\n\x04TOPO\x10\x01\x12\x08\n\x04\x44\x41TE\x10\x02\"9\n\x13ListCommitsResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"}\n\x15ListAllCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x36\n\x11pagination_params\x18\x02 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\"<\n\x16ListAllCommitsResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"T\n\x12\x43ommitStatsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\"H\n\x13\x43ommitStatsResponse\x12\x0b\n\x03oid\x18\x01 \x01(\t\x12\x11\n\tadditions\x18\x02 \x01(\x05\x12\x11\n\tdeletions\x18\x03 \x01(\x05\"n\n\x17\x43ommitIsAncestorRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x0b\x61ncestor_id\x18\x02 \x01(\t\x12\x10\n\x08\x63hild_id\x18\x03 \x01(\t\")\n\x18\x43ommitIsAncestorResponse\x12\r\n\x05value\x18\x01 \x01(\x08\"\x81\x01\n\x10TreeEntryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\r\n\x05limit\x18\x04 \x01(\x03\x12\x10\n\x08max_size\x18\x05 \x01(\x03\"\xb5\x01\n\x11TreeEntryResponse\x12\x32\n\x04type\x18\x01 \x01(\x0e\x32$.gitaly.TreeEntryResponse.ObjectType\x12\x0b\n\x03oid\x18\x02 \x01(\t\x12\x0c\n\x04size\x18\x03 \x01(\x03\x12\x0c\n\x04mode\x18\x04 \x01(\x05\x12\x0c\n\x04\x64\x61ta\x18\x05 \x01(\x0c\"5\n\nObjectType\x12\n\n\x06\x43OMMIT\x10\x00\x12\x08\n\x04\x42LOB\x10\x01\x12\x08\n\x04TREE\x10\x02\x12\x07\n\x03TAG\x10\x03\"\x9f\x02\n\x13\x43ountCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12)\n\x05\x61\x66ter\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12*\n\x06\x62\x65\x66ore\x18\x04 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0c\n\x04path\x18\x05 \x01(\x0c\x12\x11\n\tmax_count\x18\x06 \x01(\x05\x12\x0b\n\x03\x61ll\x18\x07 \x01(\x08\x12\x14\n\x0c\x66irst_parent\x18\x08 \x01(\x08\x12-\n\x0eglobal_options\x18\t \x01(\x0b\x32\x15.gitaly.GlobalOptions\"%\n\x14\x43ountCommitsResponse\x12\r\n\x05\x63ount\x18\x01 \x01(\x05\"\x8b\x01\n\x1c\x43ountDivergingCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x66rom\x18\x02 \x01(\x0c\x12\n\n\x02to\x18\x03 \x01(\x0c\x12\x11\n\tmax_count\x18\x07 \x01(\x05J\x04\x08\x04\x10\x05J\x04\x08\x05\x10\x06J\x04\x08\x06\x10\x07\"H\n\x1d\x43ountDivergingCommitsResponse\x12\x12\n\nleft_count\x18\x01 \x01(\x05\x12\x13\n\x0bright_count\x18\x02 \x01(\x05\"\xc9\x01\n\tTreeEntry\x12\x0b\n\x03oid\x18\x01 \x01(\t\x12\x14\n\x08root_oid\x18\x02 \x01(\tB\x02\x18\x01\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12)\n\x04type\x18\x04 \x01(\x0e\x32\x1b.gitaly.TreeEntry.EntryType\x12\x0c\n\x04mode\x18\x05 \x01(\x05\x12\x12\n\ncommit_oid\x18\x06 \x01(\t\x12\x11\n\tflat_path\x18\x07 \x01(\x0c\"+\n\tEntryType\x12\x08\n\x04\x42LOB\x10\x00\x12\x08\n\x04TREE\x10\x01\x12\n\n\x06\x43OMMIT\x10\x03\"\xa5\x02\n\x15GetTreeEntriesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\x11\n\trecursive\x18\x04 \x01(\x08\x12\x32\n\x04sort\x18\x05 \x01(\x0e\x32$.gitaly.GetTreeEntriesRequest.SortBy\x12\x36\n\x11pagination_params\x18\x06 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\x12\x17\n\x0fskip_flat_paths\x18\x07 \x01(\x08\"&\n\x06SortBy\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x0f\n\x0bTREES_FIRST\x10\x01\"q\n\x16GetTreeEntriesResponse\x12\"\n\x07\x65ntries\x18\x01 \x03(\x0b\x32\x11.gitaly.TreeEntry\x12\x33\n\x11pagination_cursor\x18\x02 \x01(\x0b\x32\x18.gitaly.PaginationCursor\"R\n\x10ListFilesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\"\"\n\x11ListFilesResponse\x12\r\n\x05paths\x18\x01 \x03(\x0c\"e\n\x11\x46indCommitRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x10\n\x08trailers\x18\x03 \x01(\x08\"7\n\x12\x46indCommitResponse\x12!\n\x06\x63ommit\x18\x01 \x01(\x0b\x32\x11.gitaly.GitCommit\"T\n\x17ListCommitsByOidRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03oid\x18\x02 \x03(\t\">\n\x18ListCommitsByOidResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"^\n\x1bListCommitsByRefNameRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tref_names\x18\x02 \x03(\x0c\"\xb1\x01\n\x1cListCommitsByRefNameResponse\x12\x46\n\x0b\x63ommit_refs\x18\x02 \x03(\x0b\x32\x31.gitaly.ListCommitsByRefNameResponse.CommitForRef\x1a\x43\n\x0c\x43ommitForRef\x12!\n\x06\x63ommit\x18\x01 \x01(\x0b\x32\x11.gitaly.GitCommit\x12\x10\n\x08ref_name\x18\x02 \x01(\x0cJ\x04\x08\x01\x10\x02\"\xd3\x01\n\x15\x46indAllCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x11\n\tmax_count\x18\x03 \x01(\x05\x12\x0c\n\x04skip\x18\x04 \x01(\x05\x12\x32\n\x05order\x18\x05 \x01(\x0e\x32#.gitaly.FindAllCommitsRequest.Order\"%\n\x05Order\x12\x08\n\x04NONE\x10\x00\x12\x08\n\x04TOPO\x10\x01\x12\x08\n\x04\x44\x41TE\x10\x02\"<\n\x16\x46indAllCommitsResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"\x90\x04\n\x12\x46indCommitsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\r\n\x05limit\x18\x03 \x01(\x05\x12\x0e\n\x06offset\x18\x04 \x01(\x05\x12\r\n\x05paths\x18\x05 \x03(\x0c\x12\x0e\n\x06\x66ollow\x18\x06 \x01(\x08\x12\x13\n\x0bskip_merges\x18\x07 \x01(\x08\x12\x14\n\x0c\x64isable_walk\x18\x08 \x01(\x08\x12)\n\x05\x61\x66ter\x18\t \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12*\n\x06\x62\x65\x66ore\x18\n \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x0b\n\x03\x61ll\x18\x0b \x01(\x08\x12\x14\n\x0c\x66irst_parent\x18\x0c \x01(\x08\x12\x0e\n\x06\x61uthor\x18\r \x01(\x0c\x12/\n\x05order\x18\x0e \x01(\x0e\x32 .gitaly.FindCommitsRequest.Order\x12-\n\x0eglobal_options\x18\x0f \x01(\x0b\x32\x15.gitaly.GlobalOptions\x12\x10\n\x08trailers\x18\x10 \x01(\x08\x12\x19\n\x11include_shortstat\x18\x11 \x01(\x08\x12\x1d\n\x15include_referenced_by\x18\x12 \x03(\x0c\"\x1b\n\x05Order\x12\x08\n\x04NONE\x10\x00\x12\x08\n\x04TOPO\x10\x01\"9\n\x13\x46indCommitsResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"X\n\x16\x43ommitLanguagesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\"\xaf\x01\n\x17\x43ommitLanguagesResponse\x12;\n\tlanguages\x18\x01 \x03(\x0b\x32(.gitaly.CommitLanguagesResponse.Language\x1aW\n\x08Language\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\r\n\x05share\x18\x02 \x01(\x02\x12\r\n\x05\x63olor\x18\x03 \x01(\t\x12\r\n\x05\x62ytes\x18\x05 \x01(\x04J\x04\x08\x04\x10\x05R\nfile_count\"n\n\x0fRawBlameRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\r\n\x05range\x18\x04 \x01(\x0c\" \n\x10RawBlameResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\xb1\x01\n\x18LastCommitForPathRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\x18\n\x10literal_pathspec\x18\x04 \x01(\x08\x12-\n\x0eglobal_options\x18\x05 \x01(\x0b\x32\x15.gitaly.GlobalOptions\">\n\x19LastCommitForPathResponse\x12!\n\x06\x63ommit\x18\x01 \x01(\x0b\x32\x11.gitaly.GitCommit\"\xd9\x01\n\x1dListLastCommitsForTreeRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\t\x12\x0c\n\x04path\x18\x03 \x01(\x0c\x12\r\n\x05limit\x18\x04 \x01(\x05\x12\x0e\n\x06offset\x18\x05 \x01(\x05\x12\x1c\n\x10literal_pathspec\x18\x06 \x01(\x08\x42\x02\x18\x01\x12-\n\x0eglobal_options\x18\x07 \x01(\x0b\x32\x15.gitaly.GlobalOptions\"\xbb\x01\n\x1eListLastCommitsForTreeResponse\x12\x45\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x34.gitaly.ListLastCommitsForTreeResponse.CommitForTree\x1aR\n\rCommitForTree\x12!\n\x06\x63ommit\x18\x02 \x01(\x0b\x32\x11.gitaly.GitCommit\x12\x12\n\npath_bytes\x18\x04 \x01(\x0cJ\x04\x08\x01\x10\x02J\x04\x08\x03\x10\x04\"\xc4\x01\n\x17\x43ommitsByMessageRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\x12\x0e\n\x06offset\x18\x03 \x01(\x05\x12\r\n\x05limit\x18\x04 \x01(\x05\x12\x0c\n\x04path\x18\x05 \x01(\x0c\x12\r\n\x05query\x18\x06 \x01(\t\x12-\n\x0eglobal_options\x18\x07 \x01(\x0b\x32\x15.gitaly.GlobalOptions\">\n\x18\x43ommitsByMessageResponse\x12\"\n\x07\x63ommits\x18\x01 \x03(\x0b\x32\x11.gitaly.GitCommit\"]\n\x1f\x46ilterShasWithSignaturesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04shas\x18\x02 \x03(\x0c\"0\n FilterShasWithSignaturesResponse\x12\x0c\n\x04shas\x18\x01 \x03(\x0c\"`\n\x1d\x45xtractCommitSignatureRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tcommit_id\x18\x02 \x01(\t\"H\n\x1e\x45xtractCommitSignatureResponse\x12\x11\n\tsignature\x18\x01 \x01(\x0c\x12\x13\n\x0bsigned_text\x18\x02 \x01(\x0c\"^\n\x1aGetCommitSignaturesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x12\n\ncommit_ids\x18\x02 \x03(\t\"X\n\x1bGetCommitSignaturesResponse\x12\x11\n\tcommit_id\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x13\n\x0bsigned_text\x18\x03 \x01(\x0c\"\\\n\x18GetCommitMessagesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x12\n\ncommit_ids\x18\x02 \x03(\t\"?\n\x19GetCommitMessagesResponse\x12\x11\n\tcommit_id\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\x0c\"[\n\x18\x43heckObjectsExistRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\trevisions\x18\x02 \x03(\x0c\"\x96\x01\n\x19\x43heckObjectsExistResponse\x12\x46\n\trevisions\x18\x01 \x03(\x0b\x32\x33.gitaly.CheckObjectsExistResponse.RevisionExistence\x1a\x31\n\x11RevisionExistence\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x0e\n\x06\x65xists\x18\x02 \x01(\x08\x32\xf1\x10\n\rCommitService\x12P\n\x0bListCommits\x12\x1a.gitaly.ListCommitsRequest\x1a\x1b.gitaly.ListCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12Y\n\x0eListAllCommits\x12\x1d.gitaly.ListAllCommitsRequest\x1a\x1e.gitaly.ListAllCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12]\n\x10\x43ommitIsAncestor\x12\x1f.gitaly.CommitIsAncestorRequest\x1a .gitaly.CommitIsAncestorResponse\"\x06\xfa\x97(\x02\x08\x02\x12J\n\tTreeEntry\x12\x18.gitaly.TreeEntryRequest\x1a\x19.gitaly.TreeEntryResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12Q\n\x0c\x43ountCommits\x12\x1b.gitaly.CountCommitsRequest\x1a\x1c.gitaly.CountCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x12l\n\x15\x43ountDivergingCommits\x12$.gitaly.CountDivergingCommitsRequest\x1a%.gitaly.CountDivergingCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x12Y\n\x0eGetTreeEntries\x12\x1d.gitaly.GetTreeEntriesRequest\x1a\x1e.gitaly.GetTreeEntriesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12J\n\tListFiles\x12\x18.gitaly.ListFilesRequest\x1a\x19.gitaly.ListFilesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12K\n\nFindCommit\x12\x19.gitaly.FindCommitRequest\x1a\x1a.gitaly.FindCommitResponse\"\x06\xfa\x97(\x02\x08\x02\x12N\n\x0b\x43ommitStats\x12\x1a.gitaly.CommitStatsRequest\x1a\x1b.gitaly.CommitStatsResponse\"\x06\xfa\x97(\x02\x08\x02\x12Y\n\x0e\x46indAllCommits\x12\x1d.gitaly.FindAllCommitsRequest\x1a\x1e.gitaly.FindAllCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12P\n\x0b\x46indCommits\x12\x1a.gitaly.FindCommitsRequest\x1a\x1b.gitaly.FindCommitsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12Z\n\x0f\x43ommitLanguages\x12\x1e.gitaly.CommitLanguagesRequest\x1a\x1f.gitaly.CommitLanguagesResponse\"\x06\xfa\x97(\x02\x08\x02\x12G\n\x08RawBlame\x12\x17.gitaly.RawBlameRequest\x1a\x18.gitaly.RawBlameResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12`\n\x11LastCommitForPath\x12 .gitaly.LastCommitForPathRequest\x1a!.gitaly.LastCommitForPathResponse\"\x06\xfa\x97(\x02\x08\x02\x12q\n\x16ListLastCommitsForTree\x12%.gitaly.ListLastCommitsForTreeRequest\x1a&.gitaly.ListLastCommitsForTreeResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10\x43ommitsByMessage\x12\x1f.gitaly.CommitsByMessageRequest\x1a .gitaly.CommitsByMessageResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10ListCommitsByOid\x12\x1f.gitaly.ListCommitsByOidRequest\x1a .gitaly.ListCommitsByOidResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12k\n\x14ListCommitsByRefName\x12#.gitaly.ListCommitsByRefNameRequest\x1a$.gitaly.ListCommitsByRefNameResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12y\n\x18\x46ilterShasWithSignatures\x12\'.gitaly.FilterShasWithSignaturesRequest\x1a(.gitaly.FilterShasWithSignaturesResponse\"\x06\xfa\x97(\x02\x08\x02(\x01\x30\x01\x12h\n\x13GetCommitSignatures\x12\".gitaly.GetCommitSignaturesRequest\x1a#.gitaly.GetCommitSignaturesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x62\n\x11GetCommitMessages\x12 .gitaly.GetCommitMessagesRequest\x1a!.gitaly.GetCommitMessagesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x64\n\x11\x43heckObjectsExist\x12 .gitaly.CheckObjectsExistRequest\x1a!.gitaly.CheckObjectsExistResponse\"\x06\xfa\x97(\x02\x08\x02(\x01\x30\x01\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' , dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,lint__pb2.DESCRIPTOR,shared__pb2.DESCRIPTOR,]) @@ -118,8 +118,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=2133, - serialized_end=2176, + serialized_start=2137, + serialized_end=2180, ) _sym_db.RegisterEnumDescriptor(_TREEENTRY_ENTRYTYPE) @@ -143,8 +143,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=2434, - serialized_end=2472, + serialized_start=2438, + serialized_end=2476, ) _sym_db.RegisterEnumDescriptor(_GETTREEENTRIESREQUEST_SORTBY) @@ -941,7 +941,7 @@ has_default_value=False, default_value=b"".decode('utf-8'), message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=b'\030\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='path', full_name='gitaly.TreeEntry.path', index=2, number=3, type=12, cpp_type=9, label=1, @@ -991,7 +991,7 @@ oneofs=[ ], serialized_start=1979, - serialized_end=2176, + serialized_end=2180, ) @@ -1065,8 +1065,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2179, - serialized_end=2472, + serialized_start=2183, + serialized_end=2476, ) @@ -1104,8 +1104,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2474, - serialized_end=2587, + serialized_start=2478, + serialized_end=2591, ) @@ -1143,8 +1143,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2589, - serialized_end=2671, + serialized_start=2593, + serialized_end=2675, ) @@ -1175,8 +1175,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2673, - serialized_end=2707, + serialized_start=2677, + serialized_end=2711, ) @@ -1221,8 +1221,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2709, - serialized_end=2810, + serialized_start=2713, + serialized_end=2814, ) @@ -1253,8 +1253,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2812, - serialized_end=2867, + serialized_start=2816, + serialized_end=2871, ) @@ -1292,8 +1292,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2869, - serialized_end=2953, + serialized_start=2873, + serialized_end=2957, ) @@ -1324,8 +1324,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2955, - serialized_end=3017, + serialized_start=2959, + serialized_end=3021, ) @@ -1363,8 +1363,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3019, - serialized_end=3113, + serialized_start=3023, + serialized_end=3117, ) @@ -1402,8 +1402,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3220, - serialized_end=3287, + serialized_start=3224, + serialized_end=3291, ) _LISTCOMMITSBYREFNAMERESPONSE = _descriptor.Descriptor( @@ -1433,8 +1433,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3116, - serialized_end=3293, + serialized_start=3120, + serialized_end=3297, ) @@ -1494,8 +1494,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3296, - serialized_end=3507, + serialized_start=3300, + serialized_end=3511, ) @@ -1526,8 +1526,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3509, - serialized_end=3569, + serialized_start=3513, + serialized_end=3573, ) @@ -1658,6 +1658,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='include_referenced_by', full_name='gitaly.FindCommitsRequest.include_referenced_by', index=17, + number=18, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -1671,8 +1678,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3572, - serialized_end=4069, + serialized_start=3576, + serialized_end=4104, ) @@ -1703,8 +1710,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4071, - serialized_end=4128, + serialized_start=4106, + serialized_end=4163, ) @@ -1742,8 +1749,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4130, - serialized_end=4218, + serialized_start=4165, + serialized_end=4253, ) @@ -1777,14 +1784,7 @@ is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( - name='file_count', full_name='gitaly.CommitLanguagesResponse.Language.file_count', index=3, - number=4, type=13, cpp_type=3, label=1, - has_default_value=False, default_value=0, - message_type=None, enum_type=None, containing_type=None, - is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), - _descriptor.FieldDescriptor( - name='bytes', full_name='gitaly.CommitLanguagesResponse.Language.bytes', index=4, + name='bytes', full_name='gitaly.CommitLanguagesResponse.Language.bytes', index=3, number=5, type=4, cpp_type=4, label=1, has_default_value=False, default_value=0, message_type=None, enum_type=None, containing_type=None, @@ -1802,8 +1802,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4309, - serialized_end=4398, + serialized_start=4344, + serialized_end=4431, ) _COMMITLANGUAGESRESPONSE = _descriptor.Descriptor( @@ -1833,8 +1833,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4221, - serialized_end=4398, + serialized_start=4256, + serialized_end=4431, ) @@ -1886,8 +1886,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4400, - serialized_end=4510, + serialized_start=4433, + serialized_end=4543, ) @@ -1918,8 +1918,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4512, - serialized_end=4544, + serialized_start=4545, + serialized_end=4577, ) @@ -1978,8 +1978,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4547, - serialized_end=4724, + serialized_start=4580, + serialized_end=4757, ) @@ -2010,8 +2010,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4726, - serialized_end=4788, + serialized_start=4759, + serialized_end=4821, ) @@ -2084,8 +2084,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4791, - serialized_end=5008, + serialized_start=4824, + serialized_end=5041, ) @@ -2123,8 +2123,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5116, - serialized_end=5198, + serialized_start=5149, + serialized_end=5231, ) _LISTLASTCOMMITSFORTREERESPONSE = _descriptor.Descriptor( @@ -2154,8 +2154,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5011, - serialized_end=5198, + serialized_start=5044, + serialized_end=5231, ) @@ -2228,8 +2228,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5201, - serialized_end=5397, + serialized_start=5234, + serialized_end=5430, ) @@ -2260,8 +2260,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5399, - serialized_end=5461, + serialized_start=5432, + serialized_end=5494, ) @@ -2299,8 +2299,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5463, - serialized_end=5556, + serialized_start=5496, + serialized_end=5589, ) @@ -2331,8 +2331,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5558, - serialized_end=5606, + serialized_start=5591, + serialized_end=5639, ) @@ -2370,8 +2370,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5608, - serialized_end=5704, + serialized_start=5641, + serialized_end=5737, ) @@ -2409,8 +2409,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5706, - serialized_end=5778, + serialized_start=5739, + serialized_end=5811, ) @@ -2448,8 +2448,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5780, - serialized_end=5874, + serialized_start=5813, + serialized_end=5907, ) @@ -2494,8 +2494,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5876, - serialized_end=5964, + serialized_start=5909, + serialized_end=5997, ) @@ -2533,8 +2533,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5966, - serialized_end=6058, + serialized_start=5999, + serialized_end=6091, ) @@ -2572,8 +2572,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6060, - serialized_end=6123, + serialized_start=6093, + serialized_end=6156, ) @@ -2611,8 +2611,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6125, - serialized_end=6216, + serialized_start=6158, + serialized_end=6249, ) @@ -2650,8 +2650,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6320, - serialized_end=6369, + serialized_start=6353, + serialized_end=6402, ) _CHECKOBJECTSEXISTRESPONSE = _descriptor.Descriptor( @@ -2681,8 +2681,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6219, - serialized_end=6369, + serialized_start=6252, + serialized_end=6402, ) _LISTCOMMITSREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY @@ -3190,6 +3190,7 @@ _TREEENTRYREQUEST.fields_by_name['repository']._options = None _COUNTCOMMITSREQUEST.fields_by_name['repository']._options = None _COUNTDIVERGINGCOMMITSREQUEST.fields_by_name['repository']._options = None +_TREEENTRY.fields_by_name['root_oid']._options = None _GETTREEENTRIESREQUEST.fields_by_name['repository']._options = None _LISTFILESREQUEST.fields_by_name['repository']._options = None _FINDCOMMITREQUEST.fields_by_name['repository']._options = None @@ -3216,8 +3217,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=6372, - serialized_end=8533, + serialized_start=6405, + serialized_end=8566, methods=[ _descriptor.MethodDescriptor( name='ListCommits', diff --git a/hgitaly/stub/diff_pb2.py b/hgitaly/stub/diff_pb2.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zdHViL2RpZmZfcGIyLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL2RpZmZfcGIyLnB5 100644 --- a/hgitaly/stub/diff_pb2.py +++ b/hgitaly/stub/diff_pb2.py @@ -21,7 +21,7 @@ syntax='proto3', serialized_options=b'Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\ndiff.proto\x12\x06gitaly\x1a\nlint.proto\x1a\x0cshared.proto\"\xcb\x03\n\x11\x43ommitDiffRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\x12 \n\x18ignore_whitespace_change\x18\x04 \x01(\x08\x12\r\n\x05paths\x18\x05 \x03(\x0c\x12\x16\n\x0e\x63ollapse_diffs\x18\x06 \x01(\x08\x12\x16\n\x0e\x65nforce_limits\x18\x07 \x01(\x08\x12\x11\n\tmax_files\x18\x08 \x01(\x05\x12\x11\n\tmax_lines\x18\t \x01(\x05\x12\x11\n\tmax_bytes\x18\n \x01(\x05\x12\x17\n\x0fmax_patch_bytes\x18\x0e \x01(\x05\x12\x16\n\x0esafe_max_files\x18\x0b \x01(\x05\x12\x16\n\x0esafe_max_lines\x18\x0c \x01(\x05\x12\x16\n\x0esafe_max_bytes\x18\r \x01(\x05\x12\x35\n\tdiff_mode\x18\x0f \x01(\x0e\x32\".gitaly.CommitDiffRequest.DiffMode\"%\n\x08\x44iffMode\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x0c\n\x08WORDDIFF\x10\x01\"\xff\x01\n\x12\x43ommitDiffResponse\x12\x11\n\tfrom_path\x18\x01 \x01(\x0c\x12\x0f\n\x07to_path\x18\x02 \x01(\x0c\x12\x0f\n\x07\x66rom_id\x18\x03 \x01(\t\x12\r\n\x05to_id\x18\x04 \x01(\t\x12\x10\n\x08old_mode\x18\x05 \x01(\x05\x12\x10\n\x08new_mode\x18\x06 \x01(\x05\x12\x0e\n\x06\x62inary\x18\x07 \x01(\x08\x12\x16\n\x0eraw_patch_data\x18\t \x01(\x0c\x12\x14\n\x0c\x65nd_of_patch\x18\n \x01(\x08\x12\x17\n\x0foverflow_marker\x18\x0b \x01(\x08\x12\x11\n\tcollapsed\x18\x0c \x01(\x08\x12\x11\n\ttoo_large\x18\r \x01(\x08J\x04\x08\x08\x10\t\"\x82\x01\n\x12\x43ommitDeltaRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\x12\r\n\x05paths\x18\x04 \x03(\x0c\"u\n\x0b\x43ommitDelta\x12\x11\n\tfrom_path\x18\x01 \x01(\x0c\x12\x0f\n\x07to_path\x18\x02 \x01(\x0c\x12\x0f\n\x07\x66rom_id\x18\x03 \x01(\t\x12\r\n\x05to_id\x18\x04 \x01(\t\x12\x10\n\x08old_mode\x18\x05 \x01(\x05\x12\x10\n\x08new_mode\x18\x06 \x01(\x05\":\n\x13\x43ommitDeltaResponse\x12#\n\x06\x64\x65ltas\x18\x01 \x03(\x0b\x32\x13.gitaly.CommitDelta\"o\n\x0eRawDiffRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\"\x1f\n\x0fRawDiffResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"p\n\x0fRawPatchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\" \n\x10RawPatchResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"q\n\x10\x44iffStatsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\"Q\n\tDiffStats\x12\x0c\n\x04path\x18\x01 \x01(\x0c\x12\x11\n\tadditions\x18\x02 \x01(\x05\x12\x11\n\tdeletions\x18\x03 \x01(\x05\x12\x10\n\x08old_path\x18\x04 \x01(\x0c\"5\n\x11\x44iffStatsResponse\x12 \n\x05stats\x18\x01 \x03(\x0b\x32\x11.gitaly.DiffStats\"\xdc\x03\n\x17\x46indChangedPathsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x07\x63ommits\x18\x02 \x03(\tB\x02\x18\x01\x12\x39\n\x08requests\x18\x03 \x03(\x0b\x32\'.gitaly.FindChangedPathsRequest.Request\x1a\xc2\x02\n\x07Request\x12K\n\x0ctree_request\x18\x01 \x01(\x0b\x32\x33.gitaly.FindChangedPathsRequest.Request.TreeRequestH\x00\x12O\n\x0e\x63ommit_request\x18\x02 \x01(\x0b\x32\x35.gitaly.FindChangedPathsRequest.Request.CommitRequestH\x00\x1a\x46\n\x0bTreeRequest\x12\x1a\n\x12left_tree_revision\x18\x01 \x01(\t\x12\x1b\n\x13right_tree_revision\x18\x02 \x01(\t\x1aI\n\rCommitRequest\x12\x17\n\x0f\x63ommit_revision\x18\x01 \x01(\t\x12\x1f\n\x17parent_commit_revisions\x18\x02 \x03(\tB\x06\n\x04type\"?\n\x18\x46indChangedPathsResponse\x12#\n\x05paths\x18\x01 \x03(\x0b\x32\x14.gitaly.ChangedPaths\"\xba\x01\n\x0c\x43hangedPaths\x12\x0c\n\x04path\x18\x01 \x01(\x0c\x12+\n\x06status\x18\x02 \x01(\x0e\x32\x1b.gitaly.ChangedPaths.Status\x12\x10\n\x08old_mode\x18\x03 \x01(\x05\x12\x10\n\x08new_mode\x18\x04 \x01(\x05\"K\n\x06Status\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x00\x12\x0c\n\x08MODIFIED\x10\x01\x12\x0b\n\x07\x44\x45LETED\x10\x02\x12\x0f\n\x0bTYPE_CHANGE\x10\x03\x12\n\n\x06\x43OPIED\x10\x04\x32\xea\x03\n\x0b\x44iffService\x12M\n\nCommitDiff\x12\x19.gitaly.CommitDiffRequest\x1a\x1a.gitaly.CommitDiffResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12P\n\x0b\x43ommitDelta\x12\x1a.gitaly.CommitDeltaRequest\x1a\x1b.gitaly.CommitDeltaResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x44\n\x07RawDiff\x12\x16.gitaly.RawDiffRequest\x1a\x17.gitaly.RawDiffResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12G\n\x08RawPatch\x12\x17.gitaly.RawPatchRequest\x1a\x18.gitaly.RawPatchResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12J\n\tDiffStats\x12\x18.gitaly.DiffStatsRequest\x1a\x19.gitaly.DiffStatsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10\x46indChangedPaths\x12\x1f.gitaly.FindChangedPathsRequest\x1a .gitaly.FindChangedPathsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' + serialized_pb=b'\n\ndiff.proto\x12\x06gitaly\x1a\nlint.proto\x1a\x0cshared.proto\"\xc3\x06\n\x11\x43ommitDiffRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\x12$\n\x18ignore_whitespace_change\x18\x04 \x01(\x08\x42\x02\x18\x01\x12\r\n\x05paths\x18\x05 \x03(\x0c\x12\x16\n\x0e\x63ollapse_diffs\x18\x06 \x01(\x08\x12\x16\n\x0e\x65nforce_limits\x18\x07 \x01(\x08\x12\x11\n\tmax_files\x18\x08 \x01(\x05\x12\x11\n\tmax_lines\x18\t \x01(\x05\x12\x11\n\tmax_bytes\x18\n \x01(\x05\x12\x17\n\x0fmax_patch_bytes\x18\x0e \x01(\x05\x12\x16\n\x0esafe_max_files\x18\x0b \x01(\x05\x12\x16\n\x0esafe_max_lines\x18\x0c \x01(\x05\x12\x16\n\x0esafe_max_bytes\x18\r \x01(\x05\x12\x35\n\tdiff_mode\x18\x0f \x01(\x0e\x32\".gitaly.CommitDiffRequest.DiffMode\x12h\n\"max_patch_bytes_for_file_extension\x18\x10 \x03(\x0b\x32<.gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry\x12G\n\x12whitespace_changes\x18\x11 \x01(\x0e\x32+.gitaly.CommitDiffRequest.WhitespaceChanges\x1a\x44\n\"MaxPatchBytesForFileExtensionEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x05:\x02\x38\x01\"%\n\x08\x44iffMode\x12\x0b\n\x07\x44\x45\x46\x41ULT\x10\x00\x12\x0c\n\x08WORDDIFF\x10\x01\"y\n\x11WhitespaceChanges\x12\"\n\x1eWHITESPACE_CHANGES_UNSPECIFIED\x10\x00\x12\x1d\n\x19WHITESPACE_CHANGES_IGNORE\x10\x01\x12!\n\x1dWHITESPACE_CHANGES_IGNORE_ALL\x10\x02\"\xff\x01\n\x12\x43ommitDiffResponse\x12\x11\n\tfrom_path\x18\x01 \x01(\x0c\x12\x0f\n\x07to_path\x18\x02 \x01(\x0c\x12\x0f\n\x07\x66rom_id\x18\x03 \x01(\t\x12\r\n\x05to_id\x18\x04 \x01(\t\x12\x10\n\x08old_mode\x18\x05 \x01(\x05\x12\x10\n\x08new_mode\x18\x06 \x01(\x05\x12\x0e\n\x06\x62inary\x18\x07 \x01(\x08\x12\x16\n\x0eraw_patch_data\x18\t \x01(\x0c\x12\x14\n\x0c\x65nd_of_patch\x18\n \x01(\x08\x12\x17\n\x0foverflow_marker\x18\x0b \x01(\x08\x12\x11\n\tcollapsed\x18\x0c \x01(\x08\x12\x11\n\ttoo_large\x18\r \x01(\x08J\x04\x08\x08\x10\t\"\x82\x01\n\x12\x43ommitDeltaRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\x12\r\n\x05paths\x18\x04 \x03(\x0c\"u\n\x0b\x43ommitDelta\x12\x11\n\tfrom_path\x18\x01 \x01(\x0c\x12\x0f\n\x07to_path\x18\x02 \x01(\x0c\x12\x0f\n\x07\x66rom_id\x18\x03 \x01(\t\x12\r\n\x05to_id\x18\x04 \x01(\t\x12\x10\n\x08old_mode\x18\x05 \x01(\x05\x12\x10\n\x08new_mode\x18\x06 \x01(\x05\":\n\x13\x43ommitDeltaResponse\x12#\n\x06\x64\x65ltas\x18\x01 \x03(\x0b\x32\x13.gitaly.CommitDelta\"o\n\x0eRawDiffRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\"\x1f\n\x0fRawDiffResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"p\n\x0fRawPatchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\" \n\x10RawPatchResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"q\n\x10\x44iffStatsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0eleft_commit_id\x18\x02 \x01(\t\x12\x17\n\x0fright_commit_id\x18\x03 \x01(\t\"Q\n\tDiffStats\x12\x0c\n\x04path\x18\x01 \x01(\x0c\x12\x11\n\tadditions\x18\x02 \x01(\x05\x12\x11\n\tdeletions\x18\x03 \x01(\x05\x12\x10\n\x08old_path\x18\x04 \x01(\x0c\"5\n\x11\x44iffStatsResponse\x12 \n\x05stats\x18\x01 \x03(\x0b\x32\x11.gitaly.DiffStats\"\xdc\x03\n\x17\x46indChangedPathsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x07\x63ommits\x18\x02 \x03(\tB\x02\x18\x01\x12\x39\n\x08requests\x18\x03 \x03(\x0b\x32\'.gitaly.FindChangedPathsRequest.Request\x1a\xc2\x02\n\x07Request\x12K\n\x0ctree_request\x18\x01 \x01(\x0b\x32\x33.gitaly.FindChangedPathsRequest.Request.TreeRequestH\x00\x12O\n\x0e\x63ommit_request\x18\x02 \x01(\x0b\x32\x35.gitaly.FindChangedPathsRequest.Request.CommitRequestH\x00\x1a\x46\n\x0bTreeRequest\x12\x1a\n\x12left_tree_revision\x18\x01 \x01(\t\x12\x1b\n\x13right_tree_revision\x18\x02 \x01(\t\x1aI\n\rCommitRequest\x12\x17\n\x0f\x63ommit_revision\x18\x01 \x01(\t\x12\x1f\n\x17parent_commit_revisions\x18\x02 \x03(\tB\x06\n\x04type\"?\n\x18\x46indChangedPathsResponse\x12#\n\x05paths\x18\x01 \x03(\x0b\x32\x14.gitaly.ChangedPaths\"\xba\x01\n\x0c\x43hangedPaths\x12\x0c\n\x04path\x18\x01 \x01(\x0c\x12+\n\x06status\x18\x02 \x01(\x0e\x32\x1b.gitaly.ChangedPaths.Status\x12\x10\n\x08old_mode\x18\x03 \x01(\x05\x12\x10\n\x08new_mode\x18\x04 \x01(\x05\"K\n\x06Status\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x00\x12\x0c\n\x08MODIFIED\x10\x01\x12\x0b\n\x07\x44\x45LETED\x10\x02\x12\x0f\n\x0bTYPE_CHANGE\x10\x03\x12\n\n\x06\x43OPIED\x10\x04\"m\n\x11GetPatchIDRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x14\n\x0cold_revision\x18\x02 \x01(\x0c\x12\x14\n\x0cnew_revision\x18\x03 \x01(\x0c\"&\n\x12GetPatchIDResponse\x12\x10\n\x08patch_id\x18\x01 \x01(\t2\xb7\x04\n\x0b\x44iffService\x12M\n\nCommitDiff\x12\x19.gitaly.CommitDiffRequest\x1a\x1a.gitaly.CommitDiffResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12P\n\x0b\x43ommitDelta\x12\x1a.gitaly.CommitDeltaRequest\x1a\x1b.gitaly.CommitDeltaResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x44\n\x07RawDiff\x12\x16.gitaly.RawDiffRequest\x1a\x17.gitaly.RawDiffResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12G\n\x08RawPatch\x12\x17.gitaly.RawPatchRequest\x1a\x18.gitaly.RawPatchResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12J\n\tDiffStats\x12\x18.gitaly.DiffStatsRequest\x1a\x19.gitaly.DiffStatsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10\x46indChangedPaths\x12\x1f.gitaly.FindChangedPathsRequest\x1a .gitaly.FindChangedPathsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12K\n\nGetPatchID\x12\x19.gitaly.GetPatchIDRequest\x1a\x1a.gitaly.GetPatchIDResponse\"\x06\xfa\x97(\x02\x08\x02\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' , dependencies=[lint__pb2.DESCRIPTOR,shared__pb2.DESCRIPTOR,]) @@ -47,8 +47,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=471, - serialized_end=508, + serialized_start=724, + serialized_end=761, ) _sym_db.RegisterEnumDescriptor(_COMMITDIFFREQUEST_DIFFMODE) @@ -52,6 +52,36 @@ ) _sym_db.RegisterEnumDescriptor(_COMMITDIFFREQUEST_DIFFMODE) +_COMMITDIFFREQUEST_WHITESPACECHANGES = _descriptor.EnumDescriptor( + name='WhitespaceChanges', + full_name='gitaly.CommitDiffRequest.WhitespaceChanges', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='WHITESPACE_CHANGES_UNSPECIFIED', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='WHITESPACE_CHANGES_IGNORE', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='WHITESPACE_CHANGES_IGNORE_ALL', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=763, + serialized_end=884, +) +_sym_db.RegisterEnumDescriptor(_COMMITDIFFREQUEST_WHITESPACECHANGES) + _CHANGEDPATHS_STATUS = _descriptor.EnumDescriptor( name='Status', full_name='gitaly.ChangedPaths.Status', @@ -87,9 +117,9 @@ ], containing_type=None, serialized_options=None, - serialized_start=2283, - serialized_end=2358, + serialized_start=2659, + serialized_end=2734, ) _sym_db.RegisterEnumDescriptor(_CHANGEDPATHS_STATUS) @@ -92,7 +122,45 @@ ) _sym_db.RegisterEnumDescriptor(_CHANGEDPATHS_STATUS) +_COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY = _descriptor.Descriptor( + name='MaxPatchBytesForFileExtensionEntry', + full_name='gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='key', full_name='gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry.key', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='value', full_name='gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry.value', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=b'8\001', + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=654, + serialized_end=722, +) + _COMMITDIFFREQUEST = _descriptor.Descriptor( name='CommitDiffRequest', full_name='gitaly.CommitDiffRequest', @@ -128,7 +196,7 @@ has_default_value=False, default_value=False, message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, - serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + serialized_options=b'\030\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), _descriptor.FieldDescriptor( name='paths', full_name='gitaly.CommitDiffRequest.paths', index=4, number=5, type=12, cpp_type=9, label=3, @@ -206,6 +274,20 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='max_patch_bytes_for_file_extension', full_name='gitaly.CommitDiffRequest.max_patch_bytes_for_file_extension', index=15, + number=16, type=11, cpp_type=10, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='whitespace_changes', full_name='gitaly.CommitDiffRequest.whitespace_changes', index=16, + number=17, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -209,6 +291,6 @@ ], extensions=[ ], - nested_types=[], + nested_types=[_COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY, ], enum_types=[ _COMMITDIFFREQUEST_DIFFMODE, @@ -213,5 +295,6 @@ enum_types=[ _COMMITDIFFREQUEST_DIFFMODE, + _COMMITDIFFREQUEST_WHITESPACECHANGES, ], serialized_options=None, is_extendable=False, @@ -220,7 +303,7 @@ oneofs=[ ], serialized_start=49, - serialized_end=508, + serialized_end=884, ) @@ -328,8 +411,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=511, - serialized_end=766, + serialized_start=887, + serialized_end=1142, ) @@ -381,8 +464,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=769, - serialized_end=899, + serialized_start=1145, + serialized_end=1275, ) @@ -448,8 +531,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=901, - serialized_end=1018, + serialized_start=1277, + serialized_end=1394, ) @@ -480,8 +563,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1020, - serialized_end=1078, + serialized_start=1396, + serialized_end=1454, ) @@ -526,8 +609,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1080, - serialized_end=1191, + serialized_start=1456, + serialized_end=1567, ) @@ -558,8 +641,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1193, - serialized_end=1224, + serialized_start=1569, + serialized_end=1600, ) @@ -604,8 +687,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1226, - serialized_end=1338, + serialized_start=1602, + serialized_end=1714, ) @@ -636,8 +719,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1340, - serialized_end=1372, + serialized_start=1716, + serialized_end=1748, ) @@ -682,8 +765,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1374, - serialized_end=1487, + serialized_start=1750, + serialized_end=1863, ) @@ -735,8 +818,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1489, - serialized_end=1570, + serialized_start=1865, + serialized_end=1946, ) @@ -767,8 +850,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1572, - serialized_end=1625, + serialized_start=1948, + serialized_end=2001, ) @@ -806,8 +889,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1951, - serialized_end=2021, + serialized_start=2327, + serialized_end=2397, ) _FINDCHANGEDPATHSREQUEST_REQUEST_COMMITREQUEST = _descriptor.Descriptor( @@ -844,8 +927,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2023, - serialized_end=2096, + serialized_start=2399, + serialized_end=2472, ) _FINDCHANGEDPATHSREQUEST_REQUEST = _descriptor.Descriptor( @@ -887,8 +970,8 @@ create_key=_descriptor._internal_create_key, fields=[]), ], - serialized_start=1782, - serialized_end=2104, + serialized_start=2158, + serialized_end=2480, ) _FINDCHANGEDPATHSREQUEST = _descriptor.Descriptor( @@ -932,8 +1015,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1628, - serialized_end=2104, + serialized_start=2004, + serialized_end=2480, ) @@ -964,8 +1047,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2106, - serialized_end=2169, + serialized_start=2482, + serialized_end=2545, ) @@ -1018,7 +1101,7 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2172, - serialized_end=2358, + serialized_start=2548, + serialized_end=2734, ) @@ -1023,4 +1106,83 @@ ) + +_GETPATCHIDREQUEST = _descriptor.Descriptor( + name='GetPatchIDRequest', + full_name='gitaly.GetPatchIDRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='repository', full_name='gitaly.GetPatchIDRequest.repository', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'\230\306,\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='old_revision', full_name='gitaly.GetPatchIDRequest.old_revision', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='new_revision', full_name='gitaly.GetPatchIDRequest.new_revision', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2736, + serialized_end=2845, +) + + +_GETPATCHIDRESPONSE = _descriptor.Descriptor( + name='GetPatchIDResponse', + full_name='gitaly.GetPatchIDResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='patch_id', full_name='gitaly.GetPatchIDResponse.patch_id', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=2847, + serialized_end=2885, +) + +_COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY.containing_type = _COMMITDIFFREQUEST _COMMITDIFFREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _COMMITDIFFREQUEST.fields_by_name['diff_mode'].enum_type = _COMMITDIFFREQUEST_DIFFMODE @@ -1025,3 +1187,5 @@ _COMMITDIFFREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _COMMITDIFFREQUEST.fields_by_name['diff_mode'].enum_type = _COMMITDIFFREQUEST_DIFFMODE +_COMMITDIFFREQUEST.fields_by_name['max_patch_bytes_for_file_extension'].message_type = _COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY +_COMMITDIFFREQUEST.fields_by_name['whitespace_changes'].enum_type = _COMMITDIFFREQUEST_WHITESPACECHANGES _COMMITDIFFREQUEST_DIFFMODE.containing_type = _COMMITDIFFREQUEST @@ -1027,4 +1191,5 @@ _COMMITDIFFREQUEST_DIFFMODE.containing_type = _COMMITDIFFREQUEST +_COMMITDIFFREQUEST_WHITESPACECHANGES.containing_type = _COMMITDIFFREQUEST _COMMITDELTAREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _COMMITDELTARESPONSE.fields_by_name['deltas'].message_type = _COMMITDELTA _RAWDIFFREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY @@ -1047,6 +1212,7 @@ _FINDCHANGEDPATHSRESPONSE.fields_by_name['paths'].message_type = _CHANGEDPATHS _CHANGEDPATHS.fields_by_name['status'].enum_type = _CHANGEDPATHS_STATUS _CHANGEDPATHS_STATUS.containing_type = _CHANGEDPATHS +_GETPATCHIDREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY DESCRIPTOR.message_types_by_name['CommitDiffRequest'] = _COMMITDIFFREQUEST DESCRIPTOR.message_types_by_name['CommitDiffResponse'] = _COMMITDIFFRESPONSE DESCRIPTOR.message_types_by_name['CommitDeltaRequest'] = _COMMITDELTAREQUEST @@ -1062,6 +1228,8 @@ DESCRIPTOR.message_types_by_name['FindChangedPathsRequest'] = _FINDCHANGEDPATHSREQUEST DESCRIPTOR.message_types_by_name['FindChangedPathsResponse'] = _FINDCHANGEDPATHSRESPONSE DESCRIPTOR.message_types_by_name['ChangedPaths'] = _CHANGEDPATHS +DESCRIPTOR.message_types_by_name['GetPatchIDRequest'] = _GETPATCHIDREQUEST +DESCRIPTOR.message_types_by_name['GetPatchIDResponse'] = _GETPATCHIDRESPONSE _sym_db.RegisterFileDescriptor(DESCRIPTOR) CommitDiffRequest = _reflection.GeneratedProtocolMessageType('CommitDiffRequest', (_message.Message,), { @@ -1065,8 +1233,15 @@ _sym_db.RegisterFileDescriptor(DESCRIPTOR) CommitDiffRequest = _reflection.GeneratedProtocolMessageType('CommitDiffRequest', (_message.Message,), { + + 'MaxPatchBytesForFileExtensionEntry' : _reflection.GeneratedProtocolMessageType('MaxPatchBytesForFileExtensionEntry', (_message.Message,), { + 'DESCRIPTOR' : _COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY, + '__module__' : 'diff_pb2' + # @@protoc_insertion_point(class_scope:gitaly.CommitDiffRequest.MaxPatchBytesForFileExtensionEntry) + }) + , 'DESCRIPTOR' : _COMMITDIFFREQUEST, '__module__' : 'diff_pb2' # @@protoc_insertion_point(class_scope:gitaly.CommitDiffRequest) }) _sym_db.RegisterMessage(CommitDiffRequest) @@ -1068,8 +1243,9 @@ 'DESCRIPTOR' : _COMMITDIFFREQUEST, '__module__' : 'diff_pb2' # @@protoc_insertion_point(class_scope:gitaly.CommitDiffRequest) }) _sym_db.RegisterMessage(CommitDiffRequest) +_sym_db.RegisterMessage(CommitDiffRequest.MaxPatchBytesForFileExtensionEntry) CommitDiffResponse = _reflection.GeneratedProtocolMessageType('CommitDiffResponse', (_message.Message,), { 'DESCRIPTOR' : _COMMITDIFFRESPONSE, @@ -1193,5 +1369,19 @@ }) _sym_db.RegisterMessage(ChangedPaths) +GetPatchIDRequest = _reflection.GeneratedProtocolMessageType('GetPatchIDRequest', (_message.Message,), { + 'DESCRIPTOR' : _GETPATCHIDREQUEST, + '__module__' : 'diff_pb2' + # @@protoc_insertion_point(class_scope:gitaly.GetPatchIDRequest) + }) +_sym_db.RegisterMessage(GetPatchIDRequest) + +GetPatchIDResponse = _reflection.GeneratedProtocolMessageType('GetPatchIDResponse', (_message.Message,), { + 'DESCRIPTOR' : _GETPATCHIDRESPONSE, + '__module__' : 'diff_pb2' + # @@protoc_insertion_point(class_scope:gitaly.GetPatchIDResponse) + }) +_sym_db.RegisterMessage(GetPatchIDResponse) + DESCRIPTOR._options = None @@ -1196,3 +1386,4 @@ DESCRIPTOR._options = None +_COMMITDIFFREQUEST_MAXPATCHBYTESFORFILEEXTENSIONENTRY._options = None _COMMITDIFFREQUEST.fields_by_name['repository']._options = None @@ -1198,7 +1389,8 @@ _COMMITDIFFREQUEST.fields_by_name['repository']._options = None +_COMMITDIFFREQUEST.fields_by_name['ignore_whitespace_change']._options = None _COMMITDELTAREQUEST.fields_by_name['repository']._options = None _RAWDIFFREQUEST.fields_by_name['repository']._options = None _RAWPATCHREQUEST.fields_by_name['repository']._options = None _DIFFSTATSREQUEST.fields_by_name['repository']._options = None _FINDCHANGEDPATHSREQUEST.fields_by_name['repository']._options = None _FINDCHANGEDPATHSREQUEST.fields_by_name['commits']._options = None @@ -1199,9 +1391,10 @@ _COMMITDELTAREQUEST.fields_by_name['repository']._options = None _RAWDIFFREQUEST.fields_by_name['repository']._options = None _RAWPATCHREQUEST.fields_by_name['repository']._options = None _DIFFSTATSREQUEST.fields_by_name['repository']._options = None _FINDCHANGEDPATHSREQUEST.fields_by_name['repository']._options = None _FINDCHANGEDPATHSREQUEST.fields_by_name['commits']._options = None +_GETPATCHIDREQUEST.fields_by_name['repository']._options = None _DIFFSERVICE = _descriptor.ServiceDescriptor( name='DiffService', @@ -1210,8 +1403,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=2361, - serialized_end=2851, + serialized_start=2888, + serialized_end=3455, methods=[ _descriptor.MethodDescriptor( name='CommitDiff', @@ -1273,6 +1466,16 @@ serialized_options=b'\372\227(\002\010\002', create_key=_descriptor._internal_create_key, ), + _descriptor.MethodDescriptor( + name='GetPatchID', + full_name='gitaly.DiffService.GetPatchID', + index=6, + containing_service=None, + input_type=_GETPATCHIDREQUEST, + output_type=_GETPATCHIDRESPONSE, + serialized_options=b'\372\227(\002\010\002', + create_key=_descriptor._internal_create_key, + ), ]) _sym_db.RegisterServiceDescriptor(_DIFFSERVICE) diff --git a/hgitaly/stub/diff_pb2_grpc.py b/hgitaly/stub/diff_pb2_grpc.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zdHViL2RpZmZfcGIyX2dycGMucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL2RpZmZfcGIyX2dycGMucHk= 100644 --- a/hgitaly/stub/diff_pb2_grpc.py +++ b/hgitaly/stub/diff_pb2_grpc.py @@ -46,6 +46,11 @@ request_serializer=diff__pb2.FindChangedPathsRequest.SerializeToString, response_deserializer=diff__pb2.FindChangedPathsResponse.FromString, ) + self.GetPatchID = channel.unary_unary( + '/gitaly.DiffService/GetPatchID', + request_serializer=diff__pb2.GetPatchIDRequest.SerializeToString, + response_deserializer=diff__pb2.GetPatchIDResponse.FromString, + ) class DiffServiceServicer(object): @@ -95,6 +100,16 @@ context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def GetPatchID(self, request, context): + """GetPatchID computes a patch ID for a patch. Patch IDs are a unique ID computed by hashing + a patch with some parameters like line numbers ignored. The patch ID can thus be used to compare + whether diffs make the same change. Please refer to git-patch-id(1) for further information. + If the difference between old and new change is empty then this RPC returns an error. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def add_DiffServiceServicer_to_server(servicer, server): rpc_method_handlers = { @@ -128,6 +143,11 @@ request_deserializer=diff__pb2.FindChangedPathsRequest.FromString, response_serializer=diff__pb2.FindChangedPathsResponse.SerializeToString, ), + 'GetPatchID': grpc.unary_unary_rpc_method_handler( + servicer.GetPatchID, + request_deserializer=diff__pb2.GetPatchIDRequest.FromString, + response_serializer=diff__pb2.GetPatchIDResponse.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( 'gitaly.DiffService', rpc_method_handlers) @@ -241,3 +261,20 @@ diff__pb2.FindChangedPathsResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def GetPatchID(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/gitaly.DiffService/GetPatchID', + diff__pb2.GetPatchIDRequest.SerializeToString, + diff__pb2.GetPatchIDResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/hgitaly/stub/mercurial_operations_pb2.py b/hgitaly/stub/mercurial_operations_pb2.py new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL21lcmN1cmlhbF9vcGVyYXRpb25zX3BiMi5weQ== --- /dev/null +++ b/hgitaly/stub/mercurial_operations_pb2.py @@ -0,0 +1,232 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: mercurial-operations.proto +"""Generated protocol buffer code.""" +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + +from . import lint_pb2 as lint__pb2 +from . import shared_pb2 as shared__pb2 + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='mercurial-operations.proto', + package='hgitaly', + syntax='proto3', + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\x1amercurial-operations.proto\x12\x07hgitaly\x1a\nlint.proto\x1a\x0cshared.proto\"\x94\x01\n\x14MergeAnalysisRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x17\n\x0fsource_revision\x18\x02 \x01(\x0c\x12\x17\n\x0ftarget_revision\x18\x03 \x01(\x0c\x12\x1c\n\x14skip_conflicts_check\x18\x04 \x01(\x08\"\xad\x02\n\x15MergeAnalysisResponse\x12\x17\n\x0fis_fast_forward\x18\x01 \x01(\x08\x12\x1f\n\x17has_obsolete_changesets\x18\x02 \x01(\x08\x12\x1f\n\x17has_unstable_changesets\x18\x03 \x01(\x08\x12\x15\n\rhas_conflicts\x18\x04 \x01(\x08\x12\x18\n\x10target_is_public\x18\x05 \x01(\x08\x12\x16\n\x0etarget_node_id\x18\x06 \x01(\t\x12\x15\n\rtarget_branch\x18\x07 \x01(\x0c\x12\x14\n\x0ctarget_topic\x18\x08 \x01(\x0c\x12\x16\n\x0esource_node_id\x18\t \x01(\t\x12\x15\n\rsource_branch\x18\n \x01(\x0c\x12\x14\n\x0csource_topic\x18\x0b \x01(\x0c\x32t\n\x1aMercurialOperationsService\x12V\n\rMergeAnalysis\x12\x1d.hgitaly.MergeAnalysisRequest\x1a\x1e.hgitaly.MergeAnalysisResponse\"\x06\xfa\x97(\x02\x08\x02\x62\x06proto3' + , + dependencies=[lint__pb2.DESCRIPTOR,shared__pb2.DESCRIPTOR,]) + + + + +_MERGEANALYSISREQUEST = _descriptor.Descriptor( + name='MergeAnalysisRequest', + full_name='hgitaly.MergeAnalysisRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='repository', full_name='hgitaly.MergeAnalysisRequest.repository', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'\230\306,\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='source_revision', full_name='hgitaly.MergeAnalysisRequest.source_revision', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='target_revision', full_name='hgitaly.MergeAnalysisRequest.target_revision', index=2, + number=3, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='skip_conflicts_check', full_name='hgitaly.MergeAnalysisRequest.skip_conflicts_check', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=66, + serialized_end=214, +) + + +_MERGEANALYSISRESPONSE = _descriptor.Descriptor( + name='MergeAnalysisResponse', + full_name='hgitaly.MergeAnalysisResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='is_fast_forward', full_name='hgitaly.MergeAnalysisResponse.is_fast_forward', index=0, + number=1, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='has_obsolete_changesets', full_name='hgitaly.MergeAnalysisResponse.has_obsolete_changesets', index=1, + number=2, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='has_unstable_changesets', full_name='hgitaly.MergeAnalysisResponse.has_unstable_changesets', index=2, + number=3, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='has_conflicts', full_name='hgitaly.MergeAnalysisResponse.has_conflicts', index=3, + number=4, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='target_is_public', full_name='hgitaly.MergeAnalysisResponse.target_is_public', index=4, + number=5, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='target_node_id', full_name='hgitaly.MergeAnalysisResponse.target_node_id', index=5, + number=6, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='target_branch', full_name='hgitaly.MergeAnalysisResponse.target_branch', index=6, + number=7, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='target_topic', full_name='hgitaly.MergeAnalysisResponse.target_topic', index=7, + number=8, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='source_node_id', full_name='hgitaly.MergeAnalysisResponse.source_node_id', index=8, + number=9, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='source_branch', full_name='hgitaly.MergeAnalysisResponse.source_branch', index=9, + number=10, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='source_topic', full_name='hgitaly.MergeAnalysisResponse.source_topic', index=10, + number=11, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=217, + serialized_end=518, +) + +_MERGEANALYSISREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY +DESCRIPTOR.message_types_by_name['MergeAnalysisRequest'] = _MERGEANALYSISREQUEST +DESCRIPTOR.message_types_by_name['MergeAnalysisResponse'] = _MERGEANALYSISRESPONSE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +MergeAnalysisRequest = _reflection.GeneratedProtocolMessageType('MergeAnalysisRequest', (_message.Message,), { + 'DESCRIPTOR' : _MERGEANALYSISREQUEST, + '__module__' : 'mercurial_operations_pb2' + # @@protoc_insertion_point(class_scope:hgitaly.MergeAnalysisRequest) + }) +_sym_db.RegisterMessage(MergeAnalysisRequest) + +MergeAnalysisResponse = _reflection.GeneratedProtocolMessageType('MergeAnalysisResponse', (_message.Message,), { + 'DESCRIPTOR' : _MERGEANALYSISRESPONSE, + '__module__' : 'mercurial_operations_pb2' + # @@protoc_insertion_point(class_scope:hgitaly.MergeAnalysisResponse) + }) +_sym_db.RegisterMessage(MergeAnalysisResponse) + + +_MERGEANALYSISREQUEST.fields_by_name['repository']._options = None + +_MERCURIALOPERATIONSSERVICE = _descriptor.ServiceDescriptor( + name='MercurialOperationsService', + full_name='hgitaly.MercurialOperationsService', + file=DESCRIPTOR, + index=0, + serialized_options=None, + create_key=_descriptor._internal_create_key, + serialized_start=520, + serialized_end=636, + methods=[ + _descriptor.MethodDescriptor( + name='MergeAnalysis', + full_name='hgitaly.MercurialOperationsService.MergeAnalysis', + index=0, + containing_service=None, + input_type=_MERGEANALYSISREQUEST, + output_type=_MERGEANALYSISRESPONSE, + serialized_options=b'\372\227(\002\010\002', + create_key=_descriptor._internal_create_key, + ), +]) +_sym_db.RegisterServiceDescriptor(_MERCURIALOPERATIONSSERVICE) + +DESCRIPTOR.services_by_name['MercurialOperationsService'] = _MERCURIALOPERATIONSSERVICE + +# @@protoc_insertion_point(module_scope) diff --git a/hgitaly/stub/mercurial_operations_pb2_grpc.py b/hgitaly/stub/mercurial_operations_pb2_grpc.py new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL21lcmN1cmlhbF9vcGVyYXRpb25zX3BiMl9ncnBjLnB5 --- /dev/null +++ b/hgitaly/stub/mercurial_operations_pb2_grpc.py @@ -0,0 +1,69 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +from . import mercurial_operations_pb2 as mercurial__operations__pb2 + + +class MercurialOperationsServiceStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.MergeAnalysis = channel.unary_unary( + '/hgitaly.MercurialOperationsService/MergeAnalysis', + request_serializer=mercurial__operations__pb2.MergeAnalysisRequest.SerializeToString, + response_deserializer=mercurial__operations__pb2.MergeAnalysisResponse.FromString, + ) + + +class MercurialOperationsServiceServicer(object): + """Missing associated documentation comment in .proto file.""" + + def MergeAnalysis(self, request, context): + """Provide all information for a possible merge + + Will be used in mergeability checks and last-minute checks if needed. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_MercurialOperationsServiceServicer_to_server(servicer, server): + rpc_method_handlers = { + 'MergeAnalysis': grpc.unary_unary_rpc_method_handler( + servicer.MergeAnalysis, + request_deserializer=mercurial__operations__pb2.MergeAnalysisRequest.FromString, + response_serializer=mercurial__operations__pb2.MergeAnalysisResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'hgitaly.MercurialOperationsService', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class MercurialOperationsService(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def MergeAnalysis(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/hgitaly.MercurialOperationsService/MergeAnalysis', + mercurial__operations__pb2.MergeAnalysisRequest.SerializeToString, + mercurial__operations__pb2.MergeAnalysisResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/hgitaly/stub/ref_pb2.py b/hgitaly/stub/ref_pb2.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zdHViL3JlZl9wYjIucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL3JlZl9wYjIucHk= 100644 --- a/hgitaly/stub/ref_pb2.py +++ b/hgitaly/stub/ref_pb2.py @@ -23,7 +23,7 @@ syntax='proto3', serialized_options=b'Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\tref.proto\x12\x06gitaly\x1a\x0c\x65rrors.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\nlint.proto\x1a\x0cshared.proto\"L\n\x1c\x46indDefaultBranchNameRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"-\n\x1d\x46indDefaultBranchNameResponse\x12\x0c\n\x04name\x18\x01 \x01(\x0c\"I\n\x19\x46indAllBranchNamesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"+\n\x1a\x46indAllBranchNamesResponse\x12\r\n\x05names\x18\x01 \x03(\x0c\"F\n\x16\x46indAllTagNamesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"(\n\x17\x46indAllTagNamesResponse\x12\r\n\x05names\x18\x01 \x03(\x0c\"\xf1\x01\n\x18\x46indLocalBranchesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x38\n\x07sort_by\x18\x02 \x01(\x0e\x32\'.gitaly.FindLocalBranchesRequest.SortBy\x12\x36\n\x11pagination_params\x18\x03 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\"5\n\x06SortBy\x12\x08\n\x04NAME\x10\x00\x12\x0f\n\x0bUPDATED_ASC\x10\x01\x12\x10\n\x0cUPDATED_DESC\x10\x02\"v\n\x19\x46indLocalBranchesResponse\x12\x31\n\x08\x62ranches\x18\x01 \x03(\x0b\x32\x1f.gitaly.FindLocalBranchResponse\x12&\n\x0elocal_branches\x18\x02 \x03(\x0b\x32\x0e.gitaly.Branch\"\xf0\x01\n\x17\x46indLocalBranchResponse\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x11\n\tcommit_id\x18\x02 \x01(\t\x12\x16\n\x0e\x63ommit_subject\x18\x03 \x01(\x0c\x12:\n\rcommit_author\x18\x04 \x01(\x0b\x32#.gitaly.FindLocalBranchCommitAuthor\x12=\n\x10\x63ommit_committer\x18\x05 \x01(\x0b\x32#.gitaly.FindLocalBranchCommitAuthor\x12!\n\x06\x63ommit\x18\x06 \x01(\x0b\x32\x11.gitaly.GitCommit\"v\n\x1b\x46indLocalBranchCommitAuthor\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\r\n\x05\x65mail\x18\x02 \x01(\x0c\x12(\n\x04\x64\x61te\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08timezone\x18\x04 \x01(\x0c\"t\n\x16\x46indAllBranchesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x0bmerged_only\x18\x02 \x01(\x08\x12\x17\n\x0fmerged_branches\x18\x03 \x03(\x0c\"\x8e\x01\n\x17\x46indAllBranchesResponse\x12\x38\n\x08\x62ranches\x18\x01 \x03(\x0b\x32&.gitaly.FindAllBranchesResponse.Branch\x1a\x39\n\x06\x42ranch\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12!\n\x06target\x18\x02 \x01(\x0b\x32\x11.gitaly.GitCommit\"P\n\x0e\x46indTagRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08tag_name\x18\x02 \x01(\x0c\"+\n\x0f\x46indTagResponse\x12\x18\n\x03tag\x18\x01 \x01(\x0b\x32\x0b.gitaly.Tag\"P\n\x0c\x46indTagError\x12\x37\n\rtag_not_found\x18\x01 \x01(\x0b\x32\x1e.gitaly.ReferenceNotFoundErrorH\x00\x42\x07\n\x05\x65rror\"\xd1\x02\n\x12\x46indAllTagsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x32\n\x07sort_by\x18\x02 \x01(\x0b\x32!.gitaly.FindAllTagsRequest.SortBy\x12\x36\n\x11pagination_params\x18\x03 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\x1a\xa0\x01\n\x06SortBy\x12\x32\n\x03key\x18\x01 \x01(\x0e\x32%.gitaly.FindAllTagsRequest.SortBy.Key\x12(\n\tdirection\x18\x02 \x01(\x0e\x32\x15.gitaly.SortDirection\"8\n\x03Key\x12\x0b\n\x07REFNAME\x10\x00\x12\x0f\n\x0b\x43REATORDATE\x10\x01\x12\x13\n\x0fVERSION_REFNAME\x10\x02\"0\n\x13\x46indAllTagsResponse\x12\x19\n\x04tags\x18\x01 \x03(\x0b\x32\x0b.gitaly.Tag\"M\n\x10RefExistsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03ref\x18\x02 \x01(\x0c\"\"\n\x11RefExistsResponse\x12\r\n\x05value\x18\x01 \x01(\x08\"f\n\x13\x43reateBranchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\x13\n\x0bstart_point\x18\x03 \x01(\x0c\"\xbb\x01\n\x14\x43reateBranchResponse\x12\x33\n\x06status\x18\x01 \x01(\x0e\x32#.gitaly.CreateBranchResponse.Status\x12\x1e\n\x06\x62ranch\x18\x02 \x01(\x0b\x32\x0e.gitaly.Branch\"N\n\x06Status\x12\x06\n\x02OK\x10\x00\x12\x0e\n\nERR_EXISTS\x10\x01\x12\x0f\n\x0b\x45RR_INVALID\x10\x02\x12\x1b\n\x17\x45RR_INVALID_START_POINT\x10\x03\"Q\n\x13\x44\x65leteBranchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04name\x18\x02 \x01(\x0c\"\x16\n\x14\x44\x65leteBranchResponse\"O\n\x11\x46indBranchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04name\x18\x02 \x01(\x0c\"4\n\x12\x46indBranchResponse\x12\x1e\n\x06\x62ranch\x18\x01 \x01(\x0b\x32\x0e.gitaly.Branch\"k\n\x11\x44\x65leteRefsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x1a\n\x12\x65xcept_with_prefix\x18\x02 \x03(\x0c\x12\x0c\n\x04refs\x18\x03 \x03(\x0c\"\'\n\x12\x44\x65leteRefsResponse\x12\x11\n\tgit_error\x18\x01 \x01(\t\"\x8f\x01\n\x0f\x44\x65leteRefsError\x12\x37\n\x0einvalid_format\x18\x01 \x01(\x0b\x32\x1d.gitaly.InvalidRefFormatErrorH\x00\x12:\n\x11references_locked\x18\x02 \x01(\x0b\x32\x1d.gitaly.ReferencesLockedErrorH\x00\x42\x07\n\x05\x65rror\"x\n&ListBranchNamesContainingCommitRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tcommit_id\x18\x02 \x01(\t\x12\r\n\x05limit\x18\x03 \x01(\r\"E\n\'ListBranchNamesContainingCommitResponse\x12\x14\n\x0c\x62ranch_names\x18\x02 \x03(\x0cJ\x04\x08\x01\x10\x02\"u\n#ListTagNamesContainingCommitRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tcommit_id\x18\x02 \x01(\t\x12\r\n\x05limit\x18\x03 \x01(\r\"?\n$ListTagNamesContainingCommitResponse\x12\x11\n\ttag_names\x18\x02 \x03(\x0cJ\x04\x08\x01\x10\x02\"^\n\x17GetTagSignaturesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rtag_revisions\x18\x02 \x03(\t\"\xa1\x01\n\x18GetTagSignaturesResponse\x12\x41\n\nsignatures\x18\x01 \x03(\x0b\x32-.gitaly.GetTagSignaturesResponse.TagSignature\x1a\x42\n\x0cTagSignature\x12\x0e\n\x06tag_id\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"g\n\x15GetTagMessagesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0f\n\x07tag_ids\x18\x03 \x03(\tJ\x04\x08\x02\x10\x03R\ttag_names\"I\n\x16GetTagMessagesResponse\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x0e\n\x06tag_id\x18\x03 \x01(\tJ\x04\x08\x01\x10\x02R\x08tag_name\"a\n\x1c\x46indAllRemoteBranchesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x0bremote_name\x18\x02 \x01(\t\"A\n\x1d\x46indAllRemoteBranchesResponse\x12 \n\x08\x62ranches\x18\x01 \x03(\x0b\x32\x0e.gitaly.Branch\"O\n\x0fPackRefsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01J\x04\x08\x02\x10\x03R\x08\x61ll_refs\"\x12\n\x10PackRefsResponse\"\xbe\x02\n\x0fListRefsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08patterns\x18\x02 \x03(\x0c\x12\x0c\n\x04head\x18\x03 \x01(\x08\x12/\n\x07sort_by\x18\x04 \x01(\x0b\x32\x1e.gitaly.ListRefsRequest.SortBy\x1a\xab\x01\n\x06SortBy\x12/\n\x03key\x18\x01 \x01(\x0e\x32\".gitaly.ListRefsRequest.SortBy.Key\x12(\n\tdirection\x18\x02 \x01(\x0e\x32\x15.gitaly.SortDirection\"F\n\x03Key\x12\x0b\n\x07REFNAME\x10\x00\x12\x0f\n\x0b\x43REATORDATE\x10\x01\x12\x0e\n\nAUTHORDATE\x10\x02\x12\x11\n\rCOMMITTERDATE\x10\x03\"u\n\x10ListRefsResponse\x12\x36\n\nreferences\x18\x01 \x03(\x0b\x32\".gitaly.ListRefsResponse.Reference\x1a)\n\tReference\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x0e\n\x06target\x18\x02 \x01(\t\"\x8a\x01\n\x14\x46indRefsByOIDRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03oid\x18\x02 \x01(\t\x12\x14\n\x0cref_patterns\x18\x03 \x03(\t\x12\x12\n\nsort_field\x18\x04 \x01(\t\x12\r\n\x05limit\x18\x05 \x01(\r\"%\n\x15\x46indRefsByOIDResponse\x12\x0c\n\x04refs\x18\x01 \x03(\t2\xa5\r\n\nRefService\x12l\n\x15\x46indDefaultBranchName\x12$.gitaly.FindDefaultBranchNameRequest\x1a%.gitaly.FindDefaultBranchNameResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x65\n\x12\x46indAllBranchNames\x12!.gitaly.FindAllBranchNamesRequest\x1a\".gitaly.FindAllBranchNamesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\\\n\x0f\x46indAllTagNames\x12\x1e.gitaly.FindAllTagNamesRequest\x1a\x1f.gitaly.FindAllTagNamesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x62\n\x11\x46indLocalBranches\x12 .gitaly.FindLocalBranchesRequest\x1a!.gitaly.FindLocalBranchesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\\\n\x0f\x46indAllBranches\x12\x1e.gitaly.FindAllBranchesRequest\x1a\x1f.gitaly.FindAllBranchesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12P\n\x0b\x46indAllTags\x12\x1a.gitaly.FindAllTagsRequest\x1a\x1b.gitaly.FindAllTagsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x42\n\x07\x46indTag\x12\x16.gitaly.FindTagRequest\x1a\x17.gitaly.FindTagResponse\"\x06\xfa\x97(\x02\x08\x02\x12n\n\x15\x46indAllRemoteBranches\x12$.gitaly.FindAllRemoteBranchesRequest\x1a%.gitaly.FindAllRemoteBranchesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12H\n\tRefExists\x12\x18.gitaly.RefExistsRequest\x1a\x19.gitaly.RefExistsResponse\"\x06\xfa\x97(\x02\x08\x02\x12K\n\nFindBranch\x12\x19.gitaly.FindBranchRequest\x1a\x1a.gitaly.FindBranchResponse\"\x06\xfa\x97(\x02\x08\x02\x12K\n\nDeleteRefs\x12\x19.gitaly.DeleteRefsRequest\x1a\x1a.gitaly.DeleteRefsResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x8c\x01\n\x1fListBranchNamesContainingCommit\x12..gitaly.ListBranchNamesContainingCommitRequest\x1a/.gitaly.ListBranchNamesContainingCommitResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x83\x01\n\x1cListTagNamesContainingCommit\x12+.gitaly.ListTagNamesContainingCommitRequest\x1a,.gitaly.ListTagNamesContainingCommitResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10GetTagSignatures\x12\x1f.gitaly.GetTagSignaturesRequest\x1a .gitaly.GetTagSignaturesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12Y\n\x0eGetTagMessages\x12\x1d.gitaly.GetTagMessagesRequest\x1a\x1e.gitaly.GetTagMessagesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12H\n\x08PackRefs\x12\x17.gitaly.PackRefsRequest\x1a\x18.gitaly.PackRefsResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12G\n\x08ListRefs\x12\x17.gitaly.ListRefsRequest\x1a\x18.gitaly.ListRefsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12T\n\rFindRefsByOID\x12\x1c.gitaly.FindRefsByOIDRequest\x1a\x1d.gitaly.FindRefsByOIDResponse\"\x06\xfa\x97(\x02\x08\x02\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' + serialized_pb=b'\n\tref.proto\x12\x06gitaly\x1a\x0c\x65rrors.proto\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\nlint.proto\x1a\x0cshared.proto\"L\n\x1c\x46indDefaultBranchNameRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"-\n\x1d\x46indDefaultBranchNameResponse\x12\x0c\n\x04name\x18\x01 \x01(\x0c\"I\n\x19\x46indAllBranchNamesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"+\n\x1a\x46indAllBranchNamesResponse\x12\r\n\x05names\x18\x01 \x03(\x0c\"F\n\x16\x46indAllTagNamesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"(\n\x17\x46indAllTagNamesResponse\x12\r\n\x05names\x18\x01 \x03(\x0c\"\xf1\x01\n\x18\x46indLocalBranchesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x38\n\x07sort_by\x18\x02 \x01(\x0e\x32\'.gitaly.FindLocalBranchesRequest.SortBy\x12\x36\n\x11pagination_params\x18\x03 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\"5\n\x06SortBy\x12\x08\n\x04NAME\x10\x00\x12\x0f\n\x0bUPDATED_ASC\x10\x01\x12\x10\n\x0cUPDATED_DESC\x10\x02\"v\n\x19\x46indLocalBranchesResponse\x12\x31\n\x08\x62ranches\x18\x01 \x03(\x0b\x32\x1f.gitaly.FindLocalBranchResponse\x12&\n\x0elocal_branches\x18\x02 \x03(\x0b\x32\x0e.gitaly.Branch\"\xf0\x01\n\x17\x46indLocalBranchResponse\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x11\n\tcommit_id\x18\x02 \x01(\t\x12\x16\n\x0e\x63ommit_subject\x18\x03 \x01(\x0c\x12:\n\rcommit_author\x18\x04 \x01(\x0b\x32#.gitaly.FindLocalBranchCommitAuthor\x12=\n\x10\x63ommit_committer\x18\x05 \x01(\x0b\x32#.gitaly.FindLocalBranchCommitAuthor\x12!\n\x06\x63ommit\x18\x06 \x01(\x0b\x32\x11.gitaly.GitCommit\"v\n\x1b\x46indLocalBranchCommitAuthor\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\r\n\x05\x65mail\x18\x02 \x01(\x0c\x12(\n\x04\x64\x61te\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08timezone\x18\x04 \x01(\x0c\"t\n\x16\x46indAllBranchesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x0bmerged_only\x18\x02 \x01(\x08\x12\x17\n\x0fmerged_branches\x18\x03 \x03(\x0c\"\x8e\x01\n\x17\x46indAllBranchesResponse\x12\x38\n\x08\x62ranches\x18\x01 \x03(\x0b\x32&.gitaly.FindAllBranchesResponse.Branch\x1a\x39\n\x06\x42ranch\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12!\n\x06target\x18\x02 \x01(\x0b\x32\x11.gitaly.GitCommit\"P\n\x0e\x46indTagRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08tag_name\x18\x02 \x01(\x0c\"+\n\x0f\x46indTagResponse\x12\x18\n\x03tag\x18\x01 \x01(\x0b\x32\x0b.gitaly.Tag\"P\n\x0c\x46indTagError\x12\x37\n\rtag_not_found\x18\x01 \x01(\x0b\x32\x1e.gitaly.ReferenceNotFoundErrorH\x00\x42\x07\n\x05\x65rror\"\xd1\x02\n\x12\x46indAllTagsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x32\n\x07sort_by\x18\x02 \x01(\x0b\x32!.gitaly.FindAllTagsRequest.SortBy\x12\x36\n\x11pagination_params\x18\x03 \x01(\x0b\x32\x1b.gitaly.PaginationParameter\x1a\xa0\x01\n\x06SortBy\x12\x32\n\x03key\x18\x01 \x01(\x0e\x32%.gitaly.FindAllTagsRequest.SortBy.Key\x12(\n\tdirection\x18\x02 \x01(\x0e\x32\x15.gitaly.SortDirection\"8\n\x03Key\x12\x0b\n\x07REFNAME\x10\x00\x12\x0f\n\x0b\x43REATORDATE\x10\x01\x12\x13\n\x0fVERSION_REFNAME\x10\x02\"0\n\x13\x46indAllTagsResponse\x12\x19\n\x04tags\x18\x01 \x03(\x0b\x32\x0b.gitaly.Tag\"M\n\x10RefExistsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03ref\x18\x02 \x01(\x0c\"\"\n\x11RefExistsResponse\x12\r\n\x05value\x18\x01 \x01(\x08\"f\n\x13\x43reateBranchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\x13\n\x0bstart_point\x18\x03 \x01(\x0c\"\xbb\x01\n\x14\x43reateBranchResponse\x12\x33\n\x06status\x18\x01 \x01(\x0e\x32#.gitaly.CreateBranchResponse.Status\x12\x1e\n\x06\x62ranch\x18\x02 \x01(\x0b\x32\x0e.gitaly.Branch\"N\n\x06Status\x12\x06\n\x02OK\x10\x00\x12\x0e\n\nERR_EXISTS\x10\x01\x12\x0f\n\x0b\x45RR_INVALID\x10\x02\x12\x1b\n\x17\x45RR_INVALID_START_POINT\x10\x03\"Q\n\x13\x44\x65leteBranchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04name\x18\x02 \x01(\x0c\"\x16\n\x14\x44\x65leteBranchResponse\"O\n\x11\x46indBranchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04name\x18\x02 \x01(\x0c\"4\n\x12\x46indBranchResponse\x12\x1e\n\x06\x62ranch\x18\x01 \x01(\x0b\x32\x0e.gitaly.Branch\"k\n\x11\x44\x65leteRefsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x1a\n\x12\x65xcept_with_prefix\x18\x02 \x03(\x0c\x12\x0c\n\x04refs\x18\x03 \x03(\x0c\"\'\n\x12\x44\x65leteRefsResponse\x12\x11\n\tgit_error\x18\x01 \x01(\t\"\x8f\x01\n\x0f\x44\x65leteRefsError\x12\x37\n\x0einvalid_format\x18\x01 \x01(\x0b\x32\x1d.gitaly.InvalidRefFormatErrorH\x00\x12:\n\x11references_locked\x18\x02 \x01(\x0b\x32\x1d.gitaly.ReferencesLockedErrorH\x00\x42\x07\n\x05\x65rror\"x\n&ListBranchNamesContainingCommitRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tcommit_id\x18\x02 \x01(\t\x12\r\n\x05limit\x18\x03 \x01(\r\"E\n\'ListBranchNamesContainingCommitResponse\x12\x14\n\x0c\x62ranch_names\x18\x02 \x03(\x0cJ\x04\x08\x01\x10\x02\"u\n#ListTagNamesContainingCommitRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tcommit_id\x18\x02 \x01(\t\x12\r\n\x05limit\x18\x03 \x01(\r\"?\n$ListTagNamesContainingCommitResponse\x12\x11\n\ttag_names\x18\x02 \x03(\x0cJ\x04\x08\x01\x10\x02\"^\n\x17GetTagSignaturesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rtag_revisions\x18\x02 \x03(\t\"\xa1\x01\n\x18GetTagSignaturesResponse\x12\x41\n\nsignatures\x18\x01 \x03(\x0b\x32-.gitaly.GetTagSignaturesResponse.TagSignature\x1a\x42\n\x0cTagSignature\x12\x0e\n\x06tag_id\x18\x01 \x01(\t\x12\x11\n\tsignature\x18\x02 \x01(\x0c\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\"g\n\x15GetTagMessagesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0f\n\x07tag_ids\x18\x03 \x03(\tJ\x04\x08\x02\x10\x03R\ttag_names\"I\n\x16GetTagMessagesResponse\x12\x0f\n\x07message\x18\x02 \x01(\x0c\x12\x0e\n\x06tag_id\x18\x03 \x01(\tJ\x04\x08\x01\x10\x02R\x08tag_name\"a\n\x1c\x46indAllRemoteBranchesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x13\n\x0bremote_name\x18\x02 \x01(\t\"A\n\x1d\x46indAllRemoteBranchesResponse\x12 \n\x08\x62ranches\x18\x01 \x03(\x0b\x32\x0e.gitaly.Branch\"O\n\x0fPackRefsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01J\x04\x08\x02\x10\x03R\x08\x61ll_refs\"\x12\n\x10PackRefsResponse\"\xeb\x02\n\x0fListRefsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08patterns\x18\x02 \x03(\x0c\x12\x0c\n\x04head\x18\x03 \x01(\x08\x12/\n\x07sort_by\x18\x04 \x01(\x0b\x32\x1e.gitaly.ListRefsRequest.SortBy\x12\x18\n\x10pointing_at_oids\x18\x05 \x03(\x0c\x12\x11\n\tpeel_tags\x18\x06 \x01(\x08\x1a\xab\x01\n\x06SortBy\x12/\n\x03key\x18\x01 \x01(\x0e\x32\".gitaly.ListRefsRequest.SortBy.Key\x12(\n\tdirection\x18\x02 \x01(\x0e\x32\x15.gitaly.SortDirection\"F\n\x03Key\x12\x0b\n\x07REFNAME\x10\x00\x12\x0f\n\x0b\x43REATORDATE\x10\x01\x12\x0e\n\nAUTHORDATE\x10\x02\x12\x11\n\rCOMMITTERDATE\x10\x03\"\x8c\x01\n\x10ListRefsResponse\x12\x36\n\nreferences\x18\x01 \x03(\x0b\x32\".gitaly.ListRefsResponse.Reference\x1a@\n\tReference\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\x0e\n\x06target\x18\x02 \x01(\t\x12\x15\n\rpeeled_target\x18\x03 \x01(\t\"\x8a\x01\n\x14\x46indRefsByOIDRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03oid\x18\x02 \x01(\t\x12\x14\n\x0cref_patterns\x18\x03 \x03(\t\x12\x12\n\nsort_field\x18\x04 \x01(\t\x12\r\n\x05limit\x18\x05 \x01(\r\"%\n\x15\x46indRefsByOIDResponse\x12\x0c\n\x04refs\x18\x01 \x03(\t2\xab\r\n\nRefService\x12l\n\x15\x46indDefaultBranchName\x12$.gitaly.FindDefaultBranchNameRequest\x1a%.gitaly.FindDefaultBranchNameResponse\"\x06\xfa\x97(\x02\x08\x02\x12h\n\x12\x46indAllBranchNames\x12!.gitaly.FindAllBranchNamesRequest\x1a\".gitaly.FindAllBranchNamesResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x0f\x46indAllTagNames\x12\x1e.gitaly.FindAllTagNamesRequest\x1a\x1f.gitaly.FindAllTagNamesResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x02\x30\x01\x12\x62\n\x11\x46indLocalBranches\x12 .gitaly.FindLocalBranchesRequest\x1a!.gitaly.FindLocalBranchesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\\\n\x0f\x46indAllBranches\x12\x1e.gitaly.FindAllBranchesRequest\x1a\x1f.gitaly.FindAllBranchesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12P\n\x0b\x46indAllTags\x12\x1a.gitaly.FindAllTagsRequest\x1a\x1b.gitaly.FindAllTagsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x42\n\x07\x46indTag\x12\x16.gitaly.FindTagRequest\x1a\x17.gitaly.FindTagResponse\"\x06\xfa\x97(\x02\x08\x02\x12n\n\x15\x46indAllRemoteBranches\x12$.gitaly.FindAllRemoteBranchesRequest\x1a%.gitaly.FindAllRemoteBranchesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12H\n\tRefExists\x12\x18.gitaly.RefExistsRequest\x1a\x19.gitaly.RefExistsResponse\"\x06\xfa\x97(\x02\x08\x02\x12K\n\nFindBranch\x12\x19.gitaly.FindBranchRequest\x1a\x1a.gitaly.FindBranchResponse\"\x06\xfa\x97(\x02\x08\x02\x12K\n\nDeleteRefs\x12\x19.gitaly.DeleteRefsRequest\x1a\x1a.gitaly.DeleteRefsResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x8c\x01\n\x1fListBranchNamesContainingCommit\x12..gitaly.ListBranchNamesContainingCommitRequest\x1a/.gitaly.ListBranchNamesContainingCommitResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x83\x01\n\x1cListTagNamesContainingCommit\x12+.gitaly.ListTagNamesContainingCommitRequest\x1a,.gitaly.ListTagNamesContainingCommitResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12_\n\x10GetTagSignatures\x12\x1f.gitaly.GetTagSignaturesRequest\x1a .gitaly.GetTagSignaturesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12Y\n\x0eGetTagMessages\x12\x1d.gitaly.GetTagMessagesRequest\x1a\x1e.gitaly.GetTagMessagesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12H\n\x08PackRefs\x12\x17.gitaly.PackRefsRequest\x1a\x18.gitaly.PackRefsResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12G\n\x08ListRefs\x12\x17.gitaly.ListRefsRequest\x1a\x18.gitaly.ListRefsResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12T\n\rFindRefsByOID\x12\x1c.gitaly.FindRefsByOIDRequest\x1a\x1d.gitaly.FindRefsByOIDResponse\"\x06\xfa\x97(\x02\x08\x02\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' , dependencies=[errors__pb2.DESCRIPTOR,google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,lint__pb2.DESCRIPTOR,shared__pb2.DESCRIPTOR,]) @@ -154,8 +154,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=4322, - serialized_end=4392, + serialized_start=4367, + serialized_end=4437, ) _sym_db.RegisterEnumDescriptor(_LISTREFSREQUEST_SORTBY_KEY) @@ -1826,8 +1826,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4221, - serialized_end=4392, + serialized_start=4266, + serialized_end=4437, ) _LISTREFSREQUEST = _descriptor.Descriptor( @@ -1866,6 +1866,20 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='pointing_at_oids', full_name='gitaly.ListRefsRequest.pointing_at_oids', index=4, + number=5, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='peel_tags', full_name='gitaly.ListRefsRequest.peel_tags', index=5, + number=6, type=8, cpp_type=7, label=1, + has_default_value=False, default_value=False, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -1879,7 +1893,7 @@ oneofs=[ ], serialized_start=4074, - serialized_end=4392, + serialized_end=4437, ) @@ -1905,6 +1919,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='peeled_target', full_name='gitaly.ListRefsResponse.Reference.peeled_target', index=2, + number=3, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -1917,8 +1938,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4470, - serialized_end=4511, + serialized_start=4516, + serialized_end=4580, ) _LISTREFSRESPONSE = _descriptor.Descriptor( @@ -1948,8 +1969,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4394, - serialized_end=4511, + serialized_start=4440, + serialized_end=4580, ) @@ -2008,8 +2029,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4514, - serialized_end=4652, + serialized_start=4583, + serialized_end=4721, ) @@ -2040,8 +2061,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4654, - serialized_end=4691, + serialized_start=4723, + serialized_end=4760, ) _FINDDEFAULTBRANCHNAMEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY @@ -2534,8 +2555,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=4694, - serialized_end=6395, + serialized_start=4763, + serialized_end=6470, methods=[ _descriptor.MethodDescriptor( name='FindDefaultBranchName', @@ -2554,7 +2575,7 @@ containing_service=None, input_type=_FINDALLBRANCHNAMESREQUEST, output_type=_FINDALLBRANCHNAMESRESPONSE, - serialized_options=b'\372\227(\002\010\002', + serialized_options=b'\210\002\001\372\227(\002\010\002', create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( @@ -2564,7 +2585,7 @@ containing_service=None, input_type=_FINDALLTAGNAMESREQUEST, output_type=_FINDALLTAGNAMESRESPONSE, - serialized_options=b'\372\227(\002\010\002', + serialized_options=b'\210\002\001\372\227(\002\010\002', create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( diff --git a/hgitaly/stub/ref_pb2_grpc.py b/hgitaly/stub/ref_pb2_grpc.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zdHViL3JlZl9wYjJfZ3JwYy5weQ==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL3JlZl9wYjJfZ3JwYy5weQ== 100644 --- a/hgitaly/stub/ref_pb2_grpc.py +++ b/hgitaly/stub/ref_pb2_grpc.py @@ -119,10 +119,12 @@ raise NotImplementedError('Method not implemented!') def FindAllBranchNames(self, request, context): - """This comment is left unintentionally blank. + """FindAllBranchNames is deprecated in favor of ListRefs + + https://gitlab.com/gitlab-org/gitaly/-/issues/3966 """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def FindAllTagNames(self, request, context): @@ -123,10 +125,12 @@ """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def FindAllTagNames(self, request, context): - """This comment is left unintentionally blank. + """FindAllTagNames is deprecated in favor of ListRefs + + https://gitlab.com/gitlab-org/gitaly/-/issues/3966 """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') diff --git a/hgitaly/stub/repository_pb2.py b/hgitaly/stub/repository_pb2.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zdHViL3JlcG9zaXRvcnlfcGIyLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL3JlcG9zaXRvcnlfcGIyLnB5 100644 --- a/hgitaly/stub/repository_pb2.py +++ b/hgitaly/stub/repository_pb2.py @@ -21,7 +21,7 @@ syntax='proto3', serialized_options=b'Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x10repository.proto\x12\x06gitaly\x1a\nlint.proto\x1a\x0cshared.proto\"G\n\x17RepositoryExistsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"*\n\x18RepositoryExistsResponse\x12\x0e\n\x06\x65xists\x18\x01 \x01(\x08\"H\n\x18RepackIncrementalRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x1b\n\x19RepackIncrementalResponse\"X\n\x11RepackFullRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rcreate_bitmap\x18\x02 \x01(\x08\"\x14\n\x12RepackFullResponse\"A\n\x11MidxRepackRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x14\n\x12MidxRepackResponse\"k\n\x15GarbageCollectRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rcreate_bitmap\x18\x02 \x01(\x08\x12\r\n\x05prune\x18\x03 \x01(\x08\"\x18\n\x16GarbageCollectResponse\"\xb0\x01\n\x17WriteCommitGraphRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x44\n\rsplitStrategy\x18\x02 \x01(\x0e\x32-.gitaly.WriteCommitGraphRequest.SplitStrategy\"!\n\rSplitStrategy\x12\x10\n\x0cSizeMultiple\x10\x00\"\x1a\n\x18WriteCommitGraphResponse\">\n\x0e\x43leanupRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x11\n\x0f\x43leanupResponse\"E\n\x15RepositorySizeRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"&\n\x16RepositorySizeResponse\x12\x0c\n\x04size\x18\x01 \x01(\x03\"[\n\x19\x41pplyGitattributesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\"\x1c\n\x1a\x41pplyGitattributesResponse\"e\n\x12\x46\x65tchBundleRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x13\n\x0bupdate_head\x18\x03 \x01(\x08\"\x15\n\x13\x46\x65tchBundleResponse\"\x82\x02\n\x12\x46\x65tchRemoteRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\r\n\x05\x66orce\x18\x03 \x01(\x08\x12\x0f\n\x07no_tags\x18\x04 \x01(\x08\x12\x0f\n\x07timeout\x18\x05 \x01(\x05\x12\x0f\n\x07ssh_key\x18\x06 \x01(\t\x12\x13\n\x0bknown_hosts\x18\x07 \x01(\t\x12\x10\n\x08no_prune\x18\t \x01(\x08\x12%\n\rremote_params\x18\n \x01(\x0b\x32\x0e.gitaly.Remote\x12\x1a\n\x12\x63heck_tags_changed\x18\x0b \x01(\x08J\x04\x08\x08\x10\tJ\x04\x08\x02\x10\x03R\x06remote\"+\n\x13\x46\x65tchRemoteResponse\x12\x14\n\x0ctags_changed\x18\x01 \x01(\x08\"_\n\x17\x43reateRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0e\x64\x65\x66\x61ult_branch\x18\x02 \x01(\x0c\"\x1a\n\x18\x43reateRepositoryResponse\"\x99\x02\n\x11GetArchiveRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tcommit_id\x18\x02 \x01(\t\x12\x0e\n\x06prefix\x18\x03 \x01(\t\x12\x30\n\x06\x66ormat\x18\x04 \x01(\x0e\x32 .gitaly.GetArchiveRequest.Format\x12\x0c\n\x04path\x18\x05 \x01(\x0c\x12\x0f\n\x07\x65xclude\x18\x06 \x03(\x0c\x12\x12\n\nelide_path\x18\x07 \x01(\x08\x12\x19\n\x11include_lfs_blobs\x18\x08 \x01(\x08\"3\n\x06\x46ormat\x12\x07\n\x03ZIP\x10\x00\x12\x07\n\x03TAR\x10\x01\x12\n\n\x06TAR_GZ\x10\x02\x12\x0b\n\x07TAR_BZ2\x10\x03\"\"\n\x12GetArchiveResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"G\n\x17HasLocalBranchesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\")\n\x18HasLocalBranchesResponse\x12\r\n\x05value\x18\x01 \x01(\x08\"\xa2\x01\n\x18\x46\x65tchSourceBranchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12-\n\x11source_repository\x18\x02 \x01(\x0b\x32\x12.gitaly.Repository\x12\x15\n\rsource_branch\x18\x03 \x01(\x0c\x12\x12\n\ntarget_ref\x18\x04 \x01(\x0c\"+\n\x19\x46\x65tchSourceBranchResponse\x12\x0e\n\x06result\x18\x01 \x01(\x08\";\n\x0b\x46sckRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x1d\n\x0c\x46sckResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\x0c\"\x89\x01\n\x0fWriteRefRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03ref\x18\x02 \x01(\x0c\x12\x10\n\x08revision\x18\x03 \x01(\x0c\x12\x14\n\x0cold_revision\x18\x04 \x01(\x0c\x12\r\n\x05\x66orce\x18\x05 \x01(\x08J\x04\x08\x06\x10\x07\"\x18\n\x10WriteRefResponseJ\x04\x08\x01\x10\x02\"W\n\x14\x46indMergeBaseRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\trevisions\x18\x02 \x03(\x0c\"%\n\x15\x46indMergeBaseResponse\x12\x0c\n\x04\x62\x61se\x18\x01 \x01(\t\"p\n\x11\x43reateForkRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12-\n\x11source_repository\x18\x02 \x01(\x0b\x32\x12.gitaly.Repository\"\x14\n\x12\x43reateForkResponse\"\xbf\x01\n\x1e\x43reateRepositoryFromURLRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x15\n\thttp_host\x18\x03 \x01(\tB\x02\x18\x01\x12!\n\x19http_authorization_header\x18\x04 \x01(\t\x12\x0e\n\x06mirror\x18\x05 \x01(\x08\x12\x18\n\x10resolved_address\x18\x06 \x01(\t\"!\n\x1f\x43reateRepositoryFromURLResponse\"C\n\x13\x43reateBundleRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"$\n\x14\x43reateBundleResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"`\n\x1e\x43reateBundleFromRefListRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08patterns\x18\x02 \x03(\x0c\"/\n\x1f\x43reateBundleFromRefListResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"@\n\x10GetConfigRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"!\n\x11GetConfigResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"W\n\x19RestoreCustomHooksRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"\x1c\n\x1aRestoreCustomHooksResponse\"H\n\x18\x42\x61\x63kupCustomHooksRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\")\n\x19\x42\x61\x63kupCustomHooksResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"_\n!CreateRepositoryFromBundleRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"$\n\"CreateRepositoryFromBundleResponse\"B\n\x12\x46indLicenseRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x8c\x01\n\x13\x46indLicenseResponse\x12\x1a\n\x12license_short_name\x18\x01 \x01(\t\x12\x14\n\x0clicense_name\x18\x02 \x01(\t\x12\x13\n\x0blicense_url\x18\x03 \x01(\t\x12\x14\n\x0clicense_path\x18\x04 \x01(\t\x12\x18\n\x10license_nickname\x18\x05 \x01(\t\"H\n\x18GetInfoAttributesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"/\n\x19GetInfoAttributesResponse\x12\x12\n\nattributes\x18\x01 \x01(\x0c\"H\n\x18\x43\x61lculateChecksumRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"-\n\x19\x43\x61lculateChecksumResponse\x12\x10\n\x08\x63hecksum\x18\x01 \x01(\t\"B\n\x12GetSnapshotRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"#\n\x13GetSnapshotResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\xa9\x01\n#CreateRepositoryFromSnapshotRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08http_url\x18\x02 \x01(\t\x12\x11\n\thttp_auth\x18\x03 \x01(\t\x12\x15\n\thttp_host\x18\x04 \x01(\tB\x02\x18\x01\x12\x18\n\x10resolved_address\x18\x05 \x01(\t\"&\n$CreateRepositoryFromSnapshotResponse\"p\n\x14GetRawChangesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rfrom_revision\x18\x02 \x01(\t\x12\x13\n\x0bto_revision\x18\x03 \x01(\t\"\xbe\x03\n\x15GetRawChangesResponse\x12<\n\x0braw_changes\x18\x01 \x03(\x0b\x32\'.gitaly.GetRawChangesResponse.RawChange\x1a\xe6\x02\n\tRawChange\x12\x0f\n\x07\x62lob_id\x18\x01 \x01(\t\x12\x0c\n\x04size\x18\x02 \x01(\x03\x12\x44\n\toperation\x18\x05 \x01(\x0e\x32\x31.gitaly.GetRawChangesResponse.RawChange.Operation\x12\x15\n\rraw_operation\x18\x06 \x01(\t\x12\x10\n\x08old_mode\x18\x07 \x01(\x05\x12\x10\n\x08new_mode\x18\x08 \x01(\x05\x12\x16\n\x0enew_path_bytes\x18\t \x01(\x0c\x12\x16\n\x0eold_path_bytes\x18\n \x01(\x0c\"i\n\tOperation\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x01\x12\n\n\x06\x43OPIED\x10\x02\x12\x0b\n\x07\x44\x45LETED\x10\x03\x12\x0c\n\x08MODIFIED\x10\x04\x12\x0b\n\x07RENAMED\x10\x05\x12\x10\n\x0cTYPE_CHANGED\x10\x06J\x04\x08\x03\x10\x04J\x04\x08\x04\x10\x05R\x08new_pathR\x08old_path\"\x93\x01\n\x18SearchFilesByNameRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\r\n\x05query\x18\x02 \x01(\t\x12\x0b\n\x03ref\x18\x03 \x01(\x0c\x12\x0e\n\x06\x66ilter\x18\x04 \x01(\t\x12\r\n\x05limit\x18\x05 \x01(\r\x12\x0e\n\x06offset\x18\x06 \x01(\r\"*\n\x19SearchFilesByNameResponse\x12\r\n\x05\x66iles\x18\x01 \x03(\x0c\"\x81\x01\n\x1bSearchFilesByContentRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\r\n\x05query\x18\x02 \x01(\t\x12\x0b\n\x03ref\x18\x03 \x01(\x0c\x12\x18\n\x10\x63hunked_response\x18\x04 \x01(\x08\"Y\n\x1cSearchFilesByContentResponse\x12\x0f\n\x07matches\x18\x01 \x03(\x0c\x12\x12\n\nmatch_data\x18\x02 \x01(\x0c\x12\x14\n\x0c\x65nd_of_match\x18\x03 \x01(\x08\"\x8d\x01\n\x06Remote\x12\x0b\n\x03url\x18\x01 \x01(\t\x12!\n\x19http_authorization_header\x18\x03 \x01(\t\x12\x16\n\x0emirror_refmaps\x18\x04 \x03(\t\x12\x15\n\thttp_host\x18\x05 \x01(\tB\x02\x18\x01\x12\x18\n\x10resolved_address\x18\x06 \x01(\tJ\x04\x08\x02\x10\x03R\x04name\"M\n\x1dGetObjectDirectorySizeRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\".\n\x1eGetObjectDirectorySizeResponse\x12\x0c\n\x04size\x18\x01 \x01(\x03\"G\n\x17RemoveRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x1a\n\x18RemoveRepositoryResponse\"^\n\x17RenameRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rrelative_path\x18\x02 \x01(\t\"\x1a\n\x18RenameRepositoryResponse\"n\n\x1aReplicateRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\"\n\x06source\x18\x02 \x01(\x0b\x32\x12.gitaly.Repository\"\x1d\n\x1bReplicateRepositoryResponse\"I\n\x19OptimizeRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x1c\n\x1aOptimizeRepositoryResponse\"N\n\x1ePruneUnreachableObjectsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"!\n\x1fPruneUnreachableObjectsResponse\"P\n\x12SetFullPathRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04path\x18\x02 \x01(\t\"\x15\n\x13SetFullPathResponse\"?\n\x0f\x46ullPathRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\" \n\x10\x46ullPathResponse\x12\x0c\n\x04path\x18\x01 \x01(\t2\xe3\x1e\n\x11RepositoryService\x12]\n\x10RepositoryExists\x12\x1f.gitaly.RepositoryExistsRequest\x1a .gitaly.RepositoryExistsResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x63\n\x11RepackIncremental\x12 .gitaly.RepackIncrementalRequest\x1a!.gitaly.RepackIncrementalResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12N\n\nRepackFull\x12\x19.gitaly.RepackFullRequest\x1a\x1a.gitaly.RepackFullResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12N\n\nMidxRepack\x12\x19.gitaly.MidxRepackRequest\x1a\x1a.gitaly.MidxRepackResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12Z\n\x0eGarbageCollect\x12\x1d.gitaly.GarbageCollectRequest\x1a\x1e.gitaly.GarbageCollectResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12`\n\x10WriteCommitGraph\x12\x1f.gitaly.WriteCommitGraphRequest\x1a .gitaly.WriteCommitGraphResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12W\n\x0eRepositorySize\x12\x1d.gitaly.RepositorySizeRequest\x1a\x1e.gitaly.RepositorySizeResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x63\n\x12\x41pplyGitattributes\x12!.gitaly.ApplyGitattributesRequest\x1a\".gitaly.ApplyGitattributesResponse\"\x06\xfa\x97(\x02\x08\x01\x12N\n\x0b\x46\x65tchRemote\x12\x1a.gitaly.FetchRemoteRequest\x1a\x1b.gitaly.FetchRemoteResponse\"\x06\xfa\x97(\x02\x08\x01\x12]\n\x10\x43reateRepository\x12\x1f.gitaly.CreateRepositoryRequest\x1a .gitaly.CreateRepositoryResponse\"\x06\xfa\x97(\x02\x08\x01\x12M\n\nGetArchive\x12\x19.gitaly.GetArchiveRequest\x1a\x1a.gitaly.GetArchiveResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12]\n\x10HasLocalBranches\x12\x1f.gitaly.HasLocalBranchesRequest\x1a .gitaly.HasLocalBranchesResponse\"\x06\xfa\x97(\x02\x08\x02\x12`\n\x11\x46\x65tchSourceBranch\x12 .gitaly.FetchSourceBranchRequest\x1a!.gitaly.FetchSourceBranchResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x39\n\x04\x46sck\x12\x13.gitaly.FsckRequest\x1a\x14.gitaly.FsckResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x45\n\x08WriteRef\x12\x17.gitaly.WriteRefRequest\x1a\x18.gitaly.WriteRefResponse\"\x06\xfa\x97(\x02\x08\x01\x12T\n\rFindMergeBase\x12\x1c.gitaly.FindMergeBaseRequest\x1a\x1d.gitaly.FindMergeBaseResponse\"\x06\xfa\x97(\x02\x08\x02\x12K\n\nCreateFork\x12\x19.gitaly.CreateForkRequest\x1a\x1a.gitaly.CreateForkResponse\"\x06\xfa\x97(\x02\x08\x01\x12r\n\x17\x43reateRepositoryFromURL\x12&.gitaly.CreateRepositoryFromURLRequest\x1a\'.gitaly.CreateRepositoryFromURLResponse\"\x06\xfa\x97(\x02\x08\x01\x12S\n\x0c\x43reateBundle\x12\x1b.gitaly.CreateBundleRequest\x1a\x1c.gitaly.CreateBundleResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12v\n\x17\x43reateBundleFromRefList\x12&.gitaly.CreateBundleFromRefListRequest\x1a\'.gitaly.CreateBundleFromRefListResponse\"\x06\xfa\x97(\x02\x08\x02(\x01\x30\x01\x12P\n\x0b\x46\x65tchBundle\x12\x1a.gitaly.FetchBundleRequest\x1a\x1b.gitaly.FetchBundleResponse\"\x06\xfa\x97(\x02\x08\x01(\x01\x12}\n\x1a\x43reateRepositoryFromBundle\x12).gitaly.CreateRepositoryFromBundleRequest\x1a*.gitaly.CreateRepositoryFromBundleResponse\"\x06\xfa\x97(\x02\x08\x01(\x01\x12J\n\tGetConfig\x12\x18.gitaly.GetConfigRequest\x1a\x19.gitaly.GetConfigResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12N\n\x0b\x46indLicense\x12\x1a.gitaly.FindLicenseRequest\x1a\x1b.gitaly.FindLicenseResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x62\n\x11GetInfoAttributes\x12 .gitaly.GetInfoAttributesRequest\x1a!.gitaly.GetInfoAttributesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12`\n\x11\x43\x61lculateChecksum\x12 .gitaly.CalculateChecksumRequest\x1a!.gitaly.CalculateChecksumResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x45\n\x07\x43leanup\x12\x16.gitaly.CleanupRequest\x1a\x17.gitaly.CleanupResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12P\n\x0bGetSnapshot\x12\x1a.gitaly.GetSnapshotRequest\x1a\x1b.gitaly.GetSnapshotResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x81\x01\n\x1c\x43reateRepositoryFromSnapshot\x12+.gitaly.CreateRepositoryFromSnapshotRequest\x1a,.gitaly.CreateRepositoryFromSnapshotResponse\"\x06\xfa\x97(\x02\x08\x01\x12V\n\rGetRawChanges\x12\x1c.gitaly.GetRawChangesRequest\x1a\x1d.gitaly.GetRawChangesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12k\n\x14SearchFilesByContent\x12#.gitaly.SearchFilesByContentRequest\x1a$.gitaly.SearchFilesByContentResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x62\n\x11SearchFilesByName\x12 .gitaly.SearchFilesByNameRequest\x1a!.gitaly.SearchFilesByNameResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x65\n\x12RestoreCustomHooks\x12!.gitaly.RestoreCustomHooksRequest\x1a\".gitaly.RestoreCustomHooksResponse\"\x06\xfa\x97(\x02\x08\x01(\x01\x12\x62\n\x11\x42\x61\x63kupCustomHooks\x12 .gitaly.BackupCustomHooksRequest\x1a!.gitaly.BackupCustomHooksResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12o\n\x16GetObjectDirectorySize\x12%.gitaly.GetObjectDirectorySizeRequest\x1a&.gitaly.GetObjectDirectorySizeResponse\"\x06\xfa\x97(\x02\x08\x02\x12]\n\x10RemoveRepository\x12\x1f.gitaly.RemoveRepositoryRequest\x1a .gitaly.RemoveRepositoryResponse\"\x06\xfa\x97(\x02\x08\x01\x12]\n\x10RenameRepository\x12\x1f.gitaly.RenameRepositoryRequest\x1a .gitaly.RenameRepositoryResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x66\n\x13ReplicateRepository\x12\".gitaly.ReplicateRepositoryRequest\x1a#.gitaly.ReplicateRepositoryResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x63\n\x12OptimizeRepository\x12!.gitaly.OptimizeRepositoryRequest\x1a\".gitaly.OptimizeRepositoryResponse\"\x06\xfa\x97(\x02\x08\x03\x12r\n\x17PruneUnreachableObjects\x12&.gitaly.PruneUnreachableObjectsRequest\x1a\'.gitaly.PruneUnreachableObjectsResponse\"\x06\xfa\x97(\x02\x08\x03\x12N\n\x0bSetFullPath\x12\x1a.gitaly.SetFullPathRequest\x1a\x1b.gitaly.SetFullPathResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x45\n\x08\x46ullPath\x12\x17.gitaly.FullPathRequest\x1a\x18.gitaly.FullPathResponse\"\x06\xfa\x97(\x02\x08\x02\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' + serialized_pb=b'\n\x10repository.proto\x12\x06gitaly\x1a\nlint.proto\x1a\x0cshared.proto\"G\n\x17RepositoryExistsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"*\n\x18RepositoryExistsResponse\x12\x0e\n\x06\x65xists\x18\x01 \x01(\x08\"H\n\x18RepackIncrementalRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x1b\n\x19RepackIncrementalResponse\"X\n\x11RepackFullRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rcreate_bitmap\x18\x02 \x01(\x08\"\x14\n\x12RepackFullResponse\"A\n\x11MidxRepackRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x14\n\x12MidxRepackResponse\"k\n\x15GarbageCollectRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rcreate_bitmap\x18\x02 \x01(\x08\x12\r\n\x05prune\x18\x03 \x01(\x08\"\x18\n\x16GarbageCollectResponse\"\xb0\x01\n\x17WriteCommitGraphRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x44\n\rsplitStrategy\x18\x02 \x01(\x0e\x32-.gitaly.WriteCommitGraphRequest.SplitStrategy\"!\n\rSplitStrategy\x12\x10\n\x0cSizeMultiple\x10\x00\"\x1a\n\x18WriteCommitGraphResponse\">\n\x0e\x43leanupRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x11\n\x0f\x43leanupResponse\"E\n\x15RepositorySizeRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"&\n\x16RepositorySizeResponse\x12\x0c\n\x04size\x18\x01 \x01(\x03\"C\n\x13ObjectFormatRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"<\n\x14ObjectFormatResponse\x12$\n\x06\x66ormat\x18\x01 \x01(\x0e\x32\x14.gitaly.ObjectFormat\"[\n\x19\x41pplyGitattributesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08revision\x18\x02 \x01(\x0c\"\x1c\n\x1a\x41pplyGitattributesResponse\"e\n\x12\x46\x65tchBundleRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x13\n\x0bupdate_head\x18\x03 \x01(\x08\"\x15\n\x13\x46\x65tchBundleResponse\"\x82\x02\n\x12\x46\x65tchRemoteRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\r\n\x05\x66orce\x18\x03 \x01(\x08\x12\x0f\n\x07no_tags\x18\x04 \x01(\x08\x12\x0f\n\x07timeout\x18\x05 \x01(\x05\x12\x0f\n\x07ssh_key\x18\x06 \x01(\t\x12\x13\n\x0bknown_hosts\x18\x07 \x01(\t\x12\x10\n\x08no_prune\x18\t \x01(\x08\x12%\n\rremote_params\x18\n \x01(\x0b\x32\x0e.gitaly.Remote\x12\x1a\n\x12\x63heck_tags_changed\x18\x0b \x01(\x08J\x04\x08\x08\x10\tJ\x04\x08\x02\x10\x03R\x06remote\"+\n\x13\x46\x65tchRemoteResponse\x12\x14\n\x0ctags_changed\x18\x01 \x01(\x08\"\x8c\x01\n\x17\x43reateRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0e\x64\x65\x66\x61ult_branch\x18\x02 \x01(\x0c\x12+\n\robject_format\x18\x03 \x01(\x0e\x32\x14.gitaly.ObjectFormat\"\x1a\n\x18\x43reateRepositoryResponse\"\x99\x02\n\x11GetArchiveRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\tcommit_id\x18\x02 \x01(\t\x12\x0e\n\x06prefix\x18\x03 \x01(\t\x12\x30\n\x06\x66ormat\x18\x04 \x01(\x0e\x32 .gitaly.GetArchiveRequest.Format\x12\x0c\n\x04path\x18\x05 \x01(\x0c\x12\x0f\n\x07\x65xclude\x18\x06 \x03(\x0c\x12\x12\n\nelide_path\x18\x07 \x01(\x08\x12\x19\n\x11include_lfs_blobs\x18\x08 \x01(\x08\"3\n\x06\x46ormat\x12\x07\n\x03ZIP\x10\x00\x12\x07\n\x03TAR\x10\x01\x12\n\n\x06TAR_GZ\x10\x02\x12\x0b\n\x07TAR_BZ2\x10\x03\"\"\n\x12GetArchiveResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"G\n\x17HasLocalBranchesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\")\n\x18HasLocalBranchesResponse\x12\r\n\x05value\x18\x01 \x01(\x08\"\xa2\x01\n\x18\x46\x65tchSourceBranchRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12-\n\x11source_repository\x18\x02 \x01(\x0b\x32\x12.gitaly.Repository\x12\x15\n\rsource_branch\x18\x03 \x01(\x0c\x12\x12\n\ntarget_ref\x18\x04 \x01(\x0c\"+\n\x19\x46\x65tchSourceBranchResponse\x12\x0e\n\x06result\x18\x01 \x01(\x08\";\n\x0b\x46sckRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x1d\n\x0c\x46sckResponse\x12\r\n\x05\x65rror\x18\x01 \x01(\x0c\"\x89\x01\n\x0fWriteRefRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03ref\x18\x02 \x01(\x0c\x12\x10\n\x08revision\x18\x03 \x01(\x0c\x12\x14\n\x0cold_revision\x18\x04 \x01(\x0c\x12\r\n\x05\x66orce\x18\x05 \x01(\x08J\x04\x08\x06\x10\x07\"\x18\n\x10WriteRefResponseJ\x04\x08\x01\x10\x02\"W\n\x14\x46indMergeBaseRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x11\n\trevisions\x18\x02 \x03(\x0c\"%\n\x15\x46indMergeBaseResponse\x12\x0c\n\x04\x62\x61se\x18\x01 \x01(\t\"p\n\x11\x43reateForkRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12-\n\x11source_repository\x18\x02 \x01(\x0b\x32\x12.gitaly.Repository\"\x14\n\x12\x43reateForkResponse\"\xbf\x01\n\x1e\x43reateRepositoryFromURLRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0b\n\x03url\x18\x02 \x01(\t\x12\x15\n\thttp_host\x18\x03 \x01(\tB\x02\x18\x01\x12!\n\x19http_authorization_header\x18\x04 \x01(\t\x12\x0e\n\x06mirror\x18\x05 \x01(\x08\x12\x18\n\x10resolved_address\x18\x06 \x01(\t\"!\n\x1f\x43reateRepositoryFromURLResponse\"C\n\x13\x43reateBundleRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"$\n\x14\x43reateBundleResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"`\n\x1e\x43reateBundleFromRefListRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08patterns\x18\x02 \x03(\x0c\"/\n\x1f\x43reateBundleFromRefListResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"@\n\x10GetConfigRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"!\n\x11GetConfigResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"W\n\x19RestoreCustomHooksRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"S\n\x15SetCustomHooksRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"\x1c\n\x1aRestoreCustomHooksResponse\"\x18\n\x16SetCustomHooksResponse\"H\n\x18\x42\x61\x63kupCustomHooksRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"E\n\x15GetCustomHooksRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\")\n\x19\x42\x61\x63kupCustomHooksResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"&\n\x16GetCustomHooksResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"_\n!CreateRepositoryFromBundleRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\"$\n\"CreateRepositoryFromBundleResponse\"B\n\x12\x46indLicenseRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x8c\x01\n\x13\x46indLicenseResponse\x12\x1a\n\x12license_short_name\x18\x01 \x01(\t\x12\x14\n\x0clicense_name\x18\x02 \x01(\t\x12\x13\n\x0blicense_url\x18\x03 \x01(\t\x12\x14\n\x0clicense_path\x18\x04 \x01(\t\x12\x18\n\x10license_nickname\x18\x05 \x01(\t\"H\n\x18GetInfoAttributesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"/\n\x19GetInfoAttributesResponse\x12\x12\n\nattributes\x18\x01 \x01(\x0c\"H\n\x18\x43\x61lculateChecksumRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"-\n\x19\x43\x61lculateChecksumResponse\x12\x10\n\x08\x63hecksum\x18\x01 \x01(\t\"B\n\x12GetSnapshotRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"#\n\x13GetSnapshotResponse\x12\x0c\n\x04\x64\x61ta\x18\x01 \x01(\x0c\"\xa9\x01\n#CreateRepositoryFromSnapshotRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x10\n\x08http_url\x18\x02 \x01(\t\x12\x11\n\thttp_auth\x18\x03 \x01(\t\x12\x15\n\thttp_host\x18\x04 \x01(\tB\x02\x18\x01\x12\x18\n\x10resolved_address\x18\x05 \x01(\t\"&\n$CreateRepositoryFromSnapshotResponse\"p\n\x14GetRawChangesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rfrom_revision\x18\x02 \x01(\t\x12\x13\n\x0bto_revision\x18\x03 \x01(\t\"\xbe\x03\n\x15GetRawChangesResponse\x12<\n\x0braw_changes\x18\x01 \x03(\x0b\x32\'.gitaly.GetRawChangesResponse.RawChange\x1a\xe6\x02\n\tRawChange\x12\x0f\n\x07\x62lob_id\x18\x01 \x01(\t\x12\x0c\n\x04size\x18\x02 \x01(\x03\x12\x44\n\toperation\x18\x05 \x01(\x0e\x32\x31.gitaly.GetRawChangesResponse.RawChange.Operation\x12\x15\n\rraw_operation\x18\x06 \x01(\t\x12\x10\n\x08old_mode\x18\x07 \x01(\x05\x12\x10\n\x08new_mode\x18\x08 \x01(\x05\x12\x16\n\x0enew_path_bytes\x18\t \x01(\x0c\x12\x16\n\x0eold_path_bytes\x18\n \x01(\x0c\"i\n\tOperation\x12\x0b\n\x07UNKNOWN\x10\x00\x12\t\n\x05\x41\x44\x44\x45\x44\x10\x01\x12\n\n\x06\x43OPIED\x10\x02\x12\x0b\n\x07\x44\x45LETED\x10\x03\x12\x0c\n\x08MODIFIED\x10\x04\x12\x0b\n\x07RENAMED\x10\x05\x12\x10\n\x0cTYPE_CHANGED\x10\x06J\x04\x08\x03\x10\x04J\x04\x08\x04\x10\x05R\x08new_pathR\x08old_path\"\x93\x01\n\x18SearchFilesByNameRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\r\n\x05query\x18\x02 \x01(\t\x12\x0b\n\x03ref\x18\x03 \x01(\x0c\x12\x0e\n\x06\x66ilter\x18\x04 \x01(\t\x12\r\n\x05limit\x18\x05 \x01(\r\x12\x0e\n\x06offset\x18\x06 \x01(\r\"*\n\x19SearchFilesByNameResponse\x12\r\n\x05\x66iles\x18\x01 \x03(\x0c\"\x81\x01\n\x1bSearchFilesByContentRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\r\n\x05query\x18\x02 \x01(\t\x12\x0b\n\x03ref\x18\x03 \x01(\x0c\x12\x18\n\x10\x63hunked_response\x18\x04 \x01(\x08\"Y\n\x1cSearchFilesByContentResponse\x12\x0f\n\x07matches\x18\x01 \x03(\x0c\x12\x12\n\nmatch_data\x18\x02 \x01(\x0c\x12\x14\n\x0c\x65nd_of_match\x18\x03 \x01(\x08\"\x8d\x01\n\x06Remote\x12\x0b\n\x03url\x18\x01 \x01(\t\x12!\n\x19http_authorization_header\x18\x03 \x01(\t\x12\x16\n\x0emirror_refmaps\x18\x04 \x03(\t\x12\x15\n\thttp_host\x18\x05 \x01(\tB\x02\x18\x01\x12\x18\n\x10resolved_address\x18\x06 \x01(\tJ\x04\x08\x02\x10\x03R\x04name\"M\n\x1dGetObjectDirectorySizeRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\".\n\x1eGetObjectDirectorySizeResponse\x12\x0c\n\x04size\x18\x01 \x01(\x03\"G\n\x17RemoveRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x1a\n\x18RemoveRepositoryResponse\"^\n\x17RenameRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x15\n\rrelative_path\x18\x02 \x01(\t\"\x1a\n\x18RenameRepositoryResponse\"n\n\x1aReplicateRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\"\n\x06source\x18\x02 \x01(\x0b\x32\x12.gitaly.Repository\"\x1d\n\x1bReplicateRepositoryResponse\"\xdb\x01\n\x19OptimizeRepositoryRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12<\n\x08strategy\x18\x02 \x01(\x0e\x32*.gitaly.OptimizeRepositoryRequest.Strategy\"R\n\x08Strategy\x12\x18\n\x14STRATEGY_UNSPECIFIED\x10\x00\x12\x18\n\x14STRATEGY_HEURISTICAL\x10\x01\x12\x12\n\x0eSTRATEGY_EAGER\x10\x02\"\x1c\n\x1aOptimizeRepositoryResponse\"N\n\x1ePruneUnreachableObjectsRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"!\n\x1fPruneUnreachableObjectsResponse\"P\n\x12SetFullPathRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04path\x18\x02 \x01(\t\"\x15\n\x13SetFullPathResponse\"?\n\x0f\x46ullPathRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\" \n\x10\x46ullPathResponse\x12\x0c\n\x04path\x18\x01 \x01(\t\"(\n\x10RemoveAllRequest\x12\x14\n\x0cstorage_name\x18\x01 \x01(\t\"\x13\n\x11RemoveAllResponse2\xc0!\n\x11RepositoryService\x12]\n\x10RepositoryExists\x12\x1f.gitaly.RepositoryExistsRequest\x1a .gitaly.RepositoryExistsResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x63\n\x11RepackIncremental\x12 .gitaly.RepackIncrementalRequest\x1a!.gitaly.RepackIncrementalResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12N\n\nRepackFull\x12\x19.gitaly.RepackFullRequest\x1a\x1a.gitaly.RepackFullResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12N\n\nMidxRepack\x12\x19.gitaly.MidxRepackRequest\x1a\x1a.gitaly.MidxRepackResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12Z\n\x0eGarbageCollect\x12\x1d.gitaly.GarbageCollectRequest\x1a\x1e.gitaly.GarbageCollectResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12`\n\x10WriteCommitGraph\x12\x1f.gitaly.WriteCommitGraphRequest\x1a .gitaly.WriteCommitGraphResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12W\n\x0eRepositorySize\x12\x1d.gitaly.RepositorySizeRequest\x1a\x1e.gitaly.RepositorySizeResponse\"\x06\xfa\x97(\x02\x08\x02\x12Q\n\x0cObjectFormat\x12\x1b.gitaly.ObjectFormatRequest\x1a\x1c.gitaly.ObjectFormatResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x63\n\x12\x41pplyGitattributes\x12!.gitaly.ApplyGitattributesRequest\x1a\".gitaly.ApplyGitattributesResponse\"\x06\xfa\x97(\x02\x08\x01\x12N\n\x0b\x46\x65tchRemote\x12\x1a.gitaly.FetchRemoteRequest\x1a\x1b.gitaly.FetchRemoteResponse\"\x06\xfa\x97(\x02\x08\x01\x12]\n\x10\x43reateRepository\x12\x1f.gitaly.CreateRepositoryRequest\x1a .gitaly.CreateRepositoryResponse\"\x06\xfa\x97(\x02\x08\x01\x12M\n\nGetArchive\x12\x19.gitaly.GetArchiveRequest\x1a\x1a.gitaly.GetArchiveResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12]\n\x10HasLocalBranches\x12\x1f.gitaly.HasLocalBranchesRequest\x1a .gitaly.HasLocalBranchesResponse\"\x06\xfa\x97(\x02\x08\x02\x12`\n\x11\x46\x65tchSourceBranch\x12 .gitaly.FetchSourceBranchRequest\x1a!.gitaly.FetchSourceBranchResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x39\n\x04\x46sck\x12\x13.gitaly.FsckRequest\x1a\x14.gitaly.FsckResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x45\n\x08WriteRef\x12\x17.gitaly.WriteRefRequest\x1a\x18.gitaly.WriteRefResponse\"\x06\xfa\x97(\x02\x08\x01\x12T\n\rFindMergeBase\x12\x1c.gitaly.FindMergeBaseRequest\x1a\x1d.gitaly.FindMergeBaseResponse\"\x06\xfa\x97(\x02\x08\x02\x12K\n\nCreateFork\x12\x19.gitaly.CreateForkRequest\x1a\x1a.gitaly.CreateForkResponse\"\x06\xfa\x97(\x02\x08\x01\x12r\n\x17\x43reateRepositoryFromURL\x12&.gitaly.CreateRepositoryFromURLRequest\x1a\'.gitaly.CreateRepositoryFromURLResponse\"\x06\xfa\x97(\x02\x08\x01\x12S\n\x0c\x43reateBundle\x12\x1b.gitaly.CreateBundleRequest\x1a\x1c.gitaly.CreateBundleResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12v\n\x17\x43reateBundleFromRefList\x12&.gitaly.CreateBundleFromRefListRequest\x1a\'.gitaly.CreateBundleFromRefListResponse\"\x06\xfa\x97(\x02\x08\x02(\x01\x30\x01\x12P\n\x0b\x46\x65tchBundle\x12\x1a.gitaly.FetchBundleRequest\x1a\x1b.gitaly.FetchBundleResponse\"\x06\xfa\x97(\x02\x08\x01(\x01\x12}\n\x1a\x43reateRepositoryFromBundle\x12).gitaly.CreateRepositoryFromBundleRequest\x1a*.gitaly.CreateRepositoryFromBundleResponse\"\x06\xfa\x97(\x02\x08\x01(\x01\x12J\n\tGetConfig\x12\x18.gitaly.GetConfigRequest\x1a\x19.gitaly.GetConfigResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12N\n\x0b\x46indLicense\x12\x1a.gitaly.FindLicenseRequest\x1a\x1b.gitaly.FindLicenseResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x62\n\x11GetInfoAttributes\x12 .gitaly.GetInfoAttributesRequest\x1a!.gitaly.GetInfoAttributesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12`\n\x11\x43\x61lculateChecksum\x12 .gitaly.CalculateChecksumRequest\x1a!.gitaly.CalculateChecksumResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x45\n\x07\x43leanup\x12\x16.gitaly.CleanupRequest\x1a\x17.gitaly.CleanupResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x03\x12P\n\x0bGetSnapshot\x12\x1a.gitaly.GetSnapshotRequest\x1a\x1b.gitaly.GetSnapshotResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x81\x01\n\x1c\x43reateRepositoryFromSnapshot\x12+.gitaly.CreateRepositoryFromSnapshotRequest\x1a,.gitaly.CreateRepositoryFromSnapshotResponse\"\x06\xfa\x97(\x02\x08\x01\x12V\n\rGetRawChanges\x12\x1c.gitaly.GetRawChangesRequest\x1a\x1d.gitaly.GetRawChangesResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12k\n\x14SearchFilesByContent\x12#.gitaly.SearchFilesByContentRequest\x1a$.gitaly.SearchFilesByContentResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12\x62\n\x11SearchFilesByName\x12 .gitaly.SearchFilesByNameRequest\x1a!.gitaly.SearchFilesByNameResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12h\n\x12RestoreCustomHooks\x12!.gitaly.RestoreCustomHooksRequest\x1a\".gitaly.RestoreCustomHooksResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x01(\x01\x12Y\n\x0eSetCustomHooks\x12\x1d.gitaly.SetCustomHooksRequest\x1a\x1e.gitaly.SetCustomHooksResponse\"\x06\xfa\x97(\x02\x08\x01(\x01\x12\x65\n\x11\x42\x61\x63kupCustomHooks\x12 .gitaly.BackupCustomHooksRequest\x1a!.gitaly.BackupCustomHooksResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x02\x30\x01\x12Y\n\x0eGetCustomHooks\x12\x1d.gitaly.GetCustomHooksRequest\x1a\x1e.gitaly.GetCustomHooksResponse\"\x06\xfa\x97(\x02\x08\x02\x30\x01\x12o\n\x16GetObjectDirectorySize\x12%.gitaly.GetObjectDirectorySizeRequest\x1a&.gitaly.GetObjectDirectorySizeResponse\"\x06\xfa\x97(\x02\x08\x02\x12]\n\x10RemoveRepository\x12\x1f.gitaly.RemoveRepositoryRequest\x1a .gitaly.RemoveRepositoryResponse\"\x06\xfa\x97(\x02\x08\x01\x12]\n\x10RenameRepository\x12\x1f.gitaly.RenameRepositoryRequest\x1a .gitaly.RenameRepositoryResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x66\n\x13ReplicateRepository\x12\".gitaly.ReplicateRepositoryRequest\x1a#.gitaly.ReplicateRepositoryResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x63\n\x12OptimizeRepository\x12!.gitaly.OptimizeRepositoryRequest\x1a\".gitaly.OptimizeRepositoryResponse\"\x06\xfa\x97(\x02\x08\x03\x12r\n\x17PruneUnreachableObjects\x12&.gitaly.PruneUnreachableObjectsRequest\x1a\'.gitaly.PruneUnreachableObjectsResponse\"\x06\xfa\x97(\x02\x08\x03\x12Q\n\x0bSetFullPath\x12\x1a.gitaly.SetFullPathRequest\x1a\x1b.gitaly.SetFullPathResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x01\x12H\n\x08\x46ullPath\x12\x17.gitaly.FullPathRequest\x1a\x18.gitaly.FullPathResponse\"\t\x88\x02\x01\xfa\x97(\x02\x08\x02\x12\x46\n\tRemoveAll\x12\x18.gitaly.RemoveAllRequest\x1a\x19.gitaly.RemoveAllResponse\"\x04\x80\x98(\x01\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' , dependencies=[lint__pb2.DESCRIPTOR,shared__pb2.DESCRIPTOR,]) @@ -77,8 +77,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=1922, - serialized_end=1973, + serialized_start=2099, + serialized_end=2150, ) _sym_db.RegisterEnumDescriptor(_GETARCHIVEREQUEST_FORMAT) @@ -127,8 +127,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=5010, - serialized_end=5115, + serialized_start=5409, + serialized_end=5514, ) _sym_db.RegisterEnumDescriptor(_GETRAWCHANGESRESPONSE_RAWCHANGE_OPERATION) @@ -132,6 +132,36 @@ ) _sym_db.RegisterEnumDescriptor(_GETRAWCHANGESRESPONSE_RAWCHANGE_OPERATION) +_OPTIMIZEREPOSITORYREQUEST_STRATEGY = _descriptor.EnumDescriptor( + name='Strategy', + full_name='gitaly.OptimizeRepositoryRequest.Strategy', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='STRATEGY_UNSPECIFIED', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='STRATEGY_HEURISTICAL', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='STRATEGY_EAGER', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=6742, + serialized_end=6824, +) +_sym_db.RegisterEnumDescriptor(_OPTIMIZEREPOSITORYREQUEST_STRATEGY) + _REPOSITORYEXISTSREQUEST = _descriptor.Descriptor( name='RepositoryExistsRequest', @@ -632,6 +662,70 @@ ) +_OBJECTFORMATREQUEST = _descriptor.Descriptor( + name='ObjectFormatRequest', + full_name='gitaly.ObjectFormatRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='repository', full_name='gitaly.ObjectFormatRequest.repository', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'\230\306,\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1011, + serialized_end=1078, +) + + +_OBJECTFORMATRESPONSE = _descriptor.Descriptor( + name='ObjectFormatResponse', + full_name='gitaly.ObjectFormatResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='format', full_name='gitaly.ObjectFormatResponse.format', index=0, + number=1, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=1080, + serialized_end=1140, +) + + _APPLYGITATTRIBUTESREQUEST = _descriptor.Descriptor( name='ApplyGitattributesRequest', full_name='gitaly.ApplyGitattributesRequest', @@ -666,8 +760,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1011, - serialized_end=1102, + serialized_start=1142, + serialized_end=1233, ) @@ -691,8 +785,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1104, - serialized_end=1132, + serialized_start=1235, + serialized_end=1263, ) @@ -737,8 +831,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1134, - serialized_end=1235, + serialized_start=1265, + serialized_end=1366, ) @@ -762,8 +856,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1237, - serialized_end=1258, + serialized_start=1368, + serialized_end=1389, ) @@ -850,8 +944,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1261, - serialized_end=1519, + serialized_start=1392, + serialized_end=1650, ) @@ -882,8 +976,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1521, - serialized_end=1564, + serialized_start=1652, + serialized_end=1695, ) @@ -909,6 +1003,13 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='object_format', full_name='gitaly.CreateRepositoryRequest.object_format', index=2, + number=3, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -921,8 +1022,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1566, - serialized_end=1661, + serialized_start=1698, + serialized_end=1838, ) @@ -946,8 +1047,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1663, - serialized_end=1689, + serialized_start=1840, + serialized_end=1866, ) @@ -1028,8 +1129,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1692, - serialized_end=1973, + serialized_start=1869, + serialized_end=2150, ) @@ -1060,8 +1161,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1975, - serialized_end=2009, + serialized_start=2152, + serialized_end=2186, ) @@ -1092,8 +1193,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2011, - serialized_end=2082, + serialized_start=2188, + serialized_end=2259, ) @@ -1124,8 +1225,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2084, - serialized_end=2125, + serialized_start=2261, + serialized_end=2302, ) @@ -1177,8 +1278,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2128, - serialized_end=2290, + serialized_start=2305, + serialized_end=2467, ) @@ -1209,8 +1310,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2292, - serialized_end=2335, + serialized_start=2469, + serialized_end=2512, ) @@ -1241,8 +1342,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2337, - serialized_end=2396, + serialized_start=2514, + serialized_end=2573, ) @@ -1273,8 +1374,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2398, - serialized_end=2427, + serialized_start=2575, + serialized_end=2604, ) @@ -1333,8 +1434,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2430, - serialized_end=2567, + serialized_start=2607, + serialized_end=2744, ) @@ -1358,8 +1459,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2569, - serialized_end=2593, + serialized_start=2746, + serialized_end=2770, ) @@ -1397,8 +1498,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2595, - serialized_end=2682, + serialized_start=2772, + serialized_end=2859, ) @@ -1429,8 +1530,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2684, - serialized_end=2721, + serialized_start=2861, + serialized_end=2898, ) @@ -1468,8 +1569,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2723, - serialized_end=2835, + serialized_start=2900, + serialized_end=3012, ) @@ -1493,8 +1594,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2837, - serialized_end=2857, + serialized_start=3014, + serialized_end=3034, ) @@ -1560,8 +1661,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=2860, - serialized_end=3051, + serialized_start=3037, + serialized_end=3228, ) @@ -1585,8 +1686,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3053, - serialized_end=3086, + serialized_start=3230, + serialized_end=3263, ) @@ -1617,8 +1718,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3088, - serialized_end=3155, + serialized_start=3265, + serialized_end=3332, ) @@ -1649,8 +1750,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3157, - serialized_end=3193, + serialized_start=3334, + serialized_end=3370, ) @@ -1688,8 +1789,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3195, - serialized_end=3291, + serialized_start=3372, + serialized_end=3468, ) @@ -1720,8 +1821,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3293, - serialized_end=3340, + serialized_start=3470, + serialized_end=3517, ) @@ -1752,8 +1853,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3342, - serialized_end=3406, + serialized_start=3519, + serialized_end=3583, ) @@ -1784,8 +1885,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3408, - serialized_end=3441, + serialized_start=3585, + serialized_end=3618, ) @@ -1823,8 +1924,47 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3443, - serialized_end=3530, + serialized_start=3620, + serialized_end=3707, +) + + +_SETCUSTOMHOOKSREQUEST = _descriptor.Descriptor( + name='SetCustomHooksRequest', + full_name='gitaly.SetCustomHooksRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='repository', full_name='gitaly.SetCustomHooksRequest.repository', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'\230\306,\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='data', full_name='gitaly.SetCustomHooksRequest.data', index=1, + number=2, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3709, + serialized_end=3792, ) @@ -1848,8 +1988,33 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3532, - serialized_end=3560, + serialized_start=3794, + serialized_end=3822, +) + + +_SETCUSTOMHOOKSRESPONSE = _descriptor.Descriptor( + name='SetCustomHooksResponse', + full_name='gitaly.SetCustomHooksResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3824, + serialized_end=3848, ) @@ -1880,8 +2045,40 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3562, - serialized_end=3634, + serialized_start=3850, + serialized_end=3922, +) + + +_GETCUSTOMHOOKSREQUEST = _descriptor.Descriptor( + name='GetCustomHooksRequest', + full_name='gitaly.GetCustomHooksRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='repository', full_name='gitaly.GetCustomHooksRequest.repository', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=b'\230\306,\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=3924, + serialized_end=3993, ) @@ -1912,8 +2109,40 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3636, - serialized_end=3677, + serialized_start=3995, + serialized_end=4036, +) + + +_GETCUSTOMHOOKSRESPONSE = _descriptor.Descriptor( + name='GetCustomHooksResponse', + full_name='gitaly.GetCustomHooksResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='data', full_name='gitaly.GetCustomHooksResponse.data', index=0, + number=1, type=12, cpp_type=9, label=1, + has_default_value=False, default_value=b"", + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=4038, + serialized_end=4076, ) @@ -1951,8 +2180,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3679, - serialized_end=3774, + serialized_start=4078, + serialized_end=4173, ) @@ -1976,8 +2205,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3776, - serialized_end=3812, + serialized_start=4175, + serialized_end=4211, ) @@ -2008,8 +2237,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3814, - serialized_end=3880, + serialized_start=4213, + serialized_end=4279, ) @@ -2068,8 +2297,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=3883, - serialized_end=4023, + serialized_start=4282, + serialized_end=4422, ) @@ -2100,8 +2329,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4025, - serialized_end=4097, + serialized_start=4424, + serialized_end=4496, ) @@ -2132,8 +2361,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4099, - serialized_end=4146, + serialized_start=4498, + serialized_end=4545, ) @@ -2164,8 +2393,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4148, - serialized_end=4220, + serialized_start=4547, + serialized_end=4619, ) @@ -2196,8 +2425,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4222, - serialized_end=4267, + serialized_start=4621, + serialized_end=4666, ) @@ -2228,8 +2457,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4269, - serialized_end=4335, + serialized_start=4668, + serialized_end=4734, ) @@ -2260,8 +2489,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4337, - serialized_end=4372, + serialized_start=4736, + serialized_end=4771, ) @@ -2320,8 +2549,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4375, - serialized_end=4544, + serialized_start=4774, + serialized_end=4943, ) @@ -2345,8 +2574,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4546, - serialized_end=4584, + serialized_start=4945, + serialized_end=4983, ) @@ -2391,8 +2620,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4586, - serialized_end=4698, + serialized_start=4985, + serialized_end=5097, ) @@ -2473,8 +2702,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4789, - serialized_end=5147, + serialized_start=5188, + serialized_end=5546, ) _GETRAWCHANGESRESPONSE = _descriptor.Descriptor( @@ -2504,8 +2733,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=4701, - serialized_end=5147, + serialized_start=5100, + serialized_end=5546, ) @@ -2571,8 +2800,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5150, - serialized_end=5297, + serialized_start=5549, + serialized_end=5696, ) @@ -2603,8 +2832,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5299, - serialized_end=5341, + serialized_start=5698, + serialized_end=5740, ) @@ -2656,8 +2885,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5344, - serialized_end=5473, + serialized_start=5743, + serialized_end=5872, ) @@ -2702,8 +2931,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5475, - serialized_end=5564, + serialized_start=5874, + serialized_end=5963, ) @@ -2762,8 +2991,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5567, - serialized_end=5708, + serialized_start=5966, + serialized_end=6107, ) @@ -2794,8 +3023,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5710, - serialized_end=5787, + serialized_start=6109, + serialized_end=6186, ) @@ -2826,8 +3055,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5789, - serialized_end=5835, + serialized_start=6188, + serialized_end=6234, ) @@ -2858,8 +3087,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5837, - serialized_end=5908, + serialized_start=6236, + serialized_end=6307, ) @@ -2883,8 +3112,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5910, - serialized_end=5936, + serialized_start=6309, + serialized_end=6335, ) @@ -2922,8 +3151,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=5938, - serialized_end=6032, + serialized_start=6337, + serialized_end=6431, ) @@ -2947,8 +3176,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6034, - serialized_end=6060, + serialized_start=6433, + serialized_end=6459, ) @@ -2986,8 +3215,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6062, - serialized_end=6172, + serialized_start=6461, + serialized_end=6571, ) @@ -3011,8 +3240,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6174, - serialized_end=6203, + serialized_start=6573, + serialized_end=6602, ) @@ -3031,8 +3260,15 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=b'\230\306,\001', file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='strategy', full_name='gitaly.OptimizeRepositoryRequest.strategy', index=1, + number=2, type=14, cpp_type=8, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], nested_types=[], enum_types=[ @@ -3034,8 +3270,9 @@ ], extensions=[ ], nested_types=[], enum_types=[ + _OPTIMIZEREPOSITORYREQUEST_STRATEGY, ], serialized_options=None, is_extendable=False, @@ -3043,8 +3280,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6205, - serialized_end=6278, + serialized_start=6605, + serialized_end=6824, ) @@ -3068,8 +3305,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6280, - serialized_end=6308, + serialized_start=6826, + serialized_end=6854, ) @@ -3100,8 +3337,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6310, - serialized_end=6388, + serialized_start=6856, + serialized_end=6934, ) @@ -3125,8 +3362,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6390, - serialized_end=6423, + serialized_start=6936, + serialized_end=6969, ) @@ -3164,8 +3401,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6425, - serialized_end=6505, + serialized_start=6971, + serialized_end=7051, ) @@ -3189,8 +3426,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6507, - serialized_end=6528, + serialized_start=7053, + serialized_end=7074, ) @@ -3221,8 +3458,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6530, - serialized_end=6593, + serialized_start=7076, + serialized_end=7139, ) @@ -3253,8 +3490,65 @@ extension_ranges=[], oneofs=[ ], - serialized_start=6595, - serialized_end=6627, + serialized_start=7141, + serialized_end=7173, +) + + +_REMOVEALLREQUEST = _descriptor.Descriptor( + name='RemoveAllRequest', + full_name='gitaly.RemoveAllRequest', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='storage_name', full_name='gitaly.RemoveAllRequest.storage_name', index=0, + number=1, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=7175, + serialized_end=7215, +) + + +_REMOVEALLRESPONSE = _descriptor.Descriptor( + name='RemoveAllResponse', + full_name='gitaly.RemoveAllResponse', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=7217, + serialized_end=7236, ) _REPOSITORYEXISTSREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY @@ -3267,8 +3561,10 @@ _WRITECOMMITGRAPHREQUEST_SPLITSTRATEGY.containing_type = _WRITECOMMITGRAPHREQUEST _CLEANUPREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _REPOSITORYSIZEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY +_OBJECTFORMATREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY +_OBJECTFORMATRESPONSE.fields_by_name['format'].enum_type = shared__pb2._OBJECTFORMAT _APPLYGITATTRIBUTESREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _FETCHBUNDLEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _FETCHREMOTEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _FETCHREMOTEREQUEST.fields_by_name['remote_params'].message_type = _REMOTE _CREATEREPOSITORYREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY @@ -3270,8 +3566,9 @@ _APPLYGITATTRIBUTESREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _FETCHBUNDLEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _FETCHREMOTEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _FETCHREMOTEREQUEST.fields_by_name['remote_params'].message_type = _REMOTE _CREATEREPOSITORYREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY +_CREATEREPOSITORYREQUEST.fields_by_name['object_format'].enum_type = shared__pb2._OBJECTFORMAT _GETARCHIVEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _GETARCHIVEREQUEST.fields_by_name['format'].enum_type = _GETARCHIVEREQUEST_FORMAT _GETARCHIVEREQUEST_FORMAT.containing_type = _GETARCHIVEREQUEST @@ -3288,4 +3585,5 @@ _CREATEBUNDLEFROMREFLISTREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _GETCONFIGREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _RESTORECUSTOMHOOKSREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY +_SETCUSTOMHOOKSREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _BACKUPCUSTOMHOOKSREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY @@ -3291,4 +3589,5 @@ _BACKUPCUSTOMHOOKSREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY +_GETCUSTOMHOOKSREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _CREATEREPOSITORYFROMBUNDLEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _FINDLICENSEREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _GETINFOATTRIBUTESREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY @@ -3308,6 +3607,8 @@ _REPLICATEREPOSITORYREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _REPLICATEREPOSITORYREQUEST.fields_by_name['source'].message_type = shared__pb2._REPOSITORY _OPTIMIZEREPOSITORYREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY +_OPTIMIZEREPOSITORYREQUEST.fields_by_name['strategy'].enum_type = _OPTIMIZEREPOSITORYREQUEST_STRATEGY +_OPTIMIZEREPOSITORYREQUEST_STRATEGY.containing_type = _OPTIMIZEREPOSITORYREQUEST _PRUNEUNREACHABLEOBJECTSREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _SETFULLPATHREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY _FULLPATHREQUEST.fields_by_name['repository'].message_type = shared__pb2._REPOSITORY @@ -3327,6 +3628,8 @@ DESCRIPTOR.message_types_by_name['CleanupResponse'] = _CLEANUPRESPONSE DESCRIPTOR.message_types_by_name['RepositorySizeRequest'] = _REPOSITORYSIZEREQUEST DESCRIPTOR.message_types_by_name['RepositorySizeResponse'] = _REPOSITORYSIZERESPONSE +DESCRIPTOR.message_types_by_name['ObjectFormatRequest'] = _OBJECTFORMATREQUEST +DESCRIPTOR.message_types_by_name['ObjectFormatResponse'] = _OBJECTFORMATRESPONSE DESCRIPTOR.message_types_by_name['ApplyGitattributesRequest'] = _APPLYGITATTRIBUTESREQUEST DESCRIPTOR.message_types_by_name['ApplyGitattributesResponse'] = _APPLYGITATTRIBUTESRESPONSE DESCRIPTOR.message_types_by_name['FetchBundleRequest'] = _FETCHBUNDLEREQUEST @@ -3358,4 +3661,5 @@ DESCRIPTOR.message_types_by_name['GetConfigRequest'] = _GETCONFIGREQUEST DESCRIPTOR.message_types_by_name['GetConfigResponse'] = _GETCONFIGRESPONSE DESCRIPTOR.message_types_by_name['RestoreCustomHooksRequest'] = _RESTORECUSTOMHOOKSREQUEST +DESCRIPTOR.message_types_by_name['SetCustomHooksRequest'] = _SETCUSTOMHOOKSREQUEST DESCRIPTOR.message_types_by_name['RestoreCustomHooksResponse'] = _RESTORECUSTOMHOOKSRESPONSE @@ -3361,2 +3665,3 @@ DESCRIPTOR.message_types_by_name['RestoreCustomHooksResponse'] = _RESTORECUSTOMHOOKSRESPONSE +DESCRIPTOR.message_types_by_name['SetCustomHooksResponse'] = _SETCUSTOMHOOKSRESPONSE DESCRIPTOR.message_types_by_name['BackupCustomHooksRequest'] = _BACKUPCUSTOMHOOKSREQUEST @@ -3362,2 +3667,3 @@ DESCRIPTOR.message_types_by_name['BackupCustomHooksRequest'] = _BACKUPCUSTOMHOOKSREQUEST +DESCRIPTOR.message_types_by_name['GetCustomHooksRequest'] = _GETCUSTOMHOOKSREQUEST DESCRIPTOR.message_types_by_name['BackupCustomHooksResponse'] = _BACKUPCUSTOMHOOKSRESPONSE @@ -3363,4 +3669,5 @@ DESCRIPTOR.message_types_by_name['BackupCustomHooksResponse'] = _BACKUPCUSTOMHOOKSRESPONSE +DESCRIPTOR.message_types_by_name['GetCustomHooksResponse'] = _GETCUSTOMHOOKSRESPONSE DESCRIPTOR.message_types_by_name['CreateRepositoryFromBundleRequest'] = _CREATEREPOSITORYFROMBUNDLEREQUEST DESCRIPTOR.message_types_by_name['CreateRepositoryFromBundleResponse'] = _CREATEREPOSITORYFROMBUNDLERESPONSE DESCRIPTOR.message_types_by_name['FindLicenseRequest'] = _FINDLICENSEREQUEST @@ -3396,6 +3703,8 @@ DESCRIPTOR.message_types_by_name['SetFullPathResponse'] = _SETFULLPATHRESPONSE DESCRIPTOR.message_types_by_name['FullPathRequest'] = _FULLPATHREQUEST DESCRIPTOR.message_types_by_name['FullPathResponse'] = _FULLPATHRESPONSE +DESCRIPTOR.message_types_by_name['RemoveAllRequest'] = _REMOVEALLREQUEST +DESCRIPTOR.message_types_by_name['RemoveAllResponse'] = _REMOVEALLRESPONSE _sym_db.RegisterFileDescriptor(DESCRIPTOR) RepositoryExistsRequest = _reflection.GeneratedProtocolMessageType('RepositoryExistsRequest', (_message.Message,), { @@ -3510,6 +3819,20 @@ }) _sym_db.RegisterMessage(RepositorySizeResponse) +ObjectFormatRequest = _reflection.GeneratedProtocolMessageType('ObjectFormatRequest', (_message.Message,), { + 'DESCRIPTOR' : _OBJECTFORMATREQUEST, + '__module__' : 'repository_pb2' + # @@protoc_insertion_point(class_scope:gitaly.ObjectFormatRequest) + }) +_sym_db.RegisterMessage(ObjectFormatRequest) + +ObjectFormatResponse = _reflection.GeneratedProtocolMessageType('ObjectFormatResponse', (_message.Message,), { + 'DESCRIPTOR' : _OBJECTFORMATRESPONSE, + '__module__' : 'repository_pb2' + # @@protoc_insertion_point(class_scope:gitaly.ObjectFormatResponse) + }) +_sym_db.RegisterMessage(ObjectFormatResponse) + ApplyGitattributesRequest = _reflection.GeneratedProtocolMessageType('ApplyGitattributesRequest', (_message.Message,), { 'DESCRIPTOR' : _APPLYGITATTRIBUTESREQUEST, '__module__' : 'repository_pb2' @@ -3727,6 +4050,13 @@ }) _sym_db.RegisterMessage(RestoreCustomHooksRequest) +SetCustomHooksRequest = _reflection.GeneratedProtocolMessageType('SetCustomHooksRequest', (_message.Message,), { + 'DESCRIPTOR' : _SETCUSTOMHOOKSREQUEST, + '__module__' : 'repository_pb2' + # @@protoc_insertion_point(class_scope:gitaly.SetCustomHooksRequest) + }) +_sym_db.RegisterMessage(SetCustomHooksRequest) + RestoreCustomHooksResponse = _reflection.GeneratedProtocolMessageType('RestoreCustomHooksResponse', (_message.Message,), { 'DESCRIPTOR' : _RESTORECUSTOMHOOKSRESPONSE, '__module__' : 'repository_pb2' @@ -3734,6 +4064,13 @@ }) _sym_db.RegisterMessage(RestoreCustomHooksResponse) +SetCustomHooksResponse = _reflection.GeneratedProtocolMessageType('SetCustomHooksResponse', (_message.Message,), { + 'DESCRIPTOR' : _SETCUSTOMHOOKSRESPONSE, + '__module__' : 'repository_pb2' + # @@protoc_insertion_point(class_scope:gitaly.SetCustomHooksResponse) + }) +_sym_db.RegisterMessage(SetCustomHooksResponse) + BackupCustomHooksRequest = _reflection.GeneratedProtocolMessageType('BackupCustomHooksRequest', (_message.Message,), { 'DESCRIPTOR' : _BACKUPCUSTOMHOOKSREQUEST, '__module__' : 'repository_pb2' @@ -3741,6 +4078,13 @@ }) _sym_db.RegisterMessage(BackupCustomHooksRequest) +GetCustomHooksRequest = _reflection.GeneratedProtocolMessageType('GetCustomHooksRequest', (_message.Message,), { + 'DESCRIPTOR' : _GETCUSTOMHOOKSREQUEST, + '__module__' : 'repository_pb2' + # @@protoc_insertion_point(class_scope:gitaly.GetCustomHooksRequest) + }) +_sym_db.RegisterMessage(GetCustomHooksRequest) + BackupCustomHooksResponse = _reflection.GeneratedProtocolMessageType('BackupCustomHooksResponse', (_message.Message,), { 'DESCRIPTOR' : _BACKUPCUSTOMHOOKSRESPONSE, '__module__' : 'repository_pb2' @@ -3748,6 +4092,13 @@ }) _sym_db.RegisterMessage(BackupCustomHooksResponse) +GetCustomHooksResponse = _reflection.GeneratedProtocolMessageType('GetCustomHooksResponse', (_message.Message,), { + 'DESCRIPTOR' : _GETCUSTOMHOOKSRESPONSE, + '__module__' : 'repository_pb2' + # @@protoc_insertion_point(class_scope:gitaly.GetCustomHooksResponse) + }) +_sym_db.RegisterMessage(GetCustomHooksResponse) + CreateRepositoryFromBundleRequest = _reflection.GeneratedProtocolMessageType('CreateRepositoryFromBundleRequest', (_message.Message,), { 'DESCRIPTOR' : _CREATEREPOSITORYFROMBUNDLEREQUEST, '__module__' : 'repository_pb2' @@ -4001,6 +4352,20 @@ }) _sym_db.RegisterMessage(FullPathResponse) +RemoveAllRequest = _reflection.GeneratedProtocolMessageType('RemoveAllRequest', (_message.Message,), { + 'DESCRIPTOR' : _REMOVEALLREQUEST, + '__module__' : 'repository_pb2' + # @@protoc_insertion_point(class_scope:gitaly.RemoveAllRequest) + }) +_sym_db.RegisterMessage(RemoveAllRequest) + +RemoveAllResponse = _reflection.GeneratedProtocolMessageType('RemoveAllResponse', (_message.Message,), { + 'DESCRIPTOR' : _REMOVEALLRESPONSE, + '__module__' : 'repository_pb2' + # @@protoc_insertion_point(class_scope:gitaly.RemoveAllResponse) + }) +_sym_db.RegisterMessage(RemoveAllResponse) + DESCRIPTOR._options = None _REPOSITORYEXISTSREQUEST.fields_by_name['repository']._options = None @@ -4011,6 +4376,7 @@ _WRITECOMMITGRAPHREQUEST.fields_by_name['repository']._options = None _CLEANUPREQUEST.fields_by_name['repository']._options = None _REPOSITORYSIZEREQUEST.fields_by_name['repository']._options = None +_OBJECTFORMATREQUEST.fields_by_name['repository']._options = None _APPLYGITATTRIBUTESREQUEST.fields_by_name['repository']._options = None _FETCHBUNDLEREQUEST.fields_by_name['repository']._options = None _FETCHREMOTEREQUEST.fields_by_name['repository']._options = None @@ -4028,4 +4394,5 @@ _CREATEBUNDLEFROMREFLISTREQUEST.fields_by_name['repository']._options = None _GETCONFIGREQUEST.fields_by_name['repository']._options = None _RESTORECUSTOMHOOKSREQUEST.fields_by_name['repository']._options = None +_SETCUSTOMHOOKSREQUEST.fields_by_name['repository']._options = None _BACKUPCUSTOMHOOKSREQUEST.fields_by_name['repository']._options = None @@ -4031,4 +4398,5 @@ _BACKUPCUSTOMHOOKSREQUEST.fields_by_name['repository']._options = None +_GETCUSTOMHOOKSREQUEST.fields_by_name['repository']._options = None _CREATEREPOSITORYFROMBUNDLEREQUEST.fields_by_name['repository']._options = None _FINDLICENSEREQUEST.fields_by_name['repository']._options = None _GETINFOATTRIBUTESREQUEST.fields_by_name['repository']._options = None @@ -4056,8 +4424,8 @@ index=0, serialized_options=None, create_key=_descriptor._internal_create_key, - serialized_start=6630, - serialized_end=10569, + serialized_start=7239, + serialized_end=11527, methods=[ _descriptor.MethodDescriptor( name='RepositoryExists', @@ -4130,5 +4498,15 @@ create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( + name='ObjectFormat', + full_name='gitaly.RepositoryService.ObjectFormat', + index=7, + containing_service=None, + input_type=_OBJECTFORMATREQUEST, + output_type=_OBJECTFORMATRESPONSE, + serialized_options=b'\372\227(\002\010\002', + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( name='ApplyGitattributes', full_name='gitaly.RepositoryService.ApplyGitattributes', @@ -4133,6 +4511,6 @@ name='ApplyGitattributes', full_name='gitaly.RepositoryService.ApplyGitattributes', - index=7, + index=8, containing_service=None, input_type=_APPLYGITATTRIBUTESREQUEST, output_type=_APPLYGITATTRIBUTESRESPONSE, @@ -4142,7 +4520,7 @@ _descriptor.MethodDescriptor( name='FetchRemote', full_name='gitaly.RepositoryService.FetchRemote', - index=8, + index=9, containing_service=None, input_type=_FETCHREMOTEREQUEST, output_type=_FETCHREMOTERESPONSE, @@ -4152,7 +4530,7 @@ _descriptor.MethodDescriptor( name='CreateRepository', full_name='gitaly.RepositoryService.CreateRepository', - index=9, + index=10, containing_service=None, input_type=_CREATEREPOSITORYREQUEST, output_type=_CREATEREPOSITORYRESPONSE, @@ -4162,7 +4540,7 @@ _descriptor.MethodDescriptor( name='GetArchive', full_name='gitaly.RepositoryService.GetArchive', - index=10, + index=11, containing_service=None, input_type=_GETARCHIVEREQUEST, output_type=_GETARCHIVERESPONSE, @@ -4172,7 +4550,7 @@ _descriptor.MethodDescriptor( name='HasLocalBranches', full_name='gitaly.RepositoryService.HasLocalBranches', - index=11, + index=12, containing_service=None, input_type=_HASLOCALBRANCHESREQUEST, output_type=_HASLOCALBRANCHESRESPONSE, @@ -4182,7 +4560,7 @@ _descriptor.MethodDescriptor( name='FetchSourceBranch', full_name='gitaly.RepositoryService.FetchSourceBranch', - index=12, + index=13, containing_service=None, input_type=_FETCHSOURCEBRANCHREQUEST, output_type=_FETCHSOURCEBRANCHRESPONSE, @@ -4192,7 +4570,7 @@ _descriptor.MethodDescriptor( name='Fsck', full_name='gitaly.RepositoryService.Fsck', - index=13, + index=14, containing_service=None, input_type=_FSCKREQUEST, output_type=_FSCKRESPONSE, @@ -4202,7 +4580,7 @@ _descriptor.MethodDescriptor( name='WriteRef', full_name='gitaly.RepositoryService.WriteRef', - index=14, + index=15, containing_service=None, input_type=_WRITEREFREQUEST, output_type=_WRITEREFRESPONSE, @@ -4212,7 +4590,7 @@ _descriptor.MethodDescriptor( name='FindMergeBase', full_name='gitaly.RepositoryService.FindMergeBase', - index=15, + index=16, containing_service=None, input_type=_FINDMERGEBASEREQUEST, output_type=_FINDMERGEBASERESPONSE, @@ -4222,7 +4600,7 @@ _descriptor.MethodDescriptor( name='CreateFork', full_name='gitaly.RepositoryService.CreateFork', - index=16, + index=17, containing_service=None, input_type=_CREATEFORKREQUEST, output_type=_CREATEFORKRESPONSE, @@ -4232,7 +4610,7 @@ _descriptor.MethodDescriptor( name='CreateRepositoryFromURL', full_name='gitaly.RepositoryService.CreateRepositoryFromURL', - index=17, + index=18, containing_service=None, input_type=_CREATEREPOSITORYFROMURLREQUEST, output_type=_CREATEREPOSITORYFROMURLRESPONSE, @@ -4242,7 +4620,7 @@ _descriptor.MethodDescriptor( name='CreateBundle', full_name='gitaly.RepositoryService.CreateBundle', - index=18, + index=19, containing_service=None, input_type=_CREATEBUNDLEREQUEST, output_type=_CREATEBUNDLERESPONSE, @@ -4252,7 +4630,7 @@ _descriptor.MethodDescriptor( name='CreateBundleFromRefList', full_name='gitaly.RepositoryService.CreateBundleFromRefList', - index=19, + index=20, containing_service=None, input_type=_CREATEBUNDLEFROMREFLISTREQUEST, output_type=_CREATEBUNDLEFROMREFLISTRESPONSE, @@ -4262,7 +4640,7 @@ _descriptor.MethodDescriptor( name='FetchBundle', full_name='gitaly.RepositoryService.FetchBundle', - index=20, + index=21, containing_service=None, input_type=_FETCHBUNDLEREQUEST, output_type=_FETCHBUNDLERESPONSE, @@ -4272,7 +4650,7 @@ _descriptor.MethodDescriptor( name='CreateRepositoryFromBundle', full_name='gitaly.RepositoryService.CreateRepositoryFromBundle', - index=21, + index=22, containing_service=None, input_type=_CREATEREPOSITORYFROMBUNDLEREQUEST, output_type=_CREATEREPOSITORYFROMBUNDLERESPONSE, @@ -4282,7 +4660,7 @@ _descriptor.MethodDescriptor( name='GetConfig', full_name='gitaly.RepositoryService.GetConfig', - index=22, + index=23, containing_service=None, input_type=_GETCONFIGREQUEST, output_type=_GETCONFIGRESPONSE, @@ -4292,7 +4670,7 @@ _descriptor.MethodDescriptor( name='FindLicense', full_name='gitaly.RepositoryService.FindLicense', - index=23, + index=24, containing_service=None, input_type=_FINDLICENSEREQUEST, output_type=_FINDLICENSERESPONSE, @@ -4302,7 +4680,7 @@ _descriptor.MethodDescriptor( name='GetInfoAttributes', full_name='gitaly.RepositoryService.GetInfoAttributes', - index=24, + index=25, containing_service=None, input_type=_GETINFOATTRIBUTESREQUEST, output_type=_GETINFOATTRIBUTESRESPONSE, @@ -4312,7 +4690,7 @@ _descriptor.MethodDescriptor( name='CalculateChecksum', full_name='gitaly.RepositoryService.CalculateChecksum', - index=25, + index=26, containing_service=None, input_type=_CALCULATECHECKSUMREQUEST, output_type=_CALCULATECHECKSUMRESPONSE, @@ -4322,7 +4700,7 @@ _descriptor.MethodDescriptor( name='Cleanup', full_name='gitaly.RepositoryService.Cleanup', - index=26, + index=27, containing_service=None, input_type=_CLEANUPREQUEST, output_type=_CLEANUPRESPONSE, @@ -4332,7 +4710,7 @@ _descriptor.MethodDescriptor( name='GetSnapshot', full_name='gitaly.RepositoryService.GetSnapshot', - index=27, + index=28, containing_service=None, input_type=_GETSNAPSHOTREQUEST, output_type=_GETSNAPSHOTRESPONSE, @@ -4342,7 +4720,7 @@ _descriptor.MethodDescriptor( name='CreateRepositoryFromSnapshot', full_name='gitaly.RepositoryService.CreateRepositoryFromSnapshot', - index=28, + index=29, containing_service=None, input_type=_CREATEREPOSITORYFROMSNAPSHOTREQUEST, output_type=_CREATEREPOSITORYFROMSNAPSHOTRESPONSE, @@ -4352,7 +4730,7 @@ _descriptor.MethodDescriptor( name='GetRawChanges', full_name='gitaly.RepositoryService.GetRawChanges', - index=29, + index=30, containing_service=None, input_type=_GETRAWCHANGESREQUEST, output_type=_GETRAWCHANGESRESPONSE, @@ -4362,7 +4740,7 @@ _descriptor.MethodDescriptor( name='SearchFilesByContent', full_name='gitaly.RepositoryService.SearchFilesByContent', - index=30, + index=31, containing_service=None, input_type=_SEARCHFILESBYCONTENTREQUEST, output_type=_SEARCHFILESBYCONTENTRESPONSE, @@ -4372,7 +4750,7 @@ _descriptor.MethodDescriptor( name='SearchFilesByName', full_name='gitaly.RepositoryService.SearchFilesByName', - index=31, + index=32, containing_service=None, input_type=_SEARCHFILESBYNAMEREQUEST, output_type=_SEARCHFILESBYNAMERESPONSE, @@ -4382,7 +4760,7 @@ _descriptor.MethodDescriptor( name='RestoreCustomHooks', full_name='gitaly.RepositoryService.RestoreCustomHooks', - index=32, + index=33, containing_service=None, input_type=_RESTORECUSTOMHOOKSREQUEST, output_type=_RESTORECUSTOMHOOKSRESPONSE, @@ -4386,9 +4764,19 @@ containing_service=None, input_type=_RESTORECUSTOMHOOKSREQUEST, output_type=_RESTORECUSTOMHOOKSRESPONSE, + serialized_options=b'\210\002\001\372\227(\002\010\001', + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='SetCustomHooks', + full_name='gitaly.RepositoryService.SetCustomHooks', + index=34, + containing_service=None, + input_type=_SETCUSTOMHOOKSREQUEST, + output_type=_SETCUSTOMHOOKSRESPONSE, serialized_options=b'\372\227(\002\010\001', create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( name='BackupCustomHooks', full_name='gitaly.RepositoryService.BackupCustomHooks', @@ -4389,10 +4777,10 @@ serialized_options=b'\372\227(\002\010\001', create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( name='BackupCustomHooks', full_name='gitaly.RepositoryService.BackupCustomHooks', - index=33, + index=35, containing_service=None, input_type=_BACKUPCUSTOMHOOKSREQUEST, output_type=_BACKUPCUSTOMHOOKSRESPONSE, @@ -4396,9 +4784,19 @@ containing_service=None, input_type=_BACKUPCUSTOMHOOKSREQUEST, output_type=_BACKUPCUSTOMHOOKSRESPONSE, + serialized_options=b'\210\002\001\372\227(\002\010\002', + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='GetCustomHooks', + full_name='gitaly.RepositoryService.GetCustomHooks', + index=36, + containing_service=None, + input_type=_GETCUSTOMHOOKSREQUEST, + output_type=_GETCUSTOMHOOKSRESPONSE, serialized_options=b'\372\227(\002\010\002', create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( name='GetObjectDirectorySize', full_name='gitaly.RepositoryService.GetObjectDirectorySize', @@ -4399,10 +4797,10 @@ serialized_options=b'\372\227(\002\010\002', create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( name='GetObjectDirectorySize', full_name='gitaly.RepositoryService.GetObjectDirectorySize', - index=34, + index=37, containing_service=None, input_type=_GETOBJECTDIRECTORYSIZEREQUEST, output_type=_GETOBJECTDIRECTORYSIZERESPONSE, @@ -4412,7 +4810,7 @@ _descriptor.MethodDescriptor( name='RemoveRepository', full_name='gitaly.RepositoryService.RemoveRepository', - index=35, + index=38, containing_service=None, input_type=_REMOVEREPOSITORYREQUEST, output_type=_REMOVEREPOSITORYRESPONSE, @@ -4422,7 +4820,7 @@ _descriptor.MethodDescriptor( name='RenameRepository', full_name='gitaly.RepositoryService.RenameRepository', - index=36, + index=39, containing_service=None, input_type=_RENAMEREPOSITORYREQUEST, output_type=_RENAMEREPOSITORYRESPONSE, @@ -4432,7 +4830,7 @@ _descriptor.MethodDescriptor( name='ReplicateRepository', full_name='gitaly.RepositoryService.ReplicateRepository', - index=37, + index=40, containing_service=None, input_type=_REPLICATEREPOSITORYREQUEST, output_type=_REPLICATEREPOSITORYRESPONSE, @@ -4442,7 +4840,7 @@ _descriptor.MethodDescriptor( name='OptimizeRepository', full_name='gitaly.RepositoryService.OptimizeRepository', - index=38, + index=41, containing_service=None, input_type=_OPTIMIZEREPOSITORYREQUEST, output_type=_OPTIMIZEREPOSITORYRESPONSE, @@ -4452,7 +4850,7 @@ _descriptor.MethodDescriptor( name='PruneUnreachableObjects', full_name='gitaly.RepositoryService.PruneUnreachableObjects', - index=39, + index=42, containing_service=None, input_type=_PRUNEUNREACHABLEOBJECTSREQUEST, output_type=_PRUNEUNREACHABLEOBJECTSRESPONSE, @@ -4462,7 +4860,7 @@ _descriptor.MethodDescriptor( name='SetFullPath', full_name='gitaly.RepositoryService.SetFullPath', - index=40, + index=43, containing_service=None, input_type=_SETFULLPATHREQUEST, output_type=_SETFULLPATHRESPONSE, @@ -4466,9 +4864,9 @@ containing_service=None, input_type=_SETFULLPATHREQUEST, output_type=_SETFULLPATHRESPONSE, - serialized_options=b'\372\227(\002\010\001', + serialized_options=b'\210\002\001\372\227(\002\010\001', create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( name='FullPath', full_name='gitaly.RepositoryService.FullPath', @@ -4470,9 +4868,9 @@ create_key=_descriptor._internal_create_key, ), _descriptor.MethodDescriptor( name='FullPath', full_name='gitaly.RepositoryService.FullPath', - index=41, + index=44, containing_service=None, input_type=_FULLPATHREQUEST, output_type=_FULLPATHRESPONSE, @@ -4476,7 +4874,17 @@ containing_service=None, input_type=_FULLPATHREQUEST, output_type=_FULLPATHRESPONSE, - serialized_options=b'\372\227(\002\010\002', + serialized_options=b'\210\002\001\372\227(\002\010\002', + create_key=_descriptor._internal_create_key, + ), + _descriptor.MethodDescriptor( + name='RemoveAll', + full_name='gitaly.RepositoryService.RemoveAll', + index=45, + containing_service=None, + input_type=_REMOVEALLREQUEST, + output_type=_REMOVEALLRESPONSE, + serialized_options=b'\200\230(\001', create_key=_descriptor._internal_create_key, ), ]) diff --git a/hgitaly/stub/repository_pb2_grpc.py b/hgitaly/stub/repository_pb2_grpc.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zdHViL3JlcG9zaXRvcnlfcGIyX2dycGMucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL3JlcG9zaXRvcnlfcGIyX2dycGMucHk= 100644 --- a/hgitaly/stub/repository_pb2_grpc.py +++ b/hgitaly/stub/repository_pb2_grpc.py @@ -50,6 +50,11 @@ request_serializer=repository__pb2.RepositorySizeRequest.SerializeToString, response_deserializer=repository__pb2.RepositorySizeResponse.FromString, ) + self.ObjectFormat = channel.unary_unary( + '/gitaly.RepositoryService/ObjectFormat', + request_serializer=repository__pb2.ObjectFormatRequest.SerializeToString, + response_deserializer=repository__pb2.ObjectFormatResponse.FromString, + ) self.ApplyGitattributes = channel.unary_unary( '/gitaly.RepositoryService/ApplyGitattributes', request_serializer=repository__pb2.ApplyGitattributesRequest.SerializeToString, @@ -180,8 +185,13 @@ request_serializer=repository__pb2.RestoreCustomHooksRequest.SerializeToString, response_deserializer=repository__pb2.RestoreCustomHooksResponse.FromString, ) + self.SetCustomHooks = channel.stream_unary( + '/gitaly.RepositoryService/SetCustomHooks', + request_serializer=repository__pb2.SetCustomHooksRequest.SerializeToString, + response_deserializer=repository__pb2.SetCustomHooksResponse.FromString, + ) self.BackupCustomHooks = channel.unary_stream( '/gitaly.RepositoryService/BackupCustomHooks', request_serializer=repository__pb2.BackupCustomHooksRequest.SerializeToString, response_deserializer=repository__pb2.BackupCustomHooksResponse.FromString, ) @@ -183,8 +193,13 @@ self.BackupCustomHooks = channel.unary_stream( '/gitaly.RepositoryService/BackupCustomHooks', request_serializer=repository__pb2.BackupCustomHooksRequest.SerializeToString, response_deserializer=repository__pb2.BackupCustomHooksResponse.FromString, ) + self.GetCustomHooks = channel.unary_stream( + '/gitaly.RepositoryService/GetCustomHooks', + request_serializer=repository__pb2.GetCustomHooksRequest.SerializeToString, + response_deserializer=repository__pb2.GetCustomHooksResponse.FromString, + ) self.GetObjectDirectorySize = channel.unary_unary( '/gitaly.RepositoryService/GetObjectDirectorySize', request_serializer=repository__pb2.GetObjectDirectorySizeRequest.SerializeToString, @@ -225,6 +240,11 @@ request_serializer=repository__pb2.FullPathRequest.SerializeToString, response_deserializer=repository__pb2.FullPathResponse.FromString, ) + self.RemoveAll = channel.unary_unary( + '/gitaly.RepositoryService/RemoveAll', + request_serializer=repository__pb2.RemoveAllRequest.SerializeToString, + response_deserializer=repository__pb2.RemoveAllResponse.FromString, + ) class RepositoryServiceServicer(object): @@ -280,6 +300,13 @@ context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def ObjectFormat(self, request, context): + """ObjectFormat determines the object format that is being used by the repository. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def ApplyGitattributes(self, request, context): """This comment is left unintentionally blank. """ @@ -325,7 +352,8 @@ raise NotImplementedError('Method not implemented!') def Fsck(self, request, context): - """This comment is left unintentionally blank. + """Fsck checks the repository for consistency via git-fsck(1). This can be used to check for + repository corruption. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -399,7 +427,8 @@ raise NotImplementedError('Method not implemented!') def FindLicense(self, request, context): - """This comment is left unintentionally blank. + """FindLicense looks in the given repository and attempts to detect all the + details about the license used in the repository. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -462,10 +491,21 @@ raise NotImplementedError('Method not implemented!') def RestoreCustomHooks(self, request_iterator, context): - """This comment is left unintentionally blank. + """RestoreCustomHooks sets the git hooks for a repository. The hooks are sent + in a tar archive containing a `custom_hooks` directory. This directory is + ultimately extracted to the repository. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def SetCustomHooks(self, request_iterator, context): + """SetCustomHooks sets the git hooks for a repository. The hooks are sent in a + tar archive containing a `custom_hooks` directory. This directory is + ultimately extracted to the repository. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def BackupCustomHooks(self, request, context): @@ -466,10 +506,21 @@ """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') def BackupCustomHooks(self, request, context): - """This comment is left unintentionally blank. + """BackupCustomHooks fetches the git hooks for a repository. The hooks are + sent in a tar archive containing a `custom_hooks` directory. If no hooks + are present in the repository, the response will have no data. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + def GetCustomHooks(self, request, context): + """GetCustomHooks fetches the git hooks for a repository. The hooks are sent + in a tar archive containing a `custom_hooks` directory. If no hooks are + present in the repository, the response will have no data. """ context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -552,6 +603,13 @@ context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def RemoveAll(self, request, context): + """RemoveAll deletes all repositories on a specified storage. + """ + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def add_RepositoryServiceServicer_to_server(servicer, server): rpc_method_handlers = { @@ -590,6 +648,11 @@ request_deserializer=repository__pb2.RepositorySizeRequest.FromString, response_serializer=repository__pb2.RepositorySizeResponse.SerializeToString, ), + 'ObjectFormat': grpc.unary_unary_rpc_method_handler( + servicer.ObjectFormat, + request_deserializer=repository__pb2.ObjectFormatRequest.FromString, + response_serializer=repository__pb2.ObjectFormatResponse.SerializeToString, + ), 'ApplyGitattributes': grpc.unary_unary_rpc_method_handler( servicer.ApplyGitattributes, request_deserializer=repository__pb2.ApplyGitattributesRequest.FromString, @@ -720,8 +783,13 @@ request_deserializer=repository__pb2.RestoreCustomHooksRequest.FromString, response_serializer=repository__pb2.RestoreCustomHooksResponse.SerializeToString, ), + 'SetCustomHooks': grpc.stream_unary_rpc_method_handler( + servicer.SetCustomHooks, + request_deserializer=repository__pb2.SetCustomHooksRequest.FromString, + response_serializer=repository__pb2.SetCustomHooksResponse.SerializeToString, + ), 'BackupCustomHooks': grpc.unary_stream_rpc_method_handler( servicer.BackupCustomHooks, request_deserializer=repository__pb2.BackupCustomHooksRequest.FromString, response_serializer=repository__pb2.BackupCustomHooksResponse.SerializeToString, ), @@ -723,8 +791,13 @@ 'BackupCustomHooks': grpc.unary_stream_rpc_method_handler( servicer.BackupCustomHooks, request_deserializer=repository__pb2.BackupCustomHooksRequest.FromString, response_serializer=repository__pb2.BackupCustomHooksResponse.SerializeToString, ), + 'GetCustomHooks': grpc.unary_stream_rpc_method_handler( + servicer.GetCustomHooks, + request_deserializer=repository__pb2.GetCustomHooksRequest.FromString, + response_serializer=repository__pb2.GetCustomHooksResponse.SerializeToString, + ), 'GetObjectDirectorySize': grpc.unary_unary_rpc_method_handler( servicer.GetObjectDirectorySize, request_deserializer=repository__pb2.GetObjectDirectorySizeRequest.FromString, @@ -765,6 +838,11 @@ request_deserializer=repository__pb2.FullPathRequest.FromString, response_serializer=repository__pb2.FullPathResponse.SerializeToString, ), + 'RemoveAll': grpc.unary_unary_rpc_method_handler( + servicer.RemoveAll, + request_deserializer=repository__pb2.RemoveAllRequest.FromString, + response_serializer=repository__pb2.RemoveAllResponse.SerializeToString, + ), } generic_handler = grpc.method_handlers_generic_handler( 'gitaly.RepositoryService', rpc_method_handlers) @@ -896,6 +974,23 @@ insecure, call_credentials, compression, wait_for_ready, timeout, metadata) @staticmethod + def ObjectFormat(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/gitaly.RepositoryService/ObjectFormat', + repository__pb2.ObjectFormatRequest.SerializeToString, + repository__pb2.ObjectFormatResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod def ApplyGitattributes(request, target, options=(), @@ -1338,6 +1433,23 @@ insecure, call_credentials, compression, wait_for_ready, timeout, metadata) @staticmethod + def SetCustomHooks(request_iterator, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.stream_unary(request_iterator, target, '/gitaly.RepositoryService/SetCustomHooks', + repository__pb2.SetCustomHooksRequest.SerializeToString, + repository__pb2.SetCustomHooksResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod def BackupCustomHooks(request, target, options=(), @@ -1355,6 +1467,23 @@ insecure, call_credentials, compression, wait_for_ready, timeout, metadata) @staticmethod + def GetCustomHooks(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_stream(request, target, '/gitaly.RepositoryService/GetCustomHooks', + repository__pb2.GetCustomHooksRequest.SerializeToString, + repository__pb2.GetCustomHooksResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod def GetObjectDirectorySize(request, target, options=(), @@ -1489,3 +1618,20 @@ repository__pb2.FullPathResponse.FromString, options, channel_credentials, insecure, call_credentials, compression, wait_for_ready, timeout, metadata) + + @staticmethod + def RemoveAll(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/gitaly.RepositoryService/RemoveAll', + repository__pb2.RemoveAllRequest.SerializeToString, + repository__pb2.RemoveAllResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/hgitaly/stub/shared_pb2.py b/hgitaly/stub/shared_pb2.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS9zdHViL3NoYXJlZF9wYjIucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS9zdHViL3NoYXJlZF9wYjIucHk= 100644 --- a/hgitaly/stub/shared_pb2.py +++ b/hgitaly/stub/shared_pb2.py @@ -22,7 +22,7 @@ syntax='proto3', serialized_options=b'Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb', create_key=_descriptor._internal_create_key, - serialized_pb=b'\n\x0cshared.proto\x12\x06gitaly\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\nlint.proto\"\xc3\x01\n\nRepository\x12\x14\n\x0cstorage_name\x18\x02 \x01(\t\x12\x15\n\rrelative_path\x18\x03 \x01(\t\x12\x1c\n\x14git_object_directory\x18\x04 \x01(\t\x12(\n git_alternate_object_directories\x18\x05 \x03(\t\x12\x15\n\rgl_repository\x18\x06 \x01(\t\x12\x17\n\x0fgl_project_path\x18\x08 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x07\x10\x08R\x04path\"+\n\rCommitTrailer\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\"M\n\x0e\x43ommitStatInfo\x12\x11\n\tadditions\x18\x01 \x01(\x05\x12\x11\n\tdeletions\x18\x02 \x01(\x05\x12\x15\n\rchanged_files\x18\x03 \x01(\x05\"\xc2\x02\n\tGitCommit\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0f\n\x07subject\x18\x02 \x01(\x0c\x12\x0c\n\x04\x62ody\x18\x03 \x01(\x0c\x12$\n\x06\x61uthor\x18\x04 \x01(\x0b\x32\x14.gitaly.CommitAuthor\x12\'\n\tcommitter\x18\x05 \x01(\x0b\x32\x14.gitaly.CommitAuthor\x12\x12\n\nparent_ids\x18\x06 \x03(\t\x12\x11\n\tbody_size\x18\x07 \x01(\x03\x12-\n\x0esignature_type\x18\x08 \x01(\x0e\x32\x15.gitaly.SignatureType\x12\x0f\n\x07tree_id\x18\t \x01(\t\x12\'\n\x08trailers\x18\n \x03(\x0b\x32\x15.gitaly.CommitTrailer\x12+\n\x0bshort_stats\x18\x0b \x01(\x0b\x32\x16.gitaly.CommitStatInfo\"g\n\x0c\x43ommitAuthor\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\r\n\x05\x65mail\x18\x02 \x01(\x0c\x12(\n\x04\x64\x61te\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08timezone\x18\x04 \x01(\x0c\"\x1b\n\nExitStatus\x12\r\n\x05value\x18\x01 \x01(\x05\"@\n\x06\x42ranch\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12(\n\rtarget_commit\x18\x02 \x01(\x0b\x32\x11.gitaly.GitCommit\"\xc5\x01\n\x03Tag\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\n\n\x02id\x18\x02 \x01(\t\x12(\n\rtarget_commit\x18\x03 \x01(\x0b\x32\x11.gitaly.GitCommit\x12\x0f\n\x07message\x18\x04 \x01(\x0c\x12\x14\n\x0cmessage_size\x18\x05 \x01(\x03\x12$\n\x06tagger\x18\x06 \x01(\x0b\x32\x14.gitaly.CommitAuthor\x12-\n\x0esignature_type\x18\x07 \x01(\x0e\x32\x15.gitaly.SignatureType\"Y\n\x04User\x12\r\n\x05gl_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\r\n\x05\x65mail\x18\x03 \x01(\x0c\x12\x13\n\x0bgl_username\x18\x04 \x01(\t\x12\x10\n\x08timezone\x18\x05 \x01(\t\":\n\nObjectPool\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x90\xc6,\x01\"8\n\x13PaginationParameter\x12\x12\n\npage_token\x18\x01 \x01(\t\x12\r\n\x05limit\x18\x02 \x01(\x05\"\'\n\x10PaginationCursor\x12\x13\n\x0bnext_cursor\x18\x01 \x01(\t\"*\n\rGlobalOptions\x12\x19\n\x11literal_pathspecs\x18\x01 \x01(\x08*B\n\nObjectType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x43OMMIT\x10\x01\x12\x08\n\x04\x42LOB\x10\x02\x12\x08\n\x04TREE\x10\x03\x12\x07\n\x03TAG\x10\x04*5\n\rSignatureType\x12\x08\n\x04NONE\x10\x00\x12\x07\n\x03PGP\x10\x01\x12\x08\n\x04X509\x10\x02\x12\x07\n\x03SSH\x10\x03*.\n\rSortDirection\x12\r\n\tASCENDING\x10\x00\x12\x0e\n\nDESCENDING\x10\x01\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' + serialized_pb=b'\n\x0cshared.proto\x12\x06gitaly\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\nlint.proto\"\xc3\x01\n\nRepository\x12\x14\n\x0cstorage_name\x18\x02 \x01(\t\x12\x15\n\rrelative_path\x18\x03 \x01(\t\x12\x1c\n\x14git_object_directory\x18\x04 \x01(\t\x12(\n git_alternate_object_directories\x18\x05 \x03(\t\x12\x15\n\rgl_repository\x18\x06 \x01(\t\x12\x17\n\x0fgl_project_path\x18\x08 \x01(\tJ\x04\x08\x01\x10\x02J\x04\x08\x07\x10\x08R\x04path\"+\n\rCommitTrailer\x12\x0b\n\x03key\x18\x01 \x01(\x0c\x12\r\n\x05value\x18\x02 \x01(\x0c\"M\n\x0e\x43ommitStatInfo\x12\x11\n\tadditions\x18\x01 \x01(\x05\x12\x11\n\tdeletions\x18\x02 \x01(\x05\x12\x15\n\rchanged_files\x18\x03 \x01(\x05\"\xeb\x02\n\tGitCommit\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0f\n\x07subject\x18\x02 \x01(\x0c\x12\x0c\n\x04\x62ody\x18\x03 \x01(\x0c\x12$\n\x06\x61uthor\x18\x04 \x01(\x0b\x32\x14.gitaly.CommitAuthor\x12\'\n\tcommitter\x18\x05 \x01(\x0b\x32\x14.gitaly.CommitAuthor\x12\x12\n\nparent_ids\x18\x06 \x03(\t\x12\x11\n\tbody_size\x18\x07 \x01(\x03\x12-\n\x0esignature_type\x18\x08 \x01(\x0e\x32\x15.gitaly.SignatureType\x12\x0f\n\x07tree_id\x18\t \x01(\t\x12\'\n\x08trailers\x18\n \x03(\x0b\x32\x15.gitaly.CommitTrailer\x12+\n\x0bshort_stats\x18\x0b \x01(\x0b\x32\x16.gitaly.CommitStatInfo\x12\x15\n\rreferenced_by\x18\x0c \x03(\x0c\x12\x10\n\x08\x65ncoding\x18\r \x01(\t\"g\n\x0c\x43ommitAuthor\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\r\n\x05\x65mail\x18\x02 \x01(\x0c\x12(\n\x04\x64\x61te\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x10\n\x08timezone\x18\x04 \x01(\x0c\"\x1b\n\nExitStatus\x12\r\n\x05value\x18\x01 \x01(\x05\"@\n\x06\x42ranch\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12(\n\rtarget_commit\x18\x02 \x01(\x0b\x32\x11.gitaly.GitCommit\"\xc5\x01\n\x03Tag\x12\x0c\n\x04name\x18\x01 \x01(\x0c\x12\n\n\x02id\x18\x02 \x01(\t\x12(\n\rtarget_commit\x18\x03 \x01(\x0b\x32\x11.gitaly.GitCommit\x12\x0f\n\x07message\x18\x04 \x01(\x0c\x12\x14\n\x0cmessage_size\x18\x05 \x01(\x03\x12$\n\x06tagger\x18\x06 \x01(\x0b\x32\x14.gitaly.CommitAuthor\x12-\n\x0esignature_type\x18\x07 \x01(\x0e\x32\x15.gitaly.SignatureType\"Y\n\x04User\x12\r\n\x05gl_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\x0c\x12\r\n\x05\x65mail\x18\x03 \x01(\x0c\x12\x13\n\x0bgl_username\x18\x04 \x01(\t\x12\x10\n\x08timezone\x18\x05 \x01(\t\":\n\nObjectPool\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x90\xc6,\x01\"8\n\x13PaginationParameter\x12\x12\n\npage_token\x18\x01 \x01(\t\x12\r\n\x05limit\x18\x02 \x01(\x05\"\'\n\x10PaginationCursor\x12\x13\n\x0bnext_cursor\x18\x01 \x01(\t\"*\n\rGlobalOptions\x12\x19\n\x11literal_pathspecs\x18\x01 \x01(\x08*B\n\nObjectType\x12\x0b\n\x07UNKNOWN\x10\x00\x12\n\n\x06\x43OMMIT\x10\x01\x12\x08\n\x04\x42LOB\x10\x02\x12\x08\n\x04TREE\x10\x03\x12\x07\n\x03TAG\x10\x04*_\n\x0cObjectFormat\x12\x1d\n\x19OBJECT_FORMAT_UNSPECIFIED\x10\x00\x12\x16\n\x12OBJECT_FORMAT_SHA1\x10\x01\x12\x18\n\x14OBJECT_FORMAT_SHA256\x10\x02*5\n\rSignatureType\x12\x08\n\x04NONE\x10\x00\x12\x07\n\x03PGP\x10\x01\x12\x08\n\x04X509\x10\x02\x12\x07\n\x03SSH\x10\x03*.\n\rSortDirection\x12\r\n\tASCENDING\x10\x00\x12\x0e\n\nDESCENDING\x10\x01\x42\x34Z2gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypbb\x06proto3' , dependencies=[google_dot_protobuf_dot_timestamp__pb2.DESCRIPTOR,lint__pb2.DESCRIPTOR,]) @@ -61,9 +61,9 @@ ], containing_type=None, serialized_options=None, - serialized_start=1410, - serialized_end=1476, + serialized_start=1451, + serialized_end=1517, ) _sym_db.RegisterEnumDescriptor(_OBJECTTYPE) ObjectType = enum_type_wrapper.EnumTypeWrapper(_OBJECTTYPE) @@ -66,7 +66,38 @@ ) _sym_db.RegisterEnumDescriptor(_OBJECTTYPE) ObjectType = enum_type_wrapper.EnumTypeWrapper(_OBJECTTYPE) +_OBJECTFORMAT = _descriptor.EnumDescriptor( + name='ObjectFormat', + full_name='gitaly.ObjectFormat', + filename=None, + file=DESCRIPTOR, + create_key=_descriptor._internal_create_key, + values=[ + _descriptor.EnumValueDescriptor( + name='OBJECT_FORMAT_UNSPECIFIED', index=0, number=0, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='OBJECT_FORMAT_SHA1', index=1, number=1, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + _descriptor.EnumValueDescriptor( + name='OBJECT_FORMAT_SHA256', index=2, number=2, + serialized_options=None, + type=None, + create_key=_descriptor._internal_create_key), + ], + containing_type=None, + serialized_options=None, + serialized_start=1519, + serialized_end=1614, +) +_sym_db.RegisterEnumDescriptor(_OBJECTFORMAT) + +ObjectFormat = enum_type_wrapper.EnumTypeWrapper(_OBJECTFORMAT) _SIGNATURETYPE = _descriptor.EnumDescriptor( name='SignatureType', full_name='gitaly.SignatureType', @@ -97,8 +128,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=1478, - serialized_end=1531, + serialized_start=1616, + serialized_end=1669, ) _sym_db.RegisterEnumDescriptor(_SIGNATURETYPE) @@ -123,8 +154,8 @@ ], containing_type=None, serialized_options=None, - serialized_start=1533, - serialized_end=1579, + serialized_start=1671, + serialized_end=1717, ) _sym_db.RegisterEnumDescriptor(_SORTDIRECTION) @@ -134,6 +165,9 @@ BLOB = 2 TREE = 3 TAG = 4 +OBJECT_FORMAT_UNSPECIFIED = 0 +OBJECT_FORMAT_SHA1 = 1 +OBJECT_FORMAT_SHA256 = 2 NONE = 0 PGP = 1 X509 = 2 @@ -380,6 +414,20 @@ message_type=None, enum_type=None, containing_type=None, is_extension=False, extension_scope=None, serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='referenced_by', full_name='gitaly.GitCommit.referenced_by', index=11, + number=12, type=12, cpp_type=9, label=3, + has_default_value=False, default_value=[], + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='encoding', full_name='gitaly.GitCommit.encoding', index=12, + number=13, type=9, cpp_type=9, label=1, + has_default_value=False, default_value=b"".decode('utf-8'), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), ], extensions=[ ], @@ -393,7 +441,7 @@ oneofs=[ ], serialized_start=392, - serialized_end=714, + serialized_end=755, ) @@ -445,8 +493,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=716, - serialized_end=819, + serialized_start=757, + serialized_end=860, ) @@ -477,8 +525,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=821, - serialized_end=848, + serialized_start=862, + serialized_end=889, ) @@ -516,8 +564,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=850, - serialized_end=914, + serialized_start=891, + serialized_end=955, ) @@ -590,8 +638,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=917, - serialized_end=1114, + serialized_start=958, + serialized_end=1155, ) @@ -650,8 +698,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1116, - serialized_end=1205, + serialized_start=1157, + serialized_end=1246, ) @@ -682,8 +730,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1207, - serialized_end=1265, + serialized_start=1248, + serialized_end=1306, ) @@ -721,8 +769,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1267, - serialized_end=1323, + serialized_start=1308, + serialized_end=1364, ) @@ -753,8 +801,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1325, - serialized_end=1364, + serialized_start=1366, + serialized_end=1405, ) @@ -785,8 +833,8 @@ extension_ranges=[], oneofs=[ ], - serialized_start=1366, - serialized_end=1408, + serialized_start=1407, + serialized_end=1449, ) _GITCOMMIT.fields_by_name['author'].message_type = _COMMITAUTHOR @@ -814,6 +862,7 @@ DESCRIPTOR.message_types_by_name['PaginationCursor'] = _PAGINATIONCURSOR DESCRIPTOR.message_types_by_name['GlobalOptions'] = _GLOBALOPTIONS DESCRIPTOR.enum_types_by_name['ObjectType'] = _OBJECTTYPE +DESCRIPTOR.enum_types_by_name['ObjectFormat'] = _OBJECTFORMAT DESCRIPTOR.enum_types_by_name['SignatureType'] = _SIGNATURETYPE DESCRIPTOR.enum_types_by_name['SortDirection'] = _SORTDIRECTION _sym_db.RegisterFileDescriptor(DESCRIPTOR) diff --git a/hgitaly/tag.py b/hgitaly/tag.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS90YWcucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS90YWcucHk= 100644 --- a/hgitaly/tag.py +++ b/hgitaly/tag.py @@ -11,6 +11,9 @@ from heptapod.gitlab.tag import ( gitlab_tag_ref, ) +from .gitlab_ref import ( + path_match_any, +) EXCLUDED_TAG_TYPES = (b'local', None) # 'tip' has type None @@ -30,6 +33,6 @@ yield name, (repo[node] if deref else hex(node).decode('ascii')) -def iter_gitlab_tags_as_refs(repo, **kwargs): +def iter_gitlab_tags_as_refs(repo, patterns=None, **kwargs): """Iterate on the repo tags, yielding full Git refs and change contexts. @@ -34,4 +37,5 @@ """Iterate on the repo tags, yielding full Git refs and change contexts. + :param patterns: as in :func:`path_match_any` (presplit) """ for name, target in iter_gitlab_tags(repo, **kwargs): @@ -36,6 +40,10 @@ """ for name, target in iter_gitlab_tags(repo, **kwargs): - yield gitlab_tag_ref(name), target + ref_path = gitlab_tag_ref(name) + if patterns and not path_match_any(ref_path, patterns): + continue + + yield ref_path, target def tagged_changeset(repo, tag_name): diff --git a/hgitaly/tests/test_linguist.py b/hgitaly/tests/test_linguist.py new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS90ZXN0cy90ZXN0X2xpbmd1aXN0LnB5 --- /dev/null +++ b/hgitaly/tests/test_linguist.py @@ -0,0 +1,68 @@ +# Copyright 2023 Georges Racinet <georges.racinet@octobus.net> +# +# This software may be used and distributed according to the terms of the +# GNU General Public License version 2 or any later version. +# +# SPDX-License-Identifier: GPL-2.0-or-later +import pytest +from grpc import StatusCode + +from ..linguist import ( + language_stats, +) +from ..testing.context import FakeServicerContext + + +class FakeContextAbort(RuntimeError): + pass + + +class FakeContext(FakeServicerContext): + + _trailing_metadata = _code = _details = None + + def set_trailing_metadata(self, metadata): + self._trailing_metadata = metadata + + def trailing_metadata(self): + return self._trailing_metadata + + def code(self): + return self._code + + def details(self): + return self._details + + def abort(self, code, details): + self._code = code + self._details = details + raise FakeContextAbort() + + +def test_tokei_subprocesss_errors(tmpdir): + bin_path = tmpdir / 'tokei' + context = FakeContext() + with pytest.raises(FakeContextAbort): + language_stats(bin_path, tmpdir / 'tree', context) + assert context.code() == StatusCode.INTERNAL + assert "not found" in context.details() + + bin_path.write_binary(b'#!/bin/sh\n\n echo "oops" >&2; exit 3\n') + with pytest.raises(FakeContextAbort): + language_stats(bin_path, tmpdir / 'tree', context) + assert "permission denied" in context.details() + + bin_path.chmod(0o755) + + with pytest.raises(FakeContextAbort): + language_stats(bin_path, tmpdir / 'tree', context) + assert context.code() == StatusCode.INTERNAL + assert "status code=3" in context.details() + assert "oops" in context.details() + + bin_path.write_binary(b'#!/bin/sh\n\n echo "tokei not-a-version"\n') + with pytest.raises(FakeContextAbort): + language_stats(bin_path, tmpdir / 'tree', context) + assert context.code() == StatusCode.INTERNAL + assert "Tokei version" in context.details() + assert "'tokei not-a-version'" in context.details() diff --git a/hgitaly/tests/test_workdir.py b/hgitaly/tests/test_workdir.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS90ZXN0cy90ZXN0X3dvcmtkaXIucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS90ZXN0cy90ZXN0X3dvcmtkaXIucHk= 100644 --- a/hgitaly/tests/test_workdir.py +++ b/hgitaly/tests/test_workdir.py @@ -11,6 +11,8 @@ import warnings from mercurial import error +from mercurial.merge import merge +from mercurial.node import nullrev as NULL_REVISION from hgext3rd.heptapod.branch import set_default_gitlab_branch import pytest @@ -206,6 +208,35 @@ assert parent_cs.obsolete() +@parametrize('merge_result', ('conflict', 'mergeable')) +def test_working_directory_merge(wd_fixture, merge_result): + wds_root, wrapper = wd_fixture + commit_file = wrapper.commit_file + conflict = merge_result == 'conflict' + + # a simple merge setup with a conflicting topic and a non-conflicting one + ctx0 = commit_file('foo') + cs_default = commit_file('foo', content="default") + topic_file = 'foo' if conflict else 'bar' + cs_topic = commit_file(topic_file, parent=ctx0, topic='top', content="top") + + # leaving merge result in a working directory + with working_directory(wds_root, wrapper.repo, changeset=cs_default) as wd: + default_wd_id = wd.id + stats = merge(wd.repo[cs_topic.rev()]) + if conflict: + assert stats.unresolvedcount > 0 + + # re-acquisition cleans up remnants + with working_directory(wds_root, wrapper.repo, changeset=cs_default) as wd: + assert wd.id == default_wd_id + + wctx = wd.repo[None] + assert wctx.p1() == cs_default + assert wctx.p2().rev() == NULL_REVISION + # TODO clean status (provide in mercurial_testhelpers) + + @pytest.fixture def purge_fixture(wd_fixture): wds_root, wrapper = wd_fixture diff --git a/hgitaly/util.py b/hgitaly/util.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS91dGlsLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS91dGlsLnB5 100644 --- a/hgitaly/util.py +++ b/hgitaly/util.py @@ -14,7 +14,10 @@ DEFAULT_CHUNK_SIZE = 20 -def chunked(iterable, size=DEFAULT_CHUNK_SIZE, limit=None): +def chunked(iterable, + size=DEFAULT_CHUNK_SIZE, + limit=None, + force_if_empty=False): """Return a generator of chunks out of given iterable. >>> [chunk for chunk in chunked(range(3), size=2)] @@ -37,7 +40,8 @@ chunk = [] chunk.append(val) - yield chunk + if chunk or force_if_empty: + yield chunk def chunked_with_cursor(message_class, iterable, next_cursor, builder, diff --git a/hgitaly/workdir.py b/hgitaly/workdir.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aGdpdGFseS93b3JrZGlyLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aGdpdGFseS93b3JrZGlyLnB5 100644 --- a/hgitaly/workdir.py +++ b/hgitaly/workdir.py @@ -74,7 +74,7 @@ update=False)) def command(self, name, *args, hidden=False, **kwargs): - cmd = cmdutil.findcmd(b'update', commands.table)[1][0] + cmd = cmdutil.findcmd(name, commands.table)[1][0] repo = self.repo if hidden: repo = repo.unfiltered() @@ -84,7 +84,7 @@ self.command(b'update', target_rev, clean=True, hidden=True) def purge(self): - self.command(b'purge', all=True) + self.command(b'purge', all=True, hidden=True, confirm=False) def init_repo(self, repo): weakref.finalize(repo, clear_repo_class, repo.unfiltered().__class__) diff --git a/install-requirements.txt b/install-requirements.txt index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_aW5zdGFsbC1yZXF1aXJlbWVudHMudHh0..0944dbc03457ecdaf8e5085639a35a25a2f16e62_aW5zdGFsbC1yZXF1aXJlbWVudHMudHh0 100644 --- a/install-requirements.txt +++ b/install-requirements.txt @@ -5,3 +5,4 @@ grpc-interceptor hg-loggingmod psutil +importlib_resources~=2.0.0 diff --git a/protos/commit.proto b/protos/commit.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL2NvbW1pdC5wcm90bw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL2NvbW1pdC5wcm90bw== 100644 --- a/protos/commit.proto +++ b/protos/commit.proto @@ -415,8 +415,12 @@ // OID of the object this tree entry points to string oid = 1; - // OID of the tree attached to commit_oid - string root_oid = 2; + // OID of the tree attached to commit_oid. This field is deprecated and will be removed in Gitaly + // v16.0 as it cannot be implemented efficiently without having to spawn another extra process + // that needs to get queried for every single TreeEntry. And at that point the caller can just + // manually resolve the root tree ID via a separate RPC call, especially so as there are not + // currently any known users of this feature. + string root_oid = 2 [deprecated=true]; // Path relative to repository root bytes path = 3; // This comment is left unintentionally blank. @@ -607,6 +611,13 @@ // include_shortstat determines whether to include the number of lines and files // changed in the commits. Populates the `short_stats` field. bool include_shortstat = 17; + // include_referenced_by determines whether to include references that point to a + // commit in the response. The field contains patterns that are matched against + // references. Only matching references are included in the response. For + // example, one can get tags pointing to a commit with `refs/tags`, or branches + // respectively with `refs/heads`. By sending both, the response will include all + // references that match either pattern. + repeated bytes include_referenced_by = 18; // protolint:disable:this REPEATED_FIELD_NAMES_PLURALIZED } // A single 'page' of the result set @@ -637,8 +648,11 @@ float share = 2; // Color specifies the associated color for this language, for example #3fd5e0. string color = 3; - // FileCount tells how many files with this language are found. - uint32 file_count = 4; + // FileCount was a uint32 that stored how many files with this language were found. + // However, it was never used and there is no client demand for it. + // See: https://gitlab.com/gitlab-org/gitaly/-/issues/4293. + reserved 4; + reserved "file_count"; // Bytes is the total amount of bytes written in this language uint64 bytes = 5; } diff --git a/protos/diff.proto b/protos/diff.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL2RpZmYucHJvdG8=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL2RpZmYucHJvdG8= 100644 --- a/protos/diff.proto +++ b/protos/diff.proto @@ -53,6 +53,15 @@ }; } + // GetPatchID computes a patch ID for a patch. Patch IDs are a unique ID computed by hashing + // a patch with some parameters like line numbers ignored. The patch ID can thus be used to compare + // whether diffs make the same change. Please refer to git-patch-id(1) for further information. + // If the difference between old and new change is empty then this RPC returns an error. + rpc GetPatchID(GetPatchIDRequest) returns (GetPatchIDResponse) { + option (op_type) = { + op: ACCESSOR + }; + } } // This comment is left unintentionally blank. @@ -65,9 +74,23 @@ WORDDIFF = 1; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX } + // WhiteSpaceChanges states which whitespace changes we should ignore. These options correlate to + // the ones present in git-diff(1). + enum WhitespaceChanges { + // WHITESPACE_CHANGES_UNSPECIFIED is used to not ignore any whitespace changes. This also defaults + // to the value in the deprecated field `ignore_whitespace_change` to stay backward compatible. + WHITESPACE_CHANGES_UNSPECIFIED = 0; + // WHITESPACE_CHANGES_IGNORE specifies to use the `--ignore-space-change` flag of git-diff(1). + // Only changes in amount of whitespace are ignored. + WHITESPACE_CHANGES_IGNORE = 1; + // WHITESPACE_CHANGES_IGNORE_ALL specifies to use the `--ignore-all-space` flag of git-diff(1). + // All whitespace characters are ignored when comparing lines. + WHITESPACE_CHANGES_IGNORE_ALL = 2; + } + // This comment is left unintentionally blank. Repository repository = 1 [(target_repository)=true]; // This comment is left unintentionally blank. string left_commit_id = 2; // This comment is left unintentionally blank. string right_commit_id = 3; @@ -68,11 +91,11 @@ // This comment is left unintentionally blank. Repository repository = 1 [(target_repository)=true]; // This comment is left unintentionally blank. string left_commit_id = 2; // This comment is left unintentionally blank. string right_commit_id = 3; - // This comment is left unintentionally blank. - bool ignore_whitespace_change = 4; + // This field is deprecated, use the `whitespace_changes` field instead. + bool ignore_whitespace_change = 4 [deprecated=true]; // This comment is left unintentionally blank. repeated bytes paths = 5; // This comment is left unintentionally blank. @@ -100,6 +123,15 @@ // DiffMode is the mode used for generating the diff. Please refer to the enum declaration for supported modes. DiffMode diff_mode = 15; + + // Overrides max patch bytes for file extension. + // If the file does not have an extension (eg Dockerfile), then the file name is used for matching. + // For files with more than on extension (eg file.html.tmpl) only the last extension is matched. + map<string, int32> max_patch_bytes_for_file_extension = 16; + + // WhitespaceChanges states which whitespace changes should be included in the diff. + // Please refer to the enum declaration for supported modes. + WhitespaceChanges whitespace_changes = 17; } // A CommitDiffResponse corresponds to a single changed file in a commit. @@ -312,3 +344,24 @@ // new_mode is the mode of the changed path after the change. Please refer to `old_mode` for a list of potential values. int32 new_mode = 4; } + +// GetPatchIDRequest is a request for the GetPatchID RPC. +message GetPatchIDRequest { + // Repository is the repository the patch ID shall be computed in. + Repository repository = 1 [(target_repository)=true]; + // OldRevision is the old revision that shall be used to compute the patch + // from that will then be passed to git-patch-id(1). Accepts revisions as + // specified in gitrevisions(5). + bytes old_revision = 2; + // newRevision is the new revision that shall be used to compute the patch + // from that will then be passed to git-patch-id(1). Accepts revisions as + // specified in gitrevisions(5). + bytes new_revision = 3; +} + +// GetPatchIDResponse is a response for the GetPatchID RPC. +message GetPatchIDResponse { + // PatchId is the patch ID that was generated by hashing the diff of the + // given old and new revision. + string patch_id = 1; +} diff --git a/protos/log.proto b/protos/log.proto new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL2xvZy5wcm90bw== --- /dev/null +++ b/protos/log.proto @@ -0,0 +1,47 @@ +syntax = "proto3"; + +package gitaly; + +option go_package = "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb"; + +// LogEntry is a single entry in a repository's write-ahead log. +// +// Schema for : +// - `repository/<repository_id>/log/entry/<log_index>`. +message LogEntry { + // ReferenceUpdate models a single reference update. + message ReferenceUpdate { + // reference_name is the fully qualified name of the reference + // to update. + bytes reference_name = 1; + // new_oid is the new oid to point the reference to. Deletions + // are denoted as the SHA1 or SHA256 zero OID depending on the + // hash type used in the repository. + bytes new_oid = 2; + } + + // DefaultBranchUpdate models a default branch update. + message DefaultBranchUpdate { + // reference_name is the fully qualified name of the reference + // to update the default branch to. + bytes reference_name = 1; + } + + // reference_updates contains the reference updates this log + // entry records. The logged reference updates have already passed + // through verification and are applied without any further checks. + repeated ReferenceUpdate reference_updates = 1; + // default_branch_update contains the information pertaining to updating + // the default branch of the repo. + DefaultBranchUpdate default_branch_update = 2; +} + +// LogIndex serializes a log index. It's used for storing a repository's +// applied log index in the database. +// +// Schema for: +// - `repository/<repository_id>/log/index/applied` +message LogIndex { + // log_index is an index pointing to a position in the log. + uint64 log_index = 1; +} diff --git a/protos/mercurial-operations.proto b/protos/mercurial-operations.proto new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL21lcmN1cmlhbC1vcGVyYXRpb25zLnByb3Rv --- /dev/null +++ b/protos/mercurial-operations.proto @@ -0,0 +1,48 @@ +syntax = "proto3"; + +package hgitaly; + +import "lint.proto"; +import "shared.proto"; + +service MercurialOperationsService { + + // Provide all information for a possible merge + // + // Will be used in mergeability checks and last-minute checks if needed. + rpc MergeAnalysis(MergeAnalysisRequest) returns (MergeAnalysisResponse) { + option (.gitaly.op_type) = { + op: ACCESSOR + }; + } + +} + +message MergeAnalysisRequest { + .gitaly.Repository repository = 1 [(.gitaly.target_repository)=true]; + bytes source_revision = 2; + bytes target_revision = 3; + // Conflicts checks are expensive (involve using a temporary working + // directory) and are always skipped in fast-forward situations. + // However it is worthwile to avoid them if the merge is not + // a fast-forward and that is all the caller wants to know. + bool skip_conflicts_check = 4; +} + +message MergeAnalysisResponse { + bool is_fast_forward = 1; + bool has_obsolete_changesets = 2; + bool has_unstable_changesets = 3; + // `has_conflicts` is evaluated unless + // (is_fast_forward OR has_obsolete_changesets OR has_instable changesets) + bool has_conflicts = 4; + bool target_is_public = 5; + // topic information is retrieved only for non-public changesets + // (standard vanishing property as in the Mercurial CLI by default) + string target_node_id = 6; + bytes target_branch = 7; + bytes target_topic = 8; + string source_node_id = 9; + bytes source_branch = 10; + bytes source_topic = 11; +} diff --git a/protos/objectpool.proto b/protos/objectpool.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL29iamVjdHBvb2wucHJvdG8=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL29iamVjdHBvb2wucHJvdG8= 100644 --- a/protos/objectpool.proto +++ b/protos/objectpool.proto @@ -7,9 +7,26 @@ option go_package = "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb"; -// ObjectPoolService is a service containing RPCs to manipulate object pools. -// An object pool is a separate repository that can be linked to from multiple -// satellite repositories in order to deduplicate common objects between them. -// This is mostly used in the contexet of repository forks. +// ObjectPoolService is a service that manages the lifetime of object pools. +// +// An object pool is a separate repository that can be linked to from multiple object pool members +// in order to deduplicate common objects between them. This is mostly used in the context of +// repository forks. +// +// The typical lifetime of an object pool is as follows: +// +// 1. An object pool is created via CreateObjectPool from its primary pool member. Typically this +// would be the repository that gets forked. +// 2. One or more repositories are linked to the object pool via LinkRepositoryToObjectPool. Each +// object pool member linked to the repository will have its objects deduplicated when its +// objects get repacked the next time. +// 3. The object pool is regularly updated via FetchIntoObjectPool. This is typically only done from +// the primary object pool member. +// 4. Repositories may leave the object pool via DisconnectGitAlternates. There is not much of a +// reason to do this for any repositories except for the primary object pool member in case it +// for example becomes private. +// 5. When the object pool does not have any members anymore it gets deleted via DeleteObjectPool. +// It is the responsibility of the caller to ensure that it really has no members left, else +// any existing member will become corrupt. service ObjectPoolService { @@ -14,9 +31,13 @@ service ObjectPoolService { - // This comment is left unintentionally blank. + // CreateObjectPool creates an object pool from a specific source repository. It will create the + // object pool by cloning all contents from that source repository. The source repository will not + // automatically be linked to the object pool, you need to call LinkRepositoryToObjectPool for + // this. If the object pool exists already this RPC returns an error with the FailedPrecondition + // gRPC error code. rpc CreateObjectPool(CreateObjectPoolRequest) returns (CreateObjectPoolResponse) { option (op_type) = { op: MUTATOR }; } @@ -17,13 +38,14 @@ rpc CreateObjectPool(CreateObjectPoolRequest) returns (CreateObjectPoolResponse) { option (op_type) = { op: MUTATOR }; } - // This comment is left unintentionally blank. + // DeleteObjectPool deletes the object pool. There are no safety checks in place, so if any + // repository is still using this object pool it will become corrupted. rpc DeleteObjectPool(DeleteObjectPoolRequest) returns (DeleteObjectPoolResponse) { option (op_type) = { op: MUTATOR }; } @@ -24,13 +46,14 @@ rpc DeleteObjectPool(DeleteObjectPoolRequest) returns (DeleteObjectPoolResponse) { option (op_type) = { op: MUTATOR }; } - // Repositories are assumed to be stored on the same disk + // LinkRepositoryToObjectPool links the specified repository to the object pool. Objects contained + // in the object pool will be deduplicated for this repository when repacking objects. rpc LinkRepositoryToObjectPool(LinkRepositoryToObjectPoolRequest) returns (LinkRepositoryToObjectPoolResponse) { option (op_type) = { op: MUTATOR }; } @@ -31,8 +54,13 @@ rpc LinkRepositoryToObjectPool(LinkRepositoryToObjectPoolRequest) returns (LinkRepositoryToObjectPoolResponse) { option (op_type) = { op: MUTATOR }; } - // This comment is left unintentionally blank. + // ReduplicateRepository will repack the objects in the object pool member so that the repository + // does not depend on the pool member anymore and can be removed from it. Note that this function + // is not safe for use. + // + // This RPC is deprecated. Please use DisconnectGitAlternates instead. It will be removed in + // Gitaly v16.0, refer to https://gitlab.com/gitlab-org/gitaly/-/issues/4655. rpc ReduplicateRepository(ReduplicateRepositoryRequest) returns (ReduplicateRepositoryResponse) { @@ -38,6 +66,7 @@ rpc ReduplicateRepository(ReduplicateRepositoryRequest) returns (ReduplicateRepositoryResponse) { + option deprecated = true; option (op_type) = { op: MUTATOR }; } @@ -39,9 +68,22 @@ option (op_type) = { op: MUTATOR }; } - // This comment is left unintentionally blank. + // DisconnectGitAlternates will disconnect the object pool member from its object pool. It will: + // + // 1. Link all objects from the object pool into the member repository. This essenitally + // reduplicates previously-duplicated objects so that the repository will continue to function + // after being unlinked. + // 2. Remove the alternates link to the object pool. + // 3. Perform a consistency check to assert that the repository is indeed fully functional after + // unlinking it from its pool. If the consistency check fails the alternates link is restored + // an the RPC fails. + // + // If successful, the object pool member is disconnected from the object pool and does not depend + // on it anymore. + // + // This RPC does not return an error in case the repository is not linked to any object pool. rpc DisconnectGitAlternates(DisconnectGitAlternatesRequest) returns (DisconnectGitAlternatesResponse) { option (op_type) = { op: MUTATOR @@ -58,7 +100,8 @@ }; } - // This comment is left unintentionally blank. + // GetObjectPool returns the object pool a repository is connected to. If the repository is not + // connected to a pool then this RPC returns successfully with an empty response. rpc GetObjectPool(GetObjectPoolRequest) returns (GetObjectPoolResponse) { option (op_type) = { op: ACCESSOR @@ -67,6 +110,5 @@ } -// Creates an object pool from the repository. The client is responsible for -// joining this pool later with this repository. +// CreatesObjectPoolRequest is a request for the CreateObjectPool RPC. message CreateObjectPoolRequest { @@ -72,3 +114,4 @@ message CreateObjectPoolRequest { - // This comment is left unintentionally blank. + // ObjectPool is the object pool to create. This field controls where exactly the object pool will + // be created. ObjectPool object_pool = 1 [(target_repository)=true]; @@ -74,5 +117,5 @@ ObjectPool object_pool = 1 [(target_repository)=true]; - // This comment is left unintentionally blank. + // Origin is the repository from which the object pool shall be created. Repository origin = 2 [(additional_repository)=true]; } @@ -76,7 +119,7 @@ Repository origin = 2 [(additional_repository)=true]; } -// This comment is left unintentionally blank. +// CreateObjectPoolResponse is a response for the CreateObjectPool RPC. message CreateObjectPoolResponse { } @@ -80,6 +123,5 @@ message CreateObjectPoolResponse { } -// Removes the directory from disk, caller is responsible for leaving the object -// pool before calling this RPC +// DeleteObjectPoolRequest is a request for the DeleteObjectPool RPC. message DeleteObjectPoolRequest { @@ -85,5 +127,5 @@ message DeleteObjectPoolRequest { - // This comment is left unintentionally blank. + // ObjectPool is the object pool that shall be deleted. ObjectPool object_pool = 1 [(target_repository)=true]; } @@ -87,7 +129,7 @@ ObjectPool object_pool = 1 [(target_repository)=true]; } -// This comment is left unintentionally blank. +// DeleteObjectPoolResponse is a response for the DeleteObjectPool RPC. message DeleteObjectPoolResponse { } @@ -91,5 +133,5 @@ message DeleteObjectPoolResponse { } -// This comment is left unintentionally blank. +// LinkRepositoryToObjectPoolRequest is a request for the LinkRepositoryToObjectPool RPC. message LinkRepositoryToObjectPoolRequest { @@ -95,3 +137,3 @@ message LinkRepositoryToObjectPoolRequest { - // This comment is left unintentionally blank. + // ObjectPool is the object pool to which the repository shall be linked to. ObjectPool object_pool = 1 [(additional_repository)=true]; @@ -97,5 +139,5 @@ ObjectPool object_pool = 1 [(additional_repository)=true]; - // This comment is left unintentionally blank. + // Repository is the repository that shall be linked to the object pool. Repository repository = 2 [(target_repository)=true]; } @@ -99,7 +141,7 @@ Repository repository = 2 [(target_repository)=true]; } -// This comment is left unintentionally blank. +// LinkRepositoryToObjectPoolResponse is a response for the LinkRepositoryToObjectPool RPC. message LinkRepositoryToObjectPoolResponse { } @@ -103,5 +145,5 @@ message LinkRepositoryToObjectPoolResponse { } -// This comment is left unintentionally blank. +// ReduplicateRepositoryRequest is a request for the ReduplicateRepository RPC. message ReduplicateRepositoryRequest { @@ -107,5 +149,5 @@ message ReduplicateRepositoryRequest { - // This comment is left unintentionally blank. + // Repository is the repository whose objects shall be reduplicated. Repository repository = 1 [(target_repository)=true]; } @@ -109,7 +151,7 @@ Repository repository = 1 [(target_repository)=true]; } -// This comment is left unintentionally blank. +// ReduplicateRepositoryResponse is a response for the ReduplicateRepository RPC. message ReduplicateRepositoryResponse { } @@ -113,5 +155,5 @@ message ReduplicateRepositoryResponse { } -// This comment is left unintentionally blank. +// DisconnectGitAlternatesRequest is a request for the DisconnectGitAlternates RPC. message DisconnectGitAlternatesRequest { @@ -117,5 +159,5 @@ message DisconnectGitAlternatesRequest { - // This comment is left unintentionally blank. + // Repository is th repository that shall be disconnected from its object pool. Repository repository = 1 [(target_repository)=true]; } @@ -119,7 +161,7 @@ Repository repository = 1 [(target_repository)=true]; } -// This comment is left unintentionally blank. +// DisconnectGitAlternatesResponse is a response for the DisconnectGitAlternates RPC. message DisconnectGitAlternatesResponse { } @@ -140,5 +182,5 @@ message FetchIntoObjectPoolResponse { } -// This comment is left unintentionally blank. +// GetObjectPoolRequest is a request for the GetObjectPool RPC. message GetObjectPoolRequest { @@ -144,5 +186,5 @@ message GetObjectPoolRequest { - // This comment is left unintentionally blank. + // Repository is the repository for which the object pool shall be retrieved. Repository repository = 1 [(target_repository)=true]; } @@ -146,5 +188,5 @@ Repository repository = 1 [(target_repository)=true]; } -// This comment is left unintentionally blank. +// GetObjectDirectorySizeResponse is a response for the GetObjectPool RPC. message GetObjectPoolResponse { @@ -150,4 +192,5 @@ message GetObjectPoolResponse { - // This comment is left unintentionally blank. + // ObjectPool is the object pool the repository is connected to. If the repository is not + // connected to any object pool, then this field will be empty. ObjectPool object_pool = 1; } diff --git a/protos/operations.proto b/protos/operations.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL29wZXJhdGlvbnMucHJvdG8=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL29wZXJhdGlvbnMucHJvdG8= 100644 --- a/protos/operations.proto +++ b/protos/operations.proto @@ -228,6 +228,14 @@ // perform access checks against the Rails `/internal/allowed` API. This user is also exposed to // any custom hooks executed as part of this RPC call. User user = 3; + // expected_old_oid is the object ID which branch is expected to point to. + // This is used as a safety guard to avoid races when branch has been + // updated meanwhile to point to a different object ID. + // + // If unset, the target branch will be deleted regardless of its current + // state. If set, it must either contain a valid, full object ID. Otherwise, this + // RPC will return an error. + string expected_old_oid = 4; } // UserDeleteBranchResponse is a response for the UserDeleteBranch RPC. @@ -260,6 +268,14 @@ bytes tag_name = 2; // This comment is left unintentionally blank. User user = 3; + // expected_old_oid is the object ID which tag is expected to point to. + // This is used as a safety guard to avoid races when tag has been + // updated meanwhile to point to a different object ID. + // + // If unset, the target tag will be deleted regardless of its current + // state. If set, it must either contain a valid, full object ID. Otherwise, + // this RPC will return an error. + string expected_old_oid = 4; } // This comment is left unintentionally blank. @@ -341,6 +357,15 @@ // timestamp is the optional timestamp to use for the merge commit. If it's // not set, the current time will be used. google.protobuf.Timestamp timestamp = 7; + // expected_old_oid is the object ID which branch is expected to point to. + // This is used as a safety guard to avoid races when branch has been + // updated meanwhile to point to a different object ID. + // + // If unset, the target branch will be overwritten regardless of its current + // state. If set, it must either contain a valid, full object ID or the + // zero object ID in case the branch should be created. Otherwise, this RPC + // will return an error. + string expected_old_oid = 8; // apply must only be set in the second message. Only if this second message // is sent and if apply is set to true will the branch be updated to point to @@ -449,6 +474,15 @@ // branch name only and not a fully qualified reference, e.g. "master" // instead of "refs/heads/master". bytes branch = 4; + // expected_old_oid is the object ID which branch is expected to point to. + // This is used as a safety guard to avoid races when branch has been + // updated meanwhile to point to a different object ID. + // + // If unset, the target branch will be overwritten regardless of its current + // state. If set, it must either contain a valid, full object ID or the + // zero object ID in case the branch should be created. Otherwise, this RPC + // will return an error. + string expected_old_oid = 5; } // This comment is left unintentionally blank. @@ -486,6 +520,16 @@ // timestamp is the optional timestamp to use for the created cherry-picked // commit's committer date. If it's not set, the current time will be used. google.protobuf.Timestamp timestamp = 9; + // expected_old_oid is the object ID which branch is expected to point to. + // This is used as a safety guard to avoid races when branch has been + // updated meanwhile to point to a different object ID. Only applicable when + // branch_name is set. + // + // If unset, the target branch will be overwritten regardless of its current + // state. If set, it must either contain a valid, full object ID or the + // zero object ID in case the branch should be created. Otherwise, this RPC + // will return an error. + string expected_old_oid = 10; } // This comment is left unintentionally blank. @@ -566,6 +610,16 @@ // timestamp is the optional timestamp to use for the created cherry-picked // commit's committer date. If it's not set, the current time will be used. google.protobuf.Timestamp timestamp = 9; + // expected_old_oid is the object ID which branch is expected to point to. + // This is used as a safety guard to avoid races when branch has been + // updated meanwhile to point to a different object ID. Only applicable when + // branch_name is set. + // + // If unset, the target branch will be overwritten regardless of its current + // state. If set, it must either contain a valid, full object ID or the + // zero object ID in case the branch should be created. Otherwise, this RPC + // will return an error. + string expected_old_oid = 10; } // This comment is left unintentionally blank. @@ -687,6 +741,16 @@ // timestamp is the optional timestamp to use for the commits as author and // committer date. If it's not set, the current time will be used. google.protobuf.Timestamp timestamp = 11; + // expected_old_oid is the object ID which branch is expected to point to. + // This is used as a safety guard to avoid races when branch has been + // updated meanwhile to point to a different object ID. Only applicable when + // branch_name is set. + // + // If unset, the target branch will be overwritten regardless of its current + // state. If set, it must either contain a valid, full object ID or the + // zero object ID in case the branch should be created. Otherwise, this RPC + // will return an error. + string expected_old_oid = 12; } // UserCommitFiles is the request of UserCommitFiles. @@ -866,6 +930,15 @@ // timestamp is the optional timestamp to use for the squashed commit as // committer date. If it's not set, the current time will be used. google.protobuf.Timestamp timestamp = 4; + // expected_old_oid is the object ID which branch is expected to point to. + // This is used as a safety guard to avoid races when branch has been + // updated meanwhile to point to a different object ID. + // + // If unset, the target branch will be overwritten regardless of its current + // state. If set, it must either contain a valid, full object ID or the + // zero object ID in case the branch should be created. Otherwise, this RPC + // will return an error. + string expected_old_oid = 5; } oneof user_apply_patch_request_payload { @@ -903,6 +976,15 @@ // submodule as committer date. If it's not set, the current time will be // used. google.protobuf.Timestamp timestamp = 7; + // expected_old_oid is the object ID which branch is expected to point to. + // This is used as a safety guard to avoid races when branch has been + // updated meanwhile to point to a different object ID. + // + // If unset, the target branch will be overwritten regardless of its current + // state. If set, it must either contain a valid, full object ID or the + // zero object ID in case the branch should be created. Otherwise, this RPC + // will return an error. + string expected_old_oid = 8; } // This comment is left unintentionally blank. diff --git a/protos/ref.proto b/protos/ref.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL3JlZi5wcm90bw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL3JlZi5wcm90bw== 100644 --- a/protos/ref.proto +++ b/protos/ref.proto @@ -19,8 +19,10 @@ }; } - // This comment is left unintentionally blank. + // FindAllBranchNames is deprecated in favor of ListRefs + // + // https://gitlab.com/gitlab-org/gitaly/-/issues/3966 rpc FindAllBranchNames(FindAllBranchNamesRequest) returns (stream FindAllBranchNamesResponse) { option (op_type) = { op: ACCESSOR }; @@ -23,7 +25,7 @@ rpc FindAllBranchNames(FindAllBranchNamesRequest) returns (stream FindAllBranchNamesResponse) { option (op_type) = { op: ACCESSOR }; - + option deprecated = true; } @@ -28,7 +30,9 @@ } - // This comment is left unintentionally blank. + // FindAllTagNames is deprecated in favor of ListRefs + // + // https://gitlab.com/gitlab-org/gitaly/-/issues/3966 rpc FindAllTagNames(FindAllTagNamesRequest) returns (stream FindAllTagNamesResponse) { option (op_type) = { op: ACCESSOR }; @@ -31,7 +35,8 @@ rpc FindAllTagNames(FindAllTagNamesRequest) returns (stream FindAllTagNamesResponse) { option (op_type) = { op: ACCESSOR }; + option deprecated = true; } // Return a stream so we can divide the response in chunks of branches @@ -587,6 +592,13 @@ bool head = 3; // SortBy allows to request SHAs in particular order. SortBy sort_by = 4; + // PointingAtOids is a list of OIDs that can optionally be passed to only return refs + // pointing at the given OIDs. This corresponds to the --points-at option of git-for-each-ref(1). + repeated bytes pointing_at_oids = 5; + // PeelTags controls whether annotated tags should be peeled to their target objects so that the + // `PeeledTarget` returned for the reference is the ID of the target object. Note that this + // will significantly slow down the request by a factor of 3 to 4. + bool peel_tags = 6; } // ListRefsResponse is a response for the ListRefs RPC. The RPC can return multiple responses @@ -598,6 +610,9 @@ bytes name = 1; // Target is the object ID the reference points to. string target = 2; + // PeeledTarget is the object ID an annotated tag points to. This field is only set when + // `PeelTags=true`. This field is empty in case the object is not an annotated tag. + string peeled_target = 3; } // References is the set of references returned by the RPC. diff --git a/protos/repository.proto b/protos/repository.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL3JlcG9zaXRvcnkucHJvdG8=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL3JlcG9zaXRvcnkucHJvdG8= 100644 --- a/protos/repository.proto +++ b/protos/repository.proto @@ -64,6 +64,13 @@ }; } + // ObjectFormat determines the object format that is being used by the repository. + rpc ObjectFormat(ObjectFormatRequest) returns (ObjectFormatResponse) { + option (op_type) = { + op: ACCESSOR + }; + } + // This comment is left unintentionally blank. rpc ApplyGitattributes(ApplyGitattributesRequest) returns (ApplyGitattributesResponse) { option (op_type) = { @@ -108,7 +115,8 @@ }; } - // This comment is left unintentionally blank. + // Fsck checks the repository for consistency via git-fsck(1). This can be used to check for + // repository corruption. rpc Fsck(FsckRequest) returns (FsckResponse) { option (op_type) = { op: ACCESSOR @@ -182,7 +190,8 @@ }; } - // This comment is left unintentionally blank. + // FindLicense looks in the given repository and attempts to detect all the + // details about the license used in the repository. rpc FindLicense(FindLicenseRequest) returns (FindLicenseResponse) { option (op_type) = { op: ACCESSOR @@ -246,8 +255,10 @@ }; } - // This comment is left unintentionally blank. + // RestoreCustomHooks sets the git hooks for a repository. The hooks are sent + // in a tar archive containing a `custom_hooks` directory. This directory is + // ultimately extracted to the repository. rpc RestoreCustomHooks(stream RestoreCustomHooksRequest) returns (RestoreCustomHooksResponse) { option (op_type) = { op: MUTATOR }; @@ -250,6 +261,16 @@ rpc RestoreCustomHooks(stream RestoreCustomHooksRequest) returns (RestoreCustomHooksResponse) { option (op_type) = { op: MUTATOR }; + option deprecated = true; + } + + // SetCustomHooks sets the git hooks for a repository. The hooks are sent in a + // tar archive containing a `custom_hooks` directory. This directory is + // ultimately extracted to the repository. + rpc SetCustomHooks(stream SetCustomHooksRequest) returns (SetCustomHooksResponse) { + option (op_type) = { + op: MUTATOR + }; } @@ -254,7 +275,9 @@ } - // This comment is left unintentionally blank. + // BackupCustomHooks fetches the git hooks for a repository. The hooks are + // sent in a tar archive containing a `custom_hooks` directory. If no hooks + // are present in the repository, the response will have no data. rpc BackupCustomHooks(BackupCustomHooksRequest) returns (stream BackupCustomHooksResponse) { option (op_type) = { op: ACCESSOR }; @@ -257,7 +280,17 @@ rpc BackupCustomHooks(BackupCustomHooksRequest) returns (stream BackupCustomHooksResponse) { option (op_type) = { op: ACCESSOR }; + option deprecated = true; + } + + // GetCustomHooks fetches the git hooks for a repository. The hooks are sent + // in a tar archive containing a `custom_hooks` directory. If no hooks are + // present in the repository, the response will have no data. + rpc GetCustomHooks(GetCustomHooksRequest) returns (stream GetCustomHooksResponse) { + option (op_type) = { + op: ACCESSOR + }; } // This comment is left unintentionally blank. @@ -324,6 +357,7 @@ // an admin inspects the repository's gitconfig such that he can easily see // what the repository name is. rpc SetFullPath(SetFullPathRequest) returns (SetFullPathResponse) { + option deprecated = true; option (op_type) = { op: MUTATOR }; @@ -332,7 +366,8 @@ // FullPath reads the "gitlab.fullpath" configuration from the repository's // gitconfig. Returns an error in case the full path has not been configured. rpc FullPath(FullPathRequest) returns (FullPathResponse) { + option deprecated = true; option (op_type) = { op: ACCESSOR }; } @@ -335,7 +370,12 @@ option (op_type) = { op: ACCESSOR }; } + + // RemoveAll deletes all repositories on a specified storage. + rpc RemoveAll(RemoveAllRequest) returns (RemoveAllResponse) { + option (intercepted_method) = true; + } } // This comment is left unintentionally blank. @@ -442,6 +482,18 @@ int64 size = 1; } +// ObjectFormatRequest is a request for the ObjectFormat RPC. +message ObjectFormatRequest { + // Repository is the repository for which to determine the object format. + Repository repository = 1 [(target_repository)=true]; +} + +// ObjectFormatResponse is a response for the ObjectFormat RPC. +message ObjectFormatResponse { + // Format is the object format that the repository uses. + ObjectFormat format = 1; +} + // This comment is left unintentionally blank. message ApplyGitattributesRequest { // This comment is left unintentionally blank. @@ -517,6 +569,10 @@ // repository. Note, this will be treated as the branch name and not a // fully qualified reference. bytes default_branch = 2; + // ObjectFormat is the object format the repository should be created with. Note that this is + // experimental and should not be used by callers yet. It is mostly intended for internal testing + // purposes in Gitaly right now. + ObjectFormat object_format = 3; } // This comment is left unintentionally blank. @@ -600,5 +656,5 @@ bool result = 1; } -// This comment is left unintentionally blank. +// FsckRequest is a request for the Fsck RPC. message FsckRequest { @@ -604,5 +660,5 @@ message FsckRequest { - // This comment is left unintentionally blank. + // Repository is the repository that shall be checked for consistency. Repository repository = 1 [(target_repository)=true]; } @@ -606,5 +662,5 @@ Repository repository = 1 [(target_repository)=true]; } -// This comment is left unintentionally blank. +// FsckResponse is a response for the Fsck RPC. message FsckResponse { @@ -610,5 +666,5 @@ message FsckResponse { - // This comment is left unintentionally blank. + // Error contains both stdout and stderr of git-fsck(1) in case it returned an error. bytes error = 1; } @@ -748,7 +804,15 @@ } // This comment is left unintentionally blank. +message SetCustomHooksRequest { + // This comment is left unintentionally blank. + Repository repository = 1 [(target_repository)=true]; + // This comment is left unintentionally blank. + bytes data = 2; +} + +// This comment is left unintentionally blank. message RestoreCustomHooksResponse { } // This comment is left unintentionally blank. @@ -751,10 +815,14 @@ message RestoreCustomHooksResponse { } // This comment is left unintentionally blank. +message SetCustomHooksResponse { +} + +// This comment is left unintentionally blank. message BackupCustomHooksRequest { // This comment is left unintentionally blank. Repository repository = 1 [(target_repository)=true]; } // This comment is left unintentionally blank. @@ -755,12 +823,18 @@ message BackupCustomHooksRequest { // This comment is left unintentionally blank. Repository repository = 1 [(target_repository)=true]; } // This comment is left unintentionally blank. +message GetCustomHooksRequest { + // This comment is left unintentionally blank. + Repository repository = 1 [(target_repository)=true]; +} + +// This comment is left unintentionally blank. message BackupCustomHooksResponse { // This comment is left unintentionally blank. bytes data = 1; } // This comment is left unintentionally blank. @@ -761,9 +835,15 @@ message BackupCustomHooksResponse { // This comment is left unintentionally blank. bytes data = 1; } // This comment is left unintentionally blank. +message GetCustomHooksResponse { + // This comment is left unintentionally blank. + bytes data = 1; +} + +// This comment is left unintentionally blank. message CreateRepositoryFromBundleRequest { // Only available on the first message Repository repository = 1 [(target_repository)=true]; @@ -775,5 +855,5 @@ message CreateRepositoryFromBundleResponse { } -// This comment is left unintentionally blank. +// FindLicenseRequest asks to detect the license for the given repository. message FindLicenseRequest { @@ -779,5 +859,5 @@ message FindLicenseRequest { - // This comment is left unintentionally blank. + // Repository is repository where to detect the license. Repository repository = 1 [(target_repository)=true]; } @@ -794,6 +874,8 @@ // LicenseUrl is a URL to the license on the internet. string license_url = 3; // LicensePath is a path to the file that contains the text of the license. + // When a LICENSE file is found containing the filename of another file, + // that filename will be returned, for example "mit.txt". string license_path = 4; // LicenseNickname is a shortened full name for better readability. // It exists only for a small set of licenses and an empty value is returned in most cases. @@ -949,7 +1031,7 @@ // This comment is left unintentionally blank. message SearchFilesByNameResponse { - // This comment is left unintentionally blank. + // Files contains the paths of files that have been found to match the query. repeated bytes files = 1; } @@ -1062,5 +1144,5 @@ message ReplicateRepositoryResponse{ } -// This comment is left unintentionally blank. +// OptimizeRepositoryRequest is a request for the OptimizeRepository RPC. message OptimizeRepositoryRequest { @@ -1066,3 +1148,17 @@ message OptimizeRepositoryRequest { - // This comment is left unintentionally blank. + // Strategy determines how the repository shall be optimized. + enum Strategy { + // STRATEGY_UNSPECIFIED indicates that the strategy has not been explicitly set by the + // caller. The default will be STRATEGY_HEURISTICAL in that case. + STRATEGY_UNSPECIFIED = 0; + // STRATEGY_HEURISTICAL performs heuristical optimizations in the repository. The server will + // decide on a set of heuristics which parts need optimization and which ones don't to avoid + // performing unnecessary optimization tasks. + STRATEGY_HEURISTICAL = 1; + // STRATEGY_EAGER performs eager optimizations in the repository. The server will optimize all + // data structures regardless of whether they are well-optimized already. + STRATEGY_EAGER = 2; + } + + // Repository is the repository that should be optimized. Repository repository = 1 [(target_repository)=true]; @@ -1068,3 +1164,5 @@ Repository repository = 1 [(target_repository)=true]; + // Strategy is the strategy that determines which parts of the repository shall be optimized. + Strategy strategy = 2; } @@ -1069,7 +1167,7 @@ } -// This comment is left unintentionally blank. -message OptimizeRepositoryResponse{ +// OptimizeRepositoryResponse is a response for the OptimizeRepository RPC. +message OptimizeRepositoryResponse { } // PruneUnreachableObjectsRequest is a request for the PruneUnreachableObjects @@ -1107,3 +1205,13 @@ // Path read from the "gitlab.fullpath" config key. string path = 1; } + +// RemoveAll is a request for the RemoveAll RPC. +message RemoveAllRequest { + // StorageName of the storage to have all repositories removed from. + string storage_name = 1; +} + +// RemoveAllResponse is a response for the RemoveAll RPC. +message RemoveAllResponse { +} diff --git a/protos/server.proto b/protos/server.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL3NlcnZlci5wcm90bw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL3NlcnZlci5wcm90bw== 100644 --- a/protos/server.proto +++ b/protos/server.proto @@ -79,7 +79,7 @@ // ClockSyncedRequest contains settings to be used for the system clock synchronisation check. message ClockSyncedRequest { // NtpHost is a URL to the external NTP service that should be used for clock sync check. - // Default is "ntp.pool.org" + // Default is "pool.ntp.org" string ntp_host = 1; reserved "drift_threshold_millis"; reserved 2; diff --git a/protos/service_config.proto b/protos/service_config.proto new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL3NlcnZpY2VfY29uZmlnLnByb3Rv --- /dev/null +++ b/protos/service_config.proto @@ -0,0 +1,82 @@ +syntax = "proto3"; + +package gitaly; + +import "google/protobuf/duration.proto"; +import "google/protobuf/wrappers.proto"; + +option go_package = "gitlab.com/gitlab-org/gitaly/v15/proto/go/gitalypb"; + +// ServiceConfig defines the configuration that allows service owners to publish parameters to be +// automatically used by all clients of their service. gRPC doesn't export this protobuf. So, we +// built a minimized version to for Gitaly use. The completed version is defined at +// https://github.com/grpc/grpc-proto/blob/master/grpc/service_config/service_config.proto +message ServiceConfig { + // protolint:disable:next REPEATED_FIELD_NAMES_PLURALIZED + repeated LoadBalancingConfig load_balancing_config = 1; + // protolint:disable:next REPEATED_FIELD_NAMES_PLURALIZED + repeated MethodConfig method_config = 2; +} + +// LoadBalancingConfig wraps around the round-robin strategies. Only one strategy can be selected. +message LoadBalancingConfig { + oneof policy { + // PickFirst strategy + PickFirstConfig pick_first = 1 [json_name = "pick_first"]; + // RoundRobin strategy + RoundRobinConfig round_robin = 2 [json_name = "round_robin"]; + } +} + +// PickFirstConfig signals the pick_first load-balancing strategy. This strategy is the default +// strategy of grpc client libraries so that the connection has only one subchannel, which is the +// first address after resolution +message PickFirstConfig { +} + +// RoundRobinConfig indicates the round_robin strategy. This strategy distributes the incoming +// requests to active subchannels in a round-robin fashion. +message RoundRobinConfig { +} + +// Configuration for a method. +message MethodConfig { + // Name is an object indicating which services/methods being affected by the config + message Name { + // service is name of the service,including its package. For example: gitaly.SmartHTTPService + string service = 1; + // method is the name of the method within the above service. Empty method name implies the + // method policy is effective for all methods of the service + string method = 2; + } + + // RetryPolicy defines the configuration for exponential backoff when a request fails + message RetryPolicy { + // max_attempts is the total retry attempts client perform before bailing out + uint32 max_attempts = 1; + // initial_backoff is the minimum delay for the first retries + google.protobuf.Duration initial_backoff = 2; + // max_backoff is the minimum delay + google.protobuf.Duration max_backoff = 3; + // backoff_multiplier is the factor determining "how fast" the delay increases after each retry + float backoff_multiplier = 4; + // retryable_status_codes defines the list of eligible status codes. The status must be in + // capitalized snake_case form. For example, UNAVAILABLE, FAILED_PRECONDITION + repeated string retryable_status_codes = 5; + } + + // name defines the list of affected services/methods + // The name should be is the definition of grpc. Nothing we can do about it + // protolint:disable:next REPEATED_FIELD_NAMES_PLURALIZED + repeated Name name = 1; + // The following fields are unused by Gitaly at the moment. Please refer to the original + // documentation for more information + // protolint:disable FIELDS_HAVE_COMMENT + google.protobuf.BoolValue wait_for_ready = 2; + google.protobuf.Duration timeout = 3; + google.protobuf.UInt32Value max_request_message_bytes = 4; + google.protobuf.UInt32Value max_response_message_bytes = 5; + // protolint:enable FIELDS_HAVE_COMMENT + // retry_policy defines the exponential backoff configuration for the affected services/methods + RetryPolicy retry_policy = 6; +} diff --git a/protos/shared.proto b/protos/shared.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL3NoYXJlZC5wcm90bw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL3NoYXJlZC5wcm90bw== 100644 --- a/protos/shared.proto +++ b/protos/shared.proto @@ -21,6 +21,17 @@ TAG = 4; // protolint:disable:this ENUM_FIELD_NAMES_PREFIX } +// ObjectFormat is the object format that a Git repository can use. +enum ObjectFormat { + // OBJECT_FORMAT_UNSPECIFIED is the default object type when it has not been explicitly requested + // by the client. Defaults to OBJECT_FORMAT_SHA1. + OBJECT_FORMAT_UNSPECIFIED = 0; + // OBJECT_FORMAT_SHA1 is the object format based on the SHA1 hash. + OBJECT_FORMAT_SHA1 = 1; + // OBJECT_FORMAT_SHA256 is the object format based on the SHA256 hash. This is experimental. + OBJECT_FORMAT_SHA256 = 2; +} + // This comment is left unintentionally blank. enum SignatureType { // This comment is left unintentionally blank. @@ -114,6 +125,14 @@ // The stats include additions, deletions and changed_files, // they are only set when `include_shortstat == true`. CommitStatInfo short_stats = 11; + // referenced_by contains fully-qualified reference names (e.g refs/heads/main) + // that point to the commit. + repeated bytes referenced_by = 12; // protolint:disable:this REPEATED_FIELD_NAMES_PLURALIZED + // The encoding of the commit message. This field will only be present if + // `i18n.commitEncoding` was set to a value other than "UTF-8" at the time + // this commit was made. + // See: https://git-scm.com/docs/git-commit#_discussion + string encoding = 13; } // This comment is left unintentionally blank. diff --git a/protos/smarthttp.proto b/protos/smarthttp.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cHJvdG9zL3NtYXJ0aHR0cC5wcm90bw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cHJvdG9zL3NtYXJ0aHR0cC5wcm90bw== 100644 --- a/protos/smarthttp.proto +++ b/protos/smarthttp.proto @@ -28,13 +28,6 @@ }; } - // Request and response body for POST /upload-pack - rpc PostUploadPack(stream PostUploadPackRequest) returns (stream PostUploadPackResponse) { - option (op_type) = { - op: ACCESSOR - }; - } - // Request and response body for POST /upload-pack using sidechannel protocol rpc PostUploadPackWithSidechannel(PostUploadPackWithSidechannelRequest) returns (PostUploadPackWithSidechannelResponse) { option (op_type) = { @@ -68,25 +61,6 @@ } // This comment is left unintentionally blank. -message PostUploadPackRequest { - // repository should only be present in the first message of the stream - Repository repository = 1 [(target_repository)=true]; - // Raw data to be copied to stdin of 'git upload-pack' - bytes data = 2; - // Parameters to use with git -c (key=value pairs) - repeated string git_config_options = 3; - - // Git protocol version - string git_protocol = 4; -} - -// This comment is left unintentionally blank. -message PostUploadPackResponse { - // Raw data from stdout of 'git upload-pack' - bytes data = 1; -} - -// This comment is left unintentionally blank. message PostUploadPackWithSidechannelRequest { // repository should only be present in the first message of the stream Repository repository = 1 [(target_repository)=true]; diff --git a/ruby/lib/hgitaly.rb b/ruby/lib/hgitaly.rb index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVieS9saWIvaGdpdGFseS5yYg==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVieS9saWIvaGdpdGFseS5yYg== 100644 --- a/ruby/lib/hgitaly.rb +++ b/ruby/lib/hgitaly.rb @@ -5,5 +5,7 @@ require 'hgitaly/mercurial-changeset_services_pb' +require 'hgitaly/mercurial-operations_services_pb' + require 'hgitaly/mercurial-repository_services_pb' diff --git a/ruby/lib/hgitaly/mercurial-operations_pb.rb b/ruby/lib/hgitaly/mercurial-operations_pb.rb new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVieS9saWIvaGdpdGFseS9tZXJjdXJpYWwtb3BlcmF0aW9uc19wYi5yYg== --- /dev/null +++ b/ruby/lib/hgitaly/mercurial-operations_pb.rb @@ -0,0 +1,35 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: mercurial-operations.proto + +require 'lint_pb' +require 'shared_pb' +require 'google/protobuf' + +Google::Protobuf::DescriptorPool.generated_pool.build do + add_file("mercurial-operations.proto", :syntax => :proto3) do + add_message "hgitaly.MergeAnalysisRequest" do + optional :repository, :message, 1, "gitaly.Repository" + optional :source_revision, :bytes, 2 + optional :target_revision, :bytes, 3 + optional :skip_conflicts_check, :bool, 4 + end + add_message "hgitaly.MergeAnalysisResponse" do + optional :is_fast_forward, :bool, 1 + optional :has_obsolete_changesets, :bool, 2 + optional :has_unstable_changesets, :bool, 3 + optional :has_conflicts, :bool, 4 + optional :target_is_public, :bool, 5 + optional :target_node_id, :string, 6 + optional :target_branch, :bytes, 7 + optional :target_topic, :bytes, 8 + optional :source_node_id, :string, 9 + optional :source_branch, :bytes, 10 + optional :source_topic, :bytes, 11 + end + end +end + +module Hgitaly + MergeAnalysisRequest = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hgitaly.MergeAnalysisRequest").msgclass + MergeAnalysisResponse = ::Google::Protobuf::DescriptorPool.generated_pool.lookup("hgitaly.MergeAnalysisResponse").msgclass +end diff --git a/ruby/lib/hgitaly/mercurial-operations_services_pb.rb b/ruby/lib/hgitaly/mercurial-operations_services_pb.rb new file mode 100644 index 0000000000000000000000000000000000000000..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVieS9saWIvaGdpdGFseS9tZXJjdXJpYWwtb3BlcmF0aW9uc19zZXJ2aWNlc19wYi5yYg== --- /dev/null +++ b/ruby/lib/hgitaly/mercurial-operations_services_pb.rb @@ -0,0 +1,25 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# Source: mercurial-operations.proto for package 'hgitaly' + +require 'grpc' +require 'mercurial-operations_pb' + +module Hgitaly + module MercurialOperationsService + class Service + + include ::GRPC::GenericService + + self.marshal_class_method = :encode + self.unmarshal_class_method = :decode + self.service_name = 'hgitaly.MercurialOperationsService' + + # Provide all information for a possible merge + # + # Will be used in mergeability checks and last-minute checks if needed. + rpc :MergeAnalysis, ::Hgitaly::MergeAnalysisRequest, ::Hgitaly::MergeAnalysisResponse + end + + Stub = Service.rpc_stub_class + end +end diff --git a/ruby/lib/hgitaly/version.rb b/ruby/lib/hgitaly/version.rb index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVieS9saWIvaGdpdGFseS92ZXJzaW9uLnJi..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVieS9saWIvaGdpdGFseS92ZXJzaW9uLnJi 100644 --- a/ruby/lib/hgitaly/version.rb +++ b/ruby/lib/hgitaly/version.rb @@ -1,4 +1,4 @@ # This file is generated by generate-grpc-lib. Do not edit. module Hgitaly - VERSION = '0.31.0' + VERSION = '0.40.3' end diff --git a/rust/rhgitaly/clippy.toml b/rust/rhgitaly/clippy.toml index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9jbGlwcHkudG9tbA==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9jbGlwcHkudG9tbA== 100644 --- a/rust/rhgitaly/clippy.toml +++ b/rust/rhgitaly/clippy.toml @@ -1,3 +1,3 @@ # MSRV is as Mercurial's, defined as the version in Debian testing # (currrently bookworm) -msrv = "1.61" +msrv = "1.65" diff --git a/rust/rhgitaly/proto/commit.proto b/rust/rhgitaly/proto/commit.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9wcm90by9jb21taXQucHJvdG8=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9wcm90by9jb21taXQucHJvdG8= 100644 --- a/rust/rhgitaly/proto/commit.proto +++ b/rust/rhgitaly/proto/commit.proto @@ -20,6 +20,13 @@ } // This comment is left unintentionally blank. + rpc GetTreeEntries(GetTreeEntriesRequest) returns (stream GetTreeEntriesResponse) { + option (op_type) = { + op: ACCESSOR + }; + } + + // This comment is left unintentionally blank. rpc FindCommit(FindCommitRequest) returns (FindCommitResponse) { option (op_type) = { op: ACCESSOR @@ -490,8 +497,11 @@ float share = 2; // Color specifies the associated color for this language, for example #3fd5e0. string color = 3; - // FileCount tells how many files with this language are found. - uint32 file_count = 4; + // FileCount was a uint32 that stored how many files with this language were found. + // However, it was never used and there is no client demand for it. + // See: https://gitlab.com/gitlab-org/gitaly/-/issues/4293. + reserved 4; + reserved "file_count"; // Bytes is the total amount of bytes written in this language uint64 bytes = 5; } diff --git a/rust/rhgitaly/proto/ref.proto b/rust/rhgitaly/proto/ref.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9wcm90by9yZWYucHJvdG8=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9wcm90by9yZWYucHJvdG8= 100644 --- a/rust/rhgitaly/proto/ref.proto +++ b/rust/rhgitaly/proto/ref.proto @@ -13,6 +13,13 @@ service RefService { // This comment is left unintentionally blank. + rpc FindDefaultBranchName(FindDefaultBranchNameRequest) returns (FindDefaultBranchNameResponse) { + option (op_type) = { + op: ACCESSOR + }; + } + + // This comment is left unintentionally blank. rpc RefExists(RefExistsRequest) returns (RefExistsResponse) { option (op_type) = { op: ACCESSOR diff --git a/rust/rhgitaly/proto/repository.proto b/rust/rhgitaly/proto/repository.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9wcm90by9yZXBvc2l0b3J5LnByb3Rv..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9wcm90by9yZXBvc2l0b3J5LnByb3Rv 100644 --- a/rust/rhgitaly/proto/repository.proto +++ b/rust/rhgitaly/proto/repository.proto @@ -204,6 +204,10 @@ // repository. Note, this will be treated as the branch name and not a // fully qualified reference. bytes default_branch = 2; + // ObjectFormat is the object format the repository should be created with. Note that this is + // experimental and should not be used by callers yet. It is mostly intended for internal testing + // purposes in Gitaly right now. + ObjectFormat object_format = 3; } // This comment is left unintentionally blank. @@ -287,5 +291,5 @@ bool result = 1; } -// This comment is left unintentionally blank. +// FsckRequest is a request for the Fsck RPC. message FsckRequest { @@ -291,5 +295,5 @@ message FsckRequest { - // This comment is left unintentionally blank. + // Repository is the repository that shall be checked for consistency. Repository repository = 1 [(target_repository)=true]; } @@ -293,5 +297,5 @@ Repository repository = 1 [(target_repository)=true]; } -// This comment is left unintentionally blank. +// FsckResponse is a response for the Fsck RPC. message FsckResponse { @@ -297,5 +301,5 @@ message FsckResponse { - // This comment is left unintentionally blank. + // Error contains both stdout and stderr of git-fsck(1) in case it returned an error. bytes error = 1; } @@ -462,5 +466,5 @@ message CreateRepositoryFromBundleResponse { } -// This comment is left unintentionally blank. +// FindLicenseRequest asks to detect the license for the given repository. message FindLicenseRequest { @@ -466,5 +470,5 @@ message FindLicenseRequest { - // This comment is left unintentionally blank. + // Repository is repository where to detect the license. Repository repository = 1 [(target_repository)=true]; } @@ -481,6 +485,8 @@ // LicenseUrl is a URL to the license on the internet. string license_url = 3; // LicensePath is a path to the file that contains the text of the license. + // When a LICENSE file is found containing the filename of another file, + // that filename will be returned, for example "mit.txt". string license_path = 4; // LicenseNickname is a shortened full name for better readability. // It exists only for a small set of licenses and an empty value is returned in most cases. @@ -749,5 +755,5 @@ message ReplicateRepositoryResponse{ } -// This comment is left unintentionally blank. +// OptimizeRepositoryRequest is a request for the OptimizeRepository RPC. message OptimizeRepositoryRequest { @@ -753,3 +759,17 @@ message OptimizeRepositoryRequest { - // This comment is left unintentionally blank. + // Strategy determines how the repository shall be optimized. + enum Strategy { + // STRATEGY_UNSPECIFIED indicates that the strategy has not been explicitly set by the + // caller. The default will be STRATEGY_HEURISTICAL in that case. + STRATEGY_UNSPECIFIED = 0; + // STRATEGY_HEURISTICAL performs heuristical optimizations in the repository. The server will + // decide on a set of heuristics which parts need optimization and which ones don't to avoid + // performing unnecessary optimization tasks. + STRATEGY_HEURISTICAL = 1; + // STRATEGY_EAGER performs eager optimizations in the repository. The server will optimize all + // data structures regardless of whether they are well-optimized already. + STRATEGY_EAGER = 2; + } + + // Repository is the repository that should be optimized. Repository repository = 1 [(target_repository)=true]; @@ -755,3 +775,5 @@ Repository repository = 1 [(target_repository)=true]; + // Strategy is the strategy that determines which parts of the repository shall be optimized. + Strategy strategy = 2; } @@ -756,7 +778,7 @@ } -// This comment is left unintentionally blank. -message OptimizeRepositoryResponse{ +// OptimizeRepositoryResponse is a response for the OptimizeRepository RPC. +message OptimizeRepositoryResponse { } // PruneUnreachableObjectsRequest is a request for the PruneUnreachableObjects diff --git a/rust/rhgitaly/proto/server.proto b/rust/rhgitaly/proto/server.proto index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9wcm90by9zZXJ2ZXIucHJvdG8=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9wcm90by9zZXJ2ZXIucHJvdG8= 100644 --- a/rust/rhgitaly/proto/server.proto +++ b/rust/rhgitaly/proto/server.proto @@ -70,7 +70,7 @@ // ClockSyncedRequest contains settings to be used for the system clock synchronisation check. message ClockSyncedRequest { // NtpHost is a URL to the external NTP service that should be used for clock sync check. - // Default is "ntp.pool.org" + // Default is "pool.ntp.org" string ntp_host = 1; reserved "drift_threshold_millis"; reserved 2; diff --git a/rust/rhgitaly/src/gitlab/mod.rs b/rust/rhgitaly/src/gitlab/mod.rs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9zcmMvZ2l0bGFiL21vZC5ycw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9zcmMvZ2l0bGFiL21vZC5ycw== 100644 --- a/rust/rhgitaly/src/gitlab/mod.rs +++ b/rust/rhgitaly/src/gitlab/mod.rs @@ -5,3 +5,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later pub mod revision; pub mod state; + +const GITLAB_BRANCH_REF_PREFIX: &[u8] = b"refs/heads/"; + +// Return the full GitLab ref path of a GitLab branch +pub fn gitlab_branch_ref(name: &[u8]) -> Vec<u8> { + let mut res = GITLAB_BRANCH_REF_PREFIX.to_vec(); + res.extend_from_slice(name); + res +} diff --git a/rust/rhgitaly/src/gitlab/state.rs b/rust/rhgitaly/src/gitlab/state.rs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9zcmMvZ2l0bGFiL3N0YXRlLnJz..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9zcmMvZ2l0bGFiL3N0YXRlLnJz 100644 --- a/rust/rhgitaly/src/gitlab/state.rs +++ b/rust/rhgitaly/src/gitlab/state.rs @@ -60,9 +60,9 @@ /// /// This means that it must be clear from context in code handling `TypedRef`s what /// their type is suppposed to be. -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct TypedRef { pub name: Vec<u8>, pub target_sha: Vec<u8>, } @@ -64,9 +64,9 @@ pub struct TypedRef { pub name: Vec<u8>, pub target_sha: Vec<u8>, } -#[derive(Debug, Clone, PartialEq, derive_more::From)] +#[derive(Debug, Clone, PartialEq, Eq, derive_more::From)] /// Express that a line does not follow the expected file format /// /// Absence of this error does not mean that the line components are themselves valid. diff --git a/rust/rhgitaly/src/mercurial.rs b/rust/rhgitaly/src/mercurial.rs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9zcmMvbWVyY3VyaWFsLnJz..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9zcmMvbWVyY3VyaWFsLnJz 100644 --- a/rust/rhgitaly/src/mercurial.rs +++ b/rust/rhgitaly/src/mercurial.rs @@ -5,6 +5,8 @@ // // SPDX-License-Identifier: GPL-2.0-or-later //! Utilities for Mercurial content handling +use std::collections::VecDeque; + use hg::changelog::Changelog; use hg::errors::HgError; use hg::manifest::{Manifest, ManifestEntry, Manifestlog}; @@ -12,6 +14,7 @@ use hg::revlog::{Node, NodePrefix, RevlogError, NULL_REVISION}; use hg::utils::hg_path::HgPath; -use crate::gitaly::ObjectType; +use crate::gitaly::{tree_entry::EntryType, ObjectType, TreeEntry}; +use crate::util::common_subpath_split; use super::git; @@ -16,6 +19,6 @@ use super::git; -use super::oid::blob_oid; +use super::oid::{blob_oid, tree_oid}; use tracing::debug; #[derive(Debug, Default)] @@ -256,6 +259,498 @@ }) } +/// An iterator over manifest, yielding only entries from a given sub directory +/// +/// This could be upstreamed to hg-core, where it would benefit the (private) binary search +/// method to avoid linear scanning for the directory starting point. +struct ManifestDirIterator<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + /// Path of the directory, without trailing slash + path: &'a [u8], + in_dir: bool, + manifest_iter: IM, +} + +impl<'a, 'm, IM> ManifestDirIterator<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + fn new(manifest_iter: IM, path: &'a [u8]) -> Self { + ManifestDirIterator { + path, + manifest_iter, + in_dir: false, + } + } + + /// Return the length of the string prefix corresponding to path, hence with trailing slash. + /// + /// This is meant so that, if `self.path` is `"foo"`, then `"foo/bar"[self.path_len()..]` is + /// `"bar"`. It also handles the case where `self.path` is empty correctly, sparing the callers + /// to check for this special case. + fn prefix_len(&self) -> usize { + let pl = self.path.len(); + if pl == 0 { + 0 + } else { + pl + 1 + } + } + + /// Derive from `self.path` a string prefix ready for concatenation with a relative path. + fn prefix(&self) -> Vec<u8> { + let mut v = self.path.to_vec(); + if !v.is_empty() { + v.push(b'/'); + } + v + } + + fn is_path_inside(&self, other_path: &[u8]) -> bool { + let pl = self.path.len(); + pl == 0 + || (other_path.len() > pl + && other_path[pl] == b'/' + && other_path.starts_with(self.path)) + } +} + +impl<'a, 'm, IM> Iterator for ManifestDirIterator<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + type Item = Result<ManifestEntry<'m>, HgError>; + + fn next(&mut self) -> Option<Self::Item> { + while let Some(entry_res) = self.manifest_iter.next() { + match entry_res { + Err(e) => { + return Some(Err(e)); + } + Ok(entry) => { + if !self.is_path_inside(entry.path.as_bytes()) { + if self.in_dir { + // we're leaving the directory to list, job done + return None; + } else { + // we have not entered the directory to list yet + continue; + } + } + return Some(Ok(entry)); + } + } + } + None + } +} + +/// Result of splitting a path for first and last segment +struct PathWithTopLevelDir<'a> { + /// The full path, for flat_path computation + path: &'a [u8], + /// The top level directory in the path (first segment) + top_level: &'a [u8], +} + +/// Analyze the given `sub_path`, splitting the directory part to get its top-level. +/// +/// The given (full) `entry_path` is for error messages only. +/// +/// If `sub_path` is a top-level file, `None` is returned. Otherwise, the returned +/// [`PathWithTopLevelDir`] encloses the directory part of `sub_path`. +/// +/// The computation relies on expectations for Mercurial manifeset entries, which are reflected +/// by the returned errors. Using the full entry path here should help with error inspection. +fn split_dir_and_top_level<'a>( + sub_path: &'a [u8], + entry_path: &[u8], +) -> Result<Option<PathWithTopLevelDir<'a>>, HgError> { + let mut rsplit = sub_path.rsplitn(2, |c| *c == b'/'); + rsplit.next().ok_or_else(|| { + HgError::corrupted(format!( + "Manifest entry with trailing slash: {:?}", + entry_path + )) + })?; + rsplit + .next() + .map(|dir_path| { + let top_level = dir_path.splitn(2, |c| *c == b'/').next().ok_or_else(|| { + HgError::corrupted(format!( + "Manifest entry with double slash: {:?}", + entry_path + )) + })?; + Ok(PathWithTopLevelDir { + top_level, + path: dir_path, + }) + }) + .transpose() +} + +/// Iterator yielding a [`TreeEntry`] without flat path for each top-level file or directory in a +/// manifest directory. +pub struct DirIteratorWithoutFlatPaths<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + /// Is expected to be the repetition of an incoming request "oid" field, + /// often something like `branch/default` and not a real OID + commit_oid: String, + changeset_node: Node, + root_oid: String, + manifest_dir_iter: ManifestDirIterator<'a, 'm, IM>, + current_subdir: &'m [u8], +} + +impl<'a, 'm, IM> DirIteratorWithoutFlatPaths<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + pub fn new(commit_oid: String, changeset_node: Node, manifest: IM, path: &'a [u8]) -> Self { + let root_oid = tree_oid(&changeset_node, b""); + Self { + commit_oid, + changeset_node, + root_oid, + manifest_dir_iter: ManifestDirIterator::new(manifest, path), + current_subdir: &[], + } + } + + fn tree_entry( + &self, + path: &[u8], + oid: String, + obj_type: EntryType, + mode: i32, + ) -> Result<TreeEntry, HgError> { + Ok(TreeEntry { + oid, + mode, + commit_oid: self.commit_oid.clone(), + root_oid: self.root_oid.clone(), + path: path.to_vec(), + r#type: obj_type as i32, + flat_path: Vec::new(), + }) + } +} + +impl<'a, 'm, IM> Iterator for DirIteratorWithoutFlatPaths<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + type Item = Result<TreeEntry, HgError>; + + fn next(&mut self) -> Option<Self::Item> { + while let Some(entry_res) = self.manifest_dir_iter.next() { + match entry_res { + Err(e) => { + return Some(Err(e)); + } + Ok(entry) => { + let ep = entry.path.as_bytes(); + let sp = &ep[self.manifest_dir_iter.prefix_len()..]; + match split_dir_and_top_level(sp, ep) { + Ok(None) => match git_perms(&entry) { + Err(e) => return Some(Err(e)), + Ok(mode) => { + return Some(self.tree_entry( + ep, + blob_oid(&self.changeset_node, ep), + EntryType::Blob, + mode, + )); + } + }, + Ok(Some(split)) => { + if split.top_level != self.current_subdir { + self.current_subdir = split.top_level; + let full_path = &ep + [..self.manifest_dir_iter.prefix_len() + split.top_level.len()]; + return Some(self.tree_entry( + full_path, + tree_oid(&self.changeset_node, full_path), + EntryType::Tree, + git::OBJECT_MODE_TREE, + )); + } + } + Err(e) => return Some(Err(e)), + } + } + } + } + None + } +} + +pub struct RecursiveDirIterator<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + /// Is expected to be the repetition of an incoming request "oid" field, + /// often something like `branch/default` and not a real OID + commit_oid: String, + changeset_node: Node, + root_oid: String, + manifest_dir_iter: ManifestDirIterator<'a, 'm, IM>, + current_subdir: &'m [u8], + to_yield: VecDeque<Result<TreeEntry, HgError>>, +} + +impl<'a, 'm, IM> RecursiveDirIterator<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + pub fn new(commit_oid: String, changeset_node: Node, manifest: IM, path: &'a [u8]) -> Self { + let root_oid = tree_oid(&changeset_node, b""); + Self { + commit_oid, + changeset_node, + root_oid, + manifest_dir_iter: ManifestDirIterator::new(manifest, path), + current_subdir: "".as_ref(), + /// Queue of `TreeEntry` messages that have to be emitted. + /// + /// Each manifest entry can give rise to several `TreeEntry` messages to yield, + /// because of intermediate directories. Hence we store them in this queue. + /// + /// Each call to `next()` pops either pops from the queue or consumes one or several + /// manifest entries, possibly pushing several more entries in the queue beside yielding + /// one. + to_yield: VecDeque::new(), + } + } + + fn tree_entry( + &self, + path: &[u8], + oid: String, + obj_type: EntryType, + mode: i32, + ) -> Result<TreeEntry, HgError> { + Ok(TreeEntry { + oid, + mode, + commit_oid: self.commit_oid.clone(), + root_oid: self.root_oid.clone(), + path: path.to_vec(), + r#type: obj_type as i32, + flat_path: Vec::new(), // resulting flat_path is always default for recursive queries + }) + } +} + +impl<'a, 'm, IM> Iterator for RecursiveDirIterator<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + type Item = Result<TreeEntry, HgError>; + + fn next(&mut self) -> Option<Self::Item> { + if let Some(entry) = self.to_yield.pop_front() { + return Some(entry); + } + + while let Some(entry_res) = self.manifest_dir_iter.next() { + match entry_res { + Err(e) => { + return Some(Err(e)); + } + Ok(entry) => { + let ep = entry.path.as_bytes(); + let sp = &ep[self.manifest_dir_iter.prefix_len()..]; + + let (mut subdir, rem_idx) = common_subpath_split(self.current_subdir, sp); + for i in rem_idx..sp.len() { + if sp[i] != b'/' { + continue; + } + subdir = &sp[..i]; + let fulldir = &ep[..i + self.manifest_dir_iter.prefix_len()]; + self.to_yield.push_back(self.tree_entry( + fulldir, + tree_oid(&self.changeset_node, fulldir), + EntryType::Tree, + git::OBJECT_MODE_TREE, + )); + } + self.current_subdir = subdir; + + match git_perms(&entry) { + Err(e) => { + self.to_yield.push_back(Err(e)); + } + Ok(mode) => { + self.to_yield.push_back(self.tree_entry( + ep, + blob_oid(&self.changeset_node, ep), + EntryType::Blob, + mode, + )); + } + } + } + } + } + self.to_yield.pop_front() + } +} + +/// Non recursive iterator over a directory, including "flat path" information +pub struct DirIteratorWithFlatPaths<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + /// Is expected to be the repetition of an incoming request "oid" field, + /// often something like `branch/default` and not a real OID + commit_oid: String, + changeset_node: Node, + root_oid: String, + manifest_dir_iter: ManifestDirIterator<'a, 'm, IM>, + /// This iterator also has the potential to yield several elements for a single + /// read manifest entry, however this queue is overvill, because it can at most yield two + /// TreeEntries (a Tree and a Blob), so we should later on replace with something lighter. + to_yield: VecDeque<Result<TreeEntry, HgError>>, +} + +impl<'a, 'm, IM> DirIteratorWithFlatPaths<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + pub fn new(commit_oid: String, changeset_node: Node, manifest: IM, path: &'a [u8]) -> Self { + let root_oid = tree_oid(&changeset_node, b""); + Self { + commit_oid, + changeset_node, + root_oid, + manifest_dir_iter: ManifestDirIterator::new(manifest, path), + /// Queue of `TreeEntry` messages that have to be emitted. + /// + /// Each manifest entry can give rise to several `TreeEntry` messages to yield, + /// because of intermediate directories. Hence we store them in this queue. + /// + /// each call to `next()` either pops an element from the queue or reads next manifest + /// line. + to_yield: VecDeque::new(), + } + } + + fn dir_tree_entry(&self, rel_path: &[u8], rel_flat_path: &[u8]) -> Result<TreeEntry, HgError> { + let mut path = self.manifest_dir_iter.prefix(); + path.extend_from_slice(rel_path); + let mut flat_path = self.manifest_dir_iter.prefix(); + flat_path.extend_from_slice(rel_flat_path); + Ok(TreeEntry { + oid: tree_oid(&self.changeset_node, &path), + mode: git::OBJECT_MODE_TREE, + commit_oid: self.commit_oid.clone(), + root_oid: self.root_oid.clone(), + path, + r#type: EntryType::Tree as i32, + flat_path, + }) + } + + fn file_tree_entry(&self, path: &[u8], mode: i32) -> Result<TreeEntry, HgError> { + Ok(TreeEntry { + mode, + oid: blob_oid(&self.changeset_node, path), + commit_oid: self.commit_oid.clone(), + root_oid: self.root_oid.clone(), + path: path.to_vec(), + r#type: EntryType::Blob as i32, + flat_path: path.to_vec(), + }) + } + + fn enqueue_file_entry(&mut self, entry: &ManifestEntry) { + match git_perms(entry) { + Err(e) => { + self.to_yield.push_back(Err(e)); + } + Ok(mode) => { + self.to_yield + .push_back(self.file_tree_entry(entry.path.as_bytes(), mode)); + } + } + } + + /// Main scanning loop for [`Iterator`] implementation + /// + /// Returns `Result<()>` whereas `next()` returns instead of `Option<Result<T>>` + /// to make error treatment easier (question-mark operator). Therefore this method + /// only pushes to `self.to_yield`. + fn inner_next(&mut self) -> Result<(), HgError> { + let mut current_subdir: Option<&[u8]> = None; + let mut current_flat_path: &[u8] = &[]; + + while let Some(entry_res) = self.manifest_dir_iter.next() { + let entry = entry_res?; + let ep = entry.path.as_bytes(); + let sp = &ep[self.manifest_dir_iter.prefix_len()..]; + + if let Some(subdir) = current_subdir { + let (common, rem_idx) = common_subpath_split(subdir, sp); + if rem_idx != 0 { + current_flat_path = common; + } else { + // we are leaving current_subdir, so schedule to yield it and clear it + // so that the later check whether we are entering a new one or simply have + // a top-level file runs. + self.to_yield + .push_back(self.dir_tree_entry(subdir, current_flat_path)); + current_subdir = None + } + } + + if current_subdir.is_none() { + match split_dir_and_top_level(sp, ep)? { + None => { + self.enqueue_file_entry(&entry); + break; + } + Some(split) => { + current_subdir = Some(split.top_level); + current_flat_path = split.path; + } + } + } + } + // If the last entry is not a top-level file, then the loop ends without yielding + // `current_subdir`, hence we need to do it now. + if let Some(subdir) = current_subdir { + self.to_yield + .push_back(self.dir_tree_entry(subdir, current_flat_path)); + } + Ok(()) + } +} + +impl<'a, 'm, IM> Iterator for DirIteratorWithFlatPaths<'a, 'm, IM> +where + IM: Iterator<Item = Result<ManifestEntry<'m>, HgError>>, +{ + type Item = Result<TreeEntry, HgError>; + + fn next(&mut self) -> Option<Self::Item> { + if let Some(entry) = self.to_yield.pop_front() { + return Some(entry); + } + + match self.inner_next() { + Ok(()) => self.to_yield.pop_front(), + Err(e) => Some(Err(e)), + } + } +} + #[cfg(test)] mod tests { @@ -385,4 +880,253 @@ ]) ) } + + #[test] + fn test_manifest_dir_iterator() { + let manifest = paths_manifest(vec!["foo/a", "foo/sub/a", "top-file"]); + let iter = ManifestDirIterator::new(manifest.into_iter(), b""); + let res: Vec<&[u8]> = iter.map(|r| r.unwrap().path.as_bytes()).collect(); + assert_eq!( + res, + vec![ + b"foo/a".as_ref(), + b"foo/sub/a".as_ref(), + b"top-file".as_ref(), + ] + ); + + let manifest = paths_manifest(vec![ + "foo.", + "foo/a", + "foo/sub/a", + "foo/sub/b", + "foo/subb", + "foo0", + "other/file", + ]); + let iter = ManifestDirIterator::new(manifest.into_iter(), b"foo"); + let res: Vec<&[u8]> = iter.map(|r| r.unwrap().path.as_bytes()).collect(); + assert_eq!( + res, + vec![ + b"foo/a".as_ref(), + b"foo/sub/a".as_ref(), + b"foo/sub/b".as_ref(), + b"foo/subb".as_ref(), + ] + ); + } + + fn testing_blob_flat_path(cs_node: &Node, path: &[u8], flat_path: &[u8]) -> TreeEntry { + TreeEntry { + path: path.to_vec(), + r#type: EntryType::Blob as i32, + mode: git::OBJECT_MODE_NON_EXECUTABLE, + commit_oid: "branch/test".to_owned(), + root_oid: tree_oid(cs_node, b""), + oid: blob_oid(cs_node, path), + flat_path: flat_path.to_vec(), + } + } + + fn testing_blob(cs_node: &Node, path: &[u8]) -> TreeEntry { + testing_blob_flat_path(cs_node, path, &[]) + } + + fn testing_tree_flat_path(cs_node: &Node, path: &[u8], flat_path: &[u8]) -> TreeEntry { + TreeEntry { + path: path.to_vec(), + r#type: EntryType::Tree as i32, + mode: git::OBJECT_MODE_TREE, + commit_oid: "branch/test".to_owned(), + root_oid: tree_oid(cs_node, b""), + oid: tree_oid(cs_node, path), + flat_path: flat_path.to_vec(), + } + } + + fn testing_tree(cs_node: &Node, path: &[u8]) -> TreeEntry { + testing_tree_flat_path(cs_node, path, &[]) + } + + #[test] + fn test_dir_iterator_without_flat_paths() { + let cs_node = Node::from_hex(b"1234567812345678123456781234567812345678").unwrap(); + + let manifest = paths_manifest(vec!["foo/a"]); + let iter = DirIteratorWithoutFlatPaths::new( + "branch/test".to_owned(), + cs_node, + manifest.into_iter(), + &[], + ); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!(res, vec![testing_tree(&cs_node, b"foo"),]); + + let manifest = paths_manifest(vec![ + "foo.", + "foo/a", + "foo/sub/a", + "foo/sub/b", + "foo/subb", + "foo0", + ]); + let iter = DirIteratorWithoutFlatPaths::new( + "branch/test".to_owned(), + cs_node, + manifest.into_iter(), + b"foo", + ); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!( + res, + vec![ + testing_blob(&cs_node, b"foo/a"), + testing_tree(&cs_node, b"foo/sub"), + testing_blob(&cs_node, b"foo/subb"), + ] + ); + + let manifest = paths_manifest(vec!["foo.", "foo/a", "foo/sub/ssub/b", "foo/subb", "foo0"]); + let iter = DirIteratorWithoutFlatPaths::new( + "branch/test".to_owned(), + cs_node, + manifest.into_iter(), + b"foo", + ); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!( + res, + vec![ + testing_blob(&cs_node, b"foo/a"), + testing_tree(&cs_node, b"foo/sub"), + testing_blob(&cs_node, b"foo/subb"), + ] + ); + } + + #[test] + fn test_recursive_dir_iter() { + let cs_node = Node::from_hex(b"1234567812345678123456781234567812345678").unwrap(); + + let manifest = paths_manifest(vec!["foo/a"]); + let iter = + RecursiveDirIterator::new("branch/test".to_owned(), cs_node, manifest.into_iter(), &[]); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!( + res, + vec![ + testing_tree(&cs_node, b"foo"), + testing_blob(&cs_node, b"foo/a"), + ] + ); + + let manifest = paths_manifest(vec![ + "foo.", + "foo/a", + "foo/sub/a", + "foo/sub/b", + "foo/subb", + "foo0", + ]); + let iter = RecursiveDirIterator::new( + "branch/test".to_owned(), + cs_node, + manifest.into_iter(), + b"foo", + ); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!( + res, + vec![ + testing_blob(&cs_node, b"foo/a"), + testing_tree(&cs_node, b"foo/sub"), + testing_blob(&cs_node, b"foo/sub/a"), + testing_blob(&cs_node, b"foo/sub/b"), + testing_blob(&cs_node, b"foo/subb"), + ] + ); + + let manifest = paths_manifest(vec![ + "foo.", + "foo/a", + "foo/sub/a", + "foo/sub/ssub/b", + "foo/subb", + "foo0", + ]); + let iter = RecursiveDirIterator::new( + "branch/test".to_owned(), + cs_node, + manifest.into_iter(), + b"foo", + ); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!( + res, + vec![ + testing_blob(&cs_node, b"foo/a"), + testing_tree(&cs_node, b"foo/sub"), + testing_blob(&cs_node, b"foo/sub/a"), + testing_tree(&cs_node, b"foo/sub/ssub"), + testing_blob(&cs_node, b"foo/sub/ssub/b"), + testing_blob(&cs_node, b"foo/subb"), + ] + ); + } + #[test] + fn test_dir_iter_flat_paths() { + let cs_node = Node::from_hex(b"1234567812345678123456781234567812345678").unwrap(); + + let manifest = paths_manifest(vec!["foo/a"]); + let iter = DirIteratorWithFlatPaths::new( + "branch/test".to_owned(), + cs_node, + manifest.into_iter(), + &[], + ); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!(res, vec![testing_tree_flat_path(&cs_node, b"foo", b"foo"),]); + + let manifest = paths_manifest(vec![ + "foo.", + "foo/a", + "foo/sub/a", + "foo/sub/b", + "foo/subb", + "foo0", + ]); + let iter = DirIteratorWithFlatPaths::new( + "branch/test".to_owned(), + cs_node, + manifest.into_iter(), + b"foo", + ); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!( + res, + vec![ + testing_blob_flat_path(&cs_node, b"foo/a", b"foo/a"), + testing_tree_flat_path(&cs_node, b"foo/sub", b"foo/sub"), + testing_blob_flat_path(&cs_node, b"foo/subb", b"foo/subb"), + ] + ); + + let manifest = paths_manifest(vec!["foo.", "foo/a", "foo/sub/ssub/b", "foo/subb", "foo0"]); + let iter = DirIteratorWithFlatPaths::new( + "branch/test".to_owned(), + cs_node, + manifest.into_iter(), + b"foo", + ); + let res: Vec<TreeEntry> = iter.map(|r| r.unwrap()).collect(); + assert_eq!( + res, + vec![ + testing_blob_flat_path(&cs_node, b"foo/a", b"foo/a"), + testing_tree_flat_path(&cs_node, b"foo/sub", b"foo/sub/ssub"), + testing_blob_flat_path(&cs_node, b"foo/subb", b"foo/subb"), + ] + ); + } } diff --git a/rust/rhgitaly/src/message.rs b/rust/rhgitaly/src/message.rs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9zcmMvbWVzc2FnZS5ycw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9zcmMvbWVzc2FnZS5ycw== 100644 --- a/rust/rhgitaly/src/message.rs +++ b/rust/rhgitaly/src/message.rs @@ -18,7 +18,7 @@ use prost_types::Timestamp; use std::str::FromStr; -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum TimeStampParseError { Empty, MissingTimeZone, diff --git a/rust/rhgitaly/src/service/commit.rs b/rust/rhgitaly/src/service/commit.rs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9zcmMvc2VydmljZS9jb21taXQucnM=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9zcmMvc2VydmljZS9jb21taXQucnM= 100644 --- a/rust/rhgitaly/src/service/commit.rs +++ b/rust/rhgitaly/src/service/commit.rs @@ -5,6 +5,7 @@ use tracing::{field, info, instrument}; use hg::changelog::Changelog; +use hg::errors::HgError; use hg::repo::Repo; use hg::revlog::{NodePrefix, RevlogError, NULL_REVISION}; use hg::utils::hg_path::HgPath; @@ -14,8 +15,9 @@ use crate::git; use crate::gitaly::commit_service_server::{CommitService, CommitServiceServer}; use crate::gitaly::{ - tree_entry_response::ObjectType, FindCommitRequest, FindCommitResponse, - ListCommitsByOidRequest, ListCommitsByOidResponse, Repository, TreeEntryRequest, - TreeEntryResponse, + get_tree_entries_request::SortBy, tree_entry::EntryType, tree_entry_response::ObjectType, + FindCommitRequest, FindCommitResponse, GetTreeEntriesRequest, GetTreeEntriesResponse, + ListCommitsByOidRequest, ListCommitsByOidResponse, PaginationParameter, Repository, TreeEntry, + TreeEntryRequest, TreeEntryResponse, }; use crate::gitlab::revision::gitlab_revision_node_prefix; @@ -20,6 +22,9 @@ }; use crate::gitlab::revision::gitlab_revision_node_prefix; -use crate::mercurial::{changelog_entry_manifest, ls_path, read_blob, PathContent}; +use crate::mercurial::{ + changelog_entry_manifest, ls_path, read_blob, DirIteratorWithFlatPaths, + DirIteratorWithoutFlatPaths, PathContent, RecursiveDirIterator, +}; use crate::message; use crate::metadata::correlation_id; use crate::oid::tree_oid; @@ -27,7 +32,10 @@ default_repo_spec_error_status, load_repo_and_stream, load_repo_and_then, repo_store_vfs, RequestWithRepo, }; -use crate::streaming::{BlockingResponseSender, ResultResponseStream}; +use crate::streaming::{ + empty_response_stream, stream_with_pagination, BlockingResponseSender, PaginableMessageItem, + ResultResponseStream, +}; #[derive(Debug)] pub struct CommitServiceImpl { @@ -71,8 +79,8 @@ Ok(ListCommitsByOidResponse { commits }) } -fn not_found_for_path(path: &[u8]) -> Status { - Status::not_found(format!("not found: {}", &String::from_utf8_lossy(path))) +fn not_found_for_path(_path: &[u8]) -> Status { + Status::not_found("tree entry not found") } fn stream_tree_entry( @@ -106,8 +114,7 @@ .map_err(|e| Status::internal(format!("Error reading file {:?}", e)))?; if req.max_size != 0 && metadata.size > req.max_size { tx.send(Err(Status::failed_precondition(format!( - "TreeEntry: object size ({}) is bigger than the maximum \ - allowed size ({})", + "object size ({}) is bigger than the maximum allowed size ({})", metadata.size, req.max_size )))); } else { @@ -144,9 +151,124 @@ Ok(()) } +fn stream_get_tree_entries( + req: GetTreeEntriesRequest, + repo: &Repo, + node_prefix: NodePrefix, + tx: &BlockingResponseSender<GetTreeEntriesResponse>, +) -> Result<(), Status> { + let changelog = repo + .changelog() + .map_err(|e| Status::internal(format!("Error getting changelog: {:?}", e)))?; + let manifestlog = repo + .manifestlog() + .map_err(|e| Status::internal(format!("Error getting manifestlog: {:?}", e)))?; + let (cs_node, manifest) = changelog_entry_manifest(&changelog, &manifestlog, node_prefix) + .map_err(|e| Status::internal(format!("Error obtaining manifest: {:?}", e)))? + .ok_or_else(|| not_found_for_path(&req.path))?; + + let mut pl = req.path.len(); + while pl > 0 && req.path[pl - 1] == b'/' { + pl -= 1; + } + if pl == 1 && req.path[0] == b'.' { + pl = 0 + }; + let trimmed = &req.path[0..pl]; + + let commit_oid = String::from_utf8_lossy(&req.revision).to_string(); + + if req.recursive { + stream_get_tree_entries_from_iterator( + tx, + &req, + RecursiveDirIterator::new(commit_oid, cs_node, manifest.iter(), trimmed), + ); + } else if req.skip_flat_paths { + stream_get_tree_entries_from_iterator( + tx, + &req, + DirIteratorWithoutFlatPaths::new(commit_oid, cs_node, manifest.iter(), trimmed), + ); + } else { + stream_get_tree_entries_from_iterator( + tx, + &req, + DirIteratorWithFlatPaths::new(commit_oid, cs_node, manifest.iter(), trimmed), + ); + } + Ok(()) +} + +/// Stream `GetTreeEntries` responses, using the inner iterator. +/// +/// Various options (e.g., `recursive`) give rise to different types of iterators on entries. +/// This function applies the sort and pagination parameters, final chunking and streams responses +/// to the channel. +fn stream_get_tree_entries_from_iterator<It>( + tx: &BlockingResponseSender<GetTreeEntriesResponse>, + request: &GetTreeEntriesRequest, + iterator: It, +) where + It: Iterator<Item = Result<TreeEntry, HgError>>, +{ + let pagination = &request.pagination_params; + if request.sort == SortBy::TreesFirst as i32 { + let mut trees = Vec::new(); + let mut blobs = Vec::new(); + for res in iterator { + match res { + Ok(ent) => { + if ent.r#type == EntryType::Tree as i32 { + trees.push(Ok(ent)); + } else if ent.r#type == EntryType::Blob as i32 { + blobs.push(Ok(ent)); + } + } + // arbitrary choice, weakly motivated by errors being more likely with blobs + // than with trees at this point. + err => blobs.push(err), + } + } + stream_get_tree_entries_paginated( + tx, + pagination, + trees.into_iter().chain(blobs.into_iter()), + ); + } else { + stream_get_tree_entries_paginated(tx, pagination, iterator); + } +} + +/// Stream [`GetTreeEntriesResponse`] messages with pagination +/// +/// This function takes care of the offset and limit logic enclosed into the given pagination +/// parameter, regrouping the `TreeEntry` elements yielded by the iterator into suitable chunks, +/// and providing the `next_cursor` value, but does not take care of ordering. +/// Instead it expects the incoming iiterator to be already properly ordered. +fn stream_get_tree_entries_paginated<It>( + tx: &BlockingResponseSender<GetTreeEntriesResponse>, + pagination: &Option<PaginationParameter>, + iterator: It, +) where + It: Iterator<Item = Result<TreeEntry, HgError>>, +{ + stream_with_pagination( + tx, + pagination, + iterator, + |entries, pagination_cursor| GetTreeEntriesResponse { + entries, + pagination_cursor, + }, + |err| Status::internal(format!("error reading manifest: #{:?}", err)), + |token| Status::internal(format!("could not find starting OID: {}", token)), + ) +} + impl RequestWithRepo for TreeEntryRequest { fn repository_ref(&self) -> Option<&Repository> { self.repository.as_ref() } } @@ -147,9 +269,15 @@ impl RequestWithRepo for TreeEntryRequest { fn repository_ref(&self) -> Option<&Repository> { self.repository.as_ref() } } +impl RequestWithRepo for GetTreeEntriesRequest { + fn repository_ref(&self) -> Option<&Repository> { + self.repository.as_ref() + } +} + impl RequestWithRepo for ListCommitsByOidRequest { fn repository_ref(&self) -> Option<&Repository> { self.repository.as_ref() @@ -162,7 +290,17 @@ } } +impl PaginableMessageItem for TreeEntry { + fn match_token(&self, token: &str) -> bool { + self.oid == token + } + + fn next_cursor(&self) -> String { + self.oid.clone() + } +} + #[tonic::async_trait] impl CommitService for CommitServiceImpl { type ListCommitsByOidStream = ReceiverStream<Result<ListCommitsByOidResponse, Status>>; type TreeEntryStream = ReceiverStream<Result<TreeEntryResponse, Status>>; @@ -165,7 +303,8 @@ #[tonic::async_trait] impl CommitService for CommitServiceImpl { type ListCommitsByOidStream = ReceiverStream<Result<ListCommitsByOidResponse, Status>>; type TreeEntryStream = ReceiverStream<Result<TreeEntryResponse, Status>>; + type GetTreeEntriesStream = ReceiverStream<Result<GetTreeEntriesResponse, Status>>; async fn list_commits_by_oid( &self, @@ -196,6 +335,16 @@ self.inner_tree_entry(inner, correlation_id(&metadata)) .await } + + async fn get_tree_entries( + &self, + request: Request<GetTreeEntriesRequest>, + ) -> Result<Response<Self::GetTreeEntriesStream>, Status> { + let (metadata, _ext, inner) = request.into_parts(); + + self.inner_get_tree_entries(inner, correlation_id(&metadata)) + .await + } } struct TreeEntryTracingRequest<'a>(&'a TreeEntryRequest); @@ -212,6 +361,22 @@ } } +struct GetTreeEntriesTracingRequest<'a>(&'a GetTreeEntriesRequest); + +impl Debug for GetTreeEntriesTracingRequest<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("GetTreeEntriesRequest") + .field("repository", &self.0.repository) + .field("revision", &String::from_utf8_lossy(&self.0.revision)) + .field("path", &String::from_utf8_lossy(&self.0.path)) + .field("recursive", &self.0.recursive) + .field("sort", &self.0.sort) + .field("pagination_params", &self.0.pagination_params) + .field("skip_flat_paths", &self.0.skip_flat_paths) + .finish() + } +} + struct FindCommitTracingRequest<'a>(&'a FindCommitRequest); impl Debug for FindCommitTracingRequest<'_> { @@ -268,6 +433,56 @@ } } + #[instrument(name = "get_tree_entries", + skip(self, request), + fields(request=field::debug(GetTreeEntriesTracingRequest(&request))))] + async fn inner_get_tree_entries( + &self, + request: GetTreeEntriesRequest, + correlation_id: Option<&MetadataValue<Ascii>>, + ) -> ResultResponseStream<GetTreeEntriesResponse> { + info!("Processing"); + + if request.revision.is_empty() { + return Err(Status::invalid_argument("empty revision")); + } + + let config = self.config.clone(); + let store_vfs = repo_store_vfs(&config, &request.repository) + .await + .map_err(default_repo_spec_error_status)?; + + match gitlab_revision_node_prefix(&store_vfs, &request.revision) + .await + .map_err(|e| Status::internal(format!("Error resolving revision: {:?}", e)))? + { + None => { + info!("Revision not resolved"); + empty_response_stream() + } + Some(node_prefix) => { + info!("Revision resolved as {:x}", &node_prefix); + + if request.pagination_params.as_ref().map(|p| p.limit) == Some(0) { + // let's not even load the repo (see Gitaly Comparison tests, + // no error case either) + return empty_response_stream(); + } + + load_repo_and_stream( + self.config.clone(), + request, + default_repo_spec_error_status, + move |req, repo, tx| { + if let Err(e) = stream_get_tree_entries(req, &repo, node_prefix, &tx) { + tx.send(Err(e)); + } + }, + ) + } + } + } + #[instrument(name = "list_commits_by_oid", skip(self))] async fn inner_list_commits_by_oid( &self, diff --git a/rust/rhgitaly/src/service/ref.rs b/rust/rhgitaly/src/service/ref.rs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9zcmMvc2VydmljZS9yZWYucnM=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9zcmMvc2VydmljZS9yZWYucnM= 100644 --- a/rust/rhgitaly/src/service/ref.rs +++ b/rust/rhgitaly/src/service/ref.rs @@ -11,5 +11,9 @@ use crate::config::Config; use crate::gitaly::ref_service_server::{RefService, RefServiceServer}; -use crate::gitaly::{RefExistsRequest, RefExistsResponse}; +use crate::gitaly::{ + FindDefaultBranchNameRequest, FindDefaultBranchNameResponse, RefExistsRequest, + RefExistsResponse, +}; +use crate::gitlab::gitlab_branch_ref; use crate::gitlab::revision::{map_full_ref, RefError}; @@ -15,4 +19,5 @@ use crate::gitlab::revision::{map_full_ref, RefError}; +use crate::gitlab::state::get_gitlab_default_branch; use crate::metadata::correlation_id; use crate::repository::{default_repo_spec_error_status, repo_store_vfs}; @@ -23,6 +28,15 @@ #[tonic::async_trait] impl RefService for RefServiceImpl { + async fn find_default_branch_name( + &self, + request: Request<FindDefaultBranchNameRequest>, + ) -> Result<Response<FindDefaultBranchNameResponse>, Status> { + let (metadata, _ext, inner) = request.into_parts(); + + self.inner_find_default_branch_name(inner, correlation_id(&metadata)) + .await + } async fn ref_exists( &self, request: Request<RefExistsRequest>, @@ -46,6 +60,29 @@ } impl RefServiceImpl { + #[instrument(name = "find_default_branch_name", skip(self))] + async fn inner_find_default_branch_name( + &self, + request: FindDefaultBranchNameRequest, + correlation_id: Option<&MetadataValue<Ascii>>, + ) -> Result<Response<FindDefaultBranchNameResponse>, Status> { + info!("Processing"); + + let store_vfs = repo_store_vfs(&self.config, &request.repository) + .await + .map_err(default_repo_spec_error_status)?; + + Ok(Response::new(FindDefaultBranchNameResponse { + name: get_gitlab_default_branch(&store_vfs) + .await + .map_err(|e| { + Status::internal(format!("Error reading GitLab default branch: {:?}", e)) + })? + .map(|ref name| gitlab_branch_ref(name)) + .unwrap_or_else(Vec::new), + })) + } + #[instrument(name="ref_exists", skip(self, request), fields(request=field::debug(RefExistsTracingRequest(&request))))] diff --git a/rust/rhgitaly/src/streaming.rs b/rust/rhgitaly/src/streaming.rs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9zcmMvc3RyZWFtaW5nLnJz..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9zcmMvc3RyZWFtaW5nLnJz 100644 --- a/rust/rhgitaly/src/streaming.rs +++ b/rust/rhgitaly/src/streaming.rs @@ -4,6 +4,7 @@ // GNU General Public License version 2 or any later version. // SPDX-License-Identifier: GPL-2.0-or-later use std::env; +use std::fmt::Debug; use std::str::FromStr; use lazy_static::lazy_static; @@ -7,8 +8,8 @@ use std::str::FromStr; use lazy_static::lazy_static; -use tokio::sync::mpsc::Sender; +use tokio::sync::mpsc::{self, Sender}; use tokio_stream::wrappers::ReceiverStream; use tonic::{Response, Status}; use tracing::error; @@ -11,7 +12,8 @@ use tokio_stream::wrappers::ReceiverStream; use tonic::{Response, Status}; use tracing::error; +use crate::gitaly::{PaginationCursor, PaginationParameter}; const DEFAULT_WRITE_BUFFER_SIZE: usize = 131072; lazy_static! { @@ -26,6 +28,12 @@ pub type ResultResponseStream<Resp> = Result<Response<ReceiverStream<Result<Resp, Status>>>, Status>; +/// Return a valid, yet empty response stream +pub fn empty_response_stream<Resp>() -> ResultResponseStream<Resp> { + let (_tx, rx) = mpsc::channel(1); + Ok(Response::new(ReceiverStream::new(rx))) +} + /// A specialization of [`Sender`] allowing only blocking sends and logging sending errors /// /// Server streaming methods involving a repository typically spawn a new thread with @@ -59,3 +67,241 @@ }); } } + +/// Wrap an inner iterator over Results to aggregate into chunks. +/// +/// As soon as an error is encountered while iterating for a chunk, it is yielded in place +/// of the chunk. +/// +/// As of Rust 1.65, the stdlib the [`Iterator`] trait has a `next_chunk` method but +/// - it is unstable +/// - it yields arrays +/// - the remainder still needs to be collected, making it not so practical +/// - it does not have the error handling, of course +struct ChunkedIterator<T, IT, E> +where + IT: Iterator<Item = Result<T, E>>, +{ + inner: IT, + chunk_size: usize, +} + +impl<T, IT, E> Iterator for ChunkedIterator<T, IT, E> +where + IT: Iterator<Item = Result<T, E>>, +{ + type Item = Result<Vec<T>, E>; + + fn next(&mut self) -> Option<Result<Vec<T>, E>> { + let mut chunk: Vec<T> = Vec::new(); + while chunk.len() < self.chunk_size { + match self.inner.next() { + None => { + if chunk.is_empty() { + return None; + } else { + break; + } + } + Some(Ok(v)) => chunk.push(v), + Some(Err(e)) => { + return Some(Err(e)); + } + } + } + Some(Ok(chunk)) + } +} + +pub const DEFAULT_CHUNK_SIZE: usize = 50; + +/// Stream responses by aggregating an inner iterator into chunks +/// +/// This is useful when streamed responses have a repeated field: the inner iterator +/// would yield individual elements, and this generic function can be used to +/// collect them in chunks, from which responses are built and sent to the channel. +/// +/// The resulting chunks are guaranteed not to be empty. +/// +/// In `resp_builder`, the boolean tells whether the response to build is the first one. +/// It is indeed frequent in the Gitaly protocol for streamed responses with a repeated field +/// and additional metadata to put the metadata on the first response only, the subsequent +/// ones being only about chunking the repeated field. +/// +/// This parallels Python `hgitaly.util.chunked` except that the chunk size is for now +/// the constant [`DEFAULT_CHUNK_SIZE`]. +/// Note that this flexibility was introduced early in the Python implementation, but has +/// not been actually used yet. +/// Gitaly seems to apply a more subtle logic based on actual response size +/// in some cases. It looks like a better avenue for improvement to mimick that rather than +/// making the chunk size customizable. +pub fn stream_chunks<Iter, Resp, Item, E>( + tx: &BlockingResponseSender<Resp>, + iter: Iter, + resp_builder: impl FnOnce(Vec<Item>, bool) -> Resp + Copy, + err_handler: impl FnOnce(E) -> Status + Copy, +) where + Iter: Iterator<Item = Result<Item, E>>, +{ + let mut first = true; + for res in (ChunkedIterator { + inner: iter, + chunk_size: DEFAULT_CHUNK_SIZE, + }) { + tx.send(res.map_or_else( + |e| Err(err_handler(e)), + |chunk| Ok(resp_builder(chunk, first)), + )); + if first { + first = false; + } + } +} + +/// This trait is for elements of responses which rely on the Pagination protocol +/// +/// Typically, the response will include a repeated field, and the traait is to be +/// implemented on inividual items of that field. +/// +/// For an example, see [`crate::gitaly::GetTreeEntriesResponse`] +pub trait PaginableMessageItem: Debug { + /// Provide the `next_cursor` field of `PaginationCursor` + /// + /// This is the value to tell clients that the next page of results would + /// start after the current item, which is typically the last one returned + /// by the current call + fn next_cursor(&self) -> String; + + /// Tell whether this item is the one bearing the givn token. + /// + /// This means typically that the wanted results start right afterwards. + fn match_token(&self, token: &str) -> bool; +} + +/// Stream responses by grouping them in chunks and abiding to pagination parameters. +/// +/// This is meant to take into account incoming [`PaginationParameter`] and provide in turn +/// the appropriate responses so that the client can request the next page. These together +/// represent an effort in the Gitaly protocol to standardize a client-driven second level of +/// batching on top of the server-driven streaming responses. +/// +/// This function takes severak closure arguments: +/// +/// - `resp_builder` is a closure responsible to build a response from collected items and a +/// [`PaginationCursor`] message. +/// - `err_handler` is the generic transformation from the errors that `iterator` may yield. +/// - `token_not_found` provides the error [`Status`] in case no item matches +/// `pagination.page_token`. It is expected to differ among gRPC methods and possibly need +/// some contextual information. +pub fn stream_with_pagination<Iter, Resp, Item, E>( + tx: &BlockingResponseSender<Resp>, + pagination: &Option<PaginationParameter>, + mut iterator: Iter, + resp_builder: impl FnOnce(Vec<Item>, Option<PaginationCursor>) -> Resp + Copy, + err_handler: impl FnOnce(E) -> Status + Copy, + token_not_found: impl FnOnce(&str) -> Status + Copy, +) where + Iter: Iterator<Item = Result<Item, E>>, + Item: PaginableMessageItem, +{ + match pagination { + None => { + // no pagination param: in particular, no limit + stream_chunks_with_cursor(tx, iterator, "", resp_builder, err_handler); + } + Some(pagination) => { + let token = &pagination.page_token; + if !token.is_empty() { + let mut found = false; + for res in iterator.by_ref() { + match res { + Ok(item) => { + if item.match_token(token) { + found = true; + break; + } + } + Err(e) => { + tx.send(Err(err_handler(e))); + return; + } + } + } + if !found { + tx.send(Err(token_not_found(token))); + return; + } + } + + if pagination.limit < 0 { + return stream_chunks_with_cursor(tx, iterator, "", resp_builder, err_handler); + } + + // No other choice than collecting to truncate and derive `next_cursor` + let limit = pagination.limit as usize; + let mut limited: Vec<Result<Item, E>> = Vec::new(); + for (i, item) in iterator.enumerate() { + if i >= limit { + break; + } + limited.push(item); + } + match limited.last() { + None => {} + // In case it is an error, we need to take ownership, since `err_handler` does + // not work on references. We cannot clone because some of the errors we have to + // deal with do not implement `Clone` (e.g., [`HgError`] does not) + Some(Err(_e)) => tx.send(Err(err_handler( + limited + .pop() + .expect("Last element already known to exist and to be an error") + .unwrap_err(), + ))), + Some(Ok(ref item)) => { + // We need to take a ref for next_cursor, so that the closure used in the + // underlying `stream_chunks()` is `Copy`, with leads us to clone in actual + // `PaginationCursor` instantiation (this is bearable). + // We also need to take the ref right now, to make the borrow checker accept its + // use in the call below. + let next_cursor = &item.next_cursor(); + stream_chunks_with_cursor( + tx, + limited.into_iter(), + next_cursor, + resp_builder, + err_handler, + ); + } + } + } + } +} + +/// Shortcut to reduce code dupliaction in `stream_chunks_with_pagination` +fn stream_chunks_with_cursor<Iter, Resp, Item, E>( + tx: &BlockingResponseSender<Resp>, + iter: Iter, + next_cursor: &str, + resp_builder: impl FnOnce(Vec<Item>, Option<PaginationCursor>) -> Resp + Copy, + err_handler: impl FnOnce(E) -> Status + Copy, +) where + Iter: Iterator<Item = Result<Item, E>>, +{ + stream_chunks( + tx, + iter, + |chunk, first| { + resp_builder( + chunk, + if first { + Some(PaginationCursor { + next_cursor: next_cursor.to_string(), + }) + } else { + None + }, + ) + }, + err_handler, + ); +} diff --git a/rust/rhgitaly/src/util.rs b/rust/rhgitaly/src/util.rs index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_cnVzdC9yaGdpdGFseS9zcmMvdXRpbC5ycw==..0944dbc03457ecdaf8e5085639a35a25a2f16e62_cnVzdC9yaGdpdGFseS9zcmMvdXRpbC5ycw== 100644 --- a/rust/rhgitaly/src/util.rs +++ b/rust/rhgitaly/src/util.rs @@ -21,3 +21,90 @@ } } } + +/// Return the common subpath as a subslice of `first` and the index after which the remainder +/// starts in `second`. +pub fn common_subpath_split<'a, 'b>(first: &'a [u8], second: &'b [u8]) -> (&'a [u8], usize) { + // position of the latest slash in `first` after the common subpath, if any. + let mut latest_slash: Option<usize> = None; + + let mut fit = first.iter(); + let mut sit = second.iter(); + let mut i: usize = 0; + + loop { + match fit.next() { + Some(fc) => match sit.next() { + None => { + if *fc == b'/' { + latest_slash = Some(i); + } else { + break; + } + } + Some(sc) => { + if *fc != *sc { + break; + } + if *fc == b'/' { + latest_slash = Some(i); + } + i += 1; + } + }, + None => match sit.next() { + None => { + return (first, first.len()); + } + Some(sc) => { + if *sc == b'/' { + return (first, first.len() + 1); + } else { + break; + } + } + }, + } + } + + match latest_slash { + None => (&[], 0), + Some(ls) => (&first[..ls], ls + 1), + } +} + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_common_subpath_split() { + assert_eq!(common_subpath_split(b"foo/a", b"bar"), (b"".as_ref(), 0)); + assert_eq!(common_subpath_split(b"bar", b"foo/a"), (b"".as_ref(), 0)); + assert_eq!( + common_subpath_split(b"foo/a", b"foo/b"), + (b"foo".as_ref(), 4) + ); + assert_eq!(common_subpath_split(b"foo/a", b"foox/a"), (b"".as_ref(), 0)); + assert_eq!(common_subpath_split(b"foox/a", b"foo/a"), (b"".as_ref(), 0)); + assert_eq!( + common_subpath_split(b"foo/a/", b"foo/a/b"), + (b"foo/a".as_ref(), 6) + ); + assert_eq!( + common_subpath_split(b"foo/a", b"foo/a/b"), + (b"foo/a".as_ref(), 6) + ); + assert_eq!( + common_subpath_split(b"foo/a/b", b"foo/a"), + (b"foo/a".as_ref(), 6) + ); + assert_eq!( + common_subpath_split(b"foo/a/b/c", b"foo/a/d/e"), + (b"foo/a".as_ref(), 6) + ); + assert_eq!(common_subpath_split(b"", b"foo/a"), (b"".as_ref(), 0)); + assert_eq!(common_subpath_split(b"foo/a", b""), (b"".as_ref(), 0)); + } +} diff --git a/setup.py b/setup.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_c2V0dXAucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_c2V0dXAucHk= 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,9 @@ keywords='hg mercurial heptapod gitlab', license='GPLv2+', packages=find_packages(), - package_data=dict(hgitaly=[VERSION_FILE]), + package_data={'hgitaly': [VERSION_FILE], + 'hgitaly.linguist': ['languages.json'], + }, install_requires=install_req, python_requires='>=3.8', ) diff --git a/tests_with_gitaly/test_blob_tree.py b/tests_with_gitaly/test_blob_tree.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9ibG9iX3RyZWUucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9ibG9iX3RyZWUucHk= 100644 --- a/tests_with_gitaly/test_blob_tree.py +++ b/tests_with_gitaly/test_blob_tree.py @@ -177,9 +177,6 @@ # reusing content to test GetTreeEntries, hence with a new rpc_helper # - if hg_server == 'rhgitaly': # TODO split with a module fixture - return - def gte_normalizer(rpc_helper, responses, vcs='hg'): for resp in responses: for entry in resp.entries: @@ -188,6 +185,7 @@ entry.root_oid = b'' rpc_helper = fixture.rpc_helper(stub_cls=CommitServiceStub, + hg_server=hg_server, method_name='GetTreeEntries', request_cls=GetTreeEntriesRequest, request_defaults=dict( @@ -207,6 +205,9 @@ assert_compare(path=b'.', revision=b'unknown') + # case when path is actually a file + assert_compare(path=b'sub/bar') + # sort parameter SortBy = GetTreeEntriesRequest.SortBy for recursive in (False, True): @@ -237,8 +238,10 @@ sort=SortBy.TREES_FIRST) -def test_compare_get_tree_entries_pagination(gitaly_comparison): - fixture = gitaly_comparison +@parametrize('hg_server', ('hgitaly', 'rhgitaly')) +def test_compare_get_tree_entries_pagination(gitaly_rhgitaly_comparison, + hg_server): + fixture = gitaly_rhgitaly_comparison wrapper = fixture.hg_repo_wrapper wrapper.write_commit('foo', message="Some foo") @@ -271,6 +274,7 @@ cursor2git = {} # hg cursor -> git cursor rpc_helper = fixture.rpc_helper(stub_cls=CommitServiceStub, + hg_server=hg_server, method_name='GetTreeEntries', request_cls=GetTreeEntriesRequest, request_defaults=dict( @@ -340,6 +344,10 @@ pagination_params=PaginationParameter(limit=0), ) + # case of unknown revision and limit=0 + assert_compare(path=b'.', revision=b'unknown', + pagination_params=PaginationParameter(limit=0)) + # case of no pagination params assert_compare_aggregated(path=b'sub', recursive=True, diff --git a/tests_with_gitaly/test_commit.py b/tests_with_gitaly/test_commit.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9jb21taXQucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9jb21taXQucHk= 100644 --- a/tests_with_gitaly/test_commit.py +++ b/tests_with_gitaly/test_commit.py @@ -14,5 +14,6 @@ Repository, ) from hgitaly.stub.commit_pb2 import ( + CommitLanguagesRequest, FindCommitRequest, FindCommitsRequest, @@ -17,5 +18,6 @@ FindCommitRequest, FindCommitsRequest, + LastCommitForPathRequest, ListCommitsRequest, ListCommitsByOidRequest, ListFilesRequest, @@ -35,7 +37,7 @@ parametrize = pytest.mark.parametrize -def test_compare_list_last_commits_for_tree(gitaly_comparison): +def test_compare_last_commit_for(gitaly_comparison): fixture = gitaly_comparison git_repo = fixture.git_repo @@ -102,7 +104,34 @@ # error won't be due to invalidity as a SHA, but because commit doesn't # exist (let's not depend on Gitaly accepting symbolic revisions, here) - assert_compare_errors(revision=b'be0123ef' * 5, path=b'') + assert_compare_errors(revision=b'be0123ef' * 5, path=b'sub') + + def lcfp_norm(rpc_helper, response, **kw): + normalize_commit_message(response.commit) + + rpc_helper = fixture.rpc_helper(stub_cls=CommitServiceStub, + method_name='LastCommitForPath', + request_cls=LastCommitForPathRequest, + request_sha_attrs=['revision'], + response_sha_attrs=[ + 'commit.id', + 'commit.parent_ids[]', + ], + normalizer=lcfp_norm, + ) + + assert_compare = rpc_helper.assert_compare + assert_compare_errors = rpc_helper.assert_compare_errors + + for path in (b'sub/dir', b'sub/dir/', b'', b'.', b'/', b'./', + b'sub', b'sub/', b'foo'): + for rev in (b'branch/default', b'branch/other', + ctx2.hex(), ctx3.hex()): + assert_compare(revision=rev, path=path) + + # case when revision does not exist + for path in (b'', b'foo'): + assert_compare(revision=b'be0123ef' * 5, path=path) def test_compare_raw_blame(gitaly_comparison): @@ -289,7 +318,8 @@ assert_compare_errors(repository=None, revision=b'HEAD', same_details=False) - assert_compare_errors(repository=None) # and no revision + assert_compare_errors(repository=None, # and no revision + same_details=False) fixture.gitaly_repo.relative_path = 'unknown/repo' assert_compare_errors(revision=b'HEAD', same_details=False) @@ -425,6 +455,42 @@ assert_compare(before=date) assert_compare(before=date, after=date) + # with `include_referenced_by` option + mr_ref_path, _ = fixture.write_special_ref(b'merge-requests/2/train', + ctx2.hex()) + wrapper.command('tag', b'release', rev=ctx3.hex()) + all_revs.append(wrapper.repo[b'.'].hex()) # will be HEAD + wrapper.command('gitlab-mirror') + fixture.invalidate() # will need to normalize the tagging changeset itself + + for patterns in ([b'refs/heads'], + [b'refs/heads/'], + [b'refs/heads/branch/'], + [b'refs/tags'], + [b'refs/tags/'], + [b'refs/tags/rel'], + [b'refs/merge-requests'], + [b'refs/heads', b'refs/tags'], # matching is logical OR + [b'HEAD'], + ): + for rev in all_revs: + rpc_helper.assert_compare(revision=rev, + include_referenced_by=patterns) + + # This looks to be simple matching by segment prefixes, + # but git-log(1) isn't very explicit about the type of matching it is + # performing (Gitaly uses `git log --decorate-ref` for this as of v15.9): + # --decorate-refs=<pattern>, --decorate-refs-exclude=<pattern> + # For each candidate reference, do not use it for decoration if + # it matches any patterns given to --decorate-refs-exclude or if + # it doesn’t match any of the patterns given to --decorate-refs. + for patterns in ([b'refs/h*ds/'], # glob + [b'refs/tags/rel'], # general prefixing + [b'refs/h..ds/'], # regexp + ): + rpc_helper.assert_compare(revision=b'branch/default', + include_referenced_by=patterns) + def test_compare_list_commits(gitaly_comparison): fixture = gitaly_comparison @@ -642,3 +708,47 @@ # NULL_NODE gets ignored rpc_helper.assert_compare(oid=[NULL_HEX]) rpc_helper.assert_compare(oid=[NULL_HEX, hexes[0]]) + + +def test_compare_commit_languages(gitaly_comparison): + fixture = gitaly_comparison + wrapper = fixture.hg_repo_wrapper + + rpc_helper = fixture.rpc_helper( + stub_cls=CommitServiceStub, + method_name='CommitLanguages', + request_cls=CommitLanguagesRequest, + request_sha_attrs=['oid'], + ) + assert_compare = rpc_helper.assert_compare + + # a Python file with valid content, including a blank line + wrapper.commit_file('foo.py', + content="import sys\n\nprint(sys.version)\n", + message="Some Python", + ) + # a Ruby file with valid content, with a comment + # despite Ruby being after Python in lexicographical order, + # it should come first, being the one with the most bytes. + wrapper.commit_file('bar.rb', + content=("# frozen_string_literal: true\n" + "\n" + "module Bar\n" + "def f(x)\n" + " x+1\n" + ), + message="Some Ruby", + ) + assert_compare() + + # GitHub Linguist restricts itself to some language types, namely, from + # blob_helper.rb: + # + # DETECTABLE_TYPES = [:programming, :markup].freeze + # + # it turns out that COBOL is a programming language without any associated + # color in the `languages.json` file. + wrapper.commit_file('truc.cob') + assert_compare() + + # error cases are hard to reproduce permanently in Gitaly diff --git a/tests_with_gitaly/test_diff.py b/tests_with_gitaly/test_diff.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9kaWZmLnB5..0944dbc03457ecdaf8e5085639a35a25a2f16e62_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9kaWZmLnB5 100644 --- a/tests_with_gitaly/test_diff.py +++ b/tests_with_gitaly/test_diff.py @@ -119,6 +119,6 @@ sha_not_exists = b'deadnode' * 5 with pytest.raises(grpc.RpcError) as exc_info: do_rpc('hg', sha_not_exists, ctx2.hex()) - assert exc_info.value.code() == grpc.StatusCode.UNKNOWN + assert exc_info.value.code() == grpc.StatusCode.INTERNAL with pytest.raises(grpc.RpcError) as exc_info: do_rpc('git', sha_not_exists, ctx2.hex()) @@ -123,6 +123,6 @@ with pytest.raises(grpc.RpcError) as exc_info: do_rpc('git', sha_not_exists, ctx2.hex()) - assert exc_info.value.code() == grpc.StatusCode.UNKNOWN + assert exc_info.value.code() == grpc.StatusCode.INTERNAL # case 5: EMPTY_TREE_OID to represent null commit on the left hg_resp_lines = do_rpc('hg', EMPTY_TREE_OID, ctx0.hex()).split(b'\n') diff --git a/tests_with_gitaly/test_ref.py b/tests_with_gitaly/test_ref.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9yZWYucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9yZWYucHk= 100644 --- a/tests_with_gitaly/test_ref.py +++ b/tests_with_gitaly/test_ref.py @@ -15,6 +15,7 @@ ) from hgitaly.stub.ref_pb2 import ( FindBranchRequest, + FindDefaultBranchNameRequest, FindTagRequest, FindLocalBranchesRequest, ListRefsRequest, @@ -62,6 +63,34 @@ @parametrize('hg_server', ('hgitaly', 'rhgitaly')) +def test_compare_find_default_branch_name(gitaly_rhgitaly_comparison, + hg_server): + fixture = gitaly_rhgitaly_comparison + git_repo = fixture.git_repo + + rpc_helper = fixture.rpc_helper( + hg_server=hg_server, + stub_cls=RefServiceStub, + method_name='FindDefaultBranchName', + request_cls=FindDefaultBranchNameRequest, + ) + + # empty repo + rpc_helper.assert_compare() + + fixture.hg_repo_wrapper.write_commit('foo', message="Some foo") + gl_branch = b'branch/default' + + # mirror worked + assert git_repo.branch_titles() == {gl_branch: b"Some foo"} + + rpc_helper.assert_compare() + # invalid case + rpc_helper.assert_compare_errors(repository=None, + same_details=False) + + +@parametrize('hg_server', ('hgitaly', 'rhgitaly')) def test_compare_ref_exists(gitaly_rhgitaly_comparison, hg_server): fixture = gitaly_rhgitaly_comparison wrapper = fixture.hg_repo_wrapper @@ -112,10 +141,7 @@ assert_compare_errors(ref=b'notrefs/something') -@parametrize('branch_style', ['new-style', 'old-style']) -def test_compare_find_local_branches(gitaly_comparison, branch_style): - new_style = branch_style == 'new-style' - +def test_compare_find_local_branches(gitaly_comparison): fixture = gitaly_comparison wrapper = fixture.hg_repo_wrapper @@ -129,12 +155,5 @@ assert set(fixture.git_repo.branch_titles().keys()) == { b'branch/br%02d' % i for i in range(3)} - if new_style: - resp_branches = 'local_branches' - resp_target = 'target_commit' - else: - resp_branches = 'branches' - resp_target = 'commit' - def normalize_response(rpc_helper, resp, **kw): for chunk in resp: @@ -139,5 +158,5 @@ def normalize_response(rpc_helper, resp, **kw): for chunk in resp: - for branch in getattr(chunk, resp_branches): - normalize_commit_message(getattr(branch, resp_target)) + for branch in chunk.local_branches: + normalize_commit_message(branch.target_commit) @@ -143,15 +162,6 @@ - if new_style: - resp_sha_attrs = ['local_branches[].target_commit.id', - 'local_branches[].target_commit.parent_ids[]', - ] - else: - resp_sha_attrs = ['branches[].commit_id', - 'branches[].commit.id', - 'branches[].commit.parent_ids[]', - ] rpc_helper = fixture.rpc_helper( stub_cls=RefServiceStub, method_name='FindLocalBranches', request_cls=FindLocalBranchesRequest, streaming=True, @@ -153,8 +163,10 @@ rpc_helper = fixture.rpc_helper( stub_cls=RefServiceStub, method_name='FindLocalBranches', request_cls=FindLocalBranchesRequest, streaming=True, - response_sha_attrs=resp_sha_attrs, + response_sha_attrs=['local_branches[].target_commit.id', + 'local_branches[].target_commit.parent_ids[]', + ], normalizer=normalize_response, ) @@ -159,8 +171,5 @@ normalizer=normalize_response, ) - if new_style: - rpc_helper.feature_flags.append( - ('simplify-find-local-branches-response', new_style)) def assert_compare(limit=0, page_token='', pagination=True, **kw): if pagination: @@ -283,7 +292,7 @@ for resp in resps: all_pseudo_ref_idx = None for i, ref_msg in enumerate(resp.references): - if ref_msg.name == b'ALL': + if ref_msg.name == b'ALL' and rpc_helper.norm_all_pseudo_ref: all_pseudo_ref_idx = i if ref_msg.name.startswith(prefix): ref_msg.name = prefix + rpc_helper.hg2git( @@ -297,6 +306,7 @@ request_cls=ListRefsRequest, request_defaults=dict(patterns=[b"refs/"], head=True), streaming=True, + request_sha_attrs=['pointing_at_oids'], response_sha_attrs=['references[].target'], normalizer=normalize_refs, ) @@ -300,6 +310,7 @@ response_sha_attrs=['references[].target'], normalizer=normalize_refs, ) + rpc_helper.norm_all_pseudo_ref = True # empty repo, in particular no default GitLab branch (HEAD) rpc_helper.assert_compare() @@ -310,4 +321,5 @@ hg_sha = hg_wrapper.commit_file('bar').hex() # branches + hg_shas = [] for i in range(3): @@ -313,4 +325,6 @@ for i in range(3): - hg_wrapper.commit_file('foo', branch='br%02d' % i, return_ctx=False, - utc_timestamp=now - commit_ages[i]) + hg_shas.append( + hg_wrapper.commit_file('foo', branch='br%02d' % i, + utc_timestamp=now - commit_ages[i]).hex() + ) rpc_helper.assert_compare() @@ -316,7 +330,9 @@ rpc_helper.assert_compare() + for head in False, True: + rpc_helper.assert_compare(patterns=[b'refs/heads/'], head=head) # with tags hg_wrapper.command('tag', b'v3.1', rev=b'br01') hg_wrapper.command('gitlab-mirror') fixture.invalidate() rpc_helper.assert_compare() @@ -317,10 +333,13 @@ # with tags hg_wrapper.command('tag', b'v3.1', rev=b'br01') hg_wrapper.command('gitlab-mirror') fixture.invalidate() rpc_helper.assert_compare() + for head in False, True: + rpc_helper.assert_compare(patterns=[b'refs/heads/'], head=head) + rpc_helper.assert_compare(patterns=[b'refs/tags/'], head=head) # now with special refs fixture.write_special_ref(b'pipeline/13', hg_sha) rpc_helper.assert_compare() @@ -323,8 +342,11 @@ # now with special refs fixture.write_special_ref(b'pipeline/13', hg_sha) rpc_helper.assert_compare() + for head in False, True: + rpc_helper.assert_compare(patterns=[b'refs/heads/'], head=head) + rpc_helper.assert_compare(patterns=[b'refs/tags/'], head=head) # with a keep around fixture.create_keep_around(hg_sha) rpc_helper.assert_compare() @@ -327,6 +349,25 @@ # with a keep around fixture.create_keep_around(hg_sha) rpc_helper.assert_compare() + for head in False, True: + rpc_helper.assert_compare(patterns=[b'refs/heads/'], head=head) + rpc_helper.assert_compare(patterns=[b'refs/tags/'], head=head) + + # more general patterns + rpc_helper.norm_all_pseudo_ref = False + for head in False, True: + # notice how HEAD is ignored by pattern matching + rpc_helper.assert_compare(patterns=[b'refs/heads/branch/br*'], + head=head) + + # 'branch/something' should not match `br*` and special case of + # HEAD not being part of response if nothing matches + rpc_helper.assert_compare(patterns=[b'refs/heads/br*'], head=head) + + # logical conjunction of several patterns + rpc_helper.assert_compare(patterns=[b'refs/heads/branch/br*', + b'refs/heads/branch/d*'], + head=head) # no error that we can think of would be specific of this gRPC method @@ -331,2 +372,14 @@ # no error that we can think of would be specific of this gRPC method + + # pointing_at_oids + for head in False, True: + rpc_helper.assert_compare(pointing_at_oids=[hg_shas[0]], head=head) + rpc_helper.assert_compare(pointing_at_oids=[hg_shas[0], hg_shas[1]], + head=head) + # together with patterns + for i in range(3): + # empty result if `i == 0 and not head` + rpc_helper.assert_compare(pointing_at_oids=[hg_shas[i]], + patterns=[b'refs/tags/'], + head=head) diff --git a/tests_with_gitaly/test_repository_service.py b/tests_with_gitaly/test_repository_service.py index aadc12c12dc78f21d4b3ddb9e4f674b5f252ea0c_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9yZXBvc2l0b3J5X3NlcnZpY2UucHk=..0944dbc03457ecdaf8e5085639a35a25a2f16e62_dGVzdHNfd2l0aF9naXRhbHkvdGVzdF9yZXBvc2l0b3J5X3NlcnZpY2UucHk= 100644 --- a/tests_with_gitaly/test_repository_service.py +++ b/tests_with_gitaly/test_repository_service.py @@ -21,4 +21,5 @@ CreateRepositoryFromBundleRequest, FindMergeBaseRequest, FullPathRequest, + RemoveAllRequest, RemoveRepositoryRequest, @@ -24,4 +25,5 @@ RemoveRepositoryRequest, + SearchFilesByContentRequest, SearchFilesByNameRequest, SetFullPathRequest, ) @@ -623,3 +625,81 @@ # unknown ref gives back an empty list of files, not an error assert_compare(ref=b'unknown', query='.') + + +def test_search_files_by_content(gitaly_comparison): + fixture = gitaly_comparison + + wrapper = fixture.hg_repo_wrapper + wrapper.write_commit('afoo', message="Some foo") + sub = (wrapper.path / 'sub') + sub.mkdir() + (sub / 'bar').write_text('line1\nline2\nbar content\nline4\nline5') + (sub / 'ba2').write_text('line1\nba2 content') + (sub / 'ba3').write_text('ba3 content\nline2') + # This one has a Windows endings, and exhibits that `git grep` normalizes + # to `\n`. Also Git does not interpret the MacOS classic line ending + # '\r' and we do. In that case, we can claim our response to be more + # correct and we will not compare it. + (sub / 'ba4').write_text('l1\r\nl2\nl3\nba4 content\nline6') + (sub / 'ba5').write_text('m1\nm2\nm3\nm4\nm5\nm6\nba5 content\n') + (wrapper.path / 'large').write_text('very large content\n' * 3000) + # TODO OS indep for paths (actually TODO make wrapper.commit easier to + # use, e.g., check how to make it accept patterns) + wrapper.commit(rel_paths=['sub/bar', 'sub/ba2', 'sub/ba3', + 'sub/ba4', 'sub/ba5', 'large'], + message="zebar", add_remove=True) + + default_rev = b'branch/default' + + rpc_helper = fixture.rpc_helper( + stub_cls=RepositoryServiceStub, + method_name='SearchFilesByContent', + request_cls=SearchFilesByContentRequest, + request_defaults=dict( + ref=default_rev, + ), + streaming=True, + error_details_normalizer=lambda s, vcs: s.lower(), + ) + assert_compare = rpc_helper.assert_compare + assert_compare_errors = rpc_helper.assert_compare_errors + + # precondition for the test: mirror worked + assert fixture.git_repo.branch_titles() == { + default_rev: b"zebar", + } + assert_compare(query='no match for this one') + assert_compare(query='^bar.c') + assert_compare(query='^ba2.c') # only one line before match + assert_compare(query='^ba3.c') # only one line after match + assert_compare(query='^ba4.c') # more than two lines before match + assert_compare(query='^very') + assert_compare(query='^l1|ba4') # two matches with overlapping context + assert_compare(query='^m1|ba5') # two matches with non-overlapping context + assert_compare(query='ConTent') # several files and case insensity + + # errors if query is missing + assert_compare_errors() + assert_compare_errors(ref=b'topic/default/does-not-exist') + # unresolvable ref + assert_compare(ref=b'topic/default/does-not-exist', query='foo') + # missing repo, ref + assert_compare_errors(ref=b'') + assert_compare_errors(repository=None) + fixture.gitaly_repo.relative_path = 'no/such/repo' + assert_compare_errors(query='foo', same_details=False) + + +def test_remove_all(gitaly_comparison, server_repos_root): + fixture = gitaly_comparison + rpc_helper = fixture.rpc_helper( + stub_cls=RepositoryServiceStub, + method_name='RemoveAll', + request_cls=RemoveAllRequest, + repository_arg=False, + ) + assert_compare_errors = rpc_helper.assert_compare_errors + + # unknown storage + assert_compare_errors(storage_name='unknown')