duvc-ctl 1.0.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.
@@ -0,0 +1,75 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ push:
5
+ tags: [ 'v*' ] # Trigger on version tags
6
+ workflow_dispatch: # Manual override trigger
7
+ inputs:
8
+ run_id:
9
+ description: 'Run ID from TestPyPI workflow (optional - will use latest successful run if empty)'
10
+ required: false
11
+ type: string
12
+
13
+ jobs:
14
+ upload_pypi:
15
+ name: Upload to PyPI
16
+ runs-on: ubuntu-latest
17
+ # Only run for stable releases (no hyphens) OR manual dispatch
18
+ if: |
19
+ (github.event_name == 'push' &&
20
+ startsWith(github.ref, 'refs/tags/v') &&
21
+ !contains(github.ref, '-')) ||
22
+ github.event_name == 'workflow_dispatch'
23
+ environment:
24
+ name: pypi
25
+ url: https://pypi.org/p/duvc-ctl
26
+ permissions:
27
+ id-token: write
28
+ actions: read # Needed to download artifacts from other workflows
29
+
30
+ steps:
31
+ - name: Get latest successful TestPyPI run
32
+ if: ${{ !inputs.run_id }}
33
+ id: get-run
34
+ run: |
35
+ RUN_ID=$(gh api repos/${{ github.repository }}/actions/workflows/build-wheels.yml/runs \
36
+ --jq '.workflow_runs[] | select(.conclusion == "success") | .id' | head -n1)
37
+ echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT
38
+ env:
39
+ GH_TOKEN: ${{ github.token }}
40
+
41
+ - name: Set run ID
42
+ id: run-id
43
+ run: |
44
+ if [ -n "${{ inputs.run_id }}" ]; then
45
+ echo "run_id=${{ inputs.run_id }}" >> $GITHUB_OUTPUT
46
+ else
47
+ echo "run_id=${{ steps.get-run.outputs.run_id }}" >> $GITHUB_OUTPUT
48
+ fi
49
+
50
+ - name: Download wheels from TestPyPI workflow
51
+ uses: actions/download-artifact@v4
52
+ with:
53
+ pattern: wheels-*
54
+ path: dist
55
+ merge-multiple: true
56
+ run-id: ${{ steps.run-id.outputs.run_id }}
57
+ github-token: ${{ github.token }}
58
+
59
+ - name: Download sdist from TestPyPI workflow
60
+ uses: actions/download-artifact@v4
61
+ with:
62
+ name: sdist
63
+ path: dist
64
+ run-id: ${{ steps.run-id.outputs.run_id }}
65
+ github-token: ${{ github.token }}
66
+
67
+ - name: List artifacts to upload
68
+ run: |
69
+ ls -la dist/
70
+ echo "Uploading $(ls dist/ | wc -l) files to PyPI"
71
+
72
+ - name: Publish to PyPI
73
+ uses: pypa/gh-action-pypi-publish@release/v1
74
+ with:
75
+ print-hash: true
@@ -0,0 +1,172 @@
1
+ name: Build and publish to Test_PyPi
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ tags: [ 'v*' ]
7
+ pull_request:
8
+ branches: [ main ]
9
+ workflow_dispatch:
10
+
11
+ jobs:
12
+ build_wheels:
13
+ name: Build wheels for Python ${{ matrix.python-version }}
14
+ runs-on: windows-2022
15
+ strategy:
16
+ fail-fast: false
17
+ matrix:
18
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
19
+
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ with:
23
+ fetch-depth: 0
24
+
25
+ - name: Set up Python ${{ matrix.python-version }}
26
+ uses: actions/setup-python@v4
27
+ with:
28
+ python-version: ${{ matrix.python-version }}
29
+
30
+ - name: Set Python version for cibuildwheel
31
+ shell: bash
32
+ run: |
33
+ PYTHON_VERSION="${{ matrix.python-version }}"
34
+ CIBW_PYTHON="cp${PYTHON_VERSION//./}"
35
+ echo "CIBW_PYTHON=${CIBW_PYTHON}" >> $GITHUB_ENV
36
+
37
+ - name: Build wheels
38
+ uses: pypa/cibuildwheel@v2.16.5
39
+ env:
40
+ CIBW_BUILD: "${{ env.CIBW_PYTHON }}-win_amd64"
41
+ CIBW_ARCHS_WINDOWS: "AMD64"
42
+ CIBW_TEST_COMMAND: >
43
+ python -c "import duvc_ctl;
44
+ print(f'SUCCESS: duvc_ctl {duvc_ctl.__version__} imported');
45
+ devices = duvc_ctl.list_devices();
46
+ print(f'Found {len(devices)} devices')"
47
+ CIBW_BUILD_VERBOSITY: 1
48
+
49
+ - name: Upload wheels
50
+ uses: actions/upload-artifact@v4
51
+ with:
52
+ name: wheels-py${{ matrix.python-version }}
53
+ path: ./wheelhouse/*.whl
54
+ retention-days: 30
55
+
56
+ build_sdist:
57
+ name: Build source distribution
58
+ runs-on: windows-2022
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+ with:
62
+ fetch-depth: 0
63
+
64
+ - name: Set up Python
65
+ uses: actions/setup-python@v4
66
+ with:
67
+ python-version: "3.11"
68
+
69
+ - name: Install build dependencies
70
+ run: |
71
+ python -m pip install --upgrade pip
72
+ python -m pip install build
73
+
74
+ - name: Build sdist
75
+ run: python -m build --sdist
76
+
77
+ - name: Upload sdist
78
+ uses: actions/upload-artifact@v4
79
+ with:
80
+ name: sdist
81
+ path: dist/*.tar.gz
82
+ retention-days: 30
83
+
84
+ test_install:
85
+ name: Test installation
86
+ needs: [build_wheels]
87
+ runs-on: windows-2022
88
+ strategy:
89
+ matrix:
90
+ python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
91
+
92
+ steps:
93
+ - name: Set up Python ${{ matrix.python-version }}
94
+ uses: actions/setup-python@v4
95
+ with:
96
+ python-version: ${{ matrix.python-version }}
97
+
98
+ - name: Download wheels
99
+ uses: actions/download-artifact@v4
100
+ with:
101
+ name: wheels-py${{ matrix.python-version }}
102
+ path: wheels
103
+
104
+ - name: Test wheel installation
105
+ run: |
106
+ $wheel = Get-ChildItem wheels\*.whl | Select-Object -First 1
107
+ python -m pip install $wheel.FullName
108
+ python -c "
109
+ import duvc_ctl
110
+ print(f'SUCCESS: duvc_ctl {duvc_ctl.__version__}')
111
+ devices = duvc_ctl.list_devices()
112
+ print(f'Found {len(devices)} devices')
113
+ "
114
+
115
+ upload_testpypi:
116
+ name: Upload to TestPyPI
117
+ needs: [build_wheels, build_sdist, test_install]
118
+ runs-on: ubuntu-latest
119
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
120
+ environment:
121
+ name: testpypi
122
+ url: https://test.pypi.org/p/duvc-ctl
123
+ permissions:
124
+ id-token: write
125
+
126
+ steps:
127
+ - name: Download all wheels
128
+ uses: actions/download-artifact@v4
129
+ with:
130
+ pattern: wheels-*
131
+ path: dist
132
+ merge-multiple: true
133
+
134
+ - name: Download sdist
135
+ uses: actions/download-artifact@v4
136
+ with:
137
+ name: sdist
138
+ path: dist
139
+
140
+ - name: List artifacts to upload
141
+ run: |
142
+ ls -la dist/
143
+ echo "Uploading $(ls dist/ | wc -l) files to TestPyPI"
144
+
145
+ - name: Publish to TestPyPI
146
+ uses: pypa/gh-action-pypi-publish@release/v1
147
+ with:
148
+ repository-url: https://test.pypi.org/legacy/
149
+ print-hash: true
150
+ skip-existing: true
151
+ verbose: true
152
+
153
+ create_release:
154
+ name: Create GitHub Release
155
+ needs: [upload_testpypi]
156
+ runs-on: ubuntu-latest
157
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
158
+ permissions:
159
+ contents: write
160
+
161
+ steps:
162
+ - name: Download all artifacts
163
+ uses: actions/download-artifact@v4
164
+ with:
165
+ pattern: "*"
166
+ path: artifacts
167
+
168
+ - name: Create Release
169
+ uses: softprops/action-gh-release@v1
170
+ with:
171
+ files: artifacts/**/*
172
+ generate_release_notes: true
@@ -0,0 +1,197 @@
1
+ cmake_minimum_required(VERSION 3.16)
2
+ project(duvc-ctl VERSION 1.0.0 LANGUAGES CXX)
3
+
4
+ # Options
5
+ option(DUVC_BUILD_STATIC "Build duvc static library" ON)
6
+ option(DUVC_BUILD_SHARED "Build duvc shared library" OFF)
7
+ option(DUVC_BUILD_CLI "Build duvc CLI" ON)
8
+ option(DUVC_BUILD_PYTHON "Build Python bindings (pybind11)" OFF)
9
+ option(DUVC_WARNINGS_AS_ERRORS "Treat warnings as errors" OFF)
10
+
11
+ # Global settings
12
+ set(CMAKE_CXX_STANDARD 17)
13
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
14
+ set(CMAKE_POSITION_INDEPENDENT_CODE ON)
15
+
16
+ # Output dirs (nice layout for MSVC multi-config and Makefile single-config)
17
+ foreach(OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES})
18
+ string(TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG_UC)
19
+ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG_UC} ${CMAKE_BINARY_DIR}/lib)
20
+ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_${OUTPUTCONFIG_UC} ${CMAKE_BINARY_DIR}/bin)
21
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG_UC} ${CMAKE_BINARY_DIR}/bin)
22
+ endforeach()
23
+ if(NOT CMAKE_CONFIGURATION_TYPES)
24
+ set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
25
+ set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
26
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
27
+ endif()
28
+
29
+ # Helper: warning flags
30
+ function(duvc_apply_warnings target)
31
+ if(MSVC)
32
+ target_compile_options(${target} PRIVATE /W4 /permissive-)
33
+ if(DUVC_WARNINGS_AS_ERRORS)
34
+ target_compile_options(${target} PRIVATE /WX)
35
+ endif()
36
+ target_compile_definitions(${target} PRIVATE UNICODE _UNICODE NOMINMAX)
37
+ else()
38
+ target_compile_options(${target} PRIVATE -Wall -Wextra -Wpedantic)
39
+ if(DUVC_WARNINGS_AS_ERRORS)
40
+ target_compile_options(${target} PRIVATE -Werror)
41
+ endif()
42
+ endif()
43
+ endfunction()
44
+
45
+ # Helper: link DirectShow on Windows
46
+ function(duvc_link_directshow target)
47
+ if(WIN32)
48
+ target_link_libraries(${target} PRIVATE ole32 oleaut32 strmiids)
49
+ endif()
50
+ endfunction()
51
+
52
+ # Helper: MinGW console subsystem fix
53
+ function(duvc_fix_mingw_console target)
54
+ if(MINGW)
55
+ target_link_options(${target} PRIVATE -mconsole -Wl,--subsystem,console)
56
+ endif()
57
+ endfunction()
58
+
59
+ # Include dirs
60
+ set(DUVC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include)
61
+
62
+ # Library target(s)
63
+ set(DUVC_SOURCES
64
+ src/core.cpp
65
+ src/bindings.cpp
66
+ )
67
+
68
+ if(DUVC_BUILD_STATIC)
69
+ add_library(duvc STATIC ${DUVC_SOURCES})
70
+ target_include_directories(duvc PUBLIC ${DUVC_INCLUDE_DIR})
71
+ target_compile_features(duvc PUBLIC cxx_std_17)
72
+ duvc_apply_warnings(duvc)
73
+ duvc_link_directshow(duvc)
74
+ endif()
75
+
76
+ if(DUVC_BUILD_SHARED)
77
+ add_library(duvc_shared SHARED ${DUVC_SOURCES})
78
+ target_include_directories(duvc_shared PUBLIC ${DUVC_INCLUDE_DIR})
79
+ target_compile_features(duvc_shared PUBLIC cxx_std_17)
80
+ target_compile_definitions(duvc_shared PRIVATE DUVCC_DLL_BUILD)
81
+ set_target_properties(duvc_shared PROPERTIES OUTPUT_NAME duvc)
82
+ duvc_apply_warnings(duvc_shared)
83
+ duvc_link_directshow(duvc_shared)
84
+ endif()
85
+
86
+ # CLI
87
+ if(DUVC_BUILD_CLI)
88
+ add_executable(duvc-cli cli/main.cpp)
89
+ target_include_directories(duvc-cli PRIVATE ${DUVC_INCLUDE_DIR})
90
+ if(DUVC_BUILD_STATIC)
91
+ target_link_libraries(duvc-cli PRIVATE duvc)
92
+ elseif(DUVC_BUILD_SHARED)
93
+ target_link_libraries(duvc-cli PRIVATE duvc_shared)
94
+ else()
95
+ message(FATAL_ERROR "CLI requested but no library variant enabled. Enable DUVC_BUILD_STATIC or DUVC_BUILD_SHARED.")
96
+ endif()
97
+ duvc_apply_warnings(duvc-cli)
98
+ duvc_link_directshow(duvc-cli)
99
+ duvc_fix_mingw_console(duvc-cli)
100
+ endif()
101
+
102
+ # Python bindings via pybind11 (optional)
103
+ option(DUVC_USE_SYSTEM_PYBIND11 "Use system-installed pybind11" OFF)
104
+
105
+ if(DUVC_BUILD_PYTHON)
106
+ # Locate Python
107
+ find_package(Python COMPONENTS Interpreter Development REQUIRED)
108
+
109
+ # pybind11
110
+ if(DUVC_USE_SYSTEM_PYBIND11)
111
+ find_package(pybind11 CONFIG REQUIRED)
112
+ else()
113
+ # Use FetchContent to grab pybind11
114
+ include(FetchContent)
115
+ FetchContent_Declare(
116
+ pybind11
117
+ GIT_REPOSITORY https://github.com/pybind/pybind11.git
118
+ GIT_TAG v2.11.1
119
+ )
120
+ FetchContent_MakeAvailable(pybind11)
121
+ endif()
122
+
123
+ # Python binding source
124
+ set(DUVC_PY_SOURCES src/py/pybind_module.cpp)
125
+
126
+ if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src/py/pybind_module.cpp)
127
+ pybind11_add_module(_duvc_ctl ${DUVC_PY_SOURCES})
128
+
129
+ # For MSVC, handle configuration-specific output directories
130
+ if(CMAKE_GENERATOR_PLATFORM)
131
+ set_target_properties(_duvc_ctl PROPERTIES
132
+ OUTPUT_NAME "_duvc_ctl"
133
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/py
134
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/py
135
+ LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/py
136
+ RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_BINARY_DIR}/py
137
+ LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/py
138
+ RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_BINARY_DIR}/py
139
+ )
140
+ else()
141
+ set_target_properties(_duvc_ctl PROPERTIES
142
+ OUTPUT_NAME "_duvc_ctl"
143
+ LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/py
144
+ RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/py
145
+ )
146
+ endif()
147
+
148
+ target_include_directories(_duvc_ctl PRIVATE ${DUVC_INCLUDE_DIR})
149
+
150
+ if(DUVC_BUILD_STATIC)
151
+ target_link_libraries(_duvc_ctl PRIVATE duvc)
152
+ elseif(DUVC_BUILD_SHARED)
153
+ target_link_libraries(_duvc_ctl PRIVATE duvc_shared)
154
+ else()
155
+ target_sources(_duvc_ctl PRIVATE ${DUVC_SOURCES})
156
+ duvc_link_directshow(_duvc_ctl)
157
+ endif()
158
+
159
+ duvc_apply_warnings(_duvc_ctl)
160
+ duvc_link_directshow(_duvc_ctl)
161
+
162
+ else()
163
+ message(WARNING "DUVC_BUILD_PYTHON=ON but src/py/pybind_module.cpp not found. Skipping Python module.")
164
+ endif()
165
+ endif()
166
+
167
+ # Installation (optional, basic)
168
+ include(GNUInstallDirs)
169
+
170
+ if(DUVC_BUILD_STATIC OR DUVC_BUILD_SHARED)
171
+ install(DIRECTORY include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
172
+ endif()
173
+
174
+ if(TARGET duvc)
175
+ install(TARGETS duvc
176
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
177
+ LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
178
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
179
+ endif()
180
+
181
+ if(TARGET duvc_shared)
182
+ install(TARGETS duvc_shared
183
+ ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
184
+ LIBRARY DESTINATION ${CMAKE_LIBRARY_DIR}
185
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
186
+ endif()
187
+
188
+ if(TARGET duvc-cli)
189
+ install(TARGETS duvc-cli
190
+ RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
191
+ endif()
192
+
193
+ if(DUVC_BUILD_PYTHON AND TARGET _duvc_ctl)
194
+ # Install the Python extension module to the correct location within the package
195
+ install(TARGETS _duvc_ctl
196
+ DESTINATION ${SKBUILD_PLATLIB_DIR}/duvc_ctl)
197
+ endif()
duvc_ctl-1.0.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 allanhanan
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.