// Copyright (c) 2013 Perforce Software. All rights reserved. var _ = require("underscore"); var async = require("async"); var child_process = require("child_process"); var fs = require("fs"); var os = require("os"); var path = require("path"); var ProcessUtil = require("./process_util"); function ServiceUtil(options) { options = options || {}; this.grunt = options.grunt; this.processUtil = new ProcessUtil(this.grunt); this.workDir = options.workDir; } // Some helper methods for managing our test server processes. _.extend(ServiceUtil.prototype, { // This will start the process in a detached mode, but relative to a particular // working directory. It will also redirect output to "out" and "err" // as appropriate in each of these places // // Params: // - label: the ID we're going to track the child process with // - command: the executable to run // - args: the array of parameters; you can use "{local_work}" in any of // them to replace with the working directory of the folder // - doneCallback: once ready, this will be called spawnInWork: function (label, command, args, doneCallback) { var workFolder = this.initWorkFolder(label); var out = fs.openSync(path.join(workFolder, "out"), "w"); var err = fs.openSync(path.join(workFolder, "err"), "w"); var options = { detached: true, cwd: workFolder, stdio: ["ignore", out, err] }; // Replace the string in any argument to set up the paths var processedArgs = _.map(args, function(x) { return x.replace("{local_work}", workFolder); }); console.log("spawn", command, processedArgs, options); var cp = child_process.spawn(command, processedArgs, options); var pidFile = path.join(workFolder, "pid"); fs.writeFileSync(pidFile, cp.pid.toString()); cp.unref(); doneCallback(null); }, // Make sure the local working folder for the process exists initWorkFolder: function (label) { if (!fs.existsSync(this.workDir)) { fs.mkdirSync(this.workDir); } var lwork = path.resolve(this.workDir, label); if (!fs.existsSync(lwork)) { fs.mkdirSync(lwork); } return lwork; }, // Checks to see if the process indicated by the label's pid file is really // there. // // We use two "yes" or "no" callbacks instead of returning a value here. isRunning: function (label, yepCallback, nopeCallback) { var workFolder = this.initWorkFolder(label); var pidFile = path.join(workFolder, "pid"); if (fs.existsSync(pidFile)) { var pid = parseInt(fs.readFileSync(pidFile), 10); this.processUtil.list(function(error, procs) { if (error) { return nopeCallback(); } if (_.any(procs, function(p) { return p.pid === pid; })) { yepCallback(); } else { nopeCallback(); } }); } else { nopeCallback(); } }, // Use the pid stuffed in our label file to halt the process killProc: function (label, sig) { var workFolder = this.initWorkFolder(label); var pidFile = path.join(workFolder, "pid"); if (fs.existsSync(pidFile)) { var pid = parseInt(fs.readFileSync(pidFile), 10); try { process.kill(pid, sig); } catch (err) { console.log("warning: problem killing " + label + ", continuing", err); } } }, killIfRunning: function(label, sig, callback) { var self = this; function yep() { console.log(label + " is running, killing with signal " + sig); self.killProc(label, sig); _.delay(function() { self.killIfRunning(label, sig, callback); }, 50); } this.isRunning(label, yep, callback); } }); function getUserHome() { return process.env[(process.platform == 'win32') ? 'USERPROFILE' : 'HOME']; } module.exports = ServiceUtil;
# | Change | User | Description | Committed | |
---|---|---|---|---|---|
#1 | 10513 | tjuricek |
A basic experiment with using the C++ API in Go May not work completely. I haven't messed with this in over a year. The Go tools may have come a long ways as well, and we may be able to automate things more directly in the typical toolkit then having to use node. |