Beispiel #1
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 {
    /* create the process to run the action */
    try {
      ArrayList<String> args = new ArrayList<String>();

      for (File file : agenda.getPrimaryTarget().getFiles()) args.add(file.toString());

      for (FileSeq fseq : agenda.getSecondaryTargets()) {
        for (File file : fseq.getFiles()) args.add(file.toString());
      }

      return new SubProcessHeavy(
          agenda.getNodeID().getAuthor(),
          getName() + "-" + agenda.getJobID(),
          "touch",
          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());
    }
  }
    @Override
    public void initPhase() throws PipelineException {
      /* initialize builder parameters from source images node information */
      setParamValue(new ParamMapping(DeliverNamer.aDeliverable), pSourcePrefix);
      setParamValue(new ParamMapping(aNotes), pSourceVersion.getMessage());
      setParamValue(new ParamMapping(aClientVersion), pSourceVersion.getVersionID().toString());
      setParamValue(new ParamMapping(aClientShotName), pSourcePrefix);

      /* replace placeholder parameters with the names of the available
      slate script, format script and codec settings nodes */
      {
        Path path = pProjectNamer.getSlateNukeScriptsParentPath();
        ArrayList<String> pnames = findChildNodeNames(path);
        if ((pnames == null) || pnames.isEmpty())
          throw new PipelineException(
              "Unable to find any slate creation Nuke script nodes in (" + path + ")!");

        UtilityParam param =
            new EnumUtilityParam(
                aSlateScript,
                "Select the master slate creation Nuke script to use.",
                pnames.get(0),
                pnames);
        replaceParam(param);
      }

      {
        Path path = pProjectNamer.getFormatNukeScriptsParentPath();
        ArrayList<String> pnames = findChildNodeNames(path);
        if ((pnames == null) || pnames.isEmpty())
          throw new PipelineException(
              "Unable to find any image formatting Nuke script nodes in (" + path + ")!");

        UtilityParam param =
            new EnumUtilityParam(
                aFormatScript,
                "Select final image formatting Nuke script to use.",
                pnames.get(0),
                pnames);
        replaceParam(param);
      }

      {
        Path path = pProjectNamer.getQtCodecSettingsParentPath();
        ArrayList<String> pnames = findChildNodeNames(path);
        if ((pnames == null) || pnames.isEmpty())
          throw new PipelineException(
              "Unable to find any QuickTime codec settings nodes in (" + path + ")!");

        UtilityParam param =
            new EnumUtilityParam(
                aCodecSettings,
                "Select the QuickTime codec settings to encode the final movie.",
                pnames.get(0),
                pnames);
        replaceParam(param);
      }
    }
Beispiel #3
0
  /**
   * Construct a {@link SubProcessLight} instance which when executed will launch an editor program
   * to view the given file sequence as arguments.
   *
   * <p>The default implementation executes the editor program obtained with {@link #getProgram
   * getProgram} method under the given environment. Subclasses should override this method if more
   * specialized behavior or different command line arguments are needed in order to launch the
   * editor for the given file sequence.
   *
   * <p>
   *
   * @param author The name of the user owning the files.
   * @param fseq The file sequence to edit.
   * @param env The environment under which the editor is run.
   * @param dir The working directory where the editor is run.
   * @return The controlling <CODE>SubProcessLight</CODE> instance.
   * @throws PipelineException If unable to launch the editor.
   * @see SubProcessLight
   */
  public SubProcessLight prep(String author, FileSeq fseq, Map<String, String> env, File dir)
      throws PipelineException {
    if (!fseq.isSingle())
      throw new PipelineException(
          "The " + getName() + " Editor can only edit a single file at a time!");

    ArrayList<String> args = new ArrayList<String>();
    args.add("-eol.mode=LF");
    args.add(fseq.getPath(0).toOsString());

    return new SubProcessLight(author, getName(), getProgram(), args, env, dir);
  }
  /**
   * Launch GIMP with a script which will compare the given two images using layers.
   *
   * <p>
   *
   * @param fileA The absolute path to the first file.
   * @param fileB The absolute path to the second file.
   * @param env The environment under which the comparator is run.
   * @param dir The working directory where the comparator is run.
   * @return The controlling <CODE>SubProcessLight</CODE> instance.
   * @throws PipelineException If unable to launch the comparator.
   * @see SubProcessLight
   */
  public SubProcessLight launch(File fileA, File fileB, Map<String, String> env, File dir)
      throws PipelineException {
    ArrayList<String> args = new ArrayList<String>();
    args.add(fileA.toString());
    args.add("-compare");
    args.add(fileB.toString());

    SubProcessLight proc = new SubProcessLight(getName(), getProgram(), args, env, dir);
    proc.start();

    return proc;
  }
  /**
   * 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 fromPath = null;
    FileSeq fromSeq = null;
    FileSeq toSeq = null;
    {
      ArrayList<String> formats = new ArrayList<String>();
      formats.add("xml");

      String sname = (String) getSingleParamValue("XmlSource");

      if (sname == null) throw new PipelineException("The Image Source was not set!");

      String xmlpath = null;
      if (sname != null) {
        FileSeq fxml = agenda.getPrimarySource(sname);
        xmlpath = fxml.toString();
      }

      NodeID snodeID = new NodeID(nodeID, sname);

      ArrayList<String> suffixes = new ArrayList<String>();
      suffixes.add("html");
      suffixes.add("htm");
      Path targetPath = getPrimaryTargetPath(agenda, suffixes, "Html fil");

      // ********************************************************************
      // Build the mencoder command
      // ********************************************************************
      ArrayList<String> args = new ArrayList<String>();

      args.add("/intranet/jpt/phpCliPrograms/Edit2pipe.php");
      args.add("none");
      args.add(xmlpath);
      args.add(xmlpath);

      args.add(targetPath.toOsString());

      // Create sub process
      return createSubProcess(
          agenda,
          "php5",
          args,
          agenda.getEnvironment(),
          agenda.getTargetPath().toFile(),
          outFile,
          errFile);
    }
  }
Beispiel #6
0
  /** Get an initial set of action parameters associated with an upstream node. */
  public TreeMap<String, ActionParam> getInitialSourceParams() {
    TreeMap<String, ActionParam> params = new TreeMap<String, ActionParam>();

    {
      ActionParam param = new IntegerActionParam("AnotherInteger", "An integer parameter.", 123);
      params.put(param.getName(), param);
    }

    {
      ActionParam param = new DoubleActionParam("AnotherDouble", "An double parameter.", 123.456);
      params.put(param.getName(), param);
    }

    {
      ArrayList<String> colors = new ArrayList<String>();
      colors.add("Red");
      colors.add("Yello");
      colors.add("Green");
      colors.add("Cyan");
      colors.add("Blue");
      colors.add("Purple");

      ActionParam param = new EnumActionParam("AnotherEnum", "An enum parameter.", "Cyan", colors);
      params.put(param.getName(), param);
    }

    {
      ActionParam param = new IntegerActionParam("SecondInteger", "A second integer parameter.", 2);
      params.put(param.getName(), param);
    }

    {
      ActionParam param = new BooleanActionParam("AnotherBoolean", "A boolean parameter.", true);
      params.put(param.getName(), param);
    }

    {
      ActionParam param = new LinkActionParam("AnotherLink", "An upstream link parameter.", null);
      params.put(param.getName(), param);
    }

    return params;
  }
  /** Get an initial set of action parameters associated with an upstream node. */
  public TreeMap<String, ActionParam> getInitialSourceParams() {
    TreeMap<String, ActionParam> params = new TreeMap<String, ActionParam>();

    {
      ArrayList<String> choices = new ArrayList<String>();
      choices.add(aModel);
      choices.add(aAnimation);

      ActionParam param =
          new EnumActionParam(
              aSceneType, "Is this a model scene or an animation scene.", aModel, choices);
      params.put(param.getName(), param);
    }

    addOldBuildTypeSourceParam(params);
    addNamespaceSourceParam(params);
    addPrefixNameSourceParam(params);

    return params;
  }
  /**
   * Returns a list of Actions required by this Builder, indexed by the toolset that needs to
   * contain them.
   *
   * <p>Builders should override this method to provide their own requirements. This validation gets
   * performed after all the Setup Passes have been run but before any Construct Passes are run.
   */
  @SuppressWarnings("unchecked")
  @Override
  public MappedArrayList<String, PluginContext> getNeededActions() {
    ArrayList<PluginContext> plugins = new ArrayList<PluginContext>();
    plugins.add(new PluginContext("Touch"));
    plugins.add(new PluginContext("NukeRead"));
    plugins.add(
        new PluginContext(
            "NukeSubstComp", "Temerity", new Range<VersionID>(new VersionID("2.4.3"), null)));
    plugins.add(new PluginContext("DjvUnixQt"));
    plugins.add(
        new PluginContext(
            "SlateSubst", "ICVFX", new Range<VersionID>(new VersionID("1.5.0"), null)));

    MappedArrayList<String, PluginContext> toReturn = new MappedArrayList<String, PluginContext>();
    toReturn.put(getToolset(), plugins);

    return toReturn;
  }
Beispiel #9
0
  public TestAction() {
    super(
        "Test",
        new VersionID("1.1.0"),
        "Temerity",
        "A test action with at lease one of each type of parameter.");

    {
      ActionParam param = new DoubleActionParam("SomeDouble", "An double parameter.", 123.456);
      addSingleParam(param);
    }

    {
      ActionParam param = new BooleanActionParam("SomeBoolean", "An boolean parameter.", false);
      addSingleParam(param);
    }

    {
      ActionParam param = new StringActionParam("SomeString", "A short string parameter.", "test");
      addSingleParam(param);
    }

    {
      ActionParam param =
          new StringActionParam("ExtraString", "An extra short string parameter.", "extra");
      addSingleParam(param);
    }

    {
      ArrayList<String> colors = new ArrayList<String>();
      colors.add("Red");
      colors.add("Yellow");
      colors.add("Green");
      colors.add("Cyan");
      colors.add("Blue");
      colors.add("Purple");

      ActionParam param = new EnumActionParam("SomeEnum", "An enum parameter.", "Purple", colors);
      addSingleParam(param);
    }
  }
  /**
   * 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
  /**
   * Required constructor for to launch the builder.
   *
   * @param mclient The master manager connection.
   * @param qclient The queue manager connection.
   * @param builderInfo Information that is shared among all builders in a given invocation.
   */
  public QtDeliverBuilder(
      MasterMgrClient mclient, QueueMgrClient qclient, BuilderInformation builderInfo)
      throws PipelineException {
    super(
        "QtDeliver",
        "A builder for constructing the nodes required to prepare an image sequence "
            + "for delivery to the client or for internal review.",
        mclient,
        qclient,
        builderInfo,
        new StudioDefinitions(
            mclient,
            qclient,
            UtilContext.getDefaultUtilContext(mclient),
            builderInfo.getLoggerName()),
        null,
        null,
        null);

    /* setup builder parameters */
    {
      /* hide and set parameters which shouldn't be visible to the user */
      {
        disableParam(new ParamMapping(BaseUtil.aUtilContext, UtilContextUtilityParam.aAuthor));
        disableParam(new ParamMapping(BaseUtil.aUtilContext, UtilContextUtilityParam.aView));

        // disableParam(new ParamMapping(aCheckinWhenDone));
        setParamValue(new ParamMapping(aCheckinWhenDone), true);

        disableParam(new ParamMapping(aReleaseOnError));
        setParamValue(new ParamMapping(aReleaseOnError), true);
      }

      /* the source images being delivered */
      {
        UtilityParam param =
            new NodePathUtilityParam(
                aSourceNode,
                "The fully resolved name of the node containing the images to be delivered.",
                new Path("/"));
        addParam(param);
      }

      {
        UtilityParam param =
            new StringUtilityParam(
                aSourceVersion,
                "The revision number of the source images node being delivered.",
                null);
        addParam(param);
      }

      /* deliverable info */
      {
        ArrayList<String> choices = new ArrayList<String>();
        choices.add("Test");
        choices.add("Temp");
        choices.add("For Approval");
        choices.add("For Preview");
        choices.add("Final");

        UtilityParam param =
            new EnumUtilityParam(
                aDeliveryType, "The reason the deliverable was created.", "For Approval", choices);
        addParam(param);
      }

      {
        UtilityParam param =
            new StringUtilityParam(
                DeliverNamer.aDeliverable,
                "The name for the content of the images being delivered to the client. "
                    + "Typically this will be based on a combination of the shot (or asset) and "
                    + "Pipeline task which generated the images such as: \"ri120-blot\" or "
                    + "\"rorschach-model\".",
                null);
        addParam(param);
      }

      {
        UtilityParam param =
            new StringUtilityParam(
                aClientVersion,
                "The client revision number.  This revision number is unrelated to Pipeline's "
                    + "revision number for the source images and is purely for external client use.",
                null);
        addParam(param);
      }

      {
        UtilityParam param =
            new StringUtilityParam(
                aClientShotName, "The filename of the sequence delivered to the client.", null);
        addParam(param);
      }

      {
        UtilityParam param =
            new StringUtilityParam(
                aNotes,
                "A short description of the Deliverable to be included in the image slates.  "
                    + "If not specified the check-in message associated with the source images node "
                    + "will be used instead.",
                null);
        addParam(param);
      }

      /* Nuke components */
      {
        UtilityParam param =
            new PlaceholderUtilityParam(
                aSlateScript, "Select the master slate creation Nuke script to use.");
        addParam(param);
      }

      {
        UtilityParam param =
            new IntegerUtilityParam(
                aSlateHold,
                "The number of frames to hold the constant slate image before the images being "
                    + "reviewed begin animating.",
                1);
        addParam(param);
      }

      {
        UtilityParam param =
            new PlaceholderUtilityParam(
                aFormatScript, "Select the final image formatting Nuke script to use.");
        addParam(param);
      }

      {
        UtilityParam param =
            new PlaceholderUtilityParam(
                aCodecSettings, "Select the QuickTime codec settings to encode the final movie.");
        addParam(param);
      }
    }

    /* create the setup passes */
    {
      addSetupPass(new QuickTimeEssentials());
      addSetupPass(new SetupDeliveryParams());
      addSetupPass(new GetPrerequisites());
    }

    /* setup the default editors */
    setCommonDefaultEditors();

    /* create the construct passes */
    {
      ConstructPass build = new BuildNodesPass();
      addConstructPass(build);
    }

    /* specify the layout of the parameters for each pass in the UI */
    {
      PassLayoutGroup layout = new PassLayoutGroup("Root", "Root Layout");

      {
        AdvancedLayoutGroup sub = new AdvancedLayoutGroup("QuickTimeEssentials", true);

        sub.addEntry(1, aUtilContext);
        sub.addEntry(1, null);
        sub.addEntry(1, aCheckinWhenDone);
        sub.addEntry(1, aActionOnExistence);
        sub.addEntry(1, aReleaseOnError);
        sub.addEntry(1, null);
        sub.addEntry(1, aSourceNode);
        sub.addEntry(1, aSourceVersion);

        layout.addPass(sub.getName(), sub);
      }

      {
        AdvancedLayoutGroup sub = new AdvancedLayoutGroup("None", true);
        layout.addPass(sub.getName(), sub);
      }

      {
        AdvancedLayoutGroup sub = new AdvancedLayoutGroup("DeliveryDetails", true);
        sub.addEntry(1, aDeliveryType);
        sub.addEntry(1, DeliverNamer.aDeliverable);
        sub.addEntry(1, aClientVersion);
        sub.addEntry(1, aClientShotName);
        sub.addEntry(1, aNotes);
        sub.addEntry(1, null);
        sub.addEntry(1, aSlateScript);
        sub.addEntry(1, aSlateHold);
        sub.addEntry(1, null);
        sub.addEntry(1, aFormatScript);
        sub.addEntry(1, aCodecSettings);

        layout.addPass(sub.getName(), sub);
      }

      setLayout(layout);
    }

    disableParam(new ParamMapping(aActionOnExistence));
    setParamValue(new ParamMapping(aActionOnExistence), ActionOnExistence.Conform.toString());
  }
Beispiel #12
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());
    }
  }
  /** Add the UI components for the given file sequence to the panel. */
  private void addFileSeqPanel(FileSeq fseq) {
    boolean isPresentInWorking = false;
    if ((pStatus != null) && pStatus.hasLightDetails()) {
      NodeDetailsLight details = pStatus.getLightDetails();
      NodeMod mod = details.getWorkingVersion();
      if (mod != null) {
        if (mod.getPrimarySequence().equals(fseq)) isPresentInWorking = true;
        else {
          for (FileSeq sfseq : mod.getSecondarySequences()) {
            if (sfseq.equals(fseq)) {
              isPresentInWorking = true;
              break;
            }
          }
        }
      }
    }

    /* collate the row information */
    ArrayList<VersionID> vids = new ArrayList<VersionID>();
    ArrayList<FileSeq> singles = new ArrayList<FileSeq>();
    TreeSet<FileSeq> enabled = new TreeSet<FileSeq>();
    TreeMap<FileSeq, FileState> fstates = new TreeMap<FileSeq, FileState>();
    TreeMap<FileSeq, NativeFileInfo> finfos = new TreeMap<FileSeq, NativeFileInfo>();
    TreeMap<FileSeq, QueueState> qstates = new TreeMap<FileSeq, QueueState>();
    TreeMap<FileSeq, Boolean[]> novel = new TreeMap<FileSeq, Boolean[]>();
    {
      TreeMap<FileSeq, Integer> wsingles = new TreeMap<FileSeq, Integer>();
      if ((pStatus != null) && pStatus.hasLightDetails()) {
        if (isPresentInWorking) {
          if (pStatus.hasHeavyDetails()) {
            NodeDetailsHeavy details = pStatus.getHeavyDetails();

            FileState[] fs = details.getFileStates(fseq);
            QueueState[] qs = details.getQueueStates();
            NativeFileInfo[] infos = details.getFileInfos(fseq);
            if ((fs != null) && (qs != null) && (infos != null)) {
              int wk;
              for (wk = 0; wk < fs.length; wk++) {
                FileSeq sfseq = new FileSeq(fseq, wk);
                wsingles.put(sfseq, wk);

                fstates.put(sfseq, fs[wk]);
                finfos.put(sfseq, infos[wk]);
                qstates.put(sfseq, qs[wk]);

                if (fs[wk] != FileState.CheckedIn) enabled.add(sfseq);
              }
            }
          } else {
            NodeDetailsLight details = pStatus.getLightDetails();

            int wk;
            for (wk = 0; wk < fseq.numFrames(); wk++) {
              FileSeq sfseq = new FileSeq(fseq, wk);
              wsingles.put(sfseq, wk);

              if (details.getVersionState() == VersionState.CheckedIn) {
                fstates.put(sfseq, FileState.CheckedIn);
                qstates.put(sfseq, QueueState.Undefined);
              } else {
                enabled.add(sfseq);
              }
            }
          }
        }

        {
          vids.addAll(pNovelty.keySet());
          Collections.reverse(vids);

          int idx = 0;
          for (VersionID vid : vids) {
            TreeMap<FileSeq, boolean[]> table = pNovelty.get(vid);
            for (FileSeq nfseq : table.keySet()) {
              if (fseq.similarTo(nfseq)) {
                boolean[] flags = table.get(nfseq);

                int wk;
                for (wk = 0; wk < flags.length; wk++) {
                  FileSeq sfseq = new FileSeq(nfseq, wk);
                  if (!wsingles.containsKey(sfseq)) wsingles.put(sfseq, null);

                  Boolean[] rflags = novel.get(sfseq);
                  if (rflags == null) {
                    rflags = new Boolean[pNovelty.size()];
                    novel.put(sfseq, rflags);
                  }

                  rflags[idx] = new Boolean(flags[wk]);
                }

                break;
              }
            }

            idx++;
          }
        }
      }

      TreeMap<Integer, FileSeq> order = new TreeMap<Integer, FileSeq>();
      for (FileSeq sfseq : wsingles.keySet()) {
        int frame = -1;
        if (sfseq.hasFrameNumbers()) frame = sfseq.getFrameRange().getStart();

        order.put(frame, sfseq);
      }

      singles.addAll(order.values());
    }

    /* add the panel */
    {
      JFileSeqPanel panel =
          new JFileSeqPanel(
              this,
              pManagerPanel,
              pStatus,
              pPrivilegeDetails,
              fseq,
              vids,
              pOffline,
              singles,
              fstates,
              finfos,
              qstates,
              enabled,
              novel,
              pIsListLayout);

      if (pIsListLayout) pFileSeqsBox.add(panel);
      else pFileSeqsTab.addTab(fseq.getFilePattern().toString(), sTabIcon, panel);

      pFileSeqPanels.put(fseq, panel);
    }
  }
  /**
   * 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());
    }
  }
  public TaskAnnotation() {
    super(
        "Task",
        new VersionID("2.4.1"),
        "Temerity",
        "Signifies the nodes that make up a common production goal (task).");

    {
      AnnotationParam param =
          new StringAnnotationParam(
              aProjectName, "The name of the project this task part of achieving.", null);
      addParam(param);
    }

    {
      AnnotationParam param =
          new EnumAnnotationParam(
              aEntityType,
              "The Shotgun entity type owning this task or [[IGNORE]] if not using Shotgun.",
              EntityType.Ignore.toTitle(),
              EntityType.titles());
      addParam(param);
    }

    {
      AnnotationParam param =
          new StringAnnotationParam(
              aTaskName,
              "The name of the overall production goal this node is used to achieve.  "
                  + "Typically, this is the name of a shot or the asset name.",
              null);
      addParam(param);
    }

    {
      AnnotationParam param =
          new EnumAnnotationParam(
              aTaskType,
              "The standard type of production goal this node is used to achieve.",
              TaskType.Asset.toTitle(),
              TaskType.titles());
      addParam(param);
    }

    {
      AnnotationParam param =
          new StringAnnotationParam(
              aCustomTaskType,
              "A unique type of production goal this node is used to achieve which is not one "
                  + "of the standard type available in TaskType.  If a custom type is specified, the "
                  + "TaskType parameter should be set to [[CUSTOM]].",
              null);
      addParam(param);
    }

    {
      AnnotationParam param =
          new EnumAnnotationParam(
              aPurpose,
              "The way this node is intended to be used.",
              NodePurpose.Edit.toTitle(),
              NodePurpose.commonTitles());
      addParam(param);
    }

    {
      ArrayList<String> layout = new ArrayList<String>();
      layout.add(aProjectName);
      layout.add(aEntityType);
      layout.add(aTaskName);
      layout.add(aTaskType);
      layout.add(aCustomTaskType);
      layout.add(aPurpose);

      setLayout(layout);
    }
  }