hgitaly 18.7.1__tar.gz → 18.7.2__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.1/hgitaly.egg-info → hgitaly-18.7.2}/PKG-INFO +1 -1
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_blob_tree.py +1 -1
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_commit.py +11 -2
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_ref.py +14 -0
- hgitaly-18.7.2/hgitaly/VERSION +1 -0
- hgitaly-18.7.2/hgitaly/scripts/__init__.py +3 -0
- hgitaly-18.7.2/hgitaly/scripts/load_tests.py +373 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2/hgitaly.egg-info}/PKG-INFO +1 -1
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/SOURCES.txt +3 -1
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/entry_points.txt +1 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/setup.py +1 -0
- hgitaly-18.7.1/hgitaly/VERSION +0 -1
- {hgitaly-18.7.1 → hgitaly-18.7.2}/LICENSE +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/MANIFEST.in +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/README.md +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/comparison.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/conftest.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/gitaly.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/hgitaly_rhgitaly_comparison.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/rhgitaly.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_comparison.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_diff.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_gitaly_server.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_mercurial_aux_git.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_mercurial_operations.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_mercurial_repository.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_operations.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_remote.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_repository_service.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_rhgitaly_server.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/functional_tests/test_server.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/revset.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/test_revset.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgext3rd/hgitaly/tests/test_serve.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/branch.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/changelog.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/diff.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/errors.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/feature.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/file_content.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/file_context.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/git.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/gitlab_ref.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/identification.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/logging.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/manifest.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/message.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/oid.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/pagination.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/path.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/peer.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/procutil.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/repository.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/revision.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/revset.py +0 -0
- /hgitaly-18.7.1/hgitaly/scripts.py → /hgitaly-18.7.2/hgitaly/scripts/stats.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/address.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/mono.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/tests/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/tests/test_address.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/tests/test_mono.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/tests/test_worker.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/server/worker.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/analysis.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/blob.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/commit.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/diff.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/interceptors.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/mercurial_changeset.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/mercurial_namespace.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/mercurial_operations.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/mercurial_repository.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/operations.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/ref.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/repository.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/server.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/fixture.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_analysis.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_blob.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_commit.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_default_branch.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_diff.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_changeset.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_namespace.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_operations.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_mercurial_repository.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_operations.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_ref.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_repository_service.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/service/tests/test_server.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/servicer.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/ssh.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stream.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/analysis_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/analysis_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/blob_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/blob_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/commit_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/commit_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/diff_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/diff_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/errors_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/errors_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/lint_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/lint_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_aux_git_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_aux_git_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_changeset_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_changeset_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_namespace_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_namespace_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_operations_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_operations_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_repository_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/mercurial_repository_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/operations_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/operations_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/ref_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/ref_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/remote_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/remote_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/repository_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/repository_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/server_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/server_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/shared_pb2.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/stub/shared_pb2_grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tag.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/bundle.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/context.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/grpc.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/multiprocessing.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/repo.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/ssh.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/sshd.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/storage.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/tests/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/testing/tests/test_sshd.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/__init__.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/common.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_branch.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_diff.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_errors.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_feature.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_file_context.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_gitlab_ref.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_identification.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_manifest.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_messages.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_oid.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_peer.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_repository.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_revision.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_revset.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_servicer.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_stream.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_tag.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/tests/test_workdir.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/util.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly/workdir.py +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/dependency_links.txt +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/requires.txt +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/hgitaly.egg-info/top_level.txt +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/install-requirements.txt +0 -0
- {hgitaly-18.7.1 → hgitaly-18.7.2}/setup.cfg +0 -0
|
@@ -412,7 +412,7 @@ def test_compare_get_tree_entries_pagination(gitaly_rhgitaly_comparison):
|
|
|
412
412
|
# case of unknown revision and limit=0
|
|
413
413
|
assert_compare_errors(path=b'.', revision=b'unknown',
|
|
414
414
|
pagination_params=PaginationParameter(limit=0),
|
|
415
|
-
|
|
415
|
+
)
|
|
416
416
|
|
|
417
417
|
# case of no pagination params
|
|
418
418
|
assert_compare_aggregated(path=b'sub',
|
|
@@ -41,6 +41,8 @@ if skip_comparison_tests(): # pragma no cover
|
|
|
41
41
|
|
|
42
42
|
parametrize = pytest.mark.parametrize
|
|
43
43
|
|
|
44
|
+
PSEUDO_RANGE_SEPARATORS = (b'..', b'...')
|
|
45
|
+
|
|
44
46
|
|
|
45
47
|
def test_compare_last_commit_for(gitaly_rhgitaly_comparison):
|
|
46
48
|
fixture = gitaly_rhgitaly_comparison
|
|
@@ -594,10 +596,10 @@ def test_compare_count_find_commits(gitaly_rhgitaly_comparison, hg_server):
|
|
|
594
596
|
# when `revision` is provided as <revspec>
|
|
595
597
|
with sorted_comparison():
|
|
596
598
|
all_revs = [ctx0.hex(), ctx1.hex(), ctx2.hex(), ctx3.hex(), ctx4.hex()]
|
|
597
|
-
for
|
|
599
|
+
for range_sep in PSEUDO_RANGE_SEPARATORS:
|
|
598
600
|
for r1 in all_revs:
|
|
599
601
|
for r2 in all_revs:
|
|
600
|
-
assert_compare(revision=r1 +
|
|
602
|
+
assert_compare(revision=r1 + range_sep + r2)
|
|
601
603
|
|
|
602
604
|
# with message_regex
|
|
603
605
|
rx = 'FOO.*zoO' # tests case insensitivity
|
|
@@ -835,6 +837,13 @@ def test_compare_list_commits(gitaly_rhgitaly_comparison, hg_server):
|
|
|
835
837
|
|
|
836
838
|
assert_compare(revisions=[ctx4.hex(), caret(ctx1)])
|
|
837
839
|
assert_compare(revisions=[ctx4.hex(), caret(ctx1)], reverse=True)
|
|
840
|
+
# symmetric difference (HGitaly does not accept pseudo range revisions)
|
|
841
|
+
# this is the only actual testing of `reverse` for RHGitaly many_commits
|
|
842
|
+
symdiff_revspec = b'...'.join((ctx2.hex(), ctx4.hex()))
|
|
843
|
+
if hg_server == 'rhgitaly':
|
|
844
|
+
assert_compare(revisions=[symdiff_revspec])
|
|
845
|
+
assert_compare(revisions=[symdiff_revspec], reverse=True)
|
|
846
|
+
|
|
838
847
|
# interpretation of several exclusions
|
|
839
848
|
assert_compare(revisions=[ctx4.hex(), caret(ctx1), caret(ctx2)])
|
|
840
849
|
|
|
@@ -585,6 +585,9 @@ def test_list_refs(gitaly_rhgitaly_comparison, hg_server):
|
|
|
585
585
|
ref_msg.name[len(prefix):])
|
|
586
586
|
if all_pseudo_ref_idx is not None:
|
|
587
587
|
del resp.references[all_pseudo_ref_idx]
|
|
588
|
+
if resp.HasField('pagination_cursor'):
|
|
589
|
+
pc = resp.pagination_cursor
|
|
590
|
+
pc.next_cursor = b64decode(pc.next_cursor).decode()
|
|
588
591
|
|
|
589
592
|
rpc_helper = fixture.rpc_helper(
|
|
590
593
|
hg_server=hg_server,
|
|
@@ -631,6 +634,8 @@ def test_list_refs(gitaly_rhgitaly_comparison, hg_server):
|
|
|
631
634
|
fixture.write_special_ref(b'pipeline/13', hg_sha)
|
|
632
635
|
rpc_helper.assert_compare()
|
|
633
636
|
for head in False, True:
|
|
637
|
+
rpc_helper.assert_compare(patterns=[b'refs/'], head=head)
|
|
638
|
+
rpc_helper.assert_compare(patterns=[b'refs/pipeline/'], head=head)
|
|
634
639
|
rpc_helper.assert_compare(patterns=[b'refs/heads/'], head=head)
|
|
635
640
|
rpc_helper.assert_compare(patterns=[b'refs/tags/'], head=head)
|
|
636
641
|
|
|
@@ -692,6 +697,15 @@ def test_list_refs(gitaly_rhgitaly_comparison, hg_server):
|
|
|
692
697
|
head=False,
|
|
693
698
|
)
|
|
694
699
|
|
|
700
|
+
# with pagination parameters (RHGitaly only, HGitaly no longer used)
|
|
701
|
+
paginated = dict(head=False,
|
|
702
|
+
patterns=[b'refs/heads/'], # avoid ALL
|
|
703
|
+
pagination_params=PaginationParameter(limit=2))
|
|
704
|
+
if hg_server == 'rhgitaly':
|
|
705
|
+
rpc_helper.assert_compare(**paginated)
|
|
706
|
+
rpc_helper.assert_compare(sort_by=SortBy(key=SortBy.AUTHORDATE),
|
|
707
|
+
**paginated)
|
|
708
|
+
|
|
695
709
|
# FindRefsByOID is almost a subset of ListRefs, the only stated
|
|
696
710
|
# thing that ListRefs would not do is accepting oids by prefix.
|
|
697
711
|
# So we'll use the same setup
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
18.7.2
|
|
@@ -0,0 +1,373 @@
|
|
|
1
|
+
"""Load tests for HGitaly.
|
|
2
|
+
|
|
3
|
+
This simple script assumes that the HGitaly server has a given set of
|
|
4
|
+
repositories:
|
|
5
|
+
|
|
6
|
+
They must absolutely be dedicated to the task, because the load tests
|
|
7
|
+
may involve mutation calls. Hence the script expects the HGitaly server
|
|
8
|
+
to operate on its own separate repositories root and will clone everything
|
|
9
|
+
if needed.
|
|
10
|
+
|
|
11
|
+
Future facilities:
|
|
12
|
+
|
|
13
|
+
- configuring and launching RHGitaly
|
|
14
|
+
"""
|
|
15
|
+
import argparse
|
|
16
|
+
import json
|
|
17
|
+
import logging
|
|
18
|
+
import random
|
|
19
|
+
import statistics
|
|
20
|
+
import threading
|
|
21
|
+
import multiprocessing as mp
|
|
22
|
+
import time
|
|
23
|
+
from urllib.parse import urlparse
|
|
24
|
+
|
|
25
|
+
import grpc
|
|
26
|
+
|
|
27
|
+
from hgitaly import feature
|
|
28
|
+
from hgitaly.servicer import (
|
|
29
|
+
SKIP_HOOKS_MD_KEY,
|
|
30
|
+
NATIVE_PROJECT_MD_KEY,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from hgitaly.stub.commit_pb2_grpc import CommitServiceStub
|
|
34
|
+
from hgitaly.stub.commit_pb2 import (
|
|
35
|
+
CountCommitsRequest,
|
|
36
|
+
FindCommitsRequest,
|
|
37
|
+
)
|
|
38
|
+
from hgitaly.stub.mercurial_operations_pb2 import (
|
|
39
|
+
InvalidateMergeAnalysisRequest,
|
|
40
|
+
MergeAnalysisRequest,
|
|
41
|
+
)
|
|
42
|
+
from hgitaly.stub.mercurial_operations_pb2_grpc import (
|
|
43
|
+
MercurialOperationsServiceStub,
|
|
44
|
+
)
|
|
45
|
+
from hgitaly.stub.mercurial_repository_pb2_grpc import (
|
|
46
|
+
MercurialRepositoryServiceStub,
|
|
47
|
+
)
|
|
48
|
+
from hgitaly.stub.mercurial_repository_pb2 import (
|
|
49
|
+
HgCallRequest,
|
|
50
|
+
)
|
|
51
|
+
from hgitaly.stub.repository_pb2_grpc import RepositoryServiceStub
|
|
52
|
+
from hgitaly.stub.repository_pb2 import (
|
|
53
|
+
CreateRepositoryRequest,
|
|
54
|
+
RepositoryExistsRequest,
|
|
55
|
+
)
|
|
56
|
+
from hgitaly.stub.shared_pb2 import (
|
|
57
|
+
Repository,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
FOSS_HEPTAPOD = 'https://foss.heptapod.net'
|
|
61
|
+
|
|
62
|
+
logger = logging.getLogger(__name__)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def gl_repo(relpath):
|
|
66
|
+
return Repository(storage_name='default', relative_path=relpath)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class LoadWorker:
|
|
70
|
+
|
|
71
|
+
weighted_methods = (
|
|
72
|
+
('find_commits_mercurial_devel', 9),
|
|
73
|
+
('sleep_a_bit', 1),
|
|
74
|
+
('merge_analysis_mercurial_devel', 1),
|
|
75
|
+
)
|
|
76
|
+
repositories = {
|
|
77
|
+
'mercurial-devel': FOSS_HEPTAPOD + '/mercurial/mercurial-devel',
|
|
78
|
+
}
|
|
79
|
+
feature_flags = ()
|
|
80
|
+
|
|
81
|
+
@classmethod
|
|
82
|
+
def compute_random_thresholds(cls):
|
|
83
|
+
total_weight = sum(wm[1] for wm in cls.weighted_methods)
|
|
84
|
+
|
|
85
|
+
thresholds = []
|
|
86
|
+
current = 0
|
|
87
|
+
for meth, weight in cls.weighted_methods:
|
|
88
|
+
thresholds.append((current, meth))
|
|
89
|
+
current += weight / total_weight
|
|
90
|
+
cls.random_thresholds = thresholds
|
|
91
|
+
logger.warning("Random thresholds: %r", thresholds)
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def random_method(cls):
|
|
95
|
+
rand = random.random()
|
|
96
|
+
candidate = cls.random_thresholds[0][0]
|
|
97
|
+
for thr, name in cls.random_thresholds:
|
|
98
|
+
if thr > rand:
|
|
99
|
+
break
|
|
100
|
+
candidate = name
|
|
101
|
+
return candidate
|
|
102
|
+
|
|
103
|
+
def __init__(self, url, queue, wid=None):
|
|
104
|
+
self.url = url = urlparse(url)
|
|
105
|
+
self.queue = queue
|
|
106
|
+
|
|
107
|
+
if url.scheme != 'tcp':
|
|
108
|
+
raise RuntimeError("Unsupported URL scheme: %r" % url.scheme)
|
|
109
|
+
if wid is not None:
|
|
110
|
+
logger.info("Worker %d starting", wid)
|
|
111
|
+
self.channel = grpc.insecure_channel(url.netloc)
|
|
112
|
+
self.hg_operations_service = MercurialOperationsServiceStub(
|
|
113
|
+
self.channel)
|
|
114
|
+
self.hg_repository_service = MercurialRepositoryServiceStub(
|
|
115
|
+
self.channel)
|
|
116
|
+
self.repository_service = RepositoryServiceStub(self.channel)
|
|
117
|
+
self.commit_service = CommitServiceStub(self.channel)
|
|
118
|
+
|
|
119
|
+
def close(self):
|
|
120
|
+
self.channel.close()
|
|
121
|
+
|
|
122
|
+
def grpc_metadata(self):
|
|
123
|
+
mds = feature.as_grpc_metadata(self.feature_flags)
|
|
124
|
+
mds.append((SKIP_HOOKS_MD_KEY, 'true'))
|
|
125
|
+
mds.append((NATIVE_PROJECT_MD_KEY, 'true'))
|
|
126
|
+
return mds
|
|
127
|
+
|
|
128
|
+
def repo_exists(self, relpath):
|
|
129
|
+
return self.repository_service.RepositoryExists(
|
|
130
|
+
RepositoryExistsRequest(repository=gl_repo(relpath))
|
|
131
|
+
).exists
|
|
132
|
+
|
|
133
|
+
def ensure_repos(self):
|
|
134
|
+
for relpath in self.repositories:
|
|
135
|
+
if self.repo_exists(relpath):
|
|
136
|
+
logger.info("Repository %r is present", relpath)
|
|
137
|
+
else:
|
|
138
|
+
self.import_repo(relpath)
|
|
139
|
+
|
|
140
|
+
def import_repo(self, relpath):
|
|
141
|
+
logger.warning("Importing repository %r", relpath)
|
|
142
|
+
self.repository_service.CreateRepository(
|
|
143
|
+
CreateRepositoryRequest(repository=gl_repo(relpath))
|
|
144
|
+
)
|
|
145
|
+
|
|
146
|
+
src_url = self.repositories[relpath]
|
|
147
|
+
self.hg_call(relpath,
|
|
148
|
+
(b"pull", b"-q",
|
|
149
|
+
b"--config", b"heptapod.initial-import=yes",
|
|
150
|
+
src_url.encode('ascii')),
|
|
151
|
+
timeout=3600)
|
|
152
|
+
|
|
153
|
+
def hg_call(self, relpath, args, timeout=30):
|
|
154
|
+
exit_code = -1
|
|
155
|
+
for resp in self.hg_repository_service.HgCall(
|
|
156
|
+
HgCallRequest(repository=gl_repo(relpath),
|
|
157
|
+
args=args),
|
|
158
|
+
metadata=self.grpc_metadata(),
|
|
159
|
+
timeout=timeout,
|
|
160
|
+
):
|
|
161
|
+
exit_code = resp.exit_code
|
|
162
|
+
if exit_code != 0:
|
|
163
|
+
raise RuntimeError(f"HgCall exit code {exit_code}")
|
|
164
|
+
|
|
165
|
+
def run_one(self, name):
|
|
166
|
+
start = time.time()
|
|
167
|
+
try:
|
|
168
|
+
getattr(self, name)()
|
|
169
|
+
code = 'OK'
|
|
170
|
+
except grpc.RpcError as exc:
|
|
171
|
+
code = exc.code().name
|
|
172
|
+
if self.queue is None:
|
|
173
|
+
logger.error(
|
|
174
|
+
"Failed request when checking before actual load test"
|
|
175
|
+
)
|
|
176
|
+
raise
|
|
177
|
+
|
|
178
|
+
elapsed = time.time() - start
|
|
179
|
+
|
|
180
|
+
if self.queue is None:
|
|
181
|
+
logger.info("Ran %r in %d ms", name, elapsed * 1000)
|
|
182
|
+
else:
|
|
183
|
+
self.queue.put((name, code, elapsed), block=False, timeout=1)
|
|
184
|
+
|
|
185
|
+
def run_test(self, iterations):
|
|
186
|
+
for i in range(iterations):
|
|
187
|
+
meth = self.random_method()
|
|
188
|
+
logger.info("Iteration %d, running %r", i + 1, meth)
|
|
189
|
+
self.run_one(meth)
|
|
190
|
+
|
|
191
|
+
def sleep_a_bit(self):
|
|
192
|
+
# this can make RHGitaly find there are too many idle workers
|
|
193
|
+
# and recycle them, leading to interesting problems because of
|
|
194
|
+
# long HGitaly startup time.
|
|
195
|
+
time.sleep(2)
|
|
196
|
+
|
|
197
|
+
def find_commits_mercurial_devel(self):
|
|
198
|
+
count = 0
|
|
199
|
+
future = self.commit_service.FindCommits(FindCommitsRequest(
|
|
200
|
+
repository=gl_repo('mercurial-devel'),
|
|
201
|
+
revision=b'branch/default',
|
|
202
|
+
limit=100000,
|
|
203
|
+
paths=[b'rust/hg-core/Cargo.toml'],
|
|
204
|
+
))
|
|
205
|
+
|
|
206
|
+
# see also `streaming_future_with_cancellation()`
|
|
207
|
+
for resp in future:
|
|
208
|
+
count += len(resp.commits)
|
|
209
|
+
|
|
210
|
+
logger.debug("Got FindCommits response with %d commits", count)
|
|
211
|
+
|
|
212
|
+
def count_commits_mercurial_devel(self):
|
|
213
|
+
resp = self.commit_service.CountCommits(CountCommitsRequest(
|
|
214
|
+
repository=gl_repo('mercurial-devel'),
|
|
215
|
+
revision=b'branch/default',
|
|
216
|
+
))
|
|
217
|
+
logger.debug("Got FindCommits response with %d commits", resp.count)
|
|
218
|
+
|
|
219
|
+
def merge_analysis_mercurial_devel(self):
|
|
220
|
+
repo = gl_repo('mercurial-devel')
|
|
221
|
+
self.hg_operations_service.InvalidateMergeAnalysis(
|
|
222
|
+
InvalidateMergeAnalysisRequest(repository=repo)
|
|
223
|
+
)
|
|
224
|
+
# an actual merge, without conflicts
|
|
225
|
+
future = self.hg_operations_service.MergeAnalysis.future(
|
|
226
|
+
MergeAnalysisRequest(
|
|
227
|
+
repository=repo,
|
|
228
|
+
source_revision=b'412fd1f5d8bc',
|
|
229
|
+
target_revision=b'ff85442d08d7',
|
|
230
|
+
),
|
|
231
|
+
timeout=120)
|
|
232
|
+
future.result() # see also unary_future_with_cancellation()
|
|
233
|
+
|
|
234
|
+
def assert_requests(self):
|
|
235
|
+
"""Run all requiests exactly once.
|
|
236
|
+
|
|
237
|
+
If one of them fails (typically due to a programming mistake),
|
|
238
|
+
better to know it before running thousands of them
|
|
239
|
+
"""
|
|
240
|
+
for (name, _w) in self.weighted_methods:
|
|
241
|
+
if name != 'sleep_a_bit':
|
|
242
|
+
self.run_one(name) # TODO check exit code
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
def cancel_in(future, ms):
|
|
246
|
+
time.sleep(ms / 1000)
|
|
247
|
+
logger.info("Client-side cancellation")
|
|
248
|
+
future.cancel()
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
def spawn_cancel_thread(*args):
|
|
252
|
+
t = threading.Thread(target=cancel_in, args=args)
|
|
253
|
+
t.start()
|
|
254
|
+
return t
|
|
255
|
+
|
|
256
|
+
|
|
257
|
+
def unary_future_with_cancellation(future, cancel_in_ms):
|
|
258
|
+
"""Actually send the request, but cancel it first."""
|
|
259
|
+
t = spawn_cancel_thread(future, cancel_in_ms)
|
|
260
|
+
try:
|
|
261
|
+
return future.result()
|
|
262
|
+
finally:
|
|
263
|
+
t.join()
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def streaming_future_with_cancellation(future, cancel_in_ms):
|
|
267
|
+
"""Actually send the request, but cancel it first."""
|
|
268
|
+
t = spawn_cancel_thread(future, cancel_in_ms)
|
|
269
|
+
try:
|
|
270
|
+
for resp in future:
|
|
271
|
+
yield resp
|
|
272
|
+
finally:
|
|
273
|
+
t.join()
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
LoadWorker.compute_random_thresholds()
|
|
277
|
+
x = LoadWorker.random_method()
|
|
278
|
+
x = LoadWorker.random_method()
|
|
279
|
+
x = LoadWorker.random_method()
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
def worker(wid, url, queue, iterations):
|
|
283
|
+
worker = LoadWorker(url, queue, wid=wid)
|
|
284
|
+
worker.run_test(iterations)
|
|
285
|
+
queue.put(('DONE', wid))
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def load_test():
|
|
289
|
+
parser = argparse.ArgumentParser(
|
|
290
|
+
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
|
|
291
|
+
description=__doc__)
|
|
292
|
+
|
|
293
|
+
parser.add_argument('--url', '--rhgitaly-url',
|
|
294
|
+
help="URL of the RHGitaly server",
|
|
295
|
+
default='tcp://127.0.0.1:9237')
|
|
296
|
+
parser.add_argument('-c', '--concurrency', type=int, default=6)
|
|
297
|
+
parser.add_argument('--iterations', type=int, default=1000,
|
|
298
|
+
help="Number of iteration per client worker")
|
|
299
|
+
parser.add_argument('-l', '--logging-level', default='info')
|
|
300
|
+
cl_args = parser.parse_args()
|
|
301
|
+
|
|
302
|
+
logging.basicConfig(level=getattr(logging,
|
|
303
|
+
cl_args.logging_level.upper()))
|
|
304
|
+
|
|
305
|
+
concurrency = cl_args.concurrency
|
|
306
|
+
|
|
307
|
+
prepare_worker = LoadWorker(cl_args.url, queue=None)
|
|
308
|
+
prepare_worker.ensure_repos()
|
|
309
|
+
prepare_worker.assert_requests()
|
|
310
|
+
prepare_worker.close()
|
|
311
|
+
|
|
312
|
+
logger.warning("Preflight check of all requests passed. Proceeding to "
|
|
313
|
+
"actual load test")
|
|
314
|
+
|
|
315
|
+
queue = mp.Queue()
|
|
316
|
+
|
|
317
|
+
ctx = mp.get_context('fork')
|
|
318
|
+
processes = [ctx.Process(target=worker,
|
|
319
|
+
args=(i, cl_args.url, queue, cl_args.iterations))
|
|
320
|
+
for i in range(concurrency)]
|
|
321
|
+
|
|
322
|
+
for p in processes:
|
|
323
|
+
p.start()
|
|
324
|
+
|
|
325
|
+
done_process_ids = []
|
|
326
|
+
results = {}
|
|
327
|
+
while len(done_process_ids) < len(processes):
|
|
328
|
+
res = queue.get()
|
|
329
|
+
if res[0] == 'DONE':
|
|
330
|
+
wid = res[1]
|
|
331
|
+
processes[wid].join()
|
|
332
|
+
done_process_ids.append(wid)
|
|
333
|
+
logger.warning("Worker %d is done", wid)
|
|
334
|
+
else:
|
|
335
|
+
(results.setdefault(res[1], {})
|
|
336
|
+
.setdefault(res[0], [])
|
|
337
|
+
.append(res[2])
|
|
338
|
+
)
|
|
339
|
+
|
|
340
|
+
error_stats = {}
|
|
341
|
+
for code, details in results.items():
|
|
342
|
+
if code != 'OK':
|
|
343
|
+
for name, times in details.items():
|
|
344
|
+
error_stats.setdefault(name, {})[code] = dict(
|
|
345
|
+
count=len(times),
|
|
346
|
+
mean_time=statistics.mean(times)
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
successes = results.get('OK', {})
|
|
350
|
+
stats = {}
|
|
351
|
+
for name, times in successes.items():
|
|
352
|
+
mstats = stats[name] = dict(
|
|
353
|
+
count=len(times),
|
|
354
|
+
median=statistics.mean(times),
|
|
355
|
+
mean=statistics.median(times),
|
|
356
|
+
standard_deviation=statistics.pstdev(times),
|
|
357
|
+
)
|
|
358
|
+
if len(times) > 1:
|
|
359
|
+
|
|
360
|
+
deciles = statistics.quantiles(times, method='inclusive', n=10)
|
|
361
|
+
centiles = statistics.quantiles(times, method='inclusive',
|
|
362
|
+
n=100)
|
|
363
|
+
mstats["best_centile"] = centiles[0]
|
|
364
|
+
mstats["best_decile"] = deciles[0],
|
|
365
|
+
mstats["worst_centile"] = centiles[-1],
|
|
366
|
+
mstats["worst_decile"] = deciles[-1],
|
|
367
|
+
|
|
368
|
+
print(f"\n\nRESULTS for concurrency={concurrency}: ")
|
|
369
|
+
print(json.dumps(stats, indent=2))
|
|
370
|
+
|
|
371
|
+
if error_stats:
|
|
372
|
+
print(f"\n\nERRORS for concurrency={concurrency}: ")
|
|
373
|
+
print(json.dumps(error_stats, indent=2))
|
|
@@ -52,7 +52,6 @@ hgitaly/procutil.py
|
|
|
52
52
|
hgitaly/repository.py
|
|
53
53
|
hgitaly/revision.py
|
|
54
54
|
hgitaly/revset.py
|
|
55
|
-
hgitaly/scripts.py
|
|
56
55
|
hgitaly/servicer.py
|
|
57
56
|
hgitaly/ssh.py
|
|
58
57
|
hgitaly/stream.py
|
|
@@ -65,6 +64,9 @@ hgitaly.egg-info/dependency_links.txt
|
|
|
65
64
|
hgitaly.egg-info/entry_points.txt
|
|
66
65
|
hgitaly.egg-info/requires.txt
|
|
67
66
|
hgitaly.egg-info/top_level.txt
|
|
67
|
+
hgitaly/scripts/__init__.py
|
|
68
|
+
hgitaly/scripts/load_tests.py
|
|
69
|
+
hgitaly/scripts/stats.py
|
|
68
70
|
hgitaly/server/__init__.py
|
|
69
71
|
hgitaly/server/address.py
|
|
70
72
|
hgitaly/server/mono.py
|
hgitaly-18.7.1/hgitaly/VERSION
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
18.7.1
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|