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
data/Rakefile
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# Bundler is managing $LOAD_PATH, any gem needed by this Rakefile must be
|
|
4
|
+
# listed as a development dependency in the gemspec
|
|
5
|
+
require 'bundler/setup'
|
|
6
|
+
require 'bundler/gem_tasks'
|
|
7
|
+
|
|
8
|
+
require 'rbconfig'
|
|
9
|
+
WINDOWS = RbConfig::CONFIG['host_os'] =~ /msdos|mswin|win32|mingw/i unless defined?(WINDOWS)
|
|
10
|
+
|
|
11
|
+
require 'rspec/core/rake_task'
|
|
12
|
+
desc "Run RSpec"
|
|
13
|
+
RSpec::Core::RakeTask.new do |spec|
|
|
14
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
require 'cucumber/rake/task'
|
|
18
|
+
Cucumber::Rake::Task.new do |t|
|
|
19
|
+
|
|
20
|
+
opts = []
|
|
21
|
+
opts << ["--color"]
|
|
22
|
+
opts << ["--format pretty"]
|
|
23
|
+
opts << ["--strict"]
|
|
24
|
+
opts << ["-r features"]
|
|
25
|
+
opts << ["--no-profile"]
|
|
26
|
+
opts << ["--tags ~@wip"]
|
|
27
|
+
opts << ["--tags ~@windows"] unless WINDOWS
|
|
28
|
+
opts << ["--tags ~@posix"] if WINDOWS
|
|
29
|
+
|
|
30
|
+
t.cucumber_opts = opts
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc "Run specs, both RSpec and Cucumber"
|
|
34
|
+
task :test => [:spec, :cucumber]
|
|
35
|
+
|
|
36
|
+
task :default => :test
|
|
37
|
+
|
|
38
|
+
namespace :doc do
|
|
39
|
+
|
|
40
|
+
doc_version = File.open(File.join(File.dirname(__FILE__), 'VERSION'), "r") { |f| f.read }
|
|
41
|
+
project_root = File.expand_path(File.dirname(__FILE__))
|
|
42
|
+
doc_destination = File.join(project_root, 'rdoc')
|
|
43
|
+
|
|
44
|
+
require 'yard'
|
|
45
|
+
|
|
46
|
+
YARD::Rake::YardocTask.new(:generate) do |yt|
|
|
47
|
+
yt.options = ['--output-dir', doc_destination,
|
|
48
|
+
'--title', "RepoManager #{doc_version} Documentation",
|
|
49
|
+
'--main', "README.markdown"
|
|
50
|
+
]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
desc "Remove generated documenation"
|
|
54
|
+
task :clean do
|
|
55
|
+
rm_r doc_destination if File.exists?(doc_destination)
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
desc "List undocumented objects"
|
|
59
|
+
task :undocumented do
|
|
60
|
+
system('yard stats --list-undoc')
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# put the gemfiles task in the bundler dependency chain
|
|
66
|
+
task :build => [:gemfiles]
|
|
67
|
+
task :install => [:gemfiles]
|
|
68
|
+
task :release => [:gemfiles]
|
|
69
|
+
|
|
70
|
+
desc "Generate .gemfiles via 'git ls-files'"
|
|
71
|
+
task :gemfiles do
|
|
72
|
+
files = `git ls-files`
|
|
73
|
+
|
|
74
|
+
filename = File.join(File.dirname(__FILE__), '.gemfiles')
|
|
75
|
+
cached_files = nil
|
|
76
|
+
if File.exists?(filename)
|
|
77
|
+
puts ".gemfiles exists, reading..."
|
|
78
|
+
cached_files = File.open(filename, "rb") {|f| f.read}
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
if cached_files && cached_files.match("\r\n")
|
|
82
|
+
puts ".gemfiles using DOS EOL"
|
|
83
|
+
files.gsub!(/\n/, "\r\n")
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
if cached_files != files
|
|
87
|
+
puts ".gemfiles updating"
|
|
88
|
+
File.open(filename, 'wb') {|f| f.write(files)}
|
|
89
|
+
else
|
|
90
|
+
puts ".gemfiles update not required"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
raise "unable to process .gemfiles" unless files
|
|
94
|
+
end
|
data/TODO.markdown
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
TODO
|
|
2
|
+
====
|
|
3
|
+
|
|
4
|
+
* remove git gem and duplicate needed method. The use of ENV[] will break on
|
|
5
|
+
win32 and ruby 1.9.3
|
|
6
|
+
* add find action that finds a repo based on all strings in the repo config
|
|
7
|
+
* provide native repo completion via --completion option so the entire ARGV can
|
|
8
|
+
be scanned and passed back to bash. We have to load ruby anyway, might as
|
|
9
|
+
well provide completion for commands and options too.
|
|
10
|
+
* status should show summary at the end
|
|
11
|
+
* add feature tests for all combinations of XY result codes from 'git status --porcelain'
|
|
12
|
+
* status command should have option to show last commit information
|
|
13
|
+
* native git commands need to preserve ANSI escape codes for coloring
|
|
14
|
+
* add man page via markdown and ronn. Change 'help' action to call man
|
|
15
|
+
page if man available.
|
data/VERSION
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0.7.1
|
data/bin/repo
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'repo_manager'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
require 'term/ansicolor'
|
|
6
|
+
require 'fileutils'
|
|
7
|
+
|
|
8
|
+
available_actions = RepoManager::AVAILABLE_ACTIONS
|
|
9
|
+
|
|
10
|
+
banner = <<BANNER
|
|
11
|
+
repo: CLI for batch management of multiple Git repositories
|
|
12
|
+
|
|
13
|
+
Usage: repo [options] action [filters|action pass-through options] [options]
|
|
14
|
+
BANNER
|
|
15
|
+
banner << "\nActions: #{available_actions.join(' ')}\n" unless available_actions.empty?
|
|
16
|
+
|
|
17
|
+
help = banner
|
|
18
|
+
help += <<HELP
|
|
19
|
+
|
|
20
|
+
Use 'repo help' for help on actions.
|
|
21
|
+
|
|
22
|
+
repo help task
|
|
23
|
+
repo help git
|
|
24
|
+
|
|
25
|
+
Examples:
|
|
26
|
+
|
|
27
|
+
repo list my_repo1 my_repo2
|
|
28
|
+
repo list --filter=my_repo1,my_repo2
|
|
29
|
+
|
|
30
|
+
repo list --filter=my.*
|
|
31
|
+
repo list my.*
|
|
32
|
+
|
|
33
|
+
repo --verbose --no-color config --list --filter=my_repo1,my_repo2
|
|
34
|
+
repo --verbose --no-color config core.autocrlf true filter=my.*
|
|
35
|
+
repo --verbose --no-color git config --list
|
|
36
|
+
repo --verbose --no-color config --list
|
|
37
|
+
|
|
38
|
+
Most Git commands can be passed directly, these are equivalent
|
|
39
|
+
|
|
40
|
+
repo add .
|
|
41
|
+
repo git add .
|
|
42
|
+
|
|
43
|
+
General options:
|
|
44
|
+
(use 'repo help action' for action options)
|
|
45
|
+
|
|
46
|
+
HELP
|
|
47
|
+
|
|
48
|
+
# get options from the command line, these options override both config files
|
|
49
|
+
# and defaults
|
|
50
|
+
options = {}
|
|
51
|
+
optparser = OptionParser.new do |opts|
|
|
52
|
+
opts.banner = help
|
|
53
|
+
|
|
54
|
+
opts.on("-T", "--tasks", "List tasks") do |t|
|
|
55
|
+
options[:tasks] = t
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
|
|
59
|
+
options[:verbose] = v
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
opts.on("-c", "--[no-]coloring [MODE]", "--[no-]color [MODE]", "ANSI color in output. MODE=AUTO (default) or ALWAYS") do |c|
|
|
63
|
+
options[:color] = c.nil? ? "AUTO" : c
|
|
64
|
+
options[:color].upcase! if options[:color]
|
|
65
|
+
unless [nil, false, "AUTO", "ALWAYS"].include?(options[:color])
|
|
66
|
+
puts "repo, invalid color option: #{options[:color]}"
|
|
67
|
+
exit 1
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
opts.on("--[no-]config FILE", "Load configuration options from FILE") do |file|
|
|
72
|
+
options[:config] = file
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
opts.on("--version", "Display current version and exit") do
|
|
76
|
+
puts "repo_manager, version " + RepoManager.version
|
|
77
|
+
exit 0
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# no argument, shows at tail. This will print an options summary.
|
|
81
|
+
opts.on_tail("-h", "--help", "Show this message") do
|
|
82
|
+
puts opts
|
|
83
|
+
exit 0
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# first pass, process until the action/subcommand, errors will be raised for
|
|
89
|
+
# invalid options that occur before the action/subcommand
|
|
90
|
+
begin
|
|
91
|
+
optparser.order!
|
|
92
|
+
rescue OptionParser::InvalidOption => e
|
|
93
|
+
puts "repo #{e}"
|
|
94
|
+
puts "repo --help for more information"
|
|
95
|
+
exit 1
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# OptionParser is too helpful and matches short options with long. Before the
|
|
100
|
+
# second pass, replace short git options with long because we can't tell
|
|
101
|
+
# OptionParser to stop matching short options to long.
|
|
102
|
+
ARGV.each_with_index do |arg, index|
|
|
103
|
+
# check and replace each short git option
|
|
104
|
+
# that could be parsed by main parser
|
|
105
|
+
case arg
|
|
106
|
+
when '-m'
|
|
107
|
+
ARGV[index] = '--message'
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# second pass find all global options that may come after the action/subcommand
|
|
112
|
+
# and its args, no errors raised, validity will be checked by action parser
|
|
113
|
+
argv = []
|
|
114
|
+
while unknown_arg = ARGV.shift
|
|
115
|
+
argv << unknown_arg
|
|
116
|
+
begin
|
|
117
|
+
optparser.order!
|
|
118
|
+
rescue OptionParser::InvalidOption => e
|
|
119
|
+
# put unknown args back on ARGV
|
|
120
|
+
e.recover(ARGV)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# settings from config file, if it exists, will not overwrite command line options
|
|
125
|
+
settings = RepoManager::Settings.new(FileUtils.pwd, options)
|
|
126
|
+
color = settings.options[:color]
|
|
127
|
+
|
|
128
|
+
# add summary of general options for use by action help commands
|
|
129
|
+
configuration = settings.to_hash
|
|
130
|
+
|
|
131
|
+
if STDOUT.isatty || (color == 'ALWAYS')
|
|
132
|
+
Term::ANSIColor::coloring = color
|
|
133
|
+
|
|
134
|
+
if color && RepoManager::WINDOWS
|
|
135
|
+
unless ENV['ANSICON']
|
|
136
|
+
begin
|
|
137
|
+
require 'Win32/Console/ANSI'
|
|
138
|
+
rescue LoadError
|
|
139
|
+
Term::ANSIColor::coloring = false
|
|
140
|
+
STDERR.puts 'WARNING: You must "gem install win32console" (1.2.0 or higher) or use the ANSICON driver (https://github.com/adoxa/ansicon) to get color output on MRI/Windows'
|
|
141
|
+
end
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
else
|
|
146
|
+
Term::ANSIColor::coloring = false
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
app = RepoManager::App.new(argv, configuration)
|
|
150
|
+
app.option_parser = optparser
|
|
151
|
+
app.execute
|
data/cucumber.yml
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<%
|
|
2
|
+
require 'rbconfig'
|
|
3
|
+
WINDOWS = RbConfig::CONFIG['host_os'] =~ /msdos|mswin|win32|mingw/i unless defined?(WINDOWS)
|
|
4
|
+
|
|
5
|
+
opts = []
|
|
6
|
+
opts << ["--color"]
|
|
7
|
+
opts << ["--format pretty"]
|
|
8
|
+
opts << ["--strict"]
|
|
9
|
+
opts << ["-r features"]
|
|
10
|
+
opts << ["--no-profile"]
|
|
11
|
+
opts << ["--tags ~@wip"]
|
|
12
|
+
opts << ["--tags ~@windows"] unless WINDOWS
|
|
13
|
+
opts << ["--tags ~@posix"] if WINDOWS
|
|
14
|
+
|
|
15
|
+
std_opts = opts.join(' ')
|
|
16
|
+
rerun = File.file?('rerun.txt') ? IO.read('rerun.txt') : ""
|
|
17
|
+
rerun_opts = rerun.to_s.strip.empty? ? "--format pretty" : "--format pretty #{rerun}"
|
|
18
|
+
|
|
19
|
+
%>
|
|
20
|
+
# define cucumber profiles
|
|
21
|
+
#
|
|
22
|
+
# Example usage:
|
|
23
|
+
#
|
|
24
|
+
# bundle exec cucumber --profile wip
|
|
25
|
+
---
|
|
26
|
+
default: <%= std_opts %> -r features
|
|
27
|
+
wip: --tags @wip:3 --wip -r features
|
|
28
|
+
rerun: <%= rerun_opts %> --format rerun --out rerun.txt --strict --tags ~@wip -r features
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
Creating the RepoManager Saved Game Backup Configuration
|
|
2
|
+
====================================================
|
|
3
|
+
|
|
4
|
+
> NOTE for Windows users
|
|
5
|
+
>
|
|
6
|
+
> The given instruction are intended for a Bash shell. Bash is not
|
|
7
|
+
> required to use RepoManager, but it does make using the command prompt much
|
|
8
|
+
> more flexible and productive. The MSYS distribution of portable Git
|
|
9
|
+
> includes a lean and stable Bash environment.
|
|
10
|
+
|
|
11
|
+
Initial configuration
|
|
12
|
+
---------------------
|
|
13
|
+
|
|
14
|
+
### install repo_manager
|
|
15
|
+
|
|
16
|
+
gem install repo_manager
|
|
17
|
+
|
|
18
|
+
### create configuration
|
|
19
|
+
|
|
20
|
+
The following commands were used to create this example folder from
|
|
21
|
+
scratch.
|
|
22
|
+
|
|
23
|
+
mkdir -p examples/pc_saved_game_backup && cd examples/pc_saved_game_backup
|
|
24
|
+
|
|
25
|
+
Create configuration structure with the built-in 'generate:init' task
|
|
26
|
+
|
|
27
|
+
> NOTE
|
|
28
|
+
>
|
|
29
|
+
> We are creating a local configuration. For a global configuration, you would
|
|
30
|
+
> execute the init command in your home folder
|
|
31
|
+
|
|
32
|
+
repo generate:init repo_manager
|
|
33
|
+
|
|
34
|
+
We are going to keep this under version control
|
|
35
|
+
|
|
36
|
+
git init
|
|
37
|
+
git add .
|
|
38
|
+
git commit -m "initial commit"
|
|
39
|
+
echo "/repo.log" > .gitignore
|
|
40
|
+
echo "/repo_manager/tmp" >> .gitignore
|
|
41
|
+
|
|
42
|
+
Change the generated paths from absolute to relative to make this example
|
|
43
|
+
portable.
|
|
44
|
+
|
|
45
|
+
diff --git a/repo_manager/repo.conf b/repo_manager/repo.conf
|
|
46
|
+
index ce4418d..3cc6dbe 100644
|
|
47
|
+
--- a/repo_manager/repo.conf
|
|
48
|
+
+++ b/repo_manager/repo.conf
|
|
49
|
+
@@ -11,7 +11,7 @@ options:
|
|
50
|
+
folders:
|
|
51
|
+
|
|
52
|
+
# main repo configuration files
|
|
53
|
+
- assets : /home/robert/examples/pc_saved_game_backup/repo_manager/assets
|
|
54
|
+
+ assets : assets
|
|
55
|
+
|
|
56
|
+
#
|
|
57
|
+
# repo user tasks, file extentions can be '.rb' or '.thor'
|
|
58
|
+
@@ -26,7 +26,7 @@ folders:
|
|
59
|
+
#
|
|
60
|
+
# c:/dat/condenser/tasks
|
|
61
|
+
#
|
|
62
|
+
- tasks : /home/robert/examples/pc_saved_game_backup/repo_manager/tasks
|
|
63
|
+
+ tasks : tasks
|
|
64
|
+
|
|
65
|
+
# git commands must be whitelisted
|
|
66
|
+
commands:
|
|
67
|
+
@@ -55,7 +55,7 @@ logging:
|
|
68
|
+
name : logfile
|
|
69
|
+
level : info
|
|
70
|
+
truncate : true
|
|
71
|
+
- filename : '/home/robert/examples/pc_saved_game_backup/repo_manager/repo.log'
|
|
72
|
+
+ filename : 'repo.log'
|
|
73
|
+
layout:
|
|
74
|
+
type : Pattern
|
|
75
|
+
pattern : '[%d] %l %c : %m\n'
|
|
76
|
+
|
|
77
|
+
### add sample data
|
|
78
|
+
|
|
79
|
+
Add a few example save game folder. These folders would normally be
|
|
80
|
+
scattered over the file system.
|
|
81
|
+
|
|
82
|
+
mines
|
|
83
|
+
|
|
84
|
+
mkdir -p saved_games/mines/saves
|
|
85
|
+
|
|
86
|
+
# profile data will not be stored in the Git repo since it may differ from PC to PC
|
|
87
|
+
echo "# dummy profile data" > mines/my_profile.ini
|
|
88
|
+
|
|
89
|
+
echo "# dummy save" > saved_games/mines/saves/save1
|
|
90
|
+
echo "# dummy save" > saved_games/mines/saves/save2
|
|
91
|
+
|
|
92
|
+
hearts
|
|
93
|
+
|
|
94
|
+
mkdir -p saved_games/hearts
|
|
95
|
+
|
|
96
|
+
echo "# dummy save" > saved_games/hearts/save1
|
|
97
|
+
echo "# dummy save" > saved_games/hearts/save2
|
|
98
|
+
|
|
99
|
+
### create remote folder
|
|
100
|
+
|
|
101
|
+
This folder will act as a remote to hold bare Git repositories. These
|
|
102
|
+
repos will store backups of our game saves, normally, this folder would be
|
|
103
|
+
on a remote server, NAS, or Drop Box like service.
|
|
104
|
+
|
|
105
|
+
mkdir remote
|
|
106
|
+
|
|
107
|
+
remote/.gitignore
|
|
108
|
+
|
|
109
|
+
*
|
|
110
|
+
!/.gitignore
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
Create the specialized 'git init' task
|
|
114
|
+
--------------------------------------
|
|
115
|
+
|
|
116
|
+
User tasks can be added directly to the repo_manager/tasks folder. This one
|
|
117
|
+
is 'repo_manager/tasks/remote.rb'. It doesn't use any RepoManager specific features,
|
|
118
|
+
instead, it calls git directly via Thor's 'run' command. Adding the script
|
|
119
|
+
this way will keep this related functionality with this specific RepoManager
|
|
120
|
+
configuration. Run 'repo -T' to see a full list of built-in tasks as well
|
|
121
|
+
as user defined tasks.
|
|
122
|
+
|
|
123
|
+
repo_manager/tasks/remote.rb
|
|
124
|
+
|
|
125
|
+
require 'fileutils'
|
|
126
|
+
|
|
127
|
+
module RepoManager
|
|
128
|
+
|
|
129
|
+
class Generate < Thor
|
|
130
|
+
|
|
131
|
+
# full path to the remote folder
|
|
132
|
+
REMOTE = File.expand_path('remote')
|
|
133
|
+
|
|
134
|
+
# Create, add, and commit the contents of the current working directory and
|
|
135
|
+
# then push it to a predefined remote folder
|
|
136
|
+
#
|
|
137
|
+
# @example From the repo working
|
|
138
|
+
#
|
|
139
|
+
# cd ~/my_repo_name
|
|
140
|
+
# repo generate:remote my_repo_name
|
|
141
|
+
#
|
|
142
|
+
# @example Specify the path to the working folder
|
|
143
|
+
#
|
|
144
|
+
# repo generate:remote my_repo_name --path=/path/to/my_repo_name
|
|
145
|
+
|
|
146
|
+
method_option :remote, :type => :string, :desc => "remote folder or git host, defaults to '#{REMOTE}'"
|
|
147
|
+
method_option :path, :type => :string, :desc => "path to working folder, defaults to CWD"
|
|
148
|
+
|
|
149
|
+
desc "remote REPO_NAME", "init a git repo in CWD and push to remote '#{REMOTE}'"
|
|
150
|
+
def remote(name)
|
|
151
|
+
path = options[:path] || FileUtils.pwd
|
|
152
|
+
remote = options[:remote] || "#{File.join(REMOTE, name + '.git')}"
|
|
153
|
+
|
|
154
|
+
Dir.chdir path do
|
|
155
|
+
run("git init")
|
|
156
|
+
|
|
157
|
+
# core config with windows in mind but works fine on POSIX
|
|
158
|
+
run("git config core.autocrlf false")
|
|
159
|
+
run("git config core.filemode false")
|
|
160
|
+
exit $?.exitstatus if ($?.exitstatus > 1)
|
|
161
|
+
|
|
162
|
+
# add everthing and commit
|
|
163
|
+
run("git add .")
|
|
164
|
+
run("git commit --message #{shell_quote('initial commit')}")
|
|
165
|
+
exit $?.exitstatus if ($?.exitstatus > 1)
|
|
166
|
+
|
|
167
|
+
# remove old origin first, if it exists
|
|
168
|
+
run("git remote add origin #{remote}")
|
|
169
|
+
run("git config branch.master.remote origin")
|
|
170
|
+
run("git config branch.master.merge refs/heads/master")
|
|
171
|
+
exit $?.exitstatus if ($?.exitstatus > 1)
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
run("git clone --bare #{shell_quote(path)} #{remote}")
|
|
175
|
+
exit $?.exitstatus if ($?.exitstatus > 1)
|
|
176
|
+
|
|
177
|
+
say "init done on '#{name}'", :green
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
### add remotes
|
|
184
|
+
|
|
185
|
+
In one step, we will initialize a new git repository with the working folder's
|
|
186
|
+
content and push to a new bare repository for backup.
|
|
187
|
+
|
|
188
|
+
> Normally, you don't need to specify the --path if you are already in the
|
|
189
|
+
> working folder and the repo_manager can find its global config file. For this
|
|
190
|
+
> example, we are using relative paths and will specify the working folder
|
|
191
|
+
> on the command line via the '--path' option.
|
|
192
|
+
|
|
193
|
+
repo generate:remote mines --path=saved_games/mines/saves
|
|
194
|
+
repo generate:remote hearts --path=saved_games/hearts
|
|
195
|
+
|
|
196
|
+
### create the repo_manager asset configuration files
|
|
197
|
+
|
|
198
|
+
repo add:asset saved_games/mines/saves --name=mines --force
|
|
199
|
+
repo add:asset saved_games/hearts --force
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
Create the specialized Update task
|
|
203
|
+
----------------------------------
|
|
204
|
+
|
|
205
|
+
repo_manager/tasks/update.rb
|
|
206
|
+
|
|
207
|
+
module RepoManager
|
|
208
|
+
class Action < Thor
|
|
209
|
+
namespace :action
|
|
210
|
+
include Thor::Actions
|
|
211
|
+
include RepoManager::ThorHelper
|
|
212
|
+
|
|
213
|
+
class_option :force, :type => :boolean, :desc => "Force overwrite and answer 'yes' to any prompts"
|
|
214
|
+
|
|
215
|
+
method_option :repos, :type => :string, :desc => "Restrict update to comma delimited list of repo names", :banner => "repo1,repo2"
|
|
216
|
+
method_option :message, :type => :string, :desc => "Override 'automatic commit' message"
|
|
217
|
+
method_option 'no-push', :type => :boolean, :default => false, :desc => "Force overwrite of existing config file"
|
|
218
|
+
|
|
219
|
+
desc "update", "run repo add -A, repo commit, and repo push on all modified repos"
|
|
220
|
+
def update
|
|
221
|
+
|
|
222
|
+
initial_filter = options[:repos] ? "--repos=#{options[:repos]}" : ""
|
|
223
|
+
output = run("repo status --short --unmodified=HIDE --no-verbose --no-color #{initial_filter}", :capture => true)
|
|
224
|
+
|
|
225
|
+
case $?.exitstatus
|
|
226
|
+
when 0
|
|
227
|
+
say 'no changed repos', :green
|
|
228
|
+
else
|
|
229
|
+
|
|
230
|
+
unless output
|
|
231
|
+
say "failed to successfully run 'repo status'", :red
|
|
232
|
+
exit $?.exitstatus
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
repos = []
|
|
236
|
+
output = output.split("\n")
|
|
237
|
+
while line = output.shift
|
|
238
|
+
st,repo = line.split("\t")
|
|
239
|
+
repos << repo
|
|
240
|
+
end
|
|
241
|
+
filter = repos.join(',')
|
|
242
|
+
|
|
243
|
+
unless options[:force]
|
|
244
|
+
say "Repo(s) '#{filter}' have changed."
|
|
245
|
+
unless ask("Add, commit and push them? (y/n)") == 'y'
|
|
246
|
+
say "aborting"
|
|
247
|
+
exit 0
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
say "updating #{filter}"
|
|
252
|
+
|
|
253
|
+
run "repo add -A --no-verbose --repos #{filter}"
|
|
254
|
+
exit $?.exitstatus if ($?.exitstatus > 1)
|
|
255
|
+
|
|
256
|
+
commit_message = options[:message] || "automatic commit @ #{Time.now}"
|
|
257
|
+
run "repo commit --message=#{shell_quote(commit_message)} --no-verbose --repos #{filter}"
|
|
258
|
+
exit $?.exitstatus if ($?.exitstatus > 1)
|
|
259
|
+
|
|
260
|
+
unless options['no-push']
|
|
261
|
+
run "repo push --no-verbose --repos #{filter}"
|
|
262
|
+
exit $?.exitstatus if ($?.exitstatus > 1)
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
say "update finished", :green
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
|
|
272
|
+
### whitelist non-default Git commands
|
|
273
|
+
|
|
274
|
+
Only a small subset of non-destructive git commands are enabled by default. We will
|
|
275
|
+
add the commands needed by our user task to the commands whitelist.
|
|
276
|
+
|
|
277
|
+
Add 'push, add, and commit' to the commands whitelist
|
|
278
|
+
|
|
279
|
+
diff --git a/repo_manager/repo.conf b/repo_manager/repo.conf
|
|
280
|
+
index 3cc6dbe..226b8c0 100644
|
|
281
|
+
--- a/repo_manager/repo.conf
|
|
282
|
+
+++ b/repo_manager/repo.conf
|
|
283
|
+
@@ -36,6 +36,9 @@ commands:
|
|
284
|
+
- ls-files
|
|
285
|
+
- show
|
|
286
|
+
- status
|
|
287
|
+
+- push
|
|
288
|
+
+- add
|
|
289
|
+
+- commit
|
|
290
|
+
|
|
291
|
+
Testing user tasks with Cucumber
|
|
292
|
+
--------------------------------------
|
|
293
|
+
|
|
294
|
+
### Add a Gemfile for use by Bundler
|
|
295
|
+
|
|
296
|
+
repo_manager/Gemfile
|
|
297
|
+
|
|
298
|
+
source "http://rubygems.org"
|
|
299
|
+
|
|
300
|
+
gem "repo_manager"
|
|
301
|
+
|
|
302
|
+
gem "bundler", ">= 1.0.14"
|
|
303
|
+
gem "rspec", ">= 2.6.0"
|
|
304
|
+
gem "cucumber", "~> 1.0"
|
|
305
|
+
gem "aruba", "= 0.4.5"
|
|
306
|
+
|
|
307
|
+
gem "win32console", :platforms => [:mingw, :mswin]
|
|
308
|
+
|
|
309
|
+
### Install the dependencies
|
|
310
|
+
|
|
311
|
+
gem install bundler
|
|
312
|
+
|
|
313
|
+
cd repo_manager
|
|
314
|
+
bundle
|
|
315
|
+
|
|
316
|
+
### Add Cucumber features and support files
|
|
317
|
+
|
|
318
|
+
repo_manager/features/tasks/update.feature
|
|
319
|
+
|
|
320
|
+
> NOTE: This is an excerpt, see the file for the full listing of functional tests
|
|
321
|
+
|
|
322
|
+
@announce
|
|
323
|
+
Feature: Automatically commit and update multiple repos
|
|
324
|
+
|
|
325
|
+
Background: Test repositories and a valid config file
|
|
326
|
+
Given a repo in folder "test_path_1" with the following:
|
|
327
|
+
| filename | status | content |
|
|
328
|
+
| .gitignore | C | |
|
|
329
|
+
And a repo in folder "test_path_2" with the following:
|
|
330
|
+
| filename | status | content |
|
|
331
|
+
| .gitignore | C | |
|
|
332
|
+
And a file named "repo.conf" with:
|
|
333
|
+
"""
|
|
334
|
+
---
|
|
335
|
+
folders:
|
|
336
|
+
assets : repo/asset/configuration/files
|
|
337
|
+
"""
|
|
338
|
+
And the folder "repo/asset/configuration/files" with the following asset configurations:
|
|
339
|
+
| name | path |
|
|
340
|
+
| test1 | test_path_1 |
|
|
341
|
+
| test2 | test_path_2 |
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
Scenario: No uncommitted changes
|
|
345
|
+
When I run `repo action:update`
|
|
346
|
+
Then the output should contain:
|
|
347
|
+
"""
|
|
348
|
+
no changed repos
|
|
349
|
+
"""
|
|
350
|
+
|
|
351
|
+
...
|
|
352
|
+
|
|
353
|
+
repo_manager/features/support/steps.rb
|
|
354
|
+
|
|
355
|
+
require 'repo_manager/test/base_steps'
|
|
356
|
+
require 'repo_manager/test/asset_steps'
|
|
357
|
+
require 'repo_manager/test/repo_steps'
|
|
358
|
+
|
|
359
|
+
repo_manager/features/support/env.rb
|
|
360
|
+
|
|
361
|
+
require 'repo_manager'
|
|
362
|
+
require 'aruba/cucumber'
|
|
363
|
+
require 'rspec/expectations'
|
|
364
|
+
|
|
365
|
+
repo_manager/features/support/aruba.rb
|
|
366
|
+
|
|
367
|
+
require 'aruba/api'
|
|
368
|
+
require 'fileutils'
|
|
369
|
+
|
|
370
|
+
module Aruba
|
|
371
|
+
module Api
|
|
372
|
+
|
|
373
|
+
# override aruba avoid 'current_ruby' call and make sure
|
|
374
|
+
# that binary run on Win32 without the binstubs
|
|
375
|
+
def detect_ruby(cmd)
|
|
376
|
+
wrapper = which('repo')
|
|
377
|
+
cmd = cmd.gsub(/^repo/, "ruby -S #{wrapper}") if wrapper
|
|
378
|
+
cmd
|
|
379
|
+
end
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
|
|
383
|
+
### Run tests
|
|
384
|
+
|
|
385
|
+
bundle exec cucumber
|
|
386
|
+
|
|
387
|
+
Bash completion
|
|
388
|
+
---------------
|
|
389
|
+
|
|
390
|
+
Handy functions for use under Bash. These work fine on Win32 using
|
|
391
|
+
Git-Bash.
|
|
392
|
+
|
|
393
|
+
### CD command for working folders
|
|
394
|
+
|
|
395
|
+
rpushd: repo pushd (push directory). Wrapper for 'pushd'.
|
|
396
|
+
|
|
397
|
+
### Completion for repo names
|
|
398
|
+
|
|
399
|
+
rcd: repo cd (change directory). Wrapper for 'cd', allows for simple cd <repo
|
|
400
|
+
name> to the working folder on the filesystem referenced by the 'path'
|
|
401
|
+
configuration variable.
|
|
402
|
+
|
|
403
|
+
Source these functions in your .bashrc
|
|
404
|
+
|
|
405
|
+
function rcd(){ cd "$(repo --match=ONE --no-color path $@)"; }
|
|
406
|
+
function rpushd(){ pushd "$(repo path --match=ONE --no-color $@)"; }
|
|
407
|
+
alias rpopd="popd"
|
|
408
|
+
|
|
409
|
+
# provide completion for repo names
|
|
410
|
+
function _repo_names()
|
|
411
|
+
{
|
|
412
|
+
local cur opts prev
|
|
413
|
+
COMPREPLY=()
|
|
414
|
+
cur="${COMP_WORDS[COMP_CWORD]}"
|
|
415
|
+
opts=`repo list --list=name --no-color`
|
|
416
|
+
|
|
417
|
+
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
|
|
418
|
+
return 0
|
|
419
|
+
}
|
|
420
|
+
complete -F _repo_names rcd rpushd repo
|