-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdebug-dev-stack.sh
More file actions
executable file
·238 lines (216 loc) · 10.1 KB
/
debug-dev-stack.sh
File metadata and controls
executable file
·238 lines (216 loc) · 10.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
#!/bin/bash
set -e
# Function to check if a port is available
check_port() {
local port=$1
if lsof -Pi :$port -sTCP:LISTEN -t >/dev/null 2>&1 || \
netstat -tuln 2>/dev/null | grep -q ":$port " || \
ss -tuln 2>/dev/null | grep -q ":$port "; then
return 1 # Port is in use
else
return 0 # Port is available
fi
}
# Function to find next available port starting from a base port
find_available_port() {
local base_port=$1
local port=$base_port
while ! check_port $port; do
port=$((port + 1))
done
echo $port
}
# Parse arguments
ACTION=${1:-"up"}
BASE_PORT=${2:-8000}
STACK_NAME=${3:-"dev"}
SERVICE=${4:-""}
# Check for --attached flag in SERVICE position
ATTACHED_MODE=false
if [[ "$SERVICE" == "--attached" ]] || [[ "$SERVICE" == "-a" ]]; then
ATTACHED_MODE=true
SERVICE=""
fi
shift 4 2>/dev/null || true # Remove first 4 args, remaining are exec command
EXEC_CMD=("$@")
# Validate action
if [[ ! "$ACTION" =~ ^(up|down|logs|ps|restart|stop|exec|build)$ ]]; then
echo "Usage: $0 <up|down|logs|ps|restart|stop|exec|build> [base_port] [stack_name] [service] [--attached|-a] [command...]"
echo ""
echo "Examples:"
echo " $0 up # Start default stack (port 8000, detached)"
echo " $0 up 8000 dev --attached # Start all services (attached, see logs)"
echo " $0 up 8001 # Start stack on port 8001"
echo " $0 up 8002 feature-x # Start 'feature-x' stack on port 8002"
echo " $0 up 8000 dev django-web-dev # Start only django-web-dev (attached, see logs)"
echo " $0 down 8001 # Stop stack on port 8001"
echo " $0 logs 8002 feature-x # View logs for 'feature-x' stack"
echo " $0 build 8000 dev # Rebuild all containers"
echo " $0 build 8000 dev django-web-dev # Rebuild specific service"
echo " $0 exec 8000 dev django-web-dev bash # Execute bash in django-web-dev container"
echo " $0 exec 8000 dev django-web-dev python manage.py shell # Run Django shell"
exit 1
fi
# Validate exec requires a service
if [ "$ACTION" = "exec" ] && [ -z "$SERVICE" ]; then
echo "❌ Error: 'exec' action requires a service name"
echo "Usage: $0 exec [base_port] [stack_name] <service> <command...>"
exit 1
fi
# Use docker compose project name to isolate stacks
PROJECT_NAME="papersnitch-${STACK_NAME}"
# Find available ports only if starting up
if [ "$ACTION" = "up" ]; then
echo "🚀 Starting development stack: $STACK_NAME"
echo "📍 Base port requested: $BASE_PORT"
DJANGO_PORT=$(find_available_port $BASE_PORT)
MYSQL_PORT=$(find_available_port 3307)
REDIS_PORT=$(find_available_port 6380)
GROBID_PORT=$(find_available_port 8071)
echo ""
echo "✅ Available ports found:"
echo " Django: $DJANGO_PORT"
echo " MySQL: $MYSQL_PORT"
echo " Redis: $REDIS_PORT"
echo " GROBID: $GROBID_PORT"
echo ""
# Store port configuration for this stack
mkdir -p .stacks
cat > ".stacks/${STACK_NAME}.env" <<EOF
COMPOSE_PROJECT_NAME=${PROJECT_NAME}
DJANGO_PORT=${DJANGO_PORT}
MYSQL_PORT=${MYSQL_PORT}
REDIS_PORT=${REDIS_PORT}
GROBID_PORT=${GROBID_PORT}
STACK_SUFFIX=${STACK_NAME}
EOF
# Create necessary directories
mkdir -p "mysql_${STACK_NAME}/lib"
mkdir -p "static_${STACK_NAME}"
mkdir -p "media_${STACK_NAME}"
# Copy MySQL configs if needed
if [ ! -f "mysql_${STACK_NAME}/my.cnf" ] && [ -f "mysql/my.cnf" ]; then
cp mysql/my.cnf "mysql_${STACK_NAME}/my.cnf"
fi
if [ ! -f "mysql_${STACK_NAME}/.client.cnf" ] && [ -f "mysql/.client.cnf" ]; then
cp mysql/.client.cnf "mysql_${STACK_NAME}/.client.cnf"
fi
# Create/update .env file for this stack
if [ -f ".env.local" ]; then
# Merge .env.local with stack-specific port configuration
cat .env.local > ".env.${STACK_NAME}"
echo "" >> ".env.${STACK_NAME}"
echo "# Stack-specific port configuration" >> ".env.${STACK_NAME}"
cat ".stacks/${STACK_NAME}.env" >> ".env.${STACK_NAME}"
echo "✅ Created .env.${STACK_NAME} from .env.local with port config"
elif [ ! -f ".env.${STACK_NAME}" ]; then
cp ".stacks/${STACK_NAME}.env" ".env.${STACK_NAME}"
echo "⚠️ Created .env.${STACK_NAME} with only port config (no .env.local found)"
fi
else
# Load existing configuration
if [ -f ".stacks/${STACK_NAME}.env" ]; then
source ".stacks/${STACK_NAME}.env"
# Also update the main env file to ensure ports are set
if [ -f ".env.local" ]; then
cat .env.local > ".env.${STACK_NAME}"
echo "" >> ".env.${STACK_NAME}"
echo "# Stack-specific port configuration" >> ".env.${STACK_NAME}"
cat ".stacks/${STACK_NAME}.env" >> ".env.${STACK_NAME}"
fi
if [ "$ACTION" != "exec" ]; then
echo "📋 Loaded configuration for stack: $STACK_NAME"
fi
else
echo "⚠️ No configuration found for stack: $STACK_NAME"
echo " Available stacks:"
ls -1 .stacks/*.env 2>/dev/null | sed 's/.stacks\///g' | sed 's/.env//g' | sed 's/^/ - /'
exit 1
fi
fi
# Run docker compose with environment variables
export COMPOSE_PROJECT_NAME=${PROJECT_NAME}
export DJANGO_PORT
export MYSQL_PORT
export REDIS_PORT
export GROBID_PORT
export STACK_SUFFIX=${STACK_NAME}
echo ""
if [ "$ACTION" = "exec" ]; then
echo "🐳 Executing in ${SERVICE}: ${EXEC_CMD[@]:-bash}"
elif [ "$ACTION" = "build" ]; then
if [ -n "$SERVICE" ]; then
echo "🔨 Rebuilding service: $SERVICE"
else
echo "🔨 Rebuilding all containers"
fi
elif [ -n "$SERVICE" ]; then
echo "🐳 Running: docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file .env.${STACK_NAME} $ACTION $SERVICE"
else
echo "🐳 Running: docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file .env.${STACK_NAME} $ACTION"
fi
if [ "$ACTION" != "exec" ] && [ "$ACTION" != "build" ]; then
echo " DJANGO_PORT=${DJANGO_PORT}, MYSQL_PORT=${MYSQL_PORT}, REDIS_PORT=${REDIS_PORT}, GROBID_PORT=${GROBID_PORT}"
fi
echo ""
if [ "$ACTION" = "exec" ]; then
# Execute command in container
if [ ${#EXEC_CMD[@]} -eq 0 ]; then
# No command specified, default to bash
COMPOSE_PROJECT_NAME=${PROJECT_NAME} DJANGO_PORT=${DJANGO_PORT} MYSQL_PORT=${MYSQL_PORT} REDIS_PORT=${REDIS_PORT} GROBID_PORT=${GROBID_PORT} STACK_SUFFIX=${STACK_NAME} \
docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file ".env.${STACK_NAME}" exec ${SERVICE} bash
else
# Execute the specified command
COMPOSE_PROJECT_NAME=${PROJECT_NAME} DJANGO_PORT=${DJANGO_PORT} MYSQL_PORT=${MYSQL_PORT} REDIS_PORT=${REDIS_PORT} GROBID_PORT=${GROBID_PORT} STACK_SUFFIX=${STACK_NAME} \
docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file ".env.${STACK_NAME}" exec ${SERVICE} "${EXEC_CMD[@]}"
fi
elif [ "$ACTION" = "build" ]; then
# Rebuild containers
if [ -n "$SERVICE" ]; then
# Build specific service
COMPOSE_PROJECT_NAME=${PROJECT_NAME} DJANGO_PORT=${DJANGO_PORT} MYSQL_PORT=${MYSQL_PORT} REDIS_PORT=${REDIS_PORT} GROBID_PORT=${GROBID_PORT} STACK_SUFFIX=${STACK_NAME} \
docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file ".env.${STACK_NAME}" build --no-cache ${SERVICE}
else
# Build all services
COMPOSE_PROJECT_NAME=${PROJECT_NAME} DJANGO_PORT=${DJANGO_PORT} MYSQL_PORT=${MYSQL_PORT} REDIS_PORT=${REDIS_PORT} GROBID_PORT=${GROBID_PORT} STACK_SUFFIX=${STACK_NAME} \
docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file ".env.${STACK_NAME}" build --no-cache
fi
echo ""
echo "✅ Build complete! Use '$0 up $BASE_PORT $STACK_NAME' to start the containers."
elif [ "$ACTION" = "up" ] && [ -z "$SERVICE" ]; then
# Start all services (detached or attached based on flag)
if [ "$ATTACHED_MODE" = true ]; then
echo "🔍 Starting all services in attached mode (Ctrl+C to stop)..."
COMPOSE_PROJECT_NAME=${PROJECT_NAME} DJANGO_PORT=${DJANGO_PORT} MYSQL_PORT=${MYSQL_PORT} REDIS_PORT=${REDIS_PORT} GROBID_PORT=${GROBID_PORT} STACK_SUFFIX=${STACK_NAME} \
docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file ".env.${STACK_NAME}" $ACTION
else
COMPOSE_PROJECT_NAME=${PROJECT_NAME} DJANGO_PORT=${DJANGO_PORT} MYSQL_PORT=${MYSQL_PORT} REDIS_PORT=${REDIS_PORT} GROBID_PORT=${GROBID_PORT} STACK_SUFFIX=${STACK_NAME} \
docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file ".env.${STACK_NAME}" $ACTION -d
fi
elif [ "$ACTION" = "up" ] && [ -n "$SERVICE" ]; then
# Start single service in attached mode (no -d, shows logs)
echo "🔍 Starting $SERVICE in attached mode (Ctrl+C to stop)..."
COMPOSE_PROJECT_NAME=${PROJECT_NAME} DJANGO_PORT=${DJANGO_PORT} MYSQL_PORT=${MYSQL_PORT} REDIS_PORT=${REDIS_PORT} GROBID_PORT=${GROBID_PORT} STACK_SUFFIX=${STACK_NAME} \
docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file ".env.${STACK_NAME}" $ACTION $SERVICE
else
# Other actions (down, logs, etc.)
COMPOSE_PROJECT_NAME=${PROJECT_NAME} DJANGO_PORT=${DJANGO_PORT} MYSQL_PORT=${MYSQL_PORT} REDIS_PORT=${REDIS_PORT} GROBID_PORT=${GROBID_PORT} STACK_SUFFIX=${STACK_NAME} \
docker compose -p ${PROJECT_NAME} -f compose.dev.yml --env-file ".env.${STACK_NAME}" $ACTION ${SERVICE}
fi
if [ "$ACTION" = "up" ] && [ -z "$SERVICE" ]; then
echo ""
echo "🎉 Stack '$STACK_NAME' is running!"
echo ""
echo "🌐 Access points:"
echo " Django: http://localhost:$DJANGO_PORT"
echo " MySQL: localhost:$MYSQL_PORT"
echo " Redis: localhost:$REDIS_PORT"
echo " GROBID: http://localhost:$GROBID_PORT"
echo ""
echo "📝 Useful commands:"
echo " Logs: $0 logs $BASE_PORT $STACK_NAME"
echo " Stop: $0 down $BASE_PORT $STACK_NAME"
echo " Status: $0 ps $BASE_PORT $STACK_NAME"
echo " Rebuild: $0 build $BASE_PORT $STACK_NAME"
echo ""
fi