├── .gitignore ├── README.md ├── images └── fmg.png ├── package.json └── src ├── foreman_runner.js ├── index.js └── procfile_reader.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io 2 | 3 | ### Node ### 4 | # Logs 5 | logs 6 | *.log 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 30 | node_modules 31 | 32 | 33 | ### OSX ### 34 | .DS_Store 35 | .AppleDouble 36 | .LSOverride 37 | 38 | # Icon must end with two \r 39 | Icon 40 | 41 | 42 | # Thumbnails 43 | ._* 44 | 45 | # Files that might appear on external disk 46 | .Spotlight-V100 47 | .Trashes 48 | 49 | # Directories potentially created on remote AFP share 50 | .AppleDB 51 | .AppleDesktop 52 | Network Trash Folder 53 | Temporary Items 54 | .apdisk 55 | 56 | FullProcfile 57 | Procfile 58 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Foreman-Gui 2 | 3 | Foreman-Gui is a nifty command line utility for choosing which Foreman services to run. Foreman-Gui works by generating the Procfile based on a template Procfile (usually called FullProcfile). Foreman-Gui works with all Foreman implementations. 4 | 5 | ![Foreman-Gui](https://raw.github.com/herkyl/foreman-gui/master/images/fmg.png) 6 | 7 | ## Install 8 | 9 | Install the command line tool 10 | 11 | $ npm install -g foreman-gui 12 | 13 | ## Usage 14 | 15 | Foreman-gui has a very simple API. It only takes one parameter - the `FullProcfile` location. `FullProcfile` is a file where all your servies are defined like in a normal `Procfile`. `Procfile` is generated from your `FullProcfile`. 16 | 17 | Runs Foreman-gui with the target file `FullProcfile` 18 | 19 | $ fmg 20 | 21 | Runs Foreman-gui with a custom target file. 22 | 23 | $ fmg custom_procfile_location 24 | 25 | After you have generated the Procfile, start foreman normally. 26 | 27 | $ foreman 28 | 29 | Or using node-foreman 30 | 31 | $ nf 32 | 33 | ### FullProcfile 34 | 35 | The `FullProcfile` format is a simple `key : command` format: 36 | 37 | web: node web_server.js 38 | api: node api_server.js 39 | log: node log_server.js 40 | 41 | Each line should contain a separate process. 42 | -------------------------------------------------------------------------------- /images/fmg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/herkyl/foreman-gui/fe9c9bf63bd017e4fa4616a818fd30f2a3905d65/images/fmg.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "foreman-gui", 3 | "version": "1.0.3", 4 | "description": "Console based GUI that builds you a Procfile usable with any foreman implementation", 5 | "main": "src/index.js", 6 | "homepage": "https://github.com/herkyl/foreman-gui", 7 | "keywords": [ 8 | "foreman", 9 | "Procfile" 10 | ], 11 | "scripts": { 12 | "start": "node src/index.js" 13 | }, 14 | "bin": { 15 | "fmg": "src/index.js" 16 | }, 17 | "engines": { 18 | "node": ">=0.8" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "git@github.com:herkyl/foreman-gui.git" 23 | }, 24 | "author": "Serge Herkül (https://twitter.com/_sergeh)", 25 | "license": "ISC", 26 | "preferGlobal": true, 27 | "dependencies": { 28 | "colors": "^1.0.3", 29 | "inquirer": "^0.8.0" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/foreman_runner.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var exec = require('child_process').exec; 3 | var sys = require('sys'); 4 | 5 | exports.run = function (procfileLines, callback) { 6 | try { 7 | var procfileLocation = process.cwd() + '/Procfile'; 8 | var file = fs.createWriteStream(procfileLocation); 9 | file.on('error', callback); 10 | file.on('close', callback); 11 | procfileLines.forEach(function(line) { 12 | file.write(line.name + ':' + line.command + '\n'); 13 | }); 14 | file.end(); 15 | } catch (error) { 16 | callback(error); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var inquirer = require("inquirer"); 4 | var colors = require('colors/safe'); 5 | var procfileReader = require('./procfile_reader.js'); 6 | var foremanRunner = require('./foreman_runner.js'); 7 | 8 | function getFullProcfileName() { 9 | var arguments = process.argv.slice(2); 10 | if (arguments.length > 1) { 11 | console.log(colors.red('Too many arguments:', arguments.length)); 12 | process.exit(1); 13 | } else if (arguments.length === 0) { 14 | return 'FullProcfile'; 15 | } else if (arguments.length === 1 && arguments[0] === 'Procfile') { 16 | console.log(colors.red('Input Procfile must have a different name')); 17 | process.exit(1); 18 | } else { 19 | return arguments[0]; 20 | } 21 | } 22 | 23 | procfileReader.read(getFullProcfileName(), function (error, procfile) { 24 | var choices = []; 25 | 26 | for (var i in procfile) { 27 | var line = procfile[i]; 28 | choices.push({ 29 | name: line.name, 30 | checked: true, 31 | value: i 32 | }); 33 | choices.push(new inquirer.Separator(line.command)); 34 | } 35 | 36 | inquirer.prompt([{ 37 | type: "checkbox", 38 | message: "Select services", 39 | name: "services", 40 | choices: choices, 41 | validate: function(answer) { 42 | if (answer.length < 1) { 43 | return "You must choose at least one service."; 44 | } 45 | return true; 46 | } 47 | }], function (answers, next) { 48 | var filteredProcfile = []; 49 | for (var i in answers.services) { 50 | var lineIndex = answers.services[i]; 51 | filteredProcfile.push(procfile[lineIndex]); 52 | } 53 | foremanRunner.run(filteredProcfile, function (error) { 54 | if (error) { 55 | console.log(colors.red(error)); 56 | } else { 57 | console.log(colors.green('Procfile created')); 58 | console.log(colors.green('Run foreman normally')); 59 | } 60 | }); 61 | }); 62 | }); 63 | -------------------------------------------------------------------------------- /src/procfile_reader.js: -------------------------------------------------------------------------------- 1 | var fs = require('fs'); 2 | var readline = require('readline'); 3 | var colors = require('colors/safe'); 4 | 5 | exports.read = function (fileName, callback) { 6 | var location = process.cwd() + '/' + fileName; 7 | console.log(colors.green('Reading from file ' + location)); 8 | var fs = require('fs') 9 | , readline = require('readline') 10 | , array = []; 11 | 12 | var rd = readline.createInterface({ 13 | input: fs.createReadStream(location), 14 | output: process.stdout, 15 | terminal: false 16 | }); 17 | 18 | rd.on('line', function(line) { 19 | var pair = line.split(':'); 20 | array.push({ 21 | name: pair[0].trim(), 22 | command: pair[1].trim() 23 | }); 24 | }); 25 | 26 | rd.on('close', function () { 27 | callback(null, array); 28 | }); 29 | } 30 | --------------------------------------------------------------------------------