esr-rim 1.1.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'monitor'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module RIM
|
5
|
+
module Manifest
|
6
|
+
|
7
|
+
class RimError < StandardError
|
8
|
+
def self.status_code(code)
|
9
|
+
define_method(:status_code) { code }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class ManifestFileNotFound < RimError; status_code(10) ; end
|
14
|
+
|
15
|
+
module Helpers
|
16
|
+
CHDIR_MONITOR = Monitor.new
|
17
|
+
CONFIG_FILE_NAME = "manifest.rim"
|
18
|
+
|
19
|
+
def default_manifest
|
20
|
+
manifest = find_manifest
|
21
|
+
raise ManifestFileNotFound, "Could not locate #{CONFIG_FILE_NAME}" unless manifest
|
22
|
+
Pathname.new(manifest)
|
23
|
+
end
|
24
|
+
|
25
|
+
def default_lockfile
|
26
|
+
manifest = default_manifest
|
27
|
+
Pathname.new(manifest.sub(/.rim$/, '.locked'))
|
28
|
+
end
|
29
|
+
|
30
|
+
def in_rim_project?
|
31
|
+
find_manifest
|
32
|
+
end
|
33
|
+
|
34
|
+
def chdir_monitor
|
35
|
+
CHDIR_MONITOR
|
36
|
+
end
|
37
|
+
|
38
|
+
def chdir(dir, &blk)
|
39
|
+
chdir_monitor.synchronize do
|
40
|
+
Dir.chdir dir, &blk
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
|
46
|
+
def find_manifest
|
47
|
+
given = ENV['RIM_MANIFEST']
|
48
|
+
return given if given && !given.empty?
|
49
|
+
|
50
|
+
find_file(CONFIG_FILE_NAME)
|
51
|
+
end
|
52
|
+
|
53
|
+
def find_file(*names)
|
54
|
+
search_up(*names) {|filename|
|
55
|
+
return filename if File.file?(filename)
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
def find_directory(*names)
|
60
|
+
search_up(*names) do |dirname|
|
61
|
+
return dirname if File.directory?(dirname)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def search_up(*names)
|
66
|
+
previous = nil
|
67
|
+
current = File.expand_path(Dir.pwd)
|
68
|
+
|
69
|
+
until !File.directory?(current) || current == previous
|
70
|
+
names.each do |name|
|
71
|
+
filename = File.join(current, name)
|
72
|
+
yield filename
|
73
|
+
end
|
74
|
+
current, previous = File.expand_path("..", current), current
|
75
|
+
end
|
76
|
+
end
|
77
|
+
extend self
|
78
|
+
end
|
79
|
+
|
80
|
+
end # Manifest
|
81
|
+
end # RIM
|
82
|
+
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'csv'
|
3
|
+
require 'rim/manifest/model'
|
4
|
+
|
5
|
+
class RimError < StandardError
|
6
|
+
def self.status_code(code)
|
7
|
+
define_method(:status_code) { code }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
class ManifestFileNotFound < RimError; status_code(10) ; end
|
12
|
+
|
13
|
+
module RIM
|
14
|
+
module Manifest
|
15
|
+
|
16
|
+
def read_manifest(f)
|
17
|
+
raise "no manifest found" unless f
|
18
|
+
parse_manifest(File.read(f))
|
19
|
+
end
|
20
|
+
|
21
|
+
def parse_manifest(json)
|
22
|
+
data_hash = JSON.parse(json)
|
23
|
+
modules = []
|
24
|
+
if data_hash.has_key?("modules")
|
25
|
+
data_hash["modules"].each do |mod|
|
26
|
+
modules.push(
|
27
|
+
Module.new(
|
28
|
+
:remote_path => mod["remote_path"],
|
29
|
+
:local_path => mod["local_path"],
|
30
|
+
:target_revision => mod["target_revision"],
|
31
|
+
:ignores => mod["ignores"]
|
32
|
+
))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
Manifest.new(data_hash["remote_url"], modules)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
{
|
2
|
+
"remote_url" : "ssh://gerrit",
|
3
|
+
"modules" : [
|
4
|
+
{"local_path": "./bsw/nvStorage", "remote_path": "bsw/modules/nvStorage", "target_revision": "1.1"},
|
5
|
+
{"local_path": "./bsw/eepromManager", "remote_path":"bsw/modules/eepromManager", "target_revision": "1.0"}
|
6
|
+
]
|
7
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RIM
|
2
|
+
module Manifest
|
3
|
+
|
4
|
+
class Manifest
|
5
|
+
|
6
|
+
attr_reader :remote_url
|
7
|
+
attr_reader :modules
|
8
|
+
|
9
|
+
def initialize(remote_url, modules)
|
10
|
+
@remote_url = remote_url
|
11
|
+
@modules = modules
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class Module
|
17
|
+
attr_reader :remote_path
|
18
|
+
attr_reader :local_path
|
19
|
+
attr_reader :target_revision
|
20
|
+
attr_reader :ignores
|
21
|
+
|
22
|
+
def initialize(args = {})
|
23
|
+
@remote_path = args[:remote_path]
|
24
|
+
@local_path = args[:local_path]
|
25
|
+
@target_revision = args[:target_revision]
|
26
|
+
@ignores = args[:ignores]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'rim/manifest/model'
|
3
|
+
|
4
|
+
module RIM
|
5
|
+
module Manifest
|
6
|
+
|
7
|
+
# Reader for the original Google Repo manifest
|
8
|
+
class RepoReader
|
9
|
+
|
10
|
+
def read(file)
|
11
|
+
manifest = Manifest.new
|
12
|
+
File.open(file) do |f|
|
13
|
+
doc = Nokogiri::XML::Document.parse(f)
|
14
|
+
remote_by_name = {}
|
15
|
+
defaults = nil
|
16
|
+
doc.xpath("/manifest/default").each do |d|
|
17
|
+
raise "duplicate default setting" if defaults
|
18
|
+
defaults = {
|
19
|
+
:revision => d.attr("revision"),
|
20
|
+
:remote => d.attr("remote")
|
21
|
+
}
|
22
|
+
end
|
23
|
+
doc.xpath("/manifest/remote").each do |r|
|
24
|
+
name = r.attr("name")
|
25
|
+
raise "remote without a name" unless name
|
26
|
+
rem = Remote.new(
|
27
|
+
:fetch_url => r.attr("fetch"),
|
28
|
+
:review_url => r.attr("review")
|
29
|
+
)
|
30
|
+
raise "conflicting remote name #{name}" if remote_by_name[name]
|
31
|
+
remote_by_name[name] = rem
|
32
|
+
end
|
33
|
+
doc.xpath("/manifest/project").each do |p|
|
34
|
+
remote = p.attr("remote")
|
35
|
+
remote ||= defaults[:remote]
|
36
|
+
if remote
|
37
|
+
raise "remote #{remote} not found" unless remote_by_name[remote]
|
38
|
+
else
|
39
|
+
raise "no remote specified and no default remote either"
|
40
|
+
end
|
41
|
+
revision = p.attr("revision")
|
42
|
+
revision ||= defaults[:revision]
|
43
|
+
if !revision
|
44
|
+
raise "no revision specified and no default revision either"
|
45
|
+
end
|
46
|
+
mod = Module.new(
|
47
|
+
:remote_path => p.attr("name"),
|
48
|
+
:local_path => p.attr("path"),
|
49
|
+
:revision => revision,
|
50
|
+
:remote => remote_by_name[remote]
|
51
|
+
)
|
52
|
+
manifest.add_module(mod)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
manifest
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'rim/processor'
|
2
|
+
require 'rim/rim_exception'
|
3
|
+
require 'rim/rim_info'
|
4
|
+
require 'rim/file_helper'
|
5
|
+
require 'rim/dirty_check'
|
6
|
+
|
7
|
+
module RIM
|
8
|
+
|
9
|
+
class ModuleHelper < Processor
|
10
|
+
|
11
|
+
def initialize(workspace_root, module_info, logger)
|
12
|
+
super(workspace_root, logger)
|
13
|
+
@module_info = module_info
|
14
|
+
@remote_url = get_absolute_remote_url(@module_info.remote_url)
|
15
|
+
@remote_path = remote_path(@module_info.remote_url)
|
16
|
+
@logger = logger
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
# fetch module +mod+ into the .rim folder
|
22
|
+
# works both for initial fetch and updates
|
23
|
+
def fetch_module
|
24
|
+
git_path = module_git_path(@remote_path)
|
25
|
+
FileUtils.mkdir_p git_path
|
26
|
+
RIM::git_session(git_path) do |s|
|
27
|
+
if !File.exist?(git_path + "/config")
|
28
|
+
s.execute("git clone --mirror #{@remote_url} #{git_path}") do |out, e|
|
29
|
+
raise RimException.new("Remote repository '#{@remote_url}' of module '#{@module_info.local_path}' not found.") if e
|
30
|
+
end
|
31
|
+
else
|
32
|
+
s.execute("git remote update")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
git_path
|
36
|
+
end
|
37
|
+
|
38
|
+
# prepare empty folder: remove all files not on the ignore list and empty folders
|
39
|
+
def prepare_empty_folder(local_path, ignores)
|
40
|
+
ignores = FileHelper.find_matching_files(local_path, true, ignores)
|
41
|
+
FileHelper.find_matching_files(local_path, true, "/**/*", File::FNM_DOTMATCH).each do |f|
|
42
|
+
if File.file?(f) && !ignores.include?(f)
|
43
|
+
FileUtils.rm(f)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
FileHelper.remove_empty_dirs(local_path)
|
47
|
+
FileUtils.mkdir_p(local_path)
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module RIM
|
2
|
+
|
3
|
+
class ModuleInfo
|
4
|
+
# remote url (unique identifier of module)
|
5
|
+
attr_reader :remote_url
|
6
|
+
# remote branch format
|
7
|
+
attr_reader :remote_branch_format
|
8
|
+
# locale module path
|
9
|
+
attr_reader :local_path
|
10
|
+
# target revision
|
11
|
+
attr_reader :target_revision
|
12
|
+
# ignores
|
13
|
+
attr_reader :ignores
|
14
|
+
|
15
|
+
def initialize(remote_url, local_path, target_revision, ignores = nil, remote_branch_format = nil)
|
16
|
+
@remote_url = remote_url
|
17
|
+
@remote_branch_format = remote_branch_format
|
18
|
+
@local_path = local_path
|
19
|
+
@target_revision = target_revision
|
20
|
+
if ignores.is_a?(String)
|
21
|
+
@ignores = ignores.split(",").each do |s|
|
22
|
+
s.strip!
|
23
|
+
end
|
24
|
+
else
|
25
|
+
@ignores = ignores || []
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
require 'pathname'
|
3
|
+
require 'rim/file_helper'
|
4
|
+
require 'rim/git'
|
5
|
+
require 'rim/rim_exception'
|
6
|
+
require 'rake'
|
7
|
+
require 'pathname'
|
8
|
+
require 'uri'
|
9
|
+
|
10
|
+
module RIM
|
11
|
+
|
12
|
+
class Processor
|
13
|
+
|
14
|
+
MaxThreads = 10
|
15
|
+
GerritServer = "ssh://gerrit/"
|
16
|
+
|
17
|
+
def initialize(workspace_root, logger)
|
18
|
+
@ws_root = workspace_root
|
19
|
+
@logger = logger
|
20
|
+
end
|
21
|
+
|
22
|
+
def module_git_path(remote_path)
|
23
|
+
# remote url without protocol specifier
|
24
|
+
# this way the local path should be unique
|
25
|
+
File.join(@ws_root, ".rim", remote_path)
|
26
|
+
end
|
27
|
+
|
28
|
+
def module_tmp_git_path(remote_path)
|
29
|
+
# remote url without protocol specifier
|
30
|
+
# this way the local path should be unique
|
31
|
+
File.join(@ws_root, ".rim", ".tmp", remote_path)
|
32
|
+
end
|
33
|
+
|
34
|
+
def remote_path(remote_url)
|
35
|
+
remote_url.
|
36
|
+
# protocol specifier, e.g. ssh://
|
37
|
+
sub(/^\w+:\/\//,'').
|
38
|
+
# windows drive letter
|
39
|
+
sub(/^\w+:/,'\1').
|
40
|
+
# make sure we don't .. up in a filesystem
|
41
|
+
gsub(/\.\.[\\\/]/,'')
|
42
|
+
end
|
43
|
+
|
44
|
+
def get_relative_path(path)
|
45
|
+
FileHelper.get_relative_path(path, @ws_root)
|
46
|
+
end
|
47
|
+
|
48
|
+
def get_absolute_remote_url(remote_url)
|
49
|
+
if remote_url.start_with?("file:")
|
50
|
+
remote_url = remote_url.gsub(/^file:(\/\/)?/, "")
|
51
|
+
match = remote_url.match(/^\/(\w)\|/)
|
52
|
+
if match
|
53
|
+
remote_url = "#{match[1]}:#{remote_url[match[0].size..-1]}"
|
54
|
+
elsif !remote_url.start_with?(File::SEPARATOR)
|
55
|
+
File.expand_path(remote_url, @ws_root)
|
56
|
+
else
|
57
|
+
remote_url
|
58
|
+
end
|
59
|
+
else
|
60
|
+
URI.parse(GerritServer).merge(URI.parse(remote_url)).to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def local_changes?(ws_dir, dir=ws_dir)
|
65
|
+
stat = nil
|
66
|
+
RIM::git_session(ws_dir) do |s|
|
67
|
+
stat = s.status(dir)
|
68
|
+
end
|
69
|
+
stat.lines.all?{|l| l.ignored?}
|
70
|
+
end
|
71
|
+
|
72
|
+
def clone_or_fetch_repository(remote_url, local_path, clone_log = nil)
|
73
|
+
FileUtils.mkdir_p local_path
|
74
|
+
RIM::git_session(local_path) do |s|
|
75
|
+
if !File.exist?(File.join(local_path, ".git"))
|
76
|
+
@logger.info(clone_log) if clone_log
|
77
|
+
FileHelper.make_empty_dir(local_path)
|
78
|
+
s.execute("git clone #{remote_url} .")
|
79
|
+
s.execute("git config core.ignorecase false")
|
80
|
+
else
|
81
|
+
s.execute("git remote set-url origin #{remote_url}") if !s.has_valid_remote_repository?()
|
82
|
+
s.execute("git fetch")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
local_path
|
86
|
+
end
|
87
|
+
|
88
|
+
def each_module_parallel(task_desc, modules)
|
89
|
+
if !modules.empty?
|
90
|
+
@logger.debug "starting \"#{task_desc}\" for #{modules.size} modules\r"
|
91
|
+
threads = []
|
92
|
+
messages = []
|
93
|
+
i = 0
|
94
|
+
done = 0
|
95
|
+
while i == 0 || !threads.empty?
|
96
|
+
while threads.size < MaxThreads && i < modules.size
|
97
|
+
threads << Thread.new(i) do |i|
|
98
|
+
begin
|
99
|
+
yield(modules[i], i)
|
100
|
+
rescue RimException => e
|
101
|
+
messages += e.messages
|
102
|
+
end
|
103
|
+
end
|
104
|
+
i += 1
|
105
|
+
end
|
106
|
+
sleep(0.1)
|
107
|
+
threads = threads.select{|t|
|
108
|
+
if t.alive?
|
109
|
+
true
|
110
|
+
else
|
111
|
+
t.join
|
112
|
+
done += 1
|
113
|
+
@logger.debug "#{task_desc} #{done}/#{modules.size}\r"
|
114
|
+
false
|
115
|
+
end
|
116
|
+
}
|
117
|
+
end
|
118
|
+
if !messages.empty?
|
119
|
+
raise RimException.new(messages)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module RIM
|
2
|
+
|
3
|
+
# RIM revision status object.
|
4
|
+
#
|
5
|
+
# Revision status objects hold the RIM status of a specific project git revision.
|
6
|
+
# As a special case, this could also be the status of the current working copy.
|
7
|
+
#
|
8
|
+
# The revision status consists of a set of module status objects,
|
9
|
+
# one for each module known to RIM in that revision.
|
10
|
+
# The module status points to a RimInfo object holding attribute values
|
11
|
+
# valid for that specific revision as well as the current dirty state as
|
12
|
+
# calculated by DirtyCheck and the module directory.
|
13
|
+
#
|
14
|
+
# Revsion status objects can have parent status objects. This way,
|
15
|
+
# chains and even trees of status objects can be built. For example in
|
16
|
+
# case of a merge commit, the corresponding status object would have
|
17
|
+
# two parent status objects, one for each parent git commit.
|
18
|
+
#
|
19
|
+
class RevStatus
|
20
|
+
# git revision (sha1) for which this status was created
|
21
|
+
# or nil if the status wasn't created for a git revision
|
22
|
+
attr_reader :git_rev
|
23
|
+
# module status objects
|
24
|
+
attr_reader :modules
|
25
|
+
# references to RevStatus objects of parent commits
|
26
|
+
attr_reader :parents
|
27
|
+
|
28
|
+
class ModuleStatus
|
29
|
+
# module directory, relative to project dir root
|
30
|
+
attr_reader :dir
|
31
|
+
# reference to a RimInfo object
|
32
|
+
attr_reader :rim_info
|
33
|
+
|
34
|
+
# dirty state [true, false]
|
35
|
+
def dirty?
|
36
|
+
@dirty
|
37
|
+
end
|
38
|
+
|
39
|
+
def initialize(dir, rim_info, dirty)
|
40
|
+
@dir = dir
|
41
|
+
@rim_info = rim_info
|
42
|
+
@dirty = dirty
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def initialize(modules)
|
47
|
+
@modules = modules
|
48
|
+
@parents = []
|
49
|
+
end
|
50
|
+
|
51
|
+
def dirty?
|
52
|
+
modules.any?{|m| m.dirty?}
|
53
|
+
end
|
54
|
+
|
55
|
+
def git_rev=(rev)
|
56
|
+
@git_rev = rev
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|