Skip to content

Commit de14a46

Browse files
add docker and local publish script devx improvements
1 parent 2e15c29 commit de14a46

2 files changed

Lines changed: 142 additions & 0 deletions

File tree

docker-compose.yml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# =============================================================================
2+
# OSHConnect-Python — Local PyPI Server
3+
#
4+
# A lightweight pypiserver for publishing dev builds of oshconnect so that
5+
# downstream projects (OCSASim, etc.) can `pip install` normally instead of
6+
# pointing at raw wheel paths.
7+
#
8+
# Usage:
9+
# docker compose up -d # start the local PyPI
10+
# ./scripts/publish-local.sh # build wheel + upload to local PyPI
11+
# docker compose down -v # tear down + remove packages volume
12+
#
13+
# Consumer side (e.g. OCSASim):
14+
# pip install --index-url http://localhost:8090/simple/ oshconnect
15+
# uv pip install --index-url http://localhost:8090/simple/ oshconnect
16+
# =============================================================================
17+
18+
services:
19+
pypi:
20+
image: pypiserver/pypiserver:latest
21+
container_name: local-pypi
22+
command: run -a . -P . -o
23+
ports:
24+
- "8090:8080"
25+
volumes:
26+
- pypi-packages:/data/packages
27+
healthcheck:
28+
test: ["CMD", "wget", "-q", "-O", "/dev/null", "http://localhost:8080/"]
29+
interval: 5s
30+
timeout: 3s
31+
start_period: 5s
32+
retries: 3
33+
34+
volumes:
35+
pypi-packages:

scripts/publish-local.sh

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
#!/usr/bin/env bash
2+
# =============================================================================
3+
# publish-local.sh — Build oshconnect and publish to the local PyPI server
4+
#
5+
# This is the one-command dev loop: edit code → run this → downstream picks
6+
# up the new version via `pip install --index-url http://localhost:8090/simple/`.
7+
#
8+
# The local pypiserver container must be running (`docker compose up -d`).
9+
# The --overwrite flag on the server allows re-uploading the same version,
10+
# so you don't need to bump the version for every dev iteration.
11+
#
12+
# Usage:
13+
# ./scripts/publish-local.sh # build + upload
14+
# ./scripts/publish-local.sh --no-build # upload existing wheel(s) in dist/
15+
# =============================================================================
16+
17+
set -euo pipefail
18+
19+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
20+
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
21+
22+
PYPI_URL="${LOCAL_PYPI_URL:-http://localhost:8090}"
23+
24+
RED='\033[0;31m'
25+
GREEN='\033[0;32m'
26+
CYAN='\033[0;36m'
27+
NC='\033[0m'
28+
29+
info() { echo -e "${CYAN}[INFO]${NC} $*"; }
30+
ok() { echo -e "${GREEN}[OK]${NC} $*"; }
31+
fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; }
32+
33+
info "Project root: ${PROJECT_ROOT}"
34+
35+
# ── Parse args ──────────────────────────────────────────────────────────────
36+
SKIP_BUILD=false
37+
for arg in "$@"; do
38+
case "$arg" in
39+
--no-build) SKIP_BUILD=true ;;
40+
--help|-h)
41+
echo "Usage: $0 [--no-build]"
42+
echo " --no-build Skip wheel build, upload whatever is in dist/"
43+
exit 0
44+
;;
45+
esac
46+
done
47+
48+
# ── Ensure local PyPI is running ────────────────────────────────────────────
49+
pypi_ready() {
50+
# Just check for any HTTP response (2xx or 3xx) — an empty index still returns 200
51+
local code
52+
code=$(curl -s -o /dev/null -w "%{http_code}" --max-time 3 "${PYPI_URL}/" 2>/dev/null) || return 1
53+
[ "$code" -ge 200 ] && [ "$code" -lt 400 ]
54+
}
55+
56+
info "Checking local PyPI at ${PYPI_URL}"
57+
if pypi_ready; then
58+
ok "Local PyPI is already running"
59+
else
60+
info "Local PyPI not running — starting container..."
61+
cd "${PROJECT_ROOT}"
62+
docker compose up -d pypi
63+
64+
READY=false
65+
for i in $(seq 1 10); do
66+
sleep 1
67+
if pypi_ready; then
68+
READY=true
69+
break
70+
fi
71+
info " waiting... (${i}/10)"
72+
done
73+
74+
if [ "$READY" = false ]; then
75+
fail "Could not start local PyPI"
76+
fi
77+
ok "Local PyPI started"
78+
fi
79+
80+
# ── Build ───────────────────────────────────────────────────────────────────
81+
cd "${PROJECT_ROOT}"
82+
info "Working directory: $(pwd)"
83+
84+
if [ "$SKIP_BUILD" = false ]; then
85+
info "Building wheel..."
86+
rm -rf dist/ build/ src/*.egg-info
87+
88+
uv build || fail "uv build failed"
89+
fi
90+
91+
WHEELS=(dist/*.whl)
92+
if [ ${#WHEELS[@]} -eq 0 ] || [ ! -f "${WHEELS[0]}" ]; then
93+
fail "No wheel found in ${PROJECT_ROOT}/dist/. Build first or remove --no-build."
94+
fi
95+
96+
ok "Wheel(s): ${WHEELS[*]}"
97+
98+
# ── Upload ──────────────────────────────────────────────────────────────────
99+
info "Uploading to ${PYPI_URL}"
100+
uv publish --publish-url "${PYPI_URL}" dist/*.whl || fail "uv publish failed"
101+
102+
ok "Published to local PyPI"
103+
echo ""
104+
echo " Browse: ${PYPI_URL}/simple/"
105+
echo " Install: pip install --index-url ${PYPI_URL}/simple/ oshconnect"
106+
echo " uv: uv pip install --index-url ${PYPI_URL}/simple/ oshconnect"
107+
echo " uv sync: uv sync (if pyproject.toml has [[tool.uv.index]] configured)"

0 commit comments

Comments
 (0)