├── .npmignore ├── examples ├── long.png ├── scale2.png └── lightgray.png ├── index.js ├── .gitignore ├── shielded ├── package.json ├── lib ├── svg2png.js ├── shield.js ├── converter.js └── shield.svg ├── LICENSE ├── README.md ├── shield.svg └── shields.svg /.npmignore: -------------------------------------------------------------------------------- 1 | examples/ 2 | -------------------------------------------------------------------------------- /examples/long.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/badges/shielded/master/examples/long.png -------------------------------------------------------------------------------- /examples/scale2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/badges/shielded/master/examples/scale2.png -------------------------------------------------------------------------------- /examples/lightgray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/badges/shielded/master/examples/lightgray.png -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var shield = require('./lib/shield'); 4 | module.exports = shield; 5 | 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | lib-cov 2 | *.seed 3 | *.log 4 | *.csv 5 | *.dat 6 | *.out 7 | *.pid 8 | *.gz 9 | 10 | pids 11 | logs 12 | results 13 | 14 | npm-debug.log 15 | node_modules/ 16 | -------------------------------------------------------------------------------- /shielded: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var logger = require('log-driver').logger; 4 | var shield = require('./lib/shield'); 5 | var argv = require('optimist') 6 | .usage('Usage: $0 --label=[string] --value=[string] --file=[filepath] --color=[green/yellowgreen/yellow/red/lightgray/] --scale=[num] --tempdir=[path]') 7 | .demand(['label','value', 'file']) 8 | .default('color', 'green') 9 | .default('tempdir', '/tmp') 10 | .default('scale', 1) 11 | .argv; 12 | 13 | var options = { 14 | vendorText : argv.label, 15 | statusText : argv.value, 16 | color : argv.color, 17 | filename : argv.file, 18 | scale : argv.scale, 19 | tempdir : argv.tempdir, 20 | loglevel : false 21 | }; 22 | 23 | shield(options, function(err){ 24 | if (err){ 25 | console.log("Error:"); 26 | console.log(err); 27 | process.exit(1); 28 | } 29 | }); 30 | 31 | 32 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "shielded", 3 | "version": "0.2.0", 4 | "description": "creates shield pngs for github ala https://github.com/olivierlacan/shields/ ", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "bin": { 10 | "shielded": "./shielded" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git://github.com/cainus/shielded.git" 15 | }, 16 | "keywords": [ 17 | "github", 18 | "shield", 19 | "shields", 20 | "badge", 21 | "badges" 22 | ], 23 | "author": "Gregg Caines (http://caines.ca)", 24 | "contributors": [ 25 | "Domenic Denicola (http://domenicdenicola.com)" 26 | ], 27 | "license": "BSD", 28 | "dependencies": { 29 | "phantomjs": "1.9.0-6", 30 | "optimist": "0.5.2", 31 | "log-driver": "~1.2.1" 32 | }, 33 | "devDependencies": {} 34 | } 35 | -------------------------------------------------------------------------------- /lib/svg2png.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | var execFile = require("child_process").execFile; 3 | 4 | var phantomjsCmd = path.resolve(__dirname, "../node_modules/phantomjs/bin/phantomjs"); 5 | var converterFileName = path.resolve(__dirname, "./converter.js"); 6 | 7 | module.exports = function svgToPng(sourceFileName, destFileName, scale, cb) { 8 | if (typeof scale === "function") { 9 | cb = scale; 10 | scale = 1.0; 11 | } 12 | 13 | var args = [phantomjsCmd, converterFileName, sourceFileName, destFileName, scale]; 14 | require('log-driver').logger.debug(args); 15 | execFile(process.execPath, args, function (err, stdout, stderr) { 16 | if (err) { 17 | cb(err); 18 | } else if (stdout.length > 0) { // PhantomJS always outputs to stdout. 19 | cb(new Error(stdout.toString().trim())); 20 | } else if (stderr.length > 0) { // But hey something else might get to stderr. 21 | cb(new Error(stderr.toString().trim())); 22 | } else { 23 | cb(null); 24 | } 25 | }); 26 | }; 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) Gregg Caines (gregg@caines.ca) ("Author") 2 | All rights reserved. 3 | 4 | The BSD License 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions 8 | are met: 9 | 10 | 1. Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | 13 | 2. Redistributions in binary form must reproduce the above copyright 14 | notice, this list of conditions and the following disclaimer in the 15 | documentation and/or other materials provided with the distribution. 16 | 17 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS 21 | BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 | SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 24 | BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 25 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 26 | OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 27 | IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | shielded 2 | ======== 3 | 4 | [![deprecated](http://badges.github.io/stability-badges/dist/deprecated.svg)](http://github.com/badges/stability-badges) 5 | 6 | try to solve https://github.com/olivierlacan/shields/issues/15?source=c 7 | 8 | 9 | ``` 10 | Usage: shielded --label=[string] --value=[string] --file=[filepath] --color=[green/yellowgreen/yellow/red/lightgray/] --scale=[num] 11 | 12 | Options: 13 | --label [required] 14 | --value [required] 15 | --file [required] 16 | --color [default: "green"] 17 | --scale [default: 1] 18 | 19 | ``` 20 | 21 | ##example output: 22 | ![light gray](https://raw.github.com/cainus/shielded/master/examples/lightgray.png) 23 | 24 | ![scale X 2](https://raw.github.com/cainus/shielded/master/examples/scale2.png) 25 | 26 | ![lots of text](https://raw.github.com/cainus/shielded/master/examples/long.png) 27 | 28 | 29 | ## installation: 30 | ```shell 31 | git clone git@github.com:cainus/shielded.git # clone this repo 32 | cd shielded # go into the newly created directory 33 | npm install # install the dependencies 34 | ./shielded --label=worked --value=yep --file=file.png --color=green --scale=1 # create a png named file.png 35 | ``` 36 | 37 | ## Notes: 38 | * This also works as a node.js library for use in node.js apps. See https://github.com/cainus/shield-server for an example of a web application that uses this. 39 | * @jbowes is a bad man and rewrote this service in golang: https://github.com/jbowes/buckler . It probably vastly outperforms this library. 40 | -------------------------------------------------------------------------------- /lib/shield.js: -------------------------------------------------------------------------------- 1 | // image is from: https://github.com/olivierlacan/shields 2 | var svg2png = require('./svg2png'); 3 | var fs = require('fs'); 4 | var logger = require('log-driver').logger; 5 | 6 | var getUniqueId = function(vendorText, statusText, color, scale){ 7 | return new Buffer(JSON.stringify({vendor:vendorText, 8 | status:statusText, 9 | color:color, 10 | scale:scale})) 11 | .toString('base64'); 12 | }; 13 | 14 | var shield = function(options, cb){ 15 | if (!options.vendorText || !options.statusText){ 16 | return cb("missing required field."); 17 | } 18 | if (options.loglevel || options.loglevel === false){ 19 | logger = require('log-driver').logger = require('log-driver')({level : options.loglevel }); 20 | } 21 | var vendorText = options.vendorText; 22 | var statusText = options.statusText; 23 | var color = options.color || 'lightgray'; 24 | var scale = options.scale || 1; 25 | var tempdir = options.tempdir || '/tmp'; 26 | var filename = options.filename || getUniqueId(vendorText, 27 | statusText, 28 | color, 29 | scale) + '.png'; 30 | if (['green', 'yellow', 31 | 'yellowgreen', 'red', 32 | 'lightgray' ].indexOf(color) === -1){ 33 | return cb("invalid background color: " + color); 34 | } 35 | 36 | fs.readFile(__dirname + "/shield.svg", function(err, contents){ 37 | if (err){ 38 | return cb(err); 39 | } 40 | contents = contents.toString(); 41 | var svgFileName = tempdir + '/' + getUniqueId(vendorText, statusText, color, 1) + '.svg'; 42 | // scale value is irrelevant for svg, so just set it to a constant 1 43 | logger.debug("contents: ", contents); 44 | logger.debug("svg file: ", svgFileName); 45 | var svgFileStream = fs.createWriteStream(svgFileName); 46 | contents.split('||').forEach(function(piece){ 47 | switch(piece){ 48 | case 'vendor' : 49 | piece = vendorText; 50 | break; 51 | case 'status' : 52 | piece = statusText; 53 | break; 54 | case 'color' : 55 | piece = color; 56 | break; 57 | } 58 | svgFileStream.write(piece); 59 | }); 60 | svgFileStream.end(); 61 | svg2png(svgFileName, filename, scale, function (err) { 62 | cb(err); 63 | }); 64 | }); 65 | }; 66 | 67 | module.exports = shield; 68 | -------------------------------------------------------------------------------- /shield.svg: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | vendor 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | status 75 | 76 | 77 | -------------------------------------------------------------------------------- /lib/converter.js: -------------------------------------------------------------------------------- 1 | var webpage = require("webpage"); 2 | var fs = require("fs"); 3 | 4 | if (phantom.args.length !== 3) { 5 | console.error("Usage: converter.js source dest scale"); 6 | phantom.exit(); 7 | } else { 8 | convert(phantom.args[0], phantom.args[1], Number(phantom.args[2])); 9 | } 10 | 11 | function convert(source, dest, scale) { 12 | var page = webpage.create(); 13 | page.onConsoleMessage = function(){ 14 | console.log(arguments[0]); 15 | }; 16 | 17 | var dimensions; 18 | 19 | page.open(source, function (status) { 20 | if (status !== "success") { 21 | console.error("Unable to load the source file."); 22 | phantom.exit(); 23 | return; 24 | } 25 | 26 | 27 | var doc = 'unset'; 28 | var dimensions = page.evaluate(function(){ 29 | var el = function(id){ 30 | return document.documentElement.getElementById(id); 31 | }; 32 | var setVendorText = function(text){ 33 | el("vendorText3").firstChild.textContent = text; 34 | el("vendorText2").firstChild.textContent = text; 35 | el("vendorText1").firstChild.textContent = text; 36 | }; 37 | var setStatusText = function(text){ 38 | var doc = document.documentElement; 39 | el("statusText3").firstChild.textContent = text; 40 | el("statusText2").firstChild.textContent = text; 41 | el("statusText1").firstChild.textContent = text; 42 | }; 43 | var setStatusTextX = function(x){ 44 | var doc = document.documentElement; 45 | el("statusText3").setAttribute("x", x); 46 | el("statusText2").setAttribute("x", x); 47 | el("statusText1").setAttribute("x", x); 48 | }; 49 | var setColor = function(color){ 50 | if (['green', 'yellow', 51 | 'yellowgreen', 'red', 52 | 'lightgray' ].indexOf(color) === -1){ 53 | throw "invalid background color: " + color; 54 | } 55 | el("statusBackground").setAttribute("fill", "url(#" + color + ")"); 56 | }; 57 | // vendor part 58 | 59 | //setVendorText("shawty"); 60 | 61 | // resize Vendor Background 62 | var vendorBackground = el("vendorBackground"); 63 | var vendorTextBox = el("vendorText").getBBox(); 64 | var vendorWidth = vendorTextBox.width + (2 * vendorTextBox.x); 65 | vendorBackground.setAttribute("d", 66 | "M32,19.25H3c-1.657,0-3-1.343-3-3v-12c0-1.657,1.343-3,3-3h" + 67 | vendorWidth + 68 | "V19.25z"); 69 | 70 | // status part 71 | //setStatusText("reallyreallyreallyloooooong"); 72 | 73 | setStatusTextX(vendorWidth + 4); 74 | var statusTextBox = el("statusText").getBBox(); 75 | var statusWidth = statusTextBox.width + (4 * 2); 76 | 77 | var statusBg = el("statusBackground"); 78 | var statusX = vendorWidth + 0; 79 | var statusBgBox = statusBg.getBBox(); 80 | var curveVals1 = [1.657, 0, 3, -1.343, 3, -3]; 81 | var curveVals2 = [0, -1.657, -1.343, -3, -3, -3]; 82 | var draw = "M" + (statusX) + " 19.25" + 83 | " H " + (statusX + statusWidth - 3) + //subtract 3 to leave room for curve 84 | " c " + 85 | curveVals1.join(" ") + 86 | " v -12 " + 87 | "c " + 88 | curveVals2.join(" ") + 89 | " H " + statusX + "V 19.25 z"; 90 | statusBg.setAttribute("d", draw); 91 | 92 | // setColor("yellowgreen"); 93 | 94 | var totalWidth = vendorWidth + statusWidth; 95 | document.documentElement.setAttribute("viewBox", "0 1.25 " + totalWidth + " 18"); 96 | document.documentElement.setAttribute("width", totalWidth); 97 | 98 | // TODO make png as small as the svg 99 | 100 | // resize png based on svg dimensions 101 | var doc = document.documentElement; 102 | var bbox = doc.getBBox(); 103 | //console.log(JSON.stringify(bbox)); 104 | // 105 | // 106 | // 107 | return {width : bbox.width, height : bbox.height, usesViewBox : false}; 108 | 109 | }); 110 | page.viewportSize = { 111 | width: Math.round(dimensions.width * scale), 112 | height: Math.round(dimensions.height * scale) 113 | }; 114 | if (!dimensions.usesViewBox) { 115 | page.zoomFactor = scale; 116 | } 117 | 118 | // This delay is I guess necessary for the resizing to happen? 119 | setTimeout(function () { 120 | page.render(dest); 121 | phantom.exit(); 122 | }, 0); 123 | }); 124 | } 125 | 126 | -------------------------------------------------------------------------------- /lib/shield.svg: -------------------------------------------------------------------------------- 1 | 2 | 21 | 22 | 23 | 24 | image/svg+xml 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 51 | 52 | 53 | 54 | 55 | 56 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 108 | 109 | 113 | 117 | 118 | 119 | ||status|| 127 | 128 | 129 | ||status|| 137 | ||status|| 145 | 146 | 147 | 148 | 149 | ||vendor|| 157 | 158 | 159 | ||vendor|| 167 | ||vendor|| 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /shields.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | status 27 | 28 | 29 | status 30 | 31 | 32 | 33 | 34 | service 35 | 36 | 37 | service 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | status 61 | 62 | 63 | status 64 | 65 | 66 | 67 | 68 | service 69 | 70 | 71 | service 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | status 95 | 96 | 97 | status 98 | 99 | 100 | 101 | 102 | service 103 | 104 | 105 | service 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | status 129 | 130 | 131 | status 132 | 133 | 134 | 135 | 136 | service 137 | 138 | 139 | service 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | status 163 | 164 | 165 | status 166 | 167 | 168 | 169 | 170 | service 171 | 172 | 173 | service 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | status 197 | 198 | 199 | status 200 | 201 | 202 | 203 | 204 | service 205 | 206 | 207 | service 208 | 209 | 210 | 211 | 212 | --------------------------------------------------------------------------------