flintlock 0.1.0 → 0.2.0
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.
- data/CHANGES.md +28 -0
- data/README.md +17 -8
- data/lib/flintlock.rb +1 -0
- data/lib/flintlock/cli.rb +54 -4
- data/lib/flintlock/logger.rb +5 -0
- data/lib/flintlock/metadata.rb +4 -0
- data/lib/flintlock/module.rb +105 -44
- data/lib/flintlock/runner.rb +34 -0
- data/lib/flintlock/util.rb +45 -9
- data/lib/flintlock/version.rb +1 -1
- metadata +91 -45
data/CHANGES.md
CHANGED
@@ -1,3 +1,31 @@
|
|
1
|
+
# Version 0.2.0
|
2
|
+
|
3
|
+
- Added the ``package`` subcommand, which packages up a local directory into
|
4
|
+
a module archive.
|
5
|
+
- Added the ``defaults`` subcommand, which prints out the default configuration
|
6
|
+
(from ``bin/defaults``) of the given module.
|
7
|
+
- Added the ``new`` subcommand, which generates an empty template module
|
8
|
+
- Added the ``version`` subcommand, which prints the ``flintlock`` version
|
9
|
+
- Added the ``--halt`` option to the ``deploy`` subcommand. This allows users
|
10
|
+
to halt deployment after a particular stage has run (e.g. ``--halt stage``)
|
11
|
+
- Added a new optional deployment stage called ``detect``. This script should be
|
12
|
+
used to validate whether the module is appropriate for installation on the
|
13
|
+
current host.
|
14
|
+
- Fixed a bug that prevented scripts that required a TTY from working.
|
15
|
+
- Fixed a bug with relative paths passed to the ``deploy`` command
|
16
|
+
- Module scripts are now silently skipped if they don't exist or are empty
|
17
|
+
(rather than erroring out).
|
18
|
+
- Fixed a bug where a ``/tmp`` filesystem mounted ``noexec`` would prevent
|
19
|
+
scripts from running.
|
20
|
+
- Can now deploy from local tarballs
|
21
|
+
- Can now deploy from subversion repositories
|
22
|
+
- Keyboard interrupts (``SIGQUIT``) are now caught and a nicer error is printed.
|
23
|
+
- External commands (e.g. ``git``, ``svn``) are validated prior to being run.
|
24
|
+
- Support a wider array of module URIs (e.g. ``svn+ssh://...``)
|
25
|
+
- Archives with root directories are now supported as valid module archives
|
26
|
+
(e.g. ``<archive_root>/<root_dir>/bin/*`` vs ``<archive_root>/bin/*`` layouts)
|
27
|
+
- Archive detection now uses MIME hinting rather than filename hinting
|
28
|
+
- Fixed a few issues with the RPM spec file
|
1
29
|
|
2
30
|
# Version 0.1.0
|
3
31
|
|
data/README.md
CHANGED
@@ -44,6 +44,7 @@ files and directories to ``/some/empty/directory``. Let's see what happens:
|
|
44
44
|
```console
|
45
45
|
$ flintlock deploy git://github.com/jcmcken/flintlock-redis.git /some/empty/directory
|
46
46
|
run fetching module
|
47
|
+
run detecting compatibility
|
47
48
|
info deploying jcmcken/redis (0.0.1) to '/some/empty/directory'
|
48
49
|
create creating deploy directory
|
49
50
|
run installing and configuring dependencies
|
@@ -92,10 +93,12 @@ is usually acceptable. But all of the important files should really be located t
|
|
92
93
|
|
93
94
|
## Supported Formats
|
94
95
|
|
95
|
-
Currently ``flintlock`` can install modules from a number of sources
|
96
|
-
local directories, ``flintlock`` supports the following protocols/formats:
|
96
|
+
Currently ``flintlock`` can install modules from a number of sources:
|
97
97
|
|
98
|
-
*
|
98
|
+
* From a local directory
|
99
|
+
* From a local tarball (``tar`` or ``tar.gz``)
|
100
|
+
* Over ``git`` supported protocols (``git://..``)
|
101
|
+
* Over ``svn`` supported protocols (``svn://...``)
|
99
102
|
* ``tar`` or ``tar.gz`` over ``http``/``https``
|
100
103
|
|
101
104
|
Attempting to install any other way will throw an error message similar to the following:
|
@@ -117,6 +120,7 @@ At its heart, a module has the following minimal layout:
|
|
117
120
|
sample-app-1
|
118
121
|
|-- bin
|
119
122
|
| |-- defaults
|
123
|
+
| |-- detect
|
120
124
|
| |-- modify
|
121
125
|
| |-- prepare
|
122
126
|
| |-- stage
|
@@ -130,8 +134,8 @@ generate this structure.
|
|
130
134
|
|
131
135
|
The top-level directory (in this case, ``sample-app-1``) can be called anything.
|
132
136
|
|
133
|
-
The files under ``bin`` are executable scripts (using any language you care to
|
134
|
-
|
137
|
+
The files under ``bin`` are executable scripts (using any language you care to
|
138
|
+
use). More on these later.
|
135
139
|
|
136
140
|
The ``metadata.json`` file contains metadata about the module. This metadata looks as follows:
|
137
141
|
|
@@ -143,8 +147,9 @@ The ``metadata.json`` file contains metadata about the module. This metadata loo
|
|
143
147
|
}
|
144
148
|
```
|
145
149
|
|
146
|
-
All three keys (``author``, ``name``, ``version``) are required, but can be any value
|
147
|
-
metadata are merely used to namespace
|
150
|
+
All three keys (``author``, ``name``, ``version``) are required, but can be any value
|
151
|
+
(as long as they're not the empty string). These metadata are merely used to namespace
|
152
|
+
the module.
|
148
153
|
|
149
154
|
``flintlock`` developers can choose to include more files in their modules if needed.
|
150
155
|
|
@@ -157,6 +162,7 @@ These stages correspond directly to the scripts under ``bin/``.
|
|
157
162
|
|
158
163
|
The most important stages, and their purpose, are as follows. (The stages occur in the order listed below)
|
159
164
|
|
165
|
+
* ``detect``: Detect whether the module is compatible with the current host.
|
160
166
|
* ``prepare``: Install or compile any required dependencies. This script takes no arguments.
|
161
167
|
* ``stage``: Stage the application directories and files. This script takes a single argument,
|
162
168
|
which is the directory where your app will be deployed. This directory need not exist, but if
|
@@ -205,4 +211,7 @@ command line.
|
|
205
211
|
|
206
212
|
### Examples
|
207
213
|
|
208
|
-
|
214
|
+
Some example ``flintlock`` modules can be found @ the following locations:
|
215
|
+
|
216
|
+
* http://github.com/jcmcken/flintlock-redis.git
|
217
|
+
* http://github.com/jcmcken/flintlock-tomcat.git
|
data/lib/flintlock.rb
CHANGED
data/lib/flintlock/cli.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'thor'
|
2
2
|
require 'flintlock/module'
|
3
|
+
require 'flintlock/version'
|
3
4
|
|
4
5
|
module Flintlock
|
5
6
|
class Cli < Thor
|
@@ -7,22 +8,38 @@ module Flintlock
|
|
7
8
|
|
8
9
|
desc "deploy MODULE DIRECTORY", "Deploy a flintlock module MODULE to DIRECTORY"
|
9
10
|
method_option :debug, :type => :boolean, :description => "enable debug output", :default => false
|
11
|
+
method_option :halt, :type => :string, :banner => 'STAGE',
|
12
|
+
:description => "Halt after STAGE", :enum => ['fetch', 'detect', 'prepare', 'stage', 'start', 'modify']
|
10
13
|
def deploy(uri, app_dir)
|
14
|
+
app_dir = File.expand_path(app_dir)
|
11
15
|
say_status "run", "fetching module", :magenta
|
12
16
|
mod = get_module(uri, options)
|
13
|
-
|
14
|
-
say_status "create", "creating deploy directory"
|
15
|
-
mod.create_app_dir(app_dir) rescue abort("deploy directory is not empty")
|
17
|
+
return if options[:halt] == 'fetch'
|
16
18
|
|
17
19
|
begin
|
20
|
+
say_status "run", "detecting compatibility", :magenta
|
21
|
+
mod.detect
|
22
|
+
return if options[:halt] == 'detect'
|
23
|
+
|
24
|
+
say_status "info", "deploying #{mod.full_name} to '#{app_dir}'", :blue
|
25
|
+
say_status "create", "creating deploy directory"
|
26
|
+
mod.create_app_dir(app_dir) rescue abort("deploy directory is not empty")
|
18
27
|
say_status "run", "installing and configuring dependencies", :magenta
|
19
28
|
mod.prepare
|
29
|
+
return if options[:halt] == 'prepare'
|
30
|
+
|
20
31
|
say_status "create", "staging application files"
|
21
32
|
mod.stage(app_dir)
|
33
|
+
return if options[:halt] == 'stage'
|
34
|
+
|
22
35
|
say_status "run", "launching the application", :magenta
|
23
36
|
mod.start(app_dir)
|
37
|
+
return if options[:halt] == 'start'
|
38
|
+
|
24
39
|
say_status "run", "altering application runtime environment", :magenta
|
25
40
|
mod.modify(app_dir)
|
41
|
+
return if options[:halt] == 'modify'
|
42
|
+
|
26
43
|
say_status "info", "complete!", :blue
|
27
44
|
rescue Errno::EACCES => e
|
28
45
|
abort("#{e.message.gsub(/Permission denied/, 'permission denied')}")
|
@@ -39,24 +56,57 @@ module Flintlock
|
|
39
56
|
inside("bin") do
|
40
57
|
Module.script_names.each do |script|
|
41
58
|
create_file script
|
59
|
+
chmod script, 0755, :verbose => false
|
42
60
|
end
|
43
61
|
end
|
44
62
|
create_file(Metadata.filename, Metadata.empty)
|
45
63
|
end
|
46
64
|
end
|
47
65
|
|
66
|
+
desc "package [DIRECTORY]", "Package up the given module directory"
|
67
|
+
method_option :debug, :type => :boolean, :description => "enable debug output", :default => false
|
68
|
+
def package(directory = Dir.pwd)
|
69
|
+
handle_exception { Module.package(directory, options.dup) }
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "defaults MODULE", "Print the default configuration settings for MODULE"
|
73
|
+
def defaults(uri)
|
74
|
+
mod = get_module(uri)
|
75
|
+
mod.defaults.each do |k,v|
|
76
|
+
puts "#{k}=#{v}"
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
desc "version", "Print version information"
|
81
|
+
def version
|
82
|
+
puts Flintlock::VERSION
|
83
|
+
end
|
84
|
+
|
48
85
|
private
|
49
86
|
|
50
87
|
def get_module(uri, options={})
|
51
|
-
|
88
|
+
handle_exception do
|
52
89
|
Flintlock::Module.new(uri, options)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def handle_exception(&block)
|
94
|
+
begin
|
95
|
+
result = block.call
|
53
96
|
rescue InvalidModule => e
|
54
97
|
abort("invalid flintlock module '#{e}'")
|
55
98
|
rescue UnsupportedModuleURI => e
|
56
99
|
abort("don't know how to download '#{e}'!")
|
57
100
|
rescue ModuleDownloadError => e
|
58
101
|
abort("failed to download '#{e}'")
|
102
|
+
rescue DependencyError => e
|
103
|
+
abort("missing dependency: no such command '#{e}'")
|
104
|
+
rescue Interrupt
|
105
|
+
abort("interrupted by user")
|
106
|
+
rescue PackagingError
|
107
|
+
abort("packaging failed!")
|
59
108
|
end
|
109
|
+
result
|
60
110
|
end
|
61
111
|
|
62
112
|
def error(message)
|
data/lib/flintlock/logger.rb
CHANGED
data/lib/flintlock/metadata.rb
CHANGED
data/lib/flintlock/module.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'flintlock/metadata'
|
2
2
|
require 'flintlock/logger'
|
3
3
|
require 'flintlock/util'
|
4
|
+
require 'flintlock/runner'
|
4
5
|
require 'open3'
|
5
6
|
require 'fileutils'
|
6
7
|
require 'logger'
|
@@ -15,6 +16,7 @@ module Flintlock
|
|
15
16
|
class UnsupportedModuleURI < RuntimeError; end
|
16
17
|
class ModuleDownloadError < RuntimeError; end
|
17
18
|
class RunFailure < RuntimeError; end
|
19
|
+
class PackagingError < RuntimeError; end
|
18
20
|
|
19
21
|
class Module
|
20
22
|
attr_reader :uri, :metadata
|
@@ -22,33 +24,34 @@ module Flintlock
|
|
22
24
|
def initialize(uri = nil, options={})
|
23
25
|
# track temporary files and directories for deletion
|
24
26
|
@tmpfiles = []
|
25
|
-
|
27
|
+
|
26
28
|
# destroy tmp files on exit
|
27
29
|
at_exit { handle_exit }
|
28
30
|
|
29
|
-
@debug = !!options[:debug]
|
30
31
|
@uri = uri || Dir.pwd
|
31
|
-
@log = load_logger
|
32
|
-
@
|
33
|
-
|
32
|
+
@log = Util.load_logger(!!options[:debug])
|
33
|
+
@runner = Runner.new(options)
|
34
|
+
|
35
|
+
@root_dir = detect_root_dir(download_from_uri(@uri))
|
36
|
+
@metadata = load_metadata(@root_dir)
|
34
37
|
|
35
38
|
load_scripts!
|
36
39
|
validate
|
37
40
|
|
38
41
|
@env = load_env(@defaults_script)
|
39
|
-
|
40
42
|
end
|
41
43
|
|
42
44
|
def download_from_uri(uri)
|
43
|
-
case
|
44
|
-
when nil # no scheme == local file
|
45
|
-
uri
|
45
|
+
case Util.get_uri_scheme(uri)
|
46
|
+
when nil, 'file' # no scheme == local file
|
47
|
+
handle_file(uri)
|
46
48
|
when 'git'
|
47
49
|
handle_git_uri(uri)
|
50
|
+
when 'svn'
|
51
|
+
handle_svn_uri(uri)
|
48
52
|
when 'http', 'https'
|
49
|
-
raise UnsupportedModuleURI.new(uri) if ! Util.supported_archive?(uri)
|
50
53
|
# over these protocols, we're getting an archive
|
51
|
-
|
54
|
+
handle_file(handle_http_uri(uri))
|
52
55
|
else
|
53
56
|
raise UnsupportedModuleURI, uri
|
54
57
|
end
|
@@ -59,11 +62,22 @@ module Flintlock
|
|
59
62
|
end
|
60
63
|
|
61
64
|
def handle_git_uri(uri)
|
65
|
+
Util.depends_on 'git'
|
66
|
+
|
62
67
|
root_dir = Dir.mktmpdir
|
63
68
|
@tmpfiles << root_dir
|
64
|
-
|
65
|
-
|
66
|
-
|
69
|
+
status = @runner.run(['git', 'clone', uri, root_dir])
|
70
|
+
raise ModuleDownloadError, uri if status != 0
|
71
|
+
root_dir
|
72
|
+
end
|
73
|
+
|
74
|
+
def handle_svn_uri(uri)
|
75
|
+
Util.depends_on 'svn'
|
76
|
+
|
77
|
+
root_dir = Dir.mktmpdir
|
78
|
+
@tmpfiles << root_dir
|
79
|
+
status = @runner.run(['svn', 'checkout', uri, root_dir])
|
80
|
+
raise ModuleDownloadError, uri if status != 0
|
67
81
|
root_dir
|
68
82
|
end
|
69
83
|
|
@@ -78,23 +92,32 @@ module Flintlock
|
|
78
92
|
end
|
79
93
|
end
|
80
94
|
tmpfile
|
81
|
-
rescue OpenURI::HTTPError
|
95
|
+
rescue OpenURI::HTTPError, OpenSSL::SSL::SSLError
|
82
96
|
raise ModuleDownloadError, uri
|
83
97
|
end
|
84
98
|
|
85
|
-
def
|
99
|
+
def handle_file(filename)
|
100
|
+
@log.debug("handling file '#{filename}'")
|
101
|
+
Util.depends_on 'tar'
|
102
|
+
|
86
103
|
tmpdir = Dir.mktmpdir
|
87
104
|
@tmpfiles << tmpdir
|
88
|
-
|
89
|
-
|
105
|
+
|
106
|
+
mime = Util.mime_type(filename)
|
107
|
+
@log.debug("mime-type is '#{mime}'")
|
108
|
+
|
109
|
+
case mime
|
110
|
+
when 'application/x-directory'
|
111
|
+
return filename
|
112
|
+
when 'application/x-gzip'
|
90
113
|
command = ['tar', 'xfz', filename, '-C', tmpdir]
|
91
|
-
when
|
114
|
+
when 'application/x-tar'
|
92
115
|
command = ['tar', 'xf', filename, '-C', tmpdir]
|
93
116
|
else
|
94
117
|
raise UnsupportedModuleURI, filename
|
95
118
|
end
|
96
|
-
|
97
|
-
raise ModuleDownloadError if status
|
119
|
+
status = @runner.run(command)
|
120
|
+
raise ModuleDownloadError, filename if status != 0
|
98
121
|
tmpdir
|
99
122
|
end
|
100
123
|
|
@@ -102,20 +125,29 @@ module Flintlock
|
|
102
125
|
@metadata.full_name
|
103
126
|
end
|
104
127
|
|
128
|
+
def package_name
|
129
|
+
@metadata.package_name
|
130
|
+
end
|
131
|
+
|
132
|
+
def self.stages
|
133
|
+
['detect', 'prepare', 'stage', 'start', 'modify']
|
134
|
+
end
|
135
|
+
|
105
136
|
def self.script_names
|
106
|
-
['defaults',
|
137
|
+
['defaults', *Module.stages, 'stop']
|
107
138
|
end
|
108
139
|
|
109
140
|
def scripts
|
110
|
-
[@modify_script, @prepare_script, @stage_script, @start_script, @stop_script, @defaults_script]
|
141
|
+
[@modify_script, @prepare_script, @stage_script, @start_script, @stop_script, @defaults_script, @detect_script]
|
111
142
|
end
|
112
143
|
|
113
|
-
def
|
114
|
-
|
144
|
+
def valid?
|
145
|
+
@metadata.valid?
|
115
146
|
end
|
116
147
|
|
117
|
-
def
|
118
|
-
@
|
148
|
+
def detect
|
149
|
+
@log.info("running detect stage: #{@detect_script}")
|
150
|
+
run_script(@detect_script)
|
119
151
|
end
|
120
152
|
|
121
153
|
def prepare
|
@@ -149,7 +181,7 @@ module Flintlock
|
|
149
181
|
|
150
182
|
def load_env(defaults_script)
|
151
183
|
# hokey, but seems to work
|
152
|
-
env_data = %x{set -a && source #{defaults_script} && env}.split.map{ |x| x.split('=', 2) }
|
184
|
+
env_data = %x{set -a && source #{defaults_script} && env}.split("\n").map{ |x| x.split('=', 2) }
|
153
185
|
env = Hash[env_data]
|
154
186
|
@log.debug("defaults script is #{defaults_script}")
|
155
187
|
@log.debug("defaults env is #{env.inspect}")
|
@@ -158,11 +190,34 @@ module Flintlock
|
|
158
190
|
env
|
159
191
|
end
|
160
192
|
|
193
|
+
def defaults
|
194
|
+
Hash[@env.to_a - ENV.to_a]
|
195
|
+
end
|
196
|
+
|
161
197
|
def create_app_dir(app_dir)
|
162
198
|
FileUtils.mkdir_p(app_dir)
|
163
199
|
raise if ! Util.empty_directory?(app_dir)
|
164
200
|
end
|
165
201
|
|
202
|
+
def self.package(directory, options={})
|
203
|
+
Util.depends_on 'tar'
|
204
|
+
|
205
|
+
mod = Module.new(directory, options)
|
206
|
+
archive = mod.package_name + '.tar.gz'
|
207
|
+
|
208
|
+
if Util.path_split(directory).length > 1
|
209
|
+
change_to = File.dirname(directory)
|
210
|
+
archive_path = File.basename(directory)
|
211
|
+
else
|
212
|
+
change_to = '.'
|
213
|
+
archive_path = directory
|
214
|
+
end
|
215
|
+
|
216
|
+
status = Runner.new(options).run(['tar', 'cfz', archive, '-C', change_to, archive_path])
|
217
|
+
raise PackagingError.new(directory) if status != 0
|
218
|
+
archive
|
219
|
+
end
|
220
|
+
|
166
221
|
private
|
167
222
|
|
168
223
|
def load_scripts!
|
@@ -172,36 +227,42 @@ module Flintlock
|
|
172
227
|
end
|
173
228
|
|
174
229
|
def validate
|
230
|
+
@log.debug('validating module')
|
175
231
|
raise InvalidModule.new(@uri) if ! valid?
|
176
232
|
end
|
177
233
|
|
178
|
-
def
|
179
|
-
log
|
180
|
-
log.silence! if ! @debug
|
181
|
-
log
|
182
|
-
end
|
183
|
-
|
184
|
-
def load_metadata
|
234
|
+
def load_metadata(root_dir)
|
235
|
+
@log.debug('loading module metadata')
|
185
236
|
begin
|
186
|
-
Metadata.new(File.join(
|
237
|
+
Metadata.new(File.join(root_dir, Metadata.filename))
|
187
238
|
rescue Errno::ENOENT
|
188
239
|
raise InvalidModule, uri
|
189
240
|
end
|
190
241
|
end
|
191
242
|
|
192
|
-
def
|
193
|
-
|
243
|
+
def empty_script?(script)
|
244
|
+
File.read(script).strip.empty?
|
245
|
+
end
|
246
|
+
|
247
|
+
def skip_script?(script)
|
248
|
+
skip = ! File.file?(script) || empty_script?(script)
|
249
|
+
@log.debug("skipping '#{script}'") if skip
|
250
|
+
skip
|
194
251
|
end
|
195
252
|
|
196
253
|
def run_script(script, *args)
|
197
|
-
|
254
|
+
return if skip_script?(script)
|
255
|
+
command = [*Util.detect_runtime(script), script, *args].compact
|
256
|
+
status = @runner.run(command, :env => @env)
|
257
|
+
raise RunFailure if status != 0
|
198
258
|
end
|
199
259
|
|
200
|
-
def
|
201
|
-
|
202
|
-
if
|
203
|
-
|
204
|
-
|
260
|
+
def detect_root_dir(directory)
|
261
|
+
contents = Dir[File.join(directory, '*')]
|
262
|
+
if contents.length == 1 && File.directory?(contents[0])
|
263
|
+
contents[0]
|
264
|
+
else
|
265
|
+
directory
|
205
266
|
end
|
206
267
|
end
|
207
268
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'open3'
|
2
|
+
|
3
|
+
module Flintlock
|
4
|
+
class Runner
|
5
|
+
def initialize(options={})
|
6
|
+
@log = Util.load_logger(!!options[:debug])
|
7
|
+
end
|
8
|
+
|
9
|
+
def run(command, options={})
|
10
|
+
@log.debug("running command: '#{command.inspect}'")
|
11
|
+
|
12
|
+
options[:capture] = !!options[:capture]
|
13
|
+
options[:env] = options.fetch(:env, ENV)
|
14
|
+
|
15
|
+
rout, wout = IO.pipe
|
16
|
+
rerr, werr = IO.pipe
|
17
|
+
pid = Process.spawn(options[:env], Shellwords.join(command), :out => wout, :err => werr)
|
18
|
+
|
19
|
+
Process.wait(pid)
|
20
|
+
status = $?.exitstatus
|
21
|
+
|
22
|
+
# capture stdout/stderr
|
23
|
+
wout.close
|
24
|
+
werr.close
|
25
|
+
stdout = rout.read
|
26
|
+
stderr = rerr.read
|
27
|
+
|
28
|
+
@log.linewise(stdout, :level => :info)
|
29
|
+
@log.linewise(stderr)
|
30
|
+
|
31
|
+
return options[:capture] ? [stdout, stderr, status] : status
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/flintlock/util.rb
CHANGED
@@ -1,27 +1,63 @@
|
|
1
|
+
require 'flintlock/logger'
|
2
|
+
|
1
3
|
module Flintlock
|
4
|
+
class DependencyError < RuntimeError; end
|
5
|
+
|
2
6
|
class Util
|
3
7
|
def self.empty_directory?(directory)
|
4
8
|
Dir[File.join(directory, '*')].empty?
|
5
9
|
end
|
6
10
|
|
7
|
-
def self.supported_archives
|
8
|
-
['.tar.gz', '.tar']
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.supported_archive?(filename)
|
12
|
-
Util.supported_archives.include?(full_extname(filename))
|
13
|
-
end
|
14
|
-
|
15
11
|
def self.full_extname(filename)
|
16
12
|
data = []
|
17
13
|
current_filename = filename.dup
|
18
14
|
while true
|
19
15
|
ext = File.extname(current_filename)
|
20
|
-
break if ext.empty?
|
16
|
+
break if ext.empty? || ext =~ /^\.\d+$/
|
21
17
|
current_filename = current_filename.gsub(/#{ext}$/, '')
|
22
18
|
data << ext
|
23
19
|
end
|
24
20
|
data.reverse.join
|
25
21
|
end
|
22
|
+
|
23
|
+
def self.which(command)
|
24
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
25
|
+
exe = File.join(path, command)
|
26
|
+
return exe if File.executable?(exe)
|
27
|
+
end
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.get_uri_scheme(uri)
|
32
|
+
scheme = URI.parse(uri).scheme
|
33
|
+
return scheme.nil? ? nil : scheme.split('+', 0)[0]
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.load_logger(debug = false)
|
37
|
+
log = Logger.new(STDOUT)
|
38
|
+
log.silence! if ! debug
|
39
|
+
log
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.detect_runtime(script, default="/bin/sh")
|
43
|
+
raw = File.open(script, &:readline)[/^\s*#!\s*(.+)/, 1] || default
|
44
|
+
raw.split
|
45
|
+
rescue EOFError
|
46
|
+
[default]
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.path_split(path)
|
50
|
+
path.split(File::SEPARATOR).select { |x| ! x.empty? }
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.depends_on(what)
|
54
|
+
raise DependencyError.new(what) if which(what).nil?
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.mime_type(filename)
|
58
|
+
depends_on 'file'
|
59
|
+
stdout, stderr, status = Runner.new.run(['file', '--mime-type', filename], :capture => true)
|
60
|
+
stdout.split(':')[1].strip
|
61
|
+
end
|
26
62
|
end
|
27
63
|
end
|
data/lib/flintlock/version.rb
CHANGED
metadata
CHANGED
@@ -1,89 +1,135 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: flintlock
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
6
11
|
platform: ruby
|
7
|
-
authors:
|
12
|
+
authors:
|
8
13
|
- Jon McKenzie
|
9
14
|
autorequire:
|
10
15
|
bindir: bin
|
11
16
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
|
17
|
+
|
18
|
+
date: 2014-06-03 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
15
22
|
name: thor
|
16
|
-
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
|
-
requirements:
|
19
|
-
- - ! '>='
|
20
|
-
- !ruby/object:Gem::Version
|
21
|
-
version: '0'
|
22
|
-
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
|
-
requirements:
|
27
|
-
- -
|
28
|
-
- !ruby/object:Gem::Version
|
29
|
-
|
30
|
-
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
- !ruby/object:Gem::Dependency
|
31
36
|
name: json
|
32
|
-
|
37
|
+
prerelease: false
|
38
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
33
39
|
none: false
|
34
|
-
requirements:
|
35
|
-
- -
|
36
|
-
- !ruby/object:Gem::Version
|
37
|
-
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
hash: 3
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
38
47
|
type: :runtime
|
48
|
+
version_requirements: *id002
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: rspec
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
hash: 3
|
58
|
+
segments:
|
59
|
+
- 0
|
60
|
+
version: "0"
|
61
|
+
type: :development
|
62
|
+
version_requirements: *id003
|
63
|
+
- !ruby/object:Gem::Dependency
|
64
|
+
name: fakefs
|
39
65
|
prerelease: false
|
40
|
-
|
66
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
41
67
|
none: false
|
42
|
-
requirements:
|
43
|
-
- -
|
44
|
-
- !ruby/object:Gem::Version
|
45
|
-
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
hash: 3
|
72
|
+
segments:
|
73
|
+
- 0
|
74
|
+
version: "0"
|
75
|
+
type: :development
|
76
|
+
version_requirements: *id004
|
46
77
|
description: A simple application deployer inspired by Heroku's buildpacks
|
47
78
|
email: jcmcken@gmail.com
|
48
|
-
executables:
|
79
|
+
executables:
|
49
80
|
- flintlock
|
50
81
|
extensions: []
|
82
|
+
|
51
83
|
extra_rdoc_files: []
|
52
|
-
|
84
|
+
|
85
|
+
files:
|
53
86
|
- lib/flintlock.rb
|
54
87
|
- lib/flintlock/module.rb
|
55
88
|
- lib/flintlock/metadata.rb
|
56
89
|
- lib/flintlock/util.rb
|
57
90
|
- lib/flintlock/cli.rb
|
58
91
|
- lib/flintlock/logger.rb
|
92
|
+
- lib/flintlock/runner.rb
|
59
93
|
- lib/flintlock/version.rb
|
60
94
|
- LICENSE
|
61
95
|
- README.md
|
62
96
|
- CHANGES.md
|
63
97
|
- bin/flintlock
|
98
|
+
has_rdoc: true
|
64
99
|
homepage: https://github.com/jcmcken/flintlock
|
65
|
-
licenses:
|
100
|
+
licenses:
|
66
101
|
- MIT
|
67
102
|
post_install_message:
|
68
103
|
rdoc_options: []
|
69
|
-
|
104
|
+
|
105
|
+
require_paths:
|
70
106
|
- lib
|
71
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
72
108
|
none: false
|
73
|
-
requirements:
|
74
|
-
- -
|
75
|
-
- !ruby/object:Gem::Version
|
109
|
+
requirements:
|
110
|
+
- - ">="
|
111
|
+
- !ruby/object:Gem::Version
|
112
|
+
hash: 53
|
113
|
+
segments:
|
114
|
+
- 1
|
115
|
+
- 9
|
116
|
+
- 3
|
76
117
|
version: 1.9.3
|
77
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
119
|
none: false
|
79
|
-
requirements:
|
80
|
-
- -
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
hash: 3
|
124
|
+
segments:
|
125
|
+
- 0
|
126
|
+
version: "0"
|
83
127
|
requirements: []
|
128
|
+
|
84
129
|
rubyforge_project:
|
85
|
-
rubygems_version: 1.
|
130
|
+
rubygems_version: 1.3.7
|
86
131
|
signing_key:
|
87
132
|
specification_version: 3
|
88
133
|
summary: A simple application deployer
|
89
134
|
test_files: []
|
135
|
+
|