0

first time post here and I'm hoping someone can help it'd be greatly appreciated.

So I'm writing a program in ES6 which I've already written in python, everything works perfectly in python but I want to migrate to ES6 in the hopes of making a desktop app with Electron.

I have a class that creates a Drive object, and to populate the variables in the Drive, I have a function which executes a shell command. I would like to be able to assign a Drive variable e.g 'this.mdts' to the output of the command I'm running but it only returns undefined. I can log the output to console when it's created but it doesn't return that same value to the variable.

Here are some snippets of the code:

This is drive.js

var sys = require('util')
const exec = require('child_process').exec

export default class Drive {
  constructor(node,sn) {
    this.node = node
    this.sn = sn
    this.mdts = this.getIdCtrl("mdts")
  }

  getIdCtrl(specifier) {
    exec('nvme id-ctrl /dev/' + this.node,(e,stdout,stderr) => {
      if (e instanceof Error) {
        console.error(e);
        throw e;
      }
      let line = stdout.split('\n')
      for(let i = 0; i<line.length;i++) {
        if (line[i].includes(specifier)) {
          console.log(line[i]) // prints exactly what I want
          return line[i]
        }
      }
    })
  }
}

Here is test.js where I create the Drive object

import Drive from './drive';

var sys = require('util')
var exec = require('child-process-promise').exec;
var child;

let fs = require('fs')

let listOfDrives = []

function runTest() {
  exec("nvme list").then(function (result) {
    let stdout = result.stdout;
    let stderr = result.stderr;
    let error = result.error;
    var line = stdout.split('\n');
    for(let i = 0; i<line.length;i++) {
      if (line[i].includes("/dev/")) {
        if (listOfDrives.length == 0) {
          let x = new Drive(line[i].slice(5,13).trim(),line[i].slice(17,37).trim())
          listOfDrives.push(x)
        }
        else {
          for (let x in listOfDrives) {
            if (x.sn == line[i].slice(17,37).trim()) {
              break
            }
          }
          let x = new Drive(line[i].slice(5,13).trim(),line[i].slice(17,37).trim())
          listOfDrives.push(x)
        }
      }
    }
    if (error) {
      console.log('exec error: ' + error);
    }
    console.log(listOfDrives[0])
    for(let x of listOfDrives) {
      console.log(x.sn);
    }
  })
}

runTest()

When it's after running I return the Drive object and I get this output:

{node: 'nvme0n1', sn: 'xxxx10', mdts: undefined }

I've tried child-process-promise in Drive.js just like test.js but to no avail.

Thanks very much for taking a look

EDIT:

Here's the updated version of drive.js

var sys = require('util')
const exec = require('child-process-promise').exec

export default class Drive {
  constructor(node,sn) {
    this.node = node
    this.sn = sn
    this.mdts = this.getIdCtrl("mdts")
  }

  getIdCtrl(specifier) {
    return exec('nvme id-ctrl /dev/' + this.node).then(function (result) {
      let stdout = result.stdout;
      let stderr = result.stderr;
      let error = result.error;
      if (error instanceof Error) {
        console.error(e);
        throw e;
      }
      let line = stdout.split('\n')
      for(let i = 0; i<line.length;i++) {
        if (line[i].includes(specifier)) {
          console.log(line[i]) // prints exactly what I want
          return line[i]
        }
      }
    })
  }
}

EDIT:

Here is what the Drive is returning:

Drive {
  node: 'nvme0n1',
  sn: '66GP6035PCTU',
  mdts:
   ChildProcessPromise {
     <pending>,
     _cpResolve: [Function: y],
     _cpReject: [Function: z],
     childProcess:
      ChildProcess {
        domain: null,
        _events: [Object],
        _eventsCount: 2,
        _maxListeners: undefined,
        _closesNeeded: 3,
        _closesGot: 0,
        connected: false,
        signalCode: null,
        exitCode: null,
        killed: false,
        spawnfile: '/bin/sh',
        _handle: [Object],
        spawnargs: [Object],
        pid: 7858,
        stdin: [Object],
        stdout: [Object],
        stderr: [Object],
        stdio: [Object] } } }
Darren
  • 11
  • 3
  • Possible duplicate of [How do I return the response from an asynchronous call?](http://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) –  Apr 27 '17 at 11:13
  • @JaromandaX How is this not async? https://nodejs.org/api/child_process.html#child_process_child_process_exec_command_options_callback –  Apr 27 '17 at 11:16
  • Thanks for the quick response @JaromandaX , I've been fiddling with this for the past 2 days and I came across a couple posts where returning exec was the way to go, when I do that though, I get a 'ChildProcess' object returned and not the string I was looking for – Darren Apr 27 '17 at 11:17
  • @JaromandaX I'm not entirely certain as when I did use `child-process-promise` and returned the exec, I was getting a pending promise returned – Darren Apr 27 '17 at 11:23
  • @JaromandaX exactly. –  Apr 27 '17 at 11:24
  • @JaromandaX so would the `import Drive from './drive;` be throwing off the `var exec = require('child-process-promise').exec;` in test.js because it's defined as `const exec = require('child_process').exec` in drive.js? – Darren Apr 27 '17 at 11:26
  • @Darron it doesn't throw it off, each script uses its own imports. You need to assign the result of the exec callback to the Drive instance instead of returning it, or use the promise way in Drive.js, too. –  Apr 27 '17 at 11:28
  • @JaromandaX , I've edited drive.js and appended it to the end of the post, is that what you mean? I'm still getting the same error unfortunately – Darren Apr 27 '17 at 11:38
  • @ChrisG I tried assigning the result of exec to `this.mdts` inside of `getIdCtrl` just to see but it couldn't set property 'mdts of undefined it said – Darren Apr 27 '17 at 11:40
  • @JaromandaX well since I've used `child-process-promise` it's returning a ChildProcessPromise instance which is `` , could it be that the time it takes to execute the command is taking too long? – Darren Apr 27 '17 at 11:43
  • @JaromandaX I've added in what the drive is returning – Darren Apr 27 '17 at 11:47
  • @Darren Did you check the link from the second comment? It has a perfect analogy featuring landlines and cellphones. –  Apr 27 '17 at 11:49
  • @ChrisG I checked it out, So is it a delay that is required to fulfill the command I want to execute? – Darren Apr 27 '17 at 12:09

1 Answers1

0

I found an answer to my problem after days and days of googling so for anyone who might be in the same predicament as myself, this link provides a brilliant and simple workaround that would seem trivial to anyone with decent knowledge of JS/ES6 but alas I'm not in that category....yet ;)

https://strongloop.com/strongblog/whats-new-in-node-js-v0-12-execsync-a-synchronous-api-for-child-processes/

So a simple while loop checking to see if the process was complete and holding off returning a value until it was complete.

It pretty much made all of my code redundant and eliminates the need for promises, it may not be the most efficient but it works for my purpose.

Darren
  • 11
  • 3