repo_manager 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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