Last active
March 7, 2022 12:55
-
-
Save 3nids/938119e94ec5119469f3b38d2f85788e to your computer and use it in GitHub Desktop.
QGIS settings migration script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
set -e | |
if [[ $1 == x ]]; then | |
set -x | |
fi | |
MODULE=core | |
MODULE_CODE=Core | |
MODULE_REG_CPP=src/${MODULE}/settings/qgssettingsregistry${MODULE}.cpp | |
MODULE_REG_H=src/${MODULE}/settings/qgssettingsregistry${MODULE}.h | |
DATA_FILE=scripts/settings-migration.dat | |
ALREADY_PROCESSED="-" | |
declare -a SETTING_TYPES=() | |
SETTING_TYPES[0]="EnumFlag::flagValue:setFlagValue" | |
SETTING_TYPES[1]="EnumFlag::enumValue:setEnumValue" | |
SETTING_TYPES[2]="Double:.to(Double|Float)\(\):" | |
SETTING_TYPES[3]="Integer:.toInt\(\):" | |
SETTING_TYPES[4]="String:.toString\(\):" | |
SETTING_TYPES[5]="Bool:.toBool\(\):" | |
SETTING_TYPES[6]="StringList:.toStringList\(\):" | |
declare -a HEADER_OFFSET=() | |
HEADER_OFFSET[0]="qgsrasterlayer.h:6" | |
HEADER_OFFSET[0]="pal.h:18" | |
declare -a ENUM_DEF2TYPE=() | |
# def value in code ! Enum type ! Default value if first is def override | |
ENUM_DEF2TYPE[0]="mSimplifyMethod.simplifyHints()!QgsVectorSimplifyMethod::SimplifyHint!SimplifyHint::NoSimplification" | |
ENUM_DEF2TYPE[1]="mSimplifyMethod.simplifyAlgorithm()!QgsVectorSimplifyMethod::SimplifyAlgorithm!SimplifyAlgorithm::Distance" | |
for _SETTING_TYPE in "${SETTING_TYPES[@]}"; do | |
SETTING_TYPE=$(echo ${_SETTING_TYPE} | cut -d: -f1) | |
SETTING_TYPE_TO=$(echo ${_SETTING_TYPE} | cut -d: -f2) | |
VALUE_GET=$(echo ${_SETTING_TYPE} | cut -d: -f3) | |
VALUE_SET=$(echo ${_SETTING_TYPE} | cut -d: -f4) | |
VALUE_GET=${VALUE_GET:-value} | |
VALUE_SET=${VALUE_SET:-setValue} | |
if [[ $SETTING_TYPE == EnumFlag ]]; then | |
INCLUDE_FILE="qgssettingsentryimpl.h" | |
else | |
INCLUDE_FILE="qgssettingsentryimpl.h" | |
fi | |
while read -u 3 -r LINE; do | |
# echo "****" | |
echo $LINE | |
FILE=$(echo "${LINE}" | cut -d: -f1) | |
CODE=$(echo "${LINE}" | cut -d: -f2,3,4,5,6) | |
SETTING_DEFAULT=$(echo "${CODE}" | gsed -r "s/^.*${VALUE_GET}\( QStringLiteral\( \"([^ ]+)\" \)(, ([^ ]+))?(, QgsSettings::(Section::)?(\w+))? \).*$/\1!\3!\6/") | |
SETTING=$(echo "${SETTING_DEFAULT}" | cut -d! -f1) | |
DEFAULT=$(echo "${SETTING_DEFAULT}" | cut -d! -f2) | |
SECTION=$(echo "${SETTING_DEFAULT}" | cut -d! -f3 | gsed 's/NoSection//') | |
PREFIX_STR=$(echo "$SETTING" | gsed -r 's|(/?%[0-9]+/.*)?/?[^/]+$||; s|^/||') | |
KEY=$(echo "$SETTING" | gsed "s|${PREFIX_STR}/||") | |
if [[ "${ALREADY_PROCESSED}" =~ -${SETTING}- ]]; then | |
echo "$SETTING already processed" | |
else | |
ALREADY_PROCESSED="-${SETTING}${ALREADY_PROCESSED}" | |
VALUE_DEFAULT_OVERRIDE_METHOD="setValue" | |
VALUE_DEFAULT_OVERRIDE_VALUE= | |
ENUM_SPEC= | |
if [[ $SETTING_TYPE == EnumFlag ]]; then | |
for dt in "${ENUM_DEF2TYPE[@]}"; do | |
if [[ $(echo "${dt}" | cut -d! -f1) == "${DEFAULT}" ]]; then | |
ENUM_SPEC="<$(echo "${dt}" | cut -d! -f2)>" | |
NEW_DEFAULT="$(echo "${dt}" | cut -d! -f3)" | |
if [[ -n ${NEW_DEFAULT} ]]; then | |
VALUE_DEFAULT_OVERRIDE_METHOD="valueWithDefaultOverride" | |
VALUE_DEFAULT_OVERRIDE_VALUE=${DEFAULT} | |
DEFAULT=${NEW_DEFAULT} | |
fi | |
break | |
fi | |
done | |
fi | |
if [[ ${DEFAULT} =~ ^m ]]; then | |
VALUE_DEFAULT_OVERRIDE_METHOD="valueWithDefaultOverride" | |
VALUE_DEFAULT_OVERRIDE_VALUE=${DEFAULT} | |
DEFAULT= | |
fi | |
if [[ -z ${DEFAULT} || ${DEFAULT} == "QVariant()" ]]; then | |
if [[ ${SETTING_TYPE} == "StringList" ]]; then | |
DEFAULT="QStringList()" | |
fi | |
if [[ ${SETTING_TYPE} == "String" ]]; then | |
DEFAULT="QString()" | |
fi | |
if [[ ${SETTING_TYPE} == "Double" ]]; then | |
DEFAULT="0.0" | |
fi | |
if [[ ${SETTING_TYPE} == "Integer" ]]; then | |
DEFAULT="0" | |
fi | |
if [[ ${SETTING_TYPE} == "Bool" ]]; then | |
DEFAULT="false" | |
fi | |
fi | |
if [[ ${SETTING_TYPE} == "Integer" ]]; then | |
DEFAULT=$(echo "${DEFAULT}" | gsed 's/"//g') | |
fi | |
#SETTING_VAR_NAME=$(echo "${KEY}" | gsed -r 's/^(.)/\U\1/; s/-') | |
SETTING_VAR_NAME=${KEY} | |
# PREPEND LAST PREFIX PART | |
if [[ ! ${PREFIX_STR} =~ ^(UI|qgis)$ ]]; then | |
SETTING_VAR_NAME=$(echo "${PREFIX_STR}" | gsed 's|^/?(\w+/)+||g'| gsed -r 's/^(.)/\U\1/')$(echo "${SETTING_VAR_NAME}" | gsed -r 's/^(.)/\U\1/') | |
fi | |
SETTING_VAR_NAME="settings"$(echo "${SETTING_VAR_NAME}" | gsed -r 's/^(.*)$/_\1/; s|/|_|g; s/__/_/; s/(_|-)([a-z])/\1\U\2/g; s/(-|_)//g; s/^_//;') | |
PREFIX_STR=$(echo "${SECTION,,}_${PREFIX_STR}" | gsed 's/^_//') | |
PREFIX_VAR=$(echo "${PREFIX_STR}" | gsed -r 's/^(.*)$/_\1/; s|/|_|g; s/__/_/; s/(_|-)([a-z])/\1\U\2/g; s/-//g; s/^_//;' | gsed -r 's/^(.*)$/\U\1/') | |
if [[ -z $PREFIX_STR ]]; then | |
PREFIX_VAR_COMPLETE="QgsSettings::Prefix::NO_PREFIX" | |
PREFIX_VAR="NO_PREFIX" | |
else | |
PREFIX_VAR_COMPLETE="QgsSettings::Prefix::${PREFIX_VAR}" | |
fi | |
# for regexes | |
SETTING_ESC=$(echo "${SETTING}" | gsed 's|/|.|g') | |
HEADER=$(echo ${FILE} | gsed 's|\.cpp$|.h|') | |
BASECLASS=$(basename ${HEADER} | gsed 's/\.h$//') | |
if [[ ! ${HEADER} =~ \.h$ ]]; then | |
echo "wrong header: $HEADER" | |
exit 1 | |
fi | |
# echo "$HEADER $BASECLASS" | |
HAS_CLASS=$(git grep -i -c "^ *class ${MODULE}_EXPORT ${BASECLASS}\b" ${HEADER} | cut -d: -f2) | |
CLASS_DEF=$(git grep -i "^ *class ${MODULE}_EXPORT ${BASECLASS}\b" ${HEADER} | cut -d: -f2 | gsed -r "s/^ *class ${MODULE}_EXPORT (${BASECLASS}).*$/\1/i") | |
echo -e " FILE: $FILE\n SETTING_TYPE: $SETTING_TYPE\n SETTING: $SETTING\n DEFAULT: $DEFAULT\n KEY: $KEY\n PREFIX_STR: $PREFIX_STR\n PREFIX_VAR: $PREFIX_VAR\n SECTION: $SECTION\n CLASS_DEF: $CLASS_DEF\n HAS_CLASS: $HAS_CLASS\n SETTING_VAR_NAME: $SETTING_VAR_NAME\n HEADER: $HEADER\n ENUM_SPEC: $ENUM_SPEC" | |
MODE=0 | |
while read C_LINE; do | |
C_SETTING=$(echo "$C_LINE" | cut -d: -f1) | |
C_ACTION=$(echo "$C_LINE" | cut -d: -f2) | |
if [[ "$C_SETTING" == "$SETTING" ]]; then | |
echo "setting already in config: ${C_ACTION}" | |
MODE="${C_ACTION}" | |
break | |
fi | |
done<${DATA_FILE} | |
if [[ "${MODE}" == 0 ]]; then | |
echo "***" | |
echo -e "Add ${SETTING}" to | |
echo -e " c) class ${CLASS_DEF}" | |
echo -e " r) registry" | |
echo -e " s) skip and continue" | |
echo -e " e) exit" | |
while read -n 1 n; do | |
echo ""0 | |
case $n in | |
c) | |
echo -e "add to class" | |
MODE=class | |
# https://unix.stackexchange.com/a/533708/238014 | |
#gsed -e "/^ *class ${MODULE}_EXPORT ${BASECLASS}/{:a; N; /\n *public:/!ba; a\XXXX" -e '}' ${HEADER} | |
break | |
;; | |
r) | |
echo -e "add to registry" | |
MODE=registry | |
break | |
;; | |
s) | |
echo -e "skip" | |
MODE=SKIP | |
break | |
;; | |
e) | |
exit 1 | |
;; | |
*) invalid option;; | |
esac | |
done | |
fi | |
if [[ ${MODE} != skip ]]; then | |
echo "$SETTING:$MODE" >> ${DATA_FILE} | |
sort -u -o ${DATA_FILE} ${DATA_FILE} | |
if [[ ${MODE} == class ]]; then | |
SETTING_VAR_NAME_COMPLETE="${CLASS_DEF}::${SETTING_VAR_NAME}" | |
SETTING_VAR_NAME_CLASS="${SETTING_VAR_NAME}" | |
SETTING_VAR_NAME_REGISTRY="${CLASS_DEF}::${SETTING_VAR_NAME}" | |
CLASS_FOUND=0 | |
shopt -s nocasematch | |
IFS='' | |
INCLUDE_IMPL_COUNT=$(git grep -c "#include \"${INCLUDE_FILE}\"" ${HEADER} | cut -d: -f2) | |
if [[ -z $INCLUDE_IMPL_COUNT ]]; then | |
OFFSET=20 | |
for hf in "${HEADER_OFFSET[@]}"; do | |
if [[ $(echo "${hf}" | cut -d: -f1) == $(basename ${HEADER}) ]]; then | |
OFFSET=$((${OFFSET}+$(echo "${hf}" | cut -d: -f2))) | |
break | |
fi | |
done | |
gsed -i "${OFFSET} i #include \"${INCLUDE_FILE}\"" ${HEADER} | |
fi | |
LINE_NUMBER=0 | |
while read F_LINE; do | |
((LINE_NUMBER+=1)) | |
if [[ ${CLASS_FOUND} == 0 ]]; then | |
#echo '[[ "'${F_LINE//\"/\\\"g}'" =~ class\ '${MODULE}'_EXPORT\ '${BASECLASS}' ]]' | |
if eval '[[ "'${F_LINE//\"/\\\"g}'" =~ class\ '${MODULE}'_EXPORT\ '${BASECLASS}' ]]'; then | |
echo "CLASS_FOUND" | |
CLASS_FOUND=1 | |
fi | |
else | |
if [[ "${F_LINE}" =~ ^\ *public:$ ]]; then | |
echo "public found" | |
gsed -i "$(( $LINE_NUMBER+2 )) i \ \ \ \ static const inline QgsSettingsEntry${SETTING_TYPE}${ENUM_SPEC} ${SETTING_VAR_NAME} = QgsSettingsEntry${SETTING_TYPE}${ENUM_SPEC}( QStringLiteral( \"${KEY}\" ), ${PREFIX_VAR_COMPLETE}, ${DEFAULT} ) SIP_SKIP;" ${HEADER} | |
break | |
fi | |
fi | |
done < ${HEADER} | |
shopt -u nocasematch | |
else | |
SETTING_VAR_NAME_COMPLETE="QgsSettingsRegistry${MODULE_CODE}::${SETTING_VAR_NAME}" | |
SETTING_VAR_NAME_CLASS="QgsSettingsRegistry${MODULE_CODE}::${SETTING_VAR_NAME}" | |
SETTING_VAR_NAME_REGISTRY="${SETTING_VAR_NAME}" | |
gsed -i "185 i \ \ \ \ static const inline QgsSettingsEntry${SETTING_TYPE}${ENUM_SPEC} ${SETTING_VAR_NAME_REGISTRY} = QgsSettingsEntry${SETTING_TYPE}${ENUM_SPEC}( QStringLiteral( \"${KEY}\" ), ${PREFIX_VAR_COMPLETE}, ${DEFAULT} );" ${MODULE_REG_H} | |
fi | |
PREFIX_DECL_COUNT=$(git grep -c "static const inline char \*${PREFIX_VAR} = \"${PREFIX_STR}\";" src/core/settings/qgssettings.h | cut -d: -f2) | |
if [[ -z $PREFIX_DECL_COUNT ]]; then | |
gsed -i "105 i \ \ \ \ \ \ \ \ static const inline char *${PREFIX_VAR} = \"${PREFIX_STR}\";" src/core/settings/qgssettings.h | |
fi | |
# Add setting to registry | |
HEADER_BASENAME=$(basename ${HEADER}) | |
gsed -i "102 i \ \ addSettingsEntry( \&${SETTING_VAR_NAME_REGISTRY} );" ${MODULE_REG_CPP} | |
INCLUDE_REG_COUNT=$(git grep -c "#include \"${HEADER_BASENAME}\"" ${MODULE_REG_CPP} | cut -d: -f2) | |
if [[ -z $INCLUDE_REG_COUNT ]]; then | |
gsed -i "28 i #include \"${HEADER_BASENAME}\"" ${MODULE_REG_CPP} | |
fi | |
while read -r S_FILE; do | |
if [[ -z ${S_FILE} ]]; then continue; fi | |
SVARNAME=$([[ ${S_FILE} =~ ${HEADER} ]] && echo "${SETTING_VAR_NAME}" || echo "${SETTING_VAR_NAME_COMPLETE}") | |
echo "fixing ${S_FILE} with $SVARNAME" | |
gsed -i -r "s/(QgsSettings|QSettings|mSettings|settings)\.${VALUE_GET}\( QStringLiteral. .${SETTING_ESC}. \)(, ([^ ]+))* \)${SETTING_TYPE_TO}/${SVARNAME}.${VALUE_DEFAULT_OVERRIDE_METHOD}(${VALUE_DEFAULT_OVERRIDE_VALUE})/" ${S_FILE} | |
gsed -i -r "s/(QgsSettings|QSettings|mSettings|settings)\.${VALUE_SET}\( QStringLiteral. .${SETTING_ESC}. \), ([^ ]+)(, ([^ ]+))? \)/${SVARNAME}.setValue( \2 )/" ${S_FILE} | |
if [[ ${MODE} == registry ]]; then | |
INCLUDE_IMPL_COUNT=$(git grep -c "#include \"qgssettingsregistry${MODULE}.h\"" ${S_FILE} | cut -d: -f2) | |
if [[ -z $INCLUDE_IMPL_COUNT ]]; then | |
gsed -i "20 i #include \"qgssettingsregistry${MODULE}.h\"" ${S_FILE} | |
fi | |
fi | |
done<<<$(git grep -E -c "${SETTING_ESC}" src | cut -d: -f1) | |
fi | |
git add src python tests | |
git commit -m "migrate setting ${SETTING} to ${MODE} (${SETTING_TYPE}, ${MODULE})" | |
fi | |
done 3< <( unbuffer ag --noaffinity --only-matching --nonumber --no-group --nocolor -G '\.cpp$' "settings\.${VALUE_GET}\( QStringLiteral\( \"[^ ]+\" \)(, [^ ]+)+ \)${SETTING_TYPE_TO}" src/${MODULE}) | |
done | |
# cleanup | |
while read -r FILE; do | |
if [[ $FILE =~ ^src/core/settings ]]; then | |
echo "skip $FILE" | |
continue | |
fi | |
echo "clean $FILE" | |
gsed -i -r '/^ *(const *)?QgsSettings (s|mS)ettings;/d' $FILE | |
done<<<$(ag -c QgsSettings src/${MODULE} | cut -d: -f1) | |
git add src | |
git commit -m "clean up QgsSettings in src/${MODULE}" | |
exit 0 | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment