@@ -5,8 +5,6 @@ set -euo pipefail
55SCRIPT_DIR=" $( cd " $( dirname " ${BASH_SOURCE[0]} " ) " && pwd) "
66REPO_ROOT=" $( cd " $SCRIPT_DIR /../.." && pwd) "
77TUTORIALS_BASE=" ${REPO_ROOT} /codes_and_assets/stm32f1_tutorials"
8- TEMPLATE_DIR=" ${TUTORIALS_BASE} /0_start_our_tutorial"
9- TEMPLATE_PROJECT_NAME=" stm32_demo"
108
119# ── 颜色定义 ─────────────────────────────────────────────────────────────────
1210readonly RED=' \033[0;31m'
@@ -53,6 +51,44 @@ get_next_number() {
5351 echo $(( max + 1 ))
5452}
5553
54+ # ── 根据编号查找教程目录名 ──────────────────────────────────────────────────
55+ find_tutorial_by_number () {
56+ local target_num=" $1 "
57+ for dir in " $TUTORIALS_BASE " /* ; do
58+ [[ -d " $dir " ]] || continue
59+ local base
60+ base=" $( basename " $dir " ) "
61+ if [[ " $base " =~ ^([0-9]+)_(.+)$ ]]; then
62+ local num=" ${BASH_REMATCH[1]} "
63+ if [[ " $num " -eq " $target_num " ]]; then
64+ echo " $base "
65+ return 0
66+ fi
67+ fi
68+ done
69+ return 1
70+ }
71+
72+ # ── 查找前一个教程目录(编号为 N-1 的) ─────────────────────────────────────
73+ find_previous_tutorial () {
74+ local target_num=" $1 "
75+ local prev_num=$(( target_num - 1 ))
76+ if [[ " $prev_num " -lt 0 ]]; then
77+ return 1
78+ fi
79+ find_tutorial_by_number " $prev_num "
80+ }
81+
82+ # ── 从目录名提取 CMake 项目名 ────────────────────────────────────────────────
83+ extract_cmake_name_from_dir () {
84+ local dir_name=" $1 "
85+ # 从 CMakeLists.txt 中提取 project(...) 名
86+ local cmake_file=" ${TUTORIALS_BASE} /${dir_name} /CMakeLists.txt"
87+ if [[ -f " $cmake_file " ]]; then
88+ grep -oP ' project\(\K[^ )]+' " $cmake_file " 2> /dev/null | head -1
89+ fi
90+ }
91+
5692# ── 列出现有教程 ─────────────────────────────────────────────────────────────
5793list_tutorials () {
5894 printf " \n${BOLD} Existing tutorials:${NC} \n"
@@ -74,7 +110,7 @@ show_help() {
74110 cat << 'EOF '
75111Usage: create_tutorial.sh [OPTIONS]
76112
77- Create a new STM32F1 tutorial project from the template (0_start_our_tutorial ).
113+ Create a new STM32F1 tutorial project by copying from the previous tutorial (N-1 ).
78114
79115Options:
80116 -n, --name NAME Create tutorial with specified name (non-interactive)
139175
140176# ── 预检查 ───────────────────────────────────────────────────────────────────
141177[[ -d " $TUTORIALS_BASE " ]] || die " Tutorials base not found: ${TUTORIALS_BASE} "
142- [[ -d " $TEMPLATE_DIR " ]] || die " Template not found: ${TEMPLATE_DIR} "
143178
144179# ── 交互模式:自动推断名称 ──────────────────────────────────────────────────
145180if [[ -z " $DIR_NAME " ]]; then
146181 list_tutorials
147182
148- local next_num
149183 next_num=" $( get_next_number) "
150184 printf " ${BOLD} Next available number:${NC} ${CYAN}${next_num}${NC} \n\n"
151185
@@ -157,7 +191,6 @@ if [[ -z "$DIR_NAME" ]]; then
157191
158192 DIR_NAME=" ${next_num} _${desc} "
159193
160- local cmake_name
161194 cmake_name=" $( dir_name_to_cmake_name " $DIR_NAME " ) "
162195 printf " \n Directory: ${BOLD}${DIR_NAME}${NC} "
163196 printf " \n CMake name: ${BOLD}${cmake_name}${NC} \n\n"
@@ -172,6 +205,16 @@ validate_name "$DIR_NAME"
172205TARGET_DIR=" ${TUTORIALS_BASE} /${DIR_NAME} "
173206CMAKE_NAME=" $( dir_name_to_cmake_name " $DIR_NAME " ) "
174207
208+ # ── 查找源教程(前一个编号) ─────────────────────────────────────────────────
209+ NEW_NUM=" ${DIR_NAME%% _* } "
210+ SOURCE_DIR_NAME=" $( find_previous_tutorial " $NEW_NUM " ) " \
211+ || die " No previous tutorial found for number ${NEW_NUM} . Cannot determine source."
212+ SOURCE_DIR=" ${TUTORIALS_BASE} /${SOURCE_DIR_NAME} "
213+ SOURCE_CMAKE_NAME=" $( extract_cmake_name_from_dir " $SOURCE_DIR_NAME " ) "
214+ [[ -n " $SOURCE_CMAKE_NAME " ]] || SOURCE_CMAKE_NAME=" $( dir_name_to_cmake_name " $SOURCE_DIR_NAME " ) "
215+
216+ msg_info " Source tutorial: ${SOURCE_DIR_NAME} (CMake project: ${SOURCE_CMAKE_NAME} )"
217+
175218# ── 检查目标是否已存在 ───────────────────────────────────────────────────────
176219if [[ -d " $TARGET_DIR " ]]; then
177220 die " Directory already exists: ${TARGET_DIR} \nRemove it first or choose a different name."
181224if [[ " $DRY_RUN " == true ]]; then
182225 printf " \n${BOLD} [DRY RUN] Would perform:${NC} \n"
183226 printf " Create: %s\n" " $TARGET_DIR "
184- printf " Copy: %s/ (excluding build/ .cache/)\n" " $TEMPLATE_DIR "
185- printf " Replace: 'stm32_demo ' -> '%s' in CMakeLists.txt and .vscode/launch.json\n" " $CMAKE_NAME "
227+ printf " Copy: %s/ (excluding build/ .cache/)\n" " $SOURCE_DIR "
228+ printf " Replace: '%s ' -> '%s' in CMakeLists.txt and .vscode/launch.json\n" " $SOURCE_CMAKE_NAME " " $CMAKE_NAME "
186229 printf " \n"
187230 exit 0
188231fi
@@ -202,15 +245,15 @@ COPY_STARTED=true
202245msg_info " Creating: ${TARGET_DIR} "
203246
204247if command -v rsync & > /dev/null; then
205- rsync -a --exclude=' build/' --exclude=' .cache/' " $TEMPLATE_DIR /" " $TARGET_DIR /"
248+ rsync -a --exclude=' build/' --exclude=' .cache/' " $SOURCE_DIR /" " $TARGET_DIR /"
206249else
207250 # 回退方案:逐项复制,排除 build/ 和 .cache/
208251 mkdir -p " $TARGET_DIR "
209- for item in " $TEMPLATE_DIR " /* ; do
252+ for item in " $SOURCE_DIR " /* ; do
210253 cp -r " $item " " $TARGET_DIR /"
211254 done
212255 # 复制隐藏文件/目录
213- for item in " $TEMPLATE_DIR " /.* ; do
256+ for item in " $SOURCE_DIR " /.* ; do
214257 base=" $( basename " $item " ) "
215258 [[ " $base " == " ." || " $base " == " .." || " $base " == " .cache" ]] && continue
216259 cp -r " $item " " $TARGET_DIR /"
220263msg_success " Files copied (build/ and .cache/ excluded)."
221264
222265# ── 替换项目名: CMakeLists.txt ───────────────────────────────────────────────
223- sed -i " s/project(${TEMPLATE_PROJECT_NAME } /project(${CMAKE_NAME} /" \
266+ sed -i " s/project(${SOURCE_CMAKE_NAME } /project(${CMAKE_NAME} /" \
224267 " ${TARGET_DIR} /CMakeLists.txt"
225268msg_success " CMakeLists.txt: project name -> ${CMAKE_NAME} "
226269
227270# ── 替换项目名: .vscode/launch.json ─────────────────────────────────────────
228- sed -i " s/${TEMPLATE_PROJECT_NAME } /${CMAKE_NAME} /g" \
271+ sed -i " s/${SOURCE_CMAKE_NAME } /${CMAKE_NAME} /g" \
229272 " ${TARGET_DIR} /.vscode/launch.json"
230273msg_success " launch.json: executable -> ${CMAKE_NAME} .elf"
231274
232275# ── 验证替换结果 ─────────────────────────────────────────────────────────────
233- if grep -rq " $TEMPLATE_PROJECT_NAME " " ${TARGET_DIR} /CMakeLists.txt" \
276+ if grep -rq " $SOURCE_CMAKE_NAME " " ${TARGET_DIR} /CMakeLists.txt" \
234277 " ${TARGET_DIR} /.vscode/launch.json" 2> /dev/null; then
235- msg_warn " Some occurrences of '${TEMPLATE_PROJECT_NAME } ' remain. Manual review needed."
278+ msg_warn " Some occurrences of '${SOURCE_CMAKE_NAME } ' remain. Manual review needed."
236279fi
237280
238281# ── 完成 ─────────────────────────────────────────────────────────────────────
0 commit comments