hgitaly 2.5.3__tar.gz → 2.5.4__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.
Files changed (293) hide show
  1. {hgitaly-2.5.3 → hgitaly-2.5.4}/.hgtags +1 -0
  2. {hgitaly-2.5.3 → hgitaly-2.5.4}/PKG-INFO +1 -1
  3. hgitaly-2.5.4/hgitaly/VERSION +1 -0
  4. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/diff.py +47 -20
  5. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/message.py +4 -0
  6. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/diff.py +4 -1
  7. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/ref.py +95 -3
  8. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_diff.py +46 -1
  9. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_ref.py +77 -0
  10. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_messages.py +5 -0
  11. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly.egg-info/PKG-INFO +1 -1
  12. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/comparison.py +88 -22
  13. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_commit.py +1 -1
  14. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_diff.py +26 -2
  15. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_operations.py +17 -27
  16. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_ref.py +127 -1
  17. hgitaly-2.5.3/hgitaly/VERSION +0 -1
  18. {hgitaly-2.5.3 → hgitaly-2.5.4}/.coveragerc +0 -0
  19. {hgitaly-2.5.3 → hgitaly-2.5.4}/.gitlab-ci.yml +0 -0
  20. {hgitaly-2.5.3 → hgitaly-2.5.4}/.hgignore +0 -0
  21. {hgitaly-2.5.3 → hgitaly-2.5.4}/LICENSE +0 -0
  22. {hgitaly-2.5.3 → hgitaly-2.5.4}/MANIFEST.in +0 -0
  23. {hgitaly-2.5.3 → hgitaly-2.5.4}/README.md +0 -0
  24. {hgitaly-2.5.3 → hgitaly-2.5.4}/ci/heptapod-sftp-push +0 -0
  25. {hgitaly-2.5.3 → hgitaly-2.5.4}/ci/heptapod-sign-package +0 -0
  26. {hgitaly-2.5.3 → hgitaly-2.5.4}/ci/heptapod_known_hosts.ssh +0 -0
  27. {hgitaly-2.5.3 → hgitaly-2.5.4}/ci/upload-rhgitaly +0 -0
  28. {hgitaly-2.5.3 → hgitaly-2.5.4}/conftest.py +0 -0
  29. {hgitaly-2.5.3 → hgitaly-2.5.4}/dev-requirements.txt +0 -0
  30. {hgitaly-2.5.3 → hgitaly-2.5.4}/examples/client.py +0 -0
  31. {hgitaly-2.5.3 → hgitaly-2.5.4}/examples/client_list_lcft.py +0 -0
  32. {hgitaly-2.5.3 → hgitaly-2.5.4}/generate-stubs +0 -0
  33. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgext3rd/__init__.py +0 -0
  34. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgext3rd/hgitaly/__init__.py +0 -0
  35. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgext3rd/hgitaly/revset.py +0 -0
  36. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgext3rd/hgitaly/tests/__init__.py +0 -0
  37. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgext3rd/hgitaly/tests/test_revset.py +0 -0
  38. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgext3rd/hgitaly/tests/test_serve.py +0 -0
  39. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/__init__.py +0 -0
  40. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/branch.py +0 -0
  41. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/changelog.py +0 -0
  42. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/errors.py +0 -0
  43. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/feature.py +0 -0
  44. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/file_content.py +0 -0
  45. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/file_context.py +0 -0
  46. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/git.py +0 -0
  47. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/gitlab_ref.py +0 -0
  48. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/license_detector/GPL-2.sample +0 -0
  49. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/license_detector/__init__.py +0 -0
  50. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/license_detector/spdx-licenses.json +0 -0
  51. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/linguist/__init__.py +0 -0
  52. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/linguist/languages.json +0 -0
  53. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/logging.py +0 -0
  54. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/manifest.py +0 -0
  55. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/oid.py +0 -0
  56. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/pagination.py +0 -0
  57. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/path.py +0 -0
  58. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/peer.py +0 -0
  59. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/procutil.py +0 -0
  60. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/repository.py +0 -0
  61. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/revision.py +0 -0
  62. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/revset.py +0 -0
  63. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/scripts.py +0 -0
  64. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/__init__.py +0 -0
  65. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/address.py +0 -0
  66. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/mono.py +0 -0
  67. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/prefork.py +0 -0
  68. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/tests/__init__.py +0 -0
  69. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/tests/test_address.py +0 -0
  70. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/tests/test_mono.py +0 -0
  71. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/tests/test_prefork.py +0 -0
  72. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/tests/test_worker.py +0 -0
  73. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/server/worker.py +0 -0
  74. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/__init__.py +0 -0
  75. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/analysis.py +0 -0
  76. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/blob.py +0 -0
  77. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/commit.py +0 -0
  78. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/interceptors.py +0 -0
  79. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/mercurial_changeset.py +0 -0
  80. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/mercurial_operations.py +0 -0
  81. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/mercurial_repository.py +0 -0
  82. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/operations.py +0 -0
  83. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/repository.py +0 -0
  84. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/server.py +0 -0
  85. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/__init__.py +0 -0
  86. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/fixture.py +0 -0
  87. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_analysis.py +0 -0
  88. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_blob.py +0 -0
  89. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_commit.py +0 -0
  90. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_default_branch.py +0 -0
  91. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_mercurial_changeset.py +0 -0
  92. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_mercurial_operations.py +0 -0
  93. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_mercurial_repository.py +0 -0
  94. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_operations.py +0 -0
  95. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_repository_service.py +0 -0
  96. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/service/tests/test_server.py +0 -0
  97. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/servicer.py +0 -0
  98. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/ssh.py +0 -0
  99. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stream.py +0 -0
  100. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/__init__.py +0 -0
  101. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/analysis_pb2.py +0 -0
  102. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/analysis_pb2_grpc.py +0 -0
  103. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/blob_pb2.py +0 -0
  104. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/blob_pb2_grpc.py +0 -0
  105. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/commit_pb2.py +0 -0
  106. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/commit_pb2_grpc.py +0 -0
  107. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/diff_pb2.py +0 -0
  108. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/diff_pb2_grpc.py +0 -0
  109. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/errors_pb2.py +0 -0
  110. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/errors_pb2_grpc.py +0 -0
  111. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/lint_pb2.py +0 -0
  112. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/lint_pb2_grpc.py +0 -0
  113. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/mercurial_changeset_pb2.py +0 -0
  114. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/mercurial_changeset_pb2_grpc.py +0 -0
  115. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/mercurial_operations_pb2.py +0 -0
  116. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/mercurial_operations_pb2_grpc.py +0 -0
  117. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/mercurial_repository_pb2.py +0 -0
  118. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/mercurial_repository_pb2_grpc.py +0 -0
  119. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/operations_pb2.py +0 -0
  120. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/operations_pb2_grpc.py +0 -0
  121. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/ref_pb2.py +0 -0
  122. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/ref_pb2_grpc.py +0 -0
  123. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/repository_pb2.py +0 -0
  124. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/repository_pb2_grpc.py +0 -0
  125. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/server_pb2.py +0 -0
  126. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/server_pb2_grpc.py +0 -0
  127. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/shared_pb2.py +0 -0
  128. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/stub/shared_pb2_grpc.py +0 -0
  129. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tag.py +0 -0
  130. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/__init__.py +0 -0
  131. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/bundle.py +0 -0
  132. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/context.py +0 -0
  133. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/data/authorized_keys +0 -0
  134. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/data/backup_additional_no_git.tar +0 -0
  135. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/data/id_ecdsa_user +0 -0
  136. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/data/known_hosts +0 -0
  137. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/data/ssh_host_ecdsa_key +0 -0
  138. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/data/ssh_host_ecdsa_key.pub +0 -0
  139. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/data/sshd_config +0 -0
  140. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/grpc.py +0 -0
  141. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/ssh.py +0 -0
  142. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/sshd.py +0 -0
  143. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/tests/__init__.py +0 -0
  144. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/testing/tests/test_sshd.py +0 -0
  145. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/__init__.py +0 -0
  146. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/common.py +0 -0
  147. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_branch.py +0 -0
  148. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_diff.py +0 -0
  149. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_errors.py +0 -0
  150. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_feature.py +0 -0
  151. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_file_context.py +0 -0
  152. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_gitlab_ref.py +0 -0
  153. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_license_detector.py +0 -0
  154. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_linguist.py +0 -0
  155. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_manifest.py +0 -0
  156. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_oid.py +0 -0
  157. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_peer.py +0 -0
  158. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_repository.py +0 -0
  159. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_revision.py +0 -0
  160. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_revset.py +0 -0
  161. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_servicer.py +0 -0
  162. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_stream.py +0 -0
  163. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_tag.py +0 -0
  164. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/tests/test_workdir.py +0 -0
  165. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/util.py +0 -0
  166. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly/workdir.py +0 -0
  167. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly.egg-info/SOURCES.txt +0 -0
  168. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly.egg-info/dependency_links.txt +0 -0
  169. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly.egg-info/entry_points.txt +0 -0
  170. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly.egg-info/requires.txt +0 -0
  171. {hgitaly-2.5.3 → hgitaly-2.5.4}/hgitaly.egg-info/top_level.txt +0 -0
  172. {hgitaly-2.5.3 → hgitaly-2.5.4}/install-requirements.txt +0 -0
  173. {hgitaly-2.5.3 → hgitaly-2.5.4}/lint +0 -0
  174. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/analysis.proto +0 -0
  175. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/blob.proto +0 -0
  176. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/cleanup.proto +0 -0
  177. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/cluster.proto +0 -0
  178. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/commit.proto +0 -0
  179. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/conflicts.proto +0 -0
  180. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/diff.proto +0 -0
  181. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/errors.proto +0 -0
  182. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/hook.proto +0 -0
  183. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/internal.proto +0 -0
  184. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/lint.proto +0 -0
  185. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/log.proto +0 -0
  186. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/mercurial-changeset.proto +0 -0
  187. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/mercurial-operations.proto +0 -0
  188. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/mercurial-repository.proto +0 -0
  189. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/namespace.proto +0 -0
  190. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/objectpool.proto +0 -0
  191. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/operations.proto +0 -0
  192. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/packfile.proto +0 -0
  193. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/praefect.proto +0 -0
  194. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/ref.proto +0 -0
  195. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/remote.proto +0 -0
  196. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/repository.proto +0 -0
  197. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/server.proto +0 -0
  198. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/service_config.proto +0 -0
  199. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/shared.proto +0 -0
  200. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/smarthttp.proto +0 -0
  201. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/ssh.proto +0 -0
  202. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/transaction.proto +0 -0
  203. {hgitaly-2.5.3 → hgitaly-2.5.4}/protos/wiki.proto +0 -0
  204. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/.ruby-version +0 -0
  205. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/Gemfile +0 -0
  206. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/README.md +0 -0
  207. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/generate-grpc-lib +0 -0
  208. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/hgitaly.gemspec +0 -0
  209. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/lib/hgitaly/mercurial-changeset_pb.rb +0 -0
  210. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/lib/hgitaly/mercurial-changeset_services_pb.rb +0 -0
  211. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/lib/hgitaly/mercurial-operations_pb.rb +0 -0
  212. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/lib/hgitaly/mercurial-operations_services_pb.rb +0 -0
  213. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/lib/hgitaly/mercurial-repository_pb.rb +0 -0
  214. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/lib/hgitaly/mercurial-repository_services_pb.rb +0 -0
  215. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/lib/hgitaly/version.rb +0 -0
  216. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/lib/hgitaly.rb +0 -0
  217. {hgitaly-2.5.3 → hgitaly-2.5.4}/ruby/run.rb +0 -0
  218. {hgitaly-2.5.3 → hgitaly-2.5.4}/run-all-tests +0 -0
  219. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/Cargo.lock +0 -0
  220. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/Cargo.toml +0 -0
  221. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/Makefile +0 -0
  222. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/build-from-tarball.sh +0 -0
  223. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/check-line-width +0 -0
  224. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/README.md +0 -0
  225. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/mercurial.patch +0 -0
  226. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/any.proto +0 -0
  227. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/api.proto +0 -0
  228. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/compiler/plugin.proto +0 -0
  229. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/descriptor.proto +0 -0
  230. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/duration.proto +0 -0
  231. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/empty.proto +0 -0
  232. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/field_mask.proto +0 -0
  233. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/source_context.proto +0 -0
  234. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/struct.proto +0 -0
  235. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/timestamp.proto +0 -0
  236. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/type.proto +0 -0
  237. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/dependencies/proto/google/protobuf/wrappers.proto +0 -0
  238. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/go-enry.rev +0 -0
  239. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/lint +0 -0
  240. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/mercurial.rev +0 -0
  241. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/Cargo.toml +0 -0
  242. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/build.rs +0 -0
  243. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/clippy.toml +0 -0
  244. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/config.rs +0 -0
  245. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/errors.rs +0 -0
  246. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/generated/README.md +0 -0
  247. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/git.rs +0 -0
  248. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/gitlab/mod.rs +0 -0
  249. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/gitlab/reference.rs +0 -0
  250. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/gitlab/revision.rs +0 -0
  251. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/gitlab/state.rs +0 -0
  252. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/glob.rs +0 -0
  253. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/lib.rs +0 -0
  254. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/main.rs +0 -0
  255. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/mercurial.rs +0 -0
  256. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/message.rs +0 -0
  257. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/metadata.rs +0 -0
  258. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/oid.rs +0 -0
  259. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/process.rs +0 -0
  260. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/repository.rs +0 -0
  261. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/analysis.rs +0 -0
  262. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/blob.rs +0 -0
  263. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/commit/find_commits.rs +0 -0
  264. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/commit/get_tree_entries.rs +0 -0
  265. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/commit/last_commits.rs +0 -0
  266. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/commit/mod.rs +0 -0
  267. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/commit/tree_entry.rs +0 -0
  268. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/diff.rs +0 -0
  269. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/mercurial_repository.rs +0 -0
  270. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/mod.rs +0 -0
  271. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/ref.rs +0 -0
  272. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/repository.rs +0 -0
  273. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/service/server.rs +0 -0
  274. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/sidecar.rs +0 -0
  275. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/streaming.rs +0 -0
  276. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rhgitaly/src/util.rs +0 -0
  277. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/rs-enry.rev +0 -0
  278. {hgitaly-2.5.3 → hgitaly-2.5.4}/rust/src-tarball.sh +0 -0
  279. {hgitaly-2.5.3 → hgitaly-2.5.4}/setup.cfg +0 -0
  280. {hgitaly-2.5.3 → hgitaly-2.5.4}/setup.py +0 -0
  281. {hgitaly-2.5.3 → hgitaly-2.5.4}/test-requirements.txt +0 -0
  282. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/__init__.py +0 -0
  283. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/conftest.py +0 -0
  284. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/gitaly.py +0 -0
  285. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/hgitaly_rhgitaly_comparison.py +0 -0
  286. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/rhgitaly.py +0 -0
  287. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_blob_tree.py +0 -0
  288. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_comparison.py +0 -0
  289. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_gitaly_server.py +0 -0
  290. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_mercurial_repository.py +0 -0
  291. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_repository_service.py +0 -0
  292. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_rhgitaly_server.py +0 -0
  293. {hgitaly-2.5.3 → hgitaly-2.5.4}/tests_with_gitaly/test_server.py +0 -0
@@ -118,3 +118,4 @@ a118debbf0a0deaa94b02ed0007ab2ef0f2b73c3 2.4.0
118
118
  c1b00e1bc1bf0a2d41907b345c48cf795f910a4f 2.5.0
119
119
  136dff98ddc1315e6db9479d9b6dd2c2204c2e5f 2.5.1
120
120
  7dbcba18d83708ff81d8cec9696a86d24ed5d20a 2.5.2
121
+ 3a83836b7408f1318a80f1ba97051086596edd12 2.5.3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hgitaly
3
- Version: 2.5.3
3
+ Version: 2.5.4
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
@@ -0,0 +1 @@
1
+ 2.5.4
@@ -46,17 +46,19 @@ Status_Type_Map = dict(
46
46
  added=ChangedPaths.Status.ADDED,
47
47
  modified=ChangedPaths.Status.MODIFIED,
48
48
  removed=ChangedPaths.Status.DELETED,
49
+ renamed=ChangedPaths.Status.RENAMED,
49
50
  # Note: Mercurial includes TYPE_CHANGE
50
51
  # (symlink, regular file, submodule...etc) in MODIFIED status
51
52
  )
52
53
  """Mapping status object attributes to ChangedPaths enum."""
53
54
 
54
55
  COPIED = ChangedPaths.Status.COPIED
56
+ RENAMED = ChangedPaths.Status.RENAMED
55
57
  DIFF_HUNKS_START_RX = re.compile(rb'^(--- )|^(Binary file)')
56
58
  """To match the header line right before hunks start getting dumped."""
57
59
 
58
60
 
59
- def changed_paths(repo, from_ctx, to_ctx, base_path):
61
+ def changed_paths(repo, from_ctx, to_ctx, base_path, find_renames=False):
60
62
  if base_path is None:
61
63
  matcher = None
62
64
  path_trim_at = 0
@@ -74,26 +76,33 @@ def changed_paths(repo, from_ctx, to_ctx, base_path):
74
76
  patterns=[b'path:' + base_path])
75
77
  path_trim_at = len(base_path) + 1
76
78
 
77
- copied = list(copy_changed_paths(
78
- from_ctx,
79
- to_ctx,
80
- copies.pathcopies(from_ctx, to_ctx, match=matcher),
81
- trim_at=path_trim_at))
82
- copied_paths = set(cp.path for cp in copied)
79
+ copy_info = copies.pathcopies(from_ctx, to_ctx, match=matcher)
80
+ # copies do not distinguish actual copies from renames. The difference
81
+ # will be that a rename goes with deletion of the original.
83
82
 
84
83
  status = from_ctx.status(to_ctx, match=matcher)
85
- for path in status_changed_paths(from_ctx, to_ctx, status,
86
- trim_at=path_trim_at):
87
- if path.path not in copied_paths:
88
- yield path
89
-
90
- yield from iter(copied)
91
-
92
-
93
- def status_changed_paths(from_ctx, to_ctx, status, trim_at=0):
84
+ # this will remove renames from copy_info, keeping only actual copies
85
+ yield from status_changed_paths(from_ctx, to_ctx, status, copy_info,
86
+ find_renames=find_renames,
87
+ trim_at=path_trim_at)
88
+ yield from copy_changed_paths(from_ctx,
89
+ to_ctx,
90
+ copy_info,
91
+ trim_at=path_trim_at)
92
+
93
+
94
+ def status_changed_paths(from_ctx, to_ctx, status, copy_info,
95
+ find_renames=False, trim_at=0):
96
+ rcopy_info = {v: k for k, v in copy_info.items()}
94
97
  """Return ChangedPaths from Mercurial status object"""
95
98
  for stype in ['added', 'modified', 'removed']:
96
99
  for path in status.__getattribute__(stype):
100
+ copied_from = copy_info.get(path)
101
+ if copied_from is not None:
102
+ if copied_from not in status.removed or find_renames:
103
+ continue
104
+
105
+ old_path = b''
97
106
  if stype == 'added':
98
107
  old_mode = OBJECT_MODE_DOES_NOT_EXIST
99
108
  old_blob_id = NULL_BLOB_OID
@@ -102,8 +111,21 @@ def status_changed_paths(from_ctx, to_ctx, status, trim_at=0):
102
111
  old_blob_id = ctx_blob_oid(from_ctx, path)
103
112
 
104
113
  if stype == 'removed':
105
- new_mode = OBJECT_MODE_DOES_NOT_EXIST
106
- new_blob_id = NULL_BLOB_OID
114
+ new_path = rcopy_info.get(path)
115
+ if new_path is None:
116
+ new_mode = OBJECT_MODE_DOES_NOT_EXIST
117
+ new_blob_id = NULL_BLOB_OID
118
+ else:
119
+ del copy_info[new_path]
120
+ if find_renames:
121
+ stype = 'renamed'
122
+ old_path = path
123
+ path = new_path
124
+ new_mode = git_perms(to_ctx.filectx(new_path))
125
+ new_blob_id = ctx_blob_oid(to_ctx, new_path)
126
+ else:
127
+ new_mode = OBJECT_MODE_DOES_NOT_EXIST
128
+ new_blob_id = NULL_BLOB_OID
107
129
  else:
108
130
  new_mode = git_perms(to_ctx.filectx(path))
109
131
  new_blob_id = ctx_blob_oid(to_ctx, path)
@@ -114,11 +136,13 @@ def status_changed_paths(from_ctx, to_ctx, status, trim_at=0):
114
136
  new_mode=new_mode,
115
137
  old_blob_id=old_blob_id,
116
138
  new_blob_id=new_blob_id,
139
+ old_path=old_path,
117
140
  status=Status_Type_Map[stype]
118
141
  )
119
142
 
120
143
 
121
- def copy_changed_paths(from_ctx, to_ctx, path_copies, trim_at=0):
144
+ def copy_changed_paths(from_ctx, to_ctx, path_copies,
145
+ trim_at=0, find_renames=False):
122
146
  """Return ChangedPaths for the given paths, relative to base_path.
123
147
 
124
148
  Given that Gitaly currently (gitaly@c54d613d0) does not pass
@@ -129,8 +153,11 @@ def copy_changed_paths(from_ctx, to_ctx, path_copies, trim_at=0):
129
153
  for target, source in path_copies.items():
130
154
  yield ChangedPaths(path=target[trim_at:],
131
155
  status=COPIED,
132
- old_mode=git_perms(to_ctx.filectx(source)),
156
+ old_mode=git_perms(from_ctx.filectx(source)),
157
+ old_blob_id=ctx_blob_oid(from_ctx, source),
133
158
  new_mode=git_perms(to_ctx.filectx(target)),
159
+ new_blob_id=ctx_blob_oid(to_ctx, target),
160
+ old_path=source[trim_at:],
134
161
  )
135
162
 
136
163
 
@@ -87,6 +87,10 @@ def message_to_string(message):
87
87
  return result
88
88
 
89
89
 
90
+ def as_dict(message):
91
+ return {descr.name: value for descr, value in message.ListFields()}
92
+
93
+
90
94
  class Logging:
91
95
  """Wrapper of requests and responses for sensible logging.
92
96
 
@@ -521,8 +521,11 @@ class DiffServicer(DiffServiceServicer, HGitalyServicer):
521
521
  for cp in cids_paths]
522
522
  extracted.append((left_ctx, right_ctx, path))
523
523
 
524
+ find_renames = request.find_renames
524
525
  for paths in chunked(path for extr in extracted
525
- for path in changed_paths(repo, *extr)):
526
+ for path in changed_paths(
527
+ repo, *extr,
528
+ find_renames=find_renames)):
526
529
  yield FindChangedPathsResponse(paths=paths)
527
530
 
528
531
  def GetPatchID(self, request: GetPatchIDRequest,
@@ -28,6 +28,8 @@ from hgext3rd.heptapod.special_ref import (
28
28
  )
29
29
  from hgext3rd.heptapod.keep_around import (
30
30
  parse_keep_around_ref,
31
+ iter_keep_arounds,
32
+ init_keep_arounds,
31
33
  )
32
34
 
33
35
  from ..errors import (
@@ -40,6 +42,8 @@ from ..pagination import (
40
42
  )
41
43
  from ..revision import (
42
44
  CHANGESET_HASH_BYTES_REGEXP,
45
+ ZERO_SHA,
46
+ ZERO_SHA_STR,
43
47
  gitlab_revision_hash,
44
48
  )
45
49
  from ..stream import (
@@ -51,6 +55,7 @@ from ..stub.shared_pb2 import (
51
55
  )
52
56
  from ..stub.errors_pb2 import (
53
57
  ReferenceNotFoundError,
58
+ ReferenceStateMismatchError,
54
59
  )
55
60
  from ..stub.ref_pb2 import (
56
61
  FindDefaultBranchNameRequest,
@@ -74,6 +79,9 @@ from ..stub.ref_pb2 import (
74
79
  FindBranchResponse,
75
80
  DeleteRefsRequest,
76
81
  DeleteRefsResponse,
82
+ UpdateReferencesError,
83
+ UpdateReferencesRequest,
84
+ UpdateReferencesResponse,
77
85
  ListBranchNamesContainingCommitRequest,
78
86
  ListBranchNamesContainingCommitResponse,
79
87
  ListTagNamesContainingCommitRequest,
@@ -87,9 +95,6 @@ from ..stub.ref_pb2 import (
87
95
  )
88
96
  from ..stub.ref_pb2_grpc import RefServiceServicer
89
97
 
90
- from ..revision import (
91
- ZERO_SHA_STR,
92
- )
93
98
  from ..branch import (
94
99
  BranchSortBy,
95
100
  gitlab_branch_head,
@@ -273,6 +278,93 @@ class RefServicer(RefServiceServicer, HGitalyServicer):
273
278
  return FindBranchResponse(
274
279
  branch=Branch(name=name, target_commit=message.commit(head)))
275
280
 
281
+ def UpdateReferences(self,
282
+ request: UpdateReferencesRequest,
283
+ context) -> UpdateReferencesResponse:
284
+ self.STATUS_CODE_STORAGE_NOT_FOUND = StatusCode.INVALID_ARGUMENT
285
+ first = True
286
+ special_changes = []
287
+ ka_changes = []
288
+ for req in request:
289
+ if first:
290
+ # blobs are given by oid, hence as in direct changeset Node
291
+ # IDs, the unfiltered repo is the right one for the task
292
+ repo = self.load_repo(req.repository, context).unfiltered()
293
+ first = False
294
+
295
+ for upd in req.updates:
296
+ if len(upd.new_object_id) != 40:
297
+ oid = upd.new_object_id.decode('ascii', 'replace')
298
+ context.abort(StatusCode.INVALID_ARGUMENT,
299
+ "validating new object ID: "
300
+ f'invalid object ID: "{oid}", '
301
+ f"expected length 40, got {len(oid)}")
302
+
303
+ ref_path = upd.reference
304
+ change = (upd.old_object_id, upd.new_object_id)
305
+ if change[0] == change[1]:
306
+ # let's not waste resources for this
307
+ continue
308
+
309
+ # consider only special refs and keep-arounds, as other refs
310
+ # (branches and tags) are only reflecting changesets content,
311
+ # setting them independently makes no sense with Mercurial
312
+ special_ref = parse_special_ref(ref_path)
313
+ if special_ref is not None:
314
+ special_changes.append((special_ref, change))
315
+ continue
316
+
317
+ ka = parse_keep_around_ref(upd.reference)
318
+ if ka is not None:
319
+ if (
320
+ upd.new_object_id != ZERO_SHA
321
+ and ka != upd.new_object_id
322
+ ):
323
+ context.abort(StatusCode.INVALID_ARGUMENT,
324
+ "Inconsistent keep-around.")
325
+ ka_changes.append(change)
326
+
327
+ with repo.lock():
328
+ # keeping promise of atomicity of this method
329
+ special_existing = special_refs(repo)
330
+ if special_existing is GITLAB_TYPED_REFS_MISSING:
331
+ special_existing = {}
332
+ for name, (old_id, new_id) in special_changes:
333
+ existing = special_existing.get(name)
334
+ if old_id == ZERO_SHA and existing is not None:
335
+ context.abort(StatusCode.INTERNAL,
336
+ "committing update: "
337
+ "reference already exists")
338
+ elif old_id and old_id != ZERO_SHA and existing != old_id:
339
+ Mismatch = ReferenceStateMismatchError # just too long!
340
+ structured_abort(
341
+ context, StatusCode.ABORTED,
342
+ "reference does not point to expected object",
343
+ UpdateReferencesError(
344
+ reference_state_mismatch=Mismatch(
345
+ reference_name=b'refs/' + name,
346
+ expected_object_id=old_id,
347
+ actual_object_id=existing)))
348
+ elif new_id == ZERO_SHA:
349
+ del special_existing[name]
350
+ else:
351
+ special_existing[name] = new_id
352
+
353
+ # TODO make a collect_keep_arounds() or keep_arounds_set()
354
+ ka_existing = set(iter_keep_arounds(repo))
355
+ ka_existing.discard(GITLAB_TYPED_REFS_MISSING)
356
+ for old_id, new_id in ka_changes:
357
+ # bogus requests have already been prohibited
358
+ if new_id == ZERO_SHA:
359
+ ka_existing.discard(old_id)
360
+ else:
361
+ ka_existing.add(new_id)
362
+
363
+ write_special_refs(repo, special_existing)
364
+ init_keep_arounds(repo, ka_existing)
365
+
366
+ return UpdateReferencesResponse()
367
+
276
368
  def DeleteRefs(self,
277
369
  request: DeleteRefsRequest,
278
370
  context) -> DeleteRefsResponse:
@@ -127,7 +127,7 @@ class DiffFixture(ServiceFixture):
127
127
  (changed.status, perm_change))
128
128
  return by_file
129
129
 
130
- def find_changed_paths_commits(self, commits, compare_to=()):
130
+ def find_changed_paths_commits(self, commits, compare_to=(), **kw):
131
131
  """Wrap FindChangedPaths used with CommitRequest.
132
132
 
133
133
  :param compare_to: if given, will be used in all requests, hoping
@@ -141,6 +141,7 @@ class DiffFixture(ServiceFixture):
141
141
  commit_revision=c,
142
142
  parent_commit_revisions=compare_to))
143
143
  for c in commits],
144
+ **kw
144
145
  )
145
146
 
146
147
  def find_changed_paths_tree(self, left_oid, right_oid):
@@ -686,6 +687,50 @@ def test_find_changed_paths_copy_in_tree(diff_fixture):
686
687
  }
687
688
 
688
689
 
690
+ def test_find_changed_paths_rename(diff_fixture):
691
+ wrapper = diff_fixture.repo_wrapper
692
+
693
+ (wrapper.path / 'subdir').mkdir() # avoid all lengths to be 3
694
+ (wrapper.path / 'subdir/bar').write_text('some bar')
695
+ ctx0 = wrapper.commit(rel_paths=['subdir'], add_remove=True)
696
+
697
+ wrapper.command(b'mv', wrapper.repo.root + b'/subdir/bar',
698
+ wrapper.repo.root + b'/subdir/baz')
699
+ ctx1 = wrapper.commit(rel_paths=['subdir'])
700
+
701
+ repo = wrapper.repo
702
+
703
+ sub0_oid, sub1_oid = [tree_oid(repo, ctx.hex().decode('ascii'), b'subdir')
704
+ for ctx in (ctx0, ctx1)]
705
+ ret = diff_fixture.find_changed_paths_commits(
706
+ [ctx1.hex()],
707
+ compare_to=[ctx0.hex()],
708
+ find_renames=False,
709
+ )
710
+ assert ret == {
711
+ b'subdir/baz': [(ChangedPaths.Status.ADDED,
712
+ (OBJECT_MODE_DOES_NOT_EXIST,
713
+ OBJECT_MODE_NON_EXECUTABLE),
714
+ )],
715
+ b'subdir/bar': [(ChangedPaths.Status.DELETED,
716
+ (OBJECT_MODE_NON_EXECUTABLE,
717
+ OBJECT_MODE_DOES_NOT_EXIST)
718
+ )],
719
+ }
720
+
721
+ ret = diff_fixture.find_changed_paths_commits(
722
+ [ctx1.hex()],
723
+ compare_to=[ctx0.hex()],
724
+ find_renames=True,
725
+ )
726
+ assert ret == {
727
+ b'subdir/baz': [(ChangedPaths.Status.RENAMED, None)],
728
+ }
729
+
730
+ # TODO test the case of rename with duplication:
731
+ # hg cp foo bar; hg mv foo bar2
732
+
733
+
689
734
  def test_get_patch_id(diff_fixture):
690
735
  wrapper = diff_fixture.repo_wrapper
691
736
  patch_id = diff_fixture.get_patch_id
@@ -30,6 +30,7 @@ from hgext3rd.heptapod.keep_around import (
30
30
  from hgitaly import feature
31
31
  from hgitaly.errors import parse_assert_structured_error
32
32
  from hgitaly.revision import (
33
+ ZERO_SHA,
33
34
  ZERO_SHA_STR,
34
35
  )
35
36
  from hgitaly.tests.common import (
@@ -56,6 +57,7 @@ from hgitaly.stub.ref_pb2 import (
56
57
  FindRefsByOIDRequest,
57
58
  FindTagError,
58
59
  FindTagRequest,
60
+ UpdateReferencesRequest,
59
61
  )
60
62
  from hgitaly.stub.ref_pb2_grpc import RefServiceStub
61
63
 
@@ -85,6 +87,10 @@ class RefFixture(ServiceFixture):
85
87
  metadata=feature.as_grpc_metadata(self.feature_flags),
86
88
  )
87
89
 
90
+ def ref_exists(self, ref, **kw):
91
+ kw.setdefault('repository', self.grpc_repo)
92
+ return self.stub.RefExists(RefExistsRequest(ref=ref, **kw)).value
93
+
88
94
  def list_refs(self, patterns=(b"refs/", ), **kw):
89
95
  return [(ref.name, ref.target)
90
96
  for resp in self.stub.ListRefs(
@@ -97,6 +103,22 @@ class RefFixture(ServiceFixture):
97
103
  kw.setdefault('repository', self.grpc_repo)
98
104
  return self.stub.FindRefsByOID(FindRefsByOIDRequest(**kw)).refs
99
105
 
106
+ def update_refs(self, updates, **kw):
107
+ Update = UpdateReferencesRequest.Update
108
+ kw.setdefault('repository', self.grpc_repo)
109
+
110
+ update_messages = []
111
+ for ref_path, old_id, new_id in updates:
112
+ upd_kw = dict(reference=ref_path, new_object_id=new_id)
113
+ if old_id is not None:
114
+ upd_kw['old_object_id'] = old_id
115
+ update_messages.append(Update(**upd_kw))
116
+
117
+ return self.stub.UpdateReferences(
118
+ iter([UpdateReferencesRequest(updates=[upd], **kw)
119
+ for upd in update_messages])
120
+ )
121
+
100
122
 
101
123
  @pytest.fixture
102
124
  def ref_fixture(grpc_channel, server_repos_root):
@@ -633,3 +655,58 @@ def test_list_refs(ref_fixture):
633
655
  assert fixture.find_refs_by_oid(
634
656
  oid=sha1, sort_field='refname', limit=1
635
657
  ) == ['refs/heads/branch/default']
658
+
659
+
660
+ def test_update_references(ref_fixture):
661
+ fixture = ref_fixture
662
+ wrapper = fixture.repo_wrapper
663
+
664
+ sha0 = wrapper.write_commit('afoo', message="Some foo").hex()
665
+ sha1 = wrapper.write_commit('afoo', message="Some foo").hex()
666
+
667
+ pipeline_1 = b'refs/pipelines/1'
668
+ ka_0 = b'refs/keep-around/' + sha0
669
+ fixture.update_refs([(pipeline_1, ZERO_SHA, sha1),
670
+ (ka_0, ZERO_SHA, sha0),
671
+ ])
672
+ assert fixture.ref_exists(ka_0)
673
+ assert fixture.ref_exists(pipeline_1)
674
+ assert fixture.list_refs(patterns=[b'refs/pipelines/']) == [
675
+ (pipeline_1, sha1.decode())
676
+ ]
677
+
678
+ fixture.update_refs([(pipeline_1, sha1, sha0),
679
+ (ka_0, sha0, ZERO_SHA),
680
+ ])
681
+ assert not fixture.ref_exists(ka_0)
682
+ assert fixture.list_refs(patterns=[b'refs/pipelines/']) == [
683
+ (pipeline_1, sha0.decode())
684
+ ]
685
+
686
+ # edge case equivalent to no-op
687
+ fixture.update_refs([(pipeline_1, sha0, sha0)])
688
+ assert fixture.list_refs(patterns=[b'refs/pipelines/']) == [
689
+ (pipeline_1, sha0.decode())
690
+ ]
691
+
692
+ # error cases
693
+ with pytest.raises(grpc.RpcError) as exc_info:
694
+ fixture.update_refs([(pipeline_1, None, b'branch/default')])
695
+ assert exc_info.value.code() == grpc.StatusCode.INVALID_ARGUMENT
696
+
697
+ with pytest.raises(grpc.RpcError) as exc_info:
698
+ fixture.update_refs([(ka_0, None, sha1)])
699
+ assert exc_info.value.code() == grpc.StatusCode.INVALID_ARGUMENT
700
+
701
+ with pytest.raises(grpc.RpcError) as exc_info:
702
+ fixture.update_refs([(pipeline_1, ZERO_SHA, sha1)])
703
+ assert exc_info.value.code() == grpc.StatusCode.INTERNAL
704
+ assert 'reference already exists' in exc_info.value.details()
705
+
706
+ with pytest.raises(grpc.RpcError) as exc_info:
707
+ fixture.update_refs([(pipeline_1, sha1, sha0)])
708
+ assert exc_info.value.code() == grpc.StatusCode.ABORTED
709
+
710
+ # deletions
711
+ fixture.update_refs([(pipeline_1, sha0, ZERO_SHA)])
712
+ assert not fixture.ref_exists(pipeline_1)
@@ -54,6 +54,11 @@ def test_tag(tmpdir):
54
54
  assert tag.signature_type == SignatureType.PGP
55
55
 
56
56
 
57
+ def test_as_dict():
58
+ d = dict(storage_name='thestore', relative_path='a/b/c')
59
+ assert message.as_dict(Repository(**d)) == d
60
+
61
+
57
62
  def test_commit_author():
58
63
 
59
64
  class FakeContext:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: hgitaly
3
- Version: 2.5.3
3
+ Version: 2.5.4
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
@@ -35,6 +35,7 @@ from hgitaly.errors import (
35
35
  parse_structured_error,
36
36
  )
37
37
  from hgitaly import feature
38
+ from hgitaly import message
38
39
  from hgitaly.errors import HGITALY_ISSUES_URL
39
40
  from hgitaly.gitlab_ref import (
40
41
  keep_around_ref_path,
@@ -264,6 +265,59 @@ class BaseRpcHelper:
264
265
  for k, v in defaults.items():
265
266
  kwargs.setdefault(k, v)
266
267
 
268
+ def structured_errors_git_converter(self, fields, error_git_cls=None):
269
+ """Return a function that is suitable for `to_git` in handler.
270
+
271
+ This matches the common pattern of the structured error being
272
+ an enum with subobject variants
273
+ Only full hash string or bytes values are supported and lists of
274
+ these are supported at this point
275
+
276
+ :param fields: a list of :class:`dict`with keys:
277
+
278
+ - `hg_field`: name of the variant for HGitaly
279
+ - `git_field`: name of the variant for Gitaly,
280
+ defaults to `hg_field`
281
+ - `git_cls`: variant class to use for Gitaly, defaults to the
282
+ received HGitaly variant class
283
+ - `subfields`: list of names of fields in the varian to convert.
284
+ Use the `[]` suffix to specify that a field is
285
+ repeated.
286
+ """
287
+ def to_git(error):
288
+ if error_git_cls is None:
289
+ error_git_class = error.__class__ # pragma no cover
290
+ else:
291
+ error_git_class = error_git_cls
292
+ for descr in fields:
293
+ name = descr['hg_field']
294
+ new_name = descr.get('git_field', name)
295
+ if error.HasField(name):
296
+ subobj = getattr(error, name)
297
+ git_cls = descr.get('git_cls', subobj.__class__)
298
+ # direct assignment to repeated values is not possible
299
+ # so we copy in a dict and reinstantiate
300
+ subitems = message.as_dict(subobj)
301
+ for field in descr['subfields']:
302
+ repeated = field.endswith('[]')
303
+ if repeated:
304
+ field = field[:-2]
305
+ hg_val = subitems.get(field)
306
+ if hg_val is None:
307
+ continue # pragma no cover
308
+
309
+ if repeated:
310
+ git_val = [self.hg2git(sha) for sha in hg_val]
311
+ else:
312
+ git_val = self.hg2git(hg_val)
313
+ subitems[field] = git_val
314
+ subobj = git_cls(**subitems)
315
+ return error_git_class(**{new_name: subobj})
316
+
317
+ raise AssertionError("Unexpected error variant") # pragma no cover
318
+
319
+ return to_git
320
+
267
321
  def assert_compare_grpc_exceptions(self, exc0, exc1,
268
322
  same_details=True,
269
323
  vcses=('hg', 'git'),
@@ -319,12 +373,13 @@ class BaseRpcHelper:
319
373
  if extracted:
320
374
  assert extracted[0]['code'] == extracted[1]['code']
321
375
  if vcses[1] == 'git':
322
- git_norm = handler.get('git_normalizer')
323
- if git_norm is not None:
324
- git_norm(extracted[1]['error'])
325
376
  extracted[0]['error'] = handler['to_git'](
326
377
  extracted[0]['error'])
327
378
 
379
+ norm = handler.get('normalizer')
380
+ if norm is not None:
381
+ norm(extracted[0]['error'])
382
+ norm(extracted[1]['error'])
328
383
  assert extracted[0]['error'] == extracted[1]['error']
329
384
 
330
385
  # already done and a priori not directly comparable
@@ -413,15 +468,17 @@ class RpcHelper(BaseRpcHelper):
413
468
  return keep_around_ref_path(self.hg2git(hg_sha))
414
469
 
415
470
  def request_kwargs_to_git(self, hg_kwargs):
416
- git_kwargs = hg_kwargs.copy()
417
- for sha_attr in self.request_sha_attrs:
418
- sha = hg_kwargs.get(sha_attr)
419
- if sha is None:
420
- continue
421
- if isinstance(sha, list):
422
- git_kwargs[sha_attr] = [self.revspec_to_git(s) for s in sha]
423
- else:
424
- git_kwargs[sha_attr] = self.revspec_to_git(sha)
471
+ # attr_path_to_git updates lists in place, because it needs
472
+ # to do so in the case of scalar lists for Messages. Hence in the
473
+ # case of dicts, we need to perform the deep copy.
474
+ git_kwargs = deepcopy(hg_kwargs)
475
+ sha_attr_paths = [path.split('.') for path in self.request_sha_attrs]
476
+ for attr_path in sha_attr_paths:
477
+ self.attr_path_to_git(git_kwargs, attr_path,
478
+ accessor=lambda d, k: d.get(k),
479
+ setter=lambda d, k, v: d.__setitem__(k, v),
480
+ has_field=lambda d, f: f in d,
481
+ )
425
482
  return git_kwargs
426
483
 
427
484
  def revspec_to_git(self, revspec):
@@ -445,16 +502,20 @@ class RpcHelper(BaseRpcHelper):
445
502
  def response_to_git(self, resp):
446
503
  sha_attr_paths = [path.split('.') for path in self.response_sha_attrs]
447
504
  if self.streaming:
448
- for message in resp:
449
- self.message_to_git(message, sha_attr_paths)
505
+ for msg in resp:
506
+ self.message_to_git(msg, sha_attr_paths)
450
507
  else:
451
508
  self.message_to_git(resp, sha_attr_paths)
452
509
 
453
- def message_to_git(self, message, attr_paths):
510
+ def message_to_git(self, message, attr_paths, **kw):
454
511
  for attr_path in attr_paths:
455
- self.attr_path_to_git(message, attr_path)
512
+ self.attr_path_to_git(message, attr_path, **kw)
456
513
 
457
- def attr_path_to_git(self, message, attr_path):
514
+ def attr_path_to_git(self, message, attr_path,
515
+ accessor=getattr,
516
+ setter=setattr,
517
+ has_field=lambda o, f: o.HasField(f),
518
+ ):
458
519
  """Convert to Git part of message specified by an attr_path.
459
520
 
460
521
  :param attr_path: symbolic representation, as a succession of dotted
@@ -475,11 +536,14 @@ class RpcHelper(BaseRpcHelper):
475
536
  if recurse:
476
537
  attr_name = attr_name[:-2]
477
538
  # HasField cannot be used on repeated attributes, hence the elif
478
- elif not obj.HasField(attr_name):
539
+ elif not has_field(obj, attr_name):
479
540
  return
480
- obj = getattr(obj, attr_name)
541
+ obj = accessor(obj, attr_name)
542
+ if obj is None: # can happen with an accessor for dicts
543
+ continue # pragma no cover TODO make unit tests for RpcHelper
481
544
  if recurse:
482
545
  for msg in obj:
546
+ # after traversal, we are sure to be on a Message instance
483
547
  self.message_to_git(msg, [trav])
484
548
  return
485
549
 
@@ -487,13 +551,15 @@ class RpcHelper(BaseRpcHelper):
487
551
  scalar_list = obj_attr.endswith('[]')
488
552
  if scalar_list:
489
553
  obj_attr = obj_attr[:-2]
490
- value = getattr(obj, obj_attr)
554
+ value = accessor(obj, obj_attr)
555
+ if value is None:
556
+ return
491
557
 
492
558
  if scalar_list:
493
559
  for i, sha in enumerate(value):
494
- value[i] = self.hg2git(sha)
560
+ value[i] = self.revspec_to_git(sha)
495
561
  else:
496
- setattr(obj, obj_attr, self.hg2git(value))
562
+ setter(obj, obj_attr, self.revspec_to_git(value))
497
563
 
498
564
  def call_backends(self, **hg_kwargs):
499
565
  """Call Gitaly and HGitaly with uniform request kwargs.