greenhouse 0.0.3
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.
- 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
|