repo_manager 0.7.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/.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,196 @@
|
|
|
1
|
+
module RepoManager
|
|
2
|
+
|
|
3
|
+
# Simplified version of ruby-git's class that uses Git's 'status --porcelain' command
|
|
4
|
+
#
|
|
5
|
+
# The --porcelain switch is useful since it handles ignored files and ignores
|
|
6
|
+
# non-commitable changes. Speed is not a big concern. There is only one
|
|
7
|
+
# call needed to the Git binary. No plumbing commands are used.
|
|
8
|
+
class Status
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
# repo status unchanged/clean
|
|
12
|
+
CLEAN = 0
|
|
13
|
+
|
|
14
|
+
# bitfields for status
|
|
15
|
+
NOPATH = 1
|
|
16
|
+
INVALID = 2
|
|
17
|
+
CHANGED = 4
|
|
18
|
+
ADDED = 8
|
|
19
|
+
DELETED = 16
|
|
20
|
+
UNTRACKED = 32
|
|
21
|
+
UNMERGED = 64
|
|
22
|
+
|
|
23
|
+
attr_reader :files
|
|
24
|
+
|
|
25
|
+
def initialize(scm)
|
|
26
|
+
@files = {}
|
|
27
|
+
@scm = scm
|
|
28
|
+
construct_status
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# @return [Numeric] 0 if CLEAN or bitfield with status: CHANGED | UNTRACKED | ADDED | DELETED | UNMERGED
|
|
32
|
+
def bitfield
|
|
33
|
+
# M ? A D U
|
|
34
|
+
(changed? ? CHANGED : 0) |
|
|
35
|
+
(untracked? ? UNTRACKED : 0) |
|
|
36
|
+
(added? ? ADDED : 0) |
|
|
37
|
+
(deleted? ? DELETED : 0) |
|
|
38
|
+
(unmerged? ? UNMERGED : 0)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def changed
|
|
42
|
+
@files.select { |k, f| f.type == 'M' }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def added
|
|
46
|
+
@files.select { |k, f| f.type == 'A' }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def deleted
|
|
50
|
+
@files.select { |k, f| f.type == 'D' }
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def untracked
|
|
54
|
+
@files.select { |k, f| f.type == '?' }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def unmerged
|
|
58
|
+
@files.select { |k, f| f.type == 'U' }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
# @return [Boolean] false unless a file has been modified/changed
|
|
62
|
+
def changed?
|
|
63
|
+
!changed.empty?
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# @return [Boolean] false unless a file has been added
|
|
67
|
+
def added?
|
|
68
|
+
!added.empty?
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# @return [Boolean] false unless a file has been deleted
|
|
72
|
+
def deleted?
|
|
73
|
+
!deleted.empty?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# @return [Boolean] false unless there is a new/untracked file
|
|
77
|
+
def untracked?
|
|
78
|
+
!untracked.empty?
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# @return [Boolean] false unless there is an unmerged file
|
|
82
|
+
def unmerged?
|
|
83
|
+
!unmerged.empty?
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def [](file)
|
|
87
|
+
@files[file]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def each
|
|
91
|
+
@files.each do |k, file|
|
|
92
|
+
yield file
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
class StatusFile
|
|
97
|
+
attr_accessor :path, :type
|
|
98
|
+
|
|
99
|
+
def initialize(hash)
|
|
100
|
+
@path = hash[:path]
|
|
101
|
+
@type = hash[:type]
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
private
|
|
106
|
+
|
|
107
|
+
def construct_status
|
|
108
|
+
# XY filename
|
|
109
|
+
# Y = working tree
|
|
110
|
+
#
|
|
111
|
+
# From git 1.7+ documentation
|
|
112
|
+
#
|
|
113
|
+
# X Y Meaning
|
|
114
|
+
# -------------------------------------------------
|
|
115
|
+
# [MD] not updated
|
|
116
|
+
# M [ MD] updated in index
|
|
117
|
+
# A [ MD] added to index
|
|
118
|
+
# D [ MD] deleted from index
|
|
119
|
+
# R [ MD] renamed in index
|
|
120
|
+
# C [ MD] copied in index
|
|
121
|
+
# [MARC] index and work tree matches
|
|
122
|
+
# [ MARC] M work tree changed since index
|
|
123
|
+
# [ MARC] D deleted in work tree
|
|
124
|
+
# -------------------------------------------------
|
|
125
|
+
# D D unmerged, both deleted
|
|
126
|
+
# A U unmerged, added by us
|
|
127
|
+
# U D unmerged, deleted by them
|
|
128
|
+
# U A unmerged, added by them
|
|
129
|
+
# D U unmerged, deleted by us
|
|
130
|
+
# A A unmerged, both added
|
|
131
|
+
# U U unmerged, both modified
|
|
132
|
+
# -------------------------------------------------
|
|
133
|
+
# ? ? untracked
|
|
134
|
+
# -------------------------------------------------
|
|
135
|
+
#
|
|
136
|
+
#
|
|
137
|
+
# simplify porcelain output:
|
|
138
|
+
#
|
|
139
|
+
# combine X and Y and boil down status returns to just five types,
|
|
140
|
+
# M ? A D U
|
|
141
|
+
#
|
|
142
|
+
# example output:
|
|
143
|
+
#
|
|
144
|
+
# output = [" M .gitignore", "R testing s.txt", "test space.txt", "?? new_file1.txt"]
|
|
145
|
+
#
|
|
146
|
+
# show working folder status with just five status condtions
|
|
147
|
+
#
|
|
148
|
+
# exact matches for untracked and unmerged
|
|
149
|
+
#
|
|
150
|
+
# '??' => 'untracked' [untracked.blue]
|
|
151
|
+
# 'DD', 'AU', 'UD', 'UA', 'DU', 'AA', 'UU' => 'unmerged' [unmerged.red.bold]
|
|
152
|
+
#
|
|
153
|
+
# added with working folder clear
|
|
154
|
+
#
|
|
155
|
+
# /R./ => 'renamed' [added.green], special handling required
|
|
156
|
+
# /A /, /M /, /D /, /R /, /C / => 'added' [added.green]
|
|
157
|
+
#
|
|
158
|
+
# everything else can be described by working folder status character
|
|
159
|
+
#
|
|
160
|
+
# /.D/ => 'deleted', [deleted.yellow]
|
|
161
|
+
# /.M/ => 'modified', [changed.red]
|
|
162
|
+
|
|
163
|
+
output = @scm.lib.native('status', ['--porcelain', '-z']).split("\000")
|
|
164
|
+
while line = output.shift
|
|
165
|
+
next unless line && line.length > 3
|
|
166
|
+
file_hash = nil
|
|
167
|
+
# first two chars, XY format
|
|
168
|
+
st = line[0..1]
|
|
169
|
+
# skip the space
|
|
170
|
+
filename = line[3..-1]
|
|
171
|
+
|
|
172
|
+
# renamed/copied files 'to -> from', 'from' will be on the next line,
|
|
173
|
+
# shift it off as we don't track this
|
|
174
|
+
output.shift if st.match(/[R|C]/)
|
|
175
|
+
|
|
176
|
+
case st
|
|
177
|
+
when '??'
|
|
178
|
+
file_hash = {:type => '?', :path => filename}
|
|
179
|
+
when 'DD', 'AU', 'UD', 'UA', 'DU', 'AA', 'UU'
|
|
180
|
+
file_hash = {:type => 'U', :path => filename}
|
|
181
|
+
when 'A ', 'M ', 'D ', 'R ', 'C '
|
|
182
|
+
file_hash = {:type => 'A', :path => filename}
|
|
183
|
+
when /.D/
|
|
184
|
+
file_hash = {:type => 'D', :path => filename}
|
|
185
|
+
when /.M/
|
|
186
|
+
file_hash = {:type => 'M', :path => filename}
|
|
187
|
+
else
|
|
188
|
+
raise "fatal error: unknown git status condition: '#{st}'"
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
@files[filename] = StatusFile.new(file_hash) if (file_hash && filename)
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
195
|
+
end
|
|
196
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require 'logging'
|
|
2
|
+
include Logging.globally
|
|
3
|
+
|
|
4
|
+
module RepoManager
|
|
5
|
+
module Logger
|
|
6
|
+
|
|
7
|
+
class Manager
|
|
8
|
+
|
|
9
|
+
def initialize(config_filename=nil, yaml_key=nil, configuration={})
|
|
10
|
+
|
|
11
|
+
options = configuration[:options] || {}
|
|
12
|
+
|
|
13
|
+
if config_filename && yaml_key && configuration.has_key?(yaml_key)
|
|
14
|
+
Logging::Config::YamlConfigurator.load(config_filename, yaml_key.to_s)
|
|
15
|
+
else
|
|
16
|
+
# setup a default root level STDOUT logger
|
|
17
|
+
format = {:pattern => '%-5l %c: %m\n'}
|
|
18
|
+
format = format.merge(:color_scheme => 'default') if options[:color]
|
|
19
|
+
Logging.appenders.stdout('stdout', :layout => Logging.layouts.pattern(format), :level => :info)
|
|
20
|
+
Logging.logger.root.add_appenders('stdout')
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# if verbose, all defined loggers are set to debug level
|
|
24
|
+
if options[:verbose]
|
|
25
|
+
Logging.appenders.each do |appender|
|
|
26
|
+
appender.level = :debug
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# debug
|
|
31
|
+
#Logging.show_configuration
|
|
32
|
+
#logger.error "error"
|
|
33
|
+
#logger.warn "warn"
|
|
34
|
+
#logger.info "info"
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'yaml'
|
|
2
|
+
require 'erb'
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'repo_manager/extensions/hash'
|
|
5
|
+
|
|
6
|
+
module RepoManager
|
|
7
|
+
|
|
8
|
+
# Access setting via symbolized keys or using accessor methods
|
|
9
|
+
#
|
|
10
|
+
# @example
|
|
11
|
+
#
|
|
12
|
+
# settings = Settings.new(FileUtils.pwd, {:config => 'some/file.yml'})
|
|
13
|
+
#
|
|
14
|
+
# verbose = settings.to_hash[:options] ? settings.to_hash[:options][:verbose] : false
|
|
15
|
+
#
|
|
16
|
+
# equivalent to:
|
|
17
|
+
#
|
|
18
|
+
# verbose = settings.options ? settings.options.verbose : false
|
|
19
|
+
#
|
|
20
|
+
# @return [Hash], for pure hash use 'to_hash' instead
|
|
21
|
+
class Settings < Hash
|
|
22
|
+
include RepoManager::Extensions::MethodReader
|
|
23
|
+
include RepoManager::Extensions::MethodWriter
|
|
24
|
+
|
|
25
|
+
def initialize(working_dir=nil, options={})
|
|
26
|
+
@working_dir = working_dir || FileUtils.pwd
|
|
27
|
+
@configuration = configure(options)
|
|
28
|
+
|
|
29
|
+
# call super without args
|
|
30
|
+
super *[]
|
|
31
|
+
|
|
32
|
+
self.merge!(@configuration)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
# read options from YAML config
|
|
38
|
+
def configure(options)
|
|
39
|
+
|
|
40
|
+
# config file default options
|
|
41
|
+
configuration = {
|
|
42
|
+
:options => {
|
|
43
|
+
:verbose => false,
|
|
44
|
+
:color => 'AUTO',
|
|
45
|
+
:short => false,
|
|
46
|
+
:unmodified => 'HIDE',
|
|
47
|
+
:match => 'ALL',
|
|
48
|
+
:list => 'ALL'
|
|
49
|
+
},
|
|
50
|
+
:commands => [
|
|
51
|
+
'diff',
|
|
52
|
+
'grep',
|
|
53
|
+
'log',
|
|
54
|
+
'ls-files',
|
|
55
|
+
'show',
|
|
56
|
+
'status'
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
# set default config if not given on command line
|
|
61
|
+
config = options[:config]
|
|
62
|
+
if config.nil?
|
|
63
|
+
config = [
|
|
64
|
+
File.join(@working_dir, "repo.conf"),
|
|
65
|
+
File.join(@working_dir, ".repo.conf"),
|
|
66
|
+
File.join(@working_dir, "repo_manager", "repo.conf"),
|
|
67
|
+
File.join(@working_dir, ".repo_manager", "repo.conf"),
|
|
68
|
+
File.join(@working_dir, "config", "repo.conf"),
|
|
69
|
+
File.expand_path(File.join("~", ".repo.conf")),
|
|
70
|
+
File.expand_path(File.join("~", "repo.conf")),
|
|
71
|
+
File.expand_path(File.join("~", "repo_manager", "repo.conf")),
|
|
72
|
+
File.expand_path(File.join("~", ".repo_manager", "repo.conf"))
|
|
73
|
+
].detect { |filename| File.exists?(filename) }
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
if config && File.exists?(config)
|
|
77
|
+
# load options from the config file, overwriting hard-coded defaults
|
|
78
|
+
logger.debug "reading configuration file: #{config}"
|
|
79
|
+
config_contents = YAML.load(ERB.new(File.open(config, "rb").read).result)
|
|
80
|
+
configuration.merge!(config_contents.symbolize_keys!) if config_contents && config_contents.is_a?(Hash)
|
|
81
|
+
else
|
|
82
|
+
# user specified a config file?, no error if user did not specify config file
|
|
83
|
+
raise "config file not found" if options[:config]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# store the original full config filename for later use
|
|
87
|
+
configuration[:configuration_filename] = config
|
|
88
|
+
|
|
89
|
+
configuration.recursively_symbolize_keys!
|
|
90
|
+
|
|
91
|
+
# the command line options override options read from the config file
|
|
92
|
+
configuration[:options].merge!(options)
|
|
93
|
+
configuration
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
require 'repo_manager'
|
|
2
|
+
require 'repo_manager/tasks/task_manager'
|
|
3
|
+
require 'repo_manager/actions/action_helper'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
|
|
6
|
+
module RepoManager
|
|
7
|
+
|
|
8
|
+
module GenerateHelper
|
|
9
|
+
|
|
10
|
+
def asset_name_to_config_file(name=nil)
|
|
11
|
+
raise ArgumentError, "missing name" unless name
|
|
12
|
+
raise "unable to find configuration key ':folders'" unless configuration[:folders]
|
|
13
|
+
raise "unable to find configuration key ':folders => :assets'" unless configuration[:folders][:assets]
|
|
14
|
+
|
|
15
|
+
folder = configuration.folders[:assets]
|
|
16
|
+
unless folder
|
|
17
|
+
say "unable to find folder conf key ':folders => :assets', please set key"
|
|
18
|
+
exit 1
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
unless Pathname.new(folder).absolute?
|
|
22
|
+
base_folder = File.dirname(configuration[:configuration_filename])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
file = File.join(base_folder, folder, name, "asset.conf")
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
module AddHelper
|
|
31
|
+
|
|
32
|
+
def process_discovered_assets(discovered_assets=[])
|
|
33
|
+
|
|
34
|
+
say_status "configuring", "setting discovered asset attributes"
|
|
35
|
+
discovered_assets.each do |discovered_asset|
|
|
36
|
+
folder = File.dirname(asset_name_to_config_file(discovered_asset.name))
|
|
37
|
+
discovered_asset.configuration.folder = folder
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
if options[:refresh]
|
|
41
|
+
if existing_assets.any? && discovered_assets.any?
|
|
42
|
+
say_status "merging", "merging existing asset attributes"
|
|
43
|
+
discovered_assets.each do |discovered_asset|
|
|
44
|
+
existing_asset = existing_assets.detect do |existing_asset|
|
|
45
|
+
existing_asset.name == discovered_asset.name
|
|
46
|
+
end
|
|
47
|
+
discovered_asset.attributes.merge!(existing_asset.attributes) if existing_asset
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
else
|
|
51
|
+
say_status "comparing", "looking at existing asset names"
|
|
52
|
+
discovered_assets.delete_if do |asset|
|
|
53
|
+
result = false
|
|
54
|
+
if File.exists?(asset.configuration.folder)
|
|
55
|
+
logger.debug "#{asset.name} asset name already exists, skipping"
|
|
56
|
+
result = true
|
|
57
|
+
end
|
|
58
|
+
result
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
say_status "comparing", "looking at existing asset paths"
|
|
62
|
+
discovered_assets.delete_if do |asset|
|
|
63
|
+
result = false
|
|
64
|
+
existing_asset = existing_assets.detect do |existing_asset|
|
|
65
|
+
existing_asset.path && asset.path && (File.expand_path(existing_asset.path) == File.expand_path(asset.path))
|
|
66
|
+
end
|
|
67
|
+
if (existing_asset)
|
|
68
|
+
logger.debug "#{asset.name} path matches existing asset #{existing_asset.name}, skipping"
|
|
69
|
+
result = true
|
|
70
|
+
end
|
|
71
|
+
result
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
unless discovered_assets.any?
|
|
76
|
+
say "no assets found for updating"
|
|
77
|
+
exit 0
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# list the new assets found
|
|
81
|
+
say "Discovered assets"
|
|
82
|
+
discovered_assets.each do |asset|
|
|
83
|
+
say_status :found, "%-40s path => '%s'" % [asset.name, relative_path(asset.path)] , :green
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# prompt the user
|
|
87
|
+
say
|
|
88
|
+
unless options[:force]
|
|
89
|
+
exit 0 unless (ask("Found #{discovered_assets.size} asset(s), write the configuration file(s) (y/n)?") == 'y')
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# write the assets
|
|
93
|
+
say
|
|
94
|
+
discovered_assets.each do |asset|
|
|
95
|
+
|
|
96
|
+
say_status :creating, "repo_manager configuration file for #{asset.name}", :green
|
|
97
|
+
logger.debug "writing asset #{asset.name} to #{asset.configuration.folder}"
|
|
98
|
+
asset.attributes.merge!(:parent => "../global/default")
|
|
99
|
+
save_writable_attributes(asset, asset.attributes)
|
|
100
|
+
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
class Add < Thor
|
|
108
|
+
namespace :add
|
|
109
|
+
include Thor::Actions
|
|
110
|
+
include RepoManager::ThorHelper
|
|
111
|
+
include RepoManager::GenerateHelper
|
|
112
|
+
include RepoManager::AddHelper
|
|
113
|
+
include ::RepoManager::ActionHelper
|
|
114
|
+
|
|
115
|
+
# adds :quiet, :skip, :pretent, :force
|
|
116
|
+
add_runtime_options!
|
|
117
|
+
|
|
118
|
+
method_option :filter, :type => :array, :aliases => "-f", :desc => "List of regex folder name filters"
|
|
119
|
+
method_option :refresh, :type => :boolean, :aliases => "-r", :desc => "Refresh existing blank attributes"
|
|
120
|
+
|
|
121
|
+
desc "assets FOLDER", "generate multiple config files by searching a folder, one level deep, for git repositories"
|
|
122
|
+
def assets(folder)
|
|
123
|
+
say_status "collecting", "collecting top level folder names"
|
|
124
|
+
discovered_assets = []
|
|
125
|
+
filters = options[:filter] || ['.*']
|
|
126
|
+
# Thor does not allow comma separated array options, fix that here
|
|
127
|
+
filters = filters.first.to_s.split(',') if filters.length == 1
|
|
128
|
+
Dir.glob( File.join(folder, '*/') ).each do |repo_folder|
|
|
129
|
+
logger.debug "filters: #{filters.inspect}"
|
|
130
|
+
next unless filters.find {|filter| repo_folder.match(/#{filter}/)}
|
|
131
|
+
next unless File.exists?(File.join(repo_folder, '.git/'))
|
|
132
|
+
|
|
133
|
+
# check existing assets for path match, if found, use existing name instead of the generated name
|
|
134
|
+
existing = existing_assets.detect do |existing_asset|
|
|
135
|
+
existing_asset.path && repo_folder && (File.expand_path(existing_asset.path) == File.expand_path(repo_folder))
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
if (existing)
|
|
139
|
+
name = existing.name
|
|
140
|
+
else
|
|
141
|
+
name = File.basename(repo_folder)
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
asset = ::RepoManager::RepoAsset.new(name)
|
|
145
|
+
asset.path = File.expand_path(repo_folder)
|
|
146
|
+
|
|
147
|
+
discovered_assets << asset
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
process_discovered_assets(discovered_assets)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
method_option :name, :type => :string, :aliases => "-n", :desc => "given the asset a specific name"
|
|
154
|
+
|
|
155
|
+
desc "asset FOLDER", "generate a single repo asset file given a working folder"
|
|
156
|
+
def asset(folder)
|
|
157
|
+
discovered_assets = []
|
|
158
|
+
unless File.exists?(File.join(folder, '.git/'))
|
|
159
|
+
say_status :error, "unable to find '.git' folder in working folder '#{folder}'", :red
|
|
160
|
+
exit 1
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
# check existing assets for path match, if found, use existing name instead of the generated name
|
|
164
|
+
existing = existing_assets.detect do |existing_asset|
|
|
165
|
+
existing_asset.path && folder && (File.expand_path(existing_asset.path) == File.expand_path(folder))
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
if (existing)
|
|
169
|
+
name = existing.name
|
|
170
|
+
if options[:name]
|
|
171
|
+
say_status :error, "asset already exists under a different name '#{name}'", :red
|
|
172
|
+
exit 1
|
|
173
|
+
end
|
|
174
|
+
else
|
|
175
|
+
name = options[:name]
|
|
176
|
+
name ||= File.basename(folder)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
asset = ::RepoManager::RepoAsset.new(name)
|
|
180
|
+
asset.path = File.expand_path(folder)
|
|
181
|
+
|
|
182
|
+
discovered_assets << asset
|
|
183
|
+
process_discovered_assets(discovered_assets)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
private
|
|
187
|
+
|
|
188
|
+
# where to start looking, required by the template method
|
|
189
|
+
def self.source_root
|
|
190
|
+
File.dirname(__FILE__)
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# write only the attributes that we have set
|
|
194
|
+
def save_writable_attributes(asset, attributes)
|
|
195
|
+
valid_keys = [:parent, :path]
|
|
196
|
+
accessable_attributes = {}
|
|
197
|
+
attributes.each do |key, value|
|
|
198
|
+
accessable_attributes[key] = value.dup if valid_keys.include?(key)
|
|
199
|
+
end
|
|
200
|
+
asset.configuration.save(accessable_attributes)
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
def existing_assets
|
|
204
|
+
return @existing_assets if @existing_assets
|
|
205
|
+
asset_options = {}
|
|
206
|
+
asset_options.merge!(:assets_folder => configuration[:folders][:assets]) if configuration[:folders]
|
|
207
|
+
asset_options.merge!(:base_folder => File.dirname(configuration[:configuration_filename])) if configuration[:configuration_filename]
|
|
208
|
+
|
|
209
|
+
@existing_assets = ::RepoManager::AssetManager.new.assets(asset_options)
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
end
|
|
213
|
+
end
|