hgitaly 18.7.0__tar.gz → 18.7.0a0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {hgitaly-18.7.0/hgitaly.egg-info → hgitaly-18.7.0a0}/PKG-INFO +2 -2
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_blob_tree.py +5 -4
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_commit.py +4 -15
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_ref.py +0 -1
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_repository_service.py +11 -12
- hgitaly-18.7.0a0/hgitaly/VERSION +1 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/gitlab_ref.py +39 -3
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/manifest.py +13 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/commit.py +282 -8
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/repository.py +86 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/fixture.py +12 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_commit.py +337 -15
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_mercurial_operations.py +53 -13
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_operations.py +25 -5
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_repository_service.py +156 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/storage.py +3 -17
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_gitlab_ref.py +23 -1
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_servicer.py +8 -16
- {hgitaly-18.7.0 → hgitaly-18.7.0a0/hgitaly.egg-info}/PKG-INFO +2 -2
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly.egg-info/requires.txt +1 -1
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/install-requirements.txt +1 -1
- hgitaly-18.7.0/hgitaly/VERSION +0 -1
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/LICENSE +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/MANIFEST.in +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/README.md +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/comparison.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/conftest.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/gitaly.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/hgitaly_rhgitaly_comparison.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/rhgitaly.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_comparison.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_diff.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_gitaly_server.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_mercurial_aux_git.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_mercurial_operations.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_mercurial_repository.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_operations.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_remote.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_rhgitaly_server.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/functional_tests/test_server.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgext3rd/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgext3rd/hgitaly/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgext3rd/hgitaly/revset.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgext3rd/hgitaly/tests/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgext3rd/hgitaly/tests/test_revset.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgext3rd/hgitaly/tests/test_serve.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/branch.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/changelog.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/diff.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/errors.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/feature.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/file_content.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/file_context.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/git.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/identification.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/logging.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/message.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/oid.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/pagination.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/path.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/peer.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/procutil.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/repository.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/revision.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/revset.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/scripts.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/server/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/server/address.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/server/mono.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/server/tests/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/server/tests/test_address.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/server/tests/test_mono.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/server/tests/test_worker.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/server/worker.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/analysis.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/blob.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/diff.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/interceptors.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/mercurial_changeset.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/mercurial_namespace.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/mercurial_operations.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/mercurial_repository.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/operations.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/ref.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/server.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_analysis.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_blob.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_default_branch.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_diff.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_mercurial_changeset.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_mercurial_namespace.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_mercurial_repository.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_ref.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/service/tests/test_server.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/servicer.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/ssh.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stream.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/analysis_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/analysis_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/blob_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/blob_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/commit_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/commit_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/diff_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/diff_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/errors_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/errors_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/lint_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/lint_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_aux_git_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_aux_git_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_changeset_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_changeset_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_namespace_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_namespace_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_operations_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_operations_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_repository_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/mercurial_repository_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/operations_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/operations_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/ref_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/ref_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/remote_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/remote_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/repository_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/repository_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/server_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/server_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/shared_pb2.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/stub/shared_pb2_grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tag.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/bundle.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/context.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/grpc.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/multiprocessing.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/repo.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/ssh.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/sshd.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/tests/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/testing/tests/test_sshd.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/__init__.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/common.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_branch.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_diff.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_errors.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_feature.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_file_context.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_identification.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_manifest.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_messages.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_oid.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_peer.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_repository.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_revision.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_revset.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_stream.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_tag.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/tests/test_workdir.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/util.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly/workdir.py +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly.egg-info/SOURCES.txt +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly.egg-info/dependency_links.txt +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly.egg-info/entry_points.txt +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/hgitaly.egg-info/top_level.txt +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/setup.cfg +0 -0
- {hgitaly-18.7.0 → hgitaly-18.7.0a0}/setup.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: hgitaly
|
|
3
|
-
Version: 18.7.
|
|
3
|
+
Version: 18.7.0a0
|
|
4
4
|
Summary: Server-side implementation of Gitaly protocol for Mercurial
|
|
5
5
|
Home-page: https://foss.heptapod.net/heptapod/hgitaly
|
|
6
6
|
Author: Georges Racinet
|
|
@@ -10,7 +10,7 @@ Keywords: hg mercurial heptapod gitlab
|
|
|
10
10
|
Requires-Python: >=3.8
|
|
11
11
|
Description-Content-Type: text/markdown
|
|
12
12
|
License-File: LICENSE
|
|
13
|
-
Requires-Dist: heptapod
|
|
13
|
+
Requires-Dist: heptapod>=5.4.0
|
|
14
14
|
Requires-Dist: protobuf~=6.31.1
|
|
15
15
|
Requires-Dist: grpcio~=1.76.0
|
|
16
16
|
Requires-Dist: grpcio-status~=1.76.0
|
|
@@ -108,9 +108,9 @@ def oid_normalizer(oid2git):
|
|
|
108
108
|
return normalizer
|
|
109
109
|
|
|
110
110
|
|
|
111
|
-
|
|
111
|
+
@parametrize('hg_server', ('hgitaly', 'rhgitaly'))
|
|
112
|
+
def test_compare_tree_entry_request(gitaly_rhgitaly_comparison, hg_server):
|
|
112
113
|
fixture = gitaly_rhgitaly_comparison
|
|
113
|
-
hg_server = 'rhgitaly'
|
|
114
114
|
|
|
115
115
|
wrapper = fixture.hg_repo_wrapper
|
|
116
116
|
wrapper.write_commit('foo', message="Some foo")
|
|
@@ -302,9 +302,10 @@ def test_compare_tree_entry_request(gitaly_rhgitaly_comparison):
|
|
|
302
302
|
)
|
|
303
303
|
|
|
304
304
|
|
|
305
|
-
|
|
305
|
+
@parametrize('hg_server', ('hgitaly', 'rhgitaly'))
|
|
306
|
+
def test_compare_get_tree_entries_pagination(gitaly_rhgitaly_comparison,
|
|
307
|
+
hg_server):
|
|
306
308
|
fixture = gitaly_rhgitaly_comparison
|
|
307
|
-
hg_server = 'rhgitaly'
|
|
308
309
|
|
|
309
310
|
wrapper = fixture.hg_repo_wrapper
|
|
310
311
|
wrapper.write_commit('foo', message="Some foo")
|
|
@@ -406,7 +406,8 @@ def test_compare_list_files(gitaly_comparison):
|
|
|
406
406
|
rpc_helper.assert_compare(revision=rev)
|
|
407
407
|
|
|
408
408
|
|
|
409
|
-
|
|
409
|
+
@parametrize('hg_server', ('hgitaly', 'rhgitaly'))
|
|
410
|
+
def test_compare_find_commit(gitaly_rhgitaly_comparison, hg_server):
|
|
410
411
|
fixture = gitaly_rhgitaly_comparison
|
|
411
412
|
wrapper = fixture.hg_repo_wrapper
|
|
412
413
|
|
|
@@ -415,7 +416,7 @@ def test_compare_find_commit(gitaly_rhgitaly_comparison):
|
|
|
415
416
|
normalize_commit_message(response.commit)
|
|
416
417
|
|
|
417
418
|
rpc_helper = fixture.rpc_helper(
|
|
418
|
-
hg_server=
|
|
419
|
+
hg_server=hg_server,
|
|
419
420
|
stub_cls=CommitServiceStub,
|
|
420
421
|
method_name='FindCommit',
|
|
421
422
|
request_cls=FindCommitRequest,
|
|
@@ -720,7 +721,7 @@ def test_compare_list_commits(gitaly_comparison):
|
|
|
720
721
|
#
|
|
721
722
|
# @ 4 (branch/default) merge with stable
|
|
722
723
|
# |\
|
|
723
|
-
# | o 3 creates '
|
|
724
|
+
# | o 3 creates 'animal' (branch/stable)
|
|
724
725
|
# | |
|
|
725
726
|
# o | 2 rename 'foo' to 'zoo' (user: testuser)
|
|
726
727
|
# |/
|
|
@@ -811,18 +812,6 @@ def test_compare_list_commits(gitaly_comparison):
|
|
|
811
812
|
# no result
|
|
812
813
|
assert_compare(revisions=[ctx4.hex(), caret(ctx4)])
|
|
813
814
|
|
|
814
|
-
# with paths
|
|
815
|
-
assert_compare(revisions=[ctx4.hex()], paths=[b'animals'])
|
|
816
|
-
assert_compare(revisions=[ctx4.hex()], paths=[b'foo'])
|
|
817
|
-
assert_compare(revisions=[ctx4.hex()], paths=[b'zoo'])
|
|
818
|
-
assert_compare(revisions=[ctx3.hex(), ctx2.hex()],
|
|
819
|
-
paths=[b'animals', b'zoo'])
|
|
820
|
-
assert_compare(revisions=[ctx4.hex()], paths=[b'anim*'])
|
|
821
|
-
# with two paths, Git starts returning the merge
|
|
822
|
-
# but Mercurial does not. This seems more consistent on the Mercurial
|
|
823
|
-
# side, so we won't compare. It would be:
|
|
824
|
-
# assert_compare(revisions=[ctx4.hex()], paths=[b'anim*', b'foo'])
|
|
825
|
-
|
|
826
815
|
# orderings
|
|
827
816
|
#
|
|
828
817
|
# Comparison is limited because Mercurial orderings don't exactly
|
|
@@ -122,7 +122,6 @@ def test_update_references(gitaly_rhgitaly_comparison,
|
|
|
122
122
|
normalize_commit_message(response.commit)
|
|
123
123
|
|
|
124
124
|
find_commit_helper = fixture.rpc_helper(
|
|
125
|
-
hg_server='rhgitaly',
|
|
126
125
|
stub_cls=CommitServiceStub,
|
|
127
126
|
method_name='FindCommit',
|
|
128
127
|
request_cls=FindCommitRequest,
|
|
@@ -77,7 +77,8 @@ TESTS_DATA_DIR = Path(__file__).parent / 'data'
|
|
|
77
77
|
TIP_TAG_NAME = b'tip'
|
|
78
78
|
|
|
79
79
|
|
|
80
|
-
|
|
80
|
+
@parametrize('hg_server', ('hgitaly', 'rhgitaly'))
|
|
81
|
+
def test_compare_find_merge_base(gitaly_rhgitaly_comparison, hg_server):
|
|
81
82
|
fixture = gitaly_rhgitaly_comparison
|
|
82
83
|
gitaly_repo = fixture.gitaly_repo
|
|
83
84
|
git_repo = fixture.git_repo
|
|
@@ -111,7 +112,10 @@ def test_compare_find_merge_base(gitaly_rhgitaly_comparison):
|
|
|
111
112
|
parent=node_mod.nullid).hex()
|
|
112
113
|
git_shas[sha4] = git_repo.branches()[b'branch/other']['sha']
|
|
113
114
|
|
|
114
|
-
|
|
115
|
+
if hg_server == 'rhgitaly':
|
|
116
|
+
hgitaly_channel = fixture.rhgitaly_channel
|
|
117
|
+
else:
|
|
118
|
+
hgitaly_channel = fixture.hgitaly_channel
|
|
115
119
|
diff_stubs = dict(
|
|
116
120
|
git=RepositoryServiceStub(fixture.gitaly_channel),
|
|
117
121
|
hg=RepositoryServiceStub(hgitaly_channel),
|
|
@@ -361,10 +365,11 @@ def test_repository_size(gitaly_comparison,
|
|
|
361
365
|
relative_path='/some/path'))
|
|
362
366
|
|
|
363
367
|
|
|
368
|
+
@parametrize('hg_server', ('hgitaly', 'rhgitaly'))
|
|
364
369
|
def test_has_local_branches(gitaly_rhgitaly_comparison,
|
|
365
|
-
server_repos_root
|
|
370
|
+
server_repos_root,
|
|
371
|
+
hg_server):
|
|
366
372
|
fixture = gitaly_rhgitaly_comparison
|
|
367
|
-
hg_server = 'rhgitaly'
|
|
368
373
|
grpc_repo = fixture.gitaly_repo
|
|
369
374
|
rpc_helper = fixture.rpc_helper(
|
|
370
375
|
hg_server=hg_server,
|
|
@@ -377,11 +382,6 @@ def test_has_local_branches(gitaly_rhgitaly_comparison,
|
|
|
377
382
|
|
|
378
383
|
assert_compare(repository=grpc_repo)
|
|
379
384
|
|
|
380
|
-
wrapper = fixture.hg_repo_wrapper
|
|
381
|
-
wrapper.commit_file('foo')
|
|
382
|
-
wrapper.command('gitlab-mirror')
|
|
383
|
-
assert_compare(repository=grpc_repo)
|
|
384
|
-
|
|
385
385
|
# repo does not exist
|
|
386
386
|
assert_compare_errors(
|
|
387
387
|
same_details=False,
|
|
@@ -657,9 +657,9 @@ def test_create_bundle_from_ref_list(
|
|
|
657
657
|
assert not target_repo_path(vcs, 'broken-bundle').exists()
|
|
658
658
|
|
|
659
659
|
|
|
660
|
-
|
|
660
|
+
@parametrize('hg_server', ('hgitaly', 'rhgitaly'))
|
|
661
|
+
def test_search_files_by_name(gitaly_rhgitaly_comparison, hg_server):
|
|
661
662
|
fixture = gitaly_rhgitaly_comparison
|
|
662
|
-
hg_server = 'rhgitaly'
|
|
663
663
|
|
|
664
664
|
wrapper = fixture.hg_repo_wrapper
|
|
665
665
|
ctx0 = wrapper.write_commit('afoo', message="Some foo")
|
|
@@ -841,7 +841,6 @@ def test_write_ref(gitaly_rhgitaly_comparison, server_repos_root, hg_server):
|
|
|
841
841
|
normalize_commit_message(response.commit)
|
|
842
842
|
|
|
843
843
|
find_commit_helper = fixture.rpc_helper(
|
|
844
|
-
hg_server='rhgitaly',
|
|
845
844
|
stub_cls=CommitServiceStub,
|
|
846
845
|
method_name='FindCommit',
|
|
847
846
|
request_cls=FindCommitRequest,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
18.7.0a0
|
|
@@ -13,6 +13,7 @@ utilities about refs, i.e, anything about a full ref path, such as
|
|
|
13
13
|
or tags.
|
|
14
14
|
"""
|
|
15
15
|
from fnmatch import fnmatch
|
|
16
|
+
import os
|
|
16
17
|
import re
|
|
17
18
|
|
|
18
19
|
from heptapod.gitlab.branch import gitlab_branch_ref
|
|
@@ -22,6 +23,8 @@ from hgext3rd.heptapod.branch import (
|
|
|
22
23
|
get_default_gitlab_branch,
|
|
23
24
|
)
|
|
24
25
|
from hgext3rd.heptapod.tag import gitlab_tags
|
|
26
|
+
from hgext3rd.heptapod import ensure_gitlab_special_refs
|
|
27
|
+
from hgext3rd.heptapod import ensure_gitlab_keep_arounds
|
|
25
28
|
from hgext3rd.heptapod.special_ref import (
|
|
26
29
|
GITLAB_TYPED_REFS_MISSING,
|
|
27
30
|
parse_special_ref,
|
|
@@ -37,6 +40,33 @@ from hgext3rd.heptapod.keep_around import (
|
|
|
37
40
|
DOT_HG_RX = re.compile(br'\.hg$')
|
|
38
41
|
|
|
39
42
|
|
|
43
|
+
def has_legacy_git_repo(repo):
|
|
44
|
+
"""Return whether there is a legacy Git repo for this Mercurial repo.
|
|
45
|
+
|
|
46
|
+
With "legacy" here is meant the Git repository for a non-native project.
|
|
47
|
+
Git repositories meant for mirroring are *not* included in this scope.
|
|
48
|
+
|
|
49
|
+
As of Heptapod 17.6, this is the best way to know without direct indication
|
|
50
|
+
(from the inside) that a repository is not legacy (hg-git based).
|
|
51
|
+
The reverse implication is false, as there are loopholes:
|
|
52
|
+
|
|
53
|
+
- leftover Git repositories for Projects that have migrated to native
|
|
54
|
+
- native projects with addition conversion for mirrors whose Git
|
|
55
|
+
repositories have not been moved yet (bug, time to run the migration,
|
|
56
|
+
etc.)
|
|
57
|
+
|
|
58
|
+
The caller must be aware of these loopholes and avoid overwriting existing
|
|
59
|
+
data based on the legacy Git repo. In the intended case where this is to
|
|
60
|
+
decide on calling the `ensure` methods, this means it is ok only if there
|
|
61
|
+
is no existing data.
|
|
62
|
+
"""
|
|
63
|
+
# if a repository is legacy, based on hg-git conversion, is whether
|
|
64
|
+
# it has a `.git` repository at the same location. Git repositories
|
|
65
|
+
# for mirroring are in a different place
|
|
66
|
+
git_path = DOT_HG_RX.sub(b'', repo.root) + b'.git'
|
|
67
|
+
return os.path.exists(git_path)
|
|
68
|
+
|
|
69
|
+
|
|
40
70
|
def gitlab_special_ref_target(repo, ref_path):
|
|
41
71
|
"""Return the changeset for a special ref.
|
|
42
72
|
|
|
@@ -105,6 +135,8 @@ def iter_gitlab_special_refs_as_refs(repo, deref=True, patterns=None):
|
|
|
105
135
|
"""
|
|
106
136
|
all_special_refs = special_refs(repo)
|
|
107
137
|
if all_special_refs is GITLAB_TYPED_REFS_MISSING:
|
|
138
|
+
# transitional while we still have an inner Git repo
|
|
139
|
+
# would still be the best we can do near the end of HGitaly2 milestone
|
|
108
140
|
all_special_refs = ensure_special_refs(repo)
|
|
109
141
|
|
|
110
142
|
for sref, sha in all_special_refs.items():
|
|
@@ -115,18 +147,22 @@ def iter_gitlab_special_refs_as_refs(repo, deref=True, patterns=None):
|
|
|
115
147
|
|
|
116
148
|
|
|
117
149
|
def ensure_special_refs(repo):
|
|
150
|
+
if has_legacy_git_repo(repo):
|
|
151
|
+
return ensure_gitlab_special_refs(repo.ui, repo)
|
|
118
152
|
return {}
|
|
119
153
|
|
|
120
154
|
|
|
121
155
|
def ensure_keep_arounds(repo, init_empty=False):
|
|
122
|
-
"""Ensure keep around
|
|
156
|
+
"""Ensure keep around from Git repo if present or create.
|
|
123
157
|
|
|
124
158
|
An empty file is created so that the keep-arounds file is no
|
|
125
159
|
more missing, but only if `init_empty` is `True`, so that
|
|
126
|
-
responsibility is handed to the caller,
|
|
160
|
+
responsibility is handed to the caller, than must use the
|
|
127
161
|
option only after having obtained the missing marker.
|
|
128
162
|
"""
|
|
129
|
-
if
|
|
163
|
+
if has_legacy_git_repo(repo):
|
|
164
|
+
ensure_gitlab_keep_arounds(repo.ui, repo)
|
|
165
|
+
elif init_empty:
|
|
130
166
|
init_keep_arounds(repo, ())
|
|
131
167
|
|
|
132
168
|
|
|
@@ -234,6 +234,19 @@ class ManifestMiner:
|
|
|
234
234
|
prefix + b'/'.join(flat_path) if flat_path else dir_path
|
|
235
235
|
)
|
|
236
236
|
|
|
237
|
+
def file_names_by_regexp(self, rx, subdir=b''):
|
|
238
|
+
manifest = self.changeset.manifest()
|
|
239
|
+
subdir_prefix = subdir + b'/' if subdir else b''
|
|
240
|
+
|
|
241
|
+
for file_path in manifest.iterkeys():
|
|
242
|
+
if not file_path.startswith(subdir_prefix):
|
|
243
|
+
continue
|
|
244
|
+
|
|
245
|
+
if rx is not None and rx.search(file_path) is None:
|
|
246
|
+
continue
|
|
247
|
+
|
|
248
|
+
yield file_path
|
|
249
|
+
|
|
237
250
|
def iter_files_with_content(self, exclude_binary=False):
|
|
238
251
|
manifest = self.changeset.manifest()
|
|
239
252
|
repo = self.changeset.repo().unfiltered()
|
|
@@ -22,13 +22,24 @@ from mercurial import (
|
|
|
22
22
|
from hgext3rd.heptapod.branch import get_default_gitlab_branch
|
|
23
23
|
|
|
24
24
|
from .. import (
|
|
25
|
+
manifest,
|
|
25
26
|
message,
|
|
26
27
|
)
|
|
27
28
|
from ..errors import (
|
|
28
29
|
not_implemented,
|
|
29
30
|
structured_abort,
|
|
30
31
|
)
|
|
32
|
+
from ..file_context import (
|
|
33
|
+
git_perms,
|
|
34
|
+
)
|
|
35
|
+
from ..git import (
|
|
36
|
+
OBJECT_MODE_TREE,
|
|
37
|
+
)
|
|
31
38
|
from ..logging import LoggerAdapter
|
|
39
|
+
from ..oid import (
|
|
40
|
+
tree_oid,
|
|
41
|
+
blob_oid,
|
|
42
|
+
)
|
|
32
43
|
from ..pagination import (
|
|
33
44
|
extract_limit,
|
|
34
45
|
)
|
|
@@ -51,14 +62,22 @@ from ..stream import (
|
|
|
51
62
|
from ..stub.commit_pb2 import (
|
|
52
63
|
CommitIsAncestorRequest,
|
|
53
64
|
CommitIsAncestorResponse,
|
|
65
|
+
TreeEntryRequest,
|
|
66
|
+
TreeEntryResponse,
|
|
54
67
|
CheckObjectsExistRequest,
|
|
55
68
|
CheckObjectsExistResponse,
|
|
56
69
|
CountCommitsRequest,
|
|
57
70
|
CountCommitsResponse,
|
|
58
71
|
CountDivergingCommitsRequest,
|
|
59
72
|
CountDivergingCommitsResponse,
|
|
73
|
+
GetTreeEntriesError,
|
|
74
|
+
GetTreeEntriesRequest,
|
|
75
|
+
GetTreeEntriesResponse,
|
|
76
|
+
TreeEntry,
|
|
60
77
|
ListFilesRequest,
|
|
61
78
|
ListFilesResponse,
|
|
79
|
+
FindCommitRequest,
|
|
80
|
+
FindCommitResponse,
|
|
62
81
|
CommitStatsRequest,
|
|
63
82
|
CommitStatsResponse,
|
|
64
83
|
FindAllCommitsRequest,
|
|
@@ -81,7 +100,9 @@ from ..stub.commit_pb2 import (
|
|
|
81
100
|
GetCommitMessagesResponse,
|
|
82
101
|
)
|
|
83
102
|
from ..stub.errors_pb2 import (
|
|
103
|
+
PathError,
|
|
84
104
|
PathNotFoundError,
|
|
105
|
+
ResolveRevisionError,
|
|
85
106
|
)
|
|
86
107
|
from ..stub.commit_pb2_grpc import CommitServiceServicer
|
|
87
108
|
from ..util import (
|
|
@@ -129,6 +150,110 @@ class CommitServicer(CommitServiceServicer, HGitalyServicer):
|
|
|
129
150
|
|
|
130
151
|
return CommitIsAncestorResponse(value=result)
|
|
131
152
|
|
|
153
|
+
def TreeEntry(self, request: TreeEntryRequest,
|
|
154
|
+
context) -> TreeEntryResponse:
|
|
155
|
+
"""Return an entry of a tree.
|
|
156
|
+
|
|
157
|
+
The name could be confusing with the entry for a tree: the entry
|
|
158
|
+
can be of any type.
|
|
159
|
+
|
|
160
|
+
Actually, it always yields one response message, using the empty
|
|
161
|
+
response in case the given path does not resolve.
|
|
162
|
+
"""
|
|
163
|
+
repo = self.load_repo(request.repository, context).unfiltered()
|
|
164
|
+
changeset = gitlab_revision_changeset(repo, request.revision)
|
|
165
|
+
if changeset is None:
|
|
166
|
+
# As of v15.8.0, Gitaly error details don't give up anything
|
|
167
|
+
context.abort(StatusCode.NOT_FOUND, "tree entry not found")
|
|
168
|
+
|
|
169
|
+
sha = changeset.hex().decode('ascii')
|
|
170
|
+
# early testing shows that even for leaf files, Gitaly ignores
|
|
171
|
+
# trailing slashes
|
|
172
|
+
path = request.path.rstrip(b'/')
|
|
173
|
+
|
|
174
|
+
try:
|
|
175
|
+
filectx = changeset.filectx(path)
|
|
176
|
+
except error.ManifestLookupError:
|
|
177
|
+
filectx = None
|
|
178
|
+
|
|
179
|
+
# TODO investigate why it's not the usual WRITE_BUFFER_SIZE
|
|
180
|
+
# The only occurrence we could find so far was a 16384 in grpc Golang
|
|
181
|
+
# lib (size of HTTP/2 frames).
|
|
182
|
+
# Could be because Gitaly implementation uses CopyN to send to
|
|
183
|
+
# its chunker (in `streamio.go`) and CopyN has a buffer.
|
|
184
|
+
buffer_size = 16384
|
|
185
|
+
if filectx is not None:
|
|
186
|
+
otype = TreeEntryResponse.ObjectType.BLOB
|
|
187
|
+
oid = blob_oid(repo, sha, path)
|
|
188
|
+
mode = git_perms(filectx)
|
|
189
|
+
size = filectx.size()
|
|
190
|
+
max_size = request.max_size
|
|
191
|
+
if max_size != 0 and size > request.max_size:
|
|
192
|
+
context.abort(
|
|
193
|
+
StatusCode.FAILED_PRECONDITION,
|
|
194
|
+
"object size (%d) is bigger than the maximum "
|
|
195
|
+
"allowed size (%d)" % (size, max_size))
|
|
196
|
+
|
|
197
|
+
data = filectx.data()
|
|
198
|
+
|
|
199
|
+
limit = request.limit
|
|
200
|
+
if limit != 0:
|
|
201
|
+
data = data[:limit]
|
|
202
|
+
|
|
203
|
+
offset = 0
|
|
204
|
+
while offset < size:
|
|
205
|
+
# only the first response of the stream carries the metadata
|
|
206
|
+
if offset:
|
|
207
|
+
resp = TreeEntryResponse()
|
|
208
|
+
else:
|
|
209
|
+
resp = TreeEntryResponse(type=otype,
|
|
210
|
+
oid=oid,
|
|
211
|
+
size=size,
|
|
212
|
+
mode=mode)
|
|
213
|
+
|
|
214
|
+
resp.data = data[offset:offset+buffer_size]
|
|
215
|
+
offset += buffer_size
|
|
216
|
+
|
|
217
|
+
yield resp
|
|
218
|
+
return
|
|
219
|
+
|
|
220
|
+
subtrees, file_paths = manifest.miner(changeset).ls_dir(path)
|
|
221
|
+
if not subtrees and not file_paths:
|
|
222
|
+
context.abort(StatusCode.NOT_FOUND, "tree entry not found")
|
|
223
|
+
|
|
224
|
+
# path is an actual directory
|
|
225
|
+
|
|
226
|
+
# size computation to match Git response.
|
|
227
|
+
# The formula for size computation is meant to match the size
|
|
228
|
+
# returned by Git, which is actually the size of the raw Git Tree
|
|
229
|
+
# object as returned by `git-cat-file` with `<type>` parameter.
|
|
230
|
+
#
|
|
231
|
+
# The raw Git Tree object is a simple concatenation of entries, each
|
|
232
|
+
# one being made of
|
|
233
|
+
# - mode (octal representation): 6 bytes for blobs (e.g 100644),
|
|
234
|
+
# 5 bytes for subtrees (40000)
|
|
235
|
+
# - 0x20 (separator): 1 byte
|
|
236
|
+
# - name of the entry
|
|
237
|
+
# - 0x00 (separator): 1 byte
|
|
238
|
+
# - binary SHA-1 of the object referenced by the entry: 20 bytes
|
|
239
|
+
# Hence the total length per entry is 27 + (name length) for subtrees
|
|
240
|
+
# and 28 + (name length) for blobs.
|
|
241
|
+
# Finally, our `ls_dir` returns full paths from the root, so the
|
|
242
|
+
# have to substract `len(path + b'/')`, hence `len(path) + 1`
|
|
243
|
+
# for each entry.
|
|
244
|
+
size = (
|
|
245
|
+
28 * len(file_paths) + 27 * len(subtrees)
|
|
246
|
+
+ sum(len(s) for s in subtrees) + sum(len(f) for f in file_paths)
|
|
247
|
+
- (len(subtrees) + len(file_paths)) * (len(path) + 1)
|
|
248
|
+
)
|
|
249
|
+
# max_size does not apply here (see Gitaly comparison test)
|
|
250
|
+
yield TreeEntryResponse(
|
|
251
|
+
type=TreeEntryResponse.ObjectType.TREE,
|
|
252
|
+
oid=tree_oid(repo, sha, path),
|
|
253
|
+
mode=OBJECT_MODE_TREE,
|
|
254
|
+
size=size,
|
|
255
|
+
)
|
|
256
|
+
|
|
132
257
|
def CountCommits(self,
|
|
133
258
|
request: CountCommitsRequest,
|
|
134
259
|
context) -> CountCommitsResponse:
|
|
@@ -228,6 +353,142 @@ class CommitServicer(CommitServiceServicer, HGitalyServicer):
|
|
|
228
353
|
return CountDivergingCommitsResponse(left_count=left_count,
|
|
229
354
|
right_count=right_count)
|
|
230
355
|
|
|
356
|
+
def GetTreeEntries(self, request: GetTreeEntriesRequest,
|
|
357
|
+
context) -> GetTreeEntriesResponse:
|
|
358
|
+
repo = self.load_repo(request.repository, context)
|
|
359
|
+
revision = request.revision
|
|
360
|
+
changeset = gitlab_revision_changeset(repo, revision)
|
|
361
|
+
if changeset is None:
|
|
362
|
+
structured_abort(
|
|
363
|
+
context,
|
|
364
|
+
StatusCode.INVALID_ARGUMENT,
|
|
365
|
+
"invalid revision or path",
|
|
366
|
+
GetTreeEntriesError(resolve_tree=ResolveRevisionError(
|
|
367
|
+
revision=request.revision)))
|
|
368
|
+
|
|
369
|
+
repo = repo.unfiltered()
|
|
370
|
+
sha = changeset.hex().decode('ascii')
|
|
371
|
+
if not request.path:
|
|
372
|
+
structured_abort(
|
|
373
|
+
context,
|
|
374
|
+
StatusCode.INVALID_ARGUMENT, "empty path",
|
|
375
|
+
GetTreeEntriesError(
|
|
376
|
+
path=PathError(path=request.path,
|
|
377
|
+
error_type=PathError.ERROR_TYPE_EMPTY_PATH))
|
|
378
|
+
)
|
|
379
|
+
path = request.path.rstrip(b'/') # same as in TreeEntry
|
|
380
|
+
if path == b'.': # special case, means the top directory
|
|
381
|
+
path = b''
|
|
382
|
+
|
|
383
|
+
blob_type = TreeEntry.EntryType.BLOB
|
|
384
|
+
tree_type = TreeEntry.EntryType.TREE
|
|
385
|
+
miner = manifest.miner(changeset)
|
|
386
|
+
|
|
387
|
+
if request.recursive:
|
|
388
|
+
entries = ((epath, is_dir, b'')
|
|
389
|
+
for epath, is_dir in miner.iter_dir_recursive(path))
|
|
390
|
+
elif request.skip_flat_paths:
|
|
391
|
+
trees, files = miner.ls_dir(path)
|
|
392
|
+
entries = itertools.chain(
|
|
393
|
+
((epath, True, b'') for epath in trees),
|
|
394
|
+
((epath, False, b'') for epath in files),
|
|
395
|
+
)
|
|
396
|
+
else:
|
|
397
|
+
entries = miner.iter_dir_with_flat_paths(path)
|
|
398
|
+
|
|
399
|
+
# TODO request.sort == SortBy.TREES_FIRST
|
|
400
|
+
limit = extract_limit(request)
|
|
401
|
+
if limit == 0:
|
|
402
|
+
return # simplify things (next_cursor computation notably)
|
|
403
|
+
|
|
404
|
+
# voids the advantages of iteration, but there's few choice
|
|
405
|
+
# in the matter with sort and pagination
|
|
406
|
+
if request.sort == GetTreeEntriesRequest.SortBy.TREES_FIRST:
|
|
407
|
+
# each entry is (path, is_dir (bool), flat_path)
|
|
408
|
+
# where flat_path is ignored for sorting purposes.
|
|
409
|
+
# TODO OPTIM is it an improvement to avoid this post-processing
|
|
410
|
+
# sort by making ManifestMiner already provide directories first?
|
|
411
|
+
# to get an advantage, we'd need to avoid at least a list
|
|
412
|
+
# construction
|
|
413
|
+
entries = sorted(
|
|
414
|
+
entries,
|
|
415
|
+
key=lambda entry: (1 if entry[1] else 2, entry[0]))
|
|
416
|
+
else:
|
|
417
|
+
# TODO OPTIM because Mercurial manifests are stored in
|
|
418
|
+
# lexicographical ordering, this sort is probably unnecessary.
|
|
419
|
+
# In first impl of sorting and pagination, probably not worth
|
|
420
|
+
# the risk.
|
|
421
|
+
# Also would be neat to avoid consuming the iterator into
|
|
422
|
+
# a least, but is it worth the added complexity if it can't
|
|
423
|
+
# be done in the TREES_FIRST case?
|
|
424
|
+
# What if GitLab introduces a sort direction anyway ?
|
|
425
|
+
entries = sorted(entries) # sorts lexicographically by path
|
|
426
|
+
|
|
427
|
+
if not entries:
|
|
428
|
+
# there is no such thing as an empty directory in Mercurial
|
|
429
|
+
try:
|
|
430
|
+
changeset.filectx(path)
|
|
431
|
+
except error.ManifestLookupError:
|
|
432
|
+
if request.recursive:
|
|
433
|
+
err_code = StatusCode.NOT_FOUND
|
|
434
|
+
else:
|
|
435
|
+
err_code = StatusCode.INVALID_ARGUMENT
|
|
436
|
+
structured_abort(
|
|
437
|
+
context,
|
|
438
|
+
err_code,
|
|
439
|
+
"invalid revision or path",
|
|
440
|
+
GetTreeEntriesError(resolve_tree=ResolveRevisionError(
|
|
441
|
+
revision=request.revision))
|
|
442
|
+
)
|
|
443
|
+
else:
|
|
444
|
+
structured_abort(
|
|
445
|
+
context,
|
|
446
|
+
StatusCode.INVALID_ARGUMENT,
|
|
447
|
+
"path not treeish",
|
|
448
|
+
GetTreeEntriesError(resolve_tree=ResolveRevisionError(
|
|
449
|
+
revision=request.revision))
|
|
450
|
+
)
|
|
451
|
+
|
|
452
|
+
def entry_oid(path, is_dir):
|
|
453
|
+
return (tree_oid if is_dir else blob_oid)(repo, sha, path)
|
|
454
|
+
|
|
455
|
+
page_token = request.pagination_params.page_token
|
|
456
|
+
if page_token:
|
|
457
|
+
for offset, (path, is_dir, _) in enumerate(entries):
|
|
458
|
+
if entry_oid(path, is_dir) == page_token:
|
|
459
|
+
break
|
|
460
|
+
else:
|
|
461
|
+
context.abort(StatusCode.INTERNAL,
|
|
462
|
+
"could not find starting OID: %s" % page_token)
|
|
463
|
+
|
|
464
|
+
entries = entries[offset+1:]
|
|
465
|
+
|
|
466
|
+
if limit < len(entries):
|
|
467
|
+
entries = entries[:limit]
|
|
468
|
+
last_path, last_is_dir = entries[-1][:2]
|
|
469
|
+
next_cursor = entry_oid(last_path, last_is_dir)
|
|
470
|
+
else:
|
|
471
|
+
next_cursor = ''
|
|
472
|
+
|
|
473
|
+
yield from chunked_with_cursor(
|
|
474
|
+
GetTreeEntriesResponse,
|
|
475
|
+
entries,
|
|
476
|
+
next_cursor=next_cursor,
|
|
477
|
+
builder=lambda chunk: dict(
|
|
478
|
+
entries=(
|
|
479
|
+
TreeEntry(
|
|
480
|
+
path=path,
|
|
481
|
+
type=tree_type if is_dir else blob_type,
|
|
482
|
+
oid=entry_oid(path, is_dir),
|
|
483
|
+
commit_oid=revision,
|
|
484
|
+
mode=(OBJECT_MODE_TREE if is_dir else
|
|
485
|
+
git_perms(changeset.filectx(path))),
|
|
486
|
+
flat_path=flat_path,
|
|
487
|
+
)
|
|
488
|
+
for path, is_dir, flat_path in chunk)
|
|
489
|
+
)
|
|
490
|
+
)
|
|
491
|
+
|
|
231
492
|
def ListFiles(self, request: ListFilesRequest,
|
|
232
493
|
context) -> ListFilesResponse:
|
|
233
494
|
repo = self.load_repo(request.repository, context)
|
|
@@ -262,6 +523,27 @@ class CommitServicer(CommitServiceServicer, HGitalyServicer):
|
|
|
262
523
|
deletions=removetotal,
|
|
263
524
|
)
|
|
264
525
|
|
|
526
|
+
def FindCommit(self,
|
|
527
|
+
request: FindCommitRequest, context) -> FindCommitResponse:
|
|
528
|
+
logger = LoggerAdapter(base_logger, context)
|
|
529
|
+
revision = request.revision
|
|
530
|
+
if not revision:
|
|
531
|
+
context.abort(StatusCode.INVALID_ARGUMENT, "empty revision")
|
|
532
|
+
|
|
533
|
+
repo = self.load_repo(request.repository, context)
|
|
534
|
+
ctx = gitlab_revision_changeset(repo, revision)
|
|
535
|
+
|
|
536
|
+
if ctx is None:
|
|
537
|
+
logger.warning("FindCommit revision %r could not be found",
|
|
538
|
+
revision)
|
|
539
|
+
return FindCommitResponse()
|
|
540
|
+
|
|
541
|
+
if ctx.rev() == NULL_REV:
|
|
542
|
+
return FindCommitResponse()
|
|
543
|
+
|
|
544
|
+
commit = message.commit(ctx)
|
|
545
|
+
return FindCommitResponse(commit=commit)
|
|
546
|
+
|
|
265
547
|
def FindAllCommits(self, request: FindAllCommitsRequest,
|
|
266
548
|
context) -> FindAllCommitsResponse:
|
|
267
549
|
logger = LoggerAdapter(base_logger, context)
|
|
@@ -559,14 +841,6 @@ class CommitServicer(CommitServiceServicer, HGitalyServicer):
|
|
|
559
841
|
if request.max_parents == 1:
|
|
560
842
|
revset += b" and not merge()"
|
|
561
843
|
|
|
562
|
-
if request.paths:
|
|
563
|
-
revset += b" and ("
|
|
564
|
-
revset += b" or ".join(
|
|
565
|
-
b'file("%s/%s")' % (repo.root, p)
|
|
566
|
-
for p in request.paths
|
|
567
|
-
)
|
|
568
|
-
revset += b")"
|
|
569
|
-
|
|
570
844
|
Order = ListCommitsRequest.Order
|
|
571
845
|
reverse = request.reverse
|
|
572
846
|
|