From c13209a639d28c22d8a04f3c6367566268337c4b Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Fri, 30 Jun 2023 11:55:44 +0200 Subject: [PATCH 01/26] WIP script for managing Blender project folders and deployment --- .../project-helper-tools/consistency_check.py | 81 +++++++ .../project-helper-tools/rollback_blender.sh | 72 ++++++ scripts/project-helper-tools/run_blender.py | 219 ++++++++++++++++++ scripts/project-helper-tools/run_blender.sh | 66 ++++++ scripts/project-helper-tools/update_addons.sh | 29 +++ .../project-helper-tools/update_blender.sh | 69 ++++++ 6 files changed, 536 insertions(+) create mode 100755 scripts/project-helper-tools/consistency_check.py create mode 100755 scripts/project-helper-tools/rollback_blender.sh create mode 100755 scripts/project-helper-tools/run_blender.py create mode 100755 scripts/project-helper-tools/run_blender.sh create mode 100755 scripts/project-helper-tools/update_addons.sh create mode 100755 scripts/project-helper-tools/update_blender.sh diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-helper-tools/consistency_check.py new file mode 100755 index 00000000..3199d03b --- /dev/null +++ b/scripts/project-helper-tools/consistency_check.py @@ -0,0 +1,81 @@ +#!/usr/bin/python3 + +import os +import pathlib + +def create_path_dict(startpath, max_depth): + path_stucture_dict={} + start_folder_name = os.path.basename(start_search_path) + for root, dirs, files in os.walk(startpath, followlinks=True): + # We are only interested in the files and folders inside the start path. + cur_path = root.replace(startpath, start_folder_name) + level = cur_path.count(os.sep) + # Sanity check. We don't expect the directory tree to be too deep. + # Therefore, we will stop if we go too deep. + # This avoids infinite loops that can happen when we follow symlinks + if level > max_depth: + print("We have gone unexptibly deep in the file structure, stopping...") + exit(1) + + # Insert the data into the dictionary + nested_dict = path_stucture_dict + key_path = cur_path.split(os.sep) + final_key = key_path[-1] + for key in key_path[:-1]: + nested_dict = nested_dict[key] + + files_dict = {} + for f in files: + files_dict[f] = "file" + + nested_dict[final_key] = files_dict + + # Print the files structure to we can see the traversed file tree + indent = ' ' * 4 * (level) + print('{}{}/'.format(indent, os.path.basename(root))) + subindent = ' ' * 4 * (level + 1) + + for f in files: + print('{}{}'.format(subindent, f)) + return path_stucture_dict + +def check_if_structure_is_consistent(start_path, path_dict, error_list): + for key in path_dict: + cur_path = str(start_path) + os.sep + key + print("Checking path: " + cur_path) + if os.path.exists(cur_path): + nested_item = path_dict[key] + if type(nested_item) is not dict: + if os.path.isfile(cur_path): + continue + else: + # This must be a file, warn if it is not + #print("ERROR: " + cur_path + " is not a file, when it should be!") + error_list += ["ERROR: " + cur_path + " is not a file, when it should be!"] + check_if_structure_is_consistent(cur_path, nested_item, error_list) + else: + #print("ERROR: " + cur_path + " doesn't exist!") + error_list += ["ERROR: " + cur_path + " doesn't exist!"] + +current_file_path=pathlib.Path(__file__) +start_search_path=current_file_path.parent.parent.parent.resolve() +#path_dict = create_path_dict(str(start_search_path), 5) + +# path_dict pre-generated. This is the stucture the consistency check will ensure is there +path_dict = {'pets': {'shared': {'pets': {'artifacts': {}}}, 'svn': {'tools': {'consistency_check.py': 'file'}}, 'local': {'blender': {}, 'scripts': {}, 'config': {}}}} +# TODO perhaps make a function to pretty print out the path_dict for easier inspection + +error_list = [] +check_if_structure_is_consistent(start_search_path.parent, path_dict, error_list) + +print() +if len(error_list) == 0: + print("Consistency check: PASSED") + exit(0) +else: + print("Consistency check: FAILED") + print() + for error in error_list: + print(error) +# Exit with error as we didn't pass the consistency check +exit(1) diff --git a/scripts/project-helper-tools/rollback_blender.sh b/scripts/project-helper-tools/rollback_blender.sh new file mode 100755 index 00000000..c43de309 --- /dev/null +++ b/scripts/project-helper-tools/rollback_blender.sh @@ -0,0 +1,72 @@ +#!/bin/bash + +# Get all archived sha hashes to use as ID numbers + +ARCHIVE_DIR=../../shared/pets/artifacts/blender/previous/ + +cd $ARCHIVE_DIR + +# TODO only rollbacks for one OS version + +OS=linux + +# Create an array with the available builds/files +available_builds=($(ls -t *$OS*.sha256)) + +installed_build=$(cd ../ && ls *$OS*.sha256) + +echo $installed_build + +echo -e "Available builds:\n" + +valid_ids=() + +ITER=0 + +for file in ${available_builds[@]}; do + file_date=$(stat -c '%y' $file) + # Cutoff the the date string to only show "date hours:min" + file_date=${file_date:0:19} + if [ $file == $installed_build ]; then + printf "\e[1mID:\e[0m \e[100m%3s " $ITER + printf "(%s)" "$file_date" + printf " \e[0m" + else + printf "\e[1mID:\e[0m %3s " $ITER + printf "(%s)" "$file_date" + fi + valid_ids+=($ITER) + echo + ITER=$(expr $ITER + 1) +done + +echo -e "\n" + +choosen_blend_id=-1 + +prompt="Select which Blender build number to switch to. (press ENTER to confirm): " +while read -rp "$prompt" num && [[ "$num" ]]; do + + # Check if "num" is a valid number. + [[ "$num" != *[[:digit:]]* ]] && + { echo "You need to choose a number!"; continue; } + + if [[ ! " ${valid_ids[*]} " =~ " ${num} " ]]; then + # whatever you want to do when array doesn't contain value + echo "$num is not an available ID!" + continue + fi + + choosen_blend_id=$num + + break +done + +((choosen_blend_id < 0)) && exit 0 + +choose_file=${available_builds[$choosen_blend_id]::-7} + +# Remove the build we are replacing +rm ../*$OS* +# Copy over the choosen build +cp $choose_file* ../ diff --git a/scripts/project-helper-tools/run_blender.py b/scripts/project-helper-tools/run_blender.py new file mode 100755 index 00000000..bbb878c0 --- /dev/null +++ b/scripts/project-helper-tools/run_blender.py @@ -0,0 +1,219 @@ +#!/usr/bin/env python3 + +import hashlib +import logging +import os +import platform +import shutil +import subprocess +import sys +import tempfile +import zipfile + +from dataclasses import dataclass +from pathlib import Path + + +# The project base path (where shared, local and svn are located) +PATH_BASE = Path(__file__).resolve().parent.parent.parent +PATH_ARTIFACTS = PATH_BASE / 'shared' / 'artifacts' +PATH_LOCAL = PATH_BASE / 'local' + + +def setup_logger(): + # Create a logger + logger = logging.getLogger() + logger.setLevel(logging.DEBUG) + + # Create a StreamHandler that outputs log messages to stdout + stream_handler = logging.StreamHandler(sys.stdout) + stream_handler.setLevel(logging.DEBUG) + + # Create a formatter for the log messages + formatter = logging.Formatter('%(levelname)s - %(message)s') + + # Set the formatter for the StreamHandler + stream_handler.setFormatter(formatter) + + # Add the StreamHandler to the logger + logger.addHandler(stream_handler) + + return logger + + +logger = setup_logger() + + +@dataclass +class BlenderBuild: + archive: None + checksum: None + + +def extract_dmg(dmg_file: Path, internal_pah, dst_path: Path): + # Execute hdiutil to mount the dmg file + mount_process = subprocess.run(['hdiutil', 'attach', dmg_file, '-plist'], capture_output=True, text=True) + mount_output = mount_process.stdout + + # Parse the mount_output to retrieve the mounted volume name + import plistlib + plist_data = plistlib.loads(mount_output.encode('utf-8')) + mount_point = plist_data['system-entities'][0]['mount-point'] + + # Ensure destination directory exists + dst_path = dst_path / internal_pah + dst_path.mkdir(parents=True, exist_ok=True) + + # Extract the contents of the mounted dmg to the destination directory + file_in_dmg = os.path.join(mount_point, internal_pah) + subprocess.run(['ditto', file_in_dmg, dst_path]) + + # Unmount the dmg file + subprocess.run(['hdiutil', 'detach', mount_point]) + + +def extract_tar_xz(file_path: Path, dst_path: Path): + dst_path.mkdir(parents=True, exist_ok=True) + subprocess.run(['tar', 'xf', file_path, '--directory', dst_path, '--strip-components=1']) + + +def extract_zip(file_path: Path, dst_path: Path): + temp_dir = tempfile.mkdtemp() + with zipfile.ZipFile(file_path, 'r') as zip_ref: + zip_ref.extractall(temp_dir) + + try: + src_path = [subdir for subdir in Path(temp_dir).iterdir()][0] + except IndexError: + logger.fatal("The archive %s does not contain any directory" % file_path.name) + sys.exit(1) + + dst_path.mkdir(parents=True, exist_ok=True) + shutil.move(src_path, dst_path) + + shutil.rmtree(temp_dir) + + +def compare_checksum(file1, file2): + with open(file1, 'rb') as f1, open(file2, 'rb') as f2: + hash1 = hashlib.sha256(f1.read()).hexdigest() + hash2 = hashlib.sha256(f2.read()).hexdigest() + + return hash1 == hash2 + + +def update_addons(): + # Check if we have the latest add-ons from shared + studio_pipeline_artifacts = PATH_ARTIFACTS / 'blender-studio-pipeline' + artifact_checksum = studio_pipeline_artifacts / 'main.zip.sha256' + + if not artifact_checksum.exists(): + logger.error("Missing file %s" % artifact_checksum) + logger.error("Could not update add-ons") + return + + local_checksum = PATH_LOCAL / 'main.zip.sha256' + + if local_checksum.exists(): + if compare_checksum(local_checksum, artifact_checksum): + logger.info("Already up to date") + return + + # Extract the archive in a temp location and move the addons content to local + tmp_dir = Path(tempfile.mkdtemp()) + + # Extract the zip file to the temporary directory + with zipfile.ZipFile(studio_pipeline_artifacts / 'main.zip', 'r') as zip_ref: + zip_ref.extractall(tmp_dir) + + # Get the path of the folder to copy + src_path_base = tmp_dir / 'blender-studio-pipeline' / 'scripts-blender' / 'addons' + dst_path_base = PATH_LOCAL / 'scripts' / 'addons' + + # Get a list of directories inside the given directory + addons = [subdir.name for subdir in src_path_base.iterdir() if subdir.is_dir()] + + for addon_name in addons: + logger.debug("Moving %s" % addon_name) + src_dir_addon = src_path_base / addon_name + dst_dir_addon = dst_path_base / addon_name + if dst_dir_addon.exists(): + shutil.rmtree(dst_dir_addon) + shutil.move(src_dir_addon, dst_dir_addon) + + # Clean up the temporary directory + shutil.rmtree(tmp_dir) + + # Update the sha256 file + shutil.copy(artifact_checksum, local_checksum) + + +def update_blender(): + system_name = platform.system().lower() + architecture = platform.machine() + + # Check if we have the latest add-ons from shared + artifacts_path = PATH_ARTIFACTS / 'blender' + + blender_build = BlenderBuild + + # Iterate over the files in the source directory + for file_path in artifacts_path.iterdir(): + if file_path.is_file() \ + and system_name in file_path.name \ + and architecture in file_path.name \ + and file_path.name.endswith('sha256'): + blender_build.checksum = file_path.name + blender_build.archive = file_path.with_suffix('') + break + + artifact_checksum = artifacts_path / blender_build.checksum + + if not artifact_checksum.exists(): + logger.error("Missing file %s" % artifact_checksum) + logger.error("Could not update add-ons") + return + + local_checksum = PATH_LOCAL / 'blender' / f"{system_name}.sha256" + + if local_checksum.exists(): + if compare_checksum(local_checksum, artifact_checksum): + logger.info("Already up to date") + return + + src = artifacts_path / blender_build.archive + dst = PATH_LOCAL / 'blender' / system_name + + if system_name == 'linux': + extract_tar_xz(src, dst) + elif system_name == 'darwin': + extract_dmg(src, 'Blender.app', dst) + elif system_name == 'windows': + extract_zip(src, dst) + shutil.copy(artifact_checksum, local_checksum) + + +def launch_blender(): + system_name = platform.system().lower() + blender_path_base = PATH_LOCAL / 'blender' / system_name + if system_name == 'linux': + blender_path = blender_path_base / 'blender' + elif system_name == 'darwin': + blender_path = blender_path_base / 'Blender.app' / 'Contents' / 'MacOS' / 'Blender' + elif system_name == 'windows': + blender_path = blender_path_base / 'blender.exe' + else: + sys.exit(1) + + # os.environ['BLENDER_USER_CONFIG'] = str(PATH_LOCAL / 'config') + os.environ['BLENDER_USER_SCRIPTS'] = str(PATH_LOCAL / 'scripts') + subprocess.run([blender_path]) + + +if __name__ == '__main__': + logger.info('Update Add-ons') + update_addons() + logger.info('Update Blender') + update_blender() + logger.info('Launch Blender') + launch_blender() diff --git a/scripts/project-helper-tools/run_blender.sh b/scripts/project-helper-tools/run_blender.sh new file mode 100755 index 00000000..c4d2d346 --- /dev/null +++ b/scripts/project-helper-tools/run_blender.sh @@ -0,0 +1,66 @@ +#!/bin/bash + +# TODO error out if blender is not installed locally already and there is no blender to download on shared + +cur_dir=$(pwd) + +cd ../../local + +DOWNLOAD_DIR=../shared/pets + +update_addons() { + zip_name="main.zip" + + # Check if we have the latest addons from shared + if [ -f $zip_name.sha256 ]; then + shasum=$(cat $zip_name.sha256) + pushd $DOWNLOAD_DIR/addons + echo $shasum | sha256sum --check - && echo addons already at the latest version && popd && return 0 + popd + fi + + rm -fr ./scripts/* + + extract_folder="blender-studio-pipeline/scripts-blender/addons" + + # Record the extracted content + # Remove the first 5 lines, remove the last two lines, and extract the fourth column + unzip -l $DOWNLOAD_DIR/addons/$zip_name "$extract_folder/*" | tail -n +5 | head -n -2 | awk '{ print $4 }' > $zip_name.contents + + unzip $DOWNLOAD_DIR/addons/$zip_name "$extract_folder/*" -d "./scripts" + mv ./scripts/$extract_folder ./scripts/ + rm -fr ./scripts/blender-studio-pipeline + cp $DOWNLOAD_DIR/addons/$zip_name.sha256 . +} + +update_blender() { + os=linux + + # Ensure the os folder exists + mkdir -p blender/$os + + if [ -f blender/$os.sha256 ]; then + shasum=$(cat blender/$os.sha256) + pushd $DOWNLOAD_DIR/artifacts/blender + echo $shasum *$os*.tar.xz | sha256sum --check - && echo blender already at the latest version && popd && return 0 + popd + fi + + rm -fr blender/$os/* + + echo Extracting Blender + tar xf $DOWNLOAD_DIR/artifacts/blender/*$os*.tar.xz --directory blender/$os/ --strip-components=1 --checkpoint=.1000 + cp $DOWNLOAD_DIR/artifacts/blender/*$os*.sha256 blender/$os.sha256 +} + +update_addons +update_blender + +os=linux +cd blender/$os + +export BLENDER_USER_CONFIG=../../config +export BLENDER_USER_SCRIPTS=../../scripts + +# Actually launch Blender +./blender diff --git a/scripts/project-helper-tools/update_addons.sh b/scripts/project-helper-tools/update_addons.sh new file mode 100755 index 00000000..e6a26fc7 --- /dev/null +++ b/scripts/project-helper-tools/update_addons.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +DOWNLOAD_DIR=../../shared/pets/artifacts/addons/ + +download_addon() { + URL=$1 + OUT_NAME=$2 + + # Ensure that the download directory exists + mkdir -p $DOWNLOAD_DIR + + # Switch to the download directory + pushd $DOWNLOAD_DIR + + # TODO Can't check any shasums before downloading so always remove and redownload everything for now + rm $OUT_NAME* + + # Download the addons repo + wget $URL -O $OUT_NAME + sha256sum *.zip > $OUT_NAME.sha256 + + popd +} + +# download_addon + +# Special download dir for monorepo with addons +DOWNLOAD_DIR=../../shared/pets/artifacts/blender-studio-pipeline/ +download_addon https://projects.blender.org/studio/blender-studio-pipeline/archive/main.zip blender-studio-pipeline-main.zip diff --git a/scripts/project-helper-tools/update_blender.sh b/scripts/project-helper-tools/update_blender.sh new file mode 100755 index 00000000..66cca25d --- /dev/null +++ b/scripts/project-helper-tools/update_blender.sh @@ -0,0 +1,69 @@ +#!/bin/bash + +# Stop execution on error +set -e + +HOMEPAGE="https://builder.blender.org/download/" + +BLENDER_BRANCH=main +DOWNLOAD_DIR=../../shared/pets/artifacts/blender + +# Ensure that the download directory exists +mkdir -p $DOWNLOAD_DIR + +# Switch to the download directory +pushd $DOWNLOAD_DIR + +# .zip == Windows +# .dmg == Mac +# .tar.xz == Linux + +# Create a dictinary with the above information +declare -A extensions +extensions=( ["windows"]="zip" ["darwin.x86_64"]="dmg" ["darwin.arm64"]="dmg" ["linux"]="tar.xz" ) + +latest_urls=$(wget --quiet -O - "$HOMEPAGE" | \ + grep -io ' Date: Tue, 4 Jul 2023 16:23:12 +0200 Subject: [PATCH 02/26] Add formatter settings files for black and pycodestyle --- scripts/project-helper-tools/pyproject.toml | 4 ++++ scripts/project-helper-tools/setup.cfg | 2 ++ 2 files changed, 6 insertions(+) create mode 100644 scripts/project-helper-tools/pyproject.toml create mode 100644 scripts/project-helper-tools/setup.cfg diff --git a/scripts/project-helper-tools/pyproject.toml b/scripts/project-helper-tools/pyproject.toml new file mode 100644 index 00000000..6970e018 --- /dev/null +++ b/scripts/project-helper-tools/pyproject.toml @@ -0,0 +1,4 @@ +[tool.black] +line-length = 100 +include = '\.pyi?$' +skip-string-normalization = true diff --git a/scripts/project-helper-tools/setup.cfg b/scripts/project-helper-tools/setup.cfg new file mode 100644 index 00000000..62e73811 --- /dev/null +++ b/scripts/project-helper-tools/setup.cfg @@ -0,0 +1,2 @@ +[pycodestyle] +max-line-length = 100 -- 2.30.2 From 29eb4cfe518ceeb8cc7d1a99d995aa673a071837 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 4 Jul 2023 16:23:57 +0200 Subject: [PATCH 03/26] Apply Black formatting on all python files --- .../project-helper-tools/consistency_check.py | 23 +++++++++++++------ scripts/project-helper-tools/run_blender.py | 15 ++++++++---- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-helper-tools/consistency_check.py index 3199d03b..cba3f425 100755 --- a/scripts/project-helper-tools/consistency_check.py +++ b/scripts/project-helper-tools/consistency_check.py @@ -3,8 +3,9 @@ import os import pathlib + def create_path_dict(startpath, max_depth): - path_stucture_dict={} + path_stucture_dict = {} start_folder_name = os.path.basename(start_search_path) for root, dirs, files in os.walk(startpath, followlinks=True): # We are only interested in the files and folders inside the start path. @@ -39,6 +40,7 @@ def create_path_dict(startpath, max_depth): print('{}{}'.format(subindent, f)) return path_stucture_dict + def check_if_structure_is_consistent(start_path, path_dict, error_list): for key in path_dict: cur_path = str(start_path) + os.sep + key @@ -50,19 +52,26 @@ def check_if_structure_is_consistent(start_path, path_dict, error_list): continue else: # This must be a file, warn if it is not - #print("ERROR: " + cur_path + " is not a file, when it should be!") + # print("ERROR: " + cur_path + " is not a file, when it should be!") error_list += ["ERROR: " + cur_path + " is not a file, when it should be!"] check_if_structure_is_consistent(cur_path, nested_item, error_list) else: - #print("ERROR: " + cur_path + " doesn't exist!") + # print("ERROR: " + cur_path + " doesn't exist!") error_list += ["ERROR: " + cur_path + " doesn't exist!"] -current_file_path=pathlib.Path(__file__) -start_search_path=current_file_path.parent.parent.parent.resolve() -#path_dict = create_path_dict(str(start_search_path), 5) + +current_file_path = pathlib.Path(__file__) +start_search_path = current_file_path.parent.parent.parent.resolve() +# path_dict = create_path_dict(str(start_search_path), 5) # path_dict pre-generated. This is the stucture the consistency check will ensure is there -path_dict = {'pets': {'shared': {'pets': {'artifacts': {}}}, 'svn': {'tools': {'consistency_check.py': 'file'}}, 'local': {'blender': {}, 'scripts': {}, 'config': {}}}} +path_dict = { + 'pets': { + 'shared': {'pets': {'artifacts': {}}}, + 'svn': {'tools': {'consistency_check.py': 'file'}}, + 'local': {'blender': {}, 'scripts': {}, 'config': {}}, + } +} # TODO perhaps make a function to pretty print out the path_dict for easier inspection error_list = [] diff --git a/scripts/project-helper-tools/run_blender.py b/scripts/project-helper-tools/run_blender.py index bbb878c0..d97f5a4c 100755 --- a/scripts/project-helper-tools/run_blender.py +++ b/scripts/project-helper-tools/run_blender.py @@ -52,11 +52,14 @@ class BlenderBuild: def extract_dmg(dmg_file: Path, internal_pah, dst_path: Path): # Execute hdiutil to mount the dmg file - mount_process = subprocess.run(['hdiutil', 'attach', dmg_file, '-plist'], capture_output=True, text=True) + mount_process = subprocess.run( + ['hdiutil', 'attach', dmg_file, '-plist'], capture_output=True, text=True + ) mount_output = mount_process.stdout # Parse the mount_output to retrieve the mounted volume name import plistlib + plist_data = plistlib.loads(mount_output.encode('utf-8')) mount_point = plist_data['system-entities'][0]['mount-point'] @@ -159,10 +162,12 @@ def update_blender(): # Iterate over the files in the source directory for file_path in artifacts_path.iterdir(): - if file_path.is_file() \ - and system_name in file_path.name \ - and architecture in file_path.name \ - and file_path.name.endswith('sha256'): + if ( + file_path.is_file() + and system_name in file_path.name + and architecture in file_path.name + and file_path.name.endswith('sha256') + ): blender_build.checksum = file_path.name blender_build.archive = file_path.with_suffix('') break -- 2.30.2 From 522a408ffcf61a237a6a384cbaecd4a7a6f84e85 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 4 Jul 2023 18:42:49 +0200 Subject: [PATCH 04/26] Update consistency_check.py and run_blender.py --- .../project-helper-tools/consistency_check.py | 3 +- scripts/project-helper-tools/run_blender.py | 88 ++++++++++++------- 2 files changed, 59 insertions(+), 32 deletions(-) diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-helper-tools/consistency_check.py index cba3f425..d61d8950 100755 --- a/scripts/project-helper-tools/consistency_check.py +++ b/scripts/project-helper-tools/consistency_check.py @@ -65,9 +65,10 @@ start_search_path = current_file_path.parent.parent.parent.resolve() # path_dict = create_path_dict(str(start_search_path), 5) # path_dict pre-generated. This is the stucture the consistency check will ensure is there +# TODO don't record or check the projects name. path_dict = { 'pets': { - 'shared': {'pets': {'artifacts': {}}}, + 'shared': {'artifacts': {}}, 'svn': {'tools': {'consistency_check.py': 'file'}}, 'local': {'blender': {}, 'scripts': {}, 'config': {}}, } diff --git a/scripts/project-helper-tools/run_blender.py b/scripts/project-helper-tools/run_blender.py index d97f5a4c..3f4d0efe 100755 --- a/scripts/project-helper-tools/run_blender.py +++ b/scripts/project-helper-tools/run_blender.py @@ -1,5 +1,6 @@ #!/usr/bin/env python3 +import glob import hashlib import logging import os @@ -10,7 +11,6 @@ import sys import tempfile import zipfile -from dataclasses import dataclass from pathlib import Path @@ -44,12 +44,6 @@ def setup_logger(): logger = setup_logger() -@dataclass -class BlenderBuild: - archive: None - checksum: None - - def extract_dmg(dmg_file: Path, internal_pah, dst_path: Path): # Execute hdiutil to mount the dmg file mount_process = subprocess.run( @@ -77,7 +71,17 @@ def extract_dmg(dmg_file: Path, internal_pah, dst_path: Path): def extract_tar_xz(file_path: Path, dst_path: Path): dst_path.mkdir(parents=True, exist_ok=True) - subprocess.run(['tar', 'xf', file_path, '--directory', dst_path, '--strip-components=1']) + subprocess.run( + [ + 'tar', + 'xf', + file_path, + '--directory', + dst_path, + '--strip-components=1', + '--checkpoint=.1000', + ] + ) def extract_zip(file_path: Path, dst_path: Path): @@ -109,6 +113,7 @@ def update_addons(): # Check if we have the latest add-ons from shared studio_pipeline_artifacts = PATH_ARTIFACTS / 'blender-studio-pipeline' artifact_checksum = studio_pipeline_artifacts / 'main.zip.sha256' + artifact_archive = artifact_checksum.with_suffix('') if not artifact_checksum.exists(): logger.error("Missing file %s" % artifact_checksum) @@ -122,6 +127,11 @@ def update_addons(): logger.info("Already up to date") return + if not artifact_archive.exists(): + logger.error("Shasum exists but the archive file %s does not!" % artifact_archive) + logger.error("Could not update add-ons") + return + # Extract the archive in a temp location and move the addons content to local tmp_dir = Path(tempfile.mkdtemp()) @@ -133,15 +143,25 @@ def update_addons(): src_path_base = tmp_dir / 'blender-studio-pipeline' / 'scripts-blender' / 'addons' dst_path_base = PATH_LOCAL / 'scripts' / 'addons' + # Remove all files previously installed by the archive + local_installed_files = PATH_LOCAL / 'main.zip.files' + if local_installed_files.exists(): + with open(local_installed_files) as file: + lines = [line.rstrip() for line in file] + for folder in lines: + shutil.rmtree(PATH_LOCAL / folder) + # Get a list of directories inside the given directory addons = [subdir.name for subdir in src_path_base.iterdir() if subdir.is_dir()] + with open(local_installed_files, 'w') as f: + for addon_name in addons: + f.write("%s\n" % addon_name) + for addon_name in addons: logger.debug("Moving %s" % addon_name) src_dir_addon = src_path_base / addon_name dst_dir_addon = dst_path_base / addon_name - if dst_dir_addon.exists(): - shutil.rmtree(dst_dir_addon) shutil.move(src_dir_addon, dst_dir_addon) # Clean up the temporary directory @@ -155,39 +175,45 @@ def update_blender(): system_name = platform.system().lower() architecture = platform.machine() - # Check if we have the latest add-ons from shared + # Check if we have the latest blender archive from shared artifacts_path = PATH_ARTIFACTS / 'blender' - blender_build = BlenderBuild + # Look for the appropriate Blender archive for this system + matched_archives = glob.glob("blender*" + system_name + "." + architecture + "*.sha256") - # Iterate over the files in the source directory - for file_path in artifacts_path.iterdir(): - if ( - file_path.is_file() - and system_name in file_path.name - and architecture in file_path.name - and file_path.name.endswith('sha256') - ): - blender_build.checksum = file_path.name - blender_build.archive = file_path.with_suffix('') - break + # Check if we found any files + if len(matched_archives) != 1: + if len(matched_archives) == 0: + logger.error("No Blender archives found for this system!") + logger.error("System is: %s %s" % system_name, architecture) + return + else: + logger.error( + "More than one candidate archive was found for this system. Only one is allowed!" + ) + logger.error("The following candidates were found: %s" % str(matched_archives)) + return - artifact_checksum = artifacts_path / blender_build.checksum + blender_build_checksum = Path(matched_archives[0]) + blender_build_archive = blender_build_checksum.with_suffix('') - if not artifact_checksum.exists(): - logger.error("Missing file %s" % artifact_checksum) - logger.error("Could not update add-ons") + if not blender_build_archive.exists(): + logger.error( + "Shasum exists but the target Blender archive %s does not!" % blender_build_archive + ) + logger.error("Could not update blender") return local_checksum = PATH_LOCAL / 'blender' / f"{system_name}.sha256" if local_checksum.exists(): - if compare_checksum(local_checksum, artifact_checksum): + if compare_checksum(local_checksum, blender_build_checksum): logger.info("Already up to date") return - src = artifacts_path / blender_build.archive + src = artifacts_path / blender_build_archive dst = PATH_LOCAL / 'blender' / system_name + shutil.rmtree(dst) if system_name == 'linux': extract_tar_xz(src, dst) @@ -195,7 +221,7 @@ def update_blender(): extract_dmg(src, 'Blender.app', dst) elif system_name == 'windows': extract_zip(src, dst) - shutil.copy(artifact_checksum, local_checksum) + shutil.copy(blender_build_checksum, local_checksum) def launch_blender(): @@ -210,7 +236,7 @@ def launch_blender(): else: sys.exit(1) - # os.environ['BLENDER_USER_CONFIG'] = str(PATH_LOCAL / 'config') + os.environ['BLENDER_USER_CONFIG'] = str(PATH_LOCAL / 'config') os.environ['BLENDER_USER_SCRIPTS'] = str(PATH_LOCAL / 'scripts') subprocess.run([blender_path]) -- 2.30.2 From 503fb57aaaa2b956b26020a37a47ef509eb96de9 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 4 Jul 2023 18:50:18 +0200 Subject: [PATCH 05/26] Update download scripts to the update folder structure --- scripts/project-helper-tools/update_addons.sh | 4 ++-- scripts/project-helper-tools/update_blender.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/project-helper-tools/update_addons.sh b/scripts/project-helper-tools/update_addons.sh index e6a26fc7..d40ee2a8 100755 --- a/scripts/project-helper-tools/update_addons.sh +++ b/scripts/project-helper-tools/update_addons.sh @@ -1,6 +1,6 @@ #!/bin/bash -DOWNLOAD_DIR=../../shared/pets/artifacts/addons/ +DOWNLOAD_DIR=../../shared/artifacts/addons/ download_addon() { URL=$1 @@ -25,5 +25,5 @@ download_addon() { # download_addon # Special download dir for monorepo with addons -DOWNLOAD_DIR=../../shared/pets/artifacts/blender-studio-pipeline/ +DOWNLOAD_DIR=../../shared/artifacts/blender-studio-pipeline/ download_addon https://projects.blender.org/studio/blender-studio-pipeline/archive/main.zip blender-studio-pipeline-main.zip diff --git a/scripts/project-helper-tools/update_blender.sh b/scripts/project-helper-tools/update_blender.sh index 66cca25d..ef2b95f3 100755 --- a/scripts/project-helper-tools/update_blender.sh +++ b/scripts/project-helper-tools/update_blender.sh @@ -6,7 +6,7 @@ set -e HOMEPAGE="https://builder.blender.org/download/" BLENDER_BRANCH=main -DOWNLOAD_DIR=../../shared/pets/artifacts/blender +DOWNLOAD_DIR=../../shared/artifacts/blender # Ensure that the download directory exists mkdir -p $DOWNLOAD_DIR -- 2.30.2 From 68db7b0c5891d167210de2461987c446df1f1670 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 5 Jul 2023 12:00:36 +0200 Subject: [PATCH 06/26] Make consistency_check.py not check for project folder name --- .../project-helper-tools/consistency_check.py | 28 +++++++++---------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-helper-tools/consistency_check.py index d61d8950..f02236a3 100755 --- a/scripts/project-helper-tools/consistency_check.py +++ b/scripts/project-helper-tools/consistency_check.py @@ -41,23 +41,22 @@ def create_path_dict(startpath, max_depth): return path_stucture_dict -def check_if_structure_is_consistent(start_path, path_dict, error_list): - for key in path_dict: - cur_path = str(start_path) + os.sep + key - print("Checking path: " + cur_path) - if os.path.exists(cur_path): - nested_item = path_dict[key] +def check_if_structure_is_consistent(cur_path, path_dict, error_list): + for path in path_dict: + # Get next path to check for consistency + next_path = (cur_path / path).resolve() + print("Checking path: %s" % next_path) + if next_path.exists(): + nested_item = path_dict[path] if type(nested_item) is not dict: - if os.path.isfile(cur_path): + if next_path.is_file(): continue else: # This must be a file, warn if it is not - # print("ERROR: " + cur_path + " is not a file, when it should be!") - error_list += ["ERROR: " + cur_path + " is not a file, when it should be!"] - check_if_structure_is_consistent(cur_path, nested_item, error_list) + error_list += ["ERROR: %s is not a file, when it should be!" % next_path] + check_if_structure_is_consistent(next_path, nested_item, error_list) else: - # print("ERROR: " + cur_path + " doesn't exist!") - error_list += ["ERROR: " + cur_path + " doesn't exist!"] + error_list += ["ERROR: %s doesn't exist!" % next_path] current_file_path = pathlib.Path(__file__) @@ -65,9 +64,8 @@ start_search_path = current_file_path.parent.parent.parent.resolve() # path_dict = create_path_dict(str(start_search_path), 5) # path_dict pre-generated. This is the stucture the consistency check will ensure is there -# TODO don't record or check the projects name. path_dict = { - 'pets': { + '../../../': { 'shared': {'artifacts': {}}, 'svn': {'tools': {'consistency_check.py': 'file'}}, 'local': {'blender': {}, 'scripts': {}, 'config': {}}, @@ -76,7 +74,7 @@ path_dict = { # TODO perhaps make a function to pretty print out the path_dict for easier inspection error_list = [] -check_if_structure_is_consistent(start_search_path.parent, path_dict, error_list) +check_if_structure_is_consistent(current_file_path, path_dict, error_list) print() if len(error_list) == 0: -- 2.30.2 From cbcbc602fc753d7270dedb650dd19d2e56cc94d8 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 5 Jul 2023 13:03:24 +0200 Subject: [PATCH 07/26] Make run_blender.py script fully work as intended --- scripts/project-helper-tools/run_blender.py | 39 ++++++++++++------- scripts/project-helper-tools/update_addons.sh | 3 -- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/scripts/project-helper-tools/run_blender.py b/scripts/project-helper-tools/run_blender.py index 3f4d0efe..271c24f3 100755 --- a/scripts/project-helper-tools/run_blender.py +++ b/scripts/project-helper-tools/run_blender.py @@ -109,18 +109,23 @@ def compare_checksum(file1, file2): return hash1 == hash2 -def update_addons(): +def update_addon(addon_zip_name, path_in_zip_to_extract=''): + addon_zip_sha = addon_zip_name + '.sha256' + # This is the file that records all toplevel folders/files installed by this addon + # It is used to cleanup old files and folders when updating or removing addons + addon_zip_files = addon_zip_name + '.files' + # Check if we have the latest add-ons from shared - studio_pipeline_artifacts = PATH_ARTIFACTS / 'blender-studio-pipeline' - artifact_checksum = studio_pipeline_artifacts / 'main.zip.sha256' - artifact_archive = artifact_checksum.with_suffix('') + addon_artifacts_folder = PATH_ARTIFACTS / 'addons' + artifact_archive = addon_artifacts_folder / addon_zip_name + artifact_checksum = addon_artifacts_folder / addon_zip_sha if not artifact_checksum.exists(): logger.error("Missing file %s" % artifact_checksum) logger.error("Could not update add-ons") return - local_checksum = PATH_LOCAL / 'main.zip.sha256' + local_checksum = PATH_LOCAL / addon_zip_sha if local_checksum.exists(): if compare_checksum(local_checksum, artifact_checksum): @@ -136,20 +141,20 @@ def update_addons(): tmp_dir = Path(tempfile.mkdtemp()) # Extract the zip file to the temporary directory - with zipfile.ZipFile(studio_pipeline_artifacts / 'main.zip', 'r') as zip_ref: + with zipfile.ZipFile(artifact_archive, 'r') as zip_ref: zip_ref.extractall(tmp_dir) # Get the path of the folder to copy - src_path_base = tmp_dir / 'blender-studio-pipeline' / 'scripts-blender' / 'addons' + src_path_base = tmp_dir / path_in_zip_to_extract dst_path_base = PATH_LOCAL / 'scripts' / 'addons' # Remove all files previously installed by the archive - local_installed_files = PATH_LOCAL / 'main.zip.files' + local_installed_files = PATH_LOCAL / addon_zip_files if local_installed_files.exists(): with open(local_installed_files) as file: lines = [line.rstrip() for line in file] for folder in lines: - shutil.rmtree(PATH_LOCAL / folder) + shutil.rmtree(dst_path_base / folder) # Get a list of directories inside the given directory addons = [subdir.name for subdir in src_path_base.iterdir() if subdir.is_dir()] @@ -177,15 +182,16 @@ def update_blender(): # Check if we have the latest blender archive from shared artifacts_path = PATH_ARTIFACTS / 'blender' + archive_name_pattern = "blender*" + system_name + "." + architecture + "*.sha256" # Look for the appropriate Blender archive for this system - matched_archives = glob.glob("blender*" + system_name + "." + architecture + "*.sha256") + matched_archives = glob.glob(str(artifacts_path / archive_name_pattern)) # Check if we found any files if len(matched_archives) != 1: if len(matched_archives) == 0: logger.error("No Blender archives found for this system!") - logger.error("System is: %s %s" % system_name, architecture) + logger.error("System is: %s %s" % (system_name, architecture)) return else: logger.error( @@ -241,10 +247,15 @@ def launch_blender(): subprocess.run([blender_path]) +def update_addons(): + path_in_zip_to_extract = Path('blender-studio-pipeline/scripts-blender/addons') + update_addon('blender-studio-pipeline-main.zip', path_in_zip_to_extract) + + if __name__ == '__main__': - logger.info('Update Add-ons') + logger.info('Updating Add-ons') update_addons() - logger.info('Update Blender') + logger.info('Updating Blender') update_blender() - logger.info('Launch Blender') + logger.info('Launching Blender') launch_blender() diff --git a/scripts/project-helper-tools/update_addons.sh b/scripts/project-helper-tools/update_addons.sh index d40ee2a8..c36e18df 100755 --- a/scripts/project-helper-tools/update_addons.sh +++ b/scripts/project-helper-tools/update_addons.sh @@ -23,7 +23,4 @@ download_addon() { } # download_addon - -# Special download dir for monorepo with addons -DOWNLOAD_DIR=../../shared/artifacts/blender-studio-pipeline/ download_addon https://projects.blender.org/studio/blender-studio-pipeline/archive/main.zip blender-studio-pipeline-main.zip -- 2.30.2 From 4b961998ffb996d33df838cdc505adffb6e20a37 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 5 Jul 2023 16:11:26 +0200 Subject: [PATCH 08/26] Update blender update script --- .../project-helper-tools/update_blender.sh | 68 ++++++++++++------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/scripts/project-helper-tools/update_blender.sh b/scripts/project-helper-tools/update_blender.sh index ef2b95f3..3a151500 100755 --- a/scripts/project-helper-tools/update_blender.sh +++ b/scripts/project-helper-tools/update_blender.sh @@ -12,7 +12,7 @@ DOWNLOAD_DIR=../../shared/artifacts/blender mkdir -p $DOWNLOAD_DIR # Switch to the download directory -pushd $DOWNLOAD_DIR +cd $DOWNLOAD_DIR # .zip == Windows # .dmg == Mac @@ -27,43 +27,63 @@ latest_urls=$(wget --quiet -O - "$HOMEPAGE" | \ sed -e 's/^ download_date +fi + +if [ "$updated_downloads" = true ] ; then + pushd previous + + # Put the current backup first in the directory listing + mv current_snapshot 00 + + # Bump all folder names + # Assign a number to each file, reverse the processing order to not overwrite any files. + ls -v | cat -n | tac | while read n f; do mv -n "$f" "$(printf "%02d" $n)"; done + + # Remove older backup folders if there are more than 10 + num_old_files=$(ls -1 | wc -l) + if [ "$num_old_files" -ge 10 ]; then + files_to_remove=$(ls | tail $((10-$num_old_files))) + rm -fr $files_to_remove + fi + popd +else + rm -fr previous/current_snapshot +fi -- 2.30.2 From beeb2e2fc391907bc58e8fd246eda62ef31e7af8 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 5 Jul 2023 18:05:08 +0200 Subject: [PATCH 09/26] Simplify file comparison --- scripts/project-helper-tools/consistency_check.py | 2 +- scripts/project-helper-tools/run_blender.py | 14 +++----------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-helper-tools/consistency_check.py index f02236a3..c2658ba0 100755 --- a/scripts/project-helper-tools/consistency_check.py +++ b/scripts/project-helper-tools/consistency_check.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 import os import pathlib diff --git a/scripts/project-helper-tools/run_blender.py b/scripts/project-helper-tools/run_blender.py index 271c24f3..ec62fabe 100755 --- a/scripts/project-helper-tools/run_blender.py +++ b/scripts/project-helper-tools/run_blender.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 +import filecmp import glob -import hashlib import logging import os import platform @@ -101,14 +101,6 @@ def extract_zip(file_path: Path, dst_path: Path): shutil.rmtree(temp_dir) -def compare_checksum(file1, file2): - with open(file1, 'rb') as f1, open(file2, 'rb') as f2: - hash1 = hashlib.sha256(f1.read()).hexdigest() - hash2 = hashlib.sha256(f2.read()).hexdigest() - - return hash1 == hash2 - - def update_addon(addon_zip_name, path_in_zip_to_extract=''): addon_zip_sha = addon_zip_name + '.sha256' # This is the file that records all toplevel folders/files installed by this addon @@ -128,7 +120,7 @@ def update_addon(addon_zip_name, path_in_zip_to_extract=''): local_checksum = PATH_LOCAL / addon_zip_sha if local_checksum.exists(): - if compare_checksum(local_checksum, artifact_checksum): + if filecmp.cmp(local_checksum, artifact_checksum): logger.info("Already up to date") return @@ -213,7 +205,7 @@ def update_blender(): local_checksum = PATH_LOCAL / 'blender' / f"{system_name}.sha256" if local_checksum.exists(): - if compare_checksum(local_checksum, blender_build_checksum): + if filecmp.cmp(local_checksum, blender_build_checksum): logger.info("Already up to date") return -- 2.30.2 From 2f31d4f487fd63485a9b89a3a076401eff48ed71 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 5 Jul 2023 19:00:10 +0200 Subject: [PATCH 10/26] Add rollback python version --- .../project-helper-tools/rollback_blender.py | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100755 scripts/project-helper-tools/rollback_blender.py diff --git a/scripts/project-helper-tools/rollback_blender.py b/scripts/project-helper-tools/rollback_blender.py new file mode 100755 index 00000000..05d2b0bc --- /dev/null +++ b/scripts/project-helper-tools/rollback_blender.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python3 + +import filecmp +import os +from pathlib import Path +import shutil + +# The project base path (where shared, local and svn are located) +PATH_BASE = Path(__file__).resolve().parent.parent.parent +PATH_ARTIFACTS = PATH_BASE / 'shared' / 'artifacts' / 'blender' +PATH_PREVIOUS = PATH_ARTIFACTS / 'previous' +BACKUP_DIR = PATH_PREVIOUS / '00' + +if not BACKUP_DIR.exists(): + BACKUP_DIR.mkdir() + # Backup the current files + for file in PATH_ARTIFACTS.iterdir(): + if file.is_file(): + shutil.copy(file, BACKUP_DIR) + +cur_date_file = PATH_ARTIFACTS / "download_date" + +paths = sorted(Path(PATH_PREVIOUS).iterdir()) + +print("Available builds:\n") + +for index, path in enumerate(paths): + date_file = path / "download_date" + if not date_file.exists(): + print("ERROR: The backup folder %s is missing a datefile, exiting!" % path) + + with open(date_file, 'r') as file: + date = file.read().rstrip() + + if filecmp.cmp(cur_date_file, date_file): + print("\033[1mID:\033[0m\033[100m%3i (%s) \033[0m" % (index, date)) + else: + print("\033[1mID:\033[0m%3i (%s)" % (index, date)) + +print() + +input_error_mess = "Please select an index between 0 and " + str(len(paths) - 1) +selected_index = 0 + +while True: + index_str = input("Select which Blender build number to switch to. (press ENTER to confirm): ") + if not index_str.isnumeric(): + print(input_error_mess) + continue + index = int(index_str) + if index >= 0 and index < len(paths): + selected_index = index + break + print(input_error_mess) + +# Remove current files and move the selected snapshot into current folder +for file in PATH_ARTIFACTS.iterdir(): + if file.is_file(): + os.remove(file) + +for file in paths[selected_index].iterdir(): + # Everything should be a file in here but have this check for sanity eitherway. + if file.is_file(): + shutil.copy(file, PATH_ARTIFACTS) -- 2.30.2 From bc384244019656983485b50cc1d6f57e737a6602 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 5 Jul 2023 19:05:17 +0200 Subject: [PATCH 11/26] Remove old .sh files --- .../project-helper-tools/rollback_blender.sh | 72 ------------------- scripts/project-helper-tools/run_blender.sh | 66 ----------------- 2 files changed, 138 deletions(-) delete mode 100755 scripts/project-helper-tools/rollback_blender.sh delete mode 100755 scripts/project-helper-tools/run_blender.sh diff --git a/scripts/project-helper-tools/rollback_blender.sh b/scripts/project-helper-tools/rollback_blender.sh deleted file mode 100755 index c43de309..00000000 --- a/scripts/project-helper-tools/rollback_blender.sh +++ /dev/null @@ -1,72 +0,0 @@ -#!/bin/bash - -# Get all archived sha hashes to use as ID numbers - -ARCHIVE_DIR=../../shared/pets/artifacts/blender/previous/ - -cd $ARCHIVE_DIR - -# TODO only rollbacks for one OS version - -OS=linux - -# Create an array with the available builds/files -available_builds=($(ls -t *$OS*.sha256)) - -installed_build=$(cd ../ && ls *$OS*.sha256) - -echo $installed_build - -echo -e "Available builds:\n" - -valid_ids=() - -ITER=0 - -for file in ${available_builds[@]}; do - file_date=$(stat -c '%y' $file) - # Cutoff the the date string to only show "date hours:min" - file_date=${file_date:0:19} - if [ $file == $installed_build ]; then - printf "\e[1mID:\e[0m \e[100m%3s " $ITER - printf "(%s)" "$file_date" - printf " \e[0m" - else - printf "\e[1mID:\e[0m %3s " $ITER - printf "(%s)" "$file_date" - fi - valid_ids+=($ITER) - echo - ITER=$(expr $ITER + 1) -done - -echo -e "\n" - -choosen_blend_id=-1 - -prompt="Select which Blender build number to switch to. (press ENTER to confirm): " -while read -rp "$prompt" num && [[ "$num" ]]; do - - # Check if "num" is a valid number. - [[ "$num" != *[[:digit:]]* ]] && - { echo "You need to choose a number!"; continue; } - - if [[ ! " ${valid_ids[*]} " =~ " ${num} " ]]; then - # whatever you want to do when array doesn't contain value - echo "$num is not an available ID!" - continue - fi - - choosen_blend_id=$num - - break -done - -((choosen_blend_id < 0)) && exit 0 - -choose_file=${available_builds[$choosen_blend_id]::-7} - -# Remove the build we are replacing -rm ../*$OS* -# Copy over the choosen build -cp $choose_file* ../ diff --git a/scripts/project-helper-tools/run_blender.sh b/scripts/project-helper-tools/run_blender.sh deleted file mode 100755 index c4d2d346..00000000 --- a/scripts/project-helper-tools/run_blender.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -# TODO error out if blender is not installed locally already and there is no blender to download on shared - -cur_dir=$(pwd) - -cd ../../local - -DOWNLOAD_DIR=../shared/pets - -update_addons() { - zip_name="main.zip" - - # Check if we have the latest addons from shared - if [ -f $zip_name.sha256 ]; then - shasum=$(cat $zip_name.sha256) - pushd $DOWNLOAD_DIR/addons - echo $shasum | sha256sum --check - && echo addons already at the latest version && popd && return 0 - popd - fi - - rm -fr ./scripts/* - - extract_folder="blender-studio-pipeline/scripts-blender/addons" - - # Record the extracted content - # Remove the first 5 lines, remove the last two lines, and extract the fourth column - unzip -l $DOWNLOAD_DIR/addons/$zip_name "$extract_folder/*" | tail -n +5 | head -n -2 | awk '{ print $4 }' > $zip_name.contents - - unzip $DOWNLOAD_DIR/addons/$zip_name "$extract_folder/*" -d "./scripts" - mv ./scripts/$extract_folder ./scripts/ - rm -fr ./scripts/blender-studio-pipeline - cp $DOWNLOAD_DIR/addons/$zip_name.sha256 . -} - -update_blender() { - os=linux - - # Ensure the os folder exists - mkdir -p blender/$os - - if [ -f blender/$os.sha256 ]; then - shasum=$(cat blender/$os.sha256) - pushd $DOWNLOAD_DIR/artifacts/blender - echo $shasum *$os*.tar.xz | sha256sum --check - && echo blender already at the latest version && popd && return 0 - popd - fi - - rm -fr blender/$os/* - - echo Extracting Blender - tar xf $DOWNLOAD_DIR/artifacts/blender/*$os*.tar.xz --directory blender/$os/ --strip-components=1 --checkpoint=.1000 - cp $DOWNLOAD_DIR/artifacts/blender/*$os*.sha256 blender/$os.sha256 -} - -update_addons -update_blender - -os=linux -cd blender/$os - -export BLENDER_USER_CONFIG=../../config -export BLENDER_USER_SCRIPTS=../../scripts - -# Actually launch Blender -./blender -- 2.30.2 From 6498ca6f84ec625d6cb64c12a5e738f3be87e9b8 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 5 Jul 2023 19:33:00 +0200 Subject: [PATCH 12/26] add install desktop file script --- scripts/project-helper-tools/install_desktop_file.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 scripts/project-helper-tools/install_desktop_file.sh diff --git a/scripts/project-helper-tools/install_desktop_file.sh b/scripts/project-helper-tools/install_desktop_file.sh new file mode 100644 index 00000000..e2a6e5cc --- /dev/null +++ b/scripts/project-helper-tools/install_desktop_file.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +PROJECT_NAME="Pets" +DESKTOP_FILE_DST="$HOME/.local/share/applications/blender_$PROJECT_NAME.desktop" +BLENDER_BIN_PATH=$(realpath ../../local/blender/linux/blender) + +cp ../../local/blender/linux/blender.desktop $DESKTOP_FILE_DST + +# Update the .desktop file data +sed -i -e "s:Exec=blender:Exec=$BLENDER_BIN_PATH:" -e "s:Blender:Blender $PROJECT_NAME:" "$DESKTOP_FILE_DST" -- 2.30.2 From c5af6d45b8ba2fd0986028cb84b9ae3b3624d1d5 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Fri, 7 Jul 2023 16:14:31 +0200 Subject: [PATCH 13/26] Update install desktop script --- scripts/project-helper-tools/install_desktop_file.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) mode change 100644 => 100755 scripts/project-helper-tools/install_desktop_file.sh diff --git a/scripts/project-helper-tools/install_desktop_file.sh b/scripts/project-helper-tools/install_desktop_file.sh old mode 100644 new mode 100755 index e2a6e5cc..c0cd67b5 --- a/scripts/project-helper-tools/install_desktop_file.sh +++ b/scripts/project-helper-tools/install_desktop_file.sh @@ -1,8 +1,11 @@ #!/bin/bash +# Make sure we are in this files directory +cd "$(dirname "$0")" + PROJECT_NAME="Pets" DESKTOP_FILE_DST="$HOME/.local/share/applications/blender_$PROJECT_NAME.desktop" -BLENDER_BIN_PATH=$(realpath ../../local/blender/linux/blender) +BLENDER_BIN_PATH=$(realpath ./run_blender.py) cp ../../local/blender/linux/blender.desktop $DESKTOP_FILE_DST -- 2.30.2 From d1479731da6c81e78d8efd1a38d07755e1d6e9d4 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 2 Aug 2023 18:47:51 +0200 Subject: [PATCH 14/26] Update consistency_check to exclude the script filename from the base search path --- scripts/project-helper-tools/consistency_check.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-helper-tools/consistency_check.py index c2658ba0..325088da 100755 --- a/scripts/project-helper-tools/consistency_check.py +++ b/scripts/project-helper-tools/consistency_check.py @@ -59,13 +59,13 @@ def check_if_structure_is_consistent(cur_path, path_dict, error_list): error_list += ["ERROR: %s doesn't exist!" % next_path] -current_file_path = pathlib.Path(__file__) -start_search_path = current_file_path.parent.parent.parent.resolve() +current_file_path = pathlib.Path(__file__).parent +start_search_path = current_file_path.parent.parent.resolve() # path_dict = create_path_dict(str(start_search_path), 5) # path_dict pre-generated. This is the stucture the consistency check will ensure is there path_dict = { - '../../../': { + '../../': { 'shared': {'artifacts': {}}, 'svn': {'tools': {'consistency_check.py': 'file'}}, 'local': {'blender': {}, 'scripts': {}, 'config': {}}, -- 2.30.2 From c57395b20ec1881616a441cf98d09e816679f67f Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Thu, 3 Aug 2023 12:39:43 +0200 Subject: [PATCH 15/26] WIP: update blender py --- .../project-helper-tools/update_blender.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 scripts/project-helper-tools/update_blender.py diff --git a/scripts/project-helper-tools/update_blender.py b/scripts/project-helper-tools/update_blender.py new file mode 100644 index 00000000..36f65b5d --- /dev/null +++ b/scripts/project-helper-tools/update_blender.py @@ -0,0 +1,61 @@ +import pathlib +import os +import requests +import re +import shutil +import hashlib + +HOMEPAGE = "https://builder.blender.org/download/" + +BLENDER_BRANCH = "main" +DOWNLOAD_DIR = "../../shared/artifacts/blender" + +current_file_folder_path = pathlib.Path(__file__).parent +download_folder_path = (current_file_folder_path / DOWNLOAD_DIR).resolve() +backup_folder_path = download_folder_path / "previous/current_snapshot" + +os.makedirs(download_folder_path, exist_ok=True) + +# Backup the old files +os.makedirs(backup_folder_path, exist_ok=True) + +for f in os.listdir(download_folder_path): + if os.path.isfile(f): + path_to_file = f / download_folder_path + shutil.copy(path_to_file, backup_folder_path) + +# Get all urls for the blender builds +platforms_to_download = { + "windows": "zip", + "darwin.x86_64": "dmg", + "darwin.arm64": "dmg", + "linux": "tar.xz", +} + +files_to_download = [] +branch_string = "+" + BLENDER_BRANCH +reqs = requests.get(HOMEPAGE) +for match in re.findall(' Date: Tue, 8 Aug 2023 18:06:06 +0200 Subject: [PATCH 16/26] First draft of update_blender.py --- .../project-helper-tools/update_blender.py | 103 +++++++++++++++--- 1 file changed, 88 insertions(+), 15 deletions(-) mode change 100644 => 100755 scripts/project-helper-tools/update_blender.py diff --git a/scripts/project-helper-tools/update_blender.py b/scripts/project-helper-tools/update_blender.py old mode 100644 new mode 100755 index 36f65b5d..329fa2eb --- a/scripts/project-helper-tools/update_blender.py +++ b/scripts/project-helper-tools/update_blender.py @@ -1,15 +1,39 @@ +#!/usr/bin/env python3 + import pathlib import os import requests import re import shutil import hashlib +import glob +import email.utils HOMEPAGE = "https://builder.blender.org/download/" BLENDER_BRANCH = "main" DOWNLOAD_DIR = "../../shared/artifacts/blender" + +def download_file(url, out_folder): + print("Downloading: " + url) + local_filename = out_folder / url.split('/')[-1] + # NOTE the stream=True parameter below + with requests.get(url, stream=True) as r: + r.raise_for_status() + with open(local_filename, 'wb') as f: + for chunk in r.iter_content(chunk_size=None): + if chunk: + f.write(chunk) + return local_filename + + +def shasum_matches(file, sha_sum): + with open(file, "rb") as f: + digest = hashlib.file_digest(f, "sha256") + return digest.hexdigest() == sha_sum + + current_file_folder_path = pathlib.Path(__file__).parent download_folder_path = (current_file_folder_path / DOWNLOAD_DIR).resolve() backup_folder_path = download_folder_path / "previous/current_snapshot" @@ -25,37 +49,86 @@ for f in os.listdir(download_folder_path): shutil.copy(path_to_file, backup_folder_path) # Get all urls for the blender builds -platforms_to_download = { +platforms_dict = { "windows": "zip", "darwin.x86_64": "dmg", "darwin.arm64": "dmg", "linux": "tar.xz", } -files_to_download = [] +download_info = [] branch_string = "+" + BLENDER_BRANCH reqs = requests.get(HOMEPAGE) for match in re.findall(' 1: + print( + f"Platform {platform} has multiple downloaded files in the artifacts directory, exiting!" + ) + exit(1) + # Check if we need to download the file by looking at the shasum of the currently downloaded file (if any) + if len(current_platform_file) == 1: + current_file = current_platform_file[0] + if shasum_matches(current_file, sha): + # We already have the current file + continue + else: + updated_current_files = True + os.remove(current_file) + os.remove(current_file + ".sha256") - downloaded_file = wget.download(url, out=download_folder_path) + download_file(url_sha, download_folder_path) + downloaded_file = download_file(url, download_folder_path) + # Check that the file we downloaded is not corrupt + if not shasum_matches(downloaded_file, sha): + print(f"Downloaded file {downloaded_file} does not match its shasum, exiting!") + exit(1) + new_files_downloaded = True +if new_files_downloaded: + # Save download date for use in the rollback script + with open(download_folder_path / "download_date", "w") as date_file: + date_file.write(email.utils.formatdate(localtime=True)) + print("Updated to the latest files") + +if updated_current_files: + backup_path = download_folder_path / "previous" + # Put the current backup first in the directory listing + os.rename(backup_folder_path, backup_path / "00") + backup_dirs = os.listdir(backup_path) + backup_dirs.sort(reverse=True) + + # Remove older backup folders if there are more than 10 + folders_to_remove = len(backup_dirs) - 10 + if folders_to_remove > 0: + for dir in backup_dirs[:folders_to_remove]: + shutil.rmtree(dir) + backup_dirs = backup_dirs[folders_to_remove:] + + # Bump all folder names + # Assign a number to each file, reverse the processing order to not overwrite any files. + folder_number = len(backup_dirs) + for dir in backup_dirs: + os.rename(dir, backup_path / str(folder_number).zfill(2)) + folder_number -= 1 +else: + shutil.rmtree(backup_folder_path) + print("Nothing downloaded, everything was up to date") -- 2.30.2 From cdab7554972cc5d601ad145fb3103a773362752d Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 9 Aug 2023 16:23:08 +0200 Subject: [PATCH 17/26] Add python "update addons" script --- scripts/project-helper-tools/update_addons.py | 48 +++++++++++++++++++ scripts/project-helper-tools/update_addons.sh | 2 +- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100755 scripts/project-helper-tools/update_addons.py diff --git a/scripts/project-helper-tools/update_addons.py b/scripts/project-helper-tools/update_addons.py new file mode 100755 index 00000000..54df0a0f --- /dev/null +++ b/scripts/project-helper-tools/update_addons.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python3 + +import requests +import pathlib +import os +import glob +import hashlib + +DOWNLOAD_DIR = "../../shared/artifacts/addons/" + + +def download_file(url, out_folder, filename): + print("Downloading: " + url) + local_filename = out_folder / filename + + # TODO Can't check any shasums before downloading so always remove and redownload everything for now + prev_downloaded_files = glob.glob(f"{local_filename}*") + for file in prev_downloaded_files: + os.remove(file) + + # NOTE the stream=True parameter below + with requests.get(url, stream=True) as r: + r.raise_for_status() + with open(local_filename, 'wb') as f: + for chunk in r.iter_content(chunk_size=None): + if chunk: + f.write(chunk) + + local_hash_filename = local_filename.with_suffix(".zip.sha256") + with open(local_filename, "rb") as f: + digest = hashlib.file_digest(f, "sha256") + with open(local_hash_filename, "w") as hash_file: + hash_file.write(digest.hexdigest()) + + return local_filename + + +current_file_folder_path = pathlib.Path(__file__).parent +download_folder_path = (current_file_folder_path / DOWNLOAD_DIR).resolve() + +# Ensure that the download directory exists +os.makedirs(download_folder_path, exist_ok=True) + +download_file( + "https://projects.blender.org/studio/blender-studio-pipeline/archive/main.zip", + download_folder_path, + "blender-studio-pipeline-main.zip", +) diff --git a/scripts/project-helper-tools/update_addons.sh b/scripts/project-helper-tools/update_addons.sh index c36e18df..c0c9b02b 100755 --- a/scripts/project-helper-tools/update_addons.sh +++ b/scripts/project-helper-tools/update_addons.sh @@ -17,7 +17,7 @@ download_addon() { # Download the addons repo wget $URL -O $OUT_NAME - sha256sum *.zip > $OUT_NAME.sha256 + sha256sum $OUT_NAME > $OUT_NAME.sha256 popd } -- 2.30.2 From a038285bde8e69d84da1dec14f5689b393601d8d Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Wed, 9 Aug 2023 17:24:49 +0200 Subject: [PATCH 18/26] Finish base script python conversion --- .../project-helper-tools/consistency_check.py | 18 ++-- .../folder_structure.json | 23 +++++ .../init_project_folder_structure.py | 33 +++++++ scripts/project-helper-tools/run_blender.py | 3 +- scripts/project-helper-tools/update_addons.sh | 26 ------ .../project-helper-tools/update_blender.sh | 89 ------------------- 6 files changed, 66 insertions(+), 126 deletions(-) create mode 100644 scripts/project-helper-tools/folder_structure.json create mode 100755 scripts/project-helper-tools/init_project_folder_structure.py delete mode 100755 scripts/project-helper-tools/update_addons.sh delete mode 100755 scripts/project-helper-tools/update_blender.sh diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-helper-tools/consistency_check.py index 325088da..c6e1f607 100755 --- a/scripts/project-helper-tools/consistency_check.py +++ b/scripts/project-helper-tools/consistency_check.py @@ -2,6 +2,7 @@ import os import pathlib +import json def create_path_dict(startpath, max_depth): @@ -59,22 +60,19 @@ def check_if_structure_is_consistent(cur_path, path_dict, error_list): error_list += ["ERROR: %s doesn't exist!" % next_path] -current_file_path = pathlib.Path(__file__).parent -start_search_path = current_file_path.parent.parent.resolve() +current_file_folder = pathlib.Path(__file__).parent +start_search_path = current_file_folder.parent.parent.resolve() # path_dict = create_path_dict(str(start_search_path), 5) # path_dict pre-generated. This is the stucture the consistency check will ensure is there -path_dict = { - '../../': { - 'shared': {'artifacts': {}}, - 'svn': {'tools': {'consistency_check.py': 'file'}}, - 'local': {'blender': {}, 'scripts': {}, 'config': {}}, - } -} +path_dict = {} +with open(current_file_folder / "folder_structure.json") as json_file: + path_dict = json.load(json_file) + # TODO perhaps make a function to pretty print out the path_dict for easier inspection error_list = [] -check_if_structure_is_consistent(current_file_path, path_dict, error_list) +check_if_structure_is_consistent(current_file_folder, path_dict, error_list) print() if len(error_list) == 0: diff --git a/scripts/project-helper-tools/folder_structure.json b/scripts/project-helper-tools/folder_structure.json new file mode 100644 index 00000000..a5498571 --- /dev/null +++ b/scripts/project-helper-tools/folder_structure.json @@ -0,0 +1,23 @@ +{ + "../../": { + "shared": { + "artifacts": {} + }, + "svn": { + "tools": { + "consistency_check.py": "file", + "folder_structure.json": "file", + "install_desktop_file.sh": "file", + "rollback_blender.py": "file", + "run_blender.py": "file", + "update_addons.py": "file", + "update_blender.py": "file" + } + }, + "local": { + "blender": {}, + "scripts": {}, + "config": {} + } + } +} diff --git a/scripts/project-helper-tools/init_project_folder_structure.py b/scripts/project-helper-tools/init_project_folder_structure.py new file mode 100755 index 00000000..0ad19efe --- /dev/null +++ b/scripts/project-helper-tools/init_project_folder_structure.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +import os +import pathlib +import json +import shutil + + +def create_folder_structure(cur_path, path_dict, source_folder): + for path in path_dict: + # Get next path to check for consistency + next_path = (cur_path / path).resolve() + print("Checking path: %s" % next_path) + nested_item = path_dict[path] + if type(nested_item) is not dict: + # This is a file we should copy over + if next_path.exists(): + continue + print(f"Copying over: {next_path.name}") + shutil.copy(source_folder / next_path.name, next_path) + else: + print(f"Creating folder: {next_path}") + os.makedirs(next_path) + create_folder_structure(next_path, nested_item, source_folder) + + +current_file_folder = pathlib.Path(__file__).parent +with open(current_file_folder / "folder_structure.json") as json_file: + path_dict = json.load(json_file) + target_folder = pathlib.Path("/tmp/pets") + create_folder_structure(target_folder, path_dict["../../"], current_file_folder) + print() + print("Done!") diff --git a/scripts/project-helper-tools/run_blender.py b/scripts/project-helper-tools/run_blender.py index ec62fabe..045d0965 100755 --- a/scripts/project-helper-tools/run_blender.py +++ b/scripts/project-helper-tools/run_blender.py @@ -211,7 +211,8 @@ def update_blender(): src = artifacts_path / blender_build_archive dst = PATH_LOCAL / 'blender' / system_name - shutil.rmtree(dst) + if dst.exists(): + shutil.rmtree(dst) if system_name == 'linux': extract_tar_xz(src, dst) diff --git a/scripts/project-helper-tools/update_addons.sh b/scripts/project-helper-tools/update_addons.sh deleted file mode 100755 index c0c9b02b..00000000 --- a/scripts/project-helper-tools/update_addons.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash - -DOWNLOAD_DIR=../../shared/artifacts/addons/ - -download_addon() { - URL=$1 - OUT_NAME=$2 - - # Ensure that the download directory exists - mkdir -p $DOWNLOAD_DIR - - # Switch to the download directory - pushd $DOWNLOAD_DIR - - # TODO Can't check any shasums before downloading so always remove and redownload everything for now - rm $OUT_NAME* - - # Download the addons repo - wget $URL -O $OUT_NAME - sha256sum $OUT_NAME > $OUT_NAME.sha256 - - popd -} - -# download_addon -download_addon https://projects.blender.org/studio/blender-studio-pipeline/archive/main.zip blender-studio-pipeline-main.zip diff --git a/scripts/project-helper-tools/update_blender.sh b/scripts/project-helper-tools/update_blender.sh deleted file mode 100755 index 3a151500..00000000 --- a/scripts/project-helper-tools/update_blender.sh +++ /dev/null @@ -1,89 +0,0 @@ -#!/bin/bash - -# Stop execution on error -set -e - -HOMEPAGE="https://builder.blender.org/download/" - -BLENDER_BRANCH=main -DOWNLOAD_DIR=../../shared/artifacts/blender - -# Ensure that the download directory exists -mkdir -p $DOWNLOAD_DIR - -# Switch to the download directory -cd $DOWNLOAD_DIR - -# .zip == Windows -# .dmg == Mac -# .tar.xz == Linux - -# Create a dictinary with the above information -declare -A extensions -extensions=( ["windows"]="zip" ["darwin.x86_64"]="dmg" ["darwin.arm64"]="dmg" ["linux"]="tar.xz" ) - -latest_urls=$(wget --quiet -O - "$HOMEPAGE" | \ - grep -io ' download_date -fi - -if [ "$updated_downloads" = true ] ; then - pushd previous - - # Put the current backup first in the directory listing - mv current_snapshot 00 - - # Bump all folder names - # Assign a number to each file, reverse the processing order to not overwrite any files. - ls -v | cat -n | tac | while read n f; do mv -n "$f" "$(printf "%02d" $n)"; done - - # Remove older backup folders if there are more than 10 - num_old_files=$(ls -1 | wc -l) - if [ "$num_old_files" -ge 10 ]; then - files_to_remove=$(ls | tail $((10-$num_old_files))) - rm -fr $files_to_remove - fi - popd -else - rm -fr previous/current_snapshot -fi -- 2.30.2 From 476929b5277e0c4e204aa327af2e19cf6078d8d3 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Tue, 29 Aug 2023 15:54:51 +0200 Subject: [PATCH 19/26] Remove print statement --- scripts/project-helper-tools/rollback_blender.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/scripts/project-helper-tools/rollback_blender.py b/scripts/project-helper-tools/rollback_blender.py index 05d2b0bc..b568fa40 100755 --- a/scripts/project-helper-tools/rollback_blender.py +++ b/scripts/project-helper-tools/rollback_blender.py @@ -37,8 +37,6 @@ for index, path in enumerate(paths): else: print("\033[1mID:\033[0m%3i (%s)" % (index, date)) -print() - input_error_mess = "Please select an index between 0 and " + str(len(paths) - 1) selected_index = 0 -- 2.30.2 From 530f2712a1a85bc55b868eb8e0dc3f0072eda42e Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Tue, 29 Aug 2023 17:44:18 +0200 Subject: [PATCH 20/26] Sort imports --- scripts/project-helper-tools/rollback_blender.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/project-helper-tools/rollback_blender.py b/scripts/project-helper-tools/rollback_blender.py index b568fa40..fc046154 100755 --- a/scripts/project-helper-tools/rollback_blender.py +++ b/scripts/project-helper-tools/rollback_blender.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 +from pathlib import Path import filecmp import os -from pathlib import Path import shutil # The project base path (where shared, local and svn are located) -- 2.30.2 From 31ef1deda75fffc5af4feff922226d656c14e6df Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Wed, 30 Aug 2023 02:20:43 +0200 Subject: [PATCH 21/26] Add argparse to init_project_folder_structure --- .../init_project_folder_structure.py | 35 +++++++++++++++---- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/scripts/project-helper-tools/init_project_folder_structure.py b/scripts/project-helper-tools/init_project_folder_structure.py index 0ad19efe..ecfd9ca1 100755 --- a/scripts/project-helper-tools/init_project_folder_structure.py +++ b/scripts/project-helper-tools/init_project_folder_structure.py @@ -1,9 +1,22 @@ #!/usr/bin/env python3 +import argparse import os import pathlib import json import shutil +import sys + + +def valid_dir_arg(value): + """Determine if the value is a valid directory""" + filepath = pathlib.Path(value) + + if not filepath.exists() or not filepath.is_dir(): + msg = f"Error! This is not a directory: {value}" + raise argparse.ArgumentTypeError(msg) + else: + return filepath def create_folder_structure(cur_path, path_dict, source_folder): @@ -24,10 +37,18 @@ def create_folder_structure(cur_path, path_dict, source_folder): create_folder_structure(next_path, nested_item, source_folder) -current_file_folder = pathlib.Path(__file__).parent -with open(current_file_folder / "folder_structure.json") as json_file: - path_dict = json.load(json_file) - target_folder = pathlib.Path("/tmp/pets") - create_folder_structure(target_folder, path_dict["../../"], current_file_folder) - print() - print("Done!") +def main(args): + parser = argparse.ArgumentParser(description="Generate project structure.") + parser.add_argument("-t", "--target", type=valid_dir_arg) + args = parser.parse_args(args) + target_folder = args.target or pathlib.Path.cwd().parent.parent + folder_structure = pathlib.Path(__file__).parent / "folder_structure.json" + + with open(folder_structure) as json_file: + path_dict = json.load(json_file) + create_folder_structure(target_folder, path_dict["../../"], folder_structure.parent) + print("Done!") + + +if __name__ == "__main__": + main(sys.argv[1:]) -- 2.30.2 From 54e81dcef54ebe9e5266e5f38c5ab9251ae57a42 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Wed, 30 Aug 2023 02:21:02 +0200 Subject: [PATCH 22/26] Make Python 3.11 requirement explicit --- scripts/project-helper-tools/update_addons.py | 14 +++++++++---- .../project-helper-tools/update_blender.py | 21 ++++++++++++------- 2 files changed, 23 insertions(+), 12 deletions(-) diff --git a/scripts/project-helper-tools/update_addons.py b/scripts/project-helper-tools/update_addons.py index 54df0a0f..4d34eda7 100755 --- a/scripts/project-helper-tools/update_addons.py +++ b/scripts/project-helper-tools/update_addons.py @@ -1,10 +1,16 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3.11 -import requests -import pathlib -import os import glob import hashlib +import os +import pathlib +import requests +import sys + +MIN_PYTHON = (3, 11) +if sys.version_info < MIN_PYTHON: + sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) + DOWNLOAD_DIR = "../../shared/artifacts/addons/" diff --git a/scripts/project-helper-tools/update_blender.py b/scripts/project-helper-tools/update_blender.py index 329fa2eb..54ca58c4 100755 --- a/scripts/project-helper-tools/update_blender.py +++ b/scripts/project-helper-tools/update_blender.py @@ -1,13 +1,18 @@ -#!/usr/bin/env python3 +#!/usr/bin/env python3.11 -import pathlib -import os -import requests -import re -import shutil -import hashlib -import glob import email.utils +import glob +import hashlib +import os +import pathlib +import re +import requests +import shutil +import sys + +MIN_PYTHON = (3, 11) +if sys.version_info < MIN_PYTHON: + sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) HOMEPAGE = "https://builder.blender.org/download/" -- 2.30.2 From 7e6aeda28ef8cb6a85fc4e85ab1e9e9d180f3a01 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Wed, 30 Aug 2023 02:21:25 +0200 Subject: [PATCH 23/26] Fix typos --- scripts/project-helper-tools/consistency_check.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-helper-tools/consistency_check.py index c6e1f607..b4e6e36e 100755 --- a/scripts/project-helper-tools/consistency_check.py +++ b/scripts/project-helper-tools/consistency_check.py @@ -6,7 +6,7 @@ import json def create_path_dict(startpath, max_depth): - path_stucture_dict = {} + path_structure_dict = {} start_folder_name = os.path.basename(start_search_path) for root, dirs, files in os.walk(startpath, followlinks=True): # We are only interested in the files and folders inside the start path. @@ -16,11 +16,11 @@ def create_path_dict(startpath, max_depth): # Therefore, we will stop if we go too deep. # This avoids infinite loops that can happen when we follow symlinks if level > max_depth: - print("We have gone unexptibly deep in the file structure, stopping...") + print("We have gone too deep in the file structure, stopping...") exit(1) # Insert the data into the dictionary - nested_dict = path_stucture_dict + nested_dict = path_structure_dict key_path = cur_path.split(os.sep) final_key = key_path[-1] for key in key_path[:-1]: @@ -39,7 +39,7 @@ def create_path_dict(startpath, max_depth): for f in files: print('{}{}'.format(subindent, f)) - return path_stucture_dict + return path_structure_dict def check_if_structure_is_consistent(cur_path, path_dict, error_list): -- 2.30.2 From 7e8c0570ac38021947eae0250c1e8704fcadd518 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Thu, 31 Aug 2023 20:05:15 +0200 Subject: [PATCH 24/26] Remove strict Python 3.11 requirement --- scripts/project-helper-tools/update_addons.py | 8 +------- scripts/project-helper-tools/update_blender.py | 6 +----- 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/scripts/project-helper-tools/update_addons.py b/scripts/project-helper-tools/update_addons.py index 4d34eda7..99489901 100755 --- a/scripts/project-helper-tools/update_addons.py +++ b/scripts/project-helper-tools/update_addons.py @@ -1,16 +1,10 @@ -#!/usr/bin/env python3.11 +#!/usr/bin/env python3 import glob import hashlib import os import pathlib import requests -import sys - -MIN_PYTHON = (3, 11) -if sys.version_info < MIN_PYTHON: - sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) - DOWNLOAD_DIR = "../../shared/artifacts/addons/" diff --git a/scripts/project-helper-tools/update_blender.py b/scripts/project-helper-tools/update_blender.py index 54ca58c4..39539df2 100755 --- a/scripts/project-helper-tools/update_blender.py +++ b/scripts/project-helper-tools/update_blender.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python3.11 +#!/usr/bin/env python3 import email.utils import glob @@ -8,11 +8,7 @@ import pathlib import re import requests import shutil -import sys -MIN_PYTHON = (3, 11) -if sys.version_info < MIN_PYTHON: - sys.exit("Python %s.%s or later is required.\n" % MIN_PYTHON) HOMEPAGE = "https://builder.blender.org/download/" -- 2.30.2 From 3e8b46f7f61c3ec8e56b74ac443dfec2e0f77d9e Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Thu, 31 Aug 2023 20:06:12 +0200 Subject: [PATCH 25/26] Move the value of DOWNLOAD_DIR closer to context --- scripts/project-helper-tools/update_addons.py | 4 +--- scripts/project-helper-tools/update_blender.py | 3 +-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/scripts/project-helper-tools/update_addons.py b/scripts/project-helper-tools/update_addons.py index 99489901..ec6a2336 100755 --- a/scripts/project-helper-tools/update_addons.py +++ b/scripts/project-helper-tools/update_addons.py @@ -6,8 +6,6 @@ import os import pathlib import requests -DOWNLOAD_DIR = "../../shared/artifacts/addons/" - def download_file(url, out_folder, filename): print("Downloading: " + url) @@ -36,7 +34,7 @@ def download_file(url, out_folder, filename): current_file_folder_path = pathlib.Path(__file__).parent -download_folder_path = (current_file_folder_path / DOWNLOAD_DIR).resolve() +download_folder_path = (current_file_folder_path / "../../shared/artifacts/addons/").resolve() # Ensure that the download directory exists os.makedirs(download_folder_path, exist_ok=True) diff --git a/scripts/project-helper-tools/update_blender.py b/scripts/project-helper-tools/update_blender.py index 39539df2..b8f38e52 100755 --- a/scripts/project-helper-tools/update_blender.py +++ b/scripts/project-helper-tools/update_blender.py @@ -13,7 +13,6 @@ import shutil HOMEPAGE = "https://builder.blender.org/download/" BLENDER_BRANCH = "main" -DOWNLOAD_DIR = "../../shared/artifacts/blender" def download_file(url, out_folder): @@ -36,7 +35,7 @@ def shasum_matches(file, sha_sum): current_file_folder_path = pathlib.Path(__file__).parent -download_folder_path = (current_file_folder_path / DOWNLOAD_DIR).resolve() +download_folder_path = (current_file_folder_path / "../../shared/artifacts/blender").resolve() backup_folder_path = download_folder_path / "previous/current_snapshot" os.makedirs(download_folder_path, exist_ok=True) -- 2.30.2 From 1fb52c64750cb6c3781b0e6739bda08211c210a7 Mon Sep 17 00:00:00 2001 From: Francesco Siddi Date: Thu, 31 Aug 2023 20:08:06 +0200 Subject: [PATCH 26/26] Rename project-helper-tools to project-tools --- .../{project-helper-tools => project-tools}/consistency_check.py | 0 .../{project-helper-tools => project-tools}/folder_structure.json | 0 .../init_project_folder_structure.py | 0 .../install_desktop_file.sh | 0 scripts/{project-helper-tools => project-tools}/pyproject.toml | 0 .../{project-helper-tools => project-tools}/rollback_blender.py | 0 scripts/{project-helper-tools => project-tools}/run_blender.py | 0 scripts/{project-helper-tools => project-tools}/setup.cfg | 0 scripts/{project-helper-tools => project-tools}/update_addons.py | 0 scripts/{project-helper-tools => project-tools}/update_blender.py | 0 10 files changed, 0 insertions(+), 0 deletions(-) rename scripts/{project-helper-tools => project-tools}/consistency_check.py (100%) rename scripts/{project-helper-tools => project-tools}/folder_structure.json (100%) rename scripts/{project-helper-tools => project-tools}/init_project_folder_structure.py (100%) rename scripts/{project-helper-tools => project-tools}/install_desktop_file.sh (100%) rename scripts/{project-helper-tools => project-tools}/pyproject.toml (100%) rename scripts/{project-helper-tools => project-tools}/rollback_blender.py (100%) rename scripts/{project-helper-tools => project-tools}/run_blender.py (100%) rename scripts/{project-helper-tools => project-tools}/setup.cfg (100%) rename scripts/{project-helper-tools => project-tools}/update_addons.py (100%) rename scripts/{project-helper-tools => project-tools}/update_blender.py (100%) diff --git a/scripts/project-helper-tools/consistency_check.py b/scripts/project-tools/consistency_check.py similarity index 100% rename from scripts/project-helper-tools/consistency_check.py rename to scripts/project-tools/consistency_check.py diff --git a/scripts/project-helper-tools/folder_structure.json b/scripts/project-tools/folder_structure.json similarity index 100% rename from scripts/project-helper-tools/folder_structure.json rename to scripts/project-tools/folder_structure.json diff --git a/scripts/project-helper-tools/init_project_folder_structure.py b/scripts/project-tools/init_project_folder_structure.py similarity index 100% rename from scripts/project-helper-tools/init_project_folder_structure.py rename to scripts/project-tools/init_project_folder_structure.py diff --git a/scripts/project-helper-tools/install_desktop_file.sh b/scripts/project-tools/install_desktop_file.sh similarity index 100% rename from scripts/project-helper-tools/install_desktop_file.sh rename to scripts/project-tools/install_desktop_file.sh diff --git a/scripts/project-helper-tools/pyproject.toml b/scripts/project-tools/pyproject.toml similarity index 100% rename from scripts/project-helper-tools/pyproject.toml rename to scripts/project-tools/pyproject.toml diff --git a/scripts/project-helper-tools/rollback_blender.py b/scripts/project-tools/rollback_blender.py similarity index 100% rename from scripts/project-helper-tools/rollback_blender.py rename to scripts/project-tools/rollback_blender.py diff --git a/scripts/project-helper-tools/run_blender.py b/scripts/project-tools/run_blender.py similarity index 100% rename from scripts/project-helper-tools/run_blender.py rename to scripts/project-tools/run_blender.py diff --git a/scripts/project-helper-tools/setup.cfg b/scripts/project-tools/setup.cfg similarity index 100% rename from scripts/project-helper-tools/setup.cfg rename to scripts/project-tools/setup.cfg diff --git a/scripts/project-helper-tools/update_addons.py b/scripts/project-tools/update_addons.py similarity index 100% rename from scripts/project-helper-tools/update_addons.py rename to scripts/project-tools/update_addons.py diff --git a/scripts/project-helper-tools/update_blender.py b/scripts/project-tools/update_blender.py similarity index 100% rename from scripts/project-helper-tools/update_blender.py rename to scripts/project-tools/update_blender.py -- 2.30.2