pandemonium 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md ADDED
@@ -0,0 +1,17 @@
1
+ # Pandemonium
2
+
3
+ ![](http://upload.wikimedia.org/wikipedia/commons/thumb/0/08/John_Martin_Le_Pandemonium_Louvre.JPG/640px-John_Martin_Le_Pandemonium_Louvre.JPG)
4
+
5
+ Everything started with this tweet:
6
+ https://twitter.com/poteland/status/339436974261805059
7
+
8
+ And then I tried to think the quickest (and probably dirtiest) way to do a
9
+ deploy app (aka Big Red Button)
10
+
11
+ ## Commands
12
+
13
+ ```bash
14
+ pandemonium add [repository] [deploy command]
15
+ pandemonium list
16
+ pandemonium run
17
+ ```
data/bin/pandemonium ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ $: << "lib"
3
+
4
+ require "clap"
5
+ require "pandemonium/cli"
6
+
7
+ Clap.run ARGV,
8
+ "run" => Pandemonium::CLI.method(:run),
9
+ "list" => Pandemonium::CLI.method(:list),
10
+ "add" => Pandemonium::CLI.method(:add)
11
+
12
+ # vim: ft=ruby
data/bin/worker.sh ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env bash
2
+
3
+ name="$1"
4
+ repo="$2"
5
+ deploy_script="$3"
6
+ branch=$4 || "master"
7
+ destination_folder="/tmp/$name"
8
+
9
+
10
+ if [ -d $destination_folder ]; then
11
+ cd $destination_folder
12
+ git pull
13
+ else
14
+ git clone $repo $destination_folder
15
+ fi
16
+
17
+ cd $destination_folder
18
+ $deploy_script
@@ -0,0 +1,11 @@
1
+ require "toml"
2
+ require "pandemonium/boss"
3
+ require "pandemonium/loader"
4
+
5
+ EM.kqueue = true
6
+ EventMachine.watch_file(Pandemonium::Loader::REPO_FILE, Pandemonium::Loader, config)
7
+ Pandemonium::ConfigLoader.new(config).load_repos
8
+
9
+ config["jobs"] = Hash.new do |h, k|
10
+ h[k] = Pandemonium::Boss.new(EM::Channel.new)
11
+ end
@@ -0,0 +1,52 @@
1
+ require "goliath/api"
2
+
3
+ EM.kqueue = true
4
+
5
+ module Pandemonium
6
+ class API < Goliath::API
7
+ use Goliath::Rack::Params
8
+ use Goliath::Rack::Render, ["json"]
9
+
10
+ def response(env)
11
+ case env["PATH_INFO"]
12
+ when "/"
13
+ puts env.repos
14
+ [200, {}, "Pandemonium"]
15
+ when "/attach"
16
+ project_name = env.params["project_name"]
17
+ boss = env.jobs[project_name]
18
+ channel = boss.channel
19
+
20
+ env.stream_close if !boss || !boss.running?
21
+
22
+ env["subscription"] = channel.subscribe do |message|
23
+ case message.type
24
+ when :data
25
+ env.stream_send(message.content)
26
+ when :exit_status
27
+ env.stream_send("Exit status: #{message.content}")
28
+ when :action
29
+ if message.content == :finish
30
+ channel.unsubscribe(env["subscription"])
31
+ env.stream_close
32
+ end
33
+ end
34
+ end
35
+
36
+ streaming_response(202, {"X-Stream" => "Pandemonium"})
37
+ when "/deploy"
38
+ project_name = env.params["project_name"]
39
+ project = env.repos[project_name]
40
+
41
+ boss = env.jobs[project_name]
42
+
43
+ if boss.running?
44
+ [200, {}, "Already deploying"]
45
+ else
46
+ boss.run_command project
47
+ [201, {}, "Deploying"]
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,16 @@
1
+ require "pandemonium/job"
2
+
3
+ module Pandemonium
4
+ Boss = Struct.new(:channel) do
5
+ def run_command(repo)
6
+ puts "Starting Job"
7
+
8
+ @working_on = Pandemonium::Job.new(repo, channel)
9
+ @working_on.run
10
+ end
11
+
12
+ def running?
13
+ !!@working_on && @working_on.running?
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,66 @@
1
+ require "goliath/runner"
2
+ require "toml"
3
+ require "uri"
4
+ require "pandemonium/api"
5
+ require "pandemonium/loader"
6
+
7
+ module Pandemonium
8
+ module CLI
9
+ class << self
10
+ def run
11
+ # There must be a prettier way to pass options to the runner
12
+ argv = ["-sv"]
13
+ argv << "-c"
14
+ argv << File.join(File.expand_path("../../..", __FILE__), "config/pandemonium.rb")
15
+
16
+ runner = Goliath::Runner.new(argv, nil)
17
+ api = Pandemonium::API
18
+
19
+ runner.api = api.new
20
+ runner.app = Goliath::Rack::Builder.build(api, runner.api)
21
+ runner.run
22
+ end
23
+
24
+ def help
25
+ end
26
+
27
+ def list
28
+ get_projects.each do |name, items|
29
+ if !items["last_status"].to_s.empty?
30
+ message = "#{name}: [#{items["last_run"]}] #{items["deploy_script"]}"
31
+ puts colorize(message, items["last_status"] == 0 ? 32 : 31)
32
+ else
33
+ puts "#{name}: #{items["deploy_script"]}"
34
+ end
35
+ end
36
+ end
37
+
38
+ def colorize(text, color_code)
39
+ "\e[#{color_code}m#{text}\e[0m"
40
+ end
41
+
42
+ def add(repo, script)
43
+ config = get_projects
44
+ project_name = File.basename(repo, ".git")
45
+ repo_name = escape_key(project_name)
46
+
47
+ config[repo_name] = {
48
+ repository: repo,
49
+ deploy_script: script,
50
+ last_run: "",
51
+ last_status: ""
52
+ }
53
+
54
+ File.open(Pandemonium::Loader::REPO_FILE, "w") << TOML.dump(config)
55
+ end
56
+
57
+ def get_projects
58
+ TOML.load_file(Pandemonium::Loader::REPO_FILE)
59
+ end
60
+
61
+ def escape_key(key)
62
+ key.tr("-", "_")
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,22 @@
1
+ require "pandemonium/usain_bolt"
2
+
3
+ module Pandemonium
4
+ Job = Struct.new(:repo, :output) do
5
+ def run
6
+ worker = File.join(File.expand_path("../../..", __FILE__), "bin/worker.sh")
7
+ command = "#{worker} '#{repo.name}' '#{repo.repository}' '#{repo.deploy_script}'"
8
+ puts "Unix, do your thing. Running #{command}"
9
+
10
+ @shell_command = EM.popen(command, Pandemonium::UsainBolt, self)
11
+ end
12
+
13
+ def running?
14
+ @shell_command.running?
15
+ end
16
+
17
+ def finish(exit_status)
18
+ repo.last_status = exit_status
19
+ repo.save
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,25 @@
1
+ require "pandemonium/repos"
2
+
3
+ module Pandemonium
4
+ module Loader
5
+ REPO_FILE = File.expand_path("~/.pandemonium").freeze
6
+
7
+ def initialize(config)
8
+ @config = config
9
+ end
10
+
11
+ def load_repos
12
+ puts "reloading repos"
13
+ repos = TOML.load_file(REPO_FILE)
14
+
15
+ @config["repos"] = Pandemonium::Repos.new
16
+ @config["repos"].load(repos)
17
+ end
18
+
19
+ alias file_modified load_repos
20
+ end
21
+
22
+ class ConfigLoader
23
+ include Loader
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module Pandemonium
2
+ Message = Struct.new(:type, :content)
3
+ end
@@ -0,0 +1,15 @@
1
+ module Pandemonium
2
+ Repo = Struct.new(:name, :repository, :deploy_script, :last_run, :last_status) do
3
+ def save
4
+ config = TOML.load_file(Pandemonium::Loader::REPO_FILE)
5
+ config[name].merge!({
6
+ "last_run" => Time.now,
7
+ "last_status" => last_status
8
+ })
9
+
10
+ toml_file = TOML.dump(config)
11
+
12
+ File.write(Pandemonium::Loader::REPO_FILE, toml_file)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,23 @@
1
+ require "pandemonium/repo"
2
+
3
+ module Pandemonium
4
+ class Repos
5
+ def initialize
6
+ @repos = []
7
+ end
8
+
9
+ def [](name)
10
+ @repos.select { |item| item.name == name }.first
11
+ end
12
+
13
+ def <<(repo)
14
+ @repos << repo
15
+ end
16
+
17
+ def load(array)
18
+ Array(array).each do |name, repo|
19
+ @repos << Repo.new(name, repo["repository"], repo["deploy_script"])
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,35 @@
1
+ require "pandemonium/message"
2
+
3
+ module Pandemonium
4
+ class UsainBolt < EM::Connection
5
+ def initialize(job)
6
+ @job = job
7
+ @output = job.output
8
+ @buffer = StringIO.new
9
+ end
10
+
11
+ def post_init
12
+ @running = true
13
+ puts "Running!"
14
+ end
15
+
16
+ def receive_data(data)
17
+ @output << Pandemonium::Message.new(:data, data)
18
+ @buffer << data
19
+
20
+ puts "Command output: #{data}"
21
+ end
22
+
23
+ def unbind
24
+ @running = false
25
+ @buffer = nil
26
+
27
+ @job.finish(get_status.exitstatus)
28
+
29
+ @output << Pandemonium::Message.new(:exit_status, get_status.exitstatus)
30
+ @output << Pandemonium::Message.new(:action, :finish)
31
+ end
32
+
33
+ def running?; @running; end
34
+ end
35
+ end
@@ -0,0 +1,16 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = "pandemonium"
3
+ s.executables = ["pandemonium"]
4
+ s.version = "0.0.1"
5
+ s.summary = "Pandemonium the deployer"
6
+ s.description = "Pandemonium is an app to run deployment instructions"
7
+ s.authors = ["elcuervo"]
8
+ s.email = ["yo@brunoaguirre.com"]
9
+ s.homepage = "http://github.com/elcuervo/pandemonium"
10
+ s.files = `git ls-files`.split("\n")
11
+ s.test_files = `git ls-files test`.split("\n")
12
+
13
+ s.add_dependency("goliath", "~> 1.0.2")
14
+ s.add_dependency("clap", "~> 1.0.0")
15
+ s.add_dependency("toml-rb", "~> 0.1.3")
16
+ end
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pandemonium
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - elcuervo
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-06-10 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: goliath
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 1.0.2
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.2
30
+ - !ruby/object:Gem::Dependency
31
+ name: clap
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 1.0.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: 1.0.0
46
+ - !ruby/object:Gem::Dependency
47
+ name: toml-rb
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.3
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.1.3
62
+ description: Pandemonium is an app to run deployment instructions
63
+ email:
64
+ - yo@brunoaguirre.com
65
+ executables:
66
+ - pandemonium
67
+ extensions: []
68
+ extra_rdoc_files: []
69
+ files:
70
+ - README.md
71
+ - bin/pandemonium
72
+ - bin/worker.sh
73
+ - config/pandemonium.rb
74
+ - lib/pandemonium/api.rb
75
+ - lib/pandemonium/boss.rb
76
+ - lib/pandemonium/cli.rb
77
+ - lib/pandemonium/job.rb
78
+ - lib/pandemonium/loader.rb
79
+ - lib/pandemonium/message.rb
80
+ - lib/pandemonium/repo.rb
81
+ - lib/pandemonium/repos.rb
82
+ - lib/pandemonium/usain_bolt.rb
83
+ - pandemonium.gemspec
84
+ homepage: http://github.com/elcuervo/pandemonium
85
+ licenses: []
86
+ post_install_message:
87
+ rdoc_options: []
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ none: false
92
+ requirements:
93
+ - - ! '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubyforge_project:
104
+ rubygems_version: 1.8.23
105
+ signing_key:
106
+ specification_version: 3
107
+ summary: Pandemonium the deployer
108
+ test_files: []