From bb0c6e22441171913cba0b7aed688ece901d0d0f Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Mon, 21 Sep 2015 13:05:15 +0200 Subject: [PATCH 01/11] eintopf-15 BUG: the certs folder is not copied --- README.md | 168 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 163 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e67ca67..73424d6 100644 --- a/README.md +++ b/README.md @@ -43,11 +43,18 @@ Please use the Git clone way to participate. ## Ports and Proxy magic - host port | vm port | docker expose | description | ----|---|---|--- - __4480__ | __4480__ | __80__ | Proxy that provides all started docker container - __4443__ | __4443__ | | Proxy SSL termination point __cumming soon__ - __31313__ | [_31313_] | | Eintopf GUI server currently host only version + host port | vm port | description | +---|---|--- + __4480__ | __4480__ | Proxy that provides all started docker container + __4443__ | __4443__ | Proxy SSL termination point + __31313__ | [_31313_] | Eintopf GUI server currently host only version + + +The containers being proxied must [expose](https://docs.docker.com/reference/run/#expose-incoming-ports) the port to be proxied, either by using the `EXPOSE` directive in their `Dockerfile` or by using the `--expose` flag to `docker run` or `docker create`. + +Provided your DNS is setup to forward foo.bar.com to the a host running nginx-proxy, the request will be routed to a container with the VIRTUAL_HOST env var set. + +For more information see [Proxy compatibility](#proxy-compatibility) or see the proxy [documentation](https://github.com/jwilder/nginx-proxy) # Configuration @@ -146,6 +153,157 @@ npm run app-install -- name_of_npm_module ``` Of course this method works also for pure-js modules, so you can use it all the time if you're able to remember such an ugly command. +# Pattern Development + +A pattern is a project configuration which can be used by Eintopf. + +Minimal file system: + + example-pattern/ + package.json + +The file package.json defines this package as a Eintopf pattern. Minimal package.json: + + { + "name": "example-pattern", # pattern id + "eintopf": { + "name": "Example-pattern", # pattern name + "description": "This is my example-pattern. It can be used as ..." # pattern description + } + } + +## Set your start and stop action + +To make Eintopf actually do things you have to set a start and stop action of the pattern. In this case we want to execute simple sh scripts. + +File system: + + example-pattern/ + package.json + start.sh + stop.sh + +Example package.json: + + { + ... + "scripts": { + "start": "sh ./start.sh", + "stop": "sh ./stop.sh" + }, + ... + } + +Example start.sh: + + #/bin/sh + + docker run -d --name examplepatterndev -e VIRTUAL_HOST=example-pattern.dev nginx + +Example stop.sh + + #/bin/sh + + docker stop examplepatterndev + + +## Custom actions + +You can set custom actions which can be used in the Eintopf gui. + +File system: + + example-pattern/ + package.json + start.sh + stop.sh + customaction1.sh + customaction2.sh + +Example package.json: + + { + ... + "scripts": { + "start": "sh ./start.sh", + "stop": "sh ./stop.sh", + "action1": "sh ./customaction1.sh", + "action2": "sh ./customaction2.sh" + }, + "eintopf": { + "name": "Example-pattern", + "description": "This is my example-pattern. It can be used as ...", + "actions": [ + { + "name": "customaction1", + "script": "action1" # maps to scripts.action1 + }, + { + "name": "customaction2", + "warning": "my custom action 2. This should execute script customaction2.sh", + "script": "action2" # maps to scripts.action2 + } + ] + ... + } + +## Proxy compatibility + +The full proxy documentation can be found [here](https://github.com/jwilder/nginx-proxy). + +The containers being proxied must [expose](https://docs.docker.com/reference/run/#expose-incoming-ports) the port to be proxied, either by using the `EXPOSE` directive in their `Dockerfile` or by using the `--expose` flag to `docker run` or `docker create`. + +Provided your DNS is setup to forward foo.bar.com to the a host running nginx-proxy, the request will be routed to a container with the VIRTUAL_HOST env var set. + +### Multiple Ports + +If your container exposes multiple ports, the proxy will default to the service running on port 80. If you need to specify a different port, you can set a VIRTUAL_PORT env var to select a different one. If your container only exposes one port and it has a VIRTUAL_HOST env var set, that port will be selected. + +### Multiple Hosts + +If you need to support multiple virtual hosts for a container, you can separate each entry with commas. For example, `foo.bar.com,baz.bar.com,bar.com` and each host will be setup the same. + +### Wildcard Hosts + +You can also use wildcards at the beginning and the end of host name, like `*.bar.com` or `foo.bar.*`. Or even a regular expression, which can be very useful in conjunction with a wildcard DNS service like [xip.io](http://xip.io), using `~^foo\.bar\..*\.xip\.io` will match `foo.bar.127.0.0.1.xip.io`, `foo.bar.10.0.2.2.xip.io` and all other given IPs. More information about this topic can be found in the nginx documentation about [`server_names`](http://nginx.org/en/docs/http/server_names.html). + + +Examples: + + docker run -d --name examplepatterndev -e VIRTUAL_HOST=example-pattern.dev nginx + docker run -d --name examplepatterndev2 -e VIRTUAL_HOST=*.example-pattern.dev --expose 3000 nodejs # supports wildcard certificates + docker run -d --name examplepatterndev3 -e VIRTUAL_HOST=example-pattern3.dev --expose 3000 nodejs + +Example docker-compose.yml: + + examplepatterndev: + image: nginx + environment: + - VIRTUAL_HOST=example-pattern.dev + ... + +## SSL certificates + +You can add your own ssl certificates which will be used by the proxy. The certificate files have to match the VIRTUAL_HOST name and have to end with .key and .crt. + +The files will be updated on pattern installation and on pattern update. They will be removed on pattern deletion. If the container was already running while installing the certs, you have to restart the container. + +All certificates are collected in eintopfHome/eintopfNamespace/proxy/certs/ (default: ~/.eintopf/default/proxy/certs/) + +File system: + + configs/ + example-pattern/ + package.json + start.sh + stop.sh + certs/ + example-pattern.dev.key + example-pattern.dev.crt + proxy/ + certs/ # certificates are collected here + example-pattern.dev.key + example-pattern.dev.crt # Making a release From c414c3430e76764f2c1bc65cf4939fea96431814 Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Mon, 21 Sep 2015 13:16:35 +0200 Subject: [PATCH 02/11] removed mazehall dependency in eintopf pattern definitions --- app/models/projects/list.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/projects/list.coffee b/app/models/projects/list.coffee index b0cfd81..bb658ba 100644 --- a/app/models/projects/list.coffee +++ b/app/models/projects/list.coffee @@ -141,7 +141,7 @@ model.loadProjects = () -> projects = foundProjects .flatMap mazehall.readPackageJson .filter (x) -> - x.pkg.mazehall && x.pkg.eintopf && typeof x.pkg.eintopf is "object" + x.pkg.eintopf && typeof x.pkg.eintopf is "object" .onValue (val) -> jetpack.cwd(val.path).findAsync val.path, {matching: ["README*.{md,markdown,mdown}"], absolutePath: true}, "inspect" .then (markdowns) -> From c887da93b975c45fee194cce45ebe63f4898e158 Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Mon, 21 Sep 2015 13:24:35 +0200 Subject: [PATCH 03/11] fixed not working custom actions --- .../gui/public/src/partials/cooking.projects.recipe.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/app_modules/gui/public/src/partials/cooking.projects.recipe.html b/app/app_modules/gui/public/src/partials/cooking.projects.recipe.html index da94d8b..b248f64 100644 --- a/app/app_modules/gui/public/src/partials/cooking.projects.recipe.html +++ b/app/app_modules/gui/public/src/partials/cooking.projects.recipe.html @@ -74,7 +74,7 @@
{{action.warning}} From c34b0ac6cb51c522de8b037c0c4b8c2a9c3bbdb8 Mon Sep 17 00:00:00 2001 From: developer Date: Wed, 23 Sep 2015 10:49:46 +0200 Subject: [PATCH 04/11] eintopf-13 BUG: OSX - copy/paste don't work --- app/main.js | 58 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) diff --git a/app/main.js b/app/main.js index 28ecbe4..e87c47a 100644 --- a/app/main.js +++ b/app/main.js @@ -3,6 +3,7 @@ var shell = require('shell'); var BrowserWindow = require('browser-window'); var menuEntries = require('./app_modules/gui/public/src/js/services/app-menu'); var windowStateKeeper = require('./vendor/electron_boilerplate/window_state'); +var Menu = require('menu'); process.cwd = app.getAppPath; @@ -16,7 +17,51 @@ var mainWindowState = windowStateKeeper('main', { height: 600 }); +initMenu = function () { + //if (Menu.getApplicationMenu()) return; // ignore if menu is present + + var template = [ + { + label: "Eintopf", + submenu: [ + { + label: "About", click: function () { + shell.openExternal('https://github.com/mazehall/eintopf') + } + }, + {type: "separator"}, + { + label: "Reload", accelerator: "CmdOrCtrl+R", click: function (item, focusedWindow) { + if (focusedWindow) focusedWindow.reload(); + } + }, + {type: "separator"}, + { + label: "Quit", accelerator: "CmdOrCtrl+Q", click: function () { + app.quit(); + } + } + ] + }, + { + label: "Edit", + submenu: [ + {label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:"}, + {label: "Redo", accelerator: "Shift+CmdOrCtrl+Z", selector: "redo:"}, + {type: "separator"}, + {label: "Cut", accelerator: "CmdOrCtrl+X", selector: "cut:"}, + {label: "Copy", accelerator: "CmdOrCtrl+C", selector: "copy:"}, + {label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:"}, + {label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:"} + ] + } + ]; + + Menu.setApplicationMenu(Menu.buildFromTemplate(template)); +}; + app.on('ready', function () { + initMenu(); mainWindow = new BrowserWindow({ x: mainWindowState.x, @@ -30,14 +75,14 @@ app.on('ready', function () { mainWindow.maximize(); } - process.on('app:serverstarted', function() { + process.on('app:serverstarted', function () { var appUrl = "http://localhost:" + port; mainWindow.loadUrl(appUrl, {userAgent: "electron"}); - webContents.on("will-navigate", function(event, targetUrl){ - if (targetUrl.indexOf(appUrl) === -1){ - shell.openExternal(targetUrl); - event.preventDefault(); - } + webContents.on("will-navigate", function (event, targetUrl) { + if (targetUrl.indexOf(appUrl) === -1) { + shell.openExternal(targetUrl); + event.preventDefault(); + } }); }); process.emit('app:startserver', port); @@ -48,7 +93,6 @@ app.on('ready', function () { mainWindowState.saveState(mainWindow); }); - }); app.on('window-all-closed', function () { From 014677f2bd722b42471d268aa1b8f62d9dcbfde8 Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Wed, 23 Sep 2015 11:30:16 +0200 Subject: [PATCH 05/11] eintopf-13 BUG: OSX - copy/paste don't work - added linux support --- app/main.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/main.js b/app/main.js index e87c47a..ba8df5e 100644 --- a/app/main.js +++ b/app/main.js @@ -26,7 +26,7 @@ initMenu = function () { submenu: [ { label: "About", click: function () { - shell.openExternal('https://github.com/mazehall/eintopf') + shell.openExternal('https://github.com/mazehall/eintopf'); } }, {type: "separator"}, @@ -42,8 +42,11 @@ initMenu = function () { } } ] - }, - { + } + ]; + + if (process.platform == 'darwin') { // set edit actions for OS X + template.push({ label: "Edit", submenu: [ {label: "Undo", accelerator: "CmdOrCtrl+Z", selector: "undo:"}, @@ -54,8 +57,8 @@ initMenu = function () { {label: "Paste", accelerator: "CmdOrCtrl+V", selector: "paste:"}, {label: "Select All", accelerator: "CmdOrCtrl+A", selector: "selectAll:"} ] - } - ]; + }); + } Menu.setApplicationMenu(Menu.buildFromTemplate(template)); }; From 8b045206d708720beebc626ea1592d269a382036 Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Wed, 23 Sep 2015 13:49:53 +0200 Subject: [PATCH 06/11] eintopf-17 BUG: occasional 'Cannot get /' Error on app start --- app/server.js | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/app/server.js b/app/server.js index a6011a1..1489885 100644 --- a/app/server.js +++ b/app/server.js @@ -1,8 +1,21 @@ +var mazehall = require('mazehall'); var server = require('./app.js'); +var guiLoaded = false; +var serverStarted = false; + +mazehall.moduleStream.onValue(function(val) { + if(val.module != 'gui') return false; + + guiLoaded = true; + if(serverStarted) process.emit('app:serverstarted'); //emit server start when server already listens +}); + process.on('app:startserver', function(port) { server.listen(port, function() { - process.emit('app:serverstarted'); console.log('server listen on port: ' + port); + + serverStarted = true; + if(guiLoaded) process.emit('app:serverstarted'); //emit server start when gui module was already loaded }); }); \ No newline at end of file From cc771b1b4d5a4955ff06894625d52d54353205f0 Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Fri, 25 Sep 2015 11:48:58 +0200 Subject: [PATCH 07/11] eintopf-19 BUG: creating a project which already exists deletes the project - refactoring server.js --- app/server.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/app/server.js b/app/server.js index 1489885..f2f13bc 100644 --- a/app/server.js +++ b/app/server.js @@ -1,21 +1,15 @@ +var _r = require('kefir'); var mazehall = require('mazehall'); var server = require('./app.js'); -var guiLoaded = false; -var serverStarted = false; +serverStream = _r.fromEvents(process, 'app:startserver').filter(); +guiStream = mazehall.moduleStream.filter(function(val) { if(val.module == 'gui') return val; }); -mazehall.moduleStream.onValue(function(val) { - if(val.module != 'gui') return false; - - guiLoaded = true; - if(serverStarted) process.emit('app:serverstarted'); //emit server start when server already listens -}); - -process.on('app:startserver', function(port) { +_r.zip([guiStream, serverStream]) +.onValue(function(val) { + var port = val[1]; server.listen(port, function() { console.log('server listen on port: ' + port); - - serverStarted = true; - if(guiLoaded) process.emit('app:serverstarted'); //emit server start when gui module was already loaded + process.emit('app:serverstarted'); }); }); \ No newline at end of file From b3deac7595db094ae2df6b32bf5b895ad155f89c Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Fri, 25 Sep 2015 12:56:27 +0200 Subject: [PATCH 08/11] eintopf-20 BUG: nodejs should not be a requirement to do project actions - replaced direct npm calls with the script entry from the package json -> must be tested in all OS --- app/models/projects/list.coffee | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/models/projects/list.coffee b/app/models/projects/list.coffee index bb658ba..6e914aa 100644 --- a/app/models/projects/list.coffee +++ b/app/models/projects/list.coffee @@ -156,8 +156,9 @@ model.loadProjects = () -> model.startProject = (project, callback) -> return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? + return watcherModel.log "res:project:start:#{project.id}", "script start does not exist\n" unless project.scripts["start"] - process = child.exec 'npm start', {cwd: project.path} + process = child.exec project.scripts["start"], {cwd: project.path} process.stdout.on 'data',(chunk) -> watcherModel.log 'res:project:start:' + project.id, chunk process.stderr.on 'data',(chunk) -> @@ -166,8 +167,9 @@ model.startProject = (project, callback) -> model.stopProject = (project, callback) -> return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? + return watcherModel.log "res:project:stop:#{project.id}", "script stop does not exist\n" unless project.scripts["stop"] - process = child.exec 'npm stop', {cwd: project.path} + process = child.exec project.scripts["stop"], {cwd: project.path} process.stdout.on 'data',(chunk) -> watcherModel.log 'res:project:stop:' + project.id, chunk process.stderr.on 'data',(chunk) -> @@ -205,7 +207,7 @@ model.callAction = (project, action, callback) -> return watcherModel.log "res:project:action:script:#{project.id}", "script '#{action.script}' does not exists\n" unless project.scripts[action.script] - process = child.exec "npm run #{action.script}", {cwd: project.path} + process = child.exec project.scripts[action.script], {cwd: project.path} process.stdout.on "data",(chunk) -> watcherModel.log "res:project:action:script:#{project.id}", chunk if chunk process.stderr.on "data",(chunk) -> From 977e4908edf82deaaabf8edb277c413b24281f9d Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Mon, 28 Sep 2015 12:13:40 +0200 Subject: [PATCH 09/11] eintopf-20 BUG: nodejs should not be a requirement to do project actions - refactoring eintopf project script calls --- app/models/projects/list.coffee | 80 ++++++++++++++++++--------------- 1 file changed, 45 insertions(+), 35 deletions(-) diff --git a/app/models/projects/list.coffee b/app/models/projects/list.coffee index 6e914aa..a072054 100644 --- a/app/models/projects/list.coffee +++ b/app/models/projects/list.coffee @@ -10,6 +10,30 @@ watcherModel = require '../stores/watcher.coffee' projects = [] +runCmd = (cmd, config, logName, callback) -> + config = {} if ! config + output = '' + + sh = 'sh' + shFlag = '-c' + + if process.platform == 'win32' + sh = process.env.comspec || 'cmd' + shFlag = '/d /s /c' + config.windowsVerbatimArguments = true + + proc = child.spawn sh, [shFlag, cmd], config + proc.on 'error', (err) -> + return callback err if callback + proc.on 'close', (code, signal) -> + return callback null, output if callback + proc.stdout.on 'data', (chunk) -> + watcherModel.log logName, chunk.toString() if logName + output += chunk.toString() + proc.stderr.on 'data', (chunk) -> + watcherModel.log logName, chunk.toString() if logName + output += chunk.toString() + getRunningProjectContainers = (project, callback) -> return callback [] unless project.path? dataset = "" @@ -154,27 +178,6 @@ model.loadProjects = () -> projects = foundProjects watcherModel.set 'projects:list', projects -model.startProject = (project, callback) -> - return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? - return watcherModel.log "res:project:start:#{project.id}", "script start does not exist\n" unless project.scripts["start"] - - process = child.exec project.scripts["start"], {cwd: project.path} - process.stdout.on 'data',(chunk) -> - watcherModel.log 'res:project:start:' + project.id, chunk - process.stderr.on 'data',(chunk) -> - watcherModel.log 'res:project:start:' + project.id, chunk - - -model.stopProject = (project, callback) -> - return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? - return watcherModel.log "res:project:stop:#{project.id}", "script stop does not exist\n" unless project.scripts["stop"] - - process = child.exec project.scripts["stop"], {cwd: project.path} - process.stdout.on 'data',(chunk) -> - watcherModel.log 'res:project:stop:' + project.id, chunk - process.stderr.on 'data',(chunk) -> - watcherModel.log 'res:project:stop:' + project.id, chunk - model.deleteProject = (project, callback) -> return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? @@ -188,30 +191,37 @@ model.deleteProject = (project, callback) -> model.loadProjects() callback null, true +model.startProject = (project, callback) -> + return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? + logName = "res:project:start:#{project.id}" + + return watcherModel.log logName, "script start does not exist\n" unless project.scripts["start"] + runCmd project.scripts["start"], {cwd: project.path}, logName + +model.stopProject = (project, callback) -> + return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? + logName = "res:project:stop:#{project.id}" + + return watcherModel.log logName, "script stop does not exist\n" unless project.scripts["stop"] + runCmd project.scripts["stop"], {cwd: project.path}, logName + model.updateProject = (project, callback) -> return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? + logName = "res:project:update:#{project.id}" - watcherModel.log "res:project:update:#{project.id}", ["Start pulling...\n"] - process = child.exec "git pull", {cwd: project.path} - process.stdout.on 'data',(chunk) -> - watcherModel.log "res:project:update:#{project.id}", chunk - process.stderr.on 'data',(chunk) -> - watcherModel.log "res:project:update:#{project.id}", chunk - process.on 'close', () -> + watcherModel.log logName, ["Start pulling...\n"] + runCmd "git pull", {cwd: project.path}, logName, (err, result) -> + return callback err if err model.initProject project.path, callback model.callAction = (project, action, callback) -> if callback? return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? || ! action? return callback new Error 'invalid script name' if project.scripts? or action.script? or project.scripts[action.script]? + logName = "res:project:action:script:#{project.id}" - return watcherModel.log "res:project:action:script:#{project.id}", "script '#{action.script}' does not exists\n" unless project.scripts[action.script] - - process = child.exec project.scripts[action.script], {cwd: project.path} - process.stdout.on "data",(chunk) -> - watcherModel.log "res:project:action:script:#{project.id}", chunk if chunk - process.stderr.on "data",(chunk) -> - watcherModel.log "res:project:action:script:#{project.id}", chunk + return watcherModel.log logName, "script '#{action.script}' does not exists\n" unless project.scripts[action.script] + runCmd project.scripts[action.script], {cwd: project.path}, logName watcherModel.propertyToKefir 'containers:list' .onValue -> From 15861c3689c7c1cb6edd7a9e046b4cac32c59eb4 Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Mon, 28 Sep 2015 15:47:12 +0200 Subject: [PATCH 10/11] eintopf-20 BUG: nodejs should not be a requirement to do project actions - moved runCmd function to util model --- app/models/projects/list.coffee | 32 ++++---------------------------- app/models/util/index.coffee | 27 +++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/app/models/projects/list.coffee b/app/models/projects/list.coffee index a072054..e161e5f 100644 --- a/app/models/projects/list.coffee +++ b/app/models/projects/list.coffee @@ -10,30 +10,6 @@ watcherModel = require '../stores/watcher.coffee' projects = [] -runCmd = (cmd, config, logName, callback) -> - config = {} if ! config - output = '' - - sh = 'sh' - shFlag = '-c' - - if process.platform == 'win32' - sh = process.env.comspec || 'cmd' - shFlag = '/d /s /c' - config.windowsVerbatimArguments = true - - proc = child.spawn sh, [shFlag, cmd], config - proc.on 'error', (err) -> - return callback err if callback - proc.on 'close', (code, signal) -> - return callback null, output if callback - proc.stdout.on 'data', (chunk) -> - watcherModel.log logName, chunk.toString() if logName - output += chunk.toString() - proc.stderr.on 'data', (chunk) -> - watcherModel.log logName, chunk.toString() if logName - output += chunk.toString() - getRunningProjectContainers = (project, callback) -> return callback [] unless project.path? dataset = "" @@ -196,21 +172,21 @@ model.startProject = (project, callback) -> logName = "res:project:start:#{project.id}" return watcherModel.log logName, "script start does not exist\n" unless project.scripts["start"] - runCmd project.scripts["start"], {cwd: project.path}, logName + utilModel.runCmd project.scripts["start"], {cwd: project.path}, logName model.stopProject = (project, callback) -> return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? logName = "res:project:stop:#{project.id}" return watcherModel.log logName, "script stop does not exist\n" unless project.scripts["stop"] - runCmd project.scripts["stop"], {cwd: project.path}, logName + utilModel.runCmd project.scripts["stop"], {cwd: project.path}, logName model.updateProject = (project, callback) -> return callback new Error 'invalid project given' if typeof project != "object" || ! project.path? logName = "res:project:update:#{project.id}" watcherModel.log logName, ["Start pulling...\n"] - runCmd "git pull", {cwd: project.path}, logName, (err, result) -> + utilModel.runCmd "git pull", {cwd: project.path}, logName, (err, result) -> return callback err if err model.initProject project.path, callback @@ -221,7 +197,7 @@ model.callAction = (project, action, callback) -> logName = "res:project:action:script:#{project.id}" return watcherModel.log logName, "script '#{action.script}' does not exists\n" unless project.scripts[action.script] - runCmd project.scripts[action.script], {cwd: project.path}, logName + utilModel.runCmd project.scripts[action.script], {cwd: project.path}, logName watcherModel.propertyToKefir 'containers:list' .onValue -> diff --git a/app/models/util/index.coffee b/app/models/util/index.coffee index 1f64236..f6c602d 100644 --- a/app/models/util/index.coffee +++ b/app/models/util/index.coffee @@ -1,5 +1,8 @@ config = require '../stores/config' jetpack = require 'fs-jetpack' +spawn = require('child_process').spawn + +watcherModel = require '../stores/watcher.coffee' appConfig = config.get 'app' @@ -20,3 +23,27 @@ module.exports.getConfigPath = () -> module.exports.getConfigModulePath = () -> return null if ! (configPath = @getConfigPath())? || ! appConfig.defaultNamespace return jetpack.cwd(configPath).path appConfig.defaultNamespace + +module.exports.runCmd = (cmd, config, logName, callback) -> + config = {} if ! config + output = '' + + sh = 'sh' + shFlag = '-c' + + if process.platform == 'win32' + sh = process.env.comspec || 'cmd' + shFlag = '/d /s /c' + config.windowsVerbatimArguments = true + + proc = spawn sh, [shFlag, cmd], config + proc.on 'error', (err) -> + return callback err if callback + proc.on 'close', (code, signal) -> + return callback null, output if callback + proc.stdout.on 'data', (chunk) -> + watcherModel.log logName, chunk.toString() if logName + output += chunk.toString() + proc.stderr.on 'data', (chunk) -> + watcherModel.log logName, chunk.toString() if logName + output += chunk.toString() \ No newline at end of file From 110d6cfcc1a59733fb49299460753849f0075b68 Mon Sep 17 00:00:00 2001 From: Marcel Kilian Date: Mon, 28 Sep 2015 16:25:23 +0200 Subject: [PATCH 11/11] updated prerequisites in readme --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 73424d6..73a871b 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,7 @@ Please use the Git clone way to participate. * VirtualBox * Vagrant >= 1.7 -* Git -* (currently) NodeJS +* Git + Gitbash (must be installed with the environment variables option) ```