cult 0.1.1.pre
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/.gitignore +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +240 -0
- data/Rakefile +6 -0
- data/cult +1 -0
- data/cult.gemspec +38 -0
- data/doc/welcome.txt +1 -0
- data/exe/cult +86 -0
- data/lib/cult/artifact.rb +45 -0
- data/lib/cult/cli/common.rb +265 -0
- data/lib/cult/cli/console_cmd.rb +124 -0
- data/lib/cult/cli/cri_extensions.rb +84 -0
- data/lib/cult/cli/init_cmd.rb +116 -0
- data/lib/cult/cli/load.rb +26 -0
- data/lib/cult/cli/node_cmd.rb +205 -0
- data/lib/cult/cli/provider_cmd.rb +123 -0
- data/lib/cult/cli/role_cmd.rb +149 -0
- data/lib/cult/cli/task_cmd.rb +140 -0
- data/lib/cult/commander.rb +103 -0
- data/lib/cult/config.rb +22 -0
- data/lib/cult/definition.rb +112 -0
- data/lib/cult/driver.rb +88 -0
- data/lib/cult/drivers/common.rb +192 -0
- data/lib/cult/drivers/digital_ocean_driver.rb +179 -0
- data/lib/cult/drivers/linode_driver.rb +282 -0
- data/lib/cult/drivers/load.rb +26 -0
- data/lib/cult/drivers/script_driver.rb +27 -0
- data/lib/cult/drivers/vultr_driver.rb +217 -0
- data/lib/cult/named_array.rb +129 -0
- data/lib/cult/node.rb +62 -0
- data/lib/cult/project.rb +169 -0
- data/lib/cult/provider.rb +134 -0
- data/lib/cult/role.rb +213 -0
- data/lib/cult/skel.rb +85 -0
- data/lib/cult/task.rb +64 -0
- data/lib/cult/template.rb +92 -0
- data/lib/cult/transferable.rb +61 -0
- data/lib/cult/version.rb +3 -0
- data/lib/cult.rb +4 -0
- data/skel/.cultconsolerc +4 -0
- data/skel/.cultrc.erb +29 -0
- data/skel/README.md.erb +22 -0
- data/skel/keys/.keep +0 -0
- data/skel/nodes/.keep +0 -0
- data/skel/providers/.keep +0 -0
- data/skel/roles/all/role.json +4 -0
- data/skel/roles/all/tasks/00000-do-something-cool +27 -0
- data/skel/roles/bootstrap/files/cult-motd +45 -0
- data/skel/roles/bootstrap/role.json +4 -0
- data/skel/roles/bootstrap/tasks/00000-set-hostname +22 -0
- data/skel/roles/bootstrap/tasks/00001-add-cult-user +21 -0
- data/skel/roles/bootstrap/tasks/00002-install-cult-motd +9 -0
- metadata +183 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: cea2fc50c8b92985e08159d77c53f16cb71569ce
|
4
|
+
data.tar.gz: cba93e78130a741980b6f3be07038edb2a9035fc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 70ccf020691c38b75dce07f9e408cce0f0849a1d54b06a96038de5b0f4c459be024822f6931b433c115e04fa318b461e05f937faad60f7b85ce492474efa72bc
|
7
|
+
data.tar.gz: 98370627f82c3c4aa5c240e66aa2dfce29c17f4d8368e509c205651dfd0fdcd97d4a0aef2f9711fe03f28c5d9e158206ee10771108bc04c5a6b01b8965c02525
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Mike Owens, meter.md
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,240 @@
|
|
1
|
+
# Cult
|
2
|
+
|
3
|
+
## Introduction
|
4
|
+
|
5
|
+
Cult is a tool to manage fleets of servers. It tries to work in an obvious
|
6
|
+
way, and doesn't intend on you learning a bunch of new metaphors, languages,
|
7
|
+
and terminology.
|
8
|
+
|
9
|
+
Cult may be what you're looking for if:
|
10
|
+
|
11
|
+
* You like the transparency of shell-script setup but have outgrown it, and
|
12
|
+
it's turning into a tangled mess
|
13
|
+
* "Configuration Management Systems" and "Known Configuration State" stuff
|
14
|
+
rubs you the wrong way
|
15
|
+
* You're not worried about abstracting away Unix, as if you'll be deploying
|
16
|
+
on a herd of Amigas next year
|
17
|
+
* You're not looking to find a cloud-hosted meta-script to effectively
|
18
|
+
`apt-get -y install nginx`
|
19
|
+
* You have no ceremony around spinning up and killing servers. Cult can
|
20
|
+
manage real metal, but its default mindset is: if you fuck up too bad, you
|
21
|
+
can spin up a fresh instance
|
22
|
+
* When you think of a forward migration, the first thing that comes to mind
|
23
|
+
is `#!...`
|
24
|
+
* You don't get why you need more than a working SSH to configure a server,
|
25
|
+
and why you'd want an agent running thereafter.
|
26
|
+
* It doesn't creep you out that Cult can look at your git branch name to
|
27
|
+
decide if you're in production or development mode. There are some
|
28
|
+
conventions going on.
|
29
|
+
|
30
|
+
|
31
|
+
Cult's probably not your bourbon and ginger if:
|
32
|
+
|
33
|
+
* You see value in "converging toward a configuration", as if you're guiding
|
34
|
+
your precious children through the path of life, and helping them evolve
|
35
|
+
into better people.
|
36
|
+
* You have one big-ass old server that's gets conservatively upgraded via
|
37
|
+
efforts big enough to have a project name. Cult can help you *out* of
|
38
|
+
that, though.
|
39
|
+
* You're sold on image-in-a-container-in-a-KVM deployment. That's totally
|
40
|
+
reasonable, but Cult doesn't really do anything particularly special
|
41
|
+
to help you if you're happy with the process you have building containers.
|
42
|
+
* You expect to have the same configuration abstractly work on a totally
|
43
|
+
diverse set of platforms (e.g., one "formula" that works on Ubuntu,
|
44
|
+
FreeBSD, and SCO OpenServer 5). Cult can manage these absolutely fine, but
|
45
|
+
you lose a lot of the benefit of its role-based sharing, and will find
|
46
|
+
yourself in the script-equivalent of `#ifdef`-hell.
|
47
|
+
* You've already got a working and complicated network, managed by years
|
48
|
+
worth of highly-tuned inputs into a Configuration Management System. Cult
|
49
|
+
itself does less for you, but requires a lot less of you.
|
50
|
+
|
51
|
+
But, what you gain via Cult is transparency, repeatability, and obviousness.
|
52
|
+
|
53
|
+
|
54
|
+
## Installation
|
55
|
+
|
56
|
+
Cult is written in Ruby and available as a gem, but it is an application, not a
|
57
|
+
library. It's not written in, and has no relation to Rails. It depends on
|
58
|
+
Ruby 2.3 or greater. If you've got Ruby installed, via any means, the following
|
59
|
+
command should handle everything:
|
60
|
+
|
61
|
+
$ gem install cult
|
62
|
+
|
63
|
+
Most provider drivers require outside gems, for example, the Linode driver
|
64
|
+
requires the Linode API gem, the DigitalOcean driver requires DropletKit,
|
65
|
+
etc. Cult will ask, and then install these required gems only when you go to
|
66
|
+
use the driver.
|
67
|
+
|
68
|
+
Cult requires nothing to be installed on each node, other than an operating SSH
|
69
|
+
server and Bourne Shell. If you know you've got Bash on the other end, feel
|
70
|
+
free to write your tasks in Bash. If you want to write tasks in Ruby, Python,
|
71
|
+
Node or Perl, etc, one of your firsts Tasks in the `all` role should be to
|
72
|
+
`apt-get -y install {ruby,python,node}`. All subsequent tasks will have that
|
73
|
+
interpreter available.
|
74
|
+
|
75
|
+
|
76
|
+
## General Theory
|
77
|
+
|
78
|
+
I think a reasonable level of abstraction for cloud deployments is such:
|
79
|
+
|
80
|
+
1. *Nodes*: Actual machines, virtual or otherwise, running somewhere.
|
81
|
+
2. *Roles*: The purpose of a node. e.g., `web-frontend`, `db-master`, or
|
82
|
+
`redis-server`.
|
83
|
+
3. *Tasks*: Roles are made of tasks, which are basically scripts, called
|
84
|
+
things like `install-postgres` or `configure-nginx`. They're written in
|
85
|
+
your language of choice. When you being up a Node with a Role, all of the
|
86
|
+
Role's tasks are executed to get it up and running.
|
87
|
+
4. *Providers*: Your VPS provider, e.g., Linode, DigitalOcean, etc. These
|
88
|
+
allow you to spawn and destroy nodes, and typically charge you a few cents
|
89
|
+
per node per hour. I guess there's also *Drivers*, but a Provider is
|
90
|
+
really just an instance of a *Driver* with an API key configured.
|
91
|
+
|
92
|
+
We hate adding anything on top of this because it increases complexity.
|
93
|
+
|
94
|
+
Sometimes, what you need is not baked into Cult. So Cult is full of escape
|
95
|
+
hatches like ERB templating on shell scripts and JSON files to do weird stuff.
|
96
|
+
|
97
|
+
|
98
|
+
### Drivers
|
99
|
+
|
100
|
+
Cult provides a handful of Drivers which can talk to common VPS providers,
|
101
|
+
initially DigitalOcean, Linode, and Vultr. A driver is typically 200-300 lines
|
102
|
+
of Ruby code, and is pretty well isolated from the rest of Cult, so feel free
|
103
|
+
to open a PR to add your provider of choice. You can get a current list with:
|
104
|
+
|
105
|
+
$ cult provider drivers
|
106
|
+
|
107
|
+
The goal of a driver is to talk to your VPS provider, start a server with a
|
108
|
+
size/instance type, zone/region, distribution, and ssh key you provide. It
|
109
|
+
then makes sure it's configured to allow a root login with that SSH key.
|
110
|
+
|
111
|
+
The Driver gets you to a "pre-bootstrap" stage where your server exists and
|
112
|
+
you can connect to it. The `bootstrap` role can then kick in. Your `boostrap`
|
113
|
+
role will typically create the `cult` user, disable the root account, etc (the
|
114
|
+
default bootstrap role indeed does exactly this.)
|
115
|
+
|
116
|
+
### Nodes
|
117
|
+
|
118
|
+
A node is a physical instance running somewhere. A node has a name, like
|
119
|
+
'web1', but also has a full description, that looks something like:
|
120
|
+
|
121
|
+
web1@ubuntu-16-01.2gb:digitalocean.nyc1
|
122
|
+
|
123
|
+
A node named `web1` is an idea, but hasn't spawned. A node named with its full
|
124
|
+
description should represent a real server somewhere, that is (hopefully)
|
125
|
+
running.
|
126
|
+
|
127
|
+
### Roles
|
128
|
+
A role is a collection of files (usually configuration files), Tasks (usually
|
129
|
+
shell scripts), and a configuration (`role.json`). A role can include other
|
130
|
+
roles via `includes:`. A role can state it conflicts with another role via
|
131
|
+
`conflicts:`.
|
132
|
+
|
133
|
+
A Role's tasks are named like `00000-a-descriptive-name`, because the only
|
134
|
+
ordering Cult does is asciibetical.
|
135
|
+
|
136
|
+
Every task, file, and even `role.json` is pre-processed with ERB before it gets
|
137
|
+
processed by Cult or shipped to a node. This lets you customize behavior based
|
138
|
+
on the node, the role, the provider, the project, or anything else you'd like.
|
139
|
+
|
140
|
+
#### Special Roles
|
141
|
+
There are two Roles generated by default that you should think of as
|
142
|
+
special-ish:
|
143
|
+
|
144
|
+
1. `all`: If a Role does not explicitly list an `includes` value, Cult will
|
145
|
+
act as if it specified `includes: ['all']`. In practice, this means tasks
|
146
|
+
in the `all` role are common to all nodes that haven't explicitly opted
|
147
|
+
out of it. A task can opt-out of including `all` with an explicit
|
148
|
+
`includes: []`.
|
149
|
+
2. `bootstrap`: The generator creates this role to be the first one ran on a
|
150
|
+
new node. Before it starts, we have a root account with an SSH key, when
|
151
|
+
`bootstrap` finishes, we have a `cult` user on the node with `sudo` access
|
152
|
+
who uses the same SSH key, and the root account is disabled. `bootstrap`
|
153
|
+
opts-out of `all`. The generator also installs a MOTD banner so you'll
|
154
|
+
know Cult was enabled on the server, has a demo script that sets the
|
155
|
+
hostname.
|
156
|
+
|
157
|
+
## UI
|
158
|
+
|
159
|
+
Even though you aren't required to use it, Cult includes the terminal-mode GUI
|
160
|
+
packages (`$ cult ui`). Because it's 2016, and we're not worried about a few
|
161
|
+
MB of extra packages hanging around anymore. We're steadily trying to improve
|
162
|
+
this cool-ass tmux-based UI, but it's still new right now.
|
163
|
+
|
164
|
+
## Usage
|
165
|
+
|
166
|
+
We're going to put together a complete usage guide, tutorial, and example repo
|
167
|
+
once Cult has settled down a bit. It's still pre-1.0 software, and we still
|
168
|
+
like breaking things to make it work better for us.
|
169
|
+
|
170
|
+
### 👻 Spooky Secrets
|
171
|
+
|
172
|
+
* `cult console` is built to be really nice to use. If you're not afraid of
|
173
|
+
Ruby, the method names are chosen to read almost like pseudo-code. It
|
174
|
+
supports IRB, Pry, and Ripl with command-line flags.
|
175
|
+
* Anything that Cult keeps "an Array of", that you'd maybe want to reference
|
176
|
+
by name is stored in a NamedArray, which shares some features with a Hash.
|
177
|
+
This is for convenience. For example, in `cult console`, you can find the
|
178
|
+
first driver with `drivers[0]`, find it by name with `drivers['linode']`,
|
179
|
+
or (*get ready for fancy stuff:*) look it up by a Regexp with
|
180
|
+
`drivers[/ocean/i]`.
|
181
|
+
* The NamedArray stuff even works on the command-line with String arguments,
|
182
|
+
and will convert strings that start with '/' to Regexps to search by name.
|
183
|
+
* Although Cult will only *generate* JSON, not having comments and other
|
184
|
+
stuff is a pain. If you don't care about JSON-readability of your
|
185
|
+
`node.json`s or `role.json`s, you can just rename it to `node.yaml` or
|
186
|
+
`node.yml` and it'll get parsed with a YAML parser. Cult keeps transient
|
187
|
+
state in separate files for this reason: so it doesn't overwrite your
|
188
|
+
long-lived YAML replacements with JSON equivalents.
|
189
|
+
|
190
|
+
|
191
|
+
## Development
|
192
|
+
|
193
|
+
### History
|
194
|
+
|
195
|
+
Cult was developed to basically avoid Puppet, Chef, and Ansible. I know there
|
196
|
+
are some really large, successful deployments of all of these. I just think
|
197
|
+
they just do too much for me to feel safe with when shit goes crazy.
|
198
|
+
|
199
|
+
Some of the things Cult doesn't do are things we haven't had time to implement,
|
200
|
+
like fully building out 'cult ui'. A lot of the things Cult doesn't do are
|
201
|
+
the reason Cult exists. Some of the limitations are designed to force a
|
202
|
+
certain mindset I think is healthy for building resilient systems. In
|
203
|
+
particular:
|
204
|
+
|
205
|
+
1. Exercising the server bring-up process from bottom-up as the normal mode
|
206
|
+
of operation. This is why Cult makes you bring up a node from provision/
|
207
|
+
bootstrap each time, instead of using snapshots, a feature virtually every
|
208
|
+
VPS provider supports.
|
209
|
+
2. Making it less reasonable to have nodes hanging around that have ended up
|
210
|
+
in their current state via baby-step migrations for too long. Cult does
|
211
|
+
this fine, but makes it easier to just test a new node with a clean build.
|
212
|
+
This way you're not worried about idempotent transforms, or a lot of
|
213
|
+
conditional logic. If a node is not where you want, bring up another that
|
214
|
+
is, and kill the old one.
|
215
|
+
|
216
|
+
We can be convinced otherwise, but these are sort of core tenets of what Cult
|
217
|
+
is about.
|
218
|
+
|
219
|
+
### Contributing
|
220
|
+
|
221
|
+
We greatly appreciate bug reports, pull-requests, questions, and general
|
222
|
+
commentary in the GitHub Issues. These are all *contributions*. However,
|
223
|
+
before opening an issue demanding us to work on your feature that Cult *has to
|
224
|
+
have to be taken seriously*, note:
|
225
|
+
|
226
|
+
* Cult was built by meter.md nerds to make managing our infrastructure
|
227
|
+
better. Its utility is measured by that metric. We've released the
|
228
|
+
project because we believe in the value of open *collaboration*, not so we
|
229
|
+
can be unpaid software contractors working on the demands of strangers on
|
230
|
+
the internet.
|
231
|
+
* If your contribution consists of instructing the team how to run the
|
232
|
+
project: Thanks, but we've got that handled.
|
233
|
+
|
234
|
+
If you're contributing code, asking a question, or reporting a bug, don't let
|
235
|
+
the above items you away.
|
236
|
+
|
237
|
+
## License
|
238
|
+
|
239
|
+
Cult is available as open source software under the terms of the
|
240
|
+
[MIT License](http://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/cult.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cult/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cult"
|
8
|
+
spec.version = Cult::VERSION
|
9
|
+
spec.authors = ["Mike Owens"]
|
10
|
+
spec.email = ["mike@meter.md"]
|
11
|
+
|
12
|
+
spec.summary = "Fleet Management like its 1990"
|
13
|
+
spec.homepage = "https://github.com/metermd/cult"
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
17
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
18
|
+
if spec.respond_to?(:metadata)
|
19
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
20
|
+
else
|
21
|
+
raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
|
22
|
+
end
|
23
|
+
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
25
|
+
spec.bindir = "exe"
|
26
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.required_ruby_version = '~> 2.3'
|
30
|
+
|
31
|
+
spec.add_dependency "cri", "~> 2.7.0"
|
32
|
+
spec.add_dependency "net-ssh", "~> 3.2.0"
|
33
|
+
spec.add_dependency "net-scp", "~> 1.2.1"
|
34
|
+
spec.add_dependency "rainbow", "~> 2.1.0"
|
35
|
+
|
36
|
+
spec.add_development_dependency "bundler", "~> 1.12"
|
37
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
38
|
+
end
|
data/doc/welcome.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Welcome to cult.
|
data/exe/cult
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$LOAD_PATH << File.expand_path(File.join(__dir__, '../lib'))
|
3
|
+
|
4
|
+
require 'cri'
|
5
|
+
|
6
|
+
require 'cult/version'
|
7
|
+
require 'cult/config'
|
8
|
+
require 'cult/project'
|
9
|
+
require 'cult/node'
|
10
|
+
require 'cult/cli/load'
|
11
|
+
require 'cult/drivers/load'
|
12
|
+
|
13
|
+
cult = Cri::Command.define do
|
14
|
+
optional_project
|
15
|
+
name 'cult'
|
16
|
+
usage 'cult [options] [command [options...]]'
|
17
|
+
summary 'Control a Fleet of Obedient Zomboid Machines'
|
18
|
+
description <<~EOD.format_description
|
19
|
+
Cult is a tool for creating and then managing a fleet of servers you
|
20
|
+
control. It operates on a few simple concepts:
|
21
|
+
|
22
|
+
* Nodes: actual servers out there somewhere. The purpose of using Cult
|
23
|
+
is to end up with nodes doing useful work for you.
|
24
|
+
|
25
|
+
* Roles: Every node has one or more roles, things it plans on being.
|
26
|
+
Roles are composed of...
|
27
|
+
|
28
|
+
* Tasks: Basically shell scripts that run in a specific order.
|
29
|
+
|
30
|
+
Cult has a few more convenience concepts, like Keys and Providers, but you
|
31
|
+
don't end up thinking about them too often.
|
32
|
+
|
33
|
+
To create a new Cult project, use 'cult init DIRECTORY', but see the 'init'
|
34
|
+
help first, with 'cult init --help'
|
35
|
+
EOD
|
36
|
+
|
37
|
+
required :C, :directory, 'Specify a project path' do |value|
|
38
|
+
Cult::CLI.set_project(value)
|
39
|
+
end
|
40
|
+
|
41
|
+
flag :h, :help, 'Show this help' do |value, cmd|
|
42
|
+
puts cmd.help
|
43
|
+
end
|
44
|
+
|
45
|
+
flag :y, :yes, 'Answer "yes" to any questions' do
|
46
|
+
Cult::CLI.yes = true
|
47
|
+
end
|
48
|
+
|
49
|
+
flag :q, :quiet, "Don't show any unnecessary information" do
|
50
|
+
Cult::CLI.quiet = true
|
51
|
+
end
|
52
|
+
|
53
|
+
flag :v, :version, 'Show version information' do
|
54
|
+
puts "Cult #{Cult::VERSION}"
|
55
|
+
puts 'Copyright (C) 2016 Mike A. Owens, meter.md, and Contributors'
|
56
|
+
end
|
57
|
+
|
58
|
+
run(arguments: 0) do |opts, args, cmd|
|
59
|
+
puts cmd.help
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Cult::CLI.commands.each do |m|
|
64
|
+
cult.add_command(m)
|
65
|
+
end
|
66
|
+
|
67
|
+
if (env = ENV['CULT_PROJECT'])
|
68
|
+
Cult::CLI.set_project(env)
|
69
|
+
else
|
70
|
+
Cult.project ||= Cult::Project.from_cwd
|
71
|
+
end
|
72
|
+
|
73
|
+
if Cult.project
|
74
|
+
Cult.project.execute_cultrc
|
75
|
+
end
|
76
|
+
|
77
|
+
ERROR_CULT = Rainbow("#{File.basename($0)}:").red
|
78
|
+
|
79
|
+
begin
|
80
|
+
cult.run(ARGV)
|
81
|
+
rescue Cult::CLI::CLIError, RegexpError => e
|
82
|
+
$stderr.puts "#{ERROR_CULT} #{e.message}"
|
83
|
+
exit 1
|
84
|
+
rescue Interrupt
|
85
|
+
exit 1
|
86
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'cult/transferable'
|
2
|
+
require 'cult/named_array'
|
3
|
+
|
4
|
+
module Cult
|
5
|
+
# I'd love to just call this "File", but the ambiguity with ::File would
|
6
|
+
# make it a pain.
|
7
|
+
class Artifact
|
8
|
+
include Transferable
|
9
|
+
|
10
|
+
def self.collection_name
|
11
|
+
"files"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def relative_path
|
16
|
+
name
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
attr_reader :path
|
21
|
+
attr_reader :role
|
22
|
+
|
23
|
+
def initialize(role, path)
|
24
|
+
@role = role
|
25
|
+
@path = path
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
def inspect
|
30
|
+
"\#<#{self.class.name} role:#{role&.name.inspect} name:#{name.inspect}>"
|
31
|
+
end
|
32
|
+
alias_method :to_s, :inspect
|
33
|
+
|
34
|
+
|
35
|
+
def self.all_for_role(project, role)
|
36
|
+
Dir.glob(File.join(role.path, "files", "**/*")).map do |filename|
|
37
|
+
next if File.directory?(filename)
|
38
|
+
new(role, filename).tap do |new_file|
|
39
|
+
yield new_file if block_given?
|
40
|
+
end
|
41
|
+
end.compact.to_named_array
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|