Repository: ember-cli/ember-cli
Pull request #5800 (2016-04-14 19:55:52)

Rebased "Prevent Termination Confirmation on Windows"
This is essentially https://github.com/ember-cli/ember-cli/pull/5238 rebased and with a few small test improvements. I've tested this with inquirer and didn't notice any problems.

/cc @felixrieseberg @stefanpenner @kellyselden 

felixrieseberg: Thanks for staying on top of this 👍 
Turbo87: AppVeyor tests seem mostly green except for the usual suspects :shipit:
stefanpenner: So this seems to trap for `builder` related stuff, but should this actually be more general? Allowing for this behavior in all scenarios instead of just during builds?
Turbo87: @stefanpenner I tend to agree, having this everywhere would probably make sense.

Patch:
diff --git a/lib/models/builder.js b/lib/models/builder.js
index 86384910b..667d561a1 100644
--- a/lib/models/builder.js
+++ b/lib/models/builder.js
@@ -80,10 +80,27 @@ module.exports = Task.extend({
       process.on('SIGINT',  this.onSIGINT.bind(this));
       process.on('SIGTERM', this.onSIGTERM.bind(this));
       process.on('message', this.onMessage.bind(this));
+
+      if (/^win/.test(process.platform)) {
+        this.trapWindowsSignals();
+      }
+
       signalsTrapped = true;
     }
   },
 
+  trapWindowsSignals: function () {
+    // This is required to capture Ctrl + C on Windows
+    if (process.stdin && process.stdin.isTTY) {
+      process.stdin.setRawMode(true);
+      process.stdin.on('data', function (data) {
+        if (data.length === 1 && data[0] === 0x03) {
+          process.emit('SIGINT');
+        }
+      });
+    }
+  },
+
   init: function() {
     this._super.apply(this, arguments);
     this.setupBroccoliBuilder();


Test patch:
diff --git a/tests/unit/models/builder-test.js b/tests/unit/models/builder-test.js
index e19413e38..904cef916 100644
--- a/tests/unit/models/builder-test.js
+++ b/tests/unit/models/builder-test.js
@@ -10,6 +10,7 @@ var stub            = require('../../helpers/stub').stub;
 var MockProject     = require('../../helpers/mock-project');
 var remove          = Promise.denodeify(fs.remove);
 var mkTmpDirIn      = require('../../../lib/utilities/mk-tmp-dir-in');
+var td              = require('testdouble');
 
 var chai = require('../../chai');
 var expect = chai.expect;
@@ -21,6 +22,73 @@ var tmproot         = path.join(root, 'tmp');
 describe('models/builder.js', function() {
   var addon, builder, buildResults, tmpdir;
 
+  describe('Windows CTRL + C Capture', function() {
+    var originalPlatform, originalStdin;
+
+    before(function() {
+      originalPlatform = process.platform;
+      originalStdin = process.platform;
+    });
+
+    after(function () {
+      Object.defineProperty(process, 'platform', {
+        value: originalPlatform
+      });
+
+      Object.defineProperty(process, 'stdin', {
+        value: originalStdin
+      });
+    });
+
+    it('enables raw capture on Windows', function() {
+      Object.defineProperty(process, 'platform', {
+        value: 'win'
+      });
+
+      Object.defineProperty(process, 'stdin', {
+        value: {
+          isTTY: true
+        }
+      });
+
+      var trapWindowsSignals = td.function();
+
+      builder = new Builder({
+        setupBroccoliBuilder: function() { },
+        cleanupOnExit: function() { },
+        trapWindowsSignals: trapWindowsSignals,
+        project: new MockProject()
+      });
+
+      builder.trapSignals();
+      td.verify(trapWindowsSignals());
+    });
+
+    it('does not enable raw capture on non-Windows', function() {
+      Object.defineProperty(process, 'platform', {
+        value: 'mockOS'
+      });
+
+      Object.defineProperty(process, 'stdin', {
+        value: {
+          isTTY: true
+        }
+      });
+
+      var trapWindowsSignals = td.function();
+
+      builder = new Builder({
+        setupBroccoliBuilder: function() { },
+        cleanupOnExit: function() { },
+        trapWindowsSignals: trapWindowsSignals,
+        project: new MockProject()
+      });
+
+      builder.trapSignals();
+      td.verify(trapWindowsSignals(), {times: 0, ignoreExtraArgs: true});
+    });
+  });
+
   describe('copyToOutputPath', function() {
     beforeEach(function() {
       return mkTmpDirIn(tmproot).then(function(dir) {