7 Replies Latest reply on May 17, 2017 12:26 PM by johnrellis

    Get output from LrTasks.execute(cmd)

    rderimay Level 1

      I would like to know if there is a way to get the output of a LrTasks.execute(cmd) call, without piping it to an external text file and reading it back ?

       

       

      Many thanks !

        • 1. Re: Get output from LrTasks.execute(cmd)
          johnrellis Most Valuable Participant

          Including output redirection to a temp file in the command line is the only documented way of capturing the output.  There is the undocumented LrRemoteCommunication which appears to start a task with pipes for reading and writing, but I haven't seen any reports of anyone figuring out how that works.

           

          Here is the utility function I used for running commands:

           

          --[[----------------------------------------------------------------------------
          public int exitCode, string output, string errOutput
          safeExecute (string commandLine [, boolean getOutput])
          
          Executes the command line "commandLine"in the platform shell via
          LrTasks.execute, working around a bug in execute() on Windows where quoted
          program names aren't accepted.
          
          If "getOutput" is true, "output" will contain standard out and standard
          error and "errOutput" will be "".  If "getOutput" is "separate", then
          "output" will contain standard out and "errOutput" will contain standard
          error.  If "getOutput" is false, then both "output" and "errOutput" will be
          "".
          
          Returns in "exitCode" the exit code of the command line. If any errors
          occur in safeExecute itself, "exitCode" will be -1, and "output" and
          "errOutput" will be:
          
          getOuptut == "separate": "", <error message>
          otherwise:              <error message>, ""
          ------------------------------------------------------------------------------]]
          
          function Util.safeExecute (commandLine, getOutput)
          return LrFunctionContext.callWithContext ("", function (context)
              local outFile, errFile
          
              context:addCleanupHandler (function ()
                  if outFile then LrFileUtils.delete (outFile) end
                  if errFile then LrFileUtils.delete (errFile) end
                  end)
                 
              if getOutput then
                  local uuid = LrUUID.generateUUID ()
                  outFile = child (getStandardFilePath ("temp"), uuid .. ".out")
                  commandLine = commandLine .. ' > "' .. outFile .. '"'
          
          
                  if getOutput == "separate" then
                      errFile = child (getStandardFilePath ("temp"), uuid .. ".err")
                      commandLine = commandLine .. ' 2>"' .. errFile .. '"'
                  else
                      commandLine = commandLine .. ' 2>&1'
                      end
                  end
          
              if WIN_ENV then commandLine = '"' .. commandLine .. '"' end
              local exitStatus = LrTasks.execute (commandLine)
          
              local output, errOutput, success = "", ""
          
              local function outputErr (file, output)
                  local err = string.format ("Couldn't read output:\n%s\n%s",
                      file, output)
                  if getOutput == "separate" then
                      return -1, "", err
                  else
                      return -1, err, ""
                      end
                  end
          
              if outFile then
                  success, output = pcall (LrFileUtils.readFile, outFile)
                  if not success then return outputErr (outFile, output) end
                  end
              if errFile then
                  success, errOutput = pcall (LrFileUtils.readFile, errFile)
                  if not success then return outputErr (errFile, errOutput) end
                  end
          
              return exitStatus, output, errOutput
              end) end
          
          • 2. Re: Get output from LrTasks.execute(cmd)
            rderimay Level 1

            ok, bad news... Thanks !

            • 3. Re: Get output from LrTasks.execute(cmd)
              martinl90743871

              Ji John,

               

              The problem with that is for example LrUUID seems to be unavailable for some version of Windows and Lr.
              Do you have any idea until wich version of Lr your solution is working?

               

              I'm using io.popen instead currently, but it does not work on Lightroom 4 which is a bit sad, as I don't perform amazing function with it.

               

              For example, I just try to perform a uname to know if the OS is Mac or not and perform an unzip as well.

               

              Do you have any clue?

              • 4. Re: Get output from LrTasks.execute(cmd)
                johnrellis Most Valuable Participant

                The problem with that is for example LrUUID seems to be unavailable for some version of Windows and Lr.

                LrUUID is available in LR 6 and LR 5 (OS X and Windows 10).  It is also available in LR 4 (OS X).  I haven't tested other combinations.  Which combination of LR and Windows have you observed that doesn't have LrUUID?

                 

                It's easy enough to make an adequate replacement for LrUUID.generateUUID().  Append the string versions of these three values:

                - require "Info".LrToolkitIdentifier

                - LrDate.currentTime ()

                - a global incrementing counter

                 

                This will give an ID that's unique across all plugins executing in that instance of LR.

                • 5. Re: Get output from LrTasks.execute(cmd)
                  johnrellis Most Valuable Participant

                  I just try to perform a uname to know if the OS is Mac or not and perform an unzip as well.

                  If all you want to know is whether the current instance of LR is running on Mac or Windows, use the global variables MAC_ENV or WIN_ENV, e.g.

                   

                  if MAC_ENV then ... else ... end
                  
                  • 6. Re: Get output from LrTasks.execute(cmd)
                    martinl90743871 Level 1

                    Thanks John,

                     

                    Yes I changed it with these global variables. I didn't know them before (I should read all the documentation.. ;-) )

                     

                     

                    LR4 and Windows seems to not working, but not sure.. But yes, you're right it's very easy to perform a "fake" UUID.
                    My most concerned problem was that the io.popen was not working on LR 4 even if the action I was trying to perform should be possible in this environment.

                     

                    I'll try to use your method. Did you see any performance issue or combination that result to a bug? Or it is working in all version (after LR 3)?

                    • 7. Re: Get output from LrTasks.execute(cmd)
                      johnrellis Most Valuable Participant

                      I haven't observed any performance issues with Util.safeExecute() in LR 4.   I no longer test my existing plugins with LR 4, so I might not have noticed particular problems, but I haven't received any customer reports either. 

                       

                      In general, my newer plugins require LR 5.7 or LR 6.0, typically because they use SDK features not available in LR 4.  Since LR 5 was released 5 years ago, there's not a big incentive for me to support LR 4.