Skip to content

Commit

Permalink
created plugin and environement node systems
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthieu Hog committed Jul 15, 2024
1 parent cf656b6 commit 11a7400
Show file tree
Hide file tree
Showing 16 changed files with 670 additions and 48 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,14 @@ You can create custom nodes in python and make them available in Meshroom using
In a standard precompiled version of Meshroom, you can also directly add custom nodes in `lib/meshroom/nodes`.
To be recognized by Meshroom, a custom folder with nodes should be a Python module (an `__init__.py` file is needed).

### Plugins

Meshroom supports installing containerised plugins via Docker (with the [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/install-guide.html)) or [Anaconda](https://docs.anaconda.com/free/miniconda/index.html).

To do so, make sure docker or anaconda is installed properly and available from the command line.
Then click on `File > Advanced > Install Plugin From URL` or `File > Advanced > Install Plugin From Local Folder` to begin the installation.

To learn more about using or creating plugins, check the explanations [here](meshroom/plugins/README.md).

## License

Expand Down
8 changes: 6 additions & 2 deletions meshroom/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,12 +330,15 @@ def loadPipelineTemplates(folder):
if file.endswith(".mg") and file not in pipelineTemplates:
pipelineTemplates[os.path.splitext(file)[0]] = os.path.join(folder, file)

pluginCatalogFile = os.path.join(meshroomFolder, "plugins", "catalog.json")

def initNodes():
meshroomFolder = os.path.dirname(os.path.dirname(__file__))
pluginsNodesFolder = os.path.join(meshroomFolder, "plugins")
additionalNodesPath = os.environ.get("MESHROOM_NODES_PATH", "").split(os.pathsep)
# filter empty strings
additionalNodesPath = [i for i in additionalNodesPath if i]
nodesFolders = [os.path.join(meshroomFolder, 'nodes')] + additionalNodesPath
nodesFolders = [os.path.join(meshroomFolder, 'nodes')] + additionalNodesPath + [pluginsNodesFolder]
for f in nodesFolders:
loadAllNodes(folder=f)

Expand All @@ -347,11 +350,12 @@ def initSubmitters():

def initPipelines():
meshroomFolder = os.path.dirname(os.path.dirname(__file__))
pluginsPipelinesFolder = os.path.join(meshroomFolder, "pipelines")
# Load pipeline templates: check in the default folder and any folder the user might have
# added to the environment variable
additionalPipelinesPath = os.environ.get("MESHROOM_PIPELINE_TEMPLATES_PATH", "").split(os.pathsep)
additionalPipelinesPath = [i for i in additionalPipelinesPath if i]
pipelineTemplatesFolders = [os.path.join(meshroomFolder, 'pipelines')] + additionalPipelinesPath
pipelineTemplatesFolders = [os.path.join(meshroomFolder, 'pipelines')] + additionalPipelinesPath + [pluginsPipelinesFolder]
for f in pipelineTemplatesFolders:
loadPipelineTemplates(f)

Expand Down
81 changes: 51 additions & 30 deletions meshroom/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class Status(Enum):
KILLED = 5
SUCCESS = 6
INPUT = 7 # special status for input nodes
BUILD = 8
FIRST_RUN = 9


class ExecMode(Enum):
Expand Down Expand Up @@ -401,36 +403,55 @@ def process(self, forceCompute=False):
if not forceCompute and self._status.status == Status.SUCCESS:
logging.info("Node chunk already computed: {}".format(self.name))
return
global runningProcesses
runningProcesses[self.name] = self
self._status.initStartCompute()
exceptionStatus = None
startTime = time.time()
self.upgradeStatusTo(Status.RUNNING)
self.statThread = stats.StatisticsThread(self)
self.statThread.start()
try:
self.node.nodeDesc.processChunk(self)
except Exception as e:
if self._status.status != Status.STOPPED:
exceptionStatus = Status.ERROR
raise
except (KeyboardInterrupt, SystemError, GeneratorExit) as e:
exceptionStatus = Status.STOPPED
raise
finally:
self._status.initEndCompute()
self._status.elapsedTime = time.time() - startTime
if exceptionStatus is not None:
self.upgradeStatusTo(exceptionStatus)
logging.info(' - elapsed time: {}'.format(self._status.elapsedTimeStr))
# ask and wait for the stats thread to stop
self.statThread.stopRequest()
self.statThread.join()
self.statistics = stats.Statistics()
del runningProcesses[self.name]

self.upgradeStatusTo(Status.SUCCESS)

#if plugin node and if first call call meshroom_compute inside the env on 'host' so that the processchunk
# of the node will be ran into the env
if hasattr(self.node.nodeDesc, 'envFile') and self._status.status!=Status.FIRST_RUN:
try:
if not self.node.nodeDesc.isBuild():
self.upgradeStatusTo(Status.BUILD)
self.node.nodeDesc.build()
self.upgradeStatusTo(Status.FIRST_RUN)
command = self.node.nodeDesc.getCommandLine(self)
#NOTE: docker returns 0 even if mount fail (it fails on the deamon side)
status = os.system(command)
if status != 0:
raise RuntimeError("Error in node execution")
self.updateStatusFromCache()
except Exception as ex:
self.logger.exception(ex)
self.upgradeStatusTo(Status.ERROR)
else:
global runningProcesses
runningProcesses[self.name] = self
self._status.initStartCompute()
exceptionStatus = None
startTime = time.time()
self.upgradeStatusTo(Status.RUNNING)
self.statThread = stats.StatisticsThread(self)
self.statThread.start()
try:
self.node.nodeDesc.processChunk(self)
except Exception as e:
if self._status.status != Status.STOPPED:
exceptionStatus = Status.ERROR
raise
except (KeyboardInterrupt, SystemError, GeneratorExit) as e:
exceptionStatus = Status.STOPPED
raise
finally:
self._status.initEndCompute()
self._status.elapsedTime = time.time() - startTime
if exceptionStatus is not None:
self.upgradeStatusTo(exceptionStatus)
logging.info(' - elapsed time: {}'.format(self._status.elapsedTimeStr))
# ask and wait for the stats thread to stop
self.statThread.stopRequest()
self.statThread.join()
self.statistics = stats.Statistics()
del runningProcesses[self.name]

self.upgradeStatusTo(Status.SUCCESS)

def stopProcess(self):
if not self.isExtern():
Expand Down
Loading

0 comments on commit 11a7400

Please sign in to comment.