greenhouse 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/bin/greenhouse +9 -0
- data/lib/greenhouse/cli.rb +88 -0
- data/lib/greenhouse/commands/add.rb +32 -0
- data/lib/greenhouse/commands/command.rb +88 -0
- data/lib/greenhouse/commands/configure.rb +9 -0
- data/lib/greenhouse/commands/help.rb +45 -0
- data/lib/greenhouse/commands/init.rb +93 -0
- data/lib/greenhouse/commands/launch.rb +113 -0
- data/lib/greenhouse/commands/new.rb +42 -0
- data/lib/greenhouse/commands/pull.rb +45 -0
- data/lib/greenhouse/commands/purge.rb +91 -0
- data/lib/greenhouse/commands/push.rb +45 -0
- data/lib/greenhouse/commands/remove.rb +32 -0
- data/lib/greenhouse/commands/start.rb +21 -0
- data/lib/greenhouse/commands/status.rb +50 -0
- data/lib/greenhouse/commands/sync.rb +42 -0
- data/lib/greenhouse/commands.rb +32 -0
- data/lib/greenhouse/projects/application.rb +19 -0
- data/lib/greenhouse/projects/collection.rb +23 -0
- data/lib/greenhouse/projects/engine.rb +6 -0
- data/lib/greenhouse/projects/gem.rb +6 -0
- data/lib/greenhouse/projects/project.rb +77 -0
- data/lib/greenhouse/projects/repository.rb +197 -0
- data/lib/greenhouse/projects.rb +86 -0
- data/lib/greenhouse/resources/dotenv_file.rb +69 -0
- data/lib/greenhouse/resources/file_resource.rb +50 -0
- data/lib/greenhouse/resources/ignore_file.rb +115 -0
- data/lib/greenhouse/resources/procfile.rb +144 -0
- data/lib/greenhouse/resources/projects_file.rb +44 -0
- data/lib/greenhouse/resources.rb +10 -0
- data/lib/greenhouse/scripts/argument.rb +36 -0
- data/lib/greenhouse/scripts/arguments.rb +28 -0
- data/lib/greenhouse/scripts/invalid_argument.rb +6 -0
- data/lib/greenhouse/scripts/script.rb +109 -0
- data/lib/greenhouse/scripts.rb +4 -0
- data/lib/greenhouse/tasks/add_project.rb +57 -0
- data/lib/greenhouse/tasks/generate_procfile.rb +22 -0
- data/lib/greenhouse/tasks/project_status.rb +37 -0
- data/lib/greenhouse/tasks/project_task.rb +363 -0
- data/lib/greenhouse/tasks/pull_project.rb +14 -0
- data/lib/greenhouse/tasks/purge_project.rb +13 -0
- data/lib/greenhouse/tasks/push_project.rb +14 -0
- data/lib/greenhouse/tasks/remove_greenhouse_files.rb +58 -0
- data/lib/greenhouse/tasks/remove_project.rb +15 -0
- data/lib/greenhouse/tasks/sync_project.rb +19 -0
- data/lib/greenhouse/tasks/task.rb +25 -0
- data/lib/greenhouse/tasks.rb +20 -0
- data/lib/greenhouse/version.rb +20 -0
- data/lib/greenhouse.rb +12 -0
- 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,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,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
|