Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
99 changes: 78 additions & 21 deletions src/main/java/org/mastodon/blender/setup/BlenderSetupUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,16 +35,19 @@
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;

public class BlenderSetupUtils
{

public static boolean verifyBlenderBinary( Path blenderPath )
{
try {
String output = runPythonWithinBlender( blenderPath,
"print('Blender started from within Mastodon.')" );
return output.contains( "Blender started from within Mastodon." );
try
{
String expectOutput = "Blender started from within Mastodon.";
String python = "print('" + expectOutput + "')";
return runPythonWithinBlender( blenderPath, python, expectOutput );
}
catch ( Throwable e ) {
return false;
Expand All @@ -58,32 +61,43 @@ public static void installAddon( Path blenderPath ) throws IOException
Path pythonScript = tmpDir.resolve( "install_addon.py" );
FileUtils.copyURLToFile( BlenderSetupUtils.class.getResource( "/mastodon_blender_view.zip" ), addonZip.toFile() );
FileUtils.copyURLToFile( BlenderSetupUtils.class.getResource( "/blender-scripts/install_addon.py" ), pythonScript.toFile() );
String output = runCommandGetOutput( blenderPath.toString(), //
Result result = runCommand( blenderPath.toString(), //
"--background", //
"--python", pythonScript.toAbsolutePath().toString(), //
"--", addonZip.toAbsolutePath().toString() ); //
if ( !output.contains( "dependencies installed" ) )
throw new RuntimeException( "Installation of the dependencies for the mastodon_blender_view addon failed:\n" + output );
if ( !output.contains( "mastodon blender view addon installed" ) )
throw new RuntimeException( "Installation of the mastodon_blender_view addon failed:\n" + output );
if ( !output.contains( "google RPC code compiled" ))
throw new RuntimeException( "Installation of the mastodon_blender_view addon failed:\n" + output );

if ( result.exitCode != 0 )
throw new RuntimeException( "Installation failed.\n" + result );

if ( !result.stdout.contains( "dependencies installed" ) )
throw new RuntimeException( "Installation of the dependencies for the mastodon_blender_view addon failed:\n" + result );
Comment thread
maarzt marked this conversation as resolved.
Outdated

if ( !result.stdout.contains( "mastodon blender view addon installed" ) )
throw new RuntimeException( "Installation of the mastodon_blender_view addon failed:\n" + result );
Comment thread
maarzt marked this conversation as resolved.
Outdated

if ( !result.stdout.contains( "google RPC code compiled" ) )
throw new RuntimeException( "Installation of the mastodon_blender_view addon failed:\n" + result );
Comment thread
maarzt marked this conversation as resolved.
Outdated

Files.delete( pythonScript );
Files.delete( addonZip );
Files.delete( tmpDir );
}

public static void uninstallAddon( Path blenderPath )
{
String python = "import bpy; bpy.ops.preferences.addon_remove(module='mastodon_blender_view')";
String output = runPythonWithinBlender( blenderPath, python );
String python = "import bpy; " + //
"bpy.ops.preferences.addon_remove(module='mastodon_blender_view'); " + //
"print('uninstall completed');";
runPythonWithinBlender( blenderPath, python, "uninstall completed" );
}

public static boolean isMastodonAddonInstalled( Path blenderPath )
{
String python = "import addon_utils; print([module.__name__ for module in addon_utils.modules()])";
String output = runPythonWithinBlender( blenderPath, python );
return output.contains( "'mastodon_blender_view'" );
String python = "import addon_utils; " + //
"print([module.__name__ for module in addon_utils.modules()])";
String expectedOutput = "'mastodon_blender_view'";
boolean success = runPythonWithinBlender( blenderPath, python, expectedOutput );
return success;
}

public static void runAddonTest( Path blenderPath )
Expand All @@ -106,24 +120,67 @@ public static void runAddonTest( Path blenderPath )
process.waitFor();
}

private static String runPythonWithinBlender( Path blenderPath, String python )
private static boolean runPythonWithinBlender( Path blenderPath, String python, String expectedOutput )
{
return runCommandGetOutput( blenderPath.toString(), "--background", "--python-expr", python );
Result result = runCommand( blenderPath.toString(), "--background", "--python-expr", python );
return result.exitCode == 0 && result.stdout.contains( expectedOutput );
}

private static String runCommandGetOutput( String... command )
private static Result runCommand( String... command )
{
try
{
Process process = new ProcessBuilder( command ).start();
String output = IOUtils.toString( process.getInputStream(), StandardCharsets.UTF_8 );
process.waitFor();
return output;
String output = IOUtils.toString( process.getInputStream(), StandardCharsets.UTF_8 );
String error = IOUtils.toString( process.getErrorStream(), StandardCharsets.UTF_8 );
int exitCode = process.exitValue();
return new Result( Arrays.asList( command ), output, error, exitCode );
}
catch ( IOException | InterruptedException e )
{
throw new RuntimeException( e );
}
}

public static class Result
{

private final List< String > command;

private final String stdout;

private final String stderr;

private final int exitCode;

public Result( List< String > command, String stdout, String stderr,
int exitCode )
{
this.command = command;
this.stdout = stdout;
this.stderr = stderr;
this.exitCode = exitCode;
}

@Override
public String toString()
{
final StringBuilder s = new StringBuilder();
s.append( "Command:\n " ).append( command.get( 0 ) );
for ( int i = 1; i < command.size(); i++ )
s.append( " " ).append( addQuotes( command.get( i ) ) );
s.append( "\n\n" );
s.append( "Exit Code:\n " ).append( exitCode ).append("\n\n");
s.append( "Command Output:\n\n" ).append( stdout ).append("\n\n");
s.append( "Commend Error:\n\n" ).append( stderr ).append("\n\n");
Comment thread
maarzt marked this conversation as resolved.
Outdated
return s.toString();
}

static String addQuotes(String value)
{
boolean simple = value.matches("[a-zA-Z0-9_-]+");
return simple ? value : "'" + value + "'";
}
}
}
5 changes: 3 additions & 2 deletions src/main/resources/blender-scripts/install_addon.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ def get_python_path():

python_path = get_python_path()
packages = {'grpcio', 'bidict', 'grpcio-tools', 'pandas'}
subprocess.check_output([python_path, '-m', 'pip', 'install', *packages])
subprocess.run([python_path, '-m', 'pip', 'install', *packages], check=True)

# test if dependencies are installed

Expand All @@ -77,7 +77,8 @@ def get_python_path():

filename_init_py = [m.__file__ for m in addon_utils.modules() if m.__name__ == "mastodon_blender_view"][0]
addon_dir = os.path.dirname(filename_init_py)
subprocess.check_output([python_path, '-m', 'grpc_tools.protoc', '-I.', '--python_out=.', '--grpc_python_out=.', 'mastodon_blender_view/mastodon-blender-view.proto'], cwd=os.path.dirname(addon_dir))
command = [python_path, '-m', 'grpc_tools.protoc', '-I.', '--python_out=.', '--grpc_python_out=.', 'mastodon_blender_view/mastodon-blender-view.proto']
subprocess.run(command, cwd=os.path.dirname(addon_dir), check=True)

try:
from mastodon_blender_view import mastodon_blender_view_pb2
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

Expand All @@ -61,4 +63,39 @@ public void testAddon()
BlenderSetupUtils.installAddon( blenderBinaryPath );
BlenderSetupUtils.runAddonTest( blenderBinaryPath );
}

@Test
public void testResultToString() {
BlenderSetupUtils.Result result = new BlenderSetupUtils.Result(Arrays.asList("test", "--if", "/works well/"),
"Hello World!",
"ERROR\nString",
42);
String string = result.toString();
String expected = "Command:\n" +
" test --if '/works well/'\n" +
"\n" +
"Exit Code:\n" +
" 42\n" +
"\n" +
"Command Output:\n" +
"\n" +
"Hello World!\n" +
"\n" +
"Commend Error:\n" +
"\n" +
"ERROR\n" +
"String\n\n";
assertEquals(expected, string);
}

@Test
public void testAddQuotes()
{
assertEquals("noquotes", BlenderSetupUtils.Result.addQuotes("noquotes") );
assertEquals("--no-quotes", BlenderSetupUtils.Result.addQuotes("--no-quotes") );
assertEquals("'$needs-quotes'", BlenderSetupUtils.Result.addQuotes("$needs-quotes") );
assertEquals("'needs quotes'", BlenderSetupUtils.Result.addQuotes("needs quotes") );
}
}


Loading