ehmicky / cross-platform-node-guide

📗 How to write cross-platform Node.js code

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

reference shelljs module for Shell scripting

tracker1 opened this issue · comments

In general, I just use node/npm scripts with shelljs for my scripting needs which tends to go better cross platform. :-)

Thanks for your feedback.

I mentioned shelljs but in the Core utilities section not the Shell section. The reason is because it seems to me the main goal of shelljs to reimplement Unix core utilities (mostly GNU coreutils) but cross-platform. It can actually be used directly in JavaScript without using the command line.

Please let me know if this makes sense.

Understood, I missed the reference... as I said, I pretty much just use JS for all my cross platform shell scripting... that is I don't use shell scripts, just node/npm scripts. Just think it's worth mentioning you can pretty much do anything you'd do in a shell script directly with node and js scripts.

As an example, here's one of the more complex ones.

import shell from "shelljs";

const delay = ms => new Promise(resolve => setTimeout(resolve, ms));

const dsql = sql =>
  shell.exec(
    `docker exec -i vocemsql "/opt/mssql-tools/bin/sqlcmd" -S localhost -U sa -P "Let-Me-In" -Q "${sql}"`
  );

const execTry = (...args) => {
  try {
    shell.exec(...args);
  } catch (error) {}
};

async function main(skip) {
  if (skip) return;

  const isWin = process.platform === "win32";

  console.log("stop vocemsql");
  shell.exec("docker kill vocemsql");
  await delay(1000);

  console.log("remove vocemsql");
  shell.exec("docker rm vocemsql");
  await delay(1000);

  console.log("creating new vocemsql");
  shell.exec(
    `docker run -m 2GB --restart unless-stopped --name vocemsql -h vocemsql -e "ACCEPT_EULA=Y" -e "MSSQL_SA_PASSWORD=Let_Me_In" -p 1401:1433 -d microsoft/mssql-server-linux:2017-latest`
  );
  await delay(1000);

  // wait for db to startup
  process.stdout.write("\nWaiting for vocemsql to start.");
  let tries = 0;
  let done = false;
  while (!done && ++tries <= 30) {
    await delay(1500);
    process.stdout.write(".");
    const result = shell.exec(
      `docker exec -i vocemsql /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "Let_Me_In" -Q "SELECT Name FROM sys.Databases" > ${
        isWin ? "nul" : "/dev/null"
      } 2>&1`
    );
    done = result.code === 0;
  }
  console.log("\nvocemsql available\n");
  await execTry("docker network create vocemnet");
  await execTry("docker network connect vocemnet vocemsql");
}

main(!!module.parent)
  .catch(console.error)
  .then(_ => delay(0))
  .then(_ => process.exit());

Oh I see what you mean now.

Correct me if I'm wrong but from the source code it seems to me that shelljs.exec() does not do much on top on child_process.exec() (which itself is built on top of child_process.spawn()).

On the other hand execa does more work to support Windows. For example, I don't think shelljs.exec() supports shebangs, PATHEXT, cmd.exe escaping or cross-browser child/parent cleanup. In that sense, it seems to me execa might be better for shell command spawning, and shelljs better as a core utilities abstraction layer, i.e. should be recommended likewise.

What do you think?

Yeah, execa is probably a better option I was not familiar with. shell.exec is akin to spawnSync and does do the shell thing and iirc will cleanup itself. shell.exec does a bit better imho by being able to define the entire command line, instead of breaking into an array of strings.

For the last point I think this can be provided by the shell: true option of child_process.spawn(), which is used itself by execa.shell() method.

I myself always use execa.shell() to write the command in one string, like if I were in a terminal, it is very convenient.

@allcontributors[bot] please add @tracker1 for ideas that he helped raised with this issue.

@ehmicky

I've put up a pull request to add @tracker1! 🎉