Example #1
0
  /** @return The path of a node */
  private Path getNodePath(String nodeName) throws PipelineException {

    NodeID targetID = new NodeID(w.user, w.view, nodeName);
    NodeStatus targetStat = mclient.status(targetID);
    NodeMod targetMod = targetStat.getHeavyDetails().getWorkingVersion();
    if (targetMod == null)
      throw new PipelineException(
          "No working version of the Target Scene Node ("
              + nodeName
              + ") exists "
              + "in the ("
              + w.view
              + ") working area owned by ("
              + PackageInfo.sUser
              + ")!");

    Path targetPath;

    FileSeq fseq = targetMod.getPrimarySequence();
    String suffix = fseq.getFilePattern().getSuffix();
    if (!fseq.isSingle() || (suffix == null) || (!suffix.equals("ma") && !suffix.equals("mb")))
      throw new PipelineException("The target node (" + nodeName + ") must be a maya scene!");
    targetPath =
        new Path(PackageInfo.sProdPath, targetID.getWorkingParent() + "/" + fseq.getFile(0));

    // System.err.println("$WORKING"+nodeName+"."+suffix);
    return targetPath;
  } // end getNodePath(String)
Example #2
0
  /**
   * Check that the user has properly selected a target node for this tool
   *
   * <p>
   *
   * @return The phase progress message or <CODE>null</CODE> to abort early.
   * @throws PipelineException If unable to validate the given user input.
   */
  public synchronized String collectPhaseInput() throws PipelineException {
    if (pPrimary == null) throw new PipelineException("Please select a node.");

    if (!pPrimary.matches(switchPattern))
      throw new PipelineException("This tool will only work on a switchLgt node!");

    File errFile;
    try {
      errFile = File.createTempFile("Dylanator.", ".err", PackageInfo.sTempPath.toFile());
      err = new PrintWriter(errFile);
      FileCleaner.add(errFile);
    } catch (IOException e) {
      e.printStackTrace();
    }

    NodeStatus status = pSelected.get(pPrimary);
    NodeID nodeID = status.getNodeID();
    pUser = nodeID.getAuthor();
    pView = nodeID.getView();

    //		OverallNodeState state = status.getDetails().getOverallNodeState();
    //		JToolDialog tool = new JToolDialog("Dylanator", new JPanel(), "Continue");
    //		if (!state.equals(OverallNodeState.Identical)) {
    //		JConfirmDialog dialog = new JConfirmDialog(tool,
    //		"This node is not identical to the checked in node.\n"
    //		+ "Using this tool could be a bad idea.\n Do you want to continue?");
    //		dialog.setVisible(true);
    //		if (!dialog.wasConfirmed()) {
    //		return null;
    //		}// end if
    //		}// end if

    return "...Oh Happy Day!";
  }
  /**
   * Check that the user has properly selected a target node for this tool
   *
   * <p>
   *
   * @return The phase progress message or <CODE>null</CODE> to abort early.
   * @throws PipelineException If unable to validate the given user input.
   */
  public synchronized String collectPhaseInput() throws PipelineException {
    if ((pPrimary == null) || (pSelected.size() != 1))
      throw new PipelineException("Please selected one node only.");

    // folder = nPath.getParent();
    // assetName = nPath.getName();
    Path nPath = new Path(pPrimary);
    nPath = nPath.getParentPath().getParentPath();

    if (!nPath.toString().matches(assetPattern))
      throw new PipelineException(
          "This tool only works on assets." + nPath.toString() + " " + nPath.toOsString());

    // if(!pPrimary.matches(matPattern))
    // throw new PipelineException("This tool will only work on a lgt node!");

    File errFile;
    try {
      errFile = File.createTempFile("MaterialsCheckOut", ".err", PackageInfo.sTempPath.toFile());
      err = new PrintWriter(errFile);
      FileCleaner.add(errFile);
    } catch (IOException e) {
      e.printStackTrace();
    }

    NodeStatus status = pSelected.get(pPrimary);
    NodeID nodeID = status.getNodeID();
    pUser = nodeID.getAuthor();
    pView = nodeID.getView();

    OverallNodeState state = status.getHeavyDetails().getOverallNodeState();
    JToolDialog tool = new JToolDialog("MaterialsCheckOut", new JPanel(), "Continue");
    if (!state.equals(OverallNodeState.Identical)) {
      JConfirmDialog dialog =
          new JConfirmDialog(
              tool,
              "This node is different from the checked in node. Do you want to continue with this check out?");
      dialog.setVisible(true);
      if (!dialog.wasConfirmed()) {
        return null;
      } // end if
    } // end if

    return "...Sing Hallelujah!";
  }
Example #4
0
  /**
   * Updates the asset references for a shot within Maya and then in pipeline.
   *
   * @param shotName The name of the shot being processed.
   * @param pRemoveRef The list of assets being dereferenced from the shot.
   * @param pReplaceRef The list of assets being referenced into the shot.
   * @param nameMap
   */
  private void editShotReferences(
      String shotName,
      NodeMod targetMod,
      TreeSet<String> pRemoveRef,
      TreeSet<String> pReplaceRef,
      TreeMap<String, String> nameMap)
      throws PipelineException {
    logLine("Editing shot: " + shotName);
    boolean anim = !shotName.matches(lgtPattern);

    /* writing the mel script */
    if (anim) {
      File script = null;
      try {
        script = File.createTempFile("UpdateAssetGUI.", ".mel", PackageInfo.sTempPath.toFile());
        FileCleaner.add(script);
      } // end try
      catch (IOException ex) {
        throw new PipelineException(
            "Unable to create the temporary MEL script used to collect "
                + "texture information from the Maya scene!");
      } // end catch

      try {
        PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(script)));

        for (String asset : pReplaceRef) {
          String nameSpace;
          if (asset.endsWith(lr))
            nameSpace = nameMap.get(getShortName(asset.substring(0, asset.length() - 3)));
          else {
            System.err.println("This should not be happening, a hi res asset in a lo-res node.");
            continue;
            // nameSpace = nameMap.get(getShortName(asset));
          }
          out.println("print (\"referencing file: $WORKING" + asset + ".ma\");");
          out.println(
              "file -reference -namespace \"" + nameSpace + "\" \"$WORKING" + asset + ".ma\";");
        } // end for

        for (String asset : pRemoveRef) {
          out.println("print (\"dereferencing file: $WORKING" + asset + ".ma\");");
          out.println("file -rr \"$WORKING" + asset + ".ma\";");
        } // end for

        out.println("// SAVE");
        out.println("file -save;");

        out.close();
      } // end try
      catch (IOException ex) {
        throw new PipelineException(
            "Unable to write the temporary MEL script(" + script + ") used add the references!");
      } // end catch

      NodeID targetID = new NodeID(w.user, w.view, shotName);
      // NodeStatus targetStat = mclient.status(targetID);

      /* run Maya to collect the information */
      try {

        Path targetPath = getNodePath(shotName);
        ArrayList<String> args = new ArrayList<String>();
        args.add("-batch");
        args.add("-script");
        args.add(script.getPath());
        args.add("-file");
        args.add(targetPath.toOsString());

        Path wdir = new Path(PackageInfo.sProdPath.toOsString() + targetID.getWorkingParent());

        TreeMap<String, String> env =
            mclient.getToolsetEnvironment(
                w.user, w.view, targetMod.getToolset(), PackageInfo.sOsType);

        Map<String, String> nenv = env;
        String midefs = env.get("PIPELINE_MI_SHADER_PATH");
        if (midefs != null) {
          nenv = new TreeMap<String, String>(env);
          Path dpath = new Path(new Path(wdir, midefs));
          nenv.put("MI_CUSTOM_SHADER_PATH", dpath.toOsString());
        }

        String command = "maya";
        if (PackageInfo.sOsType.equals(OsType.Windows)) command += ".exe";

        SubProcessLight proc =
            new SubProcessLight("UpdateAssetGUI", command, args, env, wdir.toFile());
        try {
          proc.start();
          proc.join();
          if (!proc.wasSuccessful()) {
            throw new PipelineException(
                "Did not correctly edit the reference due to a maya error.!\n\n"
                    + proc.getStdOut()
                    + "\n\n"
                    + proc.getStdErr());
          } // end if
        } // end try
        catch (InterruptedException ex) {
          throw new PipelineException(ex);
        } // end catch
      } // end try
      catch (Exception ex) {
        throw new PipelineException(ex);
      } // end catch
    }

    /*-edit the references in pipeline once they are done in the file-*/
    BaseAction targetAction = targetMod.getAction();
    for (String asset : pReplaceRef) {
      mclient.link(
          w.user, w.view, shotName, asset, LinkPolicy.Reference, LinkRelationship.All, null);
      if (anim) {
        /*Set the namespaces*/
        String nameSpace = nameMap.get(getShortName(asset.substring(0, asset.length() - 3)));
        System.err.println(nameSpace);
        targetAction.initSourceParams(asset);
        targetAction.setSourceParamValue(asset, "PrefixName", nameSpace);
        targetMod.setAction(targetAction);
      }
    }
    w.mclient.modifyProperties(w.user, w.view, targetMod);

    for (String asset : pRemoveRef) mclient.unlink(w.user, w.view, shotName, asset);

    if (!anim) {
      System.err.println("Queuing the switchLgt node " + shotName);
      mclient.submitJobs(w.user, w.view, shotName, null);
    }
  } // end editShotReferences
  /**
   * Construct a {@link SubProcessHeavy SubProcessHeavy} instance which when executed will fulfill
   * the given action agenda.
   *
   * <p>
   *
   * @param agenda The agenda to be accomplished by the action.
   * @param outFile The file to which all STDOUT output is redirected.
   * @param errFile The file to which all STDERR output is redirected.
   * @return The SubProcess which will fulfill the agenda.
   * @throws PipelineException If unable to prepare a SubProcess due to illegal, missing or
   *     imcompatable information in the action agenda or a general failure of the prep method code.
   */
  public SubProcessHeavy prep(ActionAgenda agenda, File outFile, File errFile)
      throws PipelineException {
    NodeID nodeID = agenda.getNodeID();

    /* sanity checks */
    String opname = null;
    File source = null;
    File preRender = null;
    File postRender = null;
    File preFrame = null;
    File postFrame = null;
    {
      {
        FileSeq fseq = agenda.getPrimaryTarget();
        if (!fseq.hasFrameNumbers())
          throw new PipelineException(
              "The HfsComposite Action requires that the output images have frame numbers.");
      }

      /* generate the filename of the Houdini scene to load */
      {
        String sname = (String) getSingleParamValue("HoudiniScene");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Houdini Scene node ("
                    + sname
                    + ") was not one of the source "
                    + "nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !suffix.equals("hip"))
            throw new PipelineException(
                "The HfsComposite Action requires that the source node specified by the "
                    + "Houdini Scene parameter ("
                    + sname
                    + ") must have a single Houdini scene "
                    + "file (.hip) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          source =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        } else {
          throw new PipelineException(
              "The HfsComposite Action requires the Houdini Scene parameter to be set!");
        }
      }

      /* the full name of the geometry output operator */
      {
        String name = (String) getSingleParamValue("OutputOperator");
        if ((name == null) || (name.length() == 0))
          throw new PipelineException(
              "The HfsComposite Action requires a valid Output Operator name!");

        opname = ("/out/" + name);
      }

      /* command script files */
      {
        String sname = (String) getSingleParamValue("PreRenderScript");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Pre Render Script node ("
                    + sname
                    + ") was not one of the "
                    + "source nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("cmd")))
            throw new PipelineException(
                "The HfsComposite Action requires that the source node specified by the Pre "
                    + "Render Script parameter ("
                    + sname
                    + ") must have a single command script "
                    + "(.cmd) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          preRender =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        }
      }

      {
        String sname = (String) getSingleParamValue("PostRenderScript");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Post Render Script node ("
                    + sname
                    + ") was not one of the "
                    + "source nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("cmd")))
            throw new PipelineException(
                "The HfsComposite Action requires that the source node specified by the "
                    + "Post Render Script parameter ("
                    + sname
                    + ") must have a single command "
                    + "script (.cmd) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          postRender =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        }
      }

      {
        String sname = (String) getSingleParamValue("PreFrameScript");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Pre Frame Script node ("
                    + sname
                    + ") was not one of the "
                    + "source nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("cmd")))
            throw new PipelineException(
                "The HfsComposite Action requires that the source node specified by the Pre "
                    + "Frame Script parameter ("
                    + sname
                    + ") must have a single command script "
                    + "(.cmd) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          preFrame =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        }
      }

      {
        String sname = (String) getSingleParamValue("PostFrameScript");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Post Frame Script node ("
                    + sname
                    + ") was not one of the "
                    + "source nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("cmd")))
            throw new PipelineException(
                "The HfsComposite Action requires that the source node specified by the "
                    + "Post Frame Script parameter ("
                    + sname
                    + ") must have a single command "
                    + "script (.cmd) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          postFrame =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        }
      }
    }

    /* create the temporary Houdini command script */
    File hscript = createTemp(agenda, 0644, "cmd");
    try {
      FileWriter out = new FileWriter(hscript);

      FileSeq fseq =
          new FileSeq(
              PackageInfo.sProdDir.getPath() + nodeID.getWorkingParent(),
              agenda.getPrimaryTarget());
      if (fseq.hasFrameNumbers()) {
        FilePattern fpat = fseq.getFilePattern();
        FrameRange frange = fseq.getFrameRange();
        out.write(
            "opparm "
                + opname
                + " trange on\n"
                + "opparm "
                + opname
                + " f1 "
                + frange.getStart()
                + "\n"
                + "opparm "
                + opname
                + " f2 "
                + frange.getEnd()
                + "\n"
                + "opparm "
                + opname
                + " f3 "
                + frange.getBy()
                + "\n"
                + "opparm "
                + opname
                + " copoutput '"
                + fpat.getPrefix()
                + ".$F");

        if (fpat.getPadding() > 1) out.write(String.valueOf(fpat.getPadding()));

        out.write("." + fpat.getSuffix() + "'\n");
      } else {
        out.write("opparm " + opname + " trange off\n" + "opparm " + opname + " " + fseq + "\n");
      }

      if (preRender != null) out.write("opparm " + opname + " prerender '" + preRender + "'\n");

      if (postRender != null) out.write("opparm " + opname + " postrender '" + postRender + "'\n");

      if (preFrame != null) out.write("opparm " + opname + " preframe '" + preFrame + "'\n");

      if (postFrame != null) out.write("opparm " + opname + " postframe '" + postFrame + "'\n");

      out.write("opparm -c " + opname + " execute\n");

      out.close();
    } catch (IOException ex) {
      throw new PipelineException(
          "Unable to write temporary script file ("
              + hscript
              + ") for Job "
              + "("
              + agenda.getJobID()
              + ")!\n"
              + ex.getMessage());
    }

    /* create the wrapper shell script */
    File script = createTemp(agenda, 0755, "bash");
    try {
      FileWriter out = new FileWriter(script);
      out.write("#!/bin/bash\n\n" + "cat " + hscript + " | hscript -v " + source);
      out.close();
    } catch (IOException ex) {
      throw new PipelineException(
          "Unable to write temporary script file ("
              + script
              + ") for Job "
              + "("
              + agenda.getJobID()
              + ")!\n"
              + ex.getMessage());
    }

    try {
      return new SubProcessHeavy(
          agenda.getNodeID().getAuthor(),
          getName() + "-" + agenda.getJobID(),
          script.getPath(),
          new ArrayList<String>(),
          agenda.getEnvironment(),
          agenda.getWorkingDir(),
          outFile,
          errFile);
    } catch (Exception ex) {
      throw new PipelineException(
          "Unable to generate the SubProcess to perform this Action!\n" + ex.getMessage());
    }
  }
Example #6
0
  /**
   * Construct a {@link SubProcessHeavy SubProcessHeavy} instance which when executed will fulfill
   * the given action agenda.
   *
   * <p>
   *
   * @param agenda The agenda to be accomplished by the action.
   * @param outFile The file to which all STDOUT output is redirected.
   * @param errFile The file to which all STDERR output is redirected.
   * @return The SubProcess which will fulfill the agenda.
   * @throws PipelineException If unable to prepare a SubProcess due to illegal, missing or
   *     imcompatable information in the action agenda or a general failure of the prep method code.
   */
  public SubProcessHeavy prep(ActionAgenda agenda, File outFile, File errFile)
      throws PipelineException {
    NodeID nodeID = agenda.getNodeID();

    /* sanity checks */
    Path loadScene = null;
    Path saveScene = null;
    boolean isAscii = false;
    TreeMap<Integer, LinkedList<Path>> mel = new TreeMap<Integer, LinkedList<Path>>();
    {
      /* generate the filename of the Maya scene to load */
      {
        String sname = (String) getSingleParamValue("MayaScene");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Maya Scene node ("
                    + sname
                    + ") was not one of the source "
                    + "nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("ma") || suffix.equals("mb")))
            throw new PipelineException(
                "The MayaMEL Action requires that the source node specified by the Maya "
                    + "Scene parameter ("
                    + sname
                    + ") must have a single Maya scene file as "
                    + "its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          loadScene =
              new Path(PackageInfo.sProdPath, snodeID.getWorkingParent() + "/" + fseq.getPath(0));
        }
      }

      /* generate the name of the Maya scene to save */
      {
        Boolean save = (Boolean) getSingleParamValue("SaveResult");
        if ((save != null) && save) {
          FileSeq fseq = agenda.getPrimaryTarget();

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("ma") || suffix.equals("mb")))
            throw new PipelineException(
                "The MayaMEL Action requires that the primary target file sequence must "
                    + "be a single Maya scene file if the Save Result parameter is set!");

          isAscii = suffix.equals("ma");
          saveScene =
              new Path(PackageInfo.sProdPath, nodeID.getWorkingParent() + "/" + fseq.getPath(0));
        }
      }

      /* generate the table of MEL script files to evaluate */
      for (String sname : getSourceNames()) {
        Integer order = (Integer) getSourceParamValue(sname, "Order");
        FileSeq fseq = agenda.getPrimarySource(sname);
        if (fseq == null)
          throw new PipelineException(
              "Somehow an per-source Order parameter exists for a node ("
                  + sname
                  + ") "
                  + "which was not one of the source nodes!");

        String suffix = fseq.getFilePattern().getSuffix();
        if (!fseq.isSingle() || (suffix == null) || !suffix.equals("mel"))
          throw new PipelineException(
              "The MayaMEL Action requires that the source node ("
                  + sname
                  + ") with "
                  + "per-source Order parameter must have a single MEL script file as its "
                  + "primary file sequence!");

        NodeID snodeID = new NodeID(nodeID, sname);
        Path script =
            new Path(PackageInfo.sProdPath, snodeID.getWorkingParent() + "/" + fseq.getPath(0));

        LinkedList<Path> scripts = mel.get(order);
        if (scripts == null) {
          scripts = new LinkedList<Path>();
          mel.put(order, scripts);
        }

        scripts.add(script);
      }
    }

    /* create a temporary MEL script file */
    File script = createTemp(agenda, 0755, "mel");
    try {
      FileWriter out = new FileWriter(script);

      /* a workaround needed in "maya -batch" mode */
      out.write("// WORK AROUNDS:\n" + "lightlink -q;\n\n");

      /* rename the current scene as the output scene */
      if (saveScene != null) {
        out.write(
            "// SCENE SETUP\n"
                + "file -rename \""
                + saveScene
                + "\";\n"
                + "file -type \""
                + (isAscii ? "mayaAscii" : "mayaBinary")
                + "\";\n\n");
      }

      /* evaluate the MEL scripts */
      if (!mel.isEmpty()) {
        out.write("// MEL SCRIPTS \n");
        for (LinkedList<Path> scripts : mel.values()) {
          for (Path spath : scripts) out.write("source \"" + spath + "\";\n");
        }
        out.write("\n");
      }

      /* save the file */
      if (saveScene != null) out.write("// SAVE\n" + "file -save;\n");

      out.close();
    } catch (IOException ex) {
      throw new PipelineException(
          "Unable to write temporary MEL script file ("
              + script
              + ") for Job "
              + "("
              + agenda.getJobID()
              + ")!\n"
              + ex.getMessage());
    }

    /* create the process to run the action */
    try {
      ArrayList<String> args = new ArrayList<String>();
      args.add("-batch");
      args.add("-script");
      args.add(script.getPath());

      if (loadScene != null) {
        args.add("-file");
        args.add(loadScene.toOsString());
      }

      String program = "maya";
      if (PackageInfo.sOsType == OsType.Windows) program = (program + ".exe");

      return new SubProcessHeavy(
          agenda.getNodeID().getAuthor(),
          getName() + "-" + agenda.getJobID(),
          program,
          args,
          agenda.getEnvironment(),
          agenda.getWorkingDir(),
          outFile,
          errFile);
    } catch (Exception ex) {
      throw new PipelineException(
          "Unable to generate the SubProcess to perform this Action!\n" + ex.getMessage());
    }
  }
Example #7
0
  /**
   * Construct a {@link SubProcessHeavy SubProcessHeavy} instance which when executed will fulfill
   * the given action agenda.
   *
   * <p>
   *
   * @param agenda The agenda to be accomplished by the action.
   * @param outFile The file to which all STDOUT output is redirected.
   * @param errFile The file to which all STDERR output is redirected.
   * @return The SubProcess which will fulfill the agenda.
   * @throws PipelineException If unable to prepare a SubProcess due to illegal, missing or
   *     imcompatable information in the action agenda or a general failure of the prep method code.
   */
  public SubProcessHeavy prep(ActionAgenda agenda, File outFile, File errFile)
      throws PipelineException {
    NodeID nodeID = agenda.getNodeID();

    /* sanity checks */
    File targetScene = null;
    ArrayList<File> sourceScenes = new ArrayList<File>();
    ArrayList<String> mergePatterns = new ArrayList<String>();
    File preBuild = null;
    File postBuild = null;
    File preScene = null;
    File postScene = null;
    {
      DoubleMap<Integer, String, TreeSet<FileSeq>> sources =
          new DoubleMap<Integer, String, TreeSet<FileSeq>>();

      for (String sname : agenda.getSourceNames()) {
        if (hasSourceParams(sname)) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          Integer order = (Integer) getSourceParamValue(sname, "Order");
          addSourceSeq(order, sname, fseq, sources);
        }

        for (FileSeq fseq : agenda.getSecondarySources(sname)) {
          FilePattern fpat = fseq.getFilePattern();
          if (hasSecondarySourceParams(sname, fpat)) {
            Integer order = (Integer) getSecondarySourceParamValue(sname, fpat, "Order");
            addSourceSeq(order, sname, fseq, sources);
          }
        }
      }

      for (Integer order : sources.keySet()) {
        for (String sname : sources.get(order).keySet()) {
          for (FileSeq fseq : sources.get(order).get(sname)) {
            String pattern = null;
            if (fseq.equals(agenda.getPrimarySource(sname)))
              pattern = (String) getSourceParamValue(sname, "MergePattern");
            else {
              FilePattern fpat = fseq.getFilePattern();
              pattern = (String) getSecondarySourceParamValue(sname, fpat, "MergePattern");
            }

            if ((pattern == null) || (pattern.length() == 0))
              throw new PipelineException(
                  "The Merge Pattern for file sequence ("
                      + fseq
                      + ") of source node "
                      + "("
                      + sname
                      + ") was not specified!");

            NodeID snodeID = new NodeID(nodeID, sname);
            File sfile =
                new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));

            sourceScenes.add(sfile);
            mergePatterns.add(pattern);
          }
        }
      }

      /* generate the name of the Houdini scene to save */
      {
        FileSeq fseq = agenda.getPrimaryTarget();
        String suffix = fseq.getFilePattern().getSuffix();
        if (!fseq.isSingle() || (suffix == null) || !suffix.equals("hip"))
          throw new PipelineException(
              "The HfsBuild Action requires that the primary target file sequence must "
                  + "be a single Houdini scene file!");

        targetScene =
            new File(PackageInfo.sProdDir, nodeID.getWorkingParent() + "/" + fseq.getFile(0));
      }

      /* command script files */
      {
        String sname = (String) getSingleParamValue("PreBuildScript");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Pre Build Script node ("
                    + sname
                    + ") was not one of the "
                    + "source nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("cmd")))
            throw new PipelineException(
                "The HfsBuild Action requires that the source node specified by the Pre "
                    + "Build Script parameter ("
                    + sname
                    + ") must have a single command "
                    + "script (.cmd) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          preBuild =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        }
      }

      {
        String sname = (String) getSingleParamValue("PostBuildScript");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Post Build Script node ("
                    + sname
                    + ") was not one of the "
                    + "source nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("cmd")))
            throw new PipelineException(
                "The HfsBuild Action requires that the source node specified by the Post "
                    + "Build Script parameter ("
                    + sname
                    + ") must have a single command "
                    + "script (.cmd) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          postBuild =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        }
      }

      {
        String sname = (String) getSingleParamValue("PreSceneScript");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Pre Scene Script node ("
                    + sname
                    + ") was not one of the "
                    + "source nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("cmd")))
            throw new PipelineException(
                "The HfsBuild Action requires that the source node specified by the Pre "
                    + "Scene Script parameter ("
                    + sname
                    + ") must have a single command script "
                    + "(.cmd) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          preScene =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        }
      }

      {
        String sname = (String) getSingleParamValue("PostSceneScript");
        if (sname != null) {
          FileSeq fseq = agenda.getPrimarySource(sname);
          if (fseq == null)
            throw new PipelineException(
                "Somehow the Post Scene Script node ("
                    + sname
                    + ") was not one of the "
                    + "source nodes!");

          String suffix = fseq.getFilePattern().getSuffix();
          if (!fseq.isSingle() || (suffix == null) || !(suffix.equals("cmd")))
            throw new PipelineException(
                "The HfsBuild Action requires that the source node specified by the Post "
                    + "Scene Script parameter ("
                    + sname
                    + ") must have a single command script "
                    + "(.cmd) as its primary file sequence!");

          NodeID snodeID = new NodeID(nodeID, sname);
          postScene =
              new File(PackageInfo.sProdDir, snodeID.getWorkingParent() + "/" + fseq.getFile(0));
        }
      }
    }

    /* create the temporary Houdini command script */
    File hscript = createTemp(agenda, 0644, "cmd");
    try {
      FileWriter out = new FileWriter(hscript);

      if (preBuild != null) out.write("source " + preBuild + "\n");

      /* load the source scenes */
      int wk;
      for (wk = 0; wk < sourceScenes.size(); wk++) {
        File sourceScene = sourceScenes.get(wk);
        String pattern = mergePatterns.get(wk);

        if (preScene != null) out.write("source " + preScene + "\n");

        out.write("mread");
        if (wk > 0) out.write(" -o -m " + pattern);
        out.write(" " + sourceScene + "\n");

        if (postScene != null) out.write("source " + postScene + "\n");
      }

      if (postBuild != null) out.write("source " + postBuild + "\n");

      /* save the file */
      out.write("mwrite " + targetScene + "\n");

      out.close();
    } catch (IOException ex) {
      throw new PipelineException(
          "Unable to write temporary command file ("
              + hscript
              + ") for Job "
              + "("
              + agenda.getJobID()
              + ")!\n"
              + ex.getMessage());
    }

    /* create the wrapper shell script */
    File script = createTemp(agenda, 0755, "bash");
    try {
      FileWriter out = new FileWriter(script);
      out.write("#!/bin/bash\n\n" + "cat " + hscript + " | hscript");
      out.close();
    } catch (IOException ex) {
      throw new PipelineException(
          "Unable to write temporary script file ("
              + script
              + ") for Job "
              + "("
              + agenda.getJobID()
              + ")!\n"
              + ex.getMessage());
    }

    try {
      return new SubProcessHeavy(
          agenda.getNodeID().getAuthor(),
          getName() + "-" + agenda.getJobID(),
          script.getPath(),
          new ArrayList<String>(),
          agenda.getEnvironment(),
          agenda.getWorkingDir(),
          outFile,
          errFile);
    } catch (Exception ex) {
      throw new PipelineException(
          "Unable to generate the SubProcess to perform this Action!\n" + ex.getMessage());
    }
  }