devpi-server 6.12.1__tar.gz → 6.13.0__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 (133) hide show
  1. {devpi-server-6.12.1 → devpi-server-6.13.0}/.flake8 +2 -2
  2. {devpi-server-6.12.1 → devpi-server-6.13.0}/CHANGELOG +35 -0
  3. {devpi-server-6.12.1 → devpi-server-6.13.0}/PKG-INFO +37 -10
  4. devpi-server-6.13.0/devpi_server/__init__.py +1 -0
  5. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/config.py +186 -77
  6. devpi-server-6.13.0/devpi_server/filestore.py +630 -0
  7. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/fileutil.py +2 -0
  8. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/fsck.py +7 -9
  9. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/genconfig.py +3 -3
  10. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/hookspecs.py +4 -4
  11. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/importexport.py +40 -26
  12. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/init.py +7 -7
  13. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/keyfs.py +46 -23
  14. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/log.py +27 -22
  15. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/main.py +38 -19
  16. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/mirror.py +7 -7
  17. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/model.py +61 -19
  18. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/mythread.py +37 -0
  19. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/passwd.py +4 -4
  20. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/replica.py +181 -94
  21. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/sizeof.py +1 -1
  22. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/views.py +94 -49
  23. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server.egg-info/PKG-INFO +37 -10
  24. devpi-server-6.13.0/pyproject.toml +99 -0
  25. {devpi-server-6.12.1 → devpi-server-6.13.0}/setup.py +2 -1
  26. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/functional.py +8 -2
  27. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/plugin.py +172 -91
  28. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_config.py +93 -22
  29. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_conftest.py +24 -3
  30. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_filestore.py +16 -20
  31. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_fsck.py +5 -8
  32. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_importexport.py +98 -81
  33. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_keyfs.py +14 -12
  34. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_keyfs_sqlite_fs.py +6 -7
  35. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_main.py +35 -31
  36. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_mirror.py +28 -0
  37. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_model.py +5 -3
  38. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_mythread.py +4 -2
  39. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_nginx_replica.py +5 -4
  40. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_permissions.py +7 -2
  41. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_replica.py +131 -77
  42. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_replica_functional.py +9 -9
  43. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_stage_customizer.py +2 -2
  44. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_streaming.py +8 -8
  45. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_streaming_nginx.py +2 -2
  46. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_streaming_replica.py +2 -2
  47. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_streaming_replica_nginx.py +2 -2
  48. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_views.py +71 -34
  49. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_views_push_external.py +24 -3
  50. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_views_status.py +67 -14
  51. devpi-server-6.13.0/tox.ini +78 -0
  52. devpi-server-6.12.1/devpi_server/__init__.py +0 -1
  53. devpi-server-6.12.1/devpi_server/filestore.py +0 -335
  54. devpi-server-6.12.1/pyproject.toml +0 -26
  55. devpi-server-6.12.1/tox.ini +0 -40
  56. {devpi-server-6.12.1 → devpi-server-6.13.0}/AUTHORS +0 -0
  57. {devpi-server-6.12.1 → devpi-server-6.13.0}/LICENSE +0 -0
  58. {devpi-server-6.12.1 → devpi-server-6.13.0}/MANIFEST.in +0 -0
  59. {devpi-server-6.12.1 → devpi-server-6.13.0}/README.rst +0 -0
  60. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/__main__.py +0 -0
  61. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/auth.py +0 -0
  62. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/auth_basic.py +0 -0
  63. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/auth_devpi.py +0 -0
  64. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/__init__.py +0 -0
  65. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/crontab.template +0 -0
  66. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/devpi.service.template +0 -0
  67. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/launchd-macos.txt.template +0 -0
  68. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/nginx-devpi-caching-http.conf.template +0 -0
  69. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/nginx-devpi-caching-location.conf.template +0 -0
  70. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/nginx-devpi-caching-proxy.conf.template +0 -0
  71. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/nginx-devpi-caching-server.conf.template +0 -0
  72. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/nginx-devpi.conf.template +0 -0
  73. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/supervisor-devpi.conf.template +0 -0
  74. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/supervisord.conf.template +0 -0
  75. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/cfg/windows-service.txt.template +0 -0
  76. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/exceptions.py +0 -0
  77. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/filestore_fs.py +0 -0
  78. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/interfaces.py +0 -0
  79. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/keyfs_sqlite.py +0 -0
  80. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/keyfs_sqlite_fs.py +0 -0
  81. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/keyfs_types.py +0 -0
  82. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/markers.py +0 -0
  83. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/middleware.py +0 -0
  84. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/readonly.py +0 -0
  85. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/vendor/__init__.py +0 -0
  86. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/vendor/_pip.py +0 -0
  87. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server/view_auth.py +0 -0
  88. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server.egg-info/SOURCES.txt +0 -0
  89. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server.egg-info/dependency_links.txt +0 -0
  90. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server.egg-info/entry_points.txt +0 -0
  91. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server.egg-info/not-zip-safe +0 -0
  92. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server.egg-info/requires.txt +0 -0
  93. {devpi-server-6.12.1 → devpi-server-6.13.0}/devpi_server.egg-info/top_level.txt +0 -0
  94. {devpi-server-6.12.1 → devpi-server-6.13.0}/pytest_devpi_server/__init__.py +0 -0
  95. {devpi-server-6.12.1 → devpi-server-6.13.0}/setup.cfg +0 -0
  96. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/__init__.py +0 -0
  97. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/conftest.py +0 -0
  98. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/example.py +0 -0
  99. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/badindexname/dataindex.json +0 -0
  100. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/badusername/dataindex.json +0 -0
  101. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/basescycle/dataindex.json +0 -0
  102. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/createdmodified/dataindex.json +0 -0
  103. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/deletedbase/dataindex.json +0 -0
  104. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/mirrordata/dataindex.json +0 -0
  105. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/mirrordata/root/pypi/dddttt/0.1.dev1/dddttt-0.1.dev1.tar.gz +0 -0
  106. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/modifiedpypi/dataindex.json +0 -0
  107. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/nocreatedmodified/dataindex.json +0 -0
  108. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/normalization/dataindex.json +0 -0
  109. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/normalization/root/dev/hello.pkg/hello.pkg-1.0.tar.gz +0 -0
  110. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/normalization_merge/dataindex.json +0 -0
  111. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/normalization_merge/root/dev/hello-pkg/hello.pkg-1.1.tar.gz +0 -0
  112. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/normalization_merge/root/dev/hello.pkg/hello.pkg-1.0.tar.gz +0 -0
  113. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/norootpypi/dataindex.json +0 -0
  114. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/nouser/dataindex.json +0 -0
  115. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/removedindexplugin/dataindex.json +0 -0
  116. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/removedindexplugin/user/dev/pkg/pkg-1.0.tar.gz +0 -0
  117. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/toxresult_naming_scheme/dataindex.json +0 -0
  118. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/toxresult_naming_scheme/root/dev/hello/0.9/hello-0.9.tar.gz +0 -0
  119. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/toxresult_naming_scheme/root/dev/hello/sha256=ed7002b439e9ac845f22357d822bac1444730fbdb6016d3ec9432297b9ec9f73/hello-0.9.tar.gz.toxresult0 +0 -0
  120. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/importexportdata/toxresult_upload_default/dataindex.json +0 -0
  121. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/reqmock.py +0 -0
  122. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/simpypi.py +0 -0
  123. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_auth.py +0 -0
  124. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_authcheck.py +0 -0
  125. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_fileutil.py +0 -0
  126. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_genconfig.py +0 -0
  127. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_log.py +0 -0
  128. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_mirror_no_project_list.py +0 -0
  129. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_nginx.py +0 -0
  130. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_readonly.py +0 -0
  131. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_reqmock.py +0 -0
  132. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_view_auth.py +0 -0
  133. {devpi-server-6.12.1 → devpi-server-6.13.0}/test_devpi_server/test_views_patch.py +0 -0
@@ -1,9 +1,9 @@
1
1
  [flake8]
2
2
  ignore = E501,E741,W503
3
3
  per-file-ignores =
4
- plugin.py:E127,E128,E225,E231,E265,E402,E712
4
+ plugin.py:E127,E128,E225,E231
5
5
  importexport.py:E127
6
6
  model.py:E128,E225,E231
7
7
  setup.py:E121,E126
8
8
  test_importexport.py:E121
9
- test*.py:E117,E126,E127,E128,E225,E226,E231,E251,E265,E712,E721
9
+ test*.py:E126,E127,E128,E225,E226,E231,E251
@@ -2,6 +2,41 @@
2
2
 
3
3
  .. towncrier release notes start
4
4
 
5
+ 6.13.0 (2024-09-19)
6
+ ===================
7
+
8
+ Deprecations and Removals
9
+ -------------------------
10
+
11
+ - Remove/Deprecate "master" related terminology in favor of "primary".
12
+ Usage related changes are the switch to ``--primary-url`` instead of ``--master-url`` and ``--role=primary`` instead of ``--role=master``.
13
+ Using the old terms will now output warnings.
14
+ The ``+status`` API has additional fields and the ``role`` field content will change with 7.0.0.
15
+
16
+
17
+
18
+ Features
19
+ --------
20
+
21
+ - Enable logging command line options for all commands.
22
+
23
+ - Added support uv pip as an installer.
24
+
25
+
26
+
27
+ Bug Fixes
28
+ ---------
29
+
30
+ - Don't report on lagging event processing while replicating.
31
+
32
+ - Report primary serial correctly with streaming replication.
33
+
34
+ - Don't store file data in memory when fetching a release while pushing from a mirror.
35
+
36
+ - Only warn about replica not being in sync instead of fatal status while still replicating.
37
+
38
+
39
+
5
40
  6.12.1 (2024-07-24)
6
41
  ===================
7
42
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: devpi-server
3
- Version: 6.12.1
3
+ Version: 6.13.0
4
4
  Summary: devpi-server: reliable private and pypi.org caching server
5
5
  Home-page: https://devpi.net
6
6
  Maintainer: Florian Schulze
@@ -9,6 +9,7 @@ License: MIT
9
9
  Project-URL: Bug Tracker, https://github.com/devpi/devpi/issues
10
10
  Project-URL: Changelog, https://github.com/devpi/devpi/blob/main/server/CHANGELOG
11
11
  Project-URL: Documentation, https://doc.devpi.net
12
+ Project-URL: Funding, https://github.com/sponsors/devpi
12
13
  Project-URL: Source Code, https://github.com/devpi/devpi
13
14
  Keywords: pypi realtime cache server
14
15
  Classifier: Development Status :: 5 - Production/Stable
@@ -104,6 +105,41 @@ Changelog
104
105
 
105
106
  .. towncrier release notes start
106
107
 
108
+ 6.13.0 (2024-09-19)
109
+ ===================
110
+
111
+ Deprecations and Removals
112
+ -------------------------
113
+
114
+ - Remove/Deprecate "master" related terminology in favor of "primary".
115
+ Usage related changes are the switch to ``--primary-url`` instead of ``--master-url`` and ``--role=primary`` instead of ``--role=master``.
116
+ Using the old terms will now output warnings.
117
+ The ``+status`` API has additional fields and the ``role`` field content will change with 7.0.0.
118
+
119
+
120
+
121
+ Features
122
+ --------
123
+
124
+ - Enable logging command line options for all commands.
125
+
126
+ - Added support uv pip as an installer.
127
+
128
+
129
+
130
+ Bug Fixes
131
+ ---------
132
+
133
+ - Don't report on lagging event processing while replicating.
134
+
135
+ - Report primary serial correctly with streaming replication.
136
+
137
+ - Don't store file data in memory when fetching a release while pushing from a mirror.
138
+
139
+ - Only warn about replica not being in sync instead of fatal status while still replicating.
140
+
141
+
142
+
107
143
  6.12.1 (2024-07-24)
108
144
  ===================
109
145
 
@@ -178,12 +214,3 @@ Bug Fixes
178
214
  - Only compare hostname instead of full URL prefix when parsing mirror packages to fix mirrors with basic authentication and absolute URLs. See #1006
179
215
 
180
216
 
181
-
182
- 6.9.2 (2023-08-06)
183
- ==================
184
-
185
- Bug Fixes
186
- ---------
187
-
188
- - Prevent duplicates when adding values to lists in index configuration with ``+=`` operator.
189
-
@@ -0,0 +1 @@
1
+ __version__ = '6.13.0'
@@ -6,6 +6,7 @@ import secrets
6
6
  import sys
7
7
  import uuid
8
8
  from operator import itemgetter
9
+ from pathlib import Path
9
10
  from tempfile import NamedTemporaryFile
10
11
  from pluggy import HookimplMarker, PluginManager
11
12
  import py
@@ -17,6 +18,8 @@ from . import hookspecs
17
18
  import json
18
19
  import devpi_server
19
20
  from devpi_common.url import URL
21
+ import warnings
22
+
20
23
 
21
24
  log = threadlog
22
25
 
@@ -70,17 +73,31 @@ def add_configfile_option(parser, pluginmanager):
70
73
  def add_role_option(parser, pluginmanager):
71
74
  parser.addoption(
72
75
  "--role", action="store", dest="role", default="auto",
73
- choices=["master", "replica", "standalone", "auto"],
76
+ choices=["master", "primary", "replica", "standalone", "auto"],
74
77
  help="set role of this instance. The default 'auto' sets "
75
- "'standalone' by default and 'replica' if the --master-url "
78
+ "'standalone' by default and 'replica' if the --primary-url "
76
79
  "option is used. To enable the replication protocol you have "
77
- "to explicitly set the 'master' role.")
80
+ "to explicitly set the 'primary' role. The 'master' role is "
81
+ "the deprecated variant of 'primary'.")
78
82
 
79
83
 
80
84
  def add_master_url_option(parser, pluginmanager):
85
+ warnings.warn(
86
+ "The add_master_url_option function is deprecated, "
87
+ "use add_primary_url_option instead",
88
+ DeprecationWarning,
89
+ stacklevel=2)
90
+ add_primary_url_option(parser, pluginmanager)
91
+
92
+
93
+ def add_primary_url_option(parser, pluginmanager): # noqa: ARG001
81
94
  parser.addoption(
82
- "--master-url", action="store", dest="master_url",
83
- help="run as a replica of the specified master server",
95
+ "--primary-url", action="store", dest="primary_url",
96
+ help="run as a replica of the specified primary server",
97
+ default=None)
98
+ parser.addoption(
99
+ "--master-url", action="store", dest="deprecated_master_url",
100
+ help="DEPRECATED, use --primary-url instead",
84
101
  default=None)
85
102
 
86
103
 
@@ -186,7 +203,7 @@ def add_mirror_options(parser, pluginmanager):
186
203
 
187
204
 
188
205
  def add_replica_options(parser, pluginmanager):
189
- add_master_url_option(parser, pluginmanager)
206
+ add_primary_url_option(parser, pluginmanager)
190
207
 
191
208
  parser.addoption(
192
209
  "--replica-max-retries", type=int, metavar="NUM",
@@ -197,7 +214,7 @@ def add_replica_options(parser, pluginmanager):
197
214
  parser.addoption(
198
215
  "--replica-file-search-path", metavar="PATH",
199
216
  help="path to existing files to try before downloading "
200
- "from master. These could be from a previous "
217
+ "from primary. These could be from a previous "
201
218
  "replication attempt or downloaded separately. "
202
219
  "Expects the structure from previous state or +files.")
203
220
 
@@ -214,13 +231,13 @@ def add_replica_options(parser, pluginmanager):
214
231
  parser.addoption(
215
232
  "--file-replication-threads", type=int, metavar="NUM",
216
233
  default=DEFAULT_FILE_REPLICATION_THREADS,
217
- help="number of threads for file download from master")
234
+ help="number of threads for file download from primary")
218
235
 
219
236
  parser.addoption(
220
237
  "--proxy-timeout", type=int, metavar="NUM",
221
238
  default=DEFAULT_PROXY_TIMEOUT,
222
239
  help="Number of seconds to wait before proxied requests from "
223
- "the replica to the master time out (login, uploads etc).")
240
+ "the replica to the primary time out (login, uploads etc).")
224
241
 
225
242
  parser.addoption(
226
243
  "--no-replica-streaming", dest="replica_streaming",
@@ -555,7 +572,7 @@ class MyArgumentParser(argparse.ArgumentParser):
555
572
  default = action.default
556
573
  if isinstance(action, argparse._StoreFalseAction):
557
574
  default = not default
558
- if action.help and action.help is not argparse.SUPPRESS and action.default is not argparse.SUPPRESS:
575
+ if action.help and argparse.SUPPRESS not in (action.help, default):
559
576
  action.help += " [%s]" % default
560
577
 
561
578
  def addgroup(self, *args, **kwargs):
@@ -584,8 +601,19 @@ class MyArgumentParser(argparse.ArgumentParser):
584
601
  def add_init_options(self):
585
602
  add_init_options(self, self.pluginmanager)
586
603
 
604
+ def add_logging_options(self) -> None:
605
+ add_logging_options(self, self.pluginmanager)
606
+
587
607
  def add_master_url_option(self):
588
- add_master_url_option(self, self.pluginmanager)
608
+ warnings.warn(
609
+ "The add_master_url_option method is deprecated, "
610
+ "use add_primary_url_option instead",
611
+ DeprecationWarning,
612
+ stacklevel=2)
613
+ add_primary_url_option(self, self.pluginmanager)
614
+
615
+ def add_primary_url_option(self):
616
+ add_primary_url_option(self, self.pluginmanager)
589
617
 
590
618
  def add_role_option(self):
591
619
  add_role_option(self, self.pluginmanager)
@@ -656,14 +684,32 @@ class Config(object):
656
684
 
657
685
  @cached_property
658
686
  def serverdir(self):
659
- return py.path.local(os.path.expanduser(self.args.serverdir))
687
+ warnings.warn(
688
+ "The serverdir property is deprecated, "
689
+ "use server_path instead",
690
+ DeprecationWarning,
691
+ stacklevel=3)
692
+ return py.path.local(self.server_path)
693
+
694
+ @cached_property
695
+ def server_path(self):
696
+ return Path(self.args.serverdir).expanduser()
660
697
 
661
698
  @cached_property
662
699
  def path_nodeinfo(self):
663
- return self.serverdir.join(".nodeinfo")
700
+ warnings.warn(
701
+ "The path_nodeinfo property is deprecated, "
702
+ "use nodeinfo_path instead",
703
+ DeprecationWarning,
704
+ stacklevel=3)
705
+ return py.path.local(self.nodeinfo_path)
706
+
707
+ @cached_property
708
+ def nodeinfo_path(self):
709
+ return self.server_path / ".nodeinfo"
664
710
 
665
711
  def init_nodeinfo(self):
666
- log.info("Loading node info from %s", self.path_nodeinfo)
712
+ log.info("Loading node info from %s", self.nodeinfo_path)
667
713
  self._determine_role()
668
714
  self._determine_uuid()
669
715
  self._determine_storage()
@@ -677,56 +723,111 @@ class Config(object):
677
723
 
678
724
  @property
679
725
  def role(self):
680
- return self.nodeinfo["role"]
726
+ role = self.nodeinfo["role"]
727
+ if role == "master":
728
+ warnings.warn(
729
+ "role==master is deprecated, use primary instead.",
730
+ DeprecationWarning,
731
+ stacklevel=2)
732
+ return "primary"
733
+ return role
681
734
 
682
735
  def set_uuid(self, uuid):
683
736
  # called when importing state
684
737
  self.nodeinfo["uuid"] = uuid
685
738
  self.write_nodeinfo()
686
739
 
687
- def set_master_uuid(self, uuid):
688
- assert self.role == "replica", "can only set master uuid on replica"
689
- existing = self.nodeinfo.get("master-uuid")
740
+ def set_primary_uuid(self, uuid):
741
+ assert self.role == "replica", "can only set primary uuid on replica"
742
+ existing = self.get_primary_uuid()
690
743
  if existing and existing != uuid:
691
- raise ValueError("already have master id %r, got %r" % (
744
+ raise ValueError("already have primary id %r, got %r" % (
692
745
  existing, uuid))
693
- self.nodeinfo["master-uuid"] = uuid
746
+ self.nodeinfo["primary-uuid"] = uuid
694
747
  self.write_nodeinfo()
695
748
 
696
749
  def get_master_uuid(self):
750
+ warnings.warn(
751
+ "get_master_uuid is deprecated, use get_primary_uuid instead",
752
+ DeprecationWarning,
753
+ stacklevel=2)
754
+ return self.get_primary_uuid()
755
+
756
+ def get_primary_uuid(self):
697
757
  if self.role != "replica":
698
758
  return self.nodeinfo["uuid"]
699
- return self.nodeinfo.get("master-uuid")
759
+ if "master-uuid" in self.nodeinfo:
760
+ warnings.warn(
761
+ "master-uuid in nodeinfo is deprecated, use primary-uuid instead",
762
+ DeprecationWarning,
763
+ stacklevel=2)
764
+ return self.nodeinfo["master-uuid"]
765
+ return self.nodeinfo.get("primary-uuid")
700
766
 
701
767
  @cached_property
702
768
  def nodeinfo(self):
703
- if self.path_nodeinfo.exists():
704
- return json.loads(self.path_nodeinfo.read("r"))
769
+ if self.nodeinfo_path.is_file():
770
+ with self.nodeinfo_path.open() as f:
771
+ return json.load(f)
705
772
  return {}
706
773
 
707
774
  def write_nodeinfo(self):
708
- nodeinfo_dir = self.path_nodeinfo.dirpath()
709
- nodeinfo_dir.ensure(dir=1)
710
- prefix = "-" + self.path_nodeinfo.basename
711
- with NamedTemporaryFile(prefix=prefix, delete=False, dir=nodeinfo_dir.strpath) as f:
775
+ nodeinfo_dir = self.nodeinfo_path.parent
776
+ nodeinfo_dir.mkdir(parents=True, exist_ok=True)
777
+ prefix = "-" + self.nodeinfo_path.name
778
+ with NamedTemporaryFile(prefix=prefix, delete=False, dir=nodeinfo_dir) as f:
712
779
  f.write(json.dumps(self.nodeinfo, indent=2).encode('utf-8'))
713
- fileutil.rename(f.name, self.path_nodeinfo.strpath)
714
- threadlog.info("wrote nodeinfo to: %s", self.path_nodeinfo)
780
+ fileutil.rename(f.name, self.nodeinfo_path)
781
+ threadlog.info("wrote nodeinfo to: %s", self.nodeinfo_path)
782
+
783
+ @property
784
+ def master_auth(self):
785
+ warnings.warn(
786
+ "master_auth is deprecated, use primary_auth instead",
787
+ DeprecationWarning,
788
+ stacklevel=2)
789
+ return self.primary_auth
715
790
 
716
791
  @property
717
792
  def master_url(self):
718
- if hasattr(self, '_master_url'):
719
- return self._master_url
720
- master_url = None
721
- if getattr(self.args, 'master_url', None):
722
- master_url = URL(self.args.master_url)
793
+ warnings.warn(
794
+ "master_url is deprecated, use primary_url instead",
795
+ DeprecationWarning,
796
+ stacklevel=2)
797
+ return self.primary_url
798
+
799
+ @property
800
+ def primary_auth(self):
801
+ # trigger setting of _primary_auth
802
+ return self._primary_auth if self.primary_url else None
803
+
804
+ @property
805
+ def primary_url(self):
806
+ if hasattr(self, '_primary_url'):
807
+ return self._primary_url
808
+ primary_url = None
809
+ if getattr(self.args, 'deprecated_master_url', None):
810
+ if getattr(self.args, 'primary_url', None):
811
+ from .main import fatal
812
+ fatal("Can't use both --master-url and --primary-url")
813
+ warnings.warn(
814
+ "The --master-url option is deprecated, "
815
+ "use --primary-url instead.",
816
+ DeprecationWarning,
817
+ stacklevel=2)
818
+ threadlog.warning(
819
+ "The --master-url option is deprecated, "
820
+ "use --primary-url instead.")
821
+ primary_url = URL(self.args.deprecated_master_url)
822
+ elif getattr(self.args, 'primary_url', None):
823
+ primary_url = URL(self.args.primary_url)
723
824
  elif self.nodeinfo.get("masterurl"):
724
- master_url = URL(self.nodeinfo["masterurl"])
725
- self.master_url = master_url
726
- return self.master_url
825
+ primary_url = URL(self.nodeinfo["masterurl"])
826
+ self.primary_url = primary_url
827
+ return self.primary_url
727
828
 
728
- @master_url.setter
729
- def master_url(self, value):
829
+ @primary_url.setter
830
+ def primary_url(self, value):
730
831
  auth = (None, None)
731
832
  if value is not None:
732
833
  auth = (value.username, value.password)
@@ -736,8 +837,8 @@ class Config(object):
736
837
  value = value.replace(netloc=netloc)
737
838
  if auth == (None, None):
738
839
  auth = None
739
- self.master_auth = auth
740
- self._master_url = value
840
+ self._primary_auth = auth
841
+ self._primary_url = value
741
842
 
742
843
  @property
743
844
  def include_mirrored_files(self):
@@ -813,25 +914,25 @@ class Config(object):
813
914
  return getattr(self.args, 'wait_for_events', False)
814
915
 
815
916
  def _init_role(self):
816
- if self.master_url:
917
+ if self.primary_url:
817
918
  self.nodeinfo["role"] = "replica"
818
919
  else:
819
920
  self.nodeinfo["role"] = "standalone"
820
921
 
821
922
  def _automatic_role(self, role):
822
923
  from .main import Fatal
823
- if role == "replica" and not self.master_url:
924
+ if role == "replica" and not self.primary_url:
824
925
  raise Fatal(
825
- "configuration error, masterurl isn't set in nodeinfo, but "
926
+ "configuration error, primary URL isn't set in nodeinfo, but "
826
927
  "role is set to replica")
827
- if role != "replica" and self.master_url:
928
+ if role != "replica" and self.primary_url:
828
929
  raise Fatal(
829
- "configuration error, masterurl set in nodeinfo, but role "
930
+ "configuration error, primary URL set in nodeinfo, but role "
830
931
  "isn't set to replica")
831
932
  if role != "replica":
832
- self.master_url = None
833
- if role == "master":
834
- # we only allow explicit master role
933
+ self.primary_url = None
934
+ if role in ("master", "primary"):
935
+ # we only allow explicit primary role
835
936
  self.nodeinfo["role"] = "standalone"
836
937
 
837
938
  def _change_role(self, old_role, new_role):
@@ -840,10 +941,10 @@ class Config(object):
840
941
  if old_role and old_role != "replica":
841
942
  msg = f"cannot run as replica, was previously run as {old_role}"
842
943
  raise Fatal(msg)
843
- if not self.master_url:
844
- raise Fatal("need to specify --master-url to run as replica")
944
+ if not self.primary_url:
945
+ raise Fatal("need to specify --primary-url to run as replica")
845
946
  else:
846
- self.master_url = None
947
+ self.primary_url = None
847
948
  self.nodeinfo["role"] = new_role
848
949
 
849
950
  def _determine_role(self):
@@ -857,9 +958,9 @@ class Config(object):
857
958
  self._change_role(old_role, role)
858
959
  assert self.nodeinfo["role"]
859
960
  if self.nodeinfo["role"] == "replica":
860
- assert self.master_url
861
- if self.master_url:
862
- self.nodeinfo["masterurl"] = self.master_url.url
961
+ assert self.primary_url
962
+ if self.primary_url:
963
+ self.nodeinfo["masterurl"] = self.primary_url.url
863
964
  else:
864
965
  self.nodeinfo.pop("masterurl", None)
865
966
 
@@ -901,36 +1002,45 @@ class Config(object):
901
1002
  def sqlite_file_needed_but_missing(self):
902
1003
  return (
903
1004
  self.storage_info['name'] == 'sqlite'
904
- and not self.serverdir.join(".sqlite").exists()
1005
+ and not self.server_path.joinpath(".sqlite").exists()
905
1006
  )
906
1007
 
907
1008
  @cached_property
908
1009
  def secretfile(self):
1010
+ warnings.warn(
1011
+ "The secretfile property is deprecated, "
1012
+ "use secret_path instead",
1013
+ DeprecationWarning,
1014
+ stacklevel=3)
1015
+ return py.path.local(self.secret_path)
1016
+
1017
+ @cached_property
1018
+ def secret_path(self):
909
1019
  if not self.args.secretfile:
910
- secretfile = self.serverdir.join('.secret')
911
- if not secretfile.check(file=True):
1020
+ secretfile = self.server_path / '.secret'
1021
+ if not secretfile.is_file():
912
1022
  return None
913
1023
  log.warning(
914
1024
  "Using deprecated existing secret file at '%s', use "
915
1025
  "--secretfile to explicitly provide the location." % secretfile)
916
1026
  return secretfile
917
- return py.path.local(
918
- os.path.expanduser(self.args.secretfile))
1027
+ return Path(self.args.secretfile).expanduser()
919
1028
 
920
1029
  def get_validated_secret(self):
921
1030
  from .main import Fatal
922
1031
  import stat
923
- if not self.secretfile.check(file=True):
1032
+ secret_path = self.secret_path
1033
+ if not secret_path.is_file():
924
1034
  raise Fatal("The given secret file doesn't exist.")
925
- if self.secretfile.stat().mode & stat.S_IRWXO and sys.platform != "win32":
1035
+ if secret_path.stat().st_mode & stat.S_IRWXO and sys.platform != "win32":
926
1036
  raise Fatal("The given secret file is world accessible, the access mode must be user accessible only (0600).")
927
- if self.secretfile.stat().mode & stat.S_IRWXG and sys.platform != "win32":
1037
+ if secret_path.stat().st_mode & stat.S_IRWXG and sys.platform != "win32":
928
1038
  raise Fatal("The given secret file is group accessible, the access mode must be user accessible only (0600).")
929
- if self.secretfile.dirpath().stat().mode & stat.S_IWGRP and sys.platform != "win32":
1039
+ if secret_path.parent.stat().st_mode & stat.S_IWGRP and sys.platform != "win32":
930
1040
  raise Fatal("The folder of the given secret file is group writable, it must only be writable by the user.")
931
- if self.secretfile.dirpath().stat().mode & stat.S_IWOTH and sys.platform != "win32":
1041
+ if secret_path.parent.stat().st_mode & stat.S_IWOTH and sys.platform != "win32":
932
1042
  raise Fatal("The folder of the given secret file is world writable, it must only be writable by the user.")
933
- secret = self.secretfile.read_binary()
1043
+ secret = secret_path.read_bytes()
934
1044
  if len(secret) < 32:
935
1045
  raise Fatal(
936
1046
  "The secret in the given secret file is too short, "
@@ -943,7 +1053,7 @@ class Config(object):
943
1053
 
944
1054
  @cached_property
945
1055
  def basesecret(self):
946
- if self.secretfile is None:
1056
+ if self.secret_path is None:
947
1057
  log.warning(
948
1058
  "No secret file provided, creating a new random secret. "
949
1059
  "Login tokens issued before are invalid. "
@@ -952,7 +1062,7 @@ class Config(object):
952
1062
  "devpi-gen-secret command.")
953
1063
  return new_secret()
954
1064
  secret = self.get_validated_secret()
955
- log.info("Using secret file '%s'.", self.secretfile)
1065
+ log.info("Using secret file '%s'.", self.secret_path)
956
1066
  return secret
957
1067
 
958
1068
  @property
@@ -994,7 +1104,6 @@ def getpath(path):
994
1104
 
995
1105
 
996
1106
  def gensecret():
997
- from .log import configure_cli_logging
998
1107
  from .log import threadlog as log
999
1108
  from .main import CommandRunner
1000
1109
  from .main import Fatal
@@ -1005,22 +1114,22 @@ def gensecret():
1005
1114
  add_help=False)
1006
1115
  parser.add_help_option()
1007
1116
  parser.add_configfile_option()
1117
+ parser.add_logging_options()
1008
1118
  parser.add_secretfile_option()
1009
1119
  config = runner.get_config(sys.argv, parser=parser)
1010
- configure_cli_logging(config.args)
1120
+ runner.configure_logging(config.args)
1011
1121
  if config.args.secretfile is None:
1012
1122
  raise Fatal("You need to provide a location for the secret file.")
1013
- if not config.secretfile.exists():
1014
- with config.secretfile.open("wb") as f:
1015
- f.write(new_secret())
1016
- log.info("New secret written to '%s'" % config.secretfile)
1123
+ if not config.secret_path.exists():
1124
+ config.secret_path.write_bytes(new_secret())
1125
+ log.info("New secret written to '%s'" % config.secret_path)
1017
1126
  if sys.platform != "win32":
1018
- mode = config.secretfile.stat().mode
1127
+ mode = config.secret_path.stat().st_mode
1019
1128
  if mode & stat.S_IRWXG or mode & stat.S_IRWXO:
1020
- config.secretfile.chmod(0o600)
1129
+ config.secret_path.chmod(0o600)
1021
1130
  log.info("Changed file mode to 0600 to adjust access permissions.")
1022
1131
  else:
1023
- log.info("Checking existing secret at '%s'" % config.secretfile)
1132
+ log.info("Checking existing secret at '%s'" % config.secret_path)
1024
1133
  # run checks
1025
1134
  config.get_validated_secret()
1026
1135
  log.info("Permissions of secret file look good.")