dokuen 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,18 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ dokuen (0.0.1)
5
+ thor
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ rake (0.9.2.2)
11
+ thor (0.14.6)
12
+
13
+ PLATFORMS
14
+ ruby
15
+
16
+ DEPENDENCIES
17
+ dokuen!
18
+ rake
data/README.md ADDED
@@ -0,0 +1,95 @@
1
+ # Dokuen, a Personal App Platform
2
+
3
+ Dokuen is a "personal app platform". It's the same idea as all of these PaaS and IaaS services out there, except you host it on your own machine. It's specifically for hosting multiple 12-factor applications on one Mac.
4
+
5
+ ## Requirements
6
+
7
+ * [Gitolite](https://github.com/sitaramc/gitolite)
8
+ * [Nginx](http://wiki.nginx.org/Main)
9
+
10
+ ## Installation
11
+
12
+
13
+ ### Step 1
14
+
15
+ ```
16
+ gem install dokuen
17
+ ```
18
+
19
+ ### Step 2
20
+
21
+ Install nginx using homebrew.
22
+
23
+ ### Step 3
24
+
25
+ Create a `git` user and install gitolite according to [package directions](http://sitaramc.github.com/gitolite/qi.html). You'll be making changes to the config later, but for now you should be able to create a new repository and push to it.
26
+
27
+ ### Step 4
28
+
29
+ Run this:
30
+
31
+ ```
32
+ $ sudo dokuen setup
33
+ ```
34
+
35
+ This will ask you a few questions, set up a few directories, and install a few useful commands. It'll also show you some things you need to do.
36
+
37
+ ## Creating an App
38
+
39
+ ```
40
+ $ ssh git@<your_host> dokuen create <name>
41
+ Creating new application named <name>
42
+ Remote: git@<your_host>:<name>.git
43
+
44
+ $ git remote add dokuen git@<your_host>:<name>.git
45
+ ```
46
+
47
+ ### Add some environment variables
48
+
49
+ ```
50
+ $ ssh git@<your_host> dokuen config <name> set -V BUILDPACK_URL="https://github.com/heroku/heroku-buildpack-ruby.git" PORT=12345 DOKUEN_SCALE="web=1"
51
+ ```
52
+
53
+ ### Deploy
54
+ ```
55
+ $ git push dokuen master
56
+ <deploy transcript>
57
+ ```
58
+
59
+ ### Check it out!
60
+ ```
61
+ $ open http://<your_host>:12345/
62
+ ```
63
+
64
+ ## Available "app" Sub-commands
65
+
66
+ * create <name>
67
+ * config <name>
68
+ * set <key>=<value> ...
69
+ * delete <key> ...
70
+ * restart_app <name>
71
+ * scale <name> <type>=<num>
72
+ * buildpacks
73
+ * install_buildpack
74
+ * remove_buildpack
75
+
76
+ ## DNS Setup
77
+
78
+ I have my home router set up to forward ports 80 and 443 to my mac mini, and I have a dynamic DNS system set up with a wildcard CNAME Unfortunately this setup is hard to automate so Dokuen doesn't manage any of it for you.
79
+
80
+ What it does do is set up Nginx server configs for you that you can choose to use. If you want to use them, put this at the bottom of the `http` section of `nginx.conf`:
81
+
82
+ ```
83
+ include /usr/local/var/dokuen/nginx/*.conf;
84
+ ```
85
+
86
+ Then, force a restart of your app:
87
+
88
+ ```
89
+ $ ssh git@<your_host> dokuen restart_app <name>
90
+ ```
91
+
92
+ ## Rails
93
+
94
+ Unfortunately the stock Heroku buildpacks install a vendored node.js compiled for the Heroku platform, which happens to be linux. This doesn't work for Mac, which means you have to use a slightly patched version. This one works with a homebrew-installed node.js: https://github.com/peterkeen/heroku-buildpack-ruby
95
+
data/bin/dokuen ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "rubygems"
4
+
5
+ begin
6
+ require 'dokuen'
7
+ rescue LoadError => e
8
+ path = File.expand_path '../../lib', __FILE__
9
+ $:.unshift(path) if File.directory?(path) && !$:.include?(path)
10
+ require 'dokuen'
11
+ end
12
+
13
+ Dokuen::Cli.start()
@@ -0,0 +1,6 @@
1
+ #!/bin/bash
2
+
3
+ NAME=`basename $1`
4
+ cp $1 /Library/LaunchDaemons
5
+ launchctl unload -wF /Library/LaunchDaemons/$NAME
6
+ launchctl load -wF /Library/LaunchDaemons/$NAME
data/bin/pre-receive ADDED
@@ -0,0 +1,122 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tmpdir'
4
+ require 'fileutils'
5
+ require 'time'
6
+
7
+ MASON = "/usr/local/Cellar/ruby/1.9.3-p125/lib/ruby/gems/1.9.1/gems/mason-0.0.11/bin/mason"
8
+ BASE_BUILD_DIR = '/usr/local/var/dokuen/build'
9
+ BASE_RELEASE_DIR = '/usr/local/var/dokuen/release'
10
+ BASE_NGINX_CONF = '/usr/local/var/dokuen/nginx'
11
+ BASE_ENV_DIR = '/usr/local/var/dokuen/env'
12
+
13
+ should_deploy = `git config hooks.deploy`.chomp
14
+ subdomain = `git config hooks.deploy.subdomain`.chomp
15
+ port = `git config hooks.deploy.port`.chomp
16
+ foreman = `git config hooks.deploy.foreman`.chomp
17
+ buildpack_url = `git config hooks.deploy.buildpack`.chomp
18
+ after_deploy = `git config hooks.deploy.after`.chomp
19
+
20
+ exit(0) if should_deploy != "true"
21
+
22
+ def sys(cmd)
23
+ system(cmd) or exit(1)
24
+ end
25
+
26
+ File.umask(0022)
27
+
28
+ git_dir = Dir.getwd
29
+ cache_dir = "#{BASE_BUILD_DIR}/#{subdomain}"
30
+ now = Time.now().utc().strftime("%Y%m%dT%H%M%S")
31
+ release_dir = "#{BASE_RELEASE_DIR}/#{subdomain}/#{now}"
32
+ env_dir = "#{BASE_ENV_DIR}/#{subdomain}"
33
+
34
+ FileUtils.mkdir_p(cache_dir, :mode => 0777)
35
+ FileUtils.mkdir_p(release_dir, :mode => 0777)
36
+ FileUtils.mkdir_p(env_dir, :mode => 0777)
37
+
38
+ rev = ""
39
+ STDIN.each do |line|
40
+ puts line
41
+ parts = line.split(/\s/)
42
+ next if parts[2] != "refs/heads/master"
43
+ rev = parts[1]
44
+ end
45
+
46
+ ENV['GIT_DIR'] = nil
47
+ ENV['PATH'] = "/usr/local/bin:#{ENV['PATH']}"
48
+
49
+ clone_dir = Dir.mktmpdir
50
+
51
+
52
+ sys("git clone #{git_dir} #{clone_dir}")
53
+
54
+ Dir.chdir clone_dir
55
+
56
+ sys("git reset --hard #{rev}")
57
+
58
+ sys("#{MASON} build #{clone_dir} -b #{buildpack_url} -o #{release_dir} -c #{cache_dir}")
59
+ sys("chmod -R a+r #{release_dir}")
60
+ sys("find #{release_dir} -type d -exec chmod a+x {} \\;")
61
+
62
+ if after_deploy != ""
63
+ Dir.chdir release_dir
64
+ sys("envdir #{env_dir} foreman run #{after_deploy}")
65
+ end
66
+
67
+ base_port = port.to_i - 200
68
+
69
+ launch_agent_contents = <<HERE
70
+ <?xml version="1.0" encoding="UTF-8"?>
71
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
72
+ <plist version="1.0">
73
+ <dict>
74
+ <key>KeepAlive</key>
75
+ <true/>
76
+ <key>Label</key>
77
+ <string>info.bugsplat.#{subdomain}</string>
78
+ <key>ProgramArguments</key>
79
+ <array>
80
+ <string>/usr/local/bin/envdir</string>
81
+ <string>#{BASE_ENV_DIR}/#{subdomain}</string>
82
+ <string>/usr/local/bin/foreman</string>
83
+ <string>start</string>
84
+ <string>-c</string>
85
+ <string>#{foreman}</string>
86
+ <string>-f</string>
87
+ <string>#{release_dir}/Procfile</string>
88
+ <string>-p</string>
89
+ <string>#{base_port}</string>
90
+ </array>
91
+ <key>RunAtLoad</key>
92
+ <true/>
93
+ <key>UserName</key>
94
+ <string>peter</string>
95
+ <key>WorkingDirectory</key>
96
+ <string>#{release_dir}</string>
97
+ </dict>
98
+ </plist>
99
+ HERE
100
+
101
+ puts "Installing LaunchDaemon"
102
+ File.open("#{release_dir}/info.bugsplat.#{subdomain}.plist", "w+") do |file|
103
+ file.write launch_agent_contents
104
+ end
105
+ sys("sudo /usr/local/bin/install_launchdaemon #{release_dir}/info.bugsplat.#{subdomain}.plist")
106
+
107
+ puts "Restarting Nginx"
108
+ File.open("#{BASE_NGINX_CONF}/info.bugsplat.#{subdomain}.conf", "w+") do |file|
109
+ file.write <<HERE
110
+ server {
111
+ server_name #{subdomain}.bugsplat.info;
112
+ listen 443;
113
+ ssl on;
114
+ location / {
115
+ proxy_pass http://localhost:#{port}/;
116
+ }
117
+ }
118
+
119
+ HERE
120
+ end
121
+
122
+ sys("sudo /usr/local/bin/restart_nginx")
data/bin/restart_nginx ADDED
@@ -0,0 +1,3 @@
1
+ #!/bin/bash
2
+
3
+ /usr/local/sbin/nginx -s reload
data/dokuen.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'dokuen'
3
+ s.version = '0.0.1'
4
+ s.date = '2012-05-19'
5
+
6
+ s.summary = 'A Personal Application Platform for Macs'
7
+ s.description = 'Like Heroku but Personal'
8
+
9
+ s.author = 'Pete Keen'
10
+ s.email = 'pete@bugsplat.info'
11
+
12
+ s.require_paths = %w< lib >
13
+
14
+ s.bindir = 'bin'
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- test/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.test_files = s.files.select {|path| path =~ /^test\/.*.rb/ }
21
+
22
+ s.add_development_dependency('rake')
23
+ s.add_dependency('thor')
24
+ s.add_dependency('mason')
25
+ s.add_dependency('foreman')
26
+
27
+ s.homepage = 'https://github.com/peterkeen/dokuen'
28
+ end
data/lib/dokuen/cli.rb ADDED
@@ -0,0 +1,244 @@
1
+ require 'rubygems'
2
+ require 'thor'
3
+ require 'fileutils'
4
+
5
+ module Dokuen
6
+ class Cli < Thor
7
+ include Thor::Actions
8
+
9
+ desc "setup", "Set up relevant things. Needs to be run as sudo."
10
+ def setup
11
+ raise "Must be run as root" unless Process.uid == 0
12
+ git_username = ask("What is your git username (usually git)?")
13
+ gitolite_src = ask("What is the path to your gitolite clone?")
14
+ say("Installing gitolite command")
15
+ create_file "#{gitolite_src}/src/commands/dokuen", <<HERE
16
+ #!/bin/sh
17
+ /usr/local/bin/dokuen $@
18
+ HERE
19
+ File.chmod(0755, "#{gitolite_src}/src/commands/dokuen")
20
+ say("Installing gitolite hook")
21
+ hook_path = "/Users/#{git_username}/.gitolite/hooks/common/pre-receive"
22
+ create_file(hook_path, <<'HERE'
23
+ #!/usr/bin/env ruby
24
+ hook = `git config hooks.pre`.chomp
25
+
26
+ rev = nil
27
+
28
+ STDIN.each do |line|
29
+ parts = line.split(/\s/)
30
+ next if parts[2] != "refs/heads/master"
31
+ rev = parts[1]
32
+ end
33
+
34
+ if hook != ""
35
+ name = File.basename(ENV['GL_REPO'])
36
+ cmd = "#{hook} #{name} #{rev}"
37
+ system(cmd) or raise "Error running pre-hook: #{cmd} returned #{$?}"
38
+ end
39
+ HERE
40
+ )
41
+ File.chmod(0755, hook_path)
42
+ say("Creating directories")
43
+ dirs = [
44
+ '/usr/local/var/dokuen/env',
45
+ '/usr/local/var/dokuen/env/_common',
46
+ '/usr/local/var/dokuen/log',
47
+ '/usr/local/var/dokuen/nginx',
48
+ '/usr/local/var/dokuen/build',
49
+ '/usr/local/var/dokuen/releases',
50
+ ]
51
+ FileUtils.mkdir_p(dirs, :mode => 0775)
52
+ FileUtils.chown(git_username, 'staff', dirs)
53
+
54
+ if yes?("Do you want to set up DNS?")
55
+ basename = ask("What is your DNS base domain? For example, if have a wildcard CNAME for *.example.com, this would be example.com.")
56
+ create_file("/usr/local/var/dokuen/env/_common/BASE_DOMAIN", basename)
57
+ end
58
+ git_hostname = `hostname`.chomp
59
+ if no?("Is #{git_hostname} the correct hostname for git remotes?")
60
+ git_hostname = ask("What hostname should we use instead?")
61
+ end
62
+ create_file("/usr/local/var/dokuen/env/_common/DOKUEN_GIT_SERVER", git_hostname)
63
+ create_file("/usr/local/var/dokuen/env/_common/DOKUEN_GIT_USER", git_username)
64
+
65
+ say(<<HERE
66
+
67
+ ==== IMPORTANT INSTRUCTIONS ====
68
+
69
+ In your .gitolite.rc file, in the COMMANDS section, add the following:
70
+
71
+ 'dokuen' => 1
72
+
73
+ In your gitolite.conf file, add the following:
74
+
75
+ repo apps/[a-zA-Z0-9].*
76
+ C = @all
77
+ RW+ = CREATOR
78
+ config hooks.pre = "/usr/local/bin/dokuen deploy"
79
+
80
+ In your nginx.conf, add the following to your http section:
81
+
82
+ include "/usr/local/var/dokuen/nginx/*.conf";
83
+
84
+ Run "sudo visudo" and add the following line:
85
+
86
+ git ALL=NOPASSWD: /usr/local/bin/dokuen
87
+
88
+ HERE
89
+ )
90
+
91
+ end
92
+
93
+ desc "create [APP]", "Create a new application."
94
+ def create(app="")
95
+ raise "app name required" if app.nil? || app == ""
96
+ read_env(app)
97
+ FileUtils.mkdir_p(Dokuen.dir("env", app))
98
+ FileUtils.mkdir_p(Dokuen.dir("release", app))
99
+ FileUtils.mkdir_p(Dokuen.dir("build", app))
100
+ puts "Created new application named #{app}"
101
+ puts "Git remote: #{Dokuen.base_clone_url}:apps/#{app}.git"
102
+ end
103
+
104
+ desc "restart_app [APP]", "Restart an existing app"
105
+ def restart_app(app="")
106
+ check_app(app)
107
+ read_env(app)
108
+ deploy = Dokuen::Deploy.new(app, '', ENV['DOKUEN_RELEASE_DIR'])
109
+ deploy.install_launch_daemon
110
+ deploy.install_nginx_conf
111
+ puts "App restarted"
112
+ end
113
+
114
+ desc "start_app [APP]", "Start an app", :hide => true
115
+ def start_app(app="")
116
+ check_app(app)
117
+ read_env(app)
118
+ ENV['PATH'] = "/usr/local/bin:#{ENV['PATH']}"
119
+ Dir.chdir(ENV['DOKUEN_RELEASE_DIR']) do
120
+ base_port = ENV['PORT'].to_i - 200
121
+ scale = ENV['DOKUEN_SCALE'].nil? ? "" : "-c #{ENV['DOKUEN_SCALE']}"
122
+ Dokuen.sys("foreman start #{scale} -p #{base_port}")
123
+ end
124
+ end
125
+
126
+ desc "scale [APP] [SCALE_SPEC]", "Scale an app to the given spec"
127
+ def scale(app="", scale_spec="")
128
+ check_app(app)
129
+ raise "scale spec required" if scale_spec == ""
130
+ read_env(app)
131
+ Dokuen.set_env(app, 'DOKUEN_SCALE', scale_spec)
132
+ restart_app(app)
133
+ puts "Scaled to #{scale_spec}"
134
+ end
135
+
136
+ desc "deploy [APP] [REV]", "Deploy an app for a given revision. Run within git pre-receive.", :hide => true
137
+ def deploy(app="", rev="")
138
+ check_app(app)
139
+ read_env(app)
140
+ Dokuen::Deploy.new(app, rev).run
141
+ puts "App #{app} deployed"
142
+ end
143
+
144
+ desc "restart_nginx", "Restart Nginx", :hide => true
145
+ def restart_nginx
146
+ raise "Must be run as root" unless Process.uid == 0
147
+ Dokuen.sys("/usr/local/sbin/nginx -s reload")
148
+ end
149
+
150
+ desc "install_launchdaemon [PATH]", "Install a launch daemon", :hide => true
151
+ def install_launchdaemon(path)
152
+ raise "Must be run as root" unless Process.uid == 0
153
+ basename = File.basename(path)
154
+ destpath = "/Library/LaunchDaemons/#{basename}"
155
+
156
+ if File.exists?(destpath)
157
+ Dokuen.sys("launchctl unload -wF #{destpath}")
158
+ end
159
+
160
+ Dokuen.sys("cp #{path} #{destpath}")
161
+ Dokuen.sys("launchctl load -wF #{destpath}")
162
+ end
163
+
164
+ desc "run_command [APP] [COMMAND]", "Run a command in the given app's environment"
165
+ def run_command(app="", command="")
166
+ check_app(app)
167
+ read_env(app)
168
+
169
+ Dir.chdir(ENV['DOKUEN_RELEASE_DIR']) do
170
+ Dokuen.sys("foreman run #{command}")
171
+ end
172
+ end
173
+
174
+ desc "config [APP] [set/delete]", "Add or remove config variables"
175
+ method_option :vars, :aliases => '-V', :desc => "Variables to set or remove", :type => :array
176
+ def config(app="", subcommand="")
177
+ check_app(app)
178
+ case subcommand
179
+ when "set"
180
+ set_vars(app)
181
+ restart_app(app)
182
+ when "delete"
183
+ delete_vars(app)
184
+ restart_app(app)
185
+ else
186
+ show_vars(app)
187
+ end
188
+ end
189
+
190
+ desc "install_buildpack [URL]", "Add a buildpack to the mason config"
191
+ def install_buildpack(url="")
192
+ raise "URL required" unless url != ""
193
+ Dokuen.sys("/usr/local/bin/mason buildpacks:install #{url}")
194
+ end
195
+
196
+ desc "remove_buildpack [NAME]", "Remove a buildpack from the mason config"
197
+ def remove_buildpack(name)
198
+ raise "Name required" unless name != ""
199
+ Dokuen.sys("/usr/local/bin/mason buildpacks:uninstall #{name}")
200
+ end
201
+
202
+ desc "buildpacks", "List the available buildpacks"
203
+ def buildpacks
204
+ Dokuen.sys("/usr/local/bin/mason buildpacks")
205
+ end
206
+
207
+ no_tasks do
208
+
209
+ def set_vars(app)
210
+ vars = options[:vars]
211
+ vars.each do |var|
212
+ key, val = var.split(/\=/)
213
+ Dokuen.set_env(app, key, val)
214
+ end
215
+ puts "Vars set"
216
+ end
217
+
218
+ def delete_vars(app)
219
+ vars = options[:vars]
220
+
221
+ vars.each do |var|
222
+ Dokuen.rm_env(app, var)
223
+ end
224
+ puts "Vars removed"
225
+ end
226
+
227
+ def show_vars(app)
228
+ read_env(app)
229
+ ENV.each do |key, val|
230
+ puts "#{key}=#{val}"
231
+ end
232
+ end
233
+
234
+ def read_env(app)
235
+ Dokuen.read_env("_common")
236
+ Dokuen.read_env(app)
237
+ end
238
+
239
+ def check_app(app)
240
+ Dokuen.app_exists?(app) or raise "App '#{app}' does not exist!"
241
+ end
242
+ end
243
+ end
244
+ end
@@ -0,0 +1,11 @@
1
+ require 'symboltable'
2
+
3
+ module Dockuen
4
+ class Config < SymbolTable
5
+
6
+ def instance
7
+ @instance ||= self.new do |c|
8
+ c.
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,173 @@
1
+ require 'tmpdir'
2
+ require 'fileutils'
3
+ require 'time'
4
+ require 'erb'
5
+
6
+ module Dokuen
7
+ class Deploy
8
+
9
+ def initialize(app, rev, release_dir=nil)
10
+ @app = app || app_name_from_env
11
+ @rev = rev
12
+ ENV['GIT_DIR'] = nil
13
+ ENV['PATH'] = "/usr/local/bin:#{ENV['PATH']}"
14
+ if release_dir
15
+ @release_dir = release_dir
16
+ end
17
+ end
18
+
19
+ def run
20
+ read_app_env
21
+ make_dirs
22
+ clone
23
+ build
24
+ install_launch_daemon
25
+ install_nginx_conf
26
+ end
27
+
28
+ def read_app_env
29
+ Dokuen.read_env('_common')
30
+ Dokuen.read_env(@app)
31
+ end
32
+
33
+ def make_dirs
34
+ FileUtils.mkdir_p([
35
+ env_dir,
36
+ release_dir,
37
+ cache_dir,
38
+ nginx_dir
39
+ ])
40
+ end
41
+
42
+ def clone
43
+ Dokuen.sys("git clone #{git_dir} #{clone_dir}")
44
+ Dir.chdir(clone_dir)
45
+ Dokuen.sys("git checkout #{@rev}")
46
+ end
47
+
48
+ def build
49
+ Dokuen.sys("mason build #{clone_dir} #{buildpack} -o #{release_dir} -c #{cache_dir}")
50
+ Dokuen.sys("chmod -R a+r #{release_dir}")
51
+ Dokuen.sys("find #{release_dir} -type d -exec chmod a+x {} \\;")
52
+ Dokuen.set_env(@app, 'DOKUEN_RELEASE_DIR', release_dir)
53
+
54
+ hook = ENV['DOKUEN_AFTER_BUILD']
55
+ if not hook.nil?
56
+ Dir.chdir release_dir do
57
+ Dokuen.sys("foreman run #{hook}")
58
+ end
59
+ end
60
+ end
61
+
62
+ def buildpack
63
+ if not ENV['BUILDPACK_URL'].nil?
64
+ "-b #{ENV['BUILDPACK_URL']}"
65
+ else
66
+ ""
67
+ end
68
+ end
69
+
70
+ def install_launch_daemon
71
+ t = ERB.new(launch_daemon_template)
72
+ plist_path = File.join(release_dir, "dokuen.#{@app}.plist")
73
+ File.open(plist_path, "w+") do |f|
74
+ f.write(t.result(binding))
75
+ end
76
+ Dokuen.sys("sudo /usr/local/bin/dokuen install_launchdaemon #{plist_path}")
77
+ end
78
+
79
+ def install_nginx_conf
80
+ t = ERB.new(nginx_template)
81
+ File.open(File.join(nginx_dir, "#{@app}.#{base_domain}.conf"), "w+") do |f|
82
+ f.write(t.result(binding))
83
+ end
84
+ Dokuen.sys("sudo /usr/local/bin/dokuen restart_nginx")
85
+ end
86
+
87
+ def base_domain
88
+ ENV['BASE_DOMAIN'] || 'dokuen'
89
+ end
90
+
91
+ def app_name_from_env
92
+ File.basename(ENV['GL_REPO']).gsub(/\.git$/, '')
93
+ end
94
+
95
+ def env_dir
96
+ Dokuen.dir("env", @app)
97
+ end
98
+
99
+ def clone_dir
100
+ @clone_dir ||= Dir.mktmpdir
101
+ end
102
+
103
+ def git_dir
104
+ @git_dir || Dir.getwd
105
+ end
106
+
107
+ def release_dir
108
+ @now = Time.now().utc().strftime("%Y%m%dT%H%M%S")
109
+ @release_dir ||= File.join(Dokuen.dir('release', @app), @now)
110
+ end
111
+
112
+ def cache_dir
113
+ Dokuen.dir('build', @app)
114
+ end
115
+
116
+ def nginx_dir
117
+ Dokuen.dir('nginx')
118
+ end
119
+
120
+ def server_port
121
+ ENV['USE_SSL'] ? "443" : "80"
122
+ end
123
+
124
+ def ssl_on
125
+ ENV['USE_SSL'] ? "on" : "off"
126
+ end
127
+
128
+ def launch_daemon_template
129
+ <<HERE
130
+ <?xml version="1.0" encoding="UTF-8"?>
131
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
132
+ <plist version="1.0">
133
+ <dict>
134
+ <key>KeepAlive</key>
135
+ <true/>
136
+ <key>Label</key>
137
+ <string>dokuen.<%= @app %></string>
138
+ <key>ProgramArguments</key>
139
+ <array>
140
+ <string>/usr/local/bin/dokuen</string>
141
+ <string>start_app</string>
142
+ <string><%= @app %></string>
143
+ </array>
144
+ <key>RunAtLoad</key>
145
+ <true/>
146
+ <key>UserName</key>
147
+ <string>peter</string>
148
+ <key>WorkingDirectory</key>
149
+ <string>/usr/local/var/dokuen</string>
150
+ <key>StandardOutPath</key>
151
+ <string>/usr/local/var/dokuen/log/<%= @app %>.log</string>
152
+ <key>StandardErrorPath</key>
153
+ <string>/usr/local/var/dokuen/log/<%= @app %>.log</string>
154
+ </dict>
155
+ </plist>
156
+ HERE
157
+ end
158
+
159
+ def nginx_template
160
+ <<HERE
161
+ server {
162
+ server_name <%= @app %>.<%= base_domain %>;
163
+ listen <%= server_port %>;
164
+ ssl <%= ssl_on %>;
165
+ location / {
166
+ proxy_pass http://localhost:<%= ENV['PORT'] %>/;
167
+ }
168
+ }
169
+ HERE
170
+ end
171
+ end
172
+ end
173
+
data/lib/dokuen.rb ADDED
@@ -0,0 +1,46 @@
1
+ require 'dokuen/cli'
2
+ require 'dokuen/deploy'
3
+
4
+ module Dokuen
5
+ def self.dir(name, app=nil)
6
+ parts = ["/usr/local/var/dokuen", name]
7
+
8
+ if not app.nil?
9
+ parts << app
10
+ end
11
+
12
+ File.join(parts)
13
+ end
14
+
15
+ def self.sys(command)
16
+ system(command) or raise "Error running #{command}"
17
+ end
18
+
19
+ def self.read_env(name)
20
+ env_dir = Dokuen.dir('env', name)
21
+ Dir.glob("#{env_dir}/*") do |var|
22
+ var_name = File.basename(var)
23
+ ENV[var_name] = File.open(var).read().chomp()
24
+ end
25
+ end
26
+
27
+ def self.set_env(name, key, value)
28
+ env_dir = Dokuen.dir('env', name)
29
+ File.open(File.join(env_dir, key), "w+") do |f|
30
+ f.write value
31
+ end
32
+ end
33
+
34
+ def self.rm_env(name, key)
35
+ env_dir = Dokuen.dir('env', name)
36
+ File.delete(File.join(env_dir, key))
37
+ end
38
+
39
+ def self.base_clone_url
40
+ "#{ENV['DOKUEN_GIT_USER']}@#{ENV['DOKUEN_GIT_SERVER']}"
41
+ end
42
+
43
+ def self.app_exists?(name)
44
+ File.exists?(Dokuen.dir('env', name))
45
+ end
46
+ end
metadata ADDED
@@ -0,0 +1,124 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dokuen
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Pete Keen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-05-19 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rake
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: thor
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: mason
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: foreman
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ! '>='
68
+ - !ruby/object:Gem::Version
69
+ version: '0'
70
+ type: :runtime
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ! '>='
76
+ - !ruby/object:Gem::Version
77
+ version: '0'
78
+ description: Like Heroku but Personal
79
+ email: pete@bugsplat.info
80
+ executables:
81
+ - dokuen
82
+ - install_launchdaemon
83
+ - pre-receive
84
+ - restart_nginx
85
+ extensions: []
86
+ extra_rdoc_files: []
87
+ files:
88
+ - Gemfile
89
+ - Gemfile.lock
90
+ - README.md
91
+ - bin/dokuen
92
+ - bin/install_launchdaemon
93
+ - bin/pre-receive
94
+ - bin/restart_nginx
95
+ - dokuen.gemspec
96
+ - lib/dokuen.rb
97
+ - lib/dokuen/cli.rb
98
+ - lib/dokuen/config.rb
99
+ - lib/dokuen/deploy.rb
100
+ homepage: https://github.com/peterkeen/dokuen
101
+ licenses: []
102
+ post_install_message:
103
+ rdoc_options: []
104
+ require_paths:
105
+ - lib
106
+ required_ruby_version: !ruby/object:Gem::Requirement
107
+ none: false
108
+ requirements:
109
+ - - ! '>='
110
+ - !ruby/object:Gem::Version
111
+ version: '0'
112
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ! '>='
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ requirements: []
119
+ rubyforge_project:
120
+ rubygems_version: 1.8.19
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: A Personal Application Platform for Macs
124
+ test_files: []