hatch-cpp 0.3.6__tar.gz → 0.4.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 (67) hide show
  1. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/.gitignore +24 -28
  2. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/PKG-INFO +2 -2
  3. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/__init__.py +1 -1
  4. {hatch_cpp-0.3.6/hatch_cpp/tests/test_project_cmake_vcpkg → hatch_cpp-0.4.0/hatch_cpp/tests/test_project_cmake}/CMakeLists.txt +2 -10
  5. {hatch_cpp-0.3.6/hatch_cpp/tests/test_project_cmake → hatch_cpp-0.4.0/hatch_cpp/tests/test_project_cmake_vcpkg}/CMakeLists.txt +2 -10
  6. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_projects.py +17 -8
  7. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_vcpkg_ref.py +54 -2
  8. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/toolchains/common.py +3 -0
  9. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/toolchains/vcpkg.py +51 -7
  10. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/pyproject.toml +6 -3
  11. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/LICENSE +0 -0
  12. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/README.md +0 -0
  13. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/config.py +0 -0
  14. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/hooks.py +0 -0
  15. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/plugin.py +0 -0
  16. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_hatch_build.py +0 -0
  17. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_platform_specific.py +0 -0
  18. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_basic/cpp/project/basic.cpp +0 -0
  19. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_basic/cpp/project/basic.hpp +0 -0
  20. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_basic/project/__init__.py +0 -0
  21. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_basic/pyproject.toml +0 -0
  22. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake/Makefile +0 -0
  23. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake/cpp/project/basic.cpp +0 -0
  24. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake/cpp/project/basic.hpp +0 -0
  25. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake/project/__init__.py +0 -0
  26. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake/project/include/project/basic.hpp +0 -0
  27. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake/pyproject.toml +0 -0
  28. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake_vcpkg/Makefile +0 -0
  29. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake_vcpkg/cpp/project/basic.cpp +0 -0
  30. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake_vcpkg/cpp/project/basic.hpp +0 -0
  31. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake_vcpkg/project/__init__.py +0 -0
  32. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake_vcpkg/project/include/project/basic.hpp +0 -0
  33. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake_vcpkg/pyproject.toml +0 -0
  34. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_cmake_vcpkg/vcpkg.json +0 -0
  35. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_hatch_build/cpp/project/basic.cpp +0 -0
  36. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_hatch_build/cpp/project/basic.hpp +0 -0
  37. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_hatch_build/project/__init__.py +0 -0
  38. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_hatch_build/pyproject.toml +0 -0
  39. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_limited_api/cpp/project/basic.cpp +0 -0
  40. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_limited_api/cpp/project/basic.hpp +0 -0
  41. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_limited_api/project/__init__.py +0 -0
  42. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_limited_api/pyproject.toml +0 -0
  43. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_nanobind/cpp/project/basic.cpp +0 -0
  44. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_nanobind/cpp/project/basic.hpp +0 -0
  45. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_nanobind/project/__init__.py +0 -0
  46. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_nanobind/pyproject.toml +0 -0
  47. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_override_classes/cpp/project/basic.cpp +0 -0
  48. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_override_classes/cpp/project/basic.hpp +0 -0
  49. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_override_classes/project/__init__.py +0 -0
  50. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_override_classes/pyproject.toml +0 -0
  51. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_override_toolchain/cpp/project/basic.cpp +0 -0
  52. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_override_toolchain/cpp/project/basic.hpp +0 -0
  53. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_override_toolchain/project/__init__.py +0 -0
  54. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_override_toolchain/pyproject.toml +0 -0
  55. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind/cpp/project/basic.cpp +0 -0
  56. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind/cpp/project/basic.hpp +0 -0
  57. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind/project/__init__.py +0 -0
  58. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind/pyproject.toml +0 -0
  59. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind_vcpkg/cpp/project/basic.cpp +0 -0
  60. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind_vcpkg/cpp/project/basic.hpp +0 -0
  61. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind_vcpkg/project/__init__.py +0 -0
  62. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind_vcpkg/pyproject.toml +0 -0
  63. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_project_pybind_vcpkg/vcpkg.json +0 -0
  64. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/tests/test_structs.py +0 -0
  65. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/toolchains/__init__.py +0 -0
  66. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/toolchains/cmake.py +0 -0
  67. {hatch_cpp-0.3.6 → hatch_cpp-0.4.0}/hatch_cpp/utils.py +0 -0
@@ -5,12 +5,18 @@ __pycache__/
5
5
 
6
6
  # C extensions
7
7
  *.a
8
+ *.o
9
+ *.dSYM
8
10
  *.so
9
11
  *.obj
10
12
  *.dll
11
13
  *.exp
12
14
  *.lib
13
15
 
16
+ # Rust
17
+ target
18
+ target-capi
19
+
14
20
  # Distribution / packaging
15
21
  .Python
16
22
  build/
@@ -55,26 +61,12 @@ junit.xml
55
61
  .hypothesis/
56
62
  .pytest_cache/
57
63
 
58
- # Translations
59
- *.mo
60
- *.pot
61
-
62
- # Django stuff:
64
+ # Django
63
65
  *.log
64
66
  local_settings.py
65
67
  db.sqlite3
66
68
  db.sqlite3-journal
67
69
 
68
- # Flask stuff:
69
- instance/
70
- .webassets-cache
71
-
72
- # Scrapy stuff:
73
- .scrapy
74
-
75
- # PyBuilder
76
- target/
77
-
78
70
  # IPython
79
71
  profile_default/
80
72
  ipython_config.py
@@ -85,15 +77,12 @@ ipython_config.py
85
77
  # pipenv
86
78
  Pipfile.lock
87
79
 
88
- # PEP 582; used by e.g. github.com/David-OConnor/pyflow
89
- __pypackages__/
90
-
91
- # Celery stuff
80
+ # Celery
92
81
  celerybeat-schedule
93
82
  celerybeat.pid
94
83
 
95
- # SageMath parsed files
96
- *.sage.py
84
+ # Airspeed Velocity
85
+ .asv
97
86
 
98
87
  # Environments
99
88
  .env
@@ -126,11 +115,12 @@ dmypy.json
126
115
  /site
127
116
  index.md
128
117
  docs/_build/
129
- docs/src/_build/
130
118
  docs/api
131
- docs/index.md
132
119
  docs/html
120
+ docs/index.md
133
121
  docs/jupyter_execute
122
+ docs/src/_build/
123
+ docs/superpowers
134
124
  index.md
135
125
 
136
126
  # JS
@@ -150,15 +140,21 @@ hatch_cpp/extension
150
140
  hatch_cpp/nbextension
151
141
  hatch_cpp/labextension
152
142
 
143
+ # Emscripten SDK (locally installed)
144
+ emsdk
145
+
153
146
  # Mac
154
147
  .DS_Store
155
148
 
156
- # Rust
157
- target
158
-
159
149
  # Hydra
160
- outputs/
161
- multirun/
150
+ /outputs/
151
+ /multirun/
152
+
153
+ # AI
154
+ ROADMAP.md
155
+ AGENTS.md
156
+ .github/hooks/sdlc.json
157
+ .superpowers
162
158
 
163
159
  vcpkg
164
160
  vcpkg_installed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hatch-cpp
3
- Version: 0.3.6
3
+ Version: 0.4.0
4
4
  Summary: Hatch plugin for C++ builds
5
5
  Project-URL: Repository, https://github.com/python-project-templates/hatch-cpp
6
6
  Project-URL: Homepage, https://github.com/python-project-templates/hatch-cpp
@@ -33,7 +33,7 @@ Requires-Dist: hatch-build>=0.3.2; extra == 'develop'
33
33
  Requires-Dist: hatchling; extra == 'develop'
34
34
  Requires-Dist: mdformat; extra == 'develop'
35
35
  Requires-Dist: mdformat-tables>=1; extra == 'develop'
36
- Requires-Dist: nanobind<2.13.0; extra == 'develop'
36
+ Requires-Dist: nanobind; extra == 'develop'
37
37
  Requires-Dist: pybind11; extra == 'develop'
38
38
  Requires-Dist: pytest; extra == 'develop'
39
39
  Requires-Dist: pytest-cov; extra == 'develop'
@@ -1,4 +1,4 @@
1
- __version__ = "0.3.6"
1
+ __version__ = "0.4.0"
2
2
 
3
3
  from .config import *
4
4
  from .hooks import *
@@ -71,19 +71,11 @@ endif()
71
71
 
72
72
 
73
73
  find_package(Python ${CSP_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module)
74
- link_directories(${Python_LIBRARY_DIRS})
75
- include_directories(${Python_INCLUDE_DIRS})
76
-
77
- set(CMAKE_SHARED_LIBRARY_PREFIX "")
78
- if(NOT WIN32)
79
- set(CMAKE_SHARED_LIBRARY_SUFFIX .so)
80
- else()
81
- set(CMAKE_SHARED_LIBRARY_SUFFIX .pyd)
82
- endif()
83
74
 
84
75
  include_directories("${CMAKE_SOURCE_DIR}/cpp")
85
76
 
86
- add_library(extension SHARED cpp/project/basic.cpp)
77
+ python_add_library(extension MODULE WITH_SOABI cpp/project/basic.cpp)
78
+
87
79
  set_target_properties(extension PROPERTIES PUBLIC_HEADER cpp/project/basic.hpp)
88
80
  install(TARGETS extension
89
81
  PUBLIC_HEADER DESTINATION project/include/project
@@ -71,19 +71,11 @@ endif()
71
71
 
72
72
 
73
73
  find_package(Python ${CSP_PYTHON_VERSION} EXACT REQUIRED COMPONENTS Interpreter Development.Module)
74
- link_directories(${Python_LIBRARY_DIRS})
75
- include_directories(${Python_INCLUDE_DIRS})
76
-
77
- set(CMAKE_SHARED_LIBRARY_PREFIX "")
78
- if(NOT WIN32)
79
- set(CMAKE_SHARED_LIBRARY_SUFFIX .so)
80
- else()
81
- set(CMAKE_SHARED_LIBRARY_SUFFIX .pyd)
82
- endif()
83
74
 
84
75
  include_directories("${CMAKE_SOURCE_DIR}/cpp")
85
76
 
86
- add_library(extension SHARED cpp/project/basic.cpp)
77
+ python_add_library(extension MODULE WITH_SOABI cpp/project/basic.cpp)
78
+
87
79
  set_target_properties(extension PROPERTIES PUBLIC_HEADER cpp/project/basic.hpp)
88
80
  install(TARGETS extension
89
81
  PUBLIC_HEADER DESTINATION project/include/project
@@ -1,8 +1,9 @@
1
- from os import listdir
1
+ import contextlib
2
+ from os import listdir, remove
2
3
  from pathlib import Path
3
- from shutil import rmtree
4
4
  from subprocess import check_call
5
5
  from sys import modules, path, platform
6
+ from sysconfig import get_config_var
6
7
 
7
8
  import pytest
8
9
 
@@ -24,9 +25,17 @@ class TestProject:
24
25
  ],
25
26
  )
26
27
  def test_basic(self, project):
28
+
29
+ suffix_ext = get_config_var("EXT_SUFFIX")
30
+
27
31
  # cleanup
28
- rmtree(f"hatch_cpp/tests/{project}/project/extension.so", ignore_errors=True)
29
- rmtree(f"hatch_cpp/tests/{project}/project/extension.pyd", ignore_errors=True)
32
+ with contextlib.suppress(FileNotFoundError):
33
+ remove(f"hatch_cpp/tests/{project}/project/extension.so")
34
+ with contextlib.suppress(FileNotFoundError):
35
+ remove(f"hatch_cpp/tests/{project}/project/extension.pyd")
36
+ with contextlib.suppress(FileNotFoundError):
37
+ remove(f"hatch_cpp/tests/{project}/project/extension{suffix_ext}")
38
+
30
39
  modules.pop("project", None)
31
40
  modules.pop("project.extension", None)
32
41
 
@@ -40,14 +49,14 @@ class TestProject:
40
49
  )
41
50
 
42
51
  # assert built
43
-
52
+ project_dir_content = listdir(f"hatch_cpp/tests/{project}/project")
44
53
  if project == "test_project_limited_api" and platform != "win32":
45
- assert "extension.abi3.so" in listdir(f"hatch_cpp/tests/{project}/project")
54
+ assert "extension.abi3.so" in project_dir_content
46
55
  else:
47
56
  if platform == "win32":
48
- assert "extension.pyd" in listdir(f"hatch_cpp/tests/{project}/project")
57
+ assert "extension.pyd" in project_dir_content or f"extension{suffix_ext}" in project_dir_content
49
58
  else:
50
- assert "extension.so" in listdir(f"hatch_cpp/tests/{project}/project")
59
+ assert "extension.so" in project_dir_content or f"extension{suffix_ext}" in project_dir_content
51
60
 
52
61
  # import
53
62
  here = Path(__file__).parent / project
@@ -156,14 +156,66 @@ class TestVcpkgGenerate:
156
156
  def test_generate_skips_clone_when_vcpkg_root_exists(self, tmp_path, monkeypatch):
157
157
  monkeypatch.chdir(tmp_path)
158
158
  self._make_vcpkg_env(tmp_path)
159
- (tmp_path / "vcpkg").mkdir()
159
+ vcpkg_root = tmp_path / "vcpkg"
160
+ vcpkg_root.mkdir()
161
+ # Existing bootstrap script and executable mean no clone/bootstrap is needed.
162
+ (vcpkg_root / "bootstrap-vcpkg.sh").write_text("#!/bin/sh\nexit 0\n")
163
+ (vcpkg_root / "vcpkg").write_text("#!/bin/sh\nexit 0\n")
160
164
 
161
165
  cfg = HatchCppVcpkgConfiguration(vcpkg_ref="2024.01.12")
166
+ monkeypatch.setattr(cfg, "_is_vcpkg_working", lambda: True)
162
167
  commands = cfg.generate(None)
163
168
 
164
- # When vcpkg_root already exists, no clone or checkout happens
169
+ # When vcpkg_root already exists with a working executable, no clone or bootstrap happens.
165
170
  assert not any("git clone" in cmd for cmd in commands)
166
171
  assert not any("checkout" in cmd for cmd in commands)
172
+ assert not any("bootstrap-vcpkg" in cmd for cmd in commands)
173
+ assert any("vcpkg" in cmd and "install" in cmd for cmd in commands)
174
+
175
+ def test_generate_reclones_when_vcpkg_root_exists_but_empty(self, tmp_path, monkeypatch):
176
+ monkeypatch.chdir(tmp_path)
177
+ self._make_vcpkg_env(tmp_path)
178
+ (tmp_path / "vcpkg").mkdir()
179
+
180
+ cfg = HatchCppVcpkgConfiguration(vcpkg_ref="2024.01.12")
181
+ commands = cfg.generate(None)
182
+
183
+ assert any(cmd.startswith('rm -rf "vcpkg"') for cmd in commands)
184
+ assert any("git clone" in cmd for cmd in commands)
185
+ assert any("checkout 2024.01.12" in cmd for cmd in commands)
186
+ assert any("bootstrap-vcpkg" in cmd for cmd in commands)
187
+ assert any("vcpkg" in cmd and "install" in cmd for cmd in commands)
188
+
189
+ def test_generate_bootstraps_when_vcpkg_executable_missing(self, tmp_path, monkeypatch):
190
+ monkeypatch.chdir(tmp_path)
191
+ self._make_vcpkg_env(tmp_path)
192
+ vcpkg_root = tmp_path / "vcpkg"
193
+ vcpkg_root.mkdir()
194
+ (vcpkg_root / "bootstrap-vcpkg.sh").write_text("#!/bin/sh\nexit 0\n")
195
+
196
+ cfg = HatchCppVcpkgConfiguration(vcpkg_ref="2024.01.12")
197
+ commands = cfg.generate(None)
198
+
199
+ assert not any("git clone" in cmd for cmd in commands)
200
+ assert any("bootstrap-vcpkg" in cmd for cmd in commands)
201
+ assert any("vcpkg" in cmd and "install" in cmd for cmd in commands)
202
+
203
+ def test_generate_reclones_when_vcpkg_exists_but_not_working(self, tmp_path, monkeypatch):
204
+ monkeypatch.chdir(tmp_path)
205
+ self._make_vcpkg_env(tmp_path)
206
+ vcpkg_root = tmp_path / "vcpkg"
207
+ vcpkg_root.mkdir()
208
+ (vcpkg_root / "bootstrap-vcpkg.sh").write_text("#!/bin/sh\nexit 0\n")
209
+ (vcpkg_root / "vcpkg").write_text("#!/bin/sh\nexit 1\n")
210
+
211
+ cfg = HatchCppVcpkgConfiguration(vcpkg_ref="2024.01.12")
212
+ monkeypatch.setattr(cfg, "_is_vcpkg_working", lambda: False)
213
+ commands = cfg.generate(None)
214
+
215
+ assert any(cmd.startswith('rm -rf "vcpkg"') for cmd in commands)
216
+ assert any("git clone" in cmd for cmd in commands)
217
+ assert any("checkout 2024.01.12" in cmd for cmd in commands)
218
+ assert any("bootstrap-vcpkg" in cmd for cmd in commands)
167
219
  assert any("vcpkg" in cmd and "install" in cmd for cmd in commands)
168
220
 
169
221
  def test_generate_no_vcpkg_json(self, tmp_path, monkeypatch):
@@ -101,6 +101,9 @@ class HatchCppLibrary(BaseModel, validate_assignment=True):
101
101
  return value
102
102
 
103
103
  def get_qualified_name(self, platform):
104
+ if self.binding == "cpython" and not self.py_limited_api:
105
+ suffix = get_config_var("EXT_SUFFIX")
106
+ return f"{self.name}{suffix}"
104
107
  if platform == "win32":
105
108
  suffix = "dll" if self.binding == "generic" else "pyd"
106
109
  elif platform == "darwin":
@@ -1,6 +1,7 @@
1
1
  from __future__ import annotations
2
2
 
3
3
  import configparser
4
+ import subprocess
4
5
  from pathlib import Path
5
6
  from platform import machine as platform_machine
6
7
  from sys import platform as sys_platform
@@ -78,6 +79,39 @@ class HatchCppVcpkgConfiguration(BaseModel):
78
79
  return self.vcpkg_ref
79
80
  return _read_vcpkg_ref_from_gitmodules(self.vcpkg_root)
80
81
 
82
+ def _bootstrap_script_path(self) -> Path:
83
+ return self.vcpkg_root / ("bootstrap-vcpkg.bat" if sys_platform == "win32" else "bootstrap-vcpkg.sh")
84
+
85
+ def _vcpkg_executable_path(self) -> Path:
86
+ if sys_platform == "win32":
87
+ return self.vcpkg_root / "vcpkg.exe"
88
+ return self.vcpkg_root / "vcpkg"
89
+
90
+ def _delete_dir_command(self, path: Path) -> str:
91
+ if sys_platform == "win32":
92
+ return f'rmdir /s /q "{path}"'
93
+ return f'rm -rf "{path}"'
94
+
95
+ def _is_vcpkg_working(self) -> bool:
96
+ vcpkg_executable = self._vcpkg_executable_path()
97
+ if not vcpkg_executable.exists():
98
+ return False
99
+ try:
100
+ result = subprocess.run([str(vcpkg_executable), "version"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, check=False)
101
+ return result.returncode == 0
102
+ except OSError:
103
+ return False
104
+
105
+ def _clone_checkout_bootstrap_commands(self) -> list[str]:
106
+ commands = [f"git clone {self.vcpkg_repo} {self.vcpkg_root}"]
107
+
108
+ ref = self._resolve_vcpkg_ref()
109
+ if ref is not None:
110
+ commands.append(f"git -C {self.vcpkg_root} checkout {ref}")
111
+
112
+ commands.append(f"./{self._bootstrap_script_path()}")
113
+ return commands
114
+
81
115
  def generate(self, config):
82
116
  commands = []
83
117
 
@@ -87,14 +121,24 @@ class HatchCppVcpkgConfiguration(BaseModel):
87
121
  raise ValueError(f"Could not determine vcpkg triplet for platform {sys_platform} and architecture {platform_machine()}")
88
122
 
89
123
  if self.vcpkg and Path(self.vcpkg).exists():
90
- if not Path(self.vcpkg_root).exists():
91
- commands.append(f"git clone {self.vcpkg_repo} {self.vcpkg_root}")
92
-
93
- ref = self._resolve_vcpkg_ref()
94
- if ref is not None:
95
- commands.append(f"git -C {self.vcpkg_root} checkout {ref}")
124
+ vcpkg_root = Path(self.vcpkg_root)
125
+ bootstrap_script = self._bootstrap_script_path()
126
+
127
+ if not vcpkg_root.exists():
128
+ commands.extend(self._clone_checkout_bootstrap_commands())
129
+ else:
130
+ is_empty_dir = vcpkg_root.is_dir() and not any(vcpkg_root.iterdir())
131
+ if is_empty_dir:
132
+ commands.append(self._delete_dir_command(vcpkg_root))
133
+ commands.extend(self._clone_checkout_bootstrap_commands())
134
+ else:
135
+ vcpkg_executable = self._vcpkg_executable_path()
136
+ if not vcpkg_executable.exists():
137
+ commands.append(f"./{bootstrap_script}")
138
+ elif not self._is_vcpkg_working():
139
+ commands.append(self._delete_dir_command(vcpkg_root))
140
+ commands.extend(self._clone_checkout_bootstrap_commands())
96
141
 
97
- commands.append(f"./{self.vcpkg_root / 'bootstrap-vcpkg.sh' if sys_platform != 'win32' else self.vcpkg_root / 'bootstrap-vcpkg.bat'}")
98
142
  commands.append(f"./{self.vcpkg_root / 'vcpkg'} install --triplet {self.vcpkg_triplet}")
99
143
 
100
144
  return commands
@@ -12,7 +12,7 @@ authors = [
12
12
  description = "Hatch plugin for C++ builds"
13
13
  readme = "README.md"
14
14
  license = { text = "Apache-2.0" }
15
- version = "0.3.6"
15
+ version = "0.4.0"
16
16
  requires-python = ">=3.10"
17
17
  keywords = [
18
18
  "hatch",
@@ -62,7 +62,7 @@ develop = [
62
62
  "uv",
63
63
  "wheel",
64
64
  # test
65
- "nanobind<2.13.0", # https://github.com/wjakob/nanobind/commit/abd27e3b5565bc95f5091321f0f863fce8b5b95b
65
+ "nanobind",
66
66
  "pybind11",
67
67
  "pytest",
68
68
  "pytest-cov",
@@ -80,7 +80,7 @@ Repository = "https://github.com/python-project-templates/hatch-cpp"
80
80
  Homepage = "https://github.com/python-project-templates/hatch-cpp"
81
81
 
82
82
  [tool.bumpversion]
83
- current_version = "0.3.6"
83
+ current_version = "0.4.0"
84
84
  commit = true
85
85
  tag = true
86
86
  commit_args = "-s"
@@ -100,6 +100,8 @@ branch = false
100
100
  omit = [
101
101
  "hatch_cpp/tests/integration/",
102
102
  ]
103
+ patch = ["subprocess"]
104
+
103
105
 
104
106
  [tool.coverage.report]
105
107
  exclude_also = [
@@ -132,6 +134,7 @@ addopts = [
132
134
  "--junitxml=junit.xml",
133
135
  ]
134
136
  testpaths = "hatch_cpp/tests"
137
+ norecursedirs = "vcpkg"
135
138
 
136
139
  [tool.ruff]
137
140
  line-length = 150
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes