r10k 0.0.1rc1 → 0.0.1
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/bin/r10k +13 -1
- data/lib/r10k.rb +1 -0
- data/lib/r10k/action.rb +7 -0
- data/lib/r10k/action/environment.rb +74 -0
- data/lib/r10k/action/module.rb +36 -0
- data/lib/r10k/cli.rb +9 -0
- data/lib/r10k/cli/{environment/cache.rb → cache.rb} +13 -4
- data/lib/r10k/cli/environment.rb +1 -3
- data/lib/r10k/cli/environment/deploy.rb +19 -17
- data/lib/r10k/cli/environment/stale.rb +34 -0
- data/lib/r10k/cli/module/deploy.rb +12 -12
- data/lib/r10k/cli/synchronize.rb +45 -0
- data/lib/r10k/deployment.rb +7 -4
- data/lib/r10k/{environment_collection.rb → deployment/environment_collection.rb} +20 -4
- data/lib/r10k/errors.rb +7 -0
- data/lib/r10k/logging.rb +49 -0
- data/lib/r10k/module/forge.rb +68 -3
- data/lib/r10k/synchro/git.rb +74 -34
- data/lib/r10k/version.rb +1 -1
- data/lib/semver.rb +124 -0
- metadata +71 -15
data/bin/r10k
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'r10k/cli'
|
4
|
+
require 'colored'
|
4
5
|
|
5
|
-
|
6
|
+
begin
|
7
|
+
R10K::CLI.command.run(ARGV)
|
8
|
+
rescue Interrupt
|
9
|
+
$stderr.puts "Aborted!".red
|
10
|
+
exit(1)
|
11
|
+
rescue SystemExit => e
|
12
|
+
exit(e.status)
|
13
|
+
rescue Exception => e
|
14
|
+
$stderr.puts "\nRuntime error: #{e.inspect}".red
|
15
|
+
$stderr.puts e.backtrace.join("\n").red if ARGV.include? '--trace'
|
16
|
+
exit(1)
|
17
|
+
end
|
data/lib/r10k.rb
CHANGED
data/lib/r10k/action.rb
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'r10k/action'
|
2
|
+
require 'r10k/errors'
|
3
|
+
require 'r10k/action/module'
|
4
|
+
require 'r10k/deployment'
|
5
|
+
require 'r10k/logging'
|
6
|
+
|
7
|
+
require 'middleware'
|
8
|
+
|
9
|
+
module R10K::Action::Environment
|
10
|
+
|
11
|
+
class Deploy
|
12
|
+
# Middleware action to deploy an environment
|
13
|
+
|
14
|
+
include R10K::Logging
|
15
|
+
|
16
|
+
# @param [Object] app The next application in the middlware stack
|
17
|
+
# @param [R10K::Module] mod The module to deploy
|
18
|
+
def initialize(app, root)
|
19
|
+
@app, @root = app, root
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [Hash] env
|
23
|
+
#
|
24
|
+
# @option env [true, false] :update_cache
|
25
|
+
# @option env [true, false] :recurse
|
26
|
+
# @option env [true, false] :trace
|
27
|
+
def call(env)
|
28
|
+
@env = env
|
29
|
+
|
30
|
+
logger.notice "Deploying environment #{@root.name}"
|
31
|
+
FileUtils.mkdir_p @root.full_path
|
32
|
+
@root.sync! :update_cache => @env[:update_cache]
|
33
|
+
|
34
|
+
if @env[:recurse]
|
35
|
+
# Build a new middleware chain and run it
|
36
|
+
stack = Middleware::Builder.new
|
37
|
+
@root.modules.each { |mod| stack.use R10K::Action::Module::Deploy, mod }
|
38
|
+
stack.call(@env)
|
39
|
+
end
|
40
|
+
|
41
|
+
@app.call(@env)
|
42
|
+
rescue R10K::ExecutionFailure => e
|
43
|
+
logger.error "Could not synchronize #{@root.full_path}: #{e}".red
|
44
|
+
$stderr.puts e.backtrace.join("\n").red if @env[:trace]
|
45
|
+
@app.call(@env)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class Purge
|
50
|
+
# Middleware action to purge stale environments from a directory
|
51
|
+
|
52
|
+
include R10K::Logging
|
53
|
+
|
54
|
+
# @param [Object] app The next application in the middlware stack
|
55
|
+
# @param [String] path The directory path to purge
|
56
|
+
def initialize(app, path)
|
57
|
+
@app, @path = app, path
|
58
|
+
end
|
59
|
+
|
60
|
+
# @param [Hash] env
|
61
|
+
def call(env)
|
62
|
+
@env = env
|
63
|
+
|
64
|
+
stale_directories = R10K::Deployment.instance.collection.stale(@path)
|
65
|
+
|
66
|
+
stale_directories.each do |dir|
|
67
|
+
logger.notice "Purging stale environment #{dir.inspect}"
|
68
|
+
FileUtils.rm_rf(dir, :secure => true)
|
69
|
+
end
|
70
|
+
|
71
|
+
@app.call(@env)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'r10k/action'
|
2
|
+
require 'r10k/errors'
|
3
|
+
require 'r10k/logging'
|
4
|
+
|
5
|
+
require 'middleware'
|
6
|
+
|
7
|
+
module R10K::Action::Module
|
8
|
+
|
9
|
+
class R10K::Action::Module::Deploy
|
10
|
+
# Middleware to deploy a module
|
11
|
+
|
12
|
+
include R10K::Logging
|
13
|
+
|
14
|
+
# @param [Object] app The next application in the middlware stack
|
15
|
+
# @param [R10K::Module] mod The module to deploy
|
16
|
+
def initialize(app, mod)
|
17
|
+
@app, @mod = app, mod
|
18
|
+
end
|
19
|
+
|
20
|
+
# @param [Hash] env
|
21
|
+
#
|
22
|
+
# @option env [true, false] :update_cache
|
23
|
+
def call(env)
|
24
|
+
@env = env
|
25
|
+
|
26
|
+
logger.notice "Deploying module #{@mod.name}"
|
27
|
+
@mod.sync! :update_cache => @env[:update_cache]
|
28
|
+
|
29
|
+
@app.call(@env)
|
30
|
+
rescue R10K::ExecutionFailure => e
|
31
|
+
logger.error "Could not synchronize #{@mod.full_path}: #{e}".red
|
32
|
+
$stderr.puts e.backtrace.join("\n").red if @env[:trace]
|
33
|
+
@app.call(@env)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/r10k/cli.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'r10k'
|
2
|
+
require 'r10k/logging'
|
2
3
|
require 'cri'
|
3
4
|
|
4
5
|
module R10K::CLI
|
@@ -21,6 +22,12 @@ module R10K::CLI
|
|
21
22
|
R10K::Deployment.instance.configfile = value
|
22
23
|
end
|
23
24
|
|
25
|
+
required :v, :verbose, 'Set verbosity level' do |value, cmd|
|
26
|
+
R10K::Logging.level = Integer(value)
|
27
|
+
end
|
28
|
+
|
29
|
+
flag :t, :trace, 'Display stack traces on application crash'
|
30
|
+
|
24
31
|
run do |opts, args, cmd|
|
25
32
|
puts cmd.help
|
26
33
|
exit 0
|
@@ -31,3 +38,5 @@ end
|
|
31
38
|
|
32
39
|
require 'r10k/cli/environment'
|
33
40
|
require 'r10k/cli/module'
|
41
|
+
require 'r10k/cli/cache'
|
42
|
+
require 'r10k/cli/synchronize'
|
@@ -1,8 +1,8 @@
|
|
1
|
-
require 'r10k/cli
|
1
|
+
require 'r10k/cli'
|
2
2
|
require 'r10k/synchro/git'
|
3
3
|
require 'cri'
|
4
4
|
|
5
|
-
module R10K::CLI
|
5
|
+
module R10K::CLI
|
6
6
|
module Cache
|
7
7
|
def self.command
|
8
8
|
@cmd ||= Cri::Command.define do
|
@@ -11,8 +11,17 @@ module R10K::CLI::Environment
|
|
11
11
|
summary 'Update cache for all sources'
|
12
12
|
|
13
13
|
run do |opts, args, cmd|
|
14
|
-
R10K::Deployment.instance[:sources]
|
15
|
-
|
14
|
+
sources = R10K::Deployment.instance[:sources]
|
15
|
+
|
16
|
+
remotes = Set.new
|
17
|
+
|
18
|
+
sources.each_pair do |name, hash|
|
19
|
+
remotes << hash['remote']
|
20
|
+
end
|
21
|
+
|
22
|
+
remotes.each do |remote|
|
23
|
+
puts "Synchronizing #{remote}"
|
24
|
+
synchro = R10K::Synchro::Git.new(remote)
|
16
25
|
synchro.cache
|
17
26
|
end
|
18
27
|
end
|
data/lib/r10k/cli/environment.rb
CHANGED
@@ -9,8 +9,6 @@ module R10K::CLI
|
|
9
9
|
usage 'environment <subcommand>'
|
10
10
|
summary 'Operate on a specific environment'
|
11
11
|
|
12
|
-
required :e, :environment, 'Specify a particular environment'
|
13
|
-
|
14
12
|
run do |opts, args, cmd|
|
15
13
|
puts cmd.help
|
16
14
|
exit 0
|
@@ -23,4 +21,4 @@ end
|
|
23
21
|
|
24
22
|
require 'r10k/cli/environment/list'
|
25
23
|
require 'r10k/cli/environment/deploy'
|
26
|
-
require 'r10k/cli/environment/
|
24
|
+
require 'r10k/cli/environment/stale'
|
@@ -1,43 +1,45 @@
|
|
1
1
|
require 'r10k/cli/environment'
|
2
2
|
require 'r10k/deployment'
|
3
|
-
require '
|
3
|
+
require 'r10k/action'
|
4
4
|
|
5
|
-
require '
|
5
|
+
require 'cri'
|
6
|
+
require 'middleware'
|
6
7
|
|
7
8
|
module R10K::CLI::Environment
|
8
9
|
module Deploy
|
9
10
|
def self.command
|
10
11
|
@cmd ||= Cri::Command.define do
|
11
12
|
name 'deploy'
|
12
|
-
usage 'deploy'
|
13
|
+
usage 'deploy <environment> <...>'
|
13
14
|
summary 'Deploy an environment'
|
14
15
|
|
15
16
|
flag :r, :recurse, 'Recursively update submodules'
|
16
|
-
|
17
|
-
required :u, :update, "Enable or disable cache updating"
|
17
|
+
flag :u, :update, "Enable or disable cache updating"
|
18
18
|
|
19
19
|
run do |opts, args, cmd|
|
20
20
|
deployment = R10K::Deployment.instance
|
21
21
|
env_list = deployment.environments
|
22
22
|
|
23
|
-
|
24
|
-
|
25
|
-
if opts[:environment]
|
26
|
-
environments = env_list.select {|env| env.name == opts[:environment]}
|
23
|
+
if not args.empty?
|
24
|
+
environments = env_list.select {|env| args.include? env.name }
|
27
25
|
else
|
28
26
|
environments = env_list
|
29
27
|
end
|
30
28
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if opts[:recurse]
|
36
|
-
env.modules.each do |mod|
|
37
|
-
mod.sync! :update_cache => update_cache
|
38
|
-
end
|
29
|
+
stack = Middleware::Builder.new do
|
30
|
+
environments.each do |env|
|
31
|
+
use R10K::Action::Environment::Deploy, env
|
39
32
|
end
|
40
33
|
end
|
34
|
+
|
35
|
+
# Prepare middleware environment
|
36
|
+
stack_env = {
|
37
|
+
:update_cache => opts[:update],
|
38
|
+
:recurse => opts[:recurse],
|
39
|
+
:trace => opts[:trace],
|
40
|
+
}
|
41
|
+
|
42
|
+
stack.call(stack_env)
|
41
43
|
end
|
42
44
|
end
|
43
45
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'r10k/cli/environment'
|
2
|
+
require 'r10k/deployment'
|
3
|
+
require 'cri'
|
4
|
+
|
5
|
+
module R10K::CLI::Environment
|
6
|
+
module Stale
|
7
|
+
def self.command
|
8
|
+
@cmd ||= Cri::Command.define do
|
9
|
+
name 'stale'
|
10
|
+
usage 'stale <directory> [directory ...]'
|
11
|
+
summary 'List all stale environments'
|
12
|
+
|
13
|
+
run do |opts, args, cmd|
|
14
|
+
deployment = R10K::Deployment.instance
|
15
|
+
|
16
|
+
if args.empty?
|
17
|
+
$stderr.print "ERROR: ".red
|
18
|
+
$stderr.puts "#{cmd.name} requires one or more directories"
|
19
|
+
$stderr.puts cmd.help
|
20
|
+
exit(1)
|
21
|
+
end
|
22
|
+
|
23
|
+
args.each do |dir|
|
24
|
+
puts "Stale environments in #{dir}:"
|
25
|
+
output = deployment.collection.stale(dir).each do |stale_dir|
|
26
|
+
puts " - #{stale_dir}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
self.command.add_command(Stale.command)
|
34
|
+
end
|
@@ -9,10 +9,10 @@ module R10K::CLI::Module
|
|
9
9
|
def self.command
|
10
10
|
@cmd ||= Cri::Command.define do
|
11
11
|
name 'deploy'
|
12
|
-
usage 'deploy <module name>'
|
12
|
+
usage 'deploy [module name] <module name> ...'
|
13
13
|
summary 'Deploy a module'
|
14
14
|
|
15
|
-
|
15
|
+
flag :u, :update, "Update module cache"
|
16
16
|
|
17
17
|
run do |opts, args, cmd|
|
18
18
|
|
@@ -21,10 +21,7 @@ module R10K::CLI::Module
|
|
21
21
|
exit 1
|
22
22
|
end
|
23
23
|
|
24
|
-
|
25
|
-
env_list = deployment.environments
|
26
|
-
|
27
|
-
update_cache = (defined? opts[:update]) ? (opts[:update] == 'true') : false
|
24
|
+
env_list = R10K::Deployment.instance.environments
|
28
25
|
|
29
26
|
if opts[:environment]
|
30
27
|
environments = env_list.select {|env| env.name == opts[:environment]}
|
@@ -33,9 +30,6 @@ module R10K::CLI::Module
|
|
33
30
|
end
|
34
31
|
|
35
32
|
environments.each do |env|
|
36
|
-
FileUtils.mkdir_p env.full_path
|
37
|
-
env.sync! :update_cache => update_cache
|
38
|
-
|
39
33
|
mods = env.modules.select { |mod| mod.name == module_name }
|
40
34
|
|
41
35
|
if mods.empty?
|
@@ -43,9 +37,15 @@ module R10K::CLI::Module
|
|
43
37
|
exit 1
|
44
38
|
end
|
45
39
|
|
46
|
-
|
47
|
-
|
48
|
-
|
40
|
+
stack = Middleware::Builder.new
|
41
|
+
mods.each { |mod| stack.use R10K::Action::Module::Deploy, mod }
|
42
|
+
|
43
|
+
stack_env = {
|
44
|
+
:update_cache => opts[:update],
|
45
|
+
:trace => opts[:trace],
|
46
|
+
}
|
47
|
+
|
48
|
+
stack.call(stack_env)
|
49
49
|
end
|
50
50
|
end
|
51
51
|
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'r10k/cli'
|
2
|
+
require 'r10k/deployment'
|
3
|
+
require 'r10k/action/environment'
|
4
|
+
|
5
|
+
require 'middleware'
|
6
|
+
require 'cri'
|
7
|
+
|
8
|
+
module R10K::CLI
|
9
|
+
module Synchronize
|
10
|
+
def self.command
|
11
|
+
@cmd ||= Cri::Command.define do
|
12
|
+
name 'synchronize'
|
13
|
+
usage 'synchronize <options>'
|
14
|
+
summary 'Fully synchronize all environments'
|
15
|
+
|
16
|
+
flag :u, :update, "Update cache before running"
|
17
|
+
|
18
|
+
run do |opts, args, cmd|
|
19
|
+
deployment = R10K::Deployment.instance
|
20
|
+
environments = deployment.environments
|
21
|
+
directories = (deployment.config[:purgedirs] || [])
|
22
|
+
|
23
|
+
stack = Middleware::Builder.new do
|
24
|
+
environments.each do |env|
|
25
|
+
use R10K::Action::Environment::Deploy, env
|
26
|
+
end
|
27
|
+
|
28
|
+
directories.each do |dir|
|
29
|
+
use R10K::Action::Environment::Purge, dir
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
stack_env = {
|
34
|
+
:update_cache => opts[:update],
|
35
|
+
:trace => opts[:trace],
|
36
|
+
:recurse => true,
|
37
|
+
}
|
38
|
+
|
39
|
+
stack.call(stack_env)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
self.command.add_command(Synchronize.command)
|
45
|
+
end
|
data/lib/r10k/deployment.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'r10k'
|
2
2
|
require 'r10k/synchro/git'
|
3
|
-
require 'r10k/environment_collection'
|
3
|
+
require 'r10k/deployment/environment_collection'
|
4
4
|
require 'yaml'
|
5
5
|
|
6
6
|
class R10K::Deployment
|
@@ -21,10 +21,14 @@ class R10K::Deployment
|
|
21
21
|
#
|
22
22
|
# @return [Array<R10K::Root>]
|
23
23
|
def environments
|
24
|
-
collection = R10K::EnvironmentCollection.new(config)
|
25
24
|
collection.to_a
|
26
25
|
end
|
27
26
|
|
27
|
+
def collection
|
28
|
+
load_config unless @config
|
29
|
+
@collection
|
30
|
+
end
|
31
|
+
|
28
32
|
# Serve up the loaded config if it's already been loaded, otherwise try to
|
29
33
|
# load a config in the current wd.
|
30
34
|
def config
|
@@ -47,8 +51,6 @@ class R10K::Deployment
|
|
47
51
|
File.open(@configfile) { |fh| @config = YAML.load(fh.read) }
|
48
52
|
apply_config_settings
|
49
53
|
@config
|
50
|
-
rescue => e
|
51
|
-
raise "Couldn't load #{configfile}: #{e}"
|
52
54
|
end
|
53
55
|
|
54
56
|
# Apply config settings to the relevant classes after a config has been loaded.
|
@@ -56,5 +58,6 @@ class R10K::Deployment
|
|
56
58
|
if @config[:cachedir]
|
57
59
|
R10K::Synchro::Git.cache_root = @config[:cachedir]
|
58
60
|
end
|
61
|
+
@collection = R10K::EnvironmentCollection.new(@config)
|
59
62
|
end
|
60
63
|
end
|
@@ -4,15 +4,22 @@ class R10K::EnvironmentCollection
|
|
4
4
|
|
5
5
|
attr_reader :update_cache
|
6
6
|
|
7
|
-
def initialize(config, options = {:update_cache =>
|
7
|
+
def initialize(config, options = {:update_cache => false})
|
8
8
|
@config = config
|
9
9
|
@environments = []
|
10
10
|
|
11
11
|
@update_cache = options.delete(:update_cache)
|
12
|
-
|
13
12
|
load_all
|
14
13
|
end
|
15
14
|
|
15
|
+
def current(basedir)
|
16
|
+
basedir = File.expand_path(basedir)
|
17
|
+
tracked_envs = @environments.select do |env|
|
18
|
+
envdir = File.expand_path(env.basedir)
|
19
|
+
envdir == basedir
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
16
23
|
# List subdirectories that aren't associated with an env
|
17
24
|
#
|
18
25
|
# If a branch associated with an environment is deleted then the associated
|
@@ -23,8 +30,17 @@ class R10K::EnvironmentCollection
|
|
23
30
|
# @param [String] basedir The directory to scan
|
24
31
|
#
|
25
32
|
# @return [Array<String>] A list of filenames
|
26
|
-
def
|
27
|
-
|
33
|
+
def stale(basedir)
|
34
|
+
basedir = File.expand_path(basedir)
|
35
|
+
|
36
|
+
all_dirs = Dir.glob("#{basedir}/*").map do |file|
|
37
|
+
File.basename(file) if File.directory?(file)
|
38
|
+
end.compact
|
39
|
+
current_dirs = current(basedir).map(&:name)
|
40
|
+
|
41
|
+
stale_dirs = all_dirs - current_dirs
|
42
|
+
|
43
|
+
stale_dirs.map {|dir| File.join(basedir, dir)}
|
28
44
|
end
|
29
45
|
|
30
46
|
# @return [Array<R10K::Root>]
|
data/lib/r10k/errors.rb
ADDED
data/lib/r10k/logging.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'r10k'
|
2
|
+
|
3
|
+
require 'log4r'
|
4
|
+
require 'log4r/configurator'
|
5
|
+
|
6
|
+
module R10K::Logging
|
7
|
+
|
8
|
+
include Log4r
|
9
|
+
|
10
|
+
def logger
|
11
|
+
unless @logger
|
12
|
+
@logger = Log4r::Logger.new(self.class.name)
|
13
|
+
@logger.add R10K::Logging.outputter
|
14
|
+
end
|
15
|
+
@logger
|
16
|
+
end
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
include Log4r
|
21
|
+
def included(klass)
|
22
|
+
unless @log4r_loaded
|
23
|
+
Configurator.custom_levels(*%w{DEBUG2 DEBUG1 DEBUG INFO NOTICE WARN ERROR FATAL})
|
24
|
+
Logger.global.level = Log4r::ALL
|
25
|
+
@log4r_loaded = true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def level
|
30
|
+
@level || Log4r::WARN # Default level is WARN
|
31
|
+
end
|
32
|
+
|
33
|
+
def level=(val)
|
34
|
+
outputter.level = val
|
35
|
+
@level = val
|
36
|
+
end
|
37
|
+
|
38
|
+
def formatter
|
39
|
+
@formatter ||= Log4r::PatternFormatter.new(:pattern => '[%C - %l] %m')
|
40
|
+
end
|
41
|
+
|
42
|
+
def outputter
|
43
|
+
@outputter ||= Log4r::StderrOutputter.new('console',
|
44
|
+
:level => self.level,
|
45
|
+
:formatter => formatter
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/r10k/module/forge.rb
CHANGED
@@ -1,19 +1,84 @@
|
|
1
1
|
require 'r10k'
|
2
2
|
require 'r10k/module'
|
3
|
+
require 'r10k/errors'
|
4
|
+
require 'r10k/logging'
|
5
|
+
|
6
|
+
require 'systemu'
|
7
|
+
require 'semver'
|
8
|
+
require 'json'
|
3
9
|
|
4
10
|
class R10K::Module::Forge < R10K::Module
|
5
11
|
|
6
12
|
def self.implements(name, args)
|
7
|
-
args.is_a? String and args
|
13
|
+
args.is_a? String and SemVer.valid?(args)
|
8
14
|
end
|
9
15
|
|
16
|
+
include R10K::Logging
|
17
|
+
|
10
18
|
def initialize(name, path, args)
|
11
19
|
super
|
12
20
|
|
13
|
-
@
|
21
|
+
@full_name = name
|
22
|
+
|
23
|
+
@owner, @name = name.split('/')
|
24
|
+
@version = SemVer.new(@args)
|
14
25
|
end
|
15
26
|
|
16
27
|
def sync!(options = {})
|
17
|
-
|
28
|
+
return if insync?
|
29
|
+
|
30
|
+
if insync?
|
31
|
+
logger.debug1 "Module #{@full_name} already matches version #{@version}"
|
32
|
+
elsif File.exist? metadata_path
|
33
|
+
logger.debug "Module #{@full_name} is installed but doesn't match version #{@version}, upgrading"
|
34
|
+
cmd = []
|
35
|
+
cmd << 'upgrade'
|
36
|
+
cmd << "--version=#{@version}"
|
37
|
+
cmd << "--ignore-dependencies"
|
38
|
+
cmd << @full_name
|
39
|
+
pmt cmd
|
40
|
+
else
|
41
|
+
logger.debug "Module #{@full_name} is not installed"
|
42
|
+
cmd = []
|
43
|
+
cmd << 'install'
|
44
|
+
cmd << "--version=#{@version}"
|
45
|
+
cmd << "--ignore-dependencies"
|
46
|
+
cmd << @full_name
|
47
|
+
pmt cmd
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def current_version
|
54
|
+
SemVer.new(metadata['version'])
|
55
|
+
end
|
56
|
+
|
57
|
+
def insync?
|
58
|
+
@version == current_version
|
59
|
+
rescue
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def metadata
|
64
|
+
JSON.parse(File.read(metadata_path))
|
65
|
+
end
|
66
|
+
|
67
|
+
def metadata_path
|
68
|
+
File.join(full_path, 'metadata.json')
|
69
|
+
end
|
70
|
+
|
71
|
+
def pmt(args)
|
72
|
+
cmd = "puppet module --modulepath '#{@path}' #{args.join(' ')}"
|
73
|
+
logger.debug1 "Execute: #{cmd}"
|
74
|
+
status, stdout, stderr = systemu(cmd)
|
75
|
+
unless status == 0
|
76
|
+
e = R10K::ExecutionFailure.new("#{cmd.inspect} returned with non-zero exit value #{status.inspect}")
|
77
|
+
e.exit_code = status
|
78
|
+
e.stdout = stdout
|
79
|
+
e.stderr = stderr
|
80
|
+
raise e
|
81
|
+
end
|
82
|
+
stdout
|
18
83
|
end
|
19
84
|
end
|
data/lib/r10k/synchro/git.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'r10k'
|
2
|
-
require '
|
2
|
+
require 'r10k/errors'
|
3
|
+
require 'r10k/logging'
|
4
|
+
|
5
|
+
require 'systemu'
|
3
6
|
require 'fileutils'
|
4
7
|
|
5
8
|
module R10K::Synchro; end
|
@@ -39,6 +42,8 @@ class R10K::Synchro::Git
|
|
39
42
|
end
|
40
43
|
end
|
41
44
|
|
45
|
+
include R10K::Logging
|
46
|
+
|
42
47
|
attr_reader :remote
|
43
48
|
|
44
49
|
# Instantiates a new git synchro and optionally prepares for caching
|
@@ -48,7 +53,7 @@ class R10K::Synchro::Git
|
|
48
53
|
@remote = remote
|
49
54
|
|
50
55
|
if self.class.cache_root
|
51
|
-
@cache_path = File.join(self.class.cache_root, @remote.gsub(/[^@\w
|
56
|
+
@cache_path = File.join(self.class.cache_root, @remote.gsub(/[^@\w\.-]/, '-'))
|
52
57
|
end
|
53
58
|
end
|
54
59
|
|
@@ -69,7 +74,7 @@ class R10K::Synchro::Git
|
|
69
74
|
end
|
70
75
|
|
71
76
|
# @return [TrueClass] if the git repository is cached
|
72
|
-
def
|
77
|
+
def cached?
|
73
78
|
@cache_path and File.directory? @cache_path
|
74
79
|
end
|
75
80
|
|
@@ -94,10 +99,13 @@ class R10K::Synchro::Git
|
|
94
99
|
|
95
100
|
# Force a cache refresh
|
96
101
|
def cache!
|
97
|
-
if
|
98
|
-
|
102
|
+
if cached?
|
103
|
+
logger.debug "Updating existing cache at #{@cache_path}"
|
104
|
+
git "fetch --prune", :git_dir => @cache_path
|
99
105
|
else
|
100
|
-
|
106
|
+
logger.debug "No cache for #{@remote.inspect}, forcing cache build"
|
107
|
+
cache_root = self.class.cache_root
|
108
|
+
FileUtils.mkdir_p cache_root unless File.exist? cache_root
|
101
109
|
git "clone --mirror #{@remote} #{@cache_path}"
|
102
110
|
end
|
103
111
|
end
|
@@ -106,9 +114,9 @@ class R10K::Synchro::Git
|
|
106
114
|
# object.
|
107
115
|
#
|
108
116
|
# @return [Array<String>] A list of all cached remote branches
|
109
|
-
def branches
|
110
|
-
cache
|
111
|
-
output = git "
|
117
|
+
def branches(options = {:update_cache => false})
|
118
|
+
cache if (options[:update_cache] or not cached?)
|
119
|
+
output = git "branch", :git_dir => @cache_path
|
112
120
|
output.split("\n").map { |str| str[2..-1] }
|
113
121
|
end
|
114
122
|
|
@@ -121,8 +129,9 @@ class R10K::Synchro::Git
|
|
121
129
|
#
|
122
130
|
# @param [String] path The directory to create the repo working directory
|
123
131
|
def clone(path)
|
124
|
-
if
|
132
|
+
if cached?
|
125
133
|
git "clone --reference #{@cache_path} #{@remote} #{path}"
|
134
|
+
git "remote add cache #{@cache_path}", :path => path
|
126
135
|
else
|
127
136
|
FileUtils.mkdir_p path unless File.directory? path
|
128
137
|
git "clone #{@remote} #{path}"
|
@@ -130,10 +139,10 @@ class R10K::Synchro::Git
|
|
130
139
|
end
|
131
140
|
|
132
141
|
def fetch(path)
|
133
|
-
if
|
134
|
-
git "fetch --prune
|
142
|
+
if cached?
|
143
|
+
git "fetch --prune cache", :path => path
|
135
144
|
else
|
136
|
-
git "fetch --prune", path
|
145
|
+
git "fetch --prune origin", :path => path
|
137
146
|
end
|
138
147
|
end
|
139
148
|
|
@@ -142,45 +151,76 @@ class R10K::Synchro::Git
|
|
142
151
|
# @param [String] path The path to the working directory of the git repo
|
143
152
|
# @param [String] ref The git reference to reset to.
|
144
153
|
def reset(path, ref)
|
154
|
+
commit = resolve_commit(ref)
|
145
155
|
|
146
|
-
# Helloooo, hackery. Try to parse the ref as a commit object. If that fails
|
147
|
-
# this probably means that the ref is a remote branch. For the sake of
|
148
|
-
# brevity this code blindly makes that assumption on the failure of
|
149
|
-
# `git rev-parse`.
|
150
156
|
begin
|
151
|
-
|
152
|
-
rescue
|
153
|
-
commit
|
157
|
+
git "reset --hard #{commit}", :path => path
|
158
|
+
rescue R10K::ExecutionFailure => e
|
159
|
+
logger.error "Unable to locate commit object #{commit} in git repo #{path}"
|
160
|
+
raise
|
154
161
|
end
|
162
|
+
end
|
155
163
|
|
156
|
-
|
164
|
+
# Resolve a ref to a commit hash
|
165
|
+
#
|
166
|
+
# @param [String] ref
|
167
|
+
#
|
168
|
+
# @return [String] The dereferenced hash of `ref`
|
169
|
+
def resolve_commit(ref)
|
170
|
+
commit = git "rev-parse #{ref}^{commit}", :git_dir => @cache_path
|
171
|
+
commit.chomp
|
172
|
+
rescue R10K::ExecutionFailure => e
|
173
|
+
logger.error "Could not resolve ref #{ref.inspect} for git cache #{@cache_path}"
|
174
|
+
raise
|
157
175
|
end
|
158
176
|
|
159
177
|
# Wrap git commands
|
160
178
|
#
|
161
179
|
# @param [String] command_line_args The arguments for the git prompt
|
162
|
-
# @param [
|
180
|
+
# @param [Hash] opts
|
181
|
+
#
|
182
|
+
# @option opts [String] :git_dir
|
183
|
+
# @option opts [String] :work_tree
|
184
|
+
# @option opts [String] :work_tree
|
163
185
|
#
|
164
186
|
# @return [String] The git command output
|
165
|
-
def git(command_line_args,
|
166
|
-
args =
|
187
|
+
def git(command_line_args, opts = {})
|
188
|
+
args = %w{git}
|
167
189
|
|
168
|
-
|
169
|
-
|
170
|
-
|
190
|
+
log_event = "git #{command_line_args}"
|
191
|
+
log_event << ", args: #{opts.inspect}" unless opts.empty?
|
192
|
+
|
193
|
+
|
194
|
+
if opts[:path]
|
195
|
+
args << "--git-dir #{opts[:path]}/.git"
|
196
|
+
args << "--work-tree #{opts[:path]}"
|
197
|
+
else
|
198
|
+
if opts[:git_dir]
|
199
|
+
args << "--git-dir #{opts[:git_dir]}"
|
200
|
+
end
|
201
|
+
if opts[:work_tree]
|
202
|
+
args << "--work-tree #{opts[:work_tree]}"
|
203
|
+
end
|
171
204
|
end
|
172
205
|
|
173
|
-
|
206
|
+
logger.debug1 "Execute: '#{log_event}'"
|
174
207
|
|
175
|
-
|
176
|
-
|
208
|
+
args << command_line_args
|
209
|
+
cmd = args.join(' ')
|
177
210
|
|
178
|
-
stderr =
|
179
|
-
stdout = result.stdout.read
|
211
|
+
status, stdout, stderr = systemu(cmd)
|
180
212
|
|
181
|
-
|
182
|
-
|
213
|
+
logger.debug2 "[#{log_event}] STDOUT: #{stdout.chomp}" unless stdout.empty?
|
214
|
+
logger.debug2 "[#{log_event}] STDERR: #{stderr.chomp}" unless stderr.empty?
|
183
215
|
|
216
|
+
unless status == 0
|
217
|
+
msg = "#{cmd.inspect} returned with non-zero exit value #{status.exitstatus}"
|
218
|
+
e = R10K::ExecutionFailure.new(msg)
|
219
|
+
e.exit_code = status
|
220
|
+
e.stdout = stdout
|
221
|
+
e.stderr = stderr
|
222
|
+
raise e
|
223
|
+
end
|
184
224
|
stdout
|
185
225
|
end
|
186
226
|
end
|
data/lib/r10k/version.rb
CHANGED
data/lib/semver.rb
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
# Ripped off from puppetlabs/puppet
|
2
|
+
|
3
|
+
# We need to subclass Numeric to force range comparisons not to try to iterate over SemVer
|
4
|
+
# and instead use numeric comparisons (eg >, <, >=, <=)
|
5
|
+
# Ruby 1.8 already did this for all ranges, but Ruby 1.9 changed range include behavior
|
6
|
+
class SemVer < Numeric
|
7
|
+
include Comparable
|
8
|
+
|
9
|
+
VERSION = /^v?(\d+)\.(\d+)\.(\d+)(-[0-9A-Za-z-]*|)$/
|
10
|
+
SIMPLE_RANGE = /^v?(\d+|[xX])(?:\.(\d+|[xX])(?:\.(\d+|[xX]))?)?$/
|
11
|
+
|
12
|
+
def self.valid?(ver)
|
13
|
+
VERSION =~ ver
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.find_matching(pattern, versions)
|
17
|
+
versions.select { |v| v.matched_by?("#{pattern}") }.sort.last
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.pre(vstring)
|
21
|
+
vstring =~ /-/ ? vstring : vstring + '-'
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.[](range)
|
25
|
+
range.gsub(/([><=])\s+/, '\1').split(/\b\s+(?!-)/).map do |r|
|
26
|
+
case r
|
27
|
+
when SemVer::VERSION
|
28
|
+
SemVer.new(pre(r)) .. SemVer.new(r)
|
29
|
+
when SemVer::SIMPLE_RANGE
|
30
|
+
r += ".0" unless SemVer.valid?(r.gsub(/x/i, '0'))
|
31
|
+
SemVer.new(r.gsub(/x/i, '0'))...SemVer.new(r.gsub(/(\d+)\.x/i) { "#{$1.to_i + 1}.0" } + '-')
|
32
|
+
when /\s+-\s+/
|
33
|
+
a, b = r.split(/\s+-\s+/)
|
34
|
+
SemVer.new(pre(a)) .. SemVer.new(b)
|
35
|
+
when /^~/
|
36
|
+
ver = r.sub(/~/, '').split('.').map(&:to_i)
|
37
|
+
start = (ver + [0] * (3 - ver.length)).join('.')
|
38
|
+
|
39
|
+
ver.pop unless ver.length == 1
|
40
|
+
ver[-1] = ver.last + 1
|
41
|
+
|
42
|
+
finish = (ver + [0] * (3 - ver.length)).join('.')
|
43
|
+
SemVer.new(pre(start)) ... SemVer.new(pre(finish))
|
44
|
+
when /^>=/
|
45
|
+
ver = r.sub(/^>=/, '')
|
46
|
+
SemVer.new(pre(ver)) .. SemVer::MAX
|
47
|
+
when /^<=/
|
48
|
+
ver = r.sub(/^<=/, '')
|
49
|
+
SemVer::MIN .. SemVer.new(ver)
|
50
|
+
when /^>/
|
51
|
+
if r =~ /-/
|
52
|
+
ver = [r[1..-1]]
|
53
|
+
else
|
54
|
+
ver = r.sub(/^>/, '').split('.').map(&:to_i)
|
55
|
+
ver[2] = ver.last + 1
|
56
|
+
end
|
57
|
+
SemVer.new(ver.join('.') + '-') .. SemVer::MAX
|
58
|
+
when /^</
|
59
|
+
ver = r.sub(/^</, '')
|
60
|
+
SemVer::MIN ... SemVer.new(pre(ver))
|
61
|
+
else
|
62
|
+
(1..1)
|
63
|
+
end
|
64
|
+
end.inject { |a,e| a & e }
|
65
|
+
end
|
66
|
+
|
67
|
+
attr_reader :major, :minor, :tiny, :special
|
68
|
+
|
69
|
+
def initialize(ver)
|
70
|
+
unless SemVer.valid?(ver)
|
71
|
+
raise ArgumentError.new("Invalid version string '#{ver}'!")
|
72
|
+
end
|
73
|
+
|
74
|
+
@major, @minor, @tiny, @special = VERSION.match(ver).captures.map do |x|
|
75
|
+
# Because Kernel#Integer tries to interpret hex and octal strings, which
|
76
|
+
# we specifically do not want, and which cannot be overridden in 1.8.7.
|
77
|
+
Float(x).to_i rescue x
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def <=>(other)
|
82
|
+
other = SemVer.new("#{other}") unless other.is_a? SemVer
|
83
|
+
return self.major <=> other.major unless self.major == other.major
|
84
|
+
return self.minor <=> other.minor unless self.minor == other.minor
|
85
|
+
return self.tiny <=> other.tiny unless self.tiny == other.tiny
|
86
|
+
|
87
|
+
return 0 if self.special == other.special
|
88
|
+
return 1 if self.special == ''
|
89
|
+
return -1 if other.special == ''
|
90
|
+
|
91
|
+
return self.special <=> other.special
|
92
|
+
end
|
93
|
+
|
94
|
+
def matched_by?(pattern)
|
95
|
+
# For the time being, this is restricted to exact version matches and
|
96
|
+
# simple range patterns. In the future, we should implement some or all of
|
97
|
+
# the comparison operators here:
|
98
|
+
# https://github.com/isaacs/node-semver/blob/d474801/semver.js#L340
|
99
|
+
|
100
|
+
case pattern
|
101
|
+
when SIMPLE_RANGE
|
102
|
+
pattern = SIMPLE_RANGE.match(pattern).captures
|
103
|
+
pattern[1] = @minor unless pattern[1] && pattern[1] !~ /x/i
|
104
|
+
pattern[2] = @tiny unless pattern[2] && pattern[2] !~ /x/i
|
105
|
+
[@major, @minor, @tiny] == pattern.map { |x| x.to_i }
|
106
|
+
when VERSION
|
107
|
+
self == SemVer.new(pattern)
|
108
|
+
else
|
109
|
+
false
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def inspect
|
114
|
+
@vstring || "v#{@major}.#{@minor}.#{@tiny}#{@special}"
|
115
|
+
end
|
116
|
+
alias :to_s :inspect
|
117
|
+
|
118
|
+
MIN = SemVer.new('0.0.0-')
|
119
|
+
MIN.instance_variable_set(:@vstring, 'vMIN')
|
120
|
+
|
121
|
+
MAX = SemVer.new('8.0.0')
|
122
|
+
MAX.instance_variable_set(:@major, (1.0/0)) # => Infinity
|
123
|
+
MAX.instance_variable_set(:@vstring, 'vMAX')
|
124
|
+
end
|
metadata
CHANGED
@@ -1,16 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: r10k
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
|
-
-
|
8
|
+
- Adrien Thebo
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2013-01-04 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: colored
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '1.2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.2'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: cri
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -28,13 +44,13 @@ dependencies:
|
|
28
44
|
- !ruby/object:Gem::Version
|
29
45
|
version: 2.3.0
|
30
46
|
- !ruby/object:Gem::Dependency
|
31
|
-
name:
|
47
|
+
name: systemu
|
32
48
|
requirement: !ruby/object:Gem::Requirement
|
33
49
|
none: false
|
34
50
|
requirements:
|
35
51
|
- - ~>
|
36
52
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
53
|
+
version: 2.5.2
|
38
54
|
type: :runtime
|
39
55
|
prerelease: false
|
40
56
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -42,15 +58,15 @@ dependencies:
|
|
42
58
|
requirements:
|
43
59
|
- - ~>
|
44
60
|
- !ruby/object:Gem::Version
|
45
|
-
version:
|
61
|
+
version: 2.5.2
|
46
62
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
63
|
+
name: middleware
|
48
64
|
requirement: !ruby/object:Gem::Requirement
|
49
65
|
none: false
|
50
66
|
requirements:
|
51
67
|
- - ~>
|
52
68
|
- !ruby/object:Gem::Version
|
53
|
-
version: 0.1.
|
69
|
+
version: 0.1.0
|
54
70
|
type: :runtime
|
55
71
|
prerelease: false
|
56
72
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -58,30 +74,69 @@ dependencies:
|
|
58
74
|
requirements:
|
59
75
|
- - ~>
|
60
76
|
- !ruby/object:Gem::Version
|
61
|
-
version: 0.1.
|
77
|
+
version: 0.1.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: json
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 1.7.6
|
86
|
+
type: :runtime
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 1.7.6
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: log4r
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.1.10
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.1.10
|
62
110
|
description: ! " R10K is an implementation of the Dynamic Puppet environments based
|
63
111
|
on git repositories\n as described in http://puppetlabs.com/blog/git-workflow-and-puppet-environments/.
|
64
112
|
It\n aggressively caches and tries to minimize network activity to ensure that
|
65
113
|
interactive\n deployment is as fast as possible.\n"
|
66
|
-
email:
|
114
|
+
email: adrien@somethingsinistral.net
|
67
115
|
executables:
|
68
116
|
- r10k
|
69
117
|
extensions: []
|
70
118
|
extra_rdoc_files: []
|
71
119
|
files:
|
72
120
|
- bin/r10k
|
73
|
-
- lib/r10k/
|
121
|
+
- lib/r10k/action/environment.rb
|
122
|
+
- lib/r10k/action/module.rb
|
123
|
+
- lib/r10k/action.rb
|
124
|
+
- lib/r10k/cli/cache.rb
|
74
125
|
- lib/r10k/cli/environment/deploy.rb
|
75
126
|
- lib/r10k/cli/environment/list.rb
|
127
|
+
- lib/r10k/cli/environment/stale.rb
|
76
128
|
- lib/r10k/cli/environment.rb
|
77
129
|
- lib/r10k/cli/module/deploy.rb
|
78
130
|
- lib/r10k/cli/module/list.rb
|
79
131
|
- lib/r10k/cli/module.rb
|
132
|
+
- lib/r10k/cli/synchronize.rb
|
80
133
|
- lib/r10k/cli.rb
|
134
|
+
- lib/r10k/deployment/environment_collection.rb
|
81
135
|
- lib/r10k/deployment.rb
|
82
|
-
- lib/r10k/
|
136
|
+
- lib/r10k/errors.rb
|
83
137
|
- lib/r10k/librarian/dsl.rb
|
84
138
|
- lib/r10k/librarian.rb
|
139
|
+
- lib/r10k/logging.rb
|
85
140
|
- lib/r10k/module/forge.rb
|
86
141
|
- lib/r10k/module/git.rb
|
87
142
|
- lib/r10k/module.rb
|
@@ -90,6 +145,7 @@ files:
|
|
90
145
|
- lib/r10k/util/interp.rb
|
91
146
|
- lib/r10k/version.rb
|
92
147
|
- lib/r10k.rb
|
148
|
+
- lib/semver.rb
|
93
149
|
homepage: http://github.com/adrienthebo/r10k
|
94
150
|
licenses: []
|
95
151
|
post_install_message:
|
@@ -105,9 +161,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
105
161
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
162
|
none: false
|
107
163
|
requirements:
|
108
|
-
- - ! '
|
164
|
+
- - ! '>='
|
109
165
|
- !ruby/object:Gem::Version
|
110
|
-
version:
|
166
|
+
version: '0'
|
111
167
|
requirements: []
|
112
168
|
rubyforge_project:
|
113
169
|
rubygems_version: 1.8.23
|