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.
Files changed (116) hide show
  1. data/.gemfiles +115 -0
  2. data/.gitattributes +1 -0
  3. data/.gitignore +7 -0
  4. data/.rspec +3 -0
  5. data/.yardopts +11 -0
  6. data/Gemfile +11 -0
  7. data/Gemfile.lock +99 -0
  8. data/Guardfile +63 -0
  9. data/HISTORY.markdown +12 -0
  10. data/LICENSE +20 -0
  11. data/README.markdown +192 -0
  12. data/Rakefile +94 -0
  13. data/TODO.markdown +15 -0
  14. data/VERSION +1 -0
  15. data/bin/repo +151 -0
  16. data/cucumber.yml +28 -0
  17. data/examples/pc_saved_game_backup/.gitignore +2 -0
  18. data/examples/pc_saved_game_backup/INSTALL.markdown +420 -0
  19. data/examples/pc_saved_game_backup/README.markdown +108 -0
  20. data/examples/pc_saved_game_backup/remote/.gitignore +2 -0
  21. data/examples/pc_saved_game_backup/repo_manager/Gemfile +12 -0
  22. data/examples/pc_saved_game_backup/repo_manager/Gemfile.lock +66 -0
  23. data/examples/pc_saved_game_backup/repo_manager/assets/.gitignore +2 -0
  24. data/examples/pc_saved_game_backup/repo_manager/features/support/aruba.rb +15 -0
  25. data/examples/pc_saved_game_backup/repo_manager/features/support/env.rb +11 -0
  26. data/examples/pc_saved_game_backup/repo_manager/features/support/steps.rb +3 -0
  27. data/examples/pc_saved_game_backup/repo_manager/features/tasks/update.feature +144 -0
  28. data/examples/pc_saved_game_backup/repo_manager/global/default/asset.conf +2 -0
  29. data/examples/pc_saved_game_backup/repo_manager/repo.conf +64 -0
  30. data/examples/pc_saved_game_backup/repo_manager/tasks/.gitignore +0 -0
  31. data/examples/pc_saved_game_backup/repo_manager/tasks/remote.rb +57 -0
  32. data/examples/pc_saved_game_backup/repo_manager/tasks/update.rb +65 -0
  33. data/examples/pc_saved_game_backup/saved_games/hearts/save1 +1 -0
  34. data/examples/pc_saved_game_backup/saved_games/hearts/save2 +1 -0
  35. data/examples/pc_saved_game_backup/saved_games/mines/my_profile.ini +1 -0
  36. data/examples/pc_saved_game_backup/saved_games/mines/saves/save1 +1 -0
  37. data/examples/pc_saved_game_backup/saved_games/mines/saves/save2 +1 -0
  38. data/features/actions/git.feature +296 -0
  39. data/features/actions/help.feature +53 -0
  40. data/features/actions/list.feature +624 -0
  41. data/features/actions/path.feature +195 -0
  42. data/features/actions/status.feature +261 -0
  43. data/features/actions/task.feature +127 -0
  44. data/features/assets/configuration.feature +204 -0
  45. data/features/assets/rendering.feature +42 -0
  46. data/features/assets/user_attributes.feature +98 -0
  47. data/features/bin.feature +42 -0
  48. data/features/logger.feature +218 -0
  49. data/features/settings.feature +240 -0
  50. data/features/support/aruba.rb +15 -0
  51. data/features/support/env.rb +11 -0
  52. data/features/support/steps.rb +3 -0
  53. data/features/tasks/add/asset.feature +178 -0
  54. data/features/tasks/generate/init.feature +56 -0
  55. data/lib/repo_manager.rb +36 -0
  56. data/lib/repo_manager/actions.rb +8 -0
  57. data/lib/repo_manager/actions/action_helper.rb +39 -0
  58. data/lib/repo_manager/actions/app_action.rb +30 -0
  59. data/lib/repo_manager/actions/base_action.rb +296 -0
  60. data/lib/repo_manager/actions/git_action.rb +113 -0
  61. data/lib/repo_manager/actions/help_action.rb +52 -0
  62. data/lib/repo_manager/actions/list_action.rb +123 -0
  63. data/lib/repo_manager/actions/path_action.rb +22 -0
  64. data/lib/repo_manager/actions/status_action.rb +192 -0
  65. data/lib/repo_manager/actions/task_action.rb +71 -0
  66. data/lib/repo_manager/app.rb +116 -0
  67. data/lib/repo_manager/assets.rb +3 -0
  68. data/lib/repo_manager/assets/app_asset.rb +15 -0
  69. data/lib/repo_manager/assets/asset_accessors.rb +67 -0
  70. data/lib/repo_manager/assets/asset_configuration.rb +137 -0
  71. data/lib/repo_manager/assets/asset_manager.rb +72 -0
  72. data/lib/repo_manager/assets/base_asset.rb +199 -0
  73. data/lib/repo_manager/assets/repo_asset.rb +30 -0
  74. data/lib/repo_manager/core.rb +2 -0
  75. data/lib/repo_manager/core/array.rb +21 -0
  76. data/lib/repo_manager/core/hash.rb +83 -0
  77. data/lib/repo_manager/errors.rb +10 -0
  78. data/lib/repo_manager/extensions/hash.rb +86 -0
  79. data/lib/repo_manager/git.rb +2 -0
  80. data/lib/repo_manager/git/lib.rb +69 -0
  81. data/lib/repo_manager/git/status.rb +196 -0
  82. data/lib/repo_manager/logger.rb +39 -0
  83. data/lib/repo_manager/settings.rb +98 -0
  84. data/lib/repo_manager/tasks.rb +3 -0
  85. data/lib/repo_manager/tasks/add/asset.rb +213 -0
  86. data/lib/repo_manager/tasks/generate/init.rb +42 -0
  87. data/lib/repo_manager/tasks/generate/templates/config/repo.conf.tt +61 -0
  88. data/lib/repo_manager/tasks/generate/templates/init/assets/.gitignore +0 -0
  89. data/lib/repo_manager/tasks/generate/templates/init/global/default/asset.conf +2 -0
  90. data/lib/repo_manager/tasks/generate/templates/init/tasks/.gitignore +0 -0
  91. data/lib/repo_manager/tasks/task_manager.rb +166 -0
  92. data/lib/repo_manager/tasks/thor_helper.rb +29 -0
  93. data/lib/repo_manager/test/asset_steps.rb +19 -0
  94. data/lib/repo_manager/test/base_steps.rb +152 -0
  95. data/lib/repo_manager/test/repo_api.rb +41 -0
  96. data/lib/repo_manager/test/repo_steps.rb +83 -0
  97. data/lib/repo_manager/test/test_api.rb +88 -0
  98. data/lib/repo_manager/views.rb +2 -0
  99. data/lib/repo_manager/views/app_view.rb +15 -0
  100. data/lib/repo_manager/views/base_view.rb +137 -0
  101. data/lib/repo_manager/views/templates/css/basic.css +26 -0
  102. data/lib/repo_manager/views/templates/default.erb +40 -0
  103. data/lib/repo_manager/views/templates/default.slim +37 -0
  104. data/lib/repo_manager/views/view_helper.rb +55 -0
  105. data/repo_manager.gemspec +75 -0
  106. data/spec/basic_app/actions/action_helper_spec.rb +54 -0
  107. data/spec/basic_app/assets/base_asset_spec.rb +210 -0
  108. data/spec/basic_app/core_spec.rb +78 -0
  109. data/spec/basic_app/settings_spec.rb +64 -0
  110. data/spec/basic_app/views/view_helper_spec.rb +28 -0
  111. data/spec/basic_gem/aruba_helper_spec.rb +33 -0
  112. data/spec/basic_gem/basic_gem_spec.rb +84 -0
  113. data/spec/basic_gem/gemspec_spec.rb +68 -0
  114. data/spec/repo_manager/git_spec.rb +31 -0
  115. data/spec/spec_helper.rb +25 -0
  116. metadata +472 -0
@@ -0,0 +1,113 @@
1
+ require 'optparse'
2
+ require 'repo_manager/actions/action_helper'
3
+
4
+ module RepoManager
5
+
6
+ # @group CLI actions
7
+ #
8
+ # Native 'git' command pass-through
9
+ #
10
+ # @example Usage: repo [options] git args [options]
11
+ #
12
+ # repo ls-files
13
+ # repo git ls-files
14
+ #
15
+ # repo add .
16
+ # repo add . --filter=test
17
+ # repo git add . --filter=test
18
+ #
19
+ # @return [Numeric] pass through of 'git' result code
20
+ class GitAction < AppAction
21
+ include RepoManager::ActionHelper
22
+
23
+ # allow pass through of unknown options
24
+ def parse_options(parser_configuration = {:raise_on_invalid_option => false})
25
+ super parser_configuration
26
+ end
27
+
28
+ def asset_options
29
+ result = super
30
+
31
+ # to allow pass through options, argument based filters must be ignored,
32
+ # delete the arg based filters and recreate from the --filter option
33
+ result.delete(:filter)
34
+ result = result.merge(:filter => options[:filter]) if options[:filter]
35
+
36
+ result
37
+ end
38
+
39
+ def process
40
+ logger.debug "process() args: #{args.inspect}"
41
+ logger.debug "process() asset_options: #{asset_options.inspect}"
42
+
43
+ # the first arg is optionally 'git'
44
+ unless args.empty?
45
+ args.shift if args[0] == 'git'
46
+ else
47
+ raise "no git command given" if args.empty?
48
+ end
49
+
50
+ command = args.shift
51
+ st = 0
52
+ result = 0
53
+ output = ""
54
+
55
+ unless configuration.commands.include?(command)
56
+ raise "git command '#{command}' is not enabled, see #{configuration[:configuration_filename]}"
57
+ end
58
+
59
+ # args should not match a repo name
60
+ if ((!args.empty?) && (!options[:filter]))
61
+ repos.each do |repo|
62
+ raise "repo name '#{repo.name}' cannot be used as a filter for git native commands, use --r, --repos, or --filter switches instead" if args.include?(repo.name)
63
+ end
64
+ end
65
+
66
+ repos.each do |repo|
67
+ begin
68
+ st = repo.status.bitfield
69
+ rescue InvalidRepositoryError => e
70
+ st = 0 #Status::INVALID
71
+ rescue NoSuchPathError => e
72
+ st = Status::NOPATH
73
+ end
74
+
75
+ case st
76
+ when (Status::NOPATH)
77
+ output += repo.name.red
78
+ output += ": #{relative_path(repo.path)}"
79
+ output += " [no such path]\n"
80
+ else
81
+ git_output = ''
82
+ begin
83
+ git = Git::Lib.new(:working_directory => repo.path, :repository => File.join(repo.path, '.git'))
84
+ git_output = git.native(command, args)
85
+ result |= $?.exitstatus unless ($?.exitstatus == 0)
86
+ rescue Git::CommandFailed => e
87
+ result |= e.exitstatus
88
+ git_output = e.error
89
+ end
90
+ if git_output != ''
91
+ output += repo.name.green + "\n"
92
+ output += git_output + "\n"
93
+ end
94
+ end
95
+ write_to_output(output)
96
+ output = ""
97
+ end
98
+
99
+ # numeric return
100
+ result
101
+ end
102
+
103
+ def help
104
+ super(:comment_starting_with => "Native 'git' command", :located_in_file => __FILE__) +
105
+ "\n" +
106
+ "\n" +
107
+ "Git commands are whitelisted. The following git commands enabled in #{configuration[:configuration_filename]}:\n" +
108
+ "\n" +
109
+ configuration.commands.join(',')
110
+ end
111
+
112
+ end
113
+ end
@@ -0,0 +1,52 @@
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 'optparse'
9
+
10
+ module RepoManager
11
+
12
+ # @group CLI actions
13
+ #
14
+ # CLI help
15
+ #
16
+ # Provide help for an action
17
+ #
18
+ # @example Usage: repo help [action]
19
+ class HelpAction < AppAction
20
+
21
+ def process
22
+ action = args.shift
23
+
24
+ unless action
25
+ puts "no action specified"
26
+ puts "Usage: repo help action | repo --help"
27
+ puts ""
28
+ puts "Where 'action' is one of: #{AVAILABLE_ACTIONS.join(' ')}"
29
+
30
+ exit(0)
31
+ end
32
+
33
+ action = action.downcase
34
+ unless AVAILABLE_ACTIONS.include?(action)
35
+ puts "invalid help action: #{action}"
36
+ exit(0)
37
+ end
38
+
39
+ klass = Object.const_get('RepoManager').const_get("#{action.capitalize}Action")
40
+ app_action = klass.new(['--help'], configuration)
41
+ app_action.option_parser = self.option_parser
42
+ result = app_action.execute
43
+
44
+ exit(0)
45
+ end
46
+
47
+ def help
48
+ super :comment_starting_with => "CLI help", :located_in_file => __FILE__
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,123 @@
1
+ require 'optparse'
2
+ require 'repo_manager/actions/action_helper'
3
+
4
+ module RepoManager
5
+
6
+ # @group CLI actions
7
+ #
8
+ # List assets to the screen or file with or without templates
9
+ # using regular expression (regex) filtering.
10
+ #
11
+ # @example Usage: repo list
12
+ #
13
+ # repo list
14
+ # repo list --list=NAME
15
+ # repo list --type=asset_type
16
+ # repo list --template ~/templates/myTemplate.slim
17
+ #
18
+ # @example Asset regex filtering:
19
+ #
20
+ # repo list --filter=ass.t1,as.et2
21
+ #
22
+ # @example Equivalent asset filtering:
23
+ #
24
+ # repo list --filter=asset1,asset2
25
+ # repo list --asset=asset1,asset2
26
+ # repo list asset1 asset2
27
+ #
28
+ # @example Equivalent usage, file writing:
29
+ #
30
+ # repo list --template=default.slim --output=tmp/aruba/index.html
31
+ # repo list --template=default.slim >> tmp/aruba/index.html
32
+ #
33
+ # @example return just the first matching asset
34
+ #
35
+ # repo list --match=FIRST
36
+ #
37
+ # @example Fail out if more than one matching asset
38
+ #
39
+ # repo list --match=ONE
40
+ #
41
+ # @example Disable regex filter matching
42
+ #
43
+ # repo list --match=EXACT
44
+ #
45
+ # @example Future usage (not implemented):
46
+ #
47
+ # repo list --tags=adventure,favorites --group_by=tags --sort=ACQUIRED
48
+ #
49
+ # @example Create a Bash 'alias' named 'rcd' to chdir to the folder of the repo
50
+ #
51
+ # function rcd(){ cd "$(repo --match=ONE --no-color path $@)"; }
52
+ #
53
+ # rcd my_repo_name
54
+ #
55
+ # @example Repo versions of Bash's pushd and popd
56
+ #
57
+ # function rpushd(){ pushd "$(repo path --match=ONE --no-color $@)"; }
58
+ # alias rpopd="popd"
59
+ #
60
+ # rcd my_repo_name
61
+ #
62
+ # @return [Number] 0 if successful
63
+ class ListAction < AppAction
64
+ include RepoManager::ActionHelper
65
+
66
+ # Add action specific options
67
+ def parse_options
68
+ super do |opts|
69
+
70
+ opts.on("--list MODE", "Listing mode. ALL, NAME, SHORT, PATH") do |u|
71
+ options[:list] = u
72
+ options[:list].upcase!
73
+ unless ["ALL", "NAME", "SHORT", "PATH"].include?(options[:list])
74
+ raise "invalid list mode '#{options[:list]}' for '--list' option"
75
+ end
76
+ end
77
+
78
+ opts.on("--short", "List summary status only, alias for '--list=SHORT'") do |s|
79
+ options[:list] = 'SHORT'
80
+ end
81
+
82
+ # Most decendants of BaseAction will only handle one type of asset, the
83
+ # list action is unique in that you can specify the type of asset to list
84
+ opts.on("--type ASSET_TYPE", "Asset type to list: app_asset (default)") do |t|
85
+ options[:type] = t
86
+ unless ["app_asset"].include?(options[:type])
87
+ raise "unknown asset type '#{options[:type]}' for '--type' option"
88
+ end
89
+ end
90
+
91
+ end
92
+ end
93
+
94
+ def render(view_options=configuration)
95
+ # templates override all other modes, if no mode specified, allow super to handle
96
+ list_mode = options[:template] || options[:list]
97
+ result = ""
98
+ case list_mode
99
+ when 'NAME'
100
+ items.each do |item|
101
+ result += "#{item.name.green}\n"
102
+ end
103
+ when 'SHORT'
104
+ items.each do |item|
105
+ result += item.name.green
106
+ result += ": #{relative_path(item.path)}\n"
107
+ end
108
+ when 'PATH'
109
+ items.each do |item|
110
+ result += "#{item.path}\n"
111
+ end
112
+ else
113
+ result = super(view_options)
114
+ end
115
+ result
116
+ end
117
+
118
+ def help
119
+ super :comment_starting_with => "List assets", :located_in_file => __FILE__
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,22 @@
1
+ module RepoManager
2
+
3
+ # @group CLI actions
4
+ #
5
+ # Show repository path contained in the configuration file to STDOUT.
6
+ #
7
+ # @example Usage: repo path
8
+ #
9
+ # Alias for 'repo list --list=path'
10
+ #
11
+ # @see #list
12
+ class PathAction < AppAction
13
+
14
+ def execute
15
+ RepoManager::ListAction.new(args.push('--list=path'), configuration).execute
16
+ end
17
+
18
+ def help
19
+ super :comment_starting_with => "Show repository path", :located_in_file => __FILE__
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,192 @@
1
+ require 'optparse'
2
+ require 'repo_manager/actions/action_helper'
3
+
4
+ module RepoManager
5
+
6
+ # @group CLI actions
7
+ #
8
+ # Show simplified summary status of repos. The exit code is a bitfield
9
+ # that collects simplified status codes. The RepoManager status simplifies
10
+ # Git's porcelain output by combining Git status X and Y and boiling
11
+ # down status returns to just five types,
12
+ #
13
+ # M ? A D U
14
+ #
15
+ # From git 1.7+ documentation
16
+ #
17
+ # X Y Meaning
18
+ # -------------------------------------------------
19
+ # [MD] not updated
20
+ # M [ MD] updated in index
21
+ # A [ MD] added to index
22
+ # D [ MD] deleted from index
23
+ # R [ MD] renamed in index
24
+ # C [ MD] copied in index
25
+ # [MARC] index and work tree matches
26
+ # [ MARC] M work tree changed since index
27
+ # [ MARC] D deleted in work tree
28
+ # -------------------------------------------------
29
+ # D D unmerged, both deleted
30
+ # A U unmerged, added by us
31
+ # U D unmerged, deleted by them
32
+ # U A unmerged, added by them
33
+ # D U unmerged, deleted by us
34
+ # A A unmerged, both added
35
+ # U U unmerged, both modified
36
+ # -------------------------------------------------
37
+ # ? ? untracked
38
+ # -------------------------------------------------
39
+ #
40
+ # @example Usage: repo status
41
+ #
42
+ # repo status
43
+ # repo status --short
44
+ # repo status repo1 --unmodified DOTS
45
+ # repo status repo1 repo2 --unmodified DOTS
46
+ #
47
+ # @example Equivalent filtering
48
+ #
49
+ # repo status --filter=test2 --unmodified DOTS
50
+ # repo status test2 --unmodified DOTS
51
+ #
52
+ # @example Alternatively, run the native git status command
53
+ #
54
+ # repo git status
55
+ #
56
+ # @return [Number] bitfield with combined repo status
57
+ #
58
+ # @see Status bitfield return values
59
+ class StatusAction < AppAction
60
+ include RepoManager::ActionHelper
61
+
62
+ # Add action specific options
63
+ def parse_options
64
+ super do |opts|
65
+
66
+ opts.on("-u", "--unmodified [MODE]", "Show unmodified repos. MODE=SHOW (default), DOTS, or HIDE") do |u|
67
+ options[:unmodified] = u || "SHOW"
68
+ options[:unmodified].upcase!
69
+ end
70
+
71
+ opts.on("--short", "Summary status only, do not show individual file status") do |s|
72
+ options[:short] = s
73
+ end
74
+
75
+ end
76
+ end
77
+
78
+ def process
79
+ st = 0
80
+ result = 0
81
+ count_unmodified = 0
82
+ need_lf = false
83
+ output = ""
84
+ unmodified_mode = options[:unmodified] || 'HIDE'
85
+
86
+ repos.each do |repo|
87
+ # M ? A D I X
88
+ begin
89
+ st = repo.status.bitfield
90
+ rescue InvalidRepositoryError => e
91
+ st = Status::INVALID # I
92
+ rescue NoSuchPathError => e
93
+ st = Status::NOPATH # X
94
+ end
95
+
96
+ result |= st unless (st == 0)
97
+
98
+ case st
99
+
100
+ when Status::CLEAN
101
+ count_unmodified += 1
102
+ case unmodified_mode
103
+ when "HIDE"
104
+ # do nothing
105
+ when "SHOW"
106
+ output += "\t#{repo.name}\n"
107
+ when "DOTS"
108
+ output += ".".green
109
+ need_lf = true
110
+ else
111
+ raise "invalid mode '#{unmodified_mode}' for '--unmodified' option"
112
+ end
113
+
114
+ when Status::NOPATH
115
+ output += "\n" if need_lf
116
+ output += "X\t#{repo.name}: #{relative_path(repo.path)}"
117
+ output += " [no such path]".red + "\n"
118
+ need_lf = false
119
+
120
+ when Status::INVALID
121
+ output += "\n" if need_lf
122
+ output += "I\t#{repo.name}: #{relative_path(repo.path)}"
123
+ output += " [not a valid repo]".red + "\n"
124
+ need_lf = false
125
+
126
+ else
127
+ output += "\n" if need_lf
128
+
129
+ # print M?ADU status letters
130
+ output += (st & Status::CHANGED == Status::CHANGED) ? "M".red : " "
131
+ output += (st & Status::UNTRACKED == Status::UNTRACKED) ? "?".blue.bold : " "
132
+ output += (st & Status::ADDED == Status::ADDED) ? "A".green : " "
133
+ output += (st & Status::DELETED == Status::DELETED) ? "D".yellow : " "
134
+ output += (st & Status::UNMERGED == Status::UNMERGED) ? "U".red.bold : " "
135
+
136
+ output += "\t#{repo.name}\n"
137
+ need_lf = false
138
+
139
+ unless options[:short]
140
+ # modified (M.red)
141
+ repo.status.changed.sort.each do |k, f|
142
+ output += "\t modified: #{f.path}".red + "\n"
143
+ end
144
+
145
+ # untracked (?.blue.bold)
146
+ repo.status.untracked.sort.each do |k, f|
147
+ output += "\t untracked: #{f.path}".blue.bold + "\n"
148
+ end
149
+
150
+ # added (A.green)
151
+ repo.status.added.sort.each do |k, f|
152
+ output += "\t added: #{f.path}".green + "\n"
153
+ end
154
+
155
+ # deleted (D.yellow)
156
+ repo.status.deleted.sort.each do |k, f|
157
+ output += "\t deleted: #{f.path}".yellow + "\n"
158
+ end
159
+
160
+ # unmerged (U.red.bold)
161
+ repo.status.unmerged.sort.each do |k, f|
162
+ output += "\t unmerged: #{f.path}".red.bold + "\n"
163
+ end
164
+ end
165
+ end
166
+ write_to_output(output)
167
+ output = ""
168
+ end
169
+
170
+ output = "\n" if need_lf
171
+
172
+
173
+ if (repos.size == 0)
174
+ # missing configuration or filter didn't match
175
+ output += "no repositories found\n"
176
+ elsif (count_unmodified == repos.size)
177
+ # summary
178
+ output += "no modified repositories, all working folders are clean\n"
179
+ end
180
+
181
+ write_to_output(output)
182
+
183
+ # numeric return
184
+ result
185
+ end
186
+
187
+ def help
188
+ super :comment_starting_with => "Show simplified summary status", :located_in_file => __FILE__
189
+ end
190
+
191
+ end
192
+ end