4
$\begingroup$

I've been developing Blender add-ons for a while now, and one thing that I've always struggled with is how to keep a single copy of the add-on so that I can make changes to the code and quickly test in Blender AND have it all under source control. I don't want my Git repository inside Blender's add-ons directory, as it can easily get deleted by Blender (via the remove add-on button), and it enforces a particular folder structure on the repository.

Currently, I mainly use an external text editor (Sublime text) to work on the add-on, and then zip it up and install when I want to test my changes. As you can imagine, this is slow and laborious, so I'd rather work in a way that allows me to simply reload the scripts and have everything work, but not have to copy changes from the Blender folder back to my source repo.

I'm sure this must be a solved problem, so could someone explain how I can set up my repository so that it's safe from accidental deletion, but can easily be reloaded in Blender.

$\endgroup$

3 Answers 3

5
$\begingroup$

This is my workflow for developing add-ons outside of the Blender add-on directory:

  1. Save script files in text editor
  2. Run a script to copy script files into Blender add-on directory
  3. Reload script files in Blender

Run a script to copy script files into Blender add-on directory

When you install a .zip add-on installation file inside of Blender, the application simply unzips the file and places the contents into your Blender add-on directory. You can also install the add-on by placing the script files manually or using a script to copy the files.

The add-on directory location depends on your operating system. A quick way to find the location of a specific add-on is to select the add-on in the Preferences > Addons menu and look at the File attribute:

enter image description here

There are many ways to create a script that will copy files from one location to another. Some examples are:

  • A Windows batch script (.bat) using the xcopy command
  • A MacOS/Linux shell script (.sh) using the cp command
  • A Python script (.py) using the shutil module

Reload script files in Blender

Once you have your scripts copied over, you can reload your scripts in Blender using the Reload Scripts operator:

  • in Blender 2.79: F8 hotkey
  • in Blender 2.8x: F3 > Reload Scripts

An important thing to note is that the reload scripts operator will only reload your __init__.py script and will not reload other add-on script files. See this answer for how to structure your __init__.py script to reload other scripts and modules: https://blender.stackexchange.com/a/28505/81365

You can also restart Blender to update all script files.

$\endgroup$
4
$\begingroup$

I actually do the opposite to @RLGUY's solution, by using the files in the 'addons' directory in my Blender 'home' directory (eg, C:\Users\Rich\AppData\Roaming\Blender Foundation\Blender\2.80\scripts) to edit the development files and then simply restart Blender to ensure I get a clean re-load of the add-on files.

I use GIT for source control and this comes with a 'Git GUI' client for booking in/out, as well as a 'Git Bash' shell.

I use a script developed to run through 'Git Bash' to clone the files from the Blender directory back into my Git repository directory, before booking them into Git. In this way I can also perform other actions in the Bash script, such as clone it and convert it from Blender 2.8 syntax/api into source code that is compatible with Blender 2.7, automatically copy it into the Blender 2.7 directory (so I merely have to launch Blender 2.7 to test the add-on in that environment), as well as package the files into ZIP files with appropriate names for distribution.

Here's an example of my Bash script for performing these actions for the Maths Expression add-on :

echo "This will overwrite 'local' copies and those in Blender 2.7!!"
echo "Are you sure? (y=continue)"

read REPLY

if [ "$REPLY" != 'y' ]
then
    echo "Aborted!"
    exit 1
fi

BLENDER28SOURCE="C:/Users/Rich/AppData/Roaming/Blender Foundation/Blender/2.80/scripts/addons/MathsExpressionBlender28"
echo -e "\n\nCopy from '$BLENDER28SOURCE' and overwrite 'local' copy?"

read REPLY

if [ "$REPLY" = "y" ]
then
    echo "Copying..."
    sleep 2

    for file in `ls -1 "$BLENDER28SOURCE"|grep '\.py$'`
    do
        #echo "$file"
		cp "$BLENDER28SOURCE/$file" MathsExpressionBlender28 
        #sleep 1
    done

    rm -f MathsExpressionBlender28/presets/*
    for file in `ls -1 "$BLENDER28SOURCE"/presets`
    do
        #echo "$file"
		cp "$BLENDER28SOURCE/presets/$file" MathsExpressionBlender28/presets 
        #sleep 1
    done

    cp "$BLENDER28SOURCE/documentation.txt" MathsExpressionBlender28 

fi

function convert_to_27()
{

SOURCEDIR=$1
DESTDIR=$2

ZIP="c:/program files/7-zip/7z.exe"

mv "$DESTDIR" "../old/$DESTDIR.`date +%Y%m%d.%H%M%S`"

if [ "$?" -ne 0 ]
then
    echo "Failed to backup old version"
    exit 2
fi

mkdir "$DESTDIR"

if [ "$?" -ne 0 ]
then
    echo "Failed to create new empty directory"
    exit 3
fi

for file in `ls -1 $SOURCEDIR`
do
    if [ ! -z "`echo $file|grep '\.py$'`" ]
    then
        #It's a 'py' file

        #Convert 'XXXX[n]: bpy.props...' to 'XXXX = bpy.props...'
        cat $SOURCEDIR/$file |sed 's/\([a-z][0-9]*\): bpy.prop/\1 = bpy.prop/' |sed 's/2, 80, 0/2, 76, 0/' >$DESTDIR/$file
    else
        #Copy it
        cp -rfd "$SOURCEDIR"/"$file" "$DESTDIR"
    fi
done
}

echo -e "\n\nConvert 'full' 28 version to 27?"
read REPLY

if [ "$REPLY" = "y" ]
then
    convert_to_27 MathsExpressionBlender28 MathsExpressionBlender27
fi

#echo -e "\n\nConvert 'lite' 28 version to 27?"
#read REPLY
#
#if [ "$REPLY" = "y" ]
#then
#   convert_to_27 MathsExpressionLiteBlender28 MathsExpressionLiteBlender27
#fi


echo -e "\n\nRe-build ZIP files?"
read REPLY

if [ "$REPLY" = "y" ]
then
    echo "Rebuilding..."

    for module in MathsExpressionBlender27 MathsExpressionBlender28 #MathsExpressionLiteBlender27 MathsExpressionLiteBlender28
    do
        echo "$module"
		rm -f "$module.zip"
        "$ZIP" a "$module.zip" $module
    done

    ls -l *zip

fi

echo -e "\n\nUnpack both versions to Blender 2.79 addons?"
read REPLY

if [ "$REPLY" = "y" ]
then
	# Unzip to 2.79 blender addons, with overwrite mode of 'all'
	"$ZIP" x -aoa -o"c:/Users/rich/AppData/Roaming/Blender Foundation/Blender/2.79/scripts/addons" MathsExpressionBlender27.zip
#   "$ZIP" x -aoa -o"c:/Users/rich/AppData/Roaming/Blender Foundation/Blender/2.79/scripts/addons" MathsExpressionLiteBlender27.zip
fi

echo -e "\n\nRename ZIPs based on version?"
read REPLY

if [ "$REPLY" = "y" ]
then
	for file in MathsExpressionBlender28 MathsExpressionBlender27 #MathsExpressionLiteBlender28 MathsExpressionLiteBlender27 
	do
		VERSION="`grep '"version":' $file/__init__.py|sed 's/.*(//'|sed 's/).*$//'|tr -d ' '|tr ',' '.'`"
		echo "$file ($VERSION)"
		mv $file.zip ${file}_${VERSION}.zip
    done

fi


echo "Done"

exit 0

Note that this is for development in a Windows environment. For Linux you could simply use a similar Bash script, without needing 'Git Bash' (I use Bash since it provides all the tools I need (such as 'sed') for manipulating the files (rather than VB Script or Batch files which are less capable (I also prefer it, coming more from a Linux background)).

$\endgroup$
0
$\begingroup$

If you're running Linux you can link your addon file or directory into the addons directory using a symlink.

For instance, if we have a multi file addon called Coords, and it exists in the directory /media/dev/blender/Coords then we can run this command in a terminal:

ln -s /media/dev/blender/Coords  ~/.config/blender/3.5/scripts/addons/

Now the workflow becomes:

  1. Save file(s) in text editor
  2. Reload scripts in Blender

If Blender deletes the addon then it only deletes the symlink, the addon will still be wherever it was and you can create a new symlink if necessary.

Mac OS (unsurprising as it's certified Unix) and apparently Windows also have symlinks.

For Mac:

ln -s /some/path /Users/$USER/Library/Application\ Support/Blender/3.5/scripts/addons/

For windows, not sure about these commands, you may have to tweak them:

# for single file
mklink C:\\some\path %USERPROFILE%\AppData\Roaming\Blender Foundation\Blender\3.5\scripts\addons\

# for multi file
mklink /D C:\\some\path %USERPROFILE%\AppData\Roaming\Blender Foundation\Blender\3.5\scripts\addons
$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .