Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 11a7400

Browse files
author
Matthieu Hog
committedJul 15, 2024·
created plugin and environement node systems
1 parent cf656b6 commit 11a7400

16 files changed

+670
-48
lines changed
 

‎README.md

+8
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,14 @@ You can create custom nodes in python and make them available in Meshroom using
6666
In a standard precompiled version of Meshroom, you can also directly add custom nodes in `lib/meshroom/nodes`.
6767
To be recognized by Meshroom, a custom folder with nodes should be a Python module (an `__init__.py` file is needed).
6868

69+
### Plugins
70+
71+
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).
72+
73+
To do so, make sure docker or anaconda is installed properly and available from the command line.
74+
Then click on `File > Advanced > Install Plugin From URL` or `File > Advanced > Install Plugin From Local Folder` to begin the installation.
75+
76+
To learn more about using or creating plugins, check the explanations [here](meshroom/plugins/README.md).
6977

7078
## License
7179

‎meshroom/core/__init__.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -330,12 +330,15 @@ def loadPipelineTemplates(folder):
330330
if file.endswith(".mg") and file not in pipelineTemplates:
331331
pipelineTemplates[os.path.splitext(file)[0]] = os.path.join(folder, file)
332332

333+
pluginCatalogFile = os.path.join(meshroomFolder, "plugins", "catalog.json")
334+
333335
def initNodes():
334336
meshroomFolder = os.path.dirname(os.path.dirname(__file__))
337+
pluginsNodesFolder = os.path.join(meshroomFolder, "plugins")
335338
additionalNodesPath = os.environ.get("MESHROOM_NODES_PATH", "").split(os.pathsep)
336339
# filter empty strings
337340
additionalNodesPath = [i for i in additionalNodesPath if i]
338-
nodesFolders = [os.path.join(meshroomFolder, 'nodes')] + additionalNodesPath
341+
nodesFolders = [os.path.join(meshroomFolder, 'nodes')] + additionalNodesPath + [pluginsNodesFolder]
339342
for f in nodesFolders:
340343
loadAllNodes(folder=f)
341344

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

348351
def initPipelines():
349352
meshroomFolder = os.path.dirname(os.path.dirname(__file__))
353+
pluginsPipelinesFolder = os.path.join(meshroomFolder, "pipelines")
350354
# Load pipeline templates: check in the default folder and any folder the user might have
351355
# added to the environment variable
352356
additionalPipelinesPath = os.environ.get("MESHROOM_PIPELINE_TEMPLATES_PATH", "").split(os.pathsep)
353357
additionalPipelinesPath = [i for i in additionalPipelinesPath if i]
354-
pipelineTemplatesFolders = [os.path.join(meshroomFolder, 'pipelines')] + additionalPipelinesPath
358+
pipelineTemplatesFolders = [os.path.join(meshroomFolder, 'pipelines')] + additionalPipelinesPath + [pluginsPipelinesFolder]
355359
for f in pipelineTemplatesFolders:
356360
loadPipelineTemplates(f)
357361

‎meshroom/core/node.py

+51-30
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ class Status(Enum):
5151
KILLED = 5
5252
SUCCESS = 6
5353
INPUT = 7 # special status for input nodes
54+
BUILD = 8
55+
FIRST_RUN = 9
5456

5557

5658
class ExecMode(Enum):
@@ -401,36 +403,55 @@ def process(self, forceCompute=False):
401403
if not forceCompute and self._status.status == Status.SUCCESS:
402404
logging.info("Node chunk already computed: {}".format(self.name))
403405
return
404-
global runningProcesses
405-
runningProcesses[self.name] = self
406-
self._status.initStartCompute()
407-
exceptionStatus = None
408-
startTime = time.time()
409-
self.upgradeStatusTo(Status.RUNNING)
410-
self.statThread = stats.StatisticsThread(self)
411-
self.statThread.start()
412-
try:
413-
self.node.nodeDesc.processChunk(self)
414-
except Exception as e:
415-
if self._status.status != Status.STOPPED:
416-
exceptionStatus = Status.ERROR
417-
raise
418-
except (KeyboardInterrupt, SystemError, GeneratorExit) as e:
419-
exceptionStatus = Status.STOPPED
420-
raise
421-
finally:
422-
self._status.initEndCompute()
423-
self._status.elapsedTime = time.time() - startTime
424-
if exceptionStatus is not None:
425-
self.upgradeStatusTo(exceptionStatus)
426-
logging.info(' - elapsed time: {}'.format(self._status.elapsedTimeStr))
427-
# ask and wait for the stats thread to stop
428-
self.statThread.stopRequest()
429-
self.statThread.join()
430-
self.statistics = stats.Statistics()
431-
del runningProcesses[self.name]
432-
433-
self.upgradeStatusTo(Status.SUCCESS)
406+
407+
#if plugin node and if first call call meshroom_compute inside the env on 'host' so that the processchunk
408+
# of the node will be ran into the env
409+
if hasattr(self.node.nodeDesc, 'envFile') and self._status.status!=Status.FIRST_RUN:
410+
try:
411+
if not self.node.nodeDesc.isBuild():
412+
self.upgradeStatusTo(Status.BUILD)
413+
self.node.nodeDesc.build()
414+
self.upgradeStatusTo(Status.FIRST_RUN)
415+
command = self.node.nodeDesc.getCommandLine(self)
416+
#NOTE: docker returns 0 even if mount fail (it fails on the deamon side)
417+
status = os.system(command)
418+
if status != 0:
419+
raise RuntimeError("Error in node execution")
420+
self.updateStatusFromCache()
421+
except Exception as ex:
422+
self.logger.exception(ex)
423+
self.upgradeStatusTo(Status.ERROR)
424+
else:
425+
global runningProcesses
426+
runningProcesses[self.name] = self
427+
self._status.initStartCompute()
428+
exceptionStatus = None
429+
startTime = time.time()
430+
self.upgradeStatusTo(Status.RUNNING)
431+
self.statThread = stats.StatisticsThread(self)
432+
self.statThread.start()
433+
try:
434+
self.node.nodeDesc.processChunk(self)
435+
except Exception as e:
436+
if self._status.status != Status.STOPPED:
437+
exceptionStatus = Status.ERROR
438+
raise
439+
except (KeyboardInterrupt, SystemError, GeneratorExit) as e:
440+
exceptionStatus = Status.STOPPED
441+
raise
442+
finally:
443+
self._status.initEndCompute()
444+
self._status.elapsedTime = time.time() - startTime
445+
if exceptionStatus is not None:
446+
self.upgradeStatusTo(exceptionStatus)
447+
logging.info(' - elapsed time: {}'.format(self._status.elapsedTimeStr))
448+
# ask and wait for the stats thread to stop
449+
self.statThread.stopRequest()
450+
self.statThread.join()
451+
self.statistics = stats.Statistics()
452+
del runningProcesses[self.name]
453+
454+
self.upgradeStatusTo(Status.SUCCESS)
434455

435456
def stopProcess(self):
436457
if not self.isExtern():

0 commit comments

Comments
 (0)