r10k 0.0.1rc1

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.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'r10k/cli'
4
+
5
+ R10K::CLI.command.run(ARGV)
@@ -0,0 +1,6 @@
1
+ module R10K; end
2
+
3
+ require 'r10k/root'
4
+ require 'r10k/synchro/git'
5
+ require 'r10k/librarian'
6
+ require 'r10k/version'
@@ -0,0 +1,33 @@
1
+ require 'r10k'
2
+ require 'cri'
3
+
4
+ module R10K::CLI
5
+ def self.command
6
+ @cmd ||= Cri::Command.define do
7
+ name 'r10k'
8
+ usage 'r10k <subcommand> [options]'
9
+ summary 'Killer robot powered Puppet environment deployment'
10
+ description <<-EOD
11
+ r10k is a suite of commands to help deploy and manage puppet code for
12
+ complex environments.
13
+ EOD
14
+
15
+ flag :h, :help, 'show help for this command' do |value, cmd|
16
+ puts cmd.help
17
+ exit 0
18
+ end
19
+
20
+ required :c, :config, 'Specify a configuration file' do |value, cmd|
21
+ R10K::Deployment.instance.configfile = value
22
+ end
23
+
24
+ run do |opts, args, cmd|
25
+ puts cmd.help
26
+ exit 0
27
+ end
28
+ end
29
+ end
30
+ end
31
+
32
+ require 'r10k/cli/environment'
33
+ require 'r10k/cli/module'
@@ -0,0 +1,26 @@
1
+ require 'r10k/cli'
2
+ require 'cri'
3
+
4
+ module R10K::CLI
5
+ module Environment
6
+ def self.command
7
+ @cmd ||= Cri::Command.define do
8
+ name 'environment'
9
+ usage 'environment <subcommand>'
10
+ summary 'Operate on a specific environment'
11
+
12
+ required :e, :environment, 'Specify a particular environment'
13
+
14
+ run do |opts, args, cmd|
15
+ puts cmd.help
16
+ exit 0
17
+ end
18
+ end
19
+ end
20
+ end
21
+ self.command.add_command(Environment.command)
22
+ end
23
+
24
+ require 'r10k/cli/environment/list'
25
+ require 'r10k/cli/environment/deploy'
26
+ require 'r10k/cli/environment/cache'
@@ -0,0 +1,23 @@
1
+ require 'r10k/cli/environment'
2
+ require 'r10k/synchro/git'
3
+ require 'cri'
4
+
5
+ module R10K::CLI::Environment
6
+ module Cache
7
+ def self.command
8
+ @cmd ||= Cri::Command.define do
9
+ name 'cache'
10
+ usage 'cache'
11
+ summary 'Update cache for all sources'
12
+
13
+ run do |opts, args, cmd|
14
+ R10K::Deployment.instance[:sources].each_pair do |name, source|
15
+ synchro = R10K::Synchro::Git.new(source)
16
+ synchro.cache
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ self.command.add_command(Cache.command)
23
+ end
@@ -0,0 +1,46 @@
1
+ require 'r10k/cli/environment'
2
+ require 'r10k/deployment'
3
+ require 'cri'
4
+
5
+ require 'fileutils'
6
+
7
+ module R10K::CLI::Environment
8
+ module Deploy
9
+ def self.command
10
+ @cmd ||= Cri::Command.define do
11
+ name 'deploy'
12
+ usage 'deploy'
13
+ summary 'Deploy an environment'
14
+
15
+ flag :r, :recurse, 'Recursively update submodules'
16
+
17
+ required :u, :update, "Enable or disable cache updating"
18
+
19
+ run do |opts, args, cmd|
20
+ deployment = R10K::Deployment.instance
21
+ env_list = deployment.environments
22
+
23
+ update_cache = (defined? opts[:update]) ? (opts[:update] == 'true') : false
24
+
25
+ if opts[:environment]
26
+ environments = env_list.select {|env| env.name == opts[:environment]}
27
+ else
28
+ environments = env_list
29
+ end
30
+
31
+ environments.each do |env|
32
+ FileUtils.mkdir_p env.full_path
33
+ env.sync! :update_cache => update_cache
34
+
35
+ if opts[:recurse]
36
+ env.modules.each do |mod|
37
+ mod.sync! :update_cache => update_cache
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ self.command.add_command(Deploy.command)
46
+ end
@@ -0,0 +1,27 @@
1
+ require 'r10k/cli/environment'
2
+ require 'r10k/deployment'
3
+ require 'cri'
4
+
5
+ module R10K::CLI::Environment
6
+ module List
7
+ def self.command
8
+ @cmd ||= Cri::Command.define do
9
+ name 'list'
10
+ usage 'list'
11
+ summary 'List all available environments'
12
+
13
+ run do |opts, args, cmd|
14
+ deployment = R10K::Deployment.instance
15
+ output = deployment.environments.inject('') do |str, root|
16
+ str << " - "
17
+ str << "#{root.name}: #{root.full_path}"
18
+ str << "\n"
19
+ end
20
+
21
+ puts output
22
+ end
23
+ end
24
+ end
25
+ end
26
+ self.command.add_command(List.command)
27
+ end
@@ -0,0 +1,25 @@
1
+ require 'r10k/cli'
2
+ require 'cri'
3
+
4
+ module R10K::CLI
5
+ module Module
6
+ def self.command
7
+ @cmd ||= Cri::Command.define do
8
+ name 'module'
9
+ usage 'module <subcommand>'
10
+ summary 'Operate on a specific puppet module'
11
+
12
+ required :e, :environment, 'Specify a particular environment'
13
+
14
+ run do |opts, args, cmd|
15
+ puts cmd.help
16
+ exit 0
17
+ end
18
+ end
19
+ end
20
+ end
21
+ self.command.add_command(Module.command)
22
+ end
23
+
24
+ require 'r10k/cli/module/deploy'
25
+ require 'r10k/cli/module/list'
@@ -0,0 +1,55 @@
1
+ require 'r10k/cli/module'
2
+ require 'r10k/deployment'
3
+ require 'cri'
4
+
5
+ require 'fileutils'
6
+
7
+ module R10K::CLI::Module
8
+ module Deploy
9
+ def self.command
10
+ @cmd ||= Cri::Command.define do
11
+ name 'deploy'
12
+ usage 'deploy <module name>'
13
+ summary 'Deploy a module'
14
+
15
+ required :u, :update, "Enable or disable cache updating"
16
+
17
+ run do |opts, args, cmd|
18
+
19
+ unless (module_name = args[0])
20
+ puts cmd.help
21
+ exit 1
22
+ end
23
+
24
+ deployment = R10K::Deployment.instance
25
+ env_list = deployment.environments
26
+
27
+ update_cache = (defined? opts[:update]) ? (opts[:update] == 'true') : false
28
+
29
+ if opts[:environment]
30
+ environments = env_list.select {|env| env.name == opts[:environment]}
31
+ else
32
+ environments = env_list
33
+ end
34
+
35
+ environments.each do |env|
36
+ FileUtils.mkdir_p env.full_path
37
+ env.sync! :update_cache => update_cache
38
+
39
+ mods = env.modules.select { |mod| mod.name == module_name }
40
+
41
+ if mods.empty?
42
+ puts "No modules with name #{module_name} matched in environments #{env.map(&:name).inspect}".red
43
+ exit 1
44
+ end
45
+
46
+ mods.each do |mod|
47
+ mod.sync! :update_cache => update_cache
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ self.command.add_command(Deploy.command)
55
+ end
@@ -0,0 +1,45 @@
1
+ require 'r10k/cli/module'
2
+ require 'r10k/deployment'
3
+ require 'cri'
4
+
5
+ module R10K::CLI::Module
6
+ module List
7
+ def self.command
8
+ @cmd ||= Cri::Command.define do
9
+ name 'list'
10
+ usage 'list'
11
+ summary 'List modules that are instantiated in environments'
12
+
13
+ run do |opts, args, cmd|
14
+ deployment = R10K::Deployment.instance
15
+ env_list = deployment.environments
16
+
17
+ update_cache = (defined? opts[:update]) ? (opts[:update] == 'true') : false
18
+
19
+ if opts[:environment]
20
+ environments = env_list.select {|env| env.name == opts[:environment]}
21
+ else
22
+ environments = env_list
23
+ end
24
+
25
+ printree = {}
26
+
27
+ environments.each do |env|
28
+ module_names = env.modules.map(&:name)
29
+
30
+ printree[env.name] = module_names
31
+ end
32
+
33
+ printree.each_pair do |env_name, mod_list|
34
+ puts " - #{env_name}"
35
+ mod_list.each do |mod|
36
+ puts " #{mod}"
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ self.command.add_command(List.command)
44
+ end
45
+
@@ -0,0 +1,60 @@
1
+ require 'r10k'
2
+ require 'r10k/synchro/git'
3
+ require 'r10k/environment_collection'
4
+ require 'yaml'
5
+
6
+ class R10K::Deployment
7
+ # Model a full installation of module directories and modules.
8
+
9
+ def self.instance
10
+ @myself ||= self.new
11
+ end
12
+
13
+ def initialize
14
+ @configfile = File.join(Dir.getwd, "config.yaml")
15
+ @update_cache = true
16
+ end
17
+
18
+ attr_accessor :configfile
19
+
20
+ # Load up all module roots
21
+ #
22
+ # @return [Array<R10K::Root>]
23
+ def environments
24
+ collection = R10K::EnvironmentCollection.new(config)
25
+ collection.to_a
26
+ end
27
+
28
+ # Serve up the loaded config if it's already been loaded, otherwise try to
29
+ # load a config in the current wd.
30
+ def config
31
+ load_config unless @config
32
+ @config
33
+ end
34
+
35
+ # @return [Object] A top level key from the config hash
36
+ def setting(key)
37
+ self.config[key]
38
+ end
39
+ alias_method :[], :setting
40
+
41
+ private
42
+
43
+ # Load and store a config file, and set relevant options
44
+ #
45
+ # @param [String] configfile The path to the YAML config file
46
+ def load_config
47
+ File.open(@configfile) { |fh| @config = YAML.load(fh.read) }
48
+ apply_config_settings
49
+ @config
50
+ rescue => e
51
+ raise "Couldn't load #{configfile}: #{e}"
52
+ end
53
+
54
+ # Apply config settings to the relevant classes after a config has been loaded.
55
+ def apply_config_settings
56
+ if @config[:cachedir]
57
+ R10K::Synchro::Git.cache_root = @config[:cachedir]
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,53 @@
1
+ require 'r10k'
2
+
3
+ class R10K::EnvironmentCollection
4
+
5
+ attr_reader :update_cache
6
+
7
+ def initialize(config, options = {:update_cache => true})
8
+ @config = config
9
+ @environments = []
10
+
11
+ @update_cache = options.delete(:update_cache)
12
+
13
+ load_all
14
+ end
15
+
16
+ # List subdirectories that aren't associated with an env
17
+ #
18
+ # If a branch associated with an environment is deleted then the associated
19
+ # branch ceases to be tracked. This method will scan a directory for
20
+ # subdirectories and return any subdirectories that don't have an active
21
+ # branch associated.
22
+ #
23
+ # @param [String] basedir The directory to scan
24
+ #
25
+ # @return [Array<String>] A list of filenames
26
+ def untracked_environments(basedir)
27
+ raise NotImplementedError
28
+ end
29
+
30
+ # @return [Array<R10K::Root>]
31
+ def to_a
32
+ @environments
33
+ end
34
+
35
+ private
36
+
37
+ def load_all
38
+ @config[:sources].each_pair do |repo_name, repo_config|
39
+ synchro = R10K::Synchro::Git.new(repo_config['remote'])
40
+ synchro.cache if @update_cache
41
+
42
+ if repo_config['ref']
43
+ @environments << R10K::Root.new(repo_config)
44
+ else
45
+ synchro.branches.each do |branch|
46
+ @environments << R10K::Root.new(repo_config.merge({'ref' => branch}))
47
+ end
48
+ end
49
+ end
50
+
51
+ @environments
52
+ end
53
+ end
@@ -0,0 +1,31 @@
1
+ require 'r10k'
2
+ require 'r10k/module'
3
+
4
+ class R10K::Librarian
5
+
6
+ attr_reader :forge
7
+
8
+ def initialize(puppetfile)
9
+ @puppetfile = puppetfile
10
+ @modules = []
11
+ @forge = 'forge.puppetlabs.com'
12
+ end
13
+
14
+ def load
15
+ dsl = R10K::Librarian::DSL.new(self)
16
+ dsl.instance_eval(File.read(@puppetfile), @puppetfile)
17
+
18
+ @modules
19
+ end
20
+
21
+ # This method only exists because people tried being excessively clever.
22
+ def set_forge(forge)
23
+ @forge = forge
24
+ end
25
+
26
+ def add_module(name, args)
27
+ @modules << [name, args]
28
+ end
29
+ end
30
+
31
+ require 'r10k/librarian/dsl'
@@ -0,0 +1,20 @@
1
+ require 'r10k/librarian'
2
+
3
+ class R10K::Librarian::DSL
4
+
5
+ def initialize(librarian)
6
+ @librarian = librarian
7
+ end
8
+
9
+ def mod(name, args = [])
10
+ @librarian.add_module(name, args)
11
+ end
12
+
13
+ def forge(location)
14
+ @librarian.set_forge(location)
15
+ end
16
+
17
+ def method_missing(method, *args)
18
+ raise NoMethodError, "unrecognized declaration '#{method}'"
19
+ end
20
+ end
@@ -0,0 +1,45 @@
1
+ require 'r10k'
2
+
3
+ class R10K::Module
4
+
5
+ # Register an inheriting class for later generation
6
+ def self.inherited(klass)
7
+ @klasses ||= []
8
+ @klasses << klass
9
+ end
10
+
11
+ # Look up the implementing class and instantiate an object
12
+ #
13
+ # This method takes the arguments for normal object generation and checks all
14
+ # inheriting classes to see if they implement the behavior needed to create
15
+ # the requested object. It selects the first class that can implement an object
16
+ # with `name, args`, and generates an object of that class.
17
+ #
18
+ # @param [String] name The unique name of the module
19
+ # @param [String] path The root path to install the module in
20
+ # @param [Object] args An arbitary value or set of values that specifies the implementation
21
+ #
22
+ # @return [Object < R10K::Module] A member of the implementing subclass
23
+ def self.new(name, path, args)
24
+ if implementation = @klasses.find { |klass| klass.implements(name, args) }
25
+ obj = implementation.send(:allocate)
26
+ obj.send(:initialize, name, path, args)
27
+ obj
28
+ else
29
+ raise "Module #{name} with args #{args.inspect} doesn't have an implementation. (Are you using the right arguments?)"
30
+ end
31
+ end
32
+
33
+ attr_accessor :name, :path
34
+
35
+ def initialize(name, path, args)
36
+ @name, @path, @args = name, path, args
37
+ end
38
+
39
+ def full_path
40
+ File.join(@path, @name)
41
+ end
42
+ end
43
+
44
+ require 'r10k/module/git'
45
+ require 'r10k/module/forge'
@@ -0,0 +1,19 @@
1
+ require 'r10k'
2
+ require 'r10k/module'
3
+
4
+ class R10K::Module::Forge < R10K::Module
5
+
6
+ def self.implements(name, args)
7
+ args.is_a? String and args.match /\d+\.\d+\.\d+/
8
+ end
9
+
10
+ def initialize(name, path, args)
11
+ super
12
+
13
+ @version = @args
14
+ end
15
+
16
+ def sync!(options = {})
17
+ puts "#{self.class.name}#sync! is not implemented. Doing nothing."
18
+ end
19
+ end
@@ -0,0 +1,24 @@
1
+ require 'r10k'
2
+ require 'r10k/module'
3
+ require 'r10k/synchro/git'
4
+
5
+ class R10K::Module::Git < R10K::Module
6
+
7
+ def self.implements(name, args)
8
+ args.is_a? Hash and args.has_key?(:git)
9
+ rescue
10
+ false
11
+ end
12
+
13
+ def initialize(name, path, args)
14
+ super
15
+
16
+ @remote = @args[:git]
17
+ @ref = (@args[:ref] || 'master')
18
+ end
19
+
20
+ def sync!(options = {})
21
+ synchro = R10K::Synchro::Git.new(@remote)
22
+ synchro.sync(full_path, @ref, options)
23
+ end
24
+ end
@@ -0,0 +1,95 @@
1
+ require 'r10k'
2
+ require 'r10k/module'
3
+ require 'r10k/synchro/git'
4
+
5
+ class R10K::Root
6
+
7
+ # @!attribute [r] name
8
+ # The directory name of this root
9
+ attr_reader :name
10
+
11
+ # @!attribute [r] basedir
12
+ # The basedir to clone the root into
13
+ attr_reader :basedir
14
+
15
+ # @!attribute [r] remote
16
+ # The location of the remote git repository
17
+ attr_reader :remote
18
+
19
+ # @!attribute [r] ref
20
+ # The git ref to instantiate into the basedir
21
+ attr_reader :ref
22
+
23
+ def initialize(hash)
24
+ parse_initialize_hash(hash)
25
+ end
26
+
27
+ def sync!(options = {})
28
+ synchro = R10K::Synchro::Git.new(@remote)
29
+ recursive_needed = !(synchro.cloned?(full_path))
30
+ synchro.sync(full_path, @ref, options)
31
+
32
+ sync_modules!(options) if recursive_needed
33
+ end
34
+
35
+ def sync_modules!(options = {})
36
+ modules.each do |mod|
37
+ mod.sync!(options)
38
+ end
39
+ end
40
+
41
+ def modules
42
+ librarian = R10K::Librarian.new("#{full_path}/Puppetfile")
43
+
44
+ module_data = librarian.load
45
+
46
+ @modules = module_data.map do |mod|
47
+ name = mod[0]
48
+ args = mod[1]
49
+ R10K::Module.new(name, "#{full_path}/modules", args)
50
+ end
51
+ rescue Errno::ENOENT
52
+ puts "#{self}: #{full_path} does not exist, cannot enumerate modules."
53
+ []
54
+ end
55
+
56
+ def full_path
57
+ @full_path ||= File.expand_path(File.join @basedir, @name)
58
+ end
59
+
60
+ private
61
+
62
+ def parse_initialize_hash(hash)
63
+ if hash['name']
64
+ @name = hash.delete('name')
65
+ elsif hash['ref']
66
+ @name = hash['ref']
67
+ else
68
+ raise "Unable to resolve directory name from options #{hash.inspect}"
69
+ end
70
+
71
+ # XXX This could be metaprogrammed, but it seems like the road to madness.
72
+
73
+ if hash['basedir']
74
+ @basedir = hash.delete('basedir')
75
+ else
76
+ raise "'basedir' is a required value for #{self.class}.new"
77
+ end
78
+
79
+ if hash['remote']
80
+ @remote = hash.delete('remote')
81
+ else
82
+ raise "'remote' is a required value for #{self.class}.new"
83
+ end
84
+
85
+ if hash['ref']
86
+ @ref = hash.delete('ref')
87
+ else
88
+ raise "'ref' is a required value for #{self.class}.new"
89
+ end
90
+
91
+ unless hash.empty?
92
+ raise "#{self.class}.new only expects keys ['name', 'basedir', 'remote', 'ref'], got #{hash.keys.inspect}"
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,186 @@
1
+ require 'r10k'
2
+ require 'shellter'
3
+ require 'fileutils'
4
+
5
+ module R10K::Synchro; end
6
+
7
+ class R10K::Synchro::Git
8
+ # Define a thingy that can synchronize git repositories.
9
+ #
10
+ # This class is built to be a general purpose mechanism for syncing and
11
+ # caching git repositories.
12
+ #
13
+ # Class instances are memoized based on the git remote path. This way if a
14
+ # single git repository is instantiated multiple times, the object cache
15
+ # will only be updated once.
16
+
17
+ class << self
18
+ attr_accessor :cache_root
19
+
20
+ # @return [Hash<R10K::Synchro::Git>] A hash of memoized class instances
21
+ def synchros
22
+ @synchros ||= {}
23
+ end
24
+
25
+ # Memoize class instances and return existing instances.
26
+ #
27
+ # This allows objects to mark themselves as cached to prevent unnecessary
28
+ # cache refreshes.
29
+ #
30
+ # @param [String] remote A git remote URL
31
+ # @return [R10K::Synchro::Git]
32
+ def new(remote)
33
+ unless synchros[remote]
34
+ obj = self.allocate
35
+ obj.send(:initialize, remote)
36
+ synchros[remote] = obj
37
+ end
38
+ synchros[remote]
39
+ end
40
+ end
41
+
42
+ attr_reader :remote
43
+
44
+ # Instantiates a new git synchro and optionally prepares for caching
45
+ #
46
+ # @param [String] remote A git remote URL
47
+ def initialize(remote)
48
+ @remote = remote
49
+
50
+ if self.class.cache_root
51
+ @cache_path = File.join(self.class.cache_root, @remote.gsub(/[^@\w-]/, '-'))
52
+ end
53
+ end
54
+
55
+ # Synchronize the local git repository.
56
+ #
57
+ # @param [String] path The destination path for the files
58
+ # @param [String] ref The git ref to instantiate at the destination path
59
+ def sync(path, ref, options = {:update_cache => true})
60
+ path = File.expand_path(path)
61
+ cache if options[:update_cache]
62
+
63
+ if self.cloned?(path)
64
+ fetch(path)
65
+ else
66
+ clone(path)
67
+ end
68
+ reset(path, ref)
69
+ end
70
+
71
+ # @return [TrueClass] if the git repository is cached
72
+ def has_cache?
73
+ @cache_path and File.directory? @cache_path
74
+ end
75
+
76
+ # Determine if repo has been cloned into a specific dir
77
+ #
78
+ # @param [String] dirname The directory to check
79
+ #
80
+ # @return [true, false] If the repo has already been cloned
81
+ def cloned?(directory)
82
+ File.directory?(File.join(directory, '.git'))
83
+ end
84
+
85
+ # Update the git object cache repository if it hasn't been done
86
+ #
87
+ # @return [true, nil] If the cache was actually updated
88
+ def cache
89
+ unless @cached
90
+ cache!
91
+ @cached = true
92
+ end
93
+ end
94
+
95
+ # Force a cache refresh
96
+ def cache!
97
+ if has_cache?
98
+ git "--git-dir #{@cache_path} fetch --prune"
99
+ else
100
+ FileUtils.mkdir_p File.dirname(File.join(@cache_path))
101
+ git "clone --mirror #{@remote} #{@cache_path}"
102
+ end
103
+ end
104
+
105
+ # Retrieve a list of cached branches for the git repo associated with this
106
+ # object.
107
+ #
108
+ # @return [Array<String>] A list of all cached remote branches
109
+ def branches
110
+ cache
111
+ output = git "--git-dir #{@cache_path} branch"
112
+ output.split("\n").map { |str| str[2..-1] }
113
+ end
114
+
115
+ private
116
+
117
+ # Perform a non-bare clone of a git repository.
118
+ #
119
+ # If a cachedir is available and the repo is already cached, it will be
120
+ # used as an object reference to speed up the clone.
121
+ #
122
+ # @param [String] path The directory to create the repo working directory
123
+ def clone(path)
124
+ if has_cache?
125
+ git "clone --reference #{@cache_path} #{@remote} #{path}"
126
+ else
127
+ FileUtils.mkdir_p path unless File.directory? path
128
+ git "clone #{@remote} #{path}"
129
+ end
130
+ end
131
+
132
+ def fetch(path)
133
+ if has_cache?
134
+ git "fetch --prune #{@cache_path}", path
135
+ else
136
+ git "fetch --prune", path
137
+ end
138
+ end
139
+
140
+ # Reset a git repo with a working directory to a specific ref
141
+ #
142
+ # @param [String] path The path to the working directory of the git repo
143
+ # @param [String] ref The git reference to reset to.
144
+ def reset(path, ref)
145
+
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
+ begin
151
+ commit = git "--git-dir #{@cache_path} rev-parse #{ref}^{commit}"
152
+ rescue RuntimeError => e
153
+ commit = "origin/#{ref}"
154
+ end
155
+
156
+ git "reset --hard #{commit}", path
157
+ end
158
+
159
+ # Wrap git commands
160
+ #
161
+ # @param [String] command_line_args The arguments for the git prompt
162
+ # @param [String] git_dir An optional git working directory
163
+ #
164
+ # @return [String] The git command output
165
+ def git(command_line_args, git_dir = nil)
166
+ args = []
167
+
168
+ if git_dir
169
+ args << "--work-tree" << git_dir
170
+ args << "--git-dir" << "#{git_dir}/.git"
171
+ end
172
+
173
+ args << command_line_args.split(/\s+/)
174
+
175
+ result = Shellter.run!('git', args.join(' '))
176
+ puts "Execute: #{result.last_command}".green
177
+
178
+ stderr = result.stderr.read
179
+ stdout = result.stdout.read
180
+
181
+ puts stdout.blue unless stdout.empty?
182
+ puts stderr.red unless stderr.empty?
183
+
184
+ stdout
185
+ end
186
+ end
@@ -0,0 +1,25 @@
1
+
2
+ module R10K; end
3
+ module R10K::Util; end
4
+
5
+ module R10K::Util::Interp
6
+
7
+ # Interpolate a string with a given scope
8
+ #
9
+ # @param [String] string
10
+ # @param [Hash] scope
11
+ #
12
+ # @return [String]
13
+ def interpolate_string(string, scope)
14
+
15
+ interp = string.clone
16
+
17
+ while (matchdata = interp.match /%\{.+?\}/)
18
+ var_name = matchdata[1].intern
19
+ var_data = scope[var_name]
20
+ interp.gsub!(/%\{#{var_name}\}/, var_data)
21
+ end
22
+
23
+ interp
24
+ end
25
+ end
@@ -0,0 +1,3 @@
1
+ module R10K
2
+ VERSION = '0.0.1rc1'
3
+ end
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: r10k
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1rc1
5
+ prerelease: 5
6
+ platform: ruby
7
+ authors:
8
+ - adrien@somethingsinistral.net
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-12-26 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cri
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: 2.3.0
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: 2.3.0
30
+ - !ruby/object:Gem::Dependency
31
+ name: shellter
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ~>
36
+ - !ruby/object:Gem::Version
37
+ version: 0.9.6
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ~>
44
+ - !ruby/object:Gem::Version
45
+ version: 0.9.6
46
+ - !ruby/object:Gem::Dependency
47
+ name: popen4
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.1.2
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.2
62
+ description: ! " R10K is an implementation of the Dynamic Puppet environments based
63
+ on git repositories\n as described in http://puppetlabs.com/blog/git-workflow-and-puppet-environments/.
64
+ It\n aggressively caches and tries to minimize network activity to ensure that
65
+ interactive\n deployment is as fast as possible.\n"
66
+ email:
67
+ executables:
68
+ - r10k
69
+ extensions: []
70
+ extra_rdoc_files: []
71
+ files:
72
+ - bin/r10k
73
+ - lib/r10k/cli/environment/cache.rb
74
+ - lib/r10k/cli/environment/deploy.rb
75
+ - lib/r10k/cli/environment/list.rb
76
+ - lib/r10k/cli/environment.rb
77
+ - lib/r10k/cli/module/deploy.rb
78
+ - lib/r10k/cli/module/list.rb
79
+ - lib/r10k/cli/module.rb
80
+ - lib/r10k/cli.rb
81
+ - lib/r10k/deployment.rb
82
+ - lib/r10k/environment_collection.rb
83
+ - lib/r10k/librarian/dsl.rb
84
+ - lib/r10k/librarian.rb
85
+ - lib/r10k/module/forge.rb
86
+ - lib/r10k/module/git.rb
87
+ - lib/r10k/module.rb
88
+ - lib/r10k/root.rb
89
+ - lib/r10k/synchro/git.rb
90
+ - lib/r10k/util/interp.rb
91
+ - lib/r10k/version.rb
92
+ - lib/r10k.rb
93
+ homepage: http://github.com/adrienthebo/r10k
94
+ licenses: []
95
+ post_install_message:
96
+ rdoc_options: []
97
+ require_paths:
98
+ - lib
99
+ required_ruby_version: !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ! '>='
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ required_rubygems_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>'
109
+ - !ruby/object:Gem::Version
110
+ version: 1.3.1
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 1.8.23
114
+ signing_key:
115
+ specification_version: 3
116
+ summary: Dynamic Puppet environments with Git
117
+ test_files: []