Skip to content

Instantly share code, notes, and snippets.

@Zaperex
Last active August 6, 2024 13:47
Show Gist options
  • Save Zaperex/5cf97c464bb0459e97ad8ebe9ad397d2 to your computer and use it in GitHub Desktop.
Save Zaperex/5cf97c464bb0459e97ad8ebe9ad397d2 to your computer and use it in GitHub Desktop.
backstage package packing
#!/bin/bash
generate_backstage_package(){
PKG_NAME=$1
if [[ $PKG_NAME =~ ^plugin-(.*) ]]; then
cd ${SRC_REPO_PATH}/plugins/${PKG_NAME:7} || return 1
echo "Changed directory to $(pwd)"
else
cd ${SRC_REPO_PATH}/packages/${PKG_NAME} || return 1
echo "Changed directory to $(pwd)"
fi
echo "Building ${PKG_NAME}"
yarn build || return 1
# Extract the name of the resultant tar file
PACKAGE_TAR=$(npm pack . | tail -1)
echo "Generated Tar File: ${PACKAGE_TAR}"
tar -xvzf ${PACKAGE_TAR}
# Remove old extracted tar file if it exists
rm -rf ./${PKG_NAME}
# Extracted tar file will be a `package/` directory
mv -vf ./package ./${PKG_NAME}
# Remove the tar file
rm ${PACKAGE_TAR}
patch_backstage_package ${PKG_NAME}
# Remove extracted tar file after the patches are generated
rm -rf ./${PKG_NAME}
}
replace_references(){
SRC_PACKAGE_PATH=$1
DEST_PACKAGE_PATH=$2
MODULE_TYPE=$3 # cjs or esm
SRC_CJS_PATH="${SRC_PACKAGE_PATH}/dist/${MODULE_TYPE}"
DEST_CJS_PATH="${DEST_PACKAGE_PATH}/dist/${MODULE_TYPE}"
if [ -d "${DEST_CJS_PATH}" ] && [ -d "${SRC_CJS_PATH}" ]; then
# TODO: Grab ALL cjs file names
if [ $(find ${SRC_CJS_PATH} -type f | wc -l) -ne 2 ] || [ $(find ${DEST_CJS_PATH} -type f | wc -l) -ne 2 ]; then
echo "This script only supports file renaming for one pair of files in the dist/${MODULE_TYPE} directory" >&2
echo "It may be necessary to manually rename and update references in ${DEST_CJS_PATH}" >&2
return 1
fi
# FIXME: Add support for when there are more than one pair in the `cjs` directory
FILE_NAME=$(ls "${DEST_PACKAGE_PATH}/dist/${MODULE_TYPE}" | tail -1 | cut -d '.' -f 1);
NEWLY_BUILT_FILE_NAME=$(ls "${SRC_PACKAGE_PATH}/dist/${MODULE_TYPE}" | tail -1 | cut -d '.' -f 1);
echo "Original File Name: ${FILE_NAME}"
echo "Newly Generated File Name: ${NEWLY_BUILT_FILE_NAME}"
echo "Renaming files in the ${SRC_CJS_PATH} directory"
# This makes the assumption that file names do not contains spaces or glob characters
filePair=($(find ${SRC_CJS_PATH} -type f -name ${NEWLY_BUILT_FILE_NAME}.*));
for file in ${filePair[@]}; do
mv -vf "${file}" "${SRC_CJS_PATH}/${FILE_NAME}.${file#*.}"
done;
# Update references to the cjs files
find ${SRC_PACKAGE_PATH} -type f -exec sed -i "s/${NEWLY_BUILT_FILE_NAME}/${FILE_NAME}/g" {} \;
fi
}
patch_backstage_package(){
PKG_NAME=$1
if [[ $PKG_NAME =~ ^plugin-(.*) ]]; then
SRC_PACKAGE_PATH="${SRC_REPO_PATH}/plugins/${PKG_NAME:7}/${PKG_NAME}"
else
SRC_PACKAGE_PATH="${SRC_REPO_PATH}/packages/${PKG_NAME}/${PKG_NAME}"
fi
DEST_PACKAGE_PATH="${DEST_REPO_PATH}/node_modules/@backstage/${PKG_NAME}"
# We want to preserve the name of the files. The only files that have name changes with each rebuilt are
# the files in the `/dist/cjs` directories from backend plugins
# See https://github.com/ds300/patch-package/issues/518
# FIXME: Currently function does not work when there are more than one pair of files in the folder
replace_references ${SRC_PACKAGE_PATH} ${DEST_PACKAGE_PATH} 'cjs'
echo "Performing a diff before the merge (after the file renaming attempt)"
echo "============================================================="
diff -r --brief ${DEST_PACKAGE_PATH} ${SRC_PACKAGE_PATH}
# Snapshot the unpatched package before merging
DEST_PACKAGE_COPY=/tmp/${PKG_NAME}-copy
mkdir ${DEST_PACKAGE_COPY}
rsync -a ${DEST_PACKAGE_PATH}/* ${DEST_PACKAGE_COPY}
echo "============================================================="
echo "Attempt to merge the package contents"
# Merge the packages.
# Note: This will replace the package.json with the one from `yarn build` which may include `^workspace` versions
# This should not matter since the `patch-package` package does not apply diff for `package.json`
if [ -d "${SRC_PACKAGE_PATH}" ] && [ "$(ls -A ${SRC_PACKAGE_PATH})" ]; then
cp -Rv ${SRC_PACKAGE_PATH}/* ${DEST_PACKAGE_PATH}
else
echo "Source directory does not exist or is empty" >&2
fi
echo "Performing a diff between unpatched and patched package after the merge"
echo "============================================================="
diff -r --brief ${DEST_PACKAGE_PATH} ${DEST_PACKAGE_COPY}
rm -rf ${DEST_PACKAGE_COPY}
}
patch_packages(){
cd ${SRC_REPO_PATH} || return 1
echo "Changed directory to $(pwd)"
# Run to regenerates dist types and such.
echo "Running yarn tsc, this might take a minute or two..."
yarn tsc
echo "Generating Patches for the following plugins/packages: ${targetPcks[*]}"
for pck in ${targetPcks[@]}; do
cd ${SRC_REPO_PATH} || continue
echo "Changed directory to $(pwd)"
echo "Generating patches for ${pck}"
generate_backstage_package ${pck}
cd ${DEST_REPO_PATH} || continue
echo "Changed directory to $(pwd)"
yarn patch-package "@backstage/${pck}"
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
done;
}
function display_help() {
echo "A utility script to create patches for packages in the backstage/backstage repository for your backstage instance"
echo
echo "Usage: ./patch-package.sh [src] [dest] [package-name-1] [package-name-2] ..."
echo
echo "src: The root of the backstage monorepo with the patched changes."
echo "dest: The root of the target backstage monorepo containing the node_modules that are to be patched."
echo "package-name-n: a list of package names separated by a space. These should match the package names in the \`node_modules/@backstage\` directory"
printf "\tIf patching a plugin, append a \`plugin-\` to the package name, ex: \`plugin-scaffolder-backend\`."
printf "\n\tIf patching a package, just provide the package name that matches the corresponding package name in the \`node_modules\`, ex: \`integration\`\n"
echo "Please note that if the resultant package has a dist/cjs directory containing more than 2 files, the user will need to manually update file names and references"
}
for arg in "$@"
do
if [[ $arg == "--help" ]]; then
display_help
exit 0
fi
done
if [[ $# -lt 3 ]]; then
echo "Error: Invalid number of arguments." >&2
display_help
exit 1
fi
# Convert to absolute path (if relative path is provided)
SRC_REPO_PATH=$(readlink -f $1)
DEST_REPO_PATH=$(readlink -f $2)
# Shift the first 2 arguments (src and dest)
shift 2
# Store the remaining arguments as package names
targetPcks=("$@")
patch_packages
@Zaperex
Copy link
Author

Zaperex commented Jun 17, 2024

It seems a yarn tsc is necessary for certain changes (such as updates to the types.ts files to appear in the resultant files of a yarn build)

@Zaperex
Copy link
Author

Zaperex commented Jul 30, 2024

Updated the script to provide more verbose logging to indicate what's going on. Also added ability to directly specify packages to patch without needing to edit the script's hard coded package array.
https://gist.github.com/Zaperex/5cf97c464bb0459e97ad8ebe9ad397d2/revisions#diff-4acdf55bd932240e35ca2312a5caa657d26bf5634c3a95d4cab795c13e8e63b0

@Zaperex
Copy link
Author

Zaperex commented Jul 31, 2024

Currently this script only supports patching packages in the /plugins directory of backstage/backstage.

@Zaperex
Copy link
Author

Zaperex commented Jul 31, 2024

Added support for patching packages located in the packages/ directory of backstage/backstage and cleaned. Just append a plugin- prefix to indicate that the package is from the plugins/ directory
https://gist.github.com/Zaperex/5cf97c464bb0459e97ad8ebe9ad397d2/revisions#diff-4acdf55bd932240e35ca2312a5caa657d26bf5634c3a95d4cab795c13e8e63b0

@Zaperex
Copy link
Author

Zaperex commented Jul 31, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment