hgitaly 17.8.1__tar.gz → 17.8.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-17.8.1/hgitaly.egg-info → hgitaly-17.8.2}/PKG-INFO +1 -1
- hgitaly-17.8.2/hgitaly/VERSION +1 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/gitlab_ref.py +51 -3
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/mercurial_repository.py +60 -1
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_mercurial_repository.py +20 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/mercurial_repository_pb2.py +13 -5
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/mercurial_repository_pb2_grpc.py +34 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_gitlab_ref.py +21 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_workdir.py +98 -1
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/workdir.py +104 -16
- {hgitaly-17.8.1 → hgitaly-17.8.2/hgitaly.egg-info}/PKG-INFO +1 -1
- hgitaly-17.8.1/hgitaly/VERSION +0 -1
- {hgitaly-17.8.1 → hgitaly-17.8.2}/LICENSE +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/MANIFEST.in +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/README.md +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgext3rd/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgext3rd/hgitaly/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgext3rd/hgitaly/revset.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgext3rd/hgitaly/tests/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgext3rd/hgitaly/tests/test_revset.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgext3rd/hgitaly/tests/test_serve.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/branch.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/changelog.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/diff.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/errors.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/feature.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/file_content.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/file_context.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/git.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/license_detector/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/license_detector/spdx-licenses.json +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/linguist/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/linguist/languages.json +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/logging.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/manifest.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/message.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/oid.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/pagination.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/path.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/peer.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/procutil.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/repository.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/revision.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/revset.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/scripts.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/address.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/mono.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/prefork.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/tests/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/tests/test_address.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/tests/test_mono.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/tests/test_prefork.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/tests/test_worker.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/server/worker.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/analysis.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/blob.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/commit.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/diff.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/interceptors.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/mercurial_changeset.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/mercurial_operations.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/operations.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/ref.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/repository.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/server.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/fixture.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_analysis.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_blob.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_commit.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_default_branch.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_diff.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_mercurial_changeset.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_mercurial_operations.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_operations.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_ref.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_repository_service.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/service/tests/test_server.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/servicer.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/ssh.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stream.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/analysis_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/analysis_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/blob_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/blob_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/commit_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/commit_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/diff_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/diff_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/errors_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/errors_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/lint_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/lint_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/mercurial_aux_git_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/mercurial_aux_git_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/mercurial_changeset_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/mercurial_changeset_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/mercurial_operations_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/mercurial_operations_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/operations_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/operations_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/ref_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/ref_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/remote_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/remote_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/repository_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/repository_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/server_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/server_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/shared_pb2.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/stub/shared_pb2_grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tag.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/bundle.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/context.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/grpc.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/ssh.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/sshd.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/storage.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/tests/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/testing/tests/test_sshd.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/common.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_branch.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_diff.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_errors.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_feature.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_file_context.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_license_detector.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_linguist.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_manifest.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_messages.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_oid.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_peer.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_repository.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_revision.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_revset.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_servicer.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_stream.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/tests/test_tag.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly/util.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly.egg-info/SOURCES.txt +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly.egg-info/dependency_links.txt +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly.egg-info/entry_points.txt +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly.egg-info/requires.txt +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/hgitaly.egg-info/top_level.txt +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/install-requirements.txt +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/setup.cfg +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/setup.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/__init__.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/comparison.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/conftest.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/gitaly.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/hgitaly_rhgitaly_comparison.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/rhgitaly.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_blob_tree.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_commit.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_comparison.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_diff.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_gitaly_server.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_mercurial_aux_git.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_mercurial_repository.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_operations.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_ref.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_remote.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_repository_service.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_rhgitaly_server.py +0 -0
- {hgitaly-17.8.1 → hgitaly-17.8.2}/tests_with_gitaly/test_server.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
17.8.2
|
|
@@ -13,6 +13,8 @@ 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
|
|
17
|
+
import re
|
|
16
18
|
|
|
17
19
|
from heptapod.gitlab.branch import gitlab_branch_ref
|
|
18
20
|
from heptapod.gitlab.tag import gitlab_tag_ref
|
|
@@ -30,10 +32,40 @@ from hgext3rd.heptapod.special_ref import (
|
|
|
30
32
|
)
|
|
31
33
|
from hgext3rd.heptapod.keep_around import (
|
|
32
34
|
iter_keep_arounds,
|
|
35
|
+
init_keep_arounds,
|
|
33
36
|
KEEP_AROUND_REF_PREFIX,
|
|
34
37
|
KEEP_AROUND_REF_PREFIX_LEN,
|
|
35
38
|
)
|
|
36
39
|
|
|
40
|
+
DOT_HG_RX = re.compile(br'\.hg$')
|
|
41
|
+
|
|
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
|
+
|
|
37
69
|
|
|
38
70
|
def gitlab_special_ref_target(repo, ref_path):
|
|
39
71
|
"""Return the changeset for a special ref.
|
|
@@ -115,7 +147,23 @@ def iter_gitlab_special_refs_as_refs(repo, deref=True, patterns=None):
|
|
|
115
147
|
|
|
116
148
|
|
|
117
149
|
def ensure_special_refs(repo):
|
|
118
|
-
|
|
150
|
+
if has_legacy_git_repo(repo):
|
|
151
|
+
return ensure_gitlab_special_refs(repo.ui, repo)
|
|
152
|
+
return {}
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def ensure_keep_arounds(repo, init_empty=False):
|
|
156
|
+
"""Ensure keep around from Git repo if present or create.
|
|
157
|
+
|
|
158
|
+
An empty file is created so that the keep-arounds file is no
|
|
159
|
+
more missing, but only if `init_empty` is `True`, so that
|
|
160
|
+
responsibility is handed to the caller, than must use the
|
|
161
|
+
option only after having obtained the missing marker.
|
|
162
|
+
"""
|
|
163
|
+
if has_legacy_git_repo(repo):
|
|
164
|
+
ensure_gitlab_keep_arounds(repo.ui, repo)
|
|
165
|
+
elif init_empty:
|
|
166
|
+
init_keep_arounds(repo, ())
|
|
119
167
|
|
|
120
168
|
|
|
121
169
|
def has_keep_around(repo, sha):
|
|
@@ -125,7 +173,7 @@ def has_keep_around(repo, sha):
|
|
|
125
173
|
"""
|
|
126
174
|
for ka in iter_keep_arounds(repo):
|
|
127
175
|
if ka is GITLAB_TYPED_REFS_MISSING:
|
|
128
|
-
|
|
176
|
+
ensure_keep_arounds(repo, init_empty=True)
|
|
129
177
|
return has_keep_around(repo, sha)
|
|
130
178
|
if ka == sha:
|
|
131
179
|
return True
|
|
@@ -146,7 +194,7 @@ def parse_keep_around_ref_path(ref):
|
|
|
146
194
|
def iter_keep_arounds_as_refs(repo, deref=True, patterns=None):
|
|
147
195
|
for sha in iter_keep_arounds(repo):
|
|
148
196
|
if sha is GITLAB_TYPED_REFS_MISSING:
|
|
149
|
-
|
|
197
|
+
ensure_keep_arounds(repo, init_empty=True)
|
|
150
198
|
yield from iter_keep_arounds_as_refs(repo, deref=deref)
|
|
151
199
|
return
|
|
152
200
|
ref_path = keep_around_ref_path(sha)
|
|
@@ -16,6 +16,7 @@ from mercurial import (
|
|
|
16
16
|
)
|
|
17
17
|
|
|
18
18
|
from ..branch import iter_gitlab_branches_matching
|
|
19
|
+
from ..logging import LoggerAdapter
|
|
19
20
|
from ..peer import (
|
|
20
21
|
FileURLOutsidePath,
|
|
21
22
|
InvalidURLScheme,
|
|
@@ -30,6 +31,10 @@ from ..repository import (
|
|
|
30
31
|
set_config_inheritance,
|
|
31
32
|
set_managed_config,
|
|
32
33
|
)
|
|
34
|
+
from ..workdir import (
|
|
35
|
+
remove_unlisted_workdirs,
|
|
36
|
+
workdirs_gc,
|
|
37
|
+
)
|
|
33
38
|
from ..errors import (
|
|
34
39
|
not_implemented,
|
|
35
40
|
)
|
|
@@ -39,6 +44,8 @@ from ..stub.mercurial_repository_pb2 import (
|
|
|
39
44
|
GetConfigItemResponse,
|
|
40
45
|
GetManagedConfigRequest,
|
|
41
46
|
GetManagedConfigResponse,
|
|
47
|
+
HousekeepingRequest,
|
|
48
|
+
HousekeepingResponse,
|
|
42
49
|
PushRequest,
|
|
43
50
|
PushResponse,
|
|
44
51
|
SetManagedConfigRequest,
|
|
@@ -49,7 +56,7 @@ from ..stub.mercurial_repository_pb2_grpc import (
|
|
|
49
56
|
)
|
|
50
57
|
from ..servicer import HGitalyServicer
|
|
51
58
|
|
|
52
|
-
|
|
59
|
+
base_logger = logging.getLogger(__name__)
|
|
53
60
|
|
|
54
61
|
|
|
55
62
|
class MercurialRepositoryServicer(MercurialRepositoryServiceServicer,
|
|
@@ -186,3 +193,55 @@ class MercurialRepositoryServicer(MercurialRepositoryServiceServicer,
|
|
|
186
193
|
context.abort(StatusCode.INTERNAL,
|
|
187
194
|
"Unexpected error, not in the actual "
|
|
188
195
|
"push to %r: %s" % (remote_url, exc))
|
|
196
|
+
|
|
197
|
+
def Housekeeping(self,
|
|
198
|
+
request: HousekeepingRequest,
|
|
199
|
+
context) -> HousekeepingResponse:
|
|
200
|
+
logger = LoggerAdapter(base_logger, context)
|
|
201
|
+
gl_repo = request.repository
|
|
202
|
+
repo = self.load_repo(gl_repo, context)
|
|
203
|
+
tasks = []
|
|
204
|
+
resp_attrs = {}
|
|
205
|
+
if request.fail:
|
|
206
|
+
tasks.append('fail')
|
|
207
|
+
if request.working_directories_age_threshold_seconds:
|
|
208
|
+
tasks.append('working_dirs_gc')
|
|
209
|
+
if request.working_directories_remove_unlisted:
|
|
210
|
+
tasks.append('remove_unlisted_working_dirs')
|
|
211
|
+
if request.recover:
|
|
212
|
+
tasks.append('recover')
|
|
213
|
+
for task in tasks:
|
|
214
|
+
try:
|
|
215
|
+
resp_attrs.update(getattr(self, 'housekeeping_' + task)(
|
|
216
|
+
repo=repo,
|
|
217
|
+
request=request,
|
|
218
|
+
context=context
|
|
219
|
+
))
|
|
220
|
+
except Exception as exc:
|
|
221
|
+
logger.error("Housekeeping task %s failed: %r" % (task, exc))
|
|
222
|
+
|
|
223
|
+
return HousekeepingResponse(**resp_attrs)
|
|
224
|
+
|
|
225
|
+
def housekeeping_fail(self, *a, **kw):
|
|
226
|
+
raise RuntimeError("client-required failure")
|
|
227
|
+
|
|
228
|
+
def housekeeping_working_dirs_gc(self, repo, request, context):
|
|
229
|
+
workdirs_gc(
|
|
230
|
+
workdirs_root=self.repo_workdirs_root(request.repository, context),
|
|
231
|
+
repo=repo,
|
|
232
|
+
max_age_seconds=request.working_directories_age_threshold_seconds
|
|
233
|
+
)
|
|
234
|
+
return [('working_directories_gc', True)]
|
|
235
|
+
|
|
236
|
+
def housekeeping_remove_unlisted_working_dirs(self, repo,
|
|
237
|
+
request, context):
|
|
238
|
+
remove_unlisted_workdirs(
|
|
239
|
+
repo=repo,
|
|
240
|
+
workdirs_root=self.repo_workdirs_root(request.repository, context),
|
|
241
|
+
)
|
|
242
|
+
return [('working_directories_remove_unlisted', True)]
|
|
243
|
+
|
|
244
|
+
def housekeeping_recover(self, repo, request, context):
|
|
245
|
+
return (('recover_run', True),
|
|
246
|
+
('recovered_interrupted_transaction', repo.recover()),
|
|
247
|
+
)
|
|
@@ -26,6 +26,7 @@ from hgitaly.stub.mercurial_repository_pb2 import (
|
|
|
26
26
|
ConfigItemType,
|
|
27
27
|
GetConfigItemRequest,
|
|
28
28
|
GetManagedConfigRequest,
|
|
29
|
+
HousekeepingRequest,
|
|
29
30
|
SetManagedConfigRequest,
|
|
30
31
|
HeptapodConfigSection,
|
|
31
32
|
MercurialPeer,
|
|
@@ -86,6 +87,10 @@ class ConfigFixture(ServiceFixture):
|
|
|
86
87
|
def include_managed_hgrc(self):
|
|
87
88
|
self.append_main_hgrc('', '%include hgrc.managed', '')
|
|
88
89
|
|
|
90
|
+
def housekeeping(self, **kw):
|
|
91
|
+
kw.setdefault('repository', self.grpc_repo)
|
|
92
|
+
return self.stub.Housekeeping(HousekeepingRequest(**kw))
|
|
93
|
+
|
|
89
94
|
|
|
90
95
|
@pytest.fixture
|
|
91
96
|
def config_fixture(grpc_channel, server_repos_root):
|
|
@@ -511,3 +516,18 @@ def test_push_invalid_url(push_fixture, url):
|
|
|
511
516
|
with pytest.raises(grpc.RpcError) as exc_info:
|
|
512
517
|
push(remote_url=url)
|
|
513
518
|
assert exc_info.value.code() == grpc.StatusCode.INVALID_ARGUMENT
|
|
519
|
+
|
|
520
|
+
|
|
521
|
+
def test_housekeeping(config_fixture):
|
|
522
|
+
fixture = config_fixture
|
|
523
|
+
|
|
524
|
+
fixture.housekeeping(fail=True)
|
|
525
|
+
|
|
526
|
+
assert fixture.housekeeping(
|
|
527
|
+
working_directories_age_threshold_seconds=1).working_directories_gc
|
|
528
|
+
|
|
529
|
+
fixture.housekeeping(working_directories_remove_unlisted=True)
|
|
530
|
+
|
|
531
|
+
resp = fixture.housekeeping(recover=True)
|
|
532
|
+
assert resp.recover_run
|
|
533
|
+
assert not resp.recovered_interrupted_transaction
|
|
@@ -15,7 +15,7 @@ from . import lint_pb2 as lint__pb2
|
|
|
15
15
|
from . import shared_pb2 as shared__pb2
|
|
16
16
|
|
|
17
17
|
|
|
18
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1amercurial-repository.proto\x12\x07hgitaly\x1a\nlint.proto\x1a\x0cshared.proto\"Y\n\x11InitConfigRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0enamespace_path\x18\x02 \x01(\t\"\x14\n\x12InitConfigResponse\"\x95\x02\n\x15HeptapodConfigSection\x12!\n\x14\x61llow_multiple_heads\x18\x02 \x01(\x08H\x00\x88\x01\x01\x12\x1c\n\x0f\x61llow_bookmarks\x18\x03 \x01(\x08H\x01\x88\x01\x01\x12\x45\n\x0c\x61uto_publish\x18\x04 \x01(\x0e\x32*.hgitaly.HeptapodConfigSection.AutoPublishH\x02\x88\x01\x01\"6\n\x0b\x41utoPublish\x12\x11\n\rWITHOUT_TOPIC\x10\x00\x12\x0b\n\x07NOTHING\x10\x01\x12\x07\n\x03\x41LL\x10\x02\x42\x17\n\x15_allow_multiple_headsB\x12\n\x10_allow_bookmarksB\x0f\n\r_auto_publish\"V\n\x17GetManagedConfigRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\r\n\x05local\x18\x02 \x01(\x08\"]\n\x18GetManagedConfigResponse\x12\x0f\n\x07inherit\x18\x01 \x01(\x08\x12\x30\n\x08heptapod\x18\x02 \x01(\x0b\x32\x1e.hgitaly.HeptapodConfigSection\"\xc2\x01\n\x17SetManagedConfigRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x14\n\x07inherit\x18\x02 \x01(\x08H\x00\x88\x01\x01\x12\x30\n\x08heptapod\x18\x03 \x01(\x0b\x32\x1e.hgitaly.HeptapodConfigSection\x12\x14\n\x0cremove_items\x18\x04 \x03(\t\x12\x0f\n\x07\x62y_line\x18\x05 \x01(\tB\n\n\x08_inherit\"\x1a\n\x18SetManagedConfigResponse\"\x8d\x01\n\x14GetConfigItemRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12(\n\x07\x61s_type\x18\x02 \x01(\x0e\x32\x17.hgitaly.ConfigItemType\x12\x0f\n\x07section\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\"H\n\x15GetConfigItemResponse\x12\x13\n\tas_string\x18\x01 \x01(\tH\x00\x12\x11\n\x07\x61s_bool\x18\x02 \x01(\x08H\x00\x42\x07\n\x05value\">\n\x0eRecoverRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"%\n\x0fRecoverResponse\x12\x12\n\nnot_needed\x18\x01 \x01(\x08\"?\n\x0fOptimizeRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x12\n\x10OptimizeResponse\"\x88\x01\n\x12ResetCachesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x31\n\x06\x63\x61\x63hes\x18\x02 \x03(\x0e\x32!.hgitaly.ResetCachesRequest.Cache\"\x11\n\x05\x43\x61\x63he\x12\x08\n\x04TAGS\x10\x00\"\x15\n\x13ResetCachesResponse\"b\n\rMercurialPeer\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0f\n\x07ssh_key\x18\x05 \x01(\t\x12\x17\n\x0fssh_known_hosts\x18\x06 \x01(\t\x12\x1a\n\x12ssh_remote_command\x18\x07 \x01(\x0c\"\xa7\x01\n\x0bPushRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12+\n\x0bremote_peer\x18\x02 \x01(\x0b\x32\x16.hgitaly.MercurialPeer\x12%\n\x1donly_gitlab_branches_matching\x18\x03 \x03(\x0c\x12\x16\n\x0einclude_drafts\x18\x04 \x01(\x08\"&\n\x0cPushResponse\x12\x16\n\x0enew_changesets\x18\x01 \x01(\x08\"\xb8\x01\n\x0bPullRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12+\n\x0bremote_peer\x18\x02 \x01(\x0b\x32\x16.hgitaly.MercurialPeer\x12\x1a\n\x04user\x18\x04 \x01(\x0b\x32\x0c.gitaly.User\x12\x1b\n\x13mercurial_revisions\x18\x05 \x03(\x0cJ\x04\x08\x03\x10\x04R\x0fgitlab_branches\"&\n\x0cPullResponse\x12\x16\n\x0enew_changesets\x18\x01 \x01(\x08\"g\n\rHgCallRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x1a\n\x04user\x18\x02 \x01(\x0b\x32\x0c.gitaly.User\x12\x0c\n\x04\x61rgs\x18\x03 \x03(\x0c\"3\n\x0eHgCallResponse\x12\x11\n\texit_code\x18\x01 \x01(\x05\x12\x0e\n\x06stdout\x18\x02 \x03(\x0c*&\n\x0e\x43onfigItemType\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x42OOL\x10\x01\x32\
|
|
18
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1amercurial-repository.proto\x12\x07hgitaly\x1a\nlint.proto\x1a\x0cshared.proto\"Y\n\x11InitConfigRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x16\n\x0enamespace_path\x18\x02 \x01(\t\"\x14\n\x12InitConfigResponse\"\x95\x02\n\x15HeptapodConfigSection\x12!\n\x14\x61llow_multiple_heads\x18\x02 \x01(\x08H\x00\x88\x01\x01\x12\x1c\n\x0f\x61llow_bookmarks\x18\x03 \x01(\x08H\x01\x88\x01\x01\x12\x45\n\x0c\x61uto_publish\x18\x04 \x01(\x0e\x32*.hgitaly.HeptapodConfigSection.AutoPublishH\x02\x88\x01\x01\"6\n\x0b\x41utoPublish\x12\x11\n\rWITHOUT_TOPIC\x10\x00\x12\x0b\n\x07NOTHING\x10\x01\x12\x07\n\x03\x41LL\x10\x02\x42\x17\n\x15_allow_multiple_headsB\x12\n\x10_allow_bookmarksB\x0f\n\r_auto_publish\"V\n\x17GetManagedConfigRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\r\n\x05local\x18\x02 \x01(\x08\"]\n\x18GetManagedConfigResponse\x12\x0f\n\x07inherit\x18\x01 \x01(\x08\x12\x30\n\x08heptapod\x18\x02 \x01(\x0b\x32\x1e.hgitaly.HeptapodConfigSection\"\xc2\x01\n\x17SetManagedConfigRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x14\n\x07inherit\x18\x02 \x01(\x08H\x00\x88\x01\x01\x12\x30\n\x08heptapod\x18\x03 \x01(\x0b\x32\x1e.hgitaly.HeptapodConfigSection\x12\x14\n\x0cremove_items\x18\x04 \x03(\t\x12\x0f\n\x07\x62y_line\x18\x05 \x01(\tB\n\n\x08_inherit\"\x1a\n\x18SetManagedConfigResponse\"\x8d\x01\n\x14GetConfigItemRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12(\n\x07\x61s_type\x18\x02 \x01(\x0e\x32\x17.hgitaly.ConfigItemType\x12\x0f\n\x07section\x18\x03 \x01(\t\x12\x0c\n\x04name\x18\x04 \x01(\t\"H\n\x15GetConfigItemResponse\x12\x13\n\tas_string\x18\x01 \x01(\tH\x00\x12\x11\n\x07\x61s_bool\x18\x02 \x01(\x08H\x00\x42\x07\n\x05value\">\n\x0eRecoverRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"%\n\x0fRecoverResponse\x12\x12\n\nnot_needed\x18\x01 \x01(\x08\"?\n\x0fOptimizeRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\"\x12\n\x10OptimizeResponse\"\x88\x01\n\x12ResetCachesRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x31\n\x06\x63\x61\x63hes\x18\x02 \x03(\x0e\x32!.hgitaly.ResetCachesRequest.Cache\"\x11\n\x05\x43\x61\x63he\x12\x08\n\x04TAGS\x10\x00\"\x15\n\x13ResetCachesResponse\"b\n\rMercurialPeer\x12\x0b\n\x03url\x18\x01 \x01(\t\x12\x0f\n\x07ssh_key\x18\x05 \x01(\t\x12\x17\n\x0fssh_known_hosts\x18\x06 \x01(\t\x12\x1a\n\x12ssh_remote_command\x18\x07 \x01(\x0c\"\xa7\x01\n\x0bPushRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12+\n\x0bremote_peer\x18\x02 \x01(\x0b\x32\x16.hgitaly.MercurialPeer\x12%\n\x1donly_gitlab_branches_matching\x18\x03 \x03(\x0c\x12\x16\n\x0einclude_drafts\x18\x04 \x01(\x08\"&\n\x0cPushResponse\x12\x16\n\x0enew_changesets\x18\x01 \x01(\x08\"\xb8\x01\n\x0bPullRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12+\n\x0bremote_peer\x18\x02 \x01(\x0b\x32\x16.hgitaly.MercurialPeer\x12\x1a\n\x04user\x18\x04 \x01(\x0b\x32\x0c.gitaly.User\x12\x1b\n\x13mercurial_revisions\x18\x05 \x03(\x0cJ\x04\x08\x03\x10\x04R\x0fgitlab_branches\"&\n\x0cPullResponse\x12\x16\n\x0enew_changesets\x18\x01 \x01(\x08\"g\n\rHgCallRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x1a\n\x04user\x18\x02 \x01(\x0b\x32\x0c.gitaly.User\x12\x0c\n\x04\x61rgs\x18\x03 \x03(\x0c\"3\n\x0eHgCallResponse\x12\x11\n\texit_code\x18\x01 \x01(\x05\x12\x0e\n\x06stdout\x18\x02 \x03(\x0c\"\xc2\x01\n\x13HousekeepingRequest\x12,\n\nrepository\x18\x01 \x01(\x0b\x32\x12.gitaly.RepositoryB\x04\x98\xc6,\x01\x12\x0c\n\x04\x66\x61il\x18\x02 \x01(\x08\x12\x0f\n\x07recover\x18\x03 \x01(\x08\x12\x31\n)working_directories_age_threshold_seconds\x18\x04 \x01(\r\x12+\n#working_directories_remove_unlisted\x18\x05 \x01(\x08\"\xa3\x01\n\x14HousekeepingResponse\x12\x13\n\x0brecover_run\x18\x01 \x01(\x08\x12)\n!recovered_interrupted_transaction\x18\x02 \x01(\x08\x12\x1e\n\x16working_directories_gc\x18\x03 \x01(\x08\x12+\n#working_directories_remove_unlisted\x18\x04 \x01(\x08*&\n\x0e\x43onfigItemType\x12\n\n\x06STRING\x10\x00\x12\x08\n\x04\x42OOL\x10\x01\x32\xfa\x06\n\x1aMercurialRepositoryService\x12M\n\nInitConfig\x12\x1a.hgitaly.InitConfigRequest\x1a\x1b.hgitaly.InitConfigResponse\"\x06\xfa\x97(\x02\x08\x01\x12V\n\rGetConfigItem\x12\x1d.hgitaly.GetConfigItemRequest\x1a\x1e.hgitaly.GetConfigItemResponse\"\x06\xfa\x97(\x02\x08\x02\x12\x44\n\x07Recover\x12\x17.hgitaly.RecoverRequest\x1a\x18.hgitaly.RecoverResponse\"\x06\xfa\x97(\x02\x08\x02\x12G\n\x08Optimize\x12\x18.hgitaly.OptimizeRequest\x1a\x19.hgitaly.OptimizeResponse\"\x06\xfa\x97(\x02\x08\x01\x12P\n\x0bResetCaches\x12\x1b.hgitaly.ResetCachesRequest\x1a\x1c.hgitaly.ResetCachesResponse\"\x06\xfa\x97(\x02\x08\x01\x12\x43\n\x06HgCall\x12\x16.hgitaly.HgCallRequest\x1a\x17.hgitaly.HgCallResponse\"\x06\xfa\x97(\x02\x08\x01\x30\x01\x12_\n\x10GetManagedConfig\x12 .hgitaly.GetManagedConfigRequest\x1a!.hgitaly.GetManagedConfigResponse\"\x06\xfa\x97(\x02\x08\x02\x12_\n\x10SetManagedConfig\x12 .hgitaly.SetManagedConfigRequest\x1a!.hgitaly.SetManagedConfigResponse\"\x06\xfa\x97(\x02\x08\x01\x12;\n\x04Push\x12\x14.hgitaly.PushRequest\x1a\x15.hgitaly.PushResponse\"\x06\xfa\x97(\x02\x08\x01\x12;\n\x04Pull\x12\x14.hgitaly.PullRequest\x1a\x15.hgitaly.PullResponse\"\x06\xfa\x97(\x02\x08\x01\x12S\n\x0cHousekeeping\x12\x1c.hgitaly.HousekeepingRequest\x1a\x1d.hgitaly.HousekeepingResponse\"\x06\xfa\x97(\x02\x08\x01\x62\x06proto3')
|
|
19
19
|
|
|
20
20
|
_globals = globals()
|
|
21
21
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -43,6 +43,8 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
43
43
|
_PULLREQUEST.fields_by_name['repository']._serialized_options = b'\230\306,\001'
|
|
44
44
|
_HGCALLREQUEST.fields_by_name['repository']._options = None
|
|
45
45
|
_HGCALLREQUEST.fields_by_name['repository']._serialized_options = b'\230\306,\001'
|
|
46
|
+
_HOUSEKEEPINGREQUEST.fields_by_name['repository']._options = None
|
|
47
|
+
_HOUSEKEEPINGREQUEST.fields_by_name['repository']._serialized_options = b'\230\306,\001'
|
|
46
48
|
_MERCURIALREPOSITORYSERVICE.methods_by_name['InitConfig']._options = None
|
|
47
49
|
_MERCURIALREPOSITORYSERVICE.methods_by_name['InitConfig']._serialized_options = b'\372\227(\002\010\001'
|
|
48
50
|
_MERCURIALREPOSITORYSERVICE.methods_by_name['GetConfigItem']._options = None
|
|
@@ -63,8 +65,10 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
63
65
|
_MERCURIALREPOSITORYSERVICE.methods_by_name['Push']._serialized_options = b'\372\227(\002\010\001'
|
|
64
66
|
_MERCURIALREPOSITORYSERVICE.methods_by_name['Pull']._options = None
|
|
65
67
|
_MERCURIALREPOSITORYSERVICE.methods_by_name['Pull']._serialized_options = b'\372\227(\002\010\001'
|
|
66
|
-
|
|
67
|
-
|
|
68
|
+
_MERCURIALREPOSITORYSERVICE.methods_by_name['Housekeeping']._options = None
|
|
69
|
+
_MERCURIALREPOSITORYSERVICE.methods_by_name['Housekeeping']._serialized_options = b'\372\227(\002\010\001'
|
|
70
|
+
_globals['_CONFIGITEMTYPE']._serialized_start=2492
|
|
71
|
+
_globals['_CONFIGITEMTYPE']._serialized_end=2530
|
|
68
72
|
_globals['_INITCONFIGREQUEST']._serialized_start=65
|
|
69
73
|
_globals['_INITCONFIGREQUEST']._serialized_end=154
|
|
70
74
|
_globals['_INITCONFIGRESPONSE']._serialized_start=156
|
|
@@ -113,6 +117,10 @@ if _descriptor._USE_C_DESCRIPTORS == False:
|
|
|
113
117
|
_globals['_HGCALLREQUEST']._serialized_end=2074
|
|
114
118
|
_globals['_HGCALLRESPONSE']._serialized_start=2076
|
|
115
119
|
_globals['_HGCALLRESPONSE']._serialized_end=2127
|
|
116
|
-
_globals['
|
|
117
|
-
_globals['
|
|
120
|
+
_globals['_HOUSEKEEPINGREQUEST']._serialized_start=2130
|
|
121
|
+
_globals['_HOUSEKEEPINGREQUEST']._serialized_end=2324
|
|
122
|
+
_globals['_HOUSEKEEPINGRESPONSE']._serialized_start=2327
|
|
123
|
+
_globals['_HOUSEKEEPINGRESPONSE']._serialized_end=2490
|
|
124
|
+
_globals['_MERCURIALREPOSITORYSERVICE']._serialized_start=2533
|
|
125
|
+
_globals['_MERCURIALREPOSITORYSERVICE']._serialized_end=3423
|
|
118
126
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -64,6 +64,11 @@ class MercurialRepositoryServiceStub(object):
|
|
|
64
64
|
request_serializer=mercurial__repository__pb2.PullRequest.SerializeToString,
|
|
65
65
|
response_deserializer=mercurial__repository__pb2.PullResponse.FromString,
|
|
66
66
|
)
|
|
67
|
+
self.Housekeeping = channel.unary_unary(
|
|
68
|
+
'/hgitaly.MercurialRepositoryService/Housekeeping',
|
|
69
|
+
request_serializer=mercurial__repository__pb2.HousekeepingRequest.SerializeToString,
|
|
70
|
+
response_deserializer=mercurial__repository__pb2.HousekeepingResponse.FromString,
|
|
71
|
+
)
|
|
67
72
|
|
|
68
73
|
|
|
69
74
|
class MercurialRepositoryServiceServicer(object):
|
|
@@ -175,6 +180,13 @@ class MercurialRepositoryServiceServicer(object):
|
|
|
175
180
|
context.set_details('Method not implemented!')
|
|
176
181
|
raise NotImplementedError('Method not implemented!')
|
|
177
182
|
|
|
183
|
+
def Housekeeping(self, request, context):
|
|
184
|
+
"""/ General tidying and optimization for this repository
|
|
185
|
+
"""
|
|
186
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
187
|
+
context.set_details('Method not implemented!')
|
|
188
|
+
raise NotImplementedError('Method not implemented!')
|
|
189
|
+
|
|
178
190
|
|
|
179
191
|
def add_MercurialRepositoryServiceServicer_to_server(servicer, server):
|
|
180
192
|
rpc_method_handlers = {
|
|
@@ -228,6 +240,11 @@ def add_MercurialRepositoryServiceServicer_to_server(servicer, server):
|
|
|
228
240
|
request_deserializer=mercurial__repository__pb2.PullRequest.FromString,
|
|
229
241
|
response_serializer=mercurial__repository__pb2.PullResponse.SerializeToString,
|
|
230
242
|
),
|
|
243
|
+
'Housekeeping': grpc.unary_unary_rpc_method_handler(
|
|
244
|
+
servicer.Housekeeping,
|
|
245
|
+
request_deserializer=mercurial__repository__pb2.HousekeepingRequest.FromString,
|
|
246
|
+
response_serializer=mercurial__repository__pb2.HousekeepingResponse.SerializeToString,
|
|
247
|
+
),
|
|
231
248
|
}
|
|
232
249
|
generic_handler = grpc.method_handlers_generic_handler(
|
|
233
250
|
'hgitaly.MercurialRepositoryService', rpc_method_handlers)
|
|
@@ -407,3 +424,20 @@ class MercurialRepositoryService(object):
|
|
|
407
424
|
mercurial__repository__pb2.PullResponse.FromString,
|
|
408
425
|
options, channel_credentials,
|
|
409
426
|
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
427
|
+
|
|
428
|
+
@staticmethod
|
|
429
|
+
def Housekeeping(request,
|
|
430
|
+
target,
|
|
431
|
+
options=(),
|
|
432
|
+
channel_credentials=None,
|
|
433
|
+
call_credentials=None,
|
|
434
|
+
insecure=False,
|
|
435
|
+
compression=None,
|
|
436
|
+
wait_for_ready=None,
|
|
437
|
+
timeout=None,
|
|
438
|
+
metadata=None):
|
|
439
|
+
return grpc.experimental.unary_unary(request, target, '/hgitaly.MercurialRepositoryService/Housekeeping',
|
|
440
|
+
mercurial__repository__pb2.HousekeepingRequest.SerializeToString,
|
|
441
|
+
mercurial__repository__pb2.HousekeepingResponse.FromString,
|
|
442
|
+
options, channel_credentials,
|
|
443
|
+
insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#
|
|
6
6
|
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
7
7
|
from copy import deepcopy
|
|
8
|
+
import shutil
|
|
8
9
|
|
|
9
10
|
import pytest
|
|
10
11
|
from heptapod.testhelpers import (
|
|
@@ -29,6 +30,7 @@ from ..gitlab_ref import (
|
|
|
29
30
|
keep_around_ref_path,
|
|
30
31
|
parse_keep_around_ref_path,
|
|
31
32
|
)
|
|
33
|
+
from .. import gitlab_ref as glref_mod # for monkey-patching
|
|
32
34
|
|
|
33
35
|
|
|
34
36
|
@pytest.fixture
|
|
@@ -97,6 +99,25 @@ def test_gitlab_special_ref_target_ensure(mirror):
|
|
|
97
99
|
assert gitlab_special_ref_target(wrapper.repo, ref_path) == ctx
|
|
98
100
|
|
|
99
101
|
|
|
102
|
+
def should_not_be_called(*a, **kw): # pragma: no cover
|
|
103
|
+
raise AssertionError("should not have been called")
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def test_special_ref_not_ensure(mirror, monkeypatch):
|
|
107
|
+
wrapper = mirror.hg_repo_wrapper
|
|
108
|
+
git_repo = mirror.git_repo
|
|
109
|
+
|
|
110
|
+
shutil.rmtree(git_repo.path)
|
|
111
|
+
monkeypatch.setattr(glref_mod, 'ensure_gitlab_special_refs',
|
|
112
|
+
should_not_be_called)
|
|
113
|
+
monkeypatch.setattr(glref_mod, 'ensure_gitlab_keep_arounds',
|
|
114
|
+
should_not_be_called)
|
|
115
|
+
|
|
116
|
+
ref_path = b'refs/environments/654'
|
|
117
|
+
assert gitlab_special_ref_target(wrapper.repo, ref_path) is None
|
|
118
|
+
assert tuple(iter_keep_arounds_as_refs(wrapper.repo)) == ()
|
|
119
|
+
|
|
120
|
+
|
|
100
121
|
def test_write_special_ref(repo_wrapper):
|
|
101
122
|
repo, wrapper = repo_wrapper
|
|
102
123
|
|
|
@@ -37,6 +37,7 @@ from ..workdir import (
|
|
|
37
37
|
reserve_workdir,
|
|
38
38
|
working_directory,
|
|
39
39
|
workdirs_gc,
|
|
40
|
+
remove_unlisted_workdirs,
|
|
40
41
|
)
|
|
41
42
|
|
|
42
43
|
parametrize = pytest.mark.parametrize
|
|
@@ -58,6 +59,11 @@ def wd_fixture(tmpdir):
|
|
|
58
59
|
yield workdirs_root, wrapper
|
|
59
60
|
|
|
60
61
|
|
|
62
|
+
def assert_roster_length(repo, n):
|
|
63
|
+
with repo.vfs(ROSTER_FILE_NAME, b'rb') as rosterf:
|
|
64
|
+
assert len(rosterf.readlines()) == n
|
|
65
|
+
|
|
66
|
+
|
|
61
67
|
def test_working_directory_basic(wd_fixture):
|
|
62
68
|
wds_root, wrapper = wd_fixture
|
|
63
69
|
src_repo = wrapper.repo
|
|
@@ -106,11 +112,17 @@ def test_working_directory_basic(wd_fixture):
|
|
|
106
112
|
for (wd_id, _, _, branch), _l in roster_iter(rosterf)}
|
|
107
113
|
assert wds == {wd_id: b'default', wd2_id: b'default'}
|
|
108
114
|
|
|
115
|
+
# And the roster file has the expected size
|
|
116
|
+
assert_roster_length(src_repo, 2)
|
|
117
|
+
|
|
109
118
|
# Both can be reused
|
|
110
119
|
with working_directory(wds_root, src_repo, changeset=ctx) as wd1:
|
|
111
120
|
with working_directory(wds_root, src_repo, changeset=ctx) as wd2:
|
|
112
121
|
assert set((wd1.path, wd2.path)) == {wd_path, wd2_path}
|
|
113
122
|
|
|
123
|
+
# with no undue growth of the roster file (hgitaly#226)
|
|
124
|
+
assert_roster_length(src_repo, 2)
|
|
125
|
+
|
|
114
126
|
|
|
115
127
|
def test_working_directory_subrepos(wd_fixture):
|
|
116
128
|
wds_root, wrapper = wd_fixture
|
|
@@ -354,6 +366,32 @@ def test_workdirs_gc_stale_default(purge_fixture):
|
|
|
354
366
|
assert lines[0][3] == b'mydefault'
|
|
355
367
|
|
|
356
368
|
|
|
369
|
+
def test_workdirs_gc_duplicate_lines(purge_fixture):
|
|
370
|
+
wds_root, wrapper = purge_fixture
|
|
371
|
+
repo = wrapper.repo
|
|
372
|
+
|
|
373
|
+
# no error if there is no working directory
|
|
374
|
+
workdirs_gc(wds_root, repo, 1)
|
|
375
|
+
|
|
376
|
+
wd_path(wds_root, 0).mkdir(parents=True)
|
|
377
|
+
wd_path(wds_root, 1).mkdir()
|
|
378
|
+
with locked_roster(repo) as (inf, outf):
|
|
379
|
+
# See hgitaly#226
|
|
380
|
+
outf.writelines((b"0 - 10000 mydefault\n",
|
|
381
|
+
b"1 - 11000 mydefault\n",
|
|
382
|
+
b"0 - 12000 mydefault\n",
|
|
383
|
+
b"1 - 13000 mydefault\n",
|
|
384
|
+
))
|
|
385
|
+
|
|
386
|
+
workdirs_gc(wds_root, repo, max_age_seconds=100, now=20000)
|
|
387
|
+
|
|
388
|
+
# The active work dir for default branch is kept, considered to be enough
|
|
389
|
+
with locked_roster(repo) as (inf, outf):
|
|
390
|
+
lines = [parsed for parsed, _line in roster_iter(inf)]
|
|
391
|
+
assert len(lines) == 1
|
|
392
|
+
assert lines[0][3] == b'mydefault'
|
|
393
|
+
|
|
394
|
+
|
|
357
395
|
def test_workdirs_gc_no_default(purge_fixture):
|
|
358
396
|
wds_root, wrapper = purge_fixture
|
|
359
397
|
repo = wrapper.repo
|
|
@@ -375,7 +413,7 @@ def test_workdirs_gc_no_default(purge_fixture):
|
|
|
375
413
|
assert len(inf.read()) == 0
|
|
376
414
|
|
|
377
415
|
|
|
378
|
-
def
|
|
416
|
+
def test_workdirs_gc_missing_workdir(purge_fixture):
|
|
379
417
|
wds_root, wrapper = purge_fixture
|
|
380
418
|
repo = wrapper.repo
|
|
381
419
|
|
|
@@ -389,11 +427,70 @@ def test_workdirs_gc_rmerror(purge_fixture):
|
|
|
389
427
|
|
|
390
428
|
workdirs_gc(wds_root, repo, max_age_seconds=100, now=20000)
|
|
391
429
|
|
|
430
|
+
with locked_roster(repo) as (inf, outf):
|
|
431
|
+
wds = {parsed[0]: parsed[3] for parsed, _line in roster_iter(inf)}
|
|
432
|
+
assert wds == {1: b'mydefault'}
|
|
433
|
+
|
|
434
|
+
|
|
435
|
+
def test_workdirs_gc_rmerror(purge_fixture, monkeypatch):
|
|
436
|
+
wds_root, wrapper = purge_fixture
|
|
437
|
+
repo = wrapper.repo
|
|
438
|
+
|
|
439
|
+
wd_path(wds_root, 0).mkdir(parents=True)
|
|
440
|
+
wd_path(wds_root, 1).mkdir()
|
|
441
|
+
with locked_roster(repo) as (inf, outf):
|
|
442
|
+
outf.writelines((b"0 - 10000 other\n",
|
|
443
|
+
b"1 - 15000 mydefault\n",
|
|
444
|
+
))
|
|
445
|
+
|
|
446
|
+
def raiser(path):
|
|
447
|
+
raise RuntimeError(f"Cannot remove {path}")
|
|
448
|
+
|
|
449
|
+
monkeypatch.setattr(shutil, 'rmtree', raiser)
|
|
450
|
+
workdirs_gc(wds_root, repo, max_age_seconds=100, now=20000)
|
|
451
|
+
|
|
392
452
|
with locked_roster(repo) as (inf, outf):
|
|
393
453
|
wds = {parsed[0]: parsed[3] for parsed, _line in roster_iter(inf)}
|
|
394
454
|
assert wds == {0: b'other', 1: b'mydefault'}
|
|
395
455
|
|
|
396
456
|
|
|
457
|
+
def test_remove_unlisted_workdirs(purge_fixture, monkeypatch):
|
|
458
|
+
wds_root, wrapper = purge_fixture
|
|
459
|
+
repo = wrapper.repo
|
|
460
|
+
|
|
461
|
+
# does not fail if working dirs root does not even exist
|
|
462
|
+
remove_unlisted_workdirs(wds_root, repo)
|
|
463
|
+
|
|
464
|
+
wd_path(wds_root, 0).mkdir(parents=True)
|
|
465
|
+
wd_path(wds_root, 1).mkdir()
|
|
466
|
+
wd_path(wds_root, 2).mkdir()
|
|
467
|
+
(wds_root / 'README').write_binary(b"innocent bystander")
|
|
468
|
+
(wds_root / '4').write_binary(b"innocent asking for trouble")
|
|
469
|
+
|
|
470
|
+
with locked_roster(repo) as (inf, outf):
|
|
471
|
+
outf.writelines((b"0 - 10000 mydefault\n",
|
|
472
|
+
))
|
|
473
|
+
rmtree = shutil.rmtree
|
|
474
|
+
|
|
475
|
+
def raiser(path):
|
|
476
|
+
if path.name == '1':
|
|
477
|
+
rmtree(path)
|
|
478
|
+
else:
|
|
479
|
+
raise RuntimeError(f"Cannot remove {path}")
|
|
480
|
+
|
|
481
|
+
monkeypatch.setattr(shutil, 'rmtree', raiser)
|
|
482
|
+
remove_unlisted_workdirs(wds_root, repo)
|
|
483
|
+
|
|
484
|
+
with locked_roster(repo) as (inf, outf):
|
|
485
|
+
wds = {parsed[0]: parsed[3] for parsed, _line in roster_iter(inf)}
|
|
486
|
+
assert wds == {0: b'mydefault'}
|
|
487
|
+
|
|
488
|
+
assert not wd_path(wds_root, 1).exists()
|
|
489
|
+
assert wd_path(wds_root, 2).exists() # our raiser did its job
|
|
490
|
+
assert (wds_root / 'README').exists()
|
|
491
|
+
assert (wds_root / '4').exists()
|
|
492
|
+
|
|
493
|
+
|
|
397
494
|
@parametrize('inner_success', ('ok', 'rm-error'))
|
|
398
495
|
def test_remove_all_workdirs(purge_fixture, monkeypatch, inner_success):
|
|
399
496
|
wds_root, wrapper = purge_fixture
|