├── .gitignore ├── .gitmodules ├── Gruntfile.js ├── README.rst ├── app ├── assets │ ├── js │ │ └── main.js │ └── styl │ │ └── main.styl └── views │ └── index.jade ├── docker-compose.yml ├── keys └── deployment │ └── .gitignore ├── package.json ├── run └── static /.gitignore: -------------------------------------------------------------------------------- 1 | webroot/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "app/assets/js/baba"] 2 | path = app/assets/js/baba 3 | url = https://github.com/Lokaltog/baba.git 4 | [submodule "app/assets/js/seedrandom"] 5 | path = app/assets/js/seedrandom 6 | url = https://github.com/davidbau/seedrandom.git 7 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | var matchdep = require('matchdep'), 3 | jsFiles, 4 | stylFiles, 5 | jadeFiles 6 | 7 | matchdep.filter('grunt-*').forEach(grunt.loadNpmTasks) 8 | 9 | jsFiles = { 10 | 'webroot/static/js/main.js': [ 11 | 'app/assets/js/baba/src/baba.js', 12 | 'app/assets/js/baba/src/grammar/common.js', 13 | 'app/assets/js/baba/src/grammar/git-manual.js', 14 | 'app/assets/js/seedrandom/seedrandom.js', 15 | 'app/assets/js/main.js', 16 | ], 17 | } 18 | stylFiles = [{ 19 | 'webroot/static/css/main.css': [ 20 | 'app/assets/styl/main.styl', 21 | ], 22 | }] 23 | jadeFiles = [{ 24 | expand: true, 25 | cwd: 'app/views', 26 | src: '**/*.jade', 27 | dest: 'webroot/', 28 | ext: '.html', 29 | }] 30 | 31 | grunt.initConfig({ 32 | pkg: grunt.file.readJSON('package.json'), 33 | 34 | clean: { 35 | all: [ 36 | 'webroot/{static,views}', 37 | ], 38 | }, 39 | sync: { 40 | all: { 41 | files: [{ 42 | cwd: 'app/assets', 43 | src: '{font,img,etc}/**', 44 | dest: 'webroot/static/', 45 | }], 46 | }, 47 | }, 48 | stylus: { 49 | development: { 50 | files: stylFiles, 51 | options: { 52 | debug: true, 53 | compress: false, 54 | 'include css': true, 55 | use: [ 56 | require('nib'), 57 | ], 58 | 'import': [ 59 | 'nib', 60 | ], 61 | }, 62 | }, 63 | production: { 64 | files: stylFiles, 65 | options: { 66 | debug: false, 67 | compress: true, 68 | 'include css': true, 69 | use: [ 70 | require('nib'), 71 | ], 72 | 'import': [ 73 | 'nib', 74 | ], 75 | }, 76 | }, 77 | }, 78 | jade: { 79 | development: { 80 | files: jadeFiles, 81 | options: { 82 | pretty: true, 83 | }, 84 | }, 85 | production: { 86 | files: jadeFiles, 87 | options: { 88 | pretty: false, 89 | }, 90 | }, 91 | }, 92 | cssmin: { 93 | all: { 94 | files: [{ 95 | expand: true, 96 | cwd: 'webroot/static/css', 97 | src: '**/*.css', 98 | dest: 'webroot/static/css', 99 | }], 100 | }, 101 | }, 102 | htmlmin: { 103 | all: { 104 | options: { 105 | collapseWhitespace: true, 106 | collapseBooleanAttributes: true, 107 | removeAttributeQuotes: true, 108 | removeRedundantAttributes: true, 109 | removeEmptyAttributes: true, 110 | removeOptionalTags: true, 111 | }, 112 | files: [{ 113 | expand: true, 114 | cwd: 'webroot/', 115 | src: '**/*.html', 116 | dest: 'webroot/', 117 | }], 118 | }, 119 | }, 120 | uglify: { 121 | development: { 122 | files: jsFiles, 123 | options: { 124 | compress: { 125 | global_defs: { 126 | DEBUG: true, 127 | }, 128 | }, 129 | beautify: true, 130 | mangle: false, 131 | warnings: true, 132 | }, 133 | }, 134 | production: { 135 | files: jsFiles, 136 | options: { 137 | compress: { 138 | drop_console: true, 139 | unsafe: true, 140 | global_defs: { 141 | DEBUG: false, 142 | }, 143 | }, 144 | beautify: false, 145 | mangle: { 146 | toplevel: true, 147 | }, 148 | warnings: true, 149 | }, 150 | }, 151 | }, 152 | watch: { 153 | options: { 154 | spawn: false, 155 | atBegin: true, 156 | }, 157 | sync: { 158 | files: ['app/assets/{img,font,etc}/**'], 159 | tasks: ['sync:all'], 160 | }, 161 | uglify: { 162 | files: ['app/assets/js/**/*.js'], 163 | tasks: ['uglify:development'], 164 | }, 165 | stylus: { 166 | files: ['app/assets/styl/**/*.styl'], 167 | tasks: ['stylus:development'], 168 | }, 169 | jade: { 170 | files: ['app/views/**/*.jade'], 171 | tasks: ['jade:development'], 172 | }, 173 | livereload: { 174 | files: ['webroot/static/css/**/*.css'], 175 | tasks: [], 176 | options: { 177 | livereload: true, 178 | }, 179 | }, 180 | }, 181 | inline: { 182 | all: { 183 | files: { 184 | 'webroot/index.html': 'webroot/index.html', 185 | }, 186 | }, 187 | }, 188 | imageEmbed: { 189 | all: { 190 | src: ['webroot/static/css/main.css'], 191 | dest: 'webroot/static/css/main.css', 192 | options: { 193 | maxImageSize: 0, 194 | baseDir: 'webroot', 195 | }, 196 | }, 197 | }, 198 | }) 199 | 200 | grunt.registerTask('development', [ 201 | 'watch', 202 | ]) 203 | 204 | grunt.registerTask('production', [ 205 | 'clean:all', 206 | 'sync:all', 207 | 'stylus:production', 208 | 'jade:production', 209 | 'uglify:production', 210 | 'cssmin:all', 211 | 'htmlmin:all', 212 | 'imageEmbed:all', 213 | 'inline:all', 214 | 'clean:all', 215 | ]) 216 | } 217 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Baba: git man page generator 2 | ============================ 3 | 4 | :Author: Kim Silkebækken (kim.silkebaekken@gmail.com) 5 | :Source: https://github.com/Lokaltog/baba-git-man-page-generator 6 | 7 | Git man page generator based on `Baba `_, a garbage 8 | text generator inspired by the Dada Engine. 9 | 10 | Live demo: http://git-man-page-generator.lokaltog.net/ 11 | -------------------------------------------------------------------------------- /app/assets/js/main.js: -------------------------------------------------------------------------------- 1 | (function () { 2 | var baba = new Baba.Parser('git-manual') 3 | 4 | var seedLength = 32 5 | var urlSeed = (document.URL.split('#')[1] || '').slice(0, seedLength) 6 | 7 | function randomSeed(seed) { 8 | if (seed) { 9 | // Seed with provided seed 10 | Math.seedrandom(seed) 11 | return seed 12 | } 13 | 14 | // Generate new random seed 15 | seed = Math.seedrandom() 16 | var hex = '' 17 | for (var i = 0; i < seed.length; i++) { 18 | hex += '' + seed.charCodeAt(i).toString(16) 19 | } 20 | var seedSliced = hex.slice(0, seedLength) 21 | Math.seedrandom(seedSliced) 22 | 23 | return seedSliced 24 | } 25 | 26 | function $(selector, el) { 27 | if (!el) { 28 | el = document 29 | } 30 | return el.querySelector(selector) 31 | } 32 | 33 | function $$(selector, el) { 34 | if (!el) { 35 | el = document 36 | } 37 | return el.querySelectorAll(selector) 38 | } 39 | 40 | function randomInt(min, max) { 41 | return Math.floor(Math.random() * (max - min + 1)) + min 42 | } 43 | 44 | function refresh() { 45 | // handle url seed (permalink) 46 | var seed = randomSeed(urlSeed) 47 | urlSeed = null 48 | $('#permalink').setAttribute('href', '#' + seed) 49 | 50 | // command name and description 51 | var commandVerb = baba.render('verb.common') 52 | var commandNoun = baba.render('noun.git') 53 | var commandNameRaw = ['git', commandVerb, commandNoun].join('-') 54 | 55 | baba.setVariable('command-verb', commandVerb) 56 | baba.setVariable('command-noun', commandNoun) 57 | 58 | var commandName = '' + commandNameRaw + '' 59 | var commandAction = baba.render('command-action') 60 | var commandDescription = baba.render('command-description') 61 | var commandNameContainers = $$('.command-name') 62 | var i 63 | 64 | $('header h1').innerHTML = commandName 65 | for (i = 0; i < commandNameContainers.length; i += 1) { 66 | commandNameContainers[i].innerHTML = commandName 67 | } 68 | 69 | document.title = commandNameRaw + ' - git man page generator' 70 | $('.command-action').innerHTML = commandAction 71 | $('.command-description').innerHTML = commandName + ' ' + commandDescription 72 | 73 | // arguments 74 | var args = [] 75 | var rawArguments = [] 76 | var argument = '' 77 | for (i = 0; i < randomInt(2, 4); i += 1) { 78 | if (Math.random() > .5) { 79 | var optarg = [] 80 | for (var i = 0; i < randomInt(2, 4); i += 1) { 81 | var a = baba.render('command-option-raw') 82 | rawArguments.push(a) 83 | optarg.push(a) 84 | } 85 | argument = '[ ' + optarg.join(' | ') + ' ]' 86 | } 87 | else { 88 | argument = baba.render('command-option-raw') 89 | rawArguments.push(argument) 90 | 91 | if (Math.random() > .5) { 92 | argument = '[ ' + argument + ' ]' 93 | } 94 | } 95 | 96 | args.push(argument) 97 | } 98 | $('.command-arguments').innerHTML = ' ' + args.join(' ') 99 | 100 | // description 101 | var description = '' 102 | for (var i = 0; i < randomInt(2, 4); i += 1) { 103 | description += '

' + baba.render('paragraph') + '

' 104 | } 105 | $('#description .contents').innerHTML = description 106 | 107 | // argument descriptions 108 | var argDesc = [] 109 | rawArguments.forEach(function (arg) { 110 | argDesc.push('
' + arg + '
' + baba.render('option-description')) 111 | }) 112 | $('#options').innerHTML = argDesc.join('') 113 | 114 | // see also 115 | var seeAlso = [] 116 | for (i = 0; i < randomInt(2, 4); i += 1) { 117 | seeAlso.push('
  • ' + baba.render('command-name') + '') 118 | } 119 | $('#see-also').innerHTML = seeAlso.join('') 120 | 121 | // add event listeners to refresh links 122 | var refreshEls = $$('.refresh') 123 | for (i = 0; i < refreshEls.length; i += 1) { 124 | refreshEls[i].addEventListener('click', refresh) 125 | } 126 | } 127 | refresh() 128 | $('#refresh').addEventListener('click', refresh) 129 | 130 | })() 131 | -------------------------------------------------------------------------------- /app/assets/styl/main.styl: -------------------------------------------------------------------------------- 1 | global-reset() 2 | reset-html5() 3 | 4 | // theme settings 5 | $font-main = sans-serif 6 | $font-monospace = monospace 7 | $font-size = 16px 8 | $color-background = #fff 9 | $color-foreground = #333 10 | $width = 860px 11 | $margin = 30px 12 | $color-theme = #37a 13 | 14 | // layout 15 | html, body 16 | background: $color-background 17 | color: $color-foreground 18 | font: $font-size/1.4 $font-main 19 | 20 | a 21 | color: $color-theme 22 | &:hover 23 | color: darken($color-theme, 10) 24 | 25 | p 26 | margin: ($margin / 2) 0 27 | 28 | code 29 | font-family: $font-monospace 30 | 31 | .disclaimer 32 | background: #fed 33 | padding: ($margin / 2) 0 34 | text-align: center 35 | color: #410 36 | 37 | header 38 | border-bottom: 1px solid rgba(#000, .2) 39 | border-top: 1px solid rgba(#000, .2) 40 | height: 40px 41 | line-height: @height 42 | padding: ($margin / 2) 0 43 | position: relative 44 | 45 | h1 46 | font: bold $font-size + 7px $font-main 47 | color: $color-theme 48 | line-height: @height 49 | margin: 0 ($margin / 2) 0 0 50 | code 51 | font: bold $font-size + 7px $font-main 52 | &::after 53 | content: '(1) Manual Page' 54 | 55 | #actions 56 | position: absolute 57 | right: 0 58 | top: ($margin / 2) 59 | li 60 | display: inline-block 61 | margin: 0 0 0 ($margin / 2) 62 | 63 | #permalink 64 | font-weight: bold 65 | 66 | #refresh 67 | background-color: $color-theme 68 | border: 0 69 | color: #fff 70 | cursor: pointer 71 | font: bold $font-size\/@height $font-main 72 | margin: 0 73 | padding: 0 ($margin / 2) 74 | &:hover 75 | background-color: darken($color-theme, 10) 76 | 77 | #contents 78 | margin: $margin auto 79 | 80 | h1 81 | color: $color-theme 82 | font: bold $font-size + 5px $font-main 83 | text-transform: uppercase 84 | 85 | .block 86 | margin: $margin 0 $margin $margin 87 | 88 | #name 89 | .command-name 90 | font-family: $font-monospace 91 | .command-action 92 | &::before 93 | content: ' — ' 94 | 95 | #synopsis 96 | font-family: $font-monospace 97 | 98 | #options 99 | dt 100 | font-family: $font-monospace 101 | font-weight: bold 102 | margin: ($margin / 2) 0 0 0 103 | dd 104 | margin: 0 0 0 $margin 105 | 106 | #see-also 107 | font-family: $font-monospace 108 | li 109 | display: inline 110 | &::after 111 | content: '(1), ' 112 | &:last-child 113 | &::after 114 | content: '(1)' 115 | 116 | footer 117 | border-top: 1px solid rgba(#000, .2) 118 | text-align: center 119 | 120 | p 121 | margin: ($margin / 2) 0 0 0 122 | 123 | header, #contents, footer, .disclaimer 124 | margin: $margin auto 125 | max-width: $width 126 | -------------------------------------------------------------------------------- /app/views/index.jade: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | meta(charset='utf-8') 5 | meta(http-equiv='Content-Type', content='text/html;charset=utf-8') 6 | title Git man page generator 7 | link(rel='stylesheet', href='static/css/main.css?__inline=true', type='text/css') 8 | 9 | body 10 | .disclaimer This is NOT real git documentation! Read carefully, and click the button to generate a new man page. 11 | 12 | header 13 | h1 14 | Git man page generator 15 | 16 | ul#actions 17 | li 18 | a#permalink(href='#') Permalink 19 | li 20 | button#refresh Generate new man page 21 | 22 | section#contents 23 | h1 Name 24 | .block 25 | #name 26 | span.command-name 27 | span.command-action 28 | 29 | h1 Synopsis 30 | .block 31 | #synopsis 32 | span.command-name 33 | span.command-arguments 34 | 35 | h1 Description 36 | .block 37 | #description 38 | p.command-description 39 | .contents 40 | 41 | h1 Options 42 | .block 43 | dl#options 44 | 45 | h1 See also 46 | .block 47 | ul#see-also 48 | 49 | footer 50 | p Created by 51 | = ' ' 52 | a(href='https://github.com/Lokaltog') Lokaltog 53 | = ' - ' 54 | a(href='https://github.com/Lokaltog/baba-git-man-page-generator') GitHub repo 55 | 56 | script 57 | | (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); 58 | | ga('create', 'UA-48138687-1', 'git-man-page-generator.lokaltog.net'); 59 | | ga('send', 'pageview'); 60 | script(src='static/js/main.js?__inline=true') 61 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | depcache-data: 2 | # Cached dependencies for npm/pip 3 | image: lokaltog/baseimage 4 | volumes: 5 | - /var/www/node_modules 6 | command: /bin/true 7 | 8 | app-common: 9 | image: lokaltog/nginx-statichost 10 | environment: 11 | - VIRTUAL_HOST=git-man-page-generator.lokaltog.net,git-man-page-generator.lokaltog.net.test 12 | - APP_ORIGIN=git@github.com:Lokaltog/git-man-page-generator.git 13 | - APP_BRANCH=develop 14 | - APP_COMMIT=HEAD 15 | - APP_NAME=git-man-page-generator.lokaltog.net 16 | log_driver: syslog 17 | log_opt: 18 | tag: '{{.ImageName}}/{{.Name}}' 19 | 20 | production: 21 | extends: app-common 22 | volumes_from: 23 | - depcache-data 24 | environment: 25 | - APP_ENV=production 26 | - CERT_NAME=lokaltog.net 27 | volumes: 28 | - ./keys:/keys 29 | - ./run:/etc/service/app/run 30 | 31 | development: 32 | extends: app-common 33 | volumes_from: 34 | - depcache-data 35 | environment: 36 | - APP_ENV=development 37 | - CERT_NAME=test 38 | volumes: 39 | - ./:/var/www 40 | -------------------------------------------------------------------------------- /keys/deployment/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baba-git-man-page-generator", 3 | "version": "0.0.1a1", 4 | "private": true, 5 | "author": "Kim Silkebækken ", 6 | "description": "Baba: git man page generator.", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/Lokaltog/baba-git-man-page-generator" 10 | }, 11 | "dependencies" : { 12 | "jade": "*", 13 | "nib": "*", 14 | "stylus": "*", 15 | "uglify-js": "*", 16 | 17 | "grunt": "*", 18 | "grunt-cli": "*", 19 | "grunt-contrib-clean": "*", 20 | "grunt-contrib-cssmin": "*", 21 | "grunt-contrib-htmlmin": "*", 22 | "grunt-contrib-jade": "*", 23 | "grunt-contrib-stylus": "*", 24 | "grunt-contrib-uglify": "*", 25 | "grunt-contrib-watch": "*", 26 | "grunt-image-embed": "*", 27 | "grunt-inline": "*", 28 | "grunt-sync": "*", 29 | "matchdep": "*" 30 | }, 31 | "engines": { 32 | "node": ">=0.10" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /run: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Set APP_ENV=production to force production build 4 | if [[ "$APP_ENV" != 'development' ]]; then 5 | as_www() { 6 | sudo -su www-data HOME=/var/www "$@" 7 | } 8 | 9 | pushd /var/www 10 | 11 | chown www-data: -R /var/www 12 | 13 | git init 14 | git remote add origin $APP_ORIGIN 15 | GIT_SSH_COMMAND="ssh -i /keys/deployment/${APP_NAME}-deployment" git pull origin --recurse-submodules $APP_BRANCH 16 | git checkout $APP_COMMIT 17 | git submodule init 18 | git submodule update --recursive 19 | 20 | as_www npm install 21 | as_www npm update 22 | as_www node_modules/.bin/grunt production 23 | 24 | popd 25 | fi 26 | 27 | exec nginx -g 'daemon off;' 2>&1 28 | -------------------------------------------------------------------------------- /static: -------------------------------------------------------------------------------- 1 | webroot --------------------------------------------------------------------------------