esr-rim 1.1.5
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.
- checksums.yaml +7 -0
- data/CHANGELOG +40 -0
- data/README.md +3 -0
- data/Rakefile +56 -0
- data/bin/rim +3 -0
- data/lib/rim/command/command.rb +37 -0
- data/lib/rim/command/status.rb +110 -0
- data/lib/rim/command/sync.rb +69 -0
- data/lib/rim/command/upload.rb +33 -0
- data/lib/rim/command_helper.rb +119 -0
- data/lib/rim/dirty_check.rb +111 -0
- data/lib/rim/file_helper.rb +58 -0
- data/lib/rim/file_logger.rb +21 -0
- data/lib/rim/git.rb +339 -0
- data/lib/rim/manifest/helper.rb +82 -0
- data/lib/rim/manifest/json_reader.rb +40 -0
- data/lib/rim/manifest/manifest.json +7 -0
- data/lib/rim/manifest/model.rb +33 -0
- data/lib/rim/manifest/repo_reader.rb +61 -0
- data/lib/rim/module_helper.rb +52 -0
- data/lib/rim/module_info.rb +30 -0
- data/lib/rim/processor.rb +126 -0
- data/lib/rim/rev_status.rb +61 -0
- data/lib/rim/rim.rb +93 -0
- data/lib/rim/rim_exception.rb +15 -0
- data/lib/rim/rim_info.rb +129 -0
- data/lib/rim/status_builder.rb +219 -0
- data/lib/rim/sync_helper.rb +121 -0
- data/lib/rim/sync_module_helper.rb +115 -0
- data/lib/rim/upload_helper.rb +67 -0
- data/lib/rim/upload_module_helper.rb +152 -0
- data/lib/rim/version.rb +10 -0
- data/test/dirty_check_test.rb +210 -0
- data/test/file_helper_test.rb +132 -0
- data/test/git_test.rb +49 -0
- data/test/manifest_helper_test.rb +29 -0
- data/test/manifest_test_dir/manifest.rim +9 -0
- data/test/manifest_test_dir/subdir/only_to_keep_folder_in_git.txt +0 -0
- data/test/processor_test.rb +32 -0
- data/test/rim_info_test.rb +93 -0
- data/test/status_builder_test.rb +488 -0
- data/test/sync_helper_test.rb +193 -0
- data/test/sync_module_helper_test.rb +96 -0
- data/test/test_helper.rb +39 -0
- data/test/unit_tests.rb +14 -0
- data/test/upload_helper_test.rb +338 -0
- data/test/upload_module_helper_test.rb +92 -0
- metadata +110 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e39178ba7e2f000cec05a0ca417d4064b1c06cb6
|
4
|
+
data.tar.gz: e51d10cecfd216dcb0890a5b3a47ab13086c46c4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a09bfcc5ef6fd0138f5c3be1be93c9c19da499cfd6701cf5efc46eafb3c213b047a8aa0e6eb0b6342f42884a65f1913a5776631104f50970bcc30c64167ed9cb
|
7
|
+
data.tar.gz: 7941fdf8455ba6ccc8594a89fe17634ad82f3458aee8a56e6871c65834ddbdd17808c18ff58b1d1b2adc60f81d3c71fbd9ad5e8b05510f91039290fe202626eb
|
data/CHANGELOG
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# 0.1.0
|
2
|
+
|
3
|
+
* initial version
|
4
|
+
|
5
|
+
# 0.1.1
|
6
|
+
|
7
|
+
* take latest clean commit to create rim branch on
|
8
|
+
* Avoid additional parameters in message.
|
9
|
+
|
10
|
+
# 0.1.2
|
11
|
+
|
12
|
+
* fixed rim status verify clean when remotes are dirty [BS-236]
|
13
|
+
|
14
|
+
# 0.1.3
|
15
|
+
|
16
|
+
* made rim status faster
|
17
|
+
* fixed rim exception when project git is renamed
|
18
|
+
|
19
|
+
# 1.0.0
|
20
|
+
|
21
|
+
* changed checksum calculation, not backward compatible!
|
22
|
+
* fixed commits becoming dirty when line ending format changes
|
23
|
+
* allow specification of multiple modules on sync and upload
|
24
|
+
* fixed sync with create option
|
25
|
+
* made printing of working copy status optional
|
26
|
+
* major performance improvements
|
27
|
+
|
28
|
+
# 1.0.1
|
29
|
+
|
30
|
+
* fixed dirty check to ignore empty directories
|
31
|
+
|
32
|
+
# 1.0.2
|
33
|
+
|
34
|
+
* write all logs to temporary file
|
35
|
+
|
36
|
+
# 1.1.0
|
37
|
+
|
38
|
+
* added --gerrit option, needed for pushing new branchs to gerrit [BS-202]
|
39
|
+
* fixed exception on rim sync after moving working copy [BS-248]
|
40
|
+
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,56 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)+"/lib")
|
2
|
+
|
3
|
+
require 'rubygems/package_task'
|
4
|
+
require 'rdoc/task'
|
5
|
+
require 'rim/version'
|
6
|
+
|
7
|
+
DocFiles = [
|
8
|
+
"README.md", "CHANGELOG"
|
9
|
+
]
|
10
|
+
|
11
|
+
RTextGemSpec = Gem::Specification.new do |s|
|
12
|
+
s.name = "esr-rim"
|
13
|
+
s.version = RIM::Version::Version
|
14
|
+
s.date = Time.now.strftime("%Y-%m-%d")
|
15
|
+
s.summary = "RIM - multi git tool"
|
16
|
+
s.description = "RIM lets you work with multiple git repositories from within one single git repository."
|
17
|
+
s.authors = "ESR Labs AG"
|
18
|
+
s.homepage = "http://esrlabs.com"
|
19
|
+
s.add_dependency('subcommand', '>= 1.0.6')
|
20
|
+
gemfiles = Rake::FileList.new
|
21
|
+
gemfiles.include("{lib,test}/**/*")
|
22
|
+
gemfiles.include(DocFiles)
|
23
|
+
gemfiles.include("Rakefile")
|
24
|
+
s.files = gemfiles
|
25
|
+
s.rdoc_options = ["--main", "README.md", "-x", "test"]
|
26
|
+
s.extra_rdoc_files = DocFiles
|
27
|
+
s.bindir = "bin"
|
28
|
+
s.executables = ["rim"]
|
29
|
+
end
|
30
|
+
|
31
|
+
RDoc::Task.new do |rd|
|
32
|
+
rd.main = "README.md"
|
33
|
+
rd.rdoc_files.include(DocFiles)
|
34
|
+
rd.rdoc_files.include("lib/**/*.rb")
|
35
|
+
rd.rdoc_dir = "doc"
|
36
|
+
end
|
37
|
+
|
38
|
+
RTextPackageTask = Gem::PackageTask.new(RTextGemSpec) do |p|
|
39
|
+
p.need_zip = false
|
40
|
+
end
|
41
|
+
|
42
|
+
task :prepare_package_rdoc => :rdoc do
|
43
|
+
RTextPackageTask.package_files.include("doc/**/*")
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'run unit tests'
|
47
|
+
task :run_tests do
|
48
|
+
sh "ruby test/unit_tests.rb"
|
49
|
+
end
|
50
|
+
|
51
|
+
task :release => [:prepare_package_rdoc, :package]
|
52
|
+
|
53
|
+
task :clobber => [:clobber_rdoc, :clobber_package]
|
54
|
+
|
55
|
+
task :default => :run_tests
|
56
|
+
|
data/bin/rim
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module RIM
|
2
|
+
module Command
|
3
|
+
|
4
|
+
class Command
|
5
|
+
attr_writer :logger
|
6
|
+
|
7
|
+
def initialize(processor)
|
8
|
+
@processor = processor
|
9
|
+
end
|
10
|
+
|
11
|
+
def project_git_dir
|
12
|
+
git_dir = find_git_dir(".")
|
13
|
+
raise RimException.new("The current path is not part of a git repository.") if !git_dir
|
14
|
+
git_dir
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def find_git_dir(start_dir)
|
20
|
+
last_dir = nil
|
21
|
+
dir = File.expand_path(start_dir)
|
22
|
+
while dir != last_dir
|
23
|
+
if File.exist?("#{dir}/.git") || dir =~ /\.git$/
|
24
|
+
return dir
|
25
|
+
end
|
26
|
+
last_dir = dir
|
27
|
+
# returns itself on file system root
|
28
|
+
dir = File.dirname(dir)
|
29
|
+
end
|
30
|
+
nil
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'rim/status_builder'
|
2
|
+
|
3
|
+
module RIM
|
4
|
+
module Command
|
5
|
+
|
6
|
+
class Status < Command
|
7
|
+
|
8
|
+
def initialize(opts)
|
9
|
+
opts.banner = "Usage: rim status [<options>] [<to-rev>|<from-rev>..<to-rev>]"
|
10
|
+
opts.description = "Prints commits and their RIM status"
|
11
|
+
opts.separator ""
|
12
|
+
opts.separator "Without revision arguments checks the current branch and all local ancestors."
|
13
|
+
opts.separator "With a single <to-rev> checks that revision and all local ancestors."
|
14
|
+
opts.separator "Otherwise checks <to-rev> and ancestors without <from-rev> and ancestors."
|
15
|
+
opts.separator "With the --gerrit option, assumes all yet unknown commits to be 'local'."
|
16
|
+
opts.separator ""
|
17
|
+
opts.on("-d", "--detailed", "print detailed status") do
|
18
|
+
@detailed = true
|
19
|
+
end
|
20
|
+
opts.on("-w", "--working-copy", "print working copy status") do
|
21
|
+
@wc_status = true
|
22
|
+
end
|
23
|
+
opts.on("-f", "--fast", "fast status assuming remote is clean") do
|
24
|
+
@fast = true
|
25
|
+
end
|
26
|
+
opts.on("--verify-clean", "exit with error code 1 if commits are dirty") do
|
27
|
+
@verify_clean = true
|
28
|
+
end
|
29
|
+
opts.on("--gerrit", "special gerrit mode which stops on all known commits") do
|
30
|
+
@gerrit_mode = true
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def invoke()
|
35
|
+
root = project_git_dir
|
36
|
+
rev_arg = ARGV.shift
|
37
|
+
stat = nil
|
38
|
+
RIM.git_session(root) do |gs|
|
39
|
+
sb = RIM::StatusBuilder.new
|
40
|
+
if @wc_status
|
41
|
+
stat = sb.fs_status(root)
|
42
|
+
print_status(gs, stat)
|
43
|
+
end
|
44
|
+
if rev_arg
|
45
|
+
if rev_arg =~ /\.\./
|
46
|
+
from_rev, to_rev = rev_arg.split("..")
|
47
|
+
else
|
48
|
+
from_rev, to_rev = nil, rev_arg
|
49
|
+
end
|
50
|
+
stat = sb.rev_history_status(gs, to_rev, :stop_rev => from_rev, :fast => @fast, :gerrit => @gerrit_mode)
|
51
|
+
print_status(gs, stat)
|
52
|
+
else
|
53
|
+
branch = gs.current_branch_name
|
54
|
+
stat = sb.rev_history_status(gs, branch, :fast => @fast)
|
55
|
+
print_status(gs, stat)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
if @verify_clean && any_dirty?(stat)
|
59
|
+
exit(1)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
def any_dirty?(stat)
|
66
|
+
# don't check the last (remote) status nodes (leaves of the status tree)
|
67
|
+
# these are normally remote commits which could be dirty
|
68
|
+
# the initial commit would also be a leave
|
69
|
+
# TODO: see print_status
|
70
|
+
stat.dirty? || stat.parents.any?{|p| !p.parents.empty? && any_dirty?(p)}
|
71
|
+
end
|
72
|
+
|
73
|
+
def print_status(gs, stat)
|
74
|
+
# don't print the last (remote) status nodes
|
75
|
+
# note: this also excludes the initial commit
|
76
|
+
# TODO: make sure to print the first commit
|
77
|
+
# otherwise the first could be dirty but won't be shown to the user
|
78
|
+
return if stat.git_rev && stat.parents.empty?
|
79
|
+
dirty_mods = stat.modules.select{|m| m.dirty?}
|
80
|
+
stat_info = dirty_mods.empty? ? "[ OK]" : "[DIRTY]"
|
81
|
+
headline = ""
|
82
|
+
if stat.git_rev
|
83
|
+
out = gs.execute "git rev-list --format=oneline -n 1 #{stat.git_rev}"
|
84
|
+
if out =~ /^(\w+) (.*)/
|
85
|
+
sha1, comment = $1, $2
|
86
|
+
comment = comment[0..56]+"..." if comment.size > 60
|
87
|
+
headline += "#{stat_info} #{sha1[0..6]} #{comment}"
|
88
|
+
end
|
89
|
+
else
|
90
|
+
headline += "#{stat_info} ------- uncommitted changes"
|
91
|
+
end
|
92
|
+
if @detailed
|
93
|
+
@logger.info headline
|
94
|
+
dirty_mods.each do |m|
|
95
|
+
@logger.info " - #{m.dir}"
|
96
|
+
end
|
97
|
+
elsif dirty_mods.size > 0
|
98
|
+
@logger.info "#{headline} (#{dirty_mods.size} modules dirty)"
|
99
|
+
else
|
100
|
+
@logger.info headline
|
101
|
+
end
|
102
|
+
stat.parents.each do |p|
|
103
|
+
print_status(gs, p)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'rim/command/command'
|
2
|
+
require 'rim/manifest/helper'
|
3
|
+
require 'rim/rim_exception'
|
4
|
+
require 'rim/rim_info'
|
5
|
+
require 'rim/sync_helper'
|
6
|
+
require 'uri'
|
7
|
+
|
8
|
+
module RIM
|
9
|
+
module Command
|
10
|
+
|
11
|
+
class Sync < Command
|
12
|
+
|
13
|
+
include RIM::Manifest
|
14
|
+
|
15
|
+
def initialize(opts)
|
16
|
+
opts.banner = "Usage: rim sync [<options>] [<local_module_path>]"
|
17
|
+
opts.description = "Synchronize specified rim modules with remote repository revisions."
|
18
|
+
opts.separator ""
|
19
|
+
opts.on("-m", "--manifest [MANIFEST]", String, "Read information from manifest.", \
|
20
|
+
"If no manifest file is specified a 'manifest.rim' file will be used.") do |manifest|
|
21
|
+
@manifest = manifest ? manifest : Helpers::default_manifest
|
22
|
+
end
|
23
|
+
opts.on("-c", "--create", "Synchronize module initially to <local_module_path>.", \
|
24
|
+
"Specify the remote URL and the target revision with the options.") do
|
25
|
+
@create = true
|
26
|
+
end
|
27
|
+
@module_options = {}
|
28
|
+
opts.on("-u", "--remote-url URL", String, "Set the remote URL of the module.", \
|
29
|
+
"A relative path will be applied to ssh://gerrit/") do |url|
|
30
|
+
@module_options[:remote_url] = url
|
31
|
+
end
|
32
|
+
opts.on("-r", "--target-revision REVISION", String, "Set the target revision of the module.") do |target_revision|
|
33
|
+
@module_options[:target_revision] = target_revision
|
34
|
+
end
|
35
|
+
opts.on("-i", "--ignore [PATTERN_LIST]", String, "Set the ignore patterns by specifying a comma separated list.") do |ignores|
|
36
|
+
@module_options[:ignores] = ignores || ""
|
37
|
+
end
|
38
|
+
opts.on("-m", "--message MESSAGE", String, "Message header to provide to each commit.") do |message|
|
39
|
+
@message = message
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def invoke()
|
44
|
+
helper = SyncHelper.new(project_git_dir, @logger)
|
45
|
+
if @manifest
|
46
|
+
helper.modules_from_manifest(@manifest)
|
47
|
+
elsif @create
|
48
|
+
local_path = ARGV.shift || "."
|
49
|
+
if helper.find_file_dir_in_workspace(local_path, RimInfo::InfoFileName)
|
50
|
+
raise RimException.new("There's already a module file. Don't use the create option to sync the module.")
|
51
|
+
elsif !@module_options[:remote_url] || !@module_options[:target_revision]
|
52
|
+
raise RimException.new("Please specify remote URL and target revision for the new module.")
|
53
|
+
else
|
54
|
+
helper.add_module_info(helper.create_module_info(@module_options[:remote_url], local_path, @module_options[:target_revision], \
|
55
|
+
@module_options[:ignores]))
|
56
|
+
end
|
57
|
+
else
|
58
|
+
helper.modules_from_paths(ARGV, @module_options)
|
59
|
+
end
|
60
|
+
helper.check_arguments
|
61
|
+
helper.sync(@message)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rim/command/command'
|
2
|
+
require 'rim/processor'
|
3
|
+
require 'rim/upload_helper'
|
4
|
+
|
5
|
+
module RIM
|
6
|
+
module Command
|
7
|
+
|
8
|
+
class Upload < Command
|
9
|
+
|
10
|
+
include RIM::Manifest
|
11
|
+
|
12
|
+
def initialize(opts)
|
13
|
+
@review = true
|
14
|
+
opts.banner = "Usage: rim upload <local_module_path>"
|
15
|
+
opts.description = "Upload changes from rim module synchronized to <local_module_path> to remote repository."
|
16
|
+
opts.on("-n", "--no-review", "Uploads without review. The changes will be pushed directly to the module's target branch.") do
|
17
|
+
@review = false
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def invoke()
|
22
|
+
helper = UploadHelper.new(project_git_dir, @review, @logger)
|
23
|
+
helper.modules_from_paths(ARGV)
|
24
|
+
helper.check_arguments
|
25
|
+
helper.upload
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'rim/file_helper'
|
2
|
+
require 'rim/processor'
|
3
|
+
require 'rim/module_info'
|
4
|
+
require 'rim/rim_info'
|
5
|
+
require 'rim/manifest/json_reader'
|
6
|
+
require 'rim/status_builder'
|
7
|
+
|
8
|
+
module RIM
|
9
|
+
|
10
|
+
class CommandHelper < Processor
|
11
|
+
|
12
|
+
include Manifest
|
13
|
+
|
14
|
+
def initialize(workspace_root, logger, module_infos = nil)
|
15
|
+
super(workspace_root, logger)
|
16
|
+
@paths = []
|
17
|
+
@logger = logger
|
18
|
+
if module_infos
|
19
|
+
module_infos.each do |m|
|
20
|
+
add_module_info(m)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# check whether workspace is not touched
|
26
|
+
def check_ready
|
27
|
+
raise RimException.new("The workspace git contains uncommitted changes.") if !local_changes?(@ws_root)
|
28
|
+
end
|
29
|
+
|
30
|
+
def check_arguments
|
31
|
+
raise RimException.new("Unexpected command line arguments.") if !ARGV.empty?
|
32
|
+
end
|
33
|
+
|
34
|
+
def create_module_info(remote_url, local_path, target_revision, ignores)
|
35
|
+
ModuleInfo.new(remote_url, get_relative_path(local_path), target_revision, ignores, get_remote_branch_format(remote_url))
|
36
|
+
end
|
37
|
+
|
38
|
+
def modules_from_manifest(path)
|
39
|
+
manifest = read_manifest(path)
|
40
|
+
manifest.modules.each do |mod|
|
41
|
+
add_unique_module_info(create_module_info(mod.remote_path, mod.local_path, mod.target_revision, mod.ignores))
|
42
|
+
end
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
def modules_from_paths(paths, opts = {})
|
47
|
+
if paths.empty?
|
48
|
+
module_from_path(nil, opts)
|
49
|
+
elsif paths.length == 1 || opts.empty?
|
50
|
+
while !paths.empty?
|
51
|
+
module_from_path(paths.shift, opts)
|
52
|
+
end
|
53
|
+
else
|
54
|
+
raise RimException.new("Multiple modules cannot be used with additional options.")
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def module_from_path(path, opts = {})
|
59
|
+
module_path = find_file_dir_in_workspace(path || ".", RimInfo::InfoFileName)
|
60
|
+
if module_path
|
61
|
+
rim_info = RimInfo.from_dir(module_path)
|
62
|
+
add_unique_module_info(create_module_info(opts.has_key?(:remote_url) ? opts[:remote_url] : rim_info.remote_url, \
|
63
|
+
module_path, opts.has_key?(:target_revision) ? opts[:target_revision] : rim_info.target_revision, \
|
64
|
+
opts.has_key?(:ignores) ? opts[:ignores] : rim_info.ignores))
|
65
|
+
module_path
|
66
|
+
else
|
67
|
+
raise RimException.new(path ? "No module info found in '#{path}'." : "No module info found.")
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def modules_from_workspace()
|
72
|
+
if File.directory?(File.join(@ws_root, ".rim"))
|
73
|
+
status = StatusBuilder.new.fs_status(@ws_root)
|
74
|
+
status.modules.each do |mod|
|
75
|
+
rim_info = mod.rim_info
|
76
|
+
add_unique_module_info(ModuleInfo.new(rim_info.remote_url, mod.dir, rim_info.upstream, rim_info.ignores))
|
77
|
+
end
|
78
|
+
true
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def add_unique_module_info(module_info)
|
83
|
+
if !@paths.include?(module_info.local_path)
|
84
|
+
@paths.push(module_info.local_path)
|
85
|
+
add_module_info(module_info)
|
86
|
+
else
|
87
|
+
raise RimException.new("Module '#{module_info.local_path}' specified more than once.")
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def get_remote_branch_format(remote_url)
|
92
|
+
get_absolute_remote_url(remote_url).start_with?(GerritServer) ? "refs/for/%s" : nil
|
93
|
+
#"refs/for/%s"
|
94
|
+
end
|
95
|
+
|
96
|
+
def find_file_dir_in_workspace(start_dir, file)
|
97
|
+
path = File.expand_path(start_dir)
|
98
|
+
while path != @ws_root
|
99
|
+
if File.exist?(File.join(path, file))
|
100
|
+
return path
|
101
|
+
else
|
102
|
+
parent = File.dirname(path)
|
103
|
+
if parent != path
|
104
|
+
path = parent
|
105
|
+
else
|
106
|
+
break
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
|
113
|
+
protected
|
114
|
+
def add_module_info(module_info)
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|