greenhouse 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/bin/greenhouse +9 -0
  3. data/lib/greenhouse/cli.rb +88 -0
  4. data/lib/greenhouse/commands/add.rb +32 -0
  5. data/lib/greenhouse/commands/command.rb +88 -0
  6. data/lib/greenhouse/commands/configure.rb +9 -0
  7. data/lib/greenhouse/commands/help.rb +45 -0
  8. data/lib/greenhouse/commands/init.rb +93 -0
  9. data/lib/greenhouse/commands/launch.rb +113 -0
  10. data/lib/greenhouse/commands/new.rb +42 -0
  11. data/lib/greenhouse/commands/pull.rb +45 -0
  12. data/lib/greenhouse/commands/purge.rb +91 -0
  13. data/lib/greenhouse/commands/push.rb +45 -0
  14. data/lib/greenhouse/commands/remove.rb +32 -0
  15. data/lib/greenhouse/commands/start.rb +21 -0
  16. data/lib/greenhouse/commands/status.rb +50 -0
  17. data/lib/greenhouse/commands/sync.rb +42 -0
  18. data/lib/greenhouse/commands.rb +32 -0
  19. data/lib/greenhouse/projects/application.rb +19 -0
  20. data/lib/greenhouse/projects/collection.rb +23 -0
  21. data/lib/greenhouse/projects/engine.rb +6 -0
  22. data/lib/greenhouse/projects/gem.rb +6 -0
  23. data/lib/greenhouse/projects/project.rb +77 -0
  24. data/lib/greenhouse/projects/repository.rb +197 -0
  25. data/lib/greenhouse/projects.rb +86 -0
  26. data/lib/greenhouse/resources/dotenv_file.rb +69 -0
  27. data/lib/greenhouse/resources/file_resource.rb +50 -0
  28. data/lib/greenhouse/resources/ignore_file.rb +115 -0
  29. data/lib/greenhouse/resources/procfile.rb +144 -0
  30. data/lib/greenhouse/resources/projects_file.rb +44 -0
  31. data/lib/greenhouse/resources.rb +10 -0
  32. data/lib/greenhouse/scripts/argument.rb +36 -0
  33. data/lib/greenhouse/scripts/arguments.rb +28 -0
  34. data/lib/greenhouse/scripts/invalid_argument.rb +6 -0
  35. data/lib/greenhouse/scripts/script.rb +109 -0
  36. data/lib/greenhouse/scripts.rb +4 -0
  37. data/lib/greenhouse/tasks/add_project.rb +57 -0
  38. data/lib/greenhouse/tasks/generate_procfile.rb +22 -0
  39. data/lib/greenhouse/tasks/project_status.rb +37 -0
  40. data/lib/greenhouse/tasks/project_task.rb +363 -0
  41. data/lib/greenhouse/tasks/pull_project.rb +14 -0
  42. data/lib/greenhouse/tasks/purge_project.rb +13 -0
  43. data/lib/greenhouse/tasks/push_project.rb +14 -0
  44. data/lib/greenhouse/tasks/remove_greenhouse_files.rb +58 -0
  45. data/lib/greenhouse/tasks/remove_project.rb +15 -0
  46. data/lib/greenhouse/tasks/sync_project.rb +19 -0
  47. data/lib/greenhouse/tasks/task.rb +25 -0
  48. data/lib/greenhouse/tasks.rb +20 -0
  49. data/lib/greenhouse/version.rb +20 -0
  50. data/lib/greenhouse.rb +12 -0
  51. metadata +165 -0
@@ -0,0 +1,69 @@
1
+ module Greenhouse
2
+ module Resources
3
+ class DotenvFile
4
+ include FileResource
5
+
6
+ attr_reader :config
7
+
8
+ class ConfigVars < Hash
9
+ def format_key(key)
10
+ key.to_s.gsub(/[^a-z\d_]+/i, "_").upcase
11
+ end
12
+
13
+ def [](key)
14
+ super(format_key(key))
15
+ end
16
+
17
+ def []=(key, value)
18
+ super(format_key(key), value)
19
+ end
20
+
21
+ def initialize(hash={})
22
+ hash.each { |k,v| self[k] = v }
23
+ end
24
+ end
25
+
26
+ def config=(hash)
27
+ @config = ConfigVars.new(hash)
28
+ end
29
+
30
+ def reload
31
+ @config = ConfigVars.new
32
+ return @config unless exists?
33
+ # pulled this straight from Dotenv, too bad there's no simple Dotenv.parse method in the gem
34
+ read do |line|
35
+ if line =~ /\A(?:export\s+)?([\w\.]+)(?:=|: ?)(.*)\z/
36
+ key = $1
37
+ case val = $2
38
+ # Remove single quotes
39
+ when /\A'(.*)'\z/ then @config[key] = $1
40
+ # Remove double quotes and unescape string preserving newline characters
41
+ when /\A"(.*)"\z/ then @config[key] = $1.gsub('\n', "\n").gsub(/\\(.)/, '\1')
42
+ else @config[key] = val
43
+ end
44
+ end
45
+ end
46
+ @config
47
+ end
48
+
49
+ def write
50
+ open("w") do |f|
51
+ @config.each do |key,val|
52
+ f.write("#{key}=#{val}\n")
53
+ end
54
+ end
55
+ end
56
+
57
+ def unlink
58
+ super
59
+ reload
60
+ end
61
+
62
+ def initialize(path)
63
+ super
64
+ reload
65
+ end
66
+
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,50 @@
1
+ module Greenhouse
2
+ module Resources
3
+ module FileResource
4
+ def self.included(base)
5
+ base.send :include, InstanceMethods
6
+ end
7
+
8
+ module ClassMethods
9
+ end
10
+
11
+ module InstanceMethods
12
+ def self.included(base)
13
+ base.send :attr_reader, :path
14
+ end
15
+
16
+ def exists?
17
+ File.exists?(path)
18
+ end
19
+
20
+ def open(mode, &block)
21
+ File.open(path, mode, &block)
22
+ end
23
+
24
+ def lines(reload=false)
25
+ @lines = nil if reload
26
+ @lines ||= [] unless exists?
27
+ @lines ||= File.read(path).split("\n")
28
+ @lines
29
+ end
30
+
31
+ def read(&block)
32
+ lines(true).each_with_index(&block)
33
+ end
34
+
35
+ def unlink
36
+ File.unlink(path) if exists?
37
+ end
38
+
39
+ def chdir(&block)
40
+ Dir.chdir(File.expand_path("../", path), &block)
41
+ end
42
+
43
+ def initialize(path)
44
+ @path = File.expand_path(path)
45
+ end
46
+ end
47
+
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,115 @@
1
+ module Greenhouse
2
+ module Resources
3
+ class IgnoreFile
4
+ include FileResource
5
+
6
+ class IgnoredFiles < Array
7
+
8
+ def unshift(file)
9
+ if !file.is_a?(IgnoredFile)
10
+ file = IgnoredFile.new(file, @ignore_file.lines.length)
11
+ end
12
+ super(file)
13
+ @ignore_file.lines[file.line] = file.to_s
14
+ end
15
+
16
+ def push(file)
17
+ if !file.is_a?(IgnoredFile)
18
+ file = IgnoredFile.new(file, @ignore_file.lines.length)
19
+ end
20
+ super(file)
21
+ @ignore_file.lines[file.line] = file.to_s
22
+ end
23
+
24
+ def <<(file)
25
+ push(file)
26
+ end
27
+
28
+ def []=(index,file)
29
+ delete_at index if index < length
30
+ file = IgnoredFile.new(file, @ignore_file.lines.length) if !file.is_a?(IgnoredFile)
31
+ super(index,file)
32
+ @ignore_file.lines[file.line] = file.to_s
33
+ end
34
+
35
+ def delete(filename)
36
+ # TODO delete any comments immediately preceding the filename
37
+ deleted = super(select { |f| f.file == filename}.first)
38
+ @ignore_file.ignored.each do |ignored|
39
+ next if ignored.line < deleted.line
40
+ ignored.line -= 1
41
+ end
42
+ line = @ignore_file.lines.slice!(deleted.line,1)
43
+ deleted
44
+ end
45
+
46
+ def delete_at(index)
47
+ delete self[index].file
48
+ end
49
+
50
+ def delete_if(&block)
51
+ select(&block).map { |ignored| delete ignored.file }
52
+ end
53
+
54
+ def keep_if(&block)
55
+ kept = select(&block)
56
+ clone.select { |ignored| !kept.map(&:file).include?(ignored.file) }.map { |ignored| delete ignored.file }
57
+ end
58
+
59
+ def initialize(ignore_file)
60
+ @ignore_file = ignore_file
61
+ super()
62
+ end
63
+ end
64
+
65
+ class IgnoredFile
66
+ attr_accessor :file, :line
67
+
68
+ def to_s
69
+ @file.to_s
70
+ end
71
+
72
+ def inspect
73
+ to_s
74
+ end
75
+
76
+ def initialize(file, line)
77
+ @file = file
78
+ @line = line
79
+ end
80
+ end
81
+
82
+ attr_accessor :ignored
83
+
84
+ def write
85
+ ignored.each { |ignored| lines[ignored.line] = ignored.to_s}
86
+ open('w') do |ifile|
87
+ lines.each do |line|
88
+ ifile.write "#{line}\n"
89
+ end
90
+ end
91
+ end
92
+ alias_method :save, :write
93
+
94
+ def reload
95
+ @ignored = IgnoredFiles.new(self)
96
+ return @ignored unless exists?
97
+ read do |line,l|
98
+ next if line.strip[0] == "#" || line.strip.empty?
99
+ @ignored << IgnoredFile.new(line,l)
100
+ end
101
+ @ignored
102
+ end
103
+
104
+ def unlink
105
+ super
106
+ reload
107
+ end
108
+
109
+ def initialize(path)
110
+ super
111
+ reload
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,144 @@
1
+ module Greenhouse
2
+ module Resources
3
+ class Procfile
4
+ include FileResource
5
+
6
+ class Processes < Hash
7
+ def [](key)
8
+ super(key.to_s)
9
+ end
10
+
11
+ def []=(key, value)
12
+ if value.is_a?(Process)
13
+ super(key.to_s, value)
14
+ else
15
+ parr = value.strip.split(":")
16
+ key = parr.slice!(0)
17
+ command = parr.join(":").strip
18
+ # TODO might need to rework this line index, won't account for blank/comment lines at the end of the file
19
+ value = Process.new(key, command, (values.map(&:line).sort.last || -1) + 1)
20
+ super(key.to_s, value)
21
+ end
22
+ @procfile.lines[value.line] = value.to_s
23
+ end
24
+
25
+ def delete(key)
26
+ del = super(key)
27
+ @procfile.processes.each do |key,process|
28
+ next if process.line < del.line
29
+ process.line -= 1
30
+ end
31
+ line = @procfile.lines.slice!(del.line,1)
32
+ del
33
+ end
34
+
35
+ def delete_if(&block)
36
+ select(&block).keys.map { |key| delete key }
37
+ end
38
+
39
+ def keep_if(&block)
40
+ kept = select(&block)
41
+ clone.select { |key,process| !kept.keys.include?(key) }.keys.map { |key| delete key }
42
+ end
43
+
44
+ def initialize(procfile)
45
+ @procfile = procfile
46
+ end
47
+ end
48
+
49
+ class Process
50
+ attr_accessor :key, :command, :line
51
+
52
+ def enabled?
53
+ !@disabled
54
+ end
55
+
56
+ def disabled?
57
+ @disabled
58
+ end
59
+
60
+ def enable
61
+ @disabled = false
62
+ end
63
+
64
+ def disable
65
+ @disabled = true
66
+ end
67
+
68
+ def to_s
69
+ "#{"#" if disabled?}#{key}: #{command}"
70
+ end
71
+
72
+ def inspect
73
+ to_s
74
+ end
75
+
76
+ def initialize(key, command, line)
77
+ @line = line
78
+ @disabled = key.strip[0] == "#"
79
+ @key = key.gsub(/\A#+/, "")
80
+ @command = command
81
+ end
82
+ end
83
+
84
+ def disabled(refresh=false)
85
+ return @processes.select { |key,process| process.disabled? } unless refresh || @processes.nil? || @processes.empty?
86
+ reload.select { |key,process| process.disabled? }
87
+ end
88
+
89
+ def enabled(refresh=false)
90
+ return @processes.select { |key,process| process.enabled? } unless refresh || @processes.nil? || @processes.empty?
91
+ reload.select { |key,process| process.enabled? }
92
+ end
93
+
94
+ def processes(refresh=false)
95
+ return @processes unless refresh || @processes.nil? || @processes.empty?
96
+ reload
97
+ end
98
+
99
+ def process_exists?(key)
100
+ processes.keys.include?(key.to_s)
101
+ end
102
+
103
+ def process(key)
104
+ processes.values.select { |p| p.key.to_s == key.to_s }.first
105
+ end
106
+
107
+ def write
108
+ processes.values.each { |process| lines[process.line] = process.to_s}
109
+ open('w') do |pfile|
110
+ lines.each do |line|
111
+ pfile.write "#{line}\n"
112
+ end
113
+ end
114
+ reload
115
+ end
116
+ alias_method :save, :write
117
+
118
+ def reload
119
+ @processes = Processes.new(self)
120
+ return @processes unless exists?
121
+
122
+ read do |line,l|
123
+ if line.match(/\A[#]*[a-z0-9_]+:\s*.*\Z/)
124
+ parr = line.strip.split(":")
125
+ key = parr.slice!(0)
126
+ command = parr.join(":").strip
127
+ process = Process.new(key, command, l)
128
+ @processes[process.key] = process
129
+ end
130
+ end
131
+ @processes
132
+ end
133
+
134
+ def unlink
135
+ super
136
+ reload
137
+ end
138
+
139
+ def initialize(path)
140
+ super
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,44 @@
1
+ require 'yaml'
2
+
3
+ module Greenhouse
4
+ module Resources
5
+ class ProjectsFile
6
+ include FileResource
7
+
8
+ def projects(refresh=false)
9
+ return @projects unless refresh || @projects.nil? || @projects.empty?
10
+ reload
11
+ end
12
+
13
+ def write
14
+ open('w') do |pfile|
15
+ #pfile.write @projects.to_yaml.gsub("!ruby/symbol ", ":").sub("---","").split("\n").map(&:rstrip).join("\n").strip
16
+ @projects.each do |name,project|
17
+ pfile.write "#{name}:\n"
18
+ project.each do |key,val|
19
+ pfile.write " #{key}: #{val.to_s}\n"
20
+ end
21
+ end
22
+ end
23
+ end
24
+ alias_method :save, :write
25
+
26
+ def reload
27
+ @projects = {}
28
+ return @projects unless exists?
29
+ @projects = YAML::load_file(path)
30
+ @projects ||= {}
31
+ @projects
32
+ end
33
+
34
+ def unlink
35
+ super
36
+ reload
37
+ end
38
+
39
+ def initialize(path)
40
+ super
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,10 @@
1
+ module Greenhouse
2
+ module Resources
3
+ end
4
+ end
5
+
6
+ require 'greenhouse/resources/file_resource'
7
+ require 'greenhouse/resources/procfile'
8
+ require 'greenhouse/resources/projects_file'
9
+ require 'greenhouse/resources/ignore_file'
10
+ require 'greenhouse/resources/dotenv_file'
@@ -0,0 +1,36 @@
1
+ module Greenhouse
2
+ module Scripts
3
+ class Argument
4
+ attr_reader :value, :valid, :summary
5
+
6
+ def value=(val)
7
+ raise "Invalid value for `#{key}` flag: '#{val}'" if (!@valid.nil? && !@valid.include?(val)) && (!val.nil? && !val.empty?)
8
+ @value = val
9
+ end
10
+
11
+ def key
12
+ @keys.is_a?(Array) ? @keys[0] : @keys
13
+ end
14
+
15
+ def keys
16
+ @keys.is_a?(Array) ? @keys : [@keys]
17
+ end
18
+
19
+ protected
20
+
21
+ def initialize(keys, *args)
22
+ @keys = (keys.is_a?(String) && keys.match(/,?\s/) ? keys.gsub(/,?\s+/, " ").split(" ") : keys)
23
+
24
+ val = args.slice!(0) if %w(String Symbol Integer).include?(args[0].class.name)
25
+
26
+ if args.length > 0 && args[0].is_a?(Hash)
27
+ opts = args.slice!(0)
28
+ @valid = (opts[:valid].is_a?(Array) ? opts[:valid].map(&:to_s) : opts[:valid].to_s) if opts.has_key?(:valid)
29
+ @summary = opts[:summary] if opts.has_key?(:summary)
30
+ end
31
+
32
+ self.value = val
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,28 @@
1
+ module Greenhouse
2
+ module Scripts
3
+ class Arguments < Array
4
+
5
+ def to_s
6
+ map do |arg|
7
+ #if arg.valid.nil? || arg.valid.empty?
8
+ "[#{arg.keys.join(", ")}]"
9
+ #else
10
+ # "[#{arg.keys.join(", ")} = (#{arg.valid.join("|")})]"
11
+ #end
12
+ end.join(" ")
13
+ end
14
+
15
+ def to_help
16
+ map do |arg|
17
+ " #{"%-#{sort { |a,b| a.keys.join(", ").length <=> b.keys.join(", ").length }.last.keys.join(", ").length + 2}s" % arg.keys.join(", ")}# #{arg.summary}"
18
+ end.join("\n")
19
+ end
20
+
21
+ protected
22
+
23
+ def initialize
24
+ super
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,6 @@
1
+ module Greenhouse
2
+ module Scripts
3
+ class InvalidArgument < Exception
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,109 @@
1
+ module Greenhouse
2
+ module Scripts
3
+ module Script
4
+ def self.included(base)
5
+ base.send :extend, ClassMethods
6
+ base.send :include, InstanceMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def self.extended(base)
11
+ end
12
+
13
+ def run
14
+ @script ||= new
15
+ raise "You have not defined a `run` method for your script." unless @script.respond_to?(:run)
16
+ @script.run
17
+ end
18
+
19
+ def validate_arguments(val=nil)
20
+ return validate_arguments? if val.nil?
21
+ @validate_arguments = val
22
+ end
23
+
24
+ def validate_arguments?
25
+ @validate_arguments = true if @validate_arguments.nil?
26
+ @validate_arguments
27
+ end
28
+
29
+ def valid_argument(arg)
30
+ @valid_args ||= Arguments.new
31
+ if arg.is_a?(Argument)
32
+ @valid_args << arg
33
+ elsif arg.is_a?(Hash)
34
+ @valid_args << Argument.new(arg.keys.first.to_s, arg.values.first)
35
+ elsif arg.is_a?(Array)
36
+ @valid_args << Argument.new(arg[0].to_s, (arg.length > 1 ? arg[1] : []))
37
+ else
38
+ @valid_args << Argument.new(arg.to_s)
39
+ end
40
+ @valid_args.last
41
+ end
42
+
43
+ def valid_arguments(*args)
44
+ @valid_args ||= Arguments.new
45
+ return @valid_args if args.empty?
46
+
47
+ args.each { |arg| valid_argument(arg) }
48
+ @valid_args
49
+ end
50
+
51
+ def project_argument(proj)
52
+ @valid_projs ||= Arguments.new
53
+ if proj.is_a?(Argument)
54
+ @valid_projs << proj
55
+ elsif proj.is_a?(Hash)
56
+ @valid_projs << Argument.new(proj.keys.first.to_s, proj.values.first)
57
+ elsif proj.is_a?(Array)
58
+ @valid_projs << Argument.new(proj[0].to_s, (proj.length > 1 ? proj[1] : []))
59
+ else
60
+ @valid_projs << Argument.new(proj.to_s)
61
+ end
62
+ @valid_projs.last
63
+ end
64
+
65
+ def project_arguments(*projs)
66
+ @valid_projs ||= Arguments.new
67
+ return @valid_projs if projs.empty?
68
+
69
+ projs.each { |proj| project_argument(proj) }
70
+ @valid_projs
71
+ end
72
+
73
+ def arguments(*args)
74
+ @arguments ||= nil
75
+ return @arguments unless @arguments.nil?
76
+ @arguments = Arguments.new
77
+ args.each_with_index do |arg,a|
78
+ argarr = arg.split("=")
79
+ argkey = argarr.slice!(0)
80
+
81
+ if !valid_arguments.concat(project_arguments).map(&:keys).any? { |keys| keys.include?(argkey) } && !arg.match(/\A(-)+[a-z0-9\-]=?.*\Z/i) && (a > 0 && args[a-1].match(/\A(-)+[a-z0-9\-]=?.*\Z/i)) && !@arguments.empty?
82
+ @arguments.last.value = arg
83
+ next
84
+ end
85
+
86
+ if validate_arguments?
87
+ raise InvalidArgument, "Invalid Argument: #{arg}" unless valid_arguments.concat(project_arguments).map(&:keys).any? { |keys| keys.include?(argkey) }
88
+ @arguments << valid_arguments.concat(project_arguments).select { |varg| varg.keys.include?(argkey) }.first
89
+ else
90
+ valid_arg = valid_arguments.concat(project_arguments).select { |varg| varg.keys.include?(argkey) }.first
91
+ @arguments << (valid_arg || Argument.new(argkey))
92
+ end
93
+ @arguments.last.value = argarr.join("=") unless argarr.empty?
94
+ end
95
+ @arguments
96
+ end
97
+ end
98
+
99
+ module InstanceMethods
100
+ %w(arguments valid_arguments project_arguments).each do |method|
101
+ define_method method do |*args|
102
+ self.class.send method, *args
103
+ end
104
+ end
105
+ end
106
+
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,4 @@
1
+ require 'greenhouse/scripts/invalid_argument'
2
+ require 'greenhouse/scripts/argument'
3
+ require 'greenhouse/scripts/arguments'
4
+ require 'greenhouse/scripts/script'
@@ -0,0 +1,57 @@
1
+ module Greenhouse
2
+ module Tasks
3
+ class AddProject
4
+ include Task
5
+
6
+ def prompt_for_project
7
+ remote = nil
8
+ print "Enter a git remote to add a project (leave blank to skip): "
9
+ remote = STDIN.gets.chomp.downcase
10
+ return if remote.empty?
11
+ project = Projects::Project.new(remote.match(/([^\/]*)\.git/)[1], {remote: remote})
12
+
13
+ if Projects::projects_file.projects.keys.include?(project.name) || Projects::projects_file.projects.values.map { |p| p['git'].downcase }.include?(project.repository.remote.downcase)
14
+ puts "\e[31mCannot add project. Another project with the same name already exists.\e[0m"
15
+ # TODO prompt to replace it?
16
+ # would need to probably remove the project, remove procs from procfile, resync project, reconfig, etc.
17
+ return
18
+ end
19
+
20
+ print "Enter a custom title for this project (leave blank for default) [#{project.title}]: "
21
+ title = STDIN.gets.chomp
22
+ project.title = title unless title.empty?
23
+
24
+ print "Is this project a 'gem', rails 'application', rails 'engine' or other type of project (leave blank to skip)?: "
25
+ type = STDIN.gets.chomp.downcase
26
+ type = 'application' if type == 'app' # hacky :/
27
+ unless type.empty?
28
+ classname = "::Greenhouse::Projects::#{type.singularize.camelize}"
29
+ if defined?(classname.constantize)
30
+ project = classname.constantize.new(project.name, {remote: project.repository.remote, title: project.title})
31
+ puts "Configuring #{project.title} as #{type == 'gem' ? 'a' : 'an'} #{type}"
32
+ end
33
+ end
34
+
35
+ project
36
+ end
37
+
38
+ def add_project(project)
39
+ Projects::projects_file.projects[project.name] = {'git' => project.repository.remote}
40
+ Projects::projects_file.projects[project.name]['title'] = project.title unless project.title == project.name.camelize
41
+ Projects::projects_file.projects[project.name]['type'] = project.class.name.underscore.split("/").last unless project.class == Projects::Project
42
+
43
+ Projects::projects_file.write
44
+
45
+ puts "Added \e[36m#{project.title}\e[0m to the ecosystem."
46
+ project
47
+ end
48
+
49
+ def perform
50
+ project = prompt_for_project
51
+ return if project.nil?
52
+
53
+ add_project(project)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,22 @@
1
+ module Greenhouse
2
+ module Tasks
3
+ class GenerateProcfile
4
+ include Task
5
+
6
+ def perform
7
+ Projects::applications.each do |app|
8
+ next unless app.procfile.exists?
9
+ app.procfile.reload
10
+
11
+ if app.procfile.processes.keys.length == 1
12
+ Projects::procfile.processes[app.name] = "#{app.name}: greenhouse launch #{app.name} #{app.procfile.processes.keys.first}" unless Projects::procfile.processes.has_key?(app.name)
13
+ else
14
+ app.procfile.processes.keys.each { |process| Projects::procfile.processes["#{app.name}_#{process}"] = "#{app.name}_#{process}: greenhouse launch #{app.name} #{process}" unless Projects::procfile.processes.has_key?("#{app.name}_#{process}") }
15
+ end
16
+ end
17
+ Projects::procfile.write
18
+ end
19
+
20
+ end
21
+ end
22
+ end