1+ #! /bin/bash
2+
3+ set -e
4+
5+ SCRIPT_DIR=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd) "
6+ PROJECT_ROOT=" ${SCRIPT_DIR} /.."
7+ DEFAULT_OPENAPI_FILE=" ${SCRIPT_DIR} /openapi.json"
8+ DEFAULT_PACKAGE_NAME=" permify"
9+ DEFAULT_CLIENT_NAME=" PermifyClient"
10+
11+ usage () {
12+ echo " Usage: $0 [OPTIONS]"
13+ echo " "
14+ echo " Generate Python SDK from OpenAPI specification and update project directories"
15+ echo " "
16+ echo " Options:"
17+ echo " -i, --input FILE OpenAPI JSON file (default: ${DEFAULT_OPENAPI_FILE} )"
18+ echo " -p, --package NAME Python package name (default: ${DEFAULT_PACKAGE_NAME} )"
19+ echo " -c, --client NAME Client class name (default: ${DEFAULT_CLIENT_NAME} )"
20+ echo " -h, --help Show this help message"
21+ echo " "
22+ echo " This script will update the following:"
23+ echo " - ../permify (generated Python package)"
24+ echo " - ../docs (API documentation)"
25+ echo " - ../test (generated tests)"
26+ echo " - ../setup.py (package metadata and dependencies)"
27+ echo " - ../pyproject.toml (package metadata and dependencies)"
28+ echo " "
29+ echo " Examples:"
30+ echo " $0 # Use defaults"
31+ echo " $0 -i swagger.json # Custom input file"
32+ echo " $0 -p custom_package # Custom package name"
33+ }
34+
35+ OPENAPI_FILE=" ${DEFAULT_OPENAPI_FILE} "
36+ PACKAGE_NAME=" ${DEFAULT_PACKAGE_NAME} "
37+ CLIENT_NAME=" ${DEFAULT_CLIENT_NAME} "
38+
39+ while [[ $# -gt 0 ]]; do
40+ case $1 in
41+ -i|--input)
42+ OPENAPI_FILE=" $2 "
43+ shift 2
44+ ;;
45+ -p|--package)
46+ PACKAGE_NAME=" $2 "
47+ shift 2
48+ ;;
49+ -c|--client)
50+ CLIENT_NAME=" $2 "
51+ shift 2
52+ ;;
53+ -h|--help)
54+ usage
55+ exit 0
56+ ;;
57+ * )
58+ echo " Unknown option: $1 "
59+ usage
60+ exit 1
61+ ;;
62+ esac
63+ done
64+
65+ if [[ ! -f " ${OPENAPI_FILE} " ]]; then
66+ echo " Error: OpenAPI file '${OPENAPI_FILE} ' not found"
67+ exit 1
68+ fi
69+
70+ # Check if Java is available
71+ if ! command -v java & > /dev/null; then
72+ echo " Error: Java is required but not installed"
73+ exit 1
74+ fi
75+
76+ TEMP_OUTPUT_DIR=$( mktemp -d)
77+ trap ' rm -rf "${TEMP_OUTPUT_DIR}"' EXIT
78+
79+ OPENAPI_ABSOLUTE_PATH=$( realpath " ${OPENAPI_FILE} " )
80+
81+ OPENAPI_VERSION=$( grep -o ' "version": *"[^"]*"' " ${OPENAPI_FILE} " | cut -d ' "' -f 4)
82+ if [[ -z " ${OPENAPI_VERSION} " ]]; then
83+ echo " Error: Could not extract version from OpenAPI file"
84+ exit 1
85+ fi
86+
87+ echo " Generating Python SDK..."
88+ echo " OpenAPI file: ${OPENAPI_ABSOLUTE_PATH} "
89+ echo " OpenAPI version: ${OPENAPI_VERSION} "
90+ echo " Package name: ${PACKAGE_NAME} "
91+ echo " Client name: ${CLIENT_NAME} "
92+ echo " Temp directory: ${TEMP_OUTPUT_DIR} "
93+ echo " "
94+
95+ # Download OpenAPI Generator CLI JAR if not present
96+ GENERATOR_JAR=" ${SCRIPT_DIR} /openapi-generator-cli.jar"
97+ if [[ ! -f " ${GENERATOR_JAR} " ]]; then
98+ echo " Downloading OpenAPI Generator CLI..."
99+ curl -L -o " ${GENERATOR_JAR} " https://repo1.maven.org/maven2/org/openapitools/openapi-generator-cli/7.2.0/openapi-generator-cli-7.2.0.jar
100+ fi
101+
102+ # Generate SDK using OpenAPI Generator CLI
103+ java -jar " ${GENERATOR_JAR} " generate \
104+ -i " ${OPENAPI_ABSOLUTE_PATH} " \
105+ -g python \
106+ -o " ${TEMP_OUTPUT_DIR} " \
107+ --package-name=" ${PACKAGE_NAME} " \
108+ --additional-properties=packageName=" ${PACKAGE_NAME} " \
109+ --additional-properties=clientPackage=" ${PACKAGE_NAME} " \
110+ --additional-properties=projectName=" ${PACKAGE_NAME} " \
111+ --additional-properties=packageUrl=" https://github.com/Permify/permify-python" \
112+ --additional-properties=packageVersion=" ${OPENAPI_VERSION} " \
113+ --additional-properties=packageDescription=" " " Permify is an open source authorization service for creating fine-grained and scalable authorization systems." " " \
114+ --additional-properties=library=urllib3 \
115+ --additional-properties=hideGenerationTimestamp=true \
116+ --additional-properties=generateSourceCodeOnly=false \
117+ --additional-properties=licenseName=" Apache-2.0" \
118+ --skip-validate-spec
119+
120+ if [[ $? -ne 0 ]]; then
121+ echo " "
122+ echo " ❌ Failed to generate Python SDK"
123+ exit 1
124+ fi
125+
126+ echo " Updating project directories..."
127+
128+ # Update the main package directory
129+ PACKAGE_DIR=" ${PROJECT_ROOT} /${PACKAGE_NAME} "
130+ if [[ -d " ${TEMP_OUTPUT_DIR} /${PACKAGE_NAME} " ]]; then
131+ echo " Updating ${PACKAGE_DIR} "
132+ # Backup any custom files that shouldn't be overwritten
133+ if [[ -f " ${PACKAGE_DIR} /py.typed" ]]; then
134+ cp " ${PACKAGE_DIR} /py.typed" " ${TEMP_OUTPUT_DIR} /${PACKAGE_NAME} /py.typed"
135+ fi
136+
137+ rm -rf " ${PACKAGE_DIR} "
138+ cp -r " ${TEMP_OUTPUT_DIR} /${PACKAGE_NAME} " " ${PACKAGE_DIR} "
139+ fi
140+
141+ # Update documentation
142+ DOCS_DIR=" ${PROJECT_ROOT} /docs"
143+ if [[ -d " ${TEMP_OUTPUT_DIR} /docs" ]]; then
144+ echo " Updating ${DOCS_DIR} "
145+ rm -rf " ${DOCS_DIR} " /* .md
146+ mkdir -p " ${DOCS_DIR} "
147+ cp " ${TEMP_OUTPUT_DIR} /docs/" * .md " ${DOCS_DIR} /"
148+ fi
149+
150+ # Update tests
151+ TEST_DIR=" ${PROJECT_ROOT} /test"
152+ if [[ -d " ${TEMP_OUTPUT_DIR} /test" ]]; then
153+ echo " Updating ${TEST_DIR} "
154+ rm -rf " ${TEST_DIR} "
155+ mkdir -p " ${TEST_DIR} "
156+ cp -r " ${TEMP_OUTPUT_DIR} /test/" * " ${TEST_DIR} /"
157+ fi
158+
159+ # Function to update setup.py with repository information
160+ update_setup_py () {
161+ local generated_setup=" ${TEMP_OUTPUT_DIR} /setup.py"
162+ local target_setup=" ${PROJECT_ROOT} /setup.py"
163+
164+ if [[ ! -f " ${generated_setup} " ]]; then
165+ echo " ⚠️ Warning: Generated setup.py not found, skipping update"
166+ return
167+ fi
168+
169+ echo " Updating setup.py"
170+
171+ # Create a backup
172+ if [[ -f " ${target_setup} " ]]; then
173+ cp " ${target_setup} " " ${target_setup} .bak"
174+ fi
175+
176+ # Directly copy the generated setup.py without any modifications
177+ cp " ${generated_setup} " " ${target_setup} "
178+
179+ echo " ✅ Updated setup.py"
180+ }
181+
182+ # Function to update pyproject.toml
183+ update_pyproject_toml () {
184+ local target_pyproject=" ${PROJECT_ROOT} /pyproject.toml"
185+
186+ if [[ ! -f " ${target_pyproject} " ]]; then
187+ echo " ⚠️ Warning: pyproject.toml not found, skipping update"
188+ return
189+ fi
190+
191+ echo " Updating pyproject.toml version"
192+
193+ # Strip 'v' prefix from version if present
194+ VERSION_WITHOUT_V=" ${OPENAPI_VERSION# v} "
195+
196+ # Update version in pyproject.toml
197+ if [[ " $OSTYPE " == " darwin" * ]]; then
198+ sed -i ' ' " s/^version = \" [^\" ]*\" /version = \" ${VERSION_WITHOUT_V} \" /" " ${target_pyproject} "
199+ else
200+ sed -i " s/^version = \" [^\" ]*\" /version = \" ${VERSION_WITHOUT_V} \" /" " ${target_pyproject} "
201+ fi
202+
203+ echo " ✅ Updated pyproject.toml version to ${VERSION_WITHOUT_V} "
204+ }
205+
206+ # Function to extract and update requirements
207+ update_requirements () {
208+ local generated_requirements=" ${TEMP_OUTPUT_DIR} /requirements.txt"
209+ local target_requirements=" ${PROJECT_ROOT} /requirements.txt"
210+
211+ if [[ -f " ${generated_requirements} " ]] && [[ -f " ${target_requirements} " ]]; then
212+ echo " Updating requirements.txt"
213+
214+ # Create backup
215+ cp " ${target_requirements} " " ${target_requirements} .bak"
216+
217+ # Extract non-dev requirements from generated file
218+ grep -v " pytest\|tox\|flake8" " ${generated_requirements} " > " ${target_requirements} " || true
219+
220+ echo " ✅ Updated requirements.txt"
221+ fi
222+ }
223+
224+ # Update package files
225+ update_setup_py
226+ update_pyproject_toml
227+ update_requirements
228+
229+ echo " "
230+ echo " ✅ Python SDK updated successfully!"
231+ echo " 📁 Updated directories:"
232+ echo " - ${PACKAGE_DIR} "
233+ echo " - ${DOCS_DIR} "
234+ echo " - ${TEST_DIR} "
235+ echo " 📝 Updated version to ${VERSION_WITHOUT_V} "
236+ echo " 🔗 Updated package configuration in:"
237+ echo " - setup.py"
238+ echo " - pyproject.toml"
239+ echo " - requirements.txt"
0 commit comments