-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinit_project.sh
More file actions
executable file
·149 lines (117 loc) · 4.59 KB
/
init_project.sh
File metadata and controls
executable file
·149 lines (117 loc) · 4.59 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
#!/usr/bin/env bash
# Initialize a new Python project from this template.
#
# Usage:
# ./init_project.sh <package_name>
#
# Example:
# git clone git@github.com:simonpavlov/python-project-template.git my-cool-project
# cd my-cool-project
# ./init_project.sh my_cool_project
set -euo pipefail
# -- Colors ----------------------------------------------------------------
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BOLD='\033[1m'
NC='\033[0m' # No Color
info() { echo -e "${BOLD}[info]${NC} $*"; }
ok() { echo -e "${GREEN}[ok]${NC} $*"; }
warn() { echo -e "${YELLOW}[warn]${NC} $*"; }
error() { echo -e "${RED}[error]${NC} $*" >&2; }
die() { error "$@"; exit 1; }
# -- Validation ------------------------------------------------------------
[[ $# -eq 1 ]] || die "Usage: $0 <package_name> (e.g. $0 my_cool_project)"
PACKAGE_NAME="$1"
# Must be a valid Python identifier: lowercase letters, digits, underscores.
# Must start with a letter. No hyphens, no uppercase.
if [[ ! "$PACKAGE_NAME" =~ ^[a-z][a-z0-9_]*$ ]]; then
die "Invalid package name: '${PACKAGE_NAME}'
Must be a valid Python identifier: lowercase letters, digits, underscores.
Must start with a lowercase letter.
Examples: my_project, cool_lib, data_pipeline_v2"
fi
if [[ "$PACKAGE_NAME" == "my_package" ]]; then
die "Package name 'my_package' is the template default. Nothing to do."
fi
# Must be run from the template root (src/my_package/ must exist)
if [[ ! -d "src/my_package" ]]; then
die "Directory 'src/my_package' not found.
Are you running this from the template root directory?"
fi
# -- Derive name variants --------------------------------------------------
SNAKE_NAME="$PACKAGE_NAME" # my_cool_project
HYPHEN_NAME="${SNAKE_NAME//_/-}" # my-cool-project
TITLE_NAME="$(echo "$SNAKE_NAME" | sed 's/_/ /g; s/\b\w/\u&/g')" # My Cool Project
info "Initializing new project:"
info " Python package : ${BOLD}${SNAKE_NAME}${NC}"
info " PyPI name : ${BOLD}${HYPHEN_NAME}${NC}"
info " Display name : ${BOLD}${TITLE_NAME}${NC}"
echo ""
# -- Rename source directory -----------------------------------------------
info "Renaming src/my_package/ -> src/${SNAKE_NAME}/"
mv "src/my_package" "src/${SNAKE_NAME}"
ok "Directory renamed"
# -- Find and replace in files ---------------------------------------------
# Files that contain template names to replace.
# Order matters: replace the more specific patterns first.
TARGET_FILES=(
"pyproject.toml"
"src/${SNAKE_NAME}/__init__.py"
"tests/test_basic.py"
"AGENTS.md"
"README.md"
)
info "Replacing template names in project files..."
for file in "${TARGET_FILES[@]}"; do
if [[ -f "$file" ]]; then
# Title case: "My Package" -> "My Cool Project" (in docstrings)
sed -i "s/My Package/${TITLE_NAME}/g" "$file"
# Hyphenated: "my-package" -> "my-cool-project" (in pyproject.toml)
sed -i "s/my-package/${HYPHEN_NAME}/g" "$file"
# Underscore: "my_package" -> "my_cool_project" (imports, paths)
sed -i "s/my_package/${SNAKE_NAME}/g" "$file"
else
warn "File not found, skipping: ${file}"
fi
done
ok "All replacements done"
# -- Reset git -------------------------------------------------------------
info "Resetting git history..."
rm -rf .git
git init --quiet
ok "Git initialized"
# -- Self-delete ------------------------------------------------------------
info "Removing initialization scripts..."
SELF="$(basename "$0")"
rm -f "$SELF"
rm -f "test_init_project.sh"
ok "Scripts removed"
# -- Initial commit ---------------------------------------------------------
info "Creating initial commit..."
git add -A
git commit --quiet -m "Initial commit from python-project-template"
ok "Initial commit created"
# -- Install dependencies ---------------------------------------------------
info "Installing dependencies (uv sync --extra dev)..."
uv sync --extra dev --quiet
ok "Dependencies installed"
# -- Verify -----------------------------------------------------------------
info "Running full test suite (make test)..."
echo ""
if make test; then
echo ""
ok "All checks passed!"
else
echo ""
die "make test failed. Check the output above for errors."
fi
# -- Done -------------------------------------------------------------------
echo ""
echo -e "${GREEN}${BOLD}Project '${SNAKE_NAME}' is ready!${NC}"
echo ""
echo " Next steps:"
echo " 1. Update description and authors in pyproject.toml"
echo " 2. Add a git remote: git remote add origin <url>"
echo " 3. Start coding in src/${SNAKE_NAME}/"
echo ""