2525# - engine/schema/src/main/resources/META-INF/db/schema-<from>to<to>-cleanup.sql
2626# and wires the new class into DatabaseUpgradeChecker.java (import + .next() entry).
2727#
28+ # Accepts both the legacy 4-position x.y.z.w scheme and the x.y.z scheme CloudStack is
29+ # moving to (dropping the leading "4."), matching what CloudStackVersion.parse() supports.
30+ #
2831# Usage: engine/schema/create-upgrade-path.sh <fromVersion> <toVersion>
29- # Example: engine/schema/create-upgrade-path.sh 4.23.0.0 4. 24.0.0
32+ # Example: engine/schema/create-upgrade-path.sh 4.23.0.0 24.0.0
3033
3134set -euo pipefail
3235
3336usage () {
3437 echo " Usage: $0 <fromVersion> <toVersion>"
35- echo " Example: $0 4.23.0.0 4. 24.0.0"
38+ echo " Example: $0 4.23.0.0 24.0.0"
3639 exit 1
3740}
3841
@@ -41,9 +44,9 @@ usage() {
4144FROM_VERSION=" $1 "
4245TO_VERSION=" $2 "
4346
44- VERSION_REGEX=' ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$'
45- [[ " $FROM_VERSION " =~ $VERSION_REGEX ]] || { echo " Invalid fromVersion '$FROM_VERSION ' (expected x.y.z.w)" ; exit 1; }
46- [[ " $TO_VERSION " =~ $VERSION_REGEX ]] || { echo " Invalid toVersion '$TO_VERSION ' (expected x.y.z.w)" ; exit 1; }
47+ VERSION_REGEX=' ^[0-9]+\.[0-9]+\.[0-9]+( \.[0-9]+)? $'
48+ [[ " $FROM_VERSION " =~ $VERSION_REGEX ]] || { echo " Invalid fromVersion '$FROM_VERSION ' (expected x.y.z or x.y.z .w)" ; exit 1; }
49+ [[ " $TO_VERSION " =~ $VERSION_REGEX ]] || { echo " Invalid toVersion '$TO_VERSION ' (expected x.y.z or x.y.z .w)" ; exit 1; }
4750
4851FROM_COMPACT=" ${FROM_VERSION// ./ } "
4952TO_COMPACT=" ${TO_VERSION// ./ } "
@@ -122,19 +125,37 @@ ${LICENSE_SQL}
122125EOF
123126
124127# 3. Wire the new class into DatabaseUpgradeChecker.java: add the import in its
125- # existing sorted block, and append a .next() entry right before .build().
128+ # existing sorted block, and append a .next() entry right before the upgrade-path
129+ # builder's .build().
126130IMPORT_LINE=" import com.cloud.upgrade.dao.${CLASS_NAME} ;"
127- FIRST_IMPORT_LINE=$( grep -n ' ^import com\.cloud\.upgrade\.dao\.Upgrade' " $CHECKER_FILE " | head -1 | cut -d: -f1)
128- LAST_IMPORT_LINE=$( grep -n ' ^import com\.cloud\.upgrade\.dao\.Upgrade' " $CHECKER_FILE " | tail -1 | cut -d: -f1)
131+ # The `|| true` on each keeps a no-match grep (exit 1, fatal under `set -e -o pipefail`)
132+ # from aborting the script before the guard below gets a chance to print a clear error.
133+ FIRST_IMPORT_LINE=$( grep -n ' ^import com\.cloud\.upgrade\.dao\.Upgrade' " $CHECKER_FILE " | head -1 | cut -d: -f1) || true
134+ LAST_IMPORT_LINE=$( grep -n ' ^import com\.cloud\.upgrade\.dao\.Upgrade' " $CHECKER_FILE " | tail -1 | cut -d: -f1) || true
135+
136+ if [[ -z " $FIRST_IMPORT_LINE " || -z " $LAST_IMPORT_LINE " ]]; then
137+ echo " Could not find any 'import com.cloud.upgrade.dao.Upgrade*;' lines in $CHECKER_FILE " \
138+ " (expected an existing block of upgrade-path imports to insert alongside)."
139+ exit 1
140+ fi
141+
142+ BUILDER_LINE=$( grep -n ' DatabaseVersionHierarchy\.builder()' " $CHECKER_FILE " | head -1 | cut -d: -f1) || true
143+ if [[ -z " $BUILDER_LINE " ]]; then
144+ echo " Could not find the 'DatabaseVersionHierarchy.builder()' line in $CHECKER_FILE " \
145+ " (needed to anchor where the new .next(...) entry gets inserted)."
146+ exit 1
147+ fi
129148
130149SORTED_IMPORTS_FILE=" $( mktemp) "
131- trap ' rm -f "$SORTED_IMPORTS_FILE"' EXIT
150+ TMP_CHECKER=" $( mktemp) "
151+ FINAL_CHECKER=" $( mktemp) "
152+ trap ' rm -f "$SORTED_IMPORTS_FILE" "$TMP_CHECKER" "$FINAL_CHECKER"' EXIT
153+
132154{
133155 grep ' ^import com\.cloud\.upgrade\.dao\.Upgrade' " $CHECKER_FILE "
134156 echo " $IMPORT_LINE "
135157} | sed ' s/;$//' | LC_ALL=C sort -u | sed ' s/$/;/' > " $SORTED_IMPORTS_FILE "
136158
137- TMP_CHECKER=" $( mktemp) "
138159awk -v first=" $FIRST_IMPORT_LINE " -v last=" $LAST_IMPORT_LINE " -v importfile=" $SORTED_IMPORTS_FILE " '
139160 NR == first {
140161 while ((getline line < importfile) > 0) print line
@@ -143,15 +164,26 @@ awk -v first="$FIRST_IMPORT_LINE" -v last="$LAST_IMPORT_LINE" -v importfile="$SO
143164 { print }
144165' " $CHECKER_FILE " > " $TMP_CHECKER "
145166
167+ # Re-locate the builder line in TMP_CHECKER: inserting the new import shifted every
168+ # later line number by one, so the line found earlier in $CHECKER_FILE no longer applies.
169+ BUILDER_LINE_IN_TMP=$( grep -n ' DatabaseVersionHierarchy\.builder()' " $TMP_CHECKER " | head -1 | cut -d: -f1) || true
170+ if [[ -z " $BUILDER_LINE_IN_TMP " ]]; then
171+ echo " Lost track of the 'DatabaseVersionHierarchy.builder()' line while rewriting imports; aborting without touching $CHECKER_FILE ."
172+ exit 1
173+ fi
174+
175+ # Only match .build(); on/after the builder line, so an unrelated .build() call
176+ # elsewhere in the file (before the upgrade-path builder) is never touched.
146177NEXT_LINE=" .next(\" ${FROM_VERSION} \" , new ${CLASS_NAME} ())"
147- awk -v nextline=" $NEXT_LINE " '
148- /^[ \t]*\.build\(\);/ && !inserted {
178+ awk -v builder= " $BUILDER_LINE_IN_TMP " -v nextline=" $NEXT_LINE " '
179+ NR >= builder && /^[ \t]*\.build\(\);/ && !inserted {
149180 print nextline
150181 inserted = 1
151182 }
152183 { print }
153- ' " $TMP_CHECKER " > " $CHECKER_FILE "
154- rm -f " $TMP_CHECKER "
184+ ' " $TMP_CHECKER " > " $FINAL_CHECKER "
185+
186+ mv " $FINAL_CHECKER " " $CHECKER_FILE "
155187
156188echo " Created:"
157189echo " $JAVA_FILE "
0 commit comments