Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 174 lines (139 sloc) 5.204 kb
60d4eee David Dollar initial
ddollar authored
1 require "digest/sha1"
2 require "net/http/post/multipart"
3 require "rest_client"
4 require "thor"
5 require "tmpdir"
6 require "uri"
7 require "vulcan"
8 require "yaml"
9
10 class Vulcan::CLI < Thor
11
548e28e David Dollar remove COMMAND from banner
ddollar authored
12 desc "build", <<-DESC
60d4eee David Dollar initial
ddollar authored
13 build a piece of software for the heroku cloud using COMMANd as a build command
14 if no COMMAND is specified, a sensible default will be chosen for you
15
16 DESC
17
18 method_option :command, :aliases => "-c", :desc => "the command to run for compilation"
19 method_option :name, :aliases => "-n", :desc => "the name of the library (defaults ot the directory name)"
20 method_option :output, :aliases => "-o", :desc => "output build artifacts to this file"
21 method_option :prefix, :aliases => "-p", :desc => "the build/install --prefix of the software"
22 method_option :source, :aliases => "-s", :desc => "the source directory to build from"
23 method_option :verbose, :aliases => "-v", :desc => "show the full build output", :type => :boolean
24
25 def build
26 app = read_config[:app] || "need a server first, use vulcan create"
27
00aced6 David Dollar tweak readme
ddollar authored
28 source = options[:source] || Dir.pwd
29 name = options[:name] || File.basename(source)
60d4eee David Dollar initial
ddollar authored
30 output = options[:output] || "/tmp/#{name}.tgz"
31 prefix = options[:prefix] || "/app/vendor/#{name}"
d1667bf David Dollar put command in the right place
ddollar authored
32 command = options[:command] || "./configure --prefix #{prefix} && make install"
60d4eee David Dollar initial
ddollar authored
33 server = URI.parse(ENV["MAKE_SERVER"] || "http://#{app}.herokuapp.com")
34
35 Dir.mktmpdir do |dir|
36 puts ">> Packaging local directory"
37 %x{ cd #{source} && tar czvf #{dir}/input.tgz . 2>&1 }
38
39 puts ">> Uploading code for build"
40 File.open("#{dir}/input.tgz", "r") do |input|
41 request = Net::HTTP::Post::Multipart.new "/make",
42 "code" => UploadIO.new(input, "application/octet-stream", "input.tgz"),
43 "command" => command,
00aced6 David Dollar tweak readme
ddollar authored
44 "prefix" => prefix,
45 "secret" => config[:secret]
60d4eee David Dollar initial
ddollar authored
46
47 puts ">> Building with: #{command}"
48 response = Net::HTTP.start(server.host, server.port) do |http|
49 http.request(request) do |response|
50 response.read_body do |chunk|
51 print chunk if options[:verbose]
52 end
53 end
54 end
55
56 error "Unknown error, no build output given" unless response["X-Make-Id"]
57
58 puts ">> Downloading build artifacts to: #{output}"
59
635f6c0 Tim Carey-Smith Print the URL where the output is available
halorgium authored
60 output_url = "#{server}/output/#{response["X-Make-Id"]}"
61 puts " (available at #{output_url})"
62
60d4eee David Dollar initial
ddollar authored
63 File.open(output, "w") do |output|
64 begin
635f6c0 Tim Carey-Smith Print the URL where the output is available
halorgium authored
65 output.print RestClient.get(output_url)
60d4eee David Dollar initial
ddollar authored
66 rescue Exception => ex
67 puts ex.inspect
68 end
69 end
70 end
71 end
72 rescue Errno::EPIPE
73 error "Could not connect to build server: #{server}"
74 end
75
76 desc "create APP_NAME", <<-DESC
77 create a build server on Heroku
78
79 DESC
80
81 def create(name)
82 secret = Digest::SHA1.hexdigest("--#{rand(10000)}--#{Time.now}--")
83
84 Dir.mktmpdir do |dir|
85 Dir.chdir(dir) do
86 system "env BUNDLE_GEMFILE= heroku create #{name} -s cedar"
87 end
88 end
d1d38e1 Terence Lee it's :app not :ap
hone authored
89 write_config :app => name, :host => "#{name}.herokuapp.com", :secret => secret
60d4eee David Dollar initial
ddollar authored
90 update
91 end
92
93
94 desc "update", <<-DESC
95 update the build server
96
97 DESC
98
99 def update
100 error "no apyet, create first" unless config[:app]
101
102 FileUtils.mkdir_p File.expand_path("~/.heroku/plugins/heroku-credentials")
103
104 File.open(File.expand_path("~/.heroku/plugins/heroku-credentials/init.rb"), "w") do |file|
105 file.puts <<-CONTENTS
378efdd David Dollar better api key getting
ddollar authored
106 class Heroku::Auth
107 def self.api_key
108 Heroku::Client.auth(user, password, host)["api_key"]
109 end
110 end
60d4eee David Dollar initial
ddollar authored
111 class Heroku::Command::Credentials < Heroku::Command::Base
112 def index
378efdd David Dollar better api key getting
ddollar authored
113 puts Heroku::Auth.api_key
60d4eee David Dollar initial
ddollar authored
114 end
115 end
116 CONTENTS
117 end
118
119 Dir.mktmpdir do |dir|
120 Dir.chdir(dir) do
1657ce7 David Dollar detect invalid api keys
ddollar authored
121 api_key = %x{ env BUNDLE_GEMFILE= heroku credentials 2>&1 }.chomp
122 error "invalid api key detected, try running `heroku credentials`" if api_key =~ / /
60d4eee David Dollar initial
ddollar authored
123
124 system "git init"
125 system "git remote add heroku git@heroku.com:#{config[:app]}.git"
126 FileUtils.cp_r "#{server_path}/.", "."
127 File.open(".gitignore", "w") do |file|
128 file.puts ".env"
129 file.puts "node_modules"
130 end
e89ac09 David Dollar silent git
ddollar authored
131 system "git add . >/dev/null"
132 system "git commit -m commit >/dev/null"
60d4eee David Dollar initial
ddollar authored
133 system "git push heroku -f master"
134
135 %x{ env BUNDLE_GEMFILE= heroku config:add SECRET=#{config[:secret]} SPAWN_ENV=heroku HEROKU_APP=#{config[:app]} HEROKU_API_KEY=#{api_key} 2>&1 }
136 %x{ env BUNDLE_GEMFILE= heroku addons:add cloudant:oxygen }
137 end
138 end
139 end
140
141 private
142
143 def config_file
144 File.expand_path("~/.vulcan")
145 end
146
147 def config
148 read_config
149 end
150
151 def read_config
152 return {} unless File.exists?(config_file)
153 config = YAML.load_file(config_file)
154 config.is_a?(Hash) ? config : {}
155 end
156
157 def write_config(config)
158 full_config = read_config.merge(config)
159 File.open(config_file, "w") do |file|
160 file.puts YAML.dump(full_config)
161 end
162 end
163
164 def error(message)
165 puts "!! #{message}"
166 exit 1
167 end
168
169 def server_path
170 File.expand_path("../../../server", __FILE__)
171 end
172
173 end
Something went wrong with that request. Please try again.