repo_manager 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemfiles +115 -0
- data/.gitattributes +1 -0
- data/.gitignore +7 -0
- data/.rspec +3 -0
- data/.yardopts +11 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +99 -0
- data/Guardfile +63 -0
- data/HISTORY.markdown +12 -0
- data/LICENSE +20 -0
- data/README.markdown +192 -0
- data/Rakefile +94 -0
- data/TODO.markdown +15 -0
- data/VERSION +1 -0
- data/bin/repo +151 -0
- data/cucumber.yml +28 -0
- data/examples/pc_saved_game_backup/.gitignore +2 -0
- data/examples/pc_saved_game_backup/INSTALL.markdown +420 -0
- data/examples/pc_saved_game_backup/README.markdown +108 -0
- data/examples/pc_saved_game_backup/remote/.gitignore +2 -0
- data/examples/pc_saved_game_backup/repo_manager/Gemfile +12 -0
- data/examples/pc_saved_game_backup/repo_manager/Gemfile.lock +66 -0
- data/examples/pc_saved_game_backup/repo_manager/assets/.gitignore +2 -0
- data/examples/pc_saved_game_backup/repo_manager/features/support/aruba.rb +15 -0
- data/examples/pc_saved_game_backup/repo_manager/features/support/env.rb +11 -0
- data/examples/pc_saved_game_backup/repo_manager/features/support/steps.rb +3 -0
- data/examples/pc_saved_game_backup/repo_manager/features/tasks/update.feature +144 -0
- data/examples/pc_saved_game_backup/repo_manager/global/default/asset.conf +2 -0
- data/examples/pc_saved_game_backup/repo_manager/repo.conf +64 -0
- data/examples/pc_saved_game_backup/repo_manager/tasks/.gitignore +0 -0
- data/examples/pc_saved_game_backup/repo_manager/tasks/remote.rb +57 -0
- data/examples/pc_saved_game_backup/repo_manager/tasks/update.rb +65 -0
- data/examples/pc_saved_game_backup/saved_games/hearts/save1 +1 -0
- data/examples/pc_saved_game_backup/saved_games/hearts/save2 +1 -0
- data/examples/pc_saved_game_backup/saved_games/mines/my_profile.ini +1 -0
- data/examples/pc_saved_game_backup/saved_games/mines/saves/save1 +1 -0
- data/examples/pc_saved_game_backup/saved_games/mines/saves/save2 +1 -0
- data/features/actions/git.feature +296 -0
- data/features/actions/help.feature +53 -0
- data/features/actions/list.feature +624 -0
- data/features/actions/path.feature +195 -0
- data/features/actions/status.feature +261 -0
- data/features/actions/task.feature +127 -0
- data/features/assets/configuration.feature +204 -0
- data/features/assets/rendering.feature +42 -0
- data/features/assets/user_attributes.feature +98 -0
- data/features/bin.feature +42 -0
- data/features/logger.feature +218 -0
- data/features/settings.feature +240 -0
- data/features/support/aruba.rb +15 -0
- data/features/support/env.rb +11 -0
- data/features/support/steps.rb +3 -0
- data/features/tasks/add/asset.feature +178 -0
- data/features/tasks/generate/init.feature +56 -0
- data/lib/repo_manager.rb +36 -0
- data/lib/repo_manager/actions.rb +8 -0
- data/lib/repo_manager/actions/action_helper.rb +39 -0
- data/lib/repo_manager/actions/app_action.rb +30 -0
- data/lib/repo_manager/actions/base_action.rb +296 -0
- data/lib/repo_manager/actions/git_action.rb +113 -0
- data/lib/repo_manager/actions/help_action.rb +52 -0
- data/lib/repo_manager/actions/list_action.rb +123 -0
- data/lib/repo_manager/actions/path_action.rb +22 -0
- data/lib/repo_manager/actions/status_action.rb +192 -0
- data/lib/repo_manager/actions/task_action.rb +71 -0
- data/lib/repo_manager/app.rb +116 -0
- data/lib/repo_manager/assets.rb +3 -0
- data/lib/repo_manager/assets/app_asset.rb +15 -0
- data/lib/repo_manager/assets/asset_accessors.rb +67 -0
- data/lib/repo_manager/assets/asset_configuration.rb +137 -0
- data/lib/repo_manager/assets/asset_manager.rb +72 -0
- data/lib/repo_manager/assets/base_asset.rb +199 -0
- data/lib/repo_manager/assets/repo_asset.rb +30 -0
- data/lib/repo_manager/core.rb +2 -0
- data/lib/repo_manager/core/array.rb +21 -0
- data/lib/repo_manager/core/hash.rb +83 -0
- data/lib/repo_manager/errors.rb +10 -0
- data/lib/repo_manager/extensions/hash.rb +86 -0
- data/lib/repo_manager/git.rb +2 -0
- data/lib/repo_manager/git/lib.rb +69 -0
- data/lib/repo_manager/git/status.rb +196 -0
- data/lib/repo_manager/logger.rb +39 -0
- data/lib/repo_manager/settings.rb +98 -0
- data/lib/repo_manager/tasks.rb +3 -0
- data/lib/repo_manager/tasks/add/asset.rb +213 -0
- data/lib/repo_manager/tasks/generate/init.rb +42 -0
- data/lib/repo_manager/tasks/generate/templates/config/repo.conf.tt +61 -0
- data/lib/repo_manager/tasks/generate/templates/init/assets/.gitignore +0 -0
- data/lib/repo_manager/tasks/generate/templates/init/global/default/asset.conf +2 -0
- data/lib/repo_manager/tasks/generate/templates/init/tasks/.gitignore +0 -0
- data/lib/repo_manager/tasks/task_manager.rb +166 -0
- data/lib/repo_manager/tasks/thor_helper.rb +29 -0
- data/lib/repo_manager/test/asset_steps.rb +19 -0
- data/lib/repo_manager/test/base_steps.rb +152 -0
- data/lib/repo_manager/test/repo_api.rb +41 -0
- data/lib/repo_manager/test/repo_steps.rb +83 -0
- data/lib/repo_manager/test/test_api.rb +88 -0
- data/lib/repo_manager/views.rb +2 -0
- data/lib/repo_manager/views/app_view.rb +15 -0
- data/lib/repo_manager/views/base_view.rb +137 -0
- data/lib/repo_manager/views/templates/css/basic.css +26 -0
- data/lib/repo_manager/views/templates/default.erb +40 -0
- data/lib/repo_manager/views/templates/default.slim +37 -0
- data/lib/repo_manager/views/view_helper.rb +55 -0
- data/repo_manager.gemspec +75 -0
- data/spec/basic_app/actions/action_helper_spec.rb +54 -0
- data/spec/basic_app/assets/base_asset_spec.rb +210 -0
- data/spec/basic_app/core_spec.rb +78 -0
- data/spec/basic_app/settings_spec.rb +64 -0
- data/spec/basic_app/views/view_helper_spec.rb +28 -0
- data/spec/basic_gem/aruba_helper_spec.rb +33 -0
- data/spec/basic_gem/basic_gem_spec.rb +84 -0
- data/spec/basic_gem/gemspec_spec.rb +68 -0
- data/spec/repo_manager/git_spec.rb +31 -0
- data/spec/spec_helper.rb +25 -0
- metadata +472 -0
@@ -0,0 +1,199 @@
|
|
1
|
+
####################################################
|
2
|
+
# The file is was originally cloned from "Basic App"
|
3
|
+
# More information on "Basic App" can be found in the
|
4
|
+
# "Basic App" repository.
|
5
|
+
#
|
6
|
+
# See http://github.com/robertwahler
|
7
|
+
####################################################
|
8
|
+
require 'mustache'
|
9
|
+
require 'pathname'
|
10
|
+
|
11
|
+
require 'repo_manager/assets/asset_configuration'
|
12
|
+
require 'repo_manager/assets/asset_accessors'
|
13
|
+
|
14
|
+
module RepoManager
|
15
|
+
|
16
|
+
class BaseAsset
|
17
|
+
include RepoManager::AssetAccessors
|
18
|
+
extend RepoManager::AssetAccessors
|
19
|
+
|
20
|
+
#
|
21
|
+
# --- Asset attributes START here ---
|
22
|
+
#
|
23
|
+
|
24
|
+
# Asset defined path
|
25
|
+
#
|
26
|
+
# Defaults to asset name when the path attribute is blank
|
27
|
+
#
|
28
|
+
# NOTE: This is not the path to the asset configuration file. If not an
|
29
|
+
# absolute path, then it is relative to the current working directory
|
30
|
+
#
|
31
|
+
# @example Full paths
|
32
|
+
#
|
33
|
+
# path: /home/robert/photos/photo1.jpg
|
34
|
+
#
|
35
|
+
# path: /home/robert/app/appfolder
|
36
|
+
#
|
37
|
+
# @example Home folder '~' paths are expanded automatically
|
38
|
+
#
|
39
|
+
# path: ~/photos/photo1.jpg -> /home/robert/photos/photo1.jpg
|
40
|
+
#
|
41
|
+
# @example Relative paths are expanded automatically relative to the CWD
|
42
|
+
#
|
43
|
+
# path: photos/photo1.jpg -> /home/robert/photos/photo1.jpg
|
44
|
+
#
|
45
|
+
# @example Mustache templates are supported
|
46
|
+
#
|
47
|
+
# path: /home/robert/{{name}}/appfolder -> /home/robert/app1/appfolder
|
48
|
+
#
|
49
|
+
# @example Mustache braces that come at the start must be quoted
|
50
|
+
#
|
51
|
+
# path: "{{name}}/appfolder" -> /home/robert/app1/appfolder
|
52
|
+
#
|
53
|
+
# @return [String] an absolute path
|
54
|
+
def path
|
55
|
+
return @path if @path
|
56
|
+
|
57
|
+
path = attributes[:path] || name
|
58
|
+
path = render(path)
|
59
|
+
if (path && !Pathname.new(path).absolute?)
|
60
|
+
# expand path if starts with '~'
|
61
|
+
path = File.expand_path(path) if path.match(/^~/)
|
62
|
+
# paths can be relative to cwd
|
63
|
+
path = File.join(File.expand_path(FileUtils.pwd), path) if (!Pathname.new(path).absolute?)
|
64
|
+
end
|
65
|
+
@path = path
|
66
|
+
end
|
67
|
+
def path=(value)
|
68
|
+
@path = nil
|
69
|
+
attributes[:path] = value
|
70
|
+
end
|
71
|
+
|
72
|
+
# Description (short)
|
73
|
+
#
|
74
|
+
# @return [String]
|
75
|
+
create_accessors :description
|
76
|
+
|
77
|
+
# Notes (user)
|
78
|
+
#
|
79
|
+
# @return [String]
|
80
|
+
create_accessors :notes
|
81
|
+
|
82
|
+
# Classification tags, an array of strings
|
83
|
+
#
|
84
|
+
# @return [Array] of tag strings
|
85
|
+
def tags
|
86
|
+
attributes[:tags] || []
|
87
|
+
end
|
88
|
+
def tags=(value)
|
89
|
+
attributes[:tags] = value
|
90
|
+
end
|
91
|
+
|
92
|
+
#
|
93
|
+
# --- Asset attributes END here ---
|
94
|
+
#
|
95
|
+
|
96
|
+
# The asset name is loosely tied to the name of the configuration folder (datastore).
|
97
|
+
# The name may also be a hash key from a YAML config file.
|
98
|
+
#
|
99
|
+
# The name should be a valid ruby variable name, in turn, a valid folder name, but this
|
100
|
+
# is not enforced.
|
101
|
+
#
|
102
|
+
# @see self.path_to_name
|
103
|
+
attr_accessor :name
|
104
|
+
|
105
|
+
# subclass factory to create Assets
|
106
|
+
#
|
107
|
+
# Call with classname to create. Pass in optional configuration folder
|
108
|
+
# name and/or a hash of attributes
|
109
|
+
#
|
110
|
+
# @param [String] asset_type (AppAsset) classname to initialize
|
111
|
+
# @param [String] asset_name (nil) asset name or folder name, if folder, will load YAML config
|
112
|
+
# @param [Hash] attributes ({}) initial attributes
|
113
|
+
#
|
114
|
+
# @return [BaseAsset] the created BaseAsset or decendent asset
|
115
|
+
def self.create(asset_type=:app_asset, asset_name=nil, attributes={})
|
116
|
+
classified_name = asset_type.to_s.split('_').collect!{ |w| w.capitalize }.join
|
117
|
+
Object.const_get('RepoManager').const_get(classified_name).new(asset_name, attributes)
|
118
|
+
end
|
119
|
+
|
120
|
+
# takes any path and returns a string suitable for asset name (Ruby identifier)
|
121
|
+
#
|
122
|
+
# @return [String] valid asset name
|
123
|
+
def self.path_to_name(path)
|
124
|
+
basename = File.basename(path)
|
125
|
+
basename = basename.gsub(/\&/,' and ')
|
126
|
+
basename = basename.downcase.strip.gsub(/ /,'_')
|
127
|
+
basename = basename.gsub(/[^a-zA-Z_0-9]/,'')
|
128
|
+
basename = basename.downcase.strip.gsub(/ /,'_')
|
129
|
+
basename.gsub(/[_]+/,'_')
|
130
|
+
end
|
131
|
+
|
132
|
+
# @param [String/Symbol] asset_name_or_folder (nil) if folder exists, will load YAML config
|
133
|
+
# @param [Hash] attributes ({}) initial attributes
|
134
|
+
def initialize(asset_name_or_folder=nil, attributes={})
|
135
|
+
# allow for lazy loading (TODO), don't assign empty attributes
|
136
|
+
@attributes = attributes.dup unless attributes.empty?
|
137
|
+
|
138
|
+
# create user_attribute methods
|
139
|
+
create_accessors(@attributes[:user_attributes]) if @attributes && @attributes[:user_attributes]
|
140
|
+
|
141
|
+
return unless asset_name_or_folder
|
142
|
+
|
143
|
+
folder = asset_name_or_folder.to_s
|
144
|
+
@name = File.basename(folder)
|
145
|
+
|
146
|
+
logger.debug "Asset name: #{name}"
|
147
|
+
logger.debug "Asset configuration folder: #{folder}"
|
148
|
+
|
149
|
+
if File.exists?(folder)
|
150
|
+
logger.debug "initializing new asset with folder: #{folder}"
|
151
|
+
configuration.load(folder)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
def configuration
|
156
|
+
@configuration ||= RepoManager::AssetConfiguration.new(self)
|
157
|
+
end
|
158
|
+
|
159
|
+
# attributes is the hash loaded from the asset config file
|
160
|
+
def attributes
|
161
|
+
@attributes ||= {}
|
162
|
+
end
|
163
|
+
|
164
|
+
def to_hash
|
165
|
+
result = {}
|
166
|
+
result.merge!(:name => name) if name
|
167
|
+
result.merge!(:attributes => attributes)
|
168
|
+
result
|
169
|
+
end
|
170
|
+
|
171
|
+
# ERB binding
|
172
|
+
def get_binding
|
173
|
+
binding
|
174
|
+
end
|
175
|
+
|
176
|
+
# render a string with mustache tags replaced in the context of this class
|
177
|
+
#
|
178
|
+
# @return [String/nil] with mustache tags replaced or nil if template is nil
|
179
|
+
def render(template)
|
180
|
+
return nil unless template
|
181
|
+
|
182
|
+
Mustache.render(template, self)
|
183
|
+
end
|
184
|
+
|
185
|
+
# support for Mustache rendering of ad hoc user defined variables
|
186
|
+
# if the key exists in the hash, use if for a lookup
|
187
|
+
def method_missing(name, *args, &block)
|
188
|
+
return attributes[name.to_sym] if attributes.include?(name.to_sym)
|
189
|
+
return super
|
190
|
+
end
|
191
|
+
|
192
|
+
# method_missing support
|
193
|
+
def respond_to?(name)
|
194
|
+
return true if attributes.include?(name.to_sym)
|
195
|
+
super
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module RepoManager
|
2
|
+
|
3
|
+
# wrapper class for a source code repository configuration
|
4
|
+
class RepoAsset < AppAsset
|
5
|
+
|
6
|
+
# The asset_key, if defined, will be used as key to asset attributes when
|
7
|
+
# loading from YAML, if not defined, the entire YAML file will load.
|
8
|
+
#
|
9
|
+
# Override in decendants.
|
10
|
+
#
|
11
|
+
# @ return [Symbol] or nil
|
12
|
+
def asset_key
|
13
|
+
:repo
|
14
|
+
end
|
15
|
+
|
16
|
+
def status
|
17
|
+
@status ||= RepoManager::Status.new(scm)
|
18
|
+
end
|
19
|
+
|
20
|
+
# version control system wrapper
|
21
|
+
def scm
|
22
|
+
return @scm if @scm
|
23
|
+
raise NoSuchPathError unless File.exists?(path)
|
24
|
+
raise InvalidRepositoryError unless File.exists?(File.join(path, '.git'))
|
25
|
+
@scm = Git.open(path)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Array
|
2
|
+
def recursively_symbolize_keys!
|
3
|
+
self.each do |item|
|
4
|
+
if item.is_a? Hash
|
5
|
+
item.recursively_symbolize_keys!
|
6
|
+
elsif item.is_a? Array
|
7
|
+
item.recursively_symbolize_keys!
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def recursively_stringify_keys!
|
13
|
+
self.each do |item|
|
14
|
+
if item.is_a? Hash
|
15
|
+
item.recursively_stringify_keys!
|
16
|
+
elsif item.is_a? Array
|
17
|
+
item.recursively_stringify_keys!
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
|
5
|
+
# YAML suitable for configuration files
|
6
|
+
#
|
7
|
+
# returns sorted YAML if Ruby 1.8
|
8
|
+
# returns insertion ordered YAML on Ruby 1.9+
|
9
|
+
def to_conf
|
10
|
+
unless RUBY_VERSION =~ /^1.8/
|
11
|
+
# fix issue with strings that can end up in non UTF-8 encodings, like
|
12
|
+
# ASCII-8BIT, force encoding so that they are not written to YAML as binary
|
13
|
+
self.each_pair { |k,v| self[k] = ((v.is_a? String) ? v.force_encoding("UTF-8") : v)}
|
14
|
+
|
15
|
+
# allow 1.9+ to_yaml to do insertion ordered conf files
|
16
|
+
return to_yaml
|
17
|
+
end
|
18
|
+
|
19
|
+
opts = {}
|
20
|
+
YAML::quick_emit( object_id, opts ) do |out|
|
21
|
+
out.map( taguri, to_yaml_style ) do |map|
|
22
|
+
sorted_keys = keys
|
23
|
+
sorted_keys = begin
|
24
|
+
sorted_keys.sort
|
25
|
+
rescue
|
26
|
+
sorted_keys.sort_by {|k| k.to_s} rescue sorted_keys
|
27
|
+
end
|
28
|
+
|
29
|
+
sorted_keys.each do |k|
|
30
|
+
map.add( k, fetch(k) )
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# active_support hash key functions
|
37
|
+
def symbolize_keys!
|
38
|
+
self.replace(self.symbolize_keys)
|
39
|
+
end
|
40
|
+
|
41
|
+
def symbolize_keys
|
42
|
+
inject({}) do |options, (key, value)|
|
43
|
+
options[(key.to_sym rescue key) || key] = value
|
44
|
+
options
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def recursively_symbolize_keys!
|
49
|
+
self.symbolize_keys!
|
50
|
+
self.values.each do |v|
|
51
|
+
if v.is_a? Hash
|
52
|
+
v.recursively_symbolize_keys!
|
53
|
+
elsif v.is_a? Array
|
54
|
+
v.recursively_symbolize_keys!
|
55
|
+
end
|
56
|
+
end
|
57
|
+
self
|
58
|
+
end
|
59
|
+
|
60
|
+
def stringify_keys!
|
61
|
+
self.replace(self.stringify_keys)
|
62
|
+
end
|
63
|
+
|
64
|
+
def stringify_keys
|
65
|
+
inject({}) do |options, (key, value)|
|
66
|
+
options[(key.to_s rescue key) || key] = value
|
67
|
+
options
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def recursively_stringify_keys!
|
72
|
+
self.stringify_keys!
|
73
|
+
self.values.each do |v|
|
74
|
+
if v.is_a? Hash
|
75
|
+
v.recursively_stringify_keys!
|
76
|
+
elsif v.is_a? Array
|
77
|
+
v.recursively_stringify_keys!
|
78
|
+
end
|
79
|
+
end
|
80
|
+
self
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
# This is a modified version of the unreleased (as of 3/9/2012) Hashie Version 2
|
2
|
+
#
|
3
|
+
# It is modified to always convert new attributes to symbols and
|
4
|
+
# return nil if missing attribute so it works more like OpenStruct but
|
5
|
+
# still retains Hash as super
|
6
|
+
module RepoManager
|
7
|
+
module Extensions
|
8
|
+
|
9
|
+
# MethodReader allows you to access keys of the hash
|
10
|
+
# via method calls. This gives you an OStruct like way
|
11
|
+
# to access your hash's keys. It will recognize keys
|
12
|
+
# either as strings or symbols.
|
13
|
+
#
|
14
|
+
# @example Extending the Hash class
|
15
|
+
#
|
16
|
+
# class User < Hash
|
17
|
+
# include RepoManager::Extensions::MethodReader
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# user = User.new
|
21
|
+
# user['first_name'] = 'Michael'
|
22
|
+
# user.first_name # => 'Michael'
|
23
|
+
#
|
24
|
+
# user[:last_name] = 'Bleigh'
|
25
|
+
# user.last_name # => 'Bleigh'
|
26
|
+
#
|
27
|
+
# user[:birthday] = nil
|
28
|
+
# user.birthday # => nil
|
29
|
+
#
|
30
|
+
# user.not_declared # => nil
|
31
|
+
#
|
32
|
+
module MethodReader
|
33
|
+
def respond_to?(name)
|
34
|
+
return true if key?(name.to_s) || key?(name.to_sym)
|
35
|
+
super
|
36
|
+
end
|
37
|
+
|
38
|
+
def method_missing(name, *args)
|
39
|
+
return self[name.to_s] if key?(name.to_s)
|
40
|
+
return self[name.to_sym] if key?(name.to_sym)
|
41
|
+
|
42
|
+
# mod to return nil instead of 'undefined method'
|
43
|
+
return nil if args.length == 0
|
44
|
+
|
45
|
+
super
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# MethodWriter gives you #key_name= shortcuts for
|
50
|
+
# writing to your hash. Keys are written as symbols
|
51
|
+
#
|
52
|
+
# Note that MethodWriter also overrides #respond_to such
|
53
|
+
# that any #method_name= will respond appropriately as true.
|
54
|
+
#
|
55
|
+
# @example
|
56
|
+
#
|
57
|
+
# class MyHash < Hash
|
58
|
+
# include RepoManager::Extensions::MethodWriter
|
59
|
+
# end
|
60
|
+
#
|
61
|
+
# h = MyHash.new
|
62
|
+
# h.awesome = 'sauce'
|
63
|
+
# h['awesome'] # => 'sauce'
|
64
|
+
#
|
65
|
+
module MethodWriter
|
66
|
+
def respond_to?(name)
|
67
|
+
return true if name.to_s =~ /=$/
|
68
|
+
super
|
69
|
+
end
|
70
|
+
|
71
|
+
def method_missing(name, *args)
|
72
|
+
if args.size == 1 && name.to_s =~ /(.*)=$/
|
73
|
+
return self[convert_key($1)] = args.first
|
74
|
+
end
|
75
|
+
|
76
|
+
super
|
77
|
+
end
|
78
|
+
|
79
|
+
def convert_key(key)
|
80
|
+
# mod to return symbol keys instead of string keys
|
81
|
+
key.to_sym
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'git'
|
2
|
+
|
3
|
+
module Git
|
4
|
+
|
5
|
+
class CommandFailed < StandardError
|
6
|
+
attr_reader :command
|
7
|
+
attr_reader :exitstatus
|
8
|
+
attr_reader :error
|
9
|
+
|
10
|
+
def initialize(command, exitstatus, error='')
|
11
|
+
@command = command
|
12
|
+
@exitstatus = exitstatus
|
13
|
+
@error = error
|
14
|
+
super "Command exited with #{exitstatus}: #{command}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class Lib
|
19
|
+
|
20
|
+
# need 'git status --porcelain'
|
21
|
+
def required_command_version
|
22
|
+
[1, 7, 0, 0]
|
23
|
+
end
|
24
|
+
|
25
|
+
# validatation once and only once with warning to STDERR
|
26
|
+
def validate
|
27
|
+
return if defined? @@validated
|
28
|
+
unless meets_required_version?
|
29
|
+
$stderr.puts "[WARNING] The repo_manager gem requires git #{required_command_version.join('.')} or later for the status command functionality, but only found #{current_command_version.join('.')}. You should probably upgrade."
|
30
|
+
end
|
31
|
+
@@validated = true
|
32
|
+
end
|
33
|
+
|
34
|
+
# liberate the ruby-git's private command method with a few tweaks
|
35
|
+
def native(cmd, opts = [], chdir = true, redirect = '', &block)
|
36
|
+
validate
|
37
|
+
|
38
|
+
ENV['GIT_DIR'] = @git_dir
|
39
|
+
ENV['GIT_INDEX_FILE'] = @git_index_file
|
40
|
+
ENV['GIT_WORK_TREE'] = @git_work_dir
|
41
|
+
path = @git_work_dir || @git_dir || @path
|
42
|
+
|
43
|
+
opts = [opts].flatten.map {|s| escape(s) }.join(' ')
|
44
|
+
git_cmd = "git #{cmd} #{opts} #{redirect} 2>&1"
|
45
|
+
|
46
|
+
out = nil
|
47
|
+
if chdir && (Dir.getwd != path)
|
48
|
+
Dir.chdir(path) { out = run_command(git_cmd, &block) }
|
49
|
+
else
|
50
|
+
out = run_command(git_cmd, &block)
|
51
|
+
end
|
52
|
+
|
53
|
+
if @logger
|
54
|
+
@logger.info(git_cmd)
|
55
|
+
@logger.debug(out)
|
56
|
+
end
|
57
|
+
|
58
|
+
if $?.exitstatus > 0
|
59
|
+
if $?.exitstatus == 1 && out == ''
|
60
|
+
return ''
|
61
|
+
end
|
62
|
+
raise Git::CommandFailed.new(git_cmd, $?.exitstatus, out.to_s)
|
63
|
+
end
|
64
|
+
out
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|