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,71 @@
|
|
1
|
+
module RepoManager
|
2
|
+
|
3
|
+
# @group CLI actions
|
4
|
+
#
|
5
|
+
# Invoke external tasks, normally Thor tasks
|
6
|
+
#
|
7
|
+
# @example Usage: repo task TASK [args]
|
8
|
+
#
|
9
|
+
# repo task repo_manager:sweep:screenshots /to/some/folder
|
10
|
+
# repo repo_manager:sweep:screenshots /to/some/folder
|
11
|
+
#
|
12
|
+
# @example General task help:
|
13
|
+
#
|
14
|
+
# repo help task
|
15
|
+
#
|
16
|
+
# @example Help for specific task
|
17
|
+
#
|
18
|
+
# repo task help repo_manager:sweep:screenshots
|
19
|
+
# repo help repo_manager:sweep:screenshots
|
20
|
+
#
|
21
|
+
# @example Display a list of tasks
|
22
|
+
#
|
23
|
+
# repo task -T
|
24
|
+
# repo -T
|
25
|
+
#
|
26
|
+
# repo task --tasks
|
27
|
+
# repo --tasks
|
28
|
+
#
|
29
|
+
# @return [Number] exit code from task
|
30
|
+
class TaskAction < AppAction
|
31
|
+
|
32
|
+
# Add action specific options
|
33
|
+
def parse_options
|
34
|
+
super(:raise_on_invalid_option => false, :parse_base_options => false) do |opts|
|
35
|
+
|
36
|
+
opts.on("-T", "--tasks", "List tasks") do |t|
|
37
|
+
options[:tasks] = t
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def process
|
44
|
+
# Thor actions can include toxic side effects,
|
45
|
+
# keep the namespace clean until needed
|
46
|
+
require 'repo_manager/tasks/task_manager'
|
47
|
+
task_manager = RepoManager::TaskManager.new(configuration)
|
48
|
+
|
49
|
+
if options[:tasks]
|
50
|
+
task_manager.list_tasks
|
51
|
+
return 0
|
52
|
+
end
|
53
|
+
|
54
|
+
raise "task name required" if args.empty?
|
55
|
+
|
56
|
+
target = args.shift
|
57
|
+
|
58
|
+
if target == "help"
|
59
|
+
target = args.shift
|
60
|
+
task_manager.task_help(target)
|
61
|
+
else
|
62
|
+
task_manager.invoke(target, args)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def help
|
67
|
+
super(:comment_starting_with => "Invoke", :located_in_file => __FILE__)
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'term/ansicolor'
|
2
|
+
|
3
|
+
class String
|
4
|
+
include Term::ANSIColor
|
5
|
+
end
|
6
|
+
|
7
|
+
module RepoManager
|
8
|
+
|
9
|
+
AVAILABLE_ACTIONS = %w[help list task path status git]
|
10
|
+
|
11
|
+
# Commands that don't need to have the 'git' arg precede them. These are not
|
12
|
+
# necessarily the same as the allowed 'commands' specified in the repo.conf
|
13
|
+
# file.
|
14
|
+
# NOTE: `git help --all` for a full list of git supported commands
|
15
|
+
GIT_NATIVE_SUPPORT = %w[add config commit diff fetch log pull push show ls-files grep]
|
16
|
+
|
17
|
+
class App
|
18
|
+
|
19
|
+
# bin wrapper option parser object
|
20
|
+
attr_accessor :option_parser
|
21
|
+
|
22
|
+
def initialize(argv=[], configuration={})
|
23
|
+
@configuration = configuration
|
24
|
+
@options = configuration[:options] || {}
|
25
|
+
@argv = argv
|
26
|
+
$stdout.sync = true
|
27
|
+
|
28
|
+
config_filename = configuration[:configuration_filename]
|
29
|
+
RepoManager::Logger::Manager.new(config_filename, :logging, configuration)
|
30
|
+
|
31
|
+
logger.debug "configuration: #{@configuration.inspect}"
|
32
|
+
logger.debug "argv: #{@argv.inspect}"
|
33
|
+
logger.debug "config file: #{configuration[:configuration_filename]}" if configuration[:configuration_filename]
|
34
|
+
end
|
35
|
+
|
36
|
+
def execute
|
37
|
+
begin
|
38
|
+
|
39
|
+
args = @argv
|
40
|
+
if action_argument_required?
|
41
|
+
action = @argv.shift
|
42
|
+
|
43
|
+
# push action back to args if this is a native pass-through command
|
44
|
+
if GIT_NATIVE_SUPPORT.include?(action)
|
45
|
+
args.unshift(action)
|
46
|
+
action = 'git'
|
47
|
+
end
|
48
|
+
|
49
|
+
# special case: actionless tasks
|
50
|
+
action = 'task' if action.nil? && @options.include?(:tasks)
|
51
|
+
|
52
|
+
# special case: `repo sweep:screenshots` is an acceptable task action
|
53
|
+
if action && action.match(/[a-zA-Z]+:+/)
|
54
|
+
args.unshift(action)
|
55
|
+
action = 'task'
|
56
|
+
end
|
57
|
+
|
58
|
+
# special case: `repo help sweep:screenshots` is an acceptable task help action
|
59
|
+
if action == 'help' && args.any?
|
60
|
+
target = args[0]
|
61
|
+
if target.match(/[a-zA-Z]+:+/)
|
62
|
+
args.unshift(action)
|
63
|
+
action = 'task'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
unless AVAILABLE_ACTIONS.include?(action)
|
68
|
+
if action.nil?
|
69
|
+
puts "repo action required"
|
70
|
+
else
|
71
|
+
puts "repo invalid action: #{action}"
|
72
|
+
end
|
73
|
+
puts "repo --help for more information"
|
74
|
+
exit 1
|
75
|
+
end
|
76
|
+
logger.debug "execute action: #{action} #{args.join(' ')}"
|
77
|
+
klass = Object.const_get('RepoManager').const_get("#{action.capitalize}Action")
|
78
|
+
app_action = klass.new(args, @configuration)
|
79
|
+
app_action.option_parser = self.option_parser
|
80
|
+
result = app_action.execute
|
81
|
+
else
|
82
|
+
#
|
83
|
+
# default action if action_argument_required? is false
|
84
|
+
#
|
85
|
+
result = 0
|
86
|
+
end
|
87
|
+
|
88
|
+
if result.is_a?(Numeric)
|
89
|
+
exit(result)
|
90
|
+
else
|
91
|
+
# handle all other return types
|
92
|
+
exit(result ? 0 : 1)
|
93
|
+
end
|
94
|
+
|
95
|
+
rescue SystemExit => e
|
96
|
+
# This is the normal exit point
|
97
|
+
logger.debug "repo run system exit: #{e}, status code: #{e.status}"
|
98
|
+
exit(e.status)
|
99
|
+
rescue Exception => e
|
100
|
+
logger.fatal("repo fatal exception: #{e.message}")
|
101
|
+
STDERR.puts("repo failed: #{e.message}".red)
|
102
|
+
STDERR.puts("Command failed, use '--verbose' for backtrace.") unless @options[:verbose]
|
103
|
+
STDERR.puts(e.backtrace.join("\n")) if @options[:verbose]
|
104
|
+
exit(1)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
# true if application requires an action to be specified on the command line
|
111
|
+
def action_argument_required?
|
112
|
+
!AVAILABLE_ACTIONS.empty?
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,15 @@
|
|
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
|
+
module RepoManager
|
9
|
+
|
10
|
+
# An abstract superclass for basic asset functionality specific to an
|
11
|
+
# application implementation. Put application specific code here.
|
12
|
+
class AppAsset < BaseAsset
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
module RepoManager
|
2
|
+
|
3
|
+
module AssetAccessors
|
4
|
+
|
5
|
+
# Given an array, create accessors
|
6
|
+
# NOTE: This is similar to using method_missing with a whitelist
|
7
|
+
#
|
8
|
+
# @return [void]
|
9
|
+
def create_accessors(*attrs)
|
10
|
+
return unless attrs
|
11
|
+
raise ArgumentError, "Expected 'user_attributes' to be an array" unless attrs.is_a? Array
|
12
|
+
|
13
|
+
# Define each of the attributes
|
14
|
+
attrs.flatten.each do |attr|
|
15
|
+
create_accessor(attr)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def create_accessor(attr)
|
20
|
+
create_reader(attr)
|
21
|
+
create_writer(attr)
|
22
|
+
end
|
23
|
+
|
24
|
+
def create_reader(attr)
|
25
|
+
return unless attr
|
26
|
+
|
27
|
+
method = "#{attr}".to_sym
|
28
|
+
|
29
|
+
if self.kind_of? RepoManager::BaseAsset
|
30
|
+
return if self.respond_to? method
|
31
|
+
|
32
|
+
self.class.send(:define_method, method) do
|
33
|
+
render(attributes[method])
|
34
|
+
end
|
35
|
+
else
|
36
|
+
return if respond_to? method
|
37
|
+
|
38
|
+
define_method(method) do
|
39
|
+
render(attributes[method])
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_writer(attr)
|
45
|
+
return unless attr
|
46
|
+
|
47
|
+
method = "#{attr}=".to_sym
|
48
|
+
|
49
|
+
if self.kind_of? RepoManager::BaseAsset
|
50
|
+
return if self.respond_to? method
|
51
|
+
|
52
|
+
self.class.send(:define_method, method) do |value|
|
53
|
+
attributes[attr] = value
|
54
|
+
end
|
55
|
+
else
|
56
|
+
return if respond_to? method
|
57
|
+
|
58
|
+
define_method(method) do |value|
|
59
|
+
attributes[attr] = value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
@@ -0,0 +1,137 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'erb'
|
3
|
+
require 'pathname'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
module RepoManager
|
7
|
+
|
8
|
+
# asset_configuration saves just the user data by subtracting out the
|
9
|
+
# global hash and writing just the result
|
10
|
+
#
|
11
|
+
# An asset requires a global template but doesn't require a user datafile.
|
12
|
+
#
|
13
|
+
# LOADING:
|
14
|
+
#
|
15
|
+
# Load up the master template YAML file first, evaluate the ERB, save this
|
16
|
+
# hash for later use.
|
17
|
+
#
|
18
|
+
# Copy the results to the asset attributes and then load the user data. The
|
19
|
+
# user data doesn't contain ERB.
|
20
|
+
#
|
21
|
+
# SAVING:
|
22
|
+
#
|
23
|
+
# Compare existing asset attributes to the saved and eval'd master hash and write
|
24
|
+
# just the change assets to the user file.
|
25
|
+
#
|
26
|
+
class AssetConfiguration
|
27
|
+
|
28
|
+
# user datastore folder, can override parent datastore
|
29
|
+
attr_accessor :folder
|
30
|
+
|
31
|
+
# parent datastore defaults folder, read asset from here first if exists
|
32
|
+
attr_accessor :parent
|
33
|
+
|
34
|
+
attr_reader :asset
|
35
|
+
|
36
|
+
def initialize(asset)
|
37
|
+
#logger.debug "initializing new AssetConfiguration with asset class: #{asset.class.to_s}"
|
38
|
+
@asset = asset
|
39
|
+
end
|
40
|
+
|
41
|
+
# Save specific attributes to an asset configuration file. Only the param
|
42
|
+
# 'attrs' and the current contents of the config file are saved. Parent
|
43
|
+
# asset configurations are not saved.
|
44
|
+
#
|
45
|
+
def save(attrs=nil)
|
46
|
+
raise "a Hash of attributes to save must be specified" unless attrs && attrs.is_a?(Hash)
|
47
|
+
raise "folder must be set prior to saving attributes" unless folder
|
48
|
+
|
49
|
+
# merge attributes to asset that contains parent attributes
|
50
|
+
@asset.attributes.merge!(attrs)
|
51
|
+
|
52
|
+
# load contents of the user folder and merge in attributes passed to save
|
53
|
+
# so that we don't save parent attributes
|
54
|
+
contents = {}
|
55
|
+
if File.exists?(folder)
|
56
|
+
contents = load_contents(folder)
|
57
|
+
raise "expected contents to be a hash" unless contents.is_a?(Hash)
|
58
|
+
end
|
59
|
+
|
60
|
+
contents = contents.merge!(attrs)
|
61
|
+
write_contents(folder, contents)
|
62
|
+
end
|
63
|
+
|
64
|
+
# load an asset from a configuration folder
|
65
|
+
def load(ds=nil)
|
66
|
+
@folder ||= ds
|
67
|
+
|
68
|
+
contents = load_contents(folder)
|
69
|
+
|
70
|
+
# if a global parent folder is defined, load it first
|
71
|
+
parent = contents.delete(:parent) || parent
|
72
|
+
if parent
|
73
|
+
parent_folder = File.join(parent)
|
74
|
+
unless Pathname.new(parent_folder).absolute?
|
75
|
+
base_folder = File.dirname(folder)
|
76
|
+
parent_folder = File.join(base_folder, parent_folder)
|
77
|
+
end
|
78
|
+
|
79
|
+
logger.debug "AssetConfiguration loading parent: #{parent_folder}"
|
80
|
+
parent_configuration = RepoManager::AssetConfiguration.new(asset)
|
81
|
+
|
82
|
+
begin
|
83
|
+
parent_configuration.load(parent_folder)
|
84
|
+
rescue Exception => e
|
85
|
+
logger.warn "AssetConfiguration parent configuration load failed on: '#{parent_folder}' with: '#{e.message}'"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Load all attributes as hash 'attributes' so that merging
|
90
|
+
# and adding new attributes doesn't require code changes. Note
|
91
|
+
# that the 'parent' setting is not merged to attributes
|
92
|
+
@asset.attributes.merge!(contents)
|
93
|
+
@asset.create_accessors(@asset.attributes[:user_attributes])
|
94
|
+
@asset
|
95
|
+
end
|
96
|
+
|
97
|
+
def to_hash
|
98
|
+
result = {}
|
99
|
+
result.merge!(:parent => parent.folder) if parent
|
100
|
+
result.merge!(:attributes => @asset.attributes)
|
101
|
+
result
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
# load the raw contents from an asset_folder, ignore parents
|
107
|
+
#
|
108
|
+
# @return [Hash] of the raw text contents
|
109
|
+
def load_contents(asset_folder)
|
110
|
+
file = File.join(asset_folder, 'asset.conf')
|
111
|
+
if File.exists?(file)
|
112
|
+
contents = YAML.load(ERB.new(File.open(file, "rb").read).result(@asset.get_binding))
|
113
|
+
if contents && contents.is_a?(Hash)
|
114
|
+
contents.recursively_symbolize_keys!
|
115
|
+
else
|
116
|
+
{}
|
117
|
+
end
|
118
|
+
else
|
119
|
+
{}
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# write raw contents to an asset_folder
|
124
|
+
def write_contents(asset_folder, contents)
|
125
|
+
contents.recursively_stringify_keys!
|
126
|
+
|
127
|
+
FileUtils.mkdir(asset_folder) unless File.exists?(asset_folder)
|
128
|
+
filename = File.join(asset_folder, 'asset.conf')
|
129
|
+
|
130
|
+
#TODO, use "wb" and write CRLF on Windows
|
131
|
+
File.open(filename, "w") do |f|
|
132
|
+
f.write(contents.to_conf)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,72 @@
|
|
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
|
+
|
9
|
+
require 'pathname'
|
10
|
+
require 'fileutils'
|
11
|
+
|
12
|
+
module RepoManager
|
13
|
+
|
14
|
+
class AssetManager
|
15
|
+
|
16
|
+
# @raise [Exception] unless asset_options contains base_folder or :assets if an absolute path
|
17
|
+
#
|
18
|
+
# @return [Array] of Asset
|
19
|
+
def assets(asset_options={})
|
20
|
+
logger.debug "asset_options: #{asset_options.inspect}"
|
21
|
+
# type of asset to create, used to guess the asset_folder name
|
22
|
+
type = asset_options[:type] || :app_asset
|
23
|
+
|
24
|
+
assets = []
|
25
|
+
filters = asset_options[:filter] || ['.*']
|
26
|
+
match_count = 0
|
27
|
+
logger.debug "generating assets array with filter array: #{filters.join(',')}"
|
28
|
+
|
29
|
+
assets_folder = asset_options[:assets_folder] || "assets"
|
30
|
+
pattern = File.join(assets_folder, '*/')
|
31
|
+
logger.debug "reading from asset type: '#{type}' from assets_folder:'#{assets_folder}' "
|
32
|
+
|
33
|
+
# asset folder can be relative to main config file
|
34
|
+
unless Pathname.new(pattern).absolute?
|
35
|
+
# base_folder is determined from the configuration file
|
36
|
+
# location, if it is not set, then the configuration file wasn't not found
|
37
|
+
raise "configuration file not found" unless asset_options[:base_folder]
|
38
|
+
base_folder = asset_options[:base_folder]
|
39
|
+
pattern = File.expand_path(File.join(base_folder, pattern))
|
40
|
+
end
|
41
|
+
logger.debug "asset glob pattern: #{pattern}"
|
42
|
+
folders = Dir.glob(pattern)
|
43
|
+
logger.debug "user assets folder is empty: #{pattern}" if folders.empty?
|
44
|
+
|
45
|
+
folders.sort.each do |folder|
|
46
|
+
folder_basename = Pathname.new(folder).basename.to_s
|
47
|
+
#logger.debug "matching folder: #{folder} using basename: #{folder_basename}"
|
48
|
+
if filters.find {|filter| matches?(folder_basename, filter, asset_options)}
|
49
|
+
logger.debug "match found for: #{folder_basename}"
|
50
|
+
match_count += 1
|
51
|
+
asset = RepoManager::AppAsset.create(type, folder, {})
|
52
|
+
assets << asset
|
53
|
+
break if ((asset_options[:match] == 'FIRST') || (asset_options[:match] == 'EXACT'))
|
54
|
+
raise "match mode = ONE, multiple matching assets found filter" if (asset_options[:match] == 'ONE' && match_count > 1)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
assets
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def matches?(str, filter, match_options={})
|
64
|
+
if (match_options[:match] == 'EXACT')
|
65
|
+
str == filter
|
66
|
+
else
|
67
|
+
str.match(/#{filter}/)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|