jit 0.0.0 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/LICENSE.txt +674 -0
- data/bin/jit +21 -0
- data/lib/color.rb +32 -0
- data/lib/command.rb +62 -0
- data/lib/command/add.rb +65 -0
- data/lib/command/base.rb +92 -0
- data/lib/command/branch.rb +199 -0
- data/lib/command/checkout.rb +104 -0
- data/lib/command/cherry_pick.rb +51 -0
- data/lib/command/commit.rb +86 -0
- data/lib/command/config.rb +126 -0
- data/lib/command/diff.rb +114 -0
- data/lib/command/fetch.rb +116 -0
- data/lib/command/init.rb +41 -0
- data/lib/command/log.rb +188 -0
- data/lib/command/merge.rb +148 -0
- data/lib/command/push.rb +172 -0
- data/lib/command/receive_pack.rb +92 -0
- data/lib/command/remote.rb +55 -0
- data/lib/command/reset.rb +64 -0
- data/lib/command/rev_list.rb +33 -0
- data/lib/command/revert.rb +69 -0
- data/lib/command/rm.rb +105 -0
- data/lib/command/shared/fast_forward.rb +19 -0
- data/lib/command/shared/print_diff.rb +116 -0
- data/lib/command/shared/receive_objects.rb +37 -0
- data/lib/command/shared/remote_agent.rb +44 -0
- data/lib/command/shared/remote_client.rb +82 -0
- data/lib/command/shared/send_objects.rb +24 -0
- data/lib/command/shared/sequencing.rb +146 -0
- data/lib/command/shared/write_commit.rb +167 -0
- data/lib/command/status.rb +210 -0
- data/lib/command/upload_pack.rb +54 -0
- data/lib/config.rb +240 -0
- data/lib/config/stack.rb +42 -0
- data/lib/database.rb +112 -0
- data/lib/database/author.rb +27 -0
- data/lib/database/backends.rb +57 -0
- data/lib/database/blob.rb +24 -0
- data/lib/database/commit.rb +70 -0
- data/lib/database/entry.rb +7 -0
- data/lib/database/loose.rb +70 -0
- data/lib/database/packed.rb +75 -0
- data/lib/database/tree.rb +77 -0
- data/lib/database/tree_diff.rb +88 -0
- data/lib/diff.rb +46 -0
- data/lib/diff/combined.rb +72 -0
- data/lib/diff/hunk.rb +64 -0
- data/lib/diff/myers.rb +90 -0
- data/lib/editor.rb +59 -0
- data/lib/index.rb +212 -0
- data/lib/index/checksum.rb +44 -0
- data/lib/index/entry.rb +91 -0
- data/lib/lockfile.rb +55 -0
- data/lib/merge/bases.rb +38 -0
- data/lib/merge/common_ancestors.rb +77 -0
- data/lib/merge/diff3.rb +156 -0
- data/lib/merge/inputs.rb +42 -0
- data/lib/merge/resolve.rb +178 -0
- data/lib/pack.rb +45 -0
- data/lib/pack/compressor.rb +83 -0
- data/lib/pack/delta.rb +58 -0
- data/lib/pack/entry.rb +54 -0
- data/lib/pack/expander.rb +54 -0
- data/lib/pack/index.rb +100 -0
- data/lib/pack/indexer.rb +200 -0
- data/lib/pack/numbers.rb +79 -0
- data/lib/pack/reader.rb +98 -0
- data/lib/pack/stream.rb +80 -0
- data/lib/pack/unpacker.rb +62 -0
- data/lib/pack/window.rb +47 -0
- data/lib/pack/writer.rb +92 -0
- data/lib/pack/xdelta.rb +118 -0
- data/lib/pager.rb +24 -0
- data/lib/progress.rb +78 -0
- data/lib/refs.rb +260 -0
- data/lib/remotes.rb +82 -0
- data/lib/remotes/protocol.rb +82 -0
- data/lib/remotes/refspec.rb +70 -0
- data/lib/remotes/remote.rb +57 -0
- data/lib/repository.rb +64 -0
- data/lib/repository/divergence.rb +21 -0
- data/lib/repository/hard_reset.rb +35 -0
- data/lib/repository/inspector.rb +49 -0
- data/lib/repository/migration.rb +168 -0
- data/lib/repository/pending_commit.rb +60 -0
- data/lib/repository/sequencer.rb +118 -0
- data/lib/repository/status.rb +98 -0
- data/lib/rev_list.rb +244 -0
- data/lib/revision.rb +155 -0
- data/lib/sorted_hash.rb +17 -0
- data/lib/temp_file.rb +34 -0
- data/lib/workspace.rb +107 -0
- metadata +103 -9
data/lib/merge/diff3.rb
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
require_relative "../diff"
|
2
|
+
|
3
|
+
module Merge
|
4
|
+
class Diff3
|
5
|
+
|
6
|
+
Clean = Struct.new(:lines) do
|
7
|
+
def to_s(*)
|
8
|
+
lines.join("")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
Conflict = Struct.new(:o_lines, :a_lines, :b_lines) do
|
13
|
+
def to_s(a_name = nil, b_name = nil)
|
14
|
+
text = ""
|
15
|
+
separator(text, "<", a_name)
|
16
|
+
a_lines.each { |line| text.concat(line) }
|
17
|
+
separator(text, "=")
|
18
|
+
b_lines.each { |line| text.concat(line) }
|
19
|
+
separator(text, ">", b_name)
|
20
|
+
text
|
21
|
+
end
|
22
|
+
|
23
|
+
def separator(text, char, name = nil)
|
24
|
+
text.concat(char * 7)
|
25
|
+
text.concat(" #{ name }") if name
|
26
|
+
text.concat("\n")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Result = Struct.new(:chunks) do
|
31
|
+
def clean?
|
32
|
+
chunks.none? { |chunk| chunk.is_a?(Conflict) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_s(a_name = nil, b_name = nil)
|
36
|
+
chunks.map { |chunk| chunk.to_s(a_name, b_name) }.join("")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.merge(o, a, b)
|
41
|
+
o = o.lines if o.is_a?(String)
|
42
|
+
a = a.lines if a.is_a?(String)
|
43
|
+
b = b.lines if b.is_a?(String)
|
44
|
+
|
45
|
+
new(o, a, b).merge
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(o, a, b)
|
49
|
+
@o, @a, @b = o, a, b
|
50
|
+
end
|
51
|
+
|
52
|
+
def merge
|
53
|
+
setup
|
54
|
+
generate_chunks
|
55
|
+
Result.new(@chunks)
|
56
|
+
end
|
57
|
+
|
58
|
+
def setup
|
59
|
+
@chunks = []
|
60
|
+
@line_o = @line_a = @line_b = 0
|
61
|
+
|
62
|
+
@match_a = match_set(@a)
|
63
|
+
@match_b = match_set(@b)
|
64
|
+
end
|
65
|
+
|
66
|
+
def match_set(file)
|
67
|
+
matches = {}
|
68
|
+
|
69
|
+
Diff.diff(@o, file).each do |edit|
|
70
|
+
next unless edit.type == :eql
|
71
|
+
matches[edit.a_line.number] = edit.b_line.number
|
72
|
+
end
|
73
|
+
|
74
|
+
matches
|
75
|
+
end
|
76
|
+
|
77
|
+
def generate_chunks
|
78
|
+
loop do
|
79
|
+
i = find_next_mismatch
|
80
|
+
|
81
|
+
if i == 1
|
82
|
+
o, a, b = find_next_match
|
83
|
+
|
84
|
+
if a and b
|
85
|
+
emit_chunk(o, a, b)
|
86
|
+
else
|
87
|
+
emit_final_chunk
|
88
|
+
return
|
89
|
+
end
|
90
|
+
|
91
|
+
elsif i
|
92
|
+
emit_chunk(@line_o + i, @line_a + i, @line_b + i)
|
93
|
+
|
94
|
+
else
|
95
|
+
emit_final_chunk
|
96
|
+
return
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def find_next_mismatch
|
102
|
+
i = 1
|
103
|
+
while in_bounds?(i) and
|
104
|
+
match?(@match_a, @line_a, i) and
|
105
|
+
match?(@match_b, @line_b, i)
|
106
|
+
i += 1
|
107
|
+
end
|
108
|
+
in_bounds?(i) ? i : nil
|
109
|
+
end
|
110
|
+
|
111
|
+
def in_bounds?(i)
|
112
|
+
@line_o + i <= @o.size or
|
113
|
+
@line_a + i <= @a.size or
|
114
|
+
@line_b + i <= @b.size
|
115
|
+
end
|
116
|
+
|
117
|
+
def match?(matches, offset, i)
|
118
|
+
matches[@line_o + i] == offset + i
|
119
|
+
end
|
120
|
+
|
121
|
+
def find_next_match
|
122
|
+
o = @line_o + 1
|
123
|
+
until o > @o.size or (@match_a.has_key?(o) and @match_b.has_key?(o))
|
124
|
+
o += 1
|
125
|
+
end
|
126
|
+
[o, @match_a[o], @match_b[o]]
|
127
|
+
end
|
128
|
+
|
129
|
+
def emit_chunk(o, a, b)
|
130
|
+
write_chunk(
|
131
|
+
@o[@line_o ... o - 1],
|
132
|
+
@a[@line_a ... a - 1],
|
133
|
+
@b[@line_b ... b - 1])
|
134
|
+
|
135
|
+
@line_o, @line_a, @line_b = o - 1, a - 1, b - 1
|
136
|
+
end
|
137
|
+
|
138
|
+
def emit_final_chunk
|
139
|
+
write_chunk(
|
140
|
+
@o[@line_o .. -1],
|
141
|
+
@a[@line_a .. -1],
|
142
|
+
@b[@line_b .. -1])
|
143
|
+
end
|
144
|
+
|
145
|
+
def write_chunk(o, a, b)
|
146
|
+
if a == o or a == b
|
147
|
+
@chunks.push(Clean.new(b))
|
148
|
+
elsif b == o
|
149
|
+
@chunks.push(Clean.new(a))
|
150
|
+
else
|
151
|
+
@chunks.push(Conflict.new(o, a, b))
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
end
|
data/lib/merge/inputs.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative "./bases"
|
2
|
+
require_relative "../revision"
|
3
|
+
|
4
|
+
module Merge
|
5
|
+
class Inputs
|
6
|
+
|
7
|
+
ATTRS = [ :left_name, :right_name,
|
8
|
+
:left_oid, :right_oid,
|
9
|
+
:base_oids ]
|
10
|
+
|
11
|
+
attr_reader(*ATTRS)
|
12
|
+
|
13
|
+
def initialize(repository, left_name, right_name)
|
14
|
+
@repo = repository
|
15
|
+
@left_name = left_name
|
16
|
+
@right_name = right_name
|
17
|
+
|
18
|
+
@left_oid = resolve_rev(@left_name)
|
19
|
+
@right_oid = resolve_rev(@right_name)
|
20
|
+
|
21
|
+
common = Bases.new(@repo.database, @left_oid, @right_oid)
|
22
|
+
@base_oids = common.find
|
23
|
+
end
|
24
|
+
|
25
|
+
def already_merged?
|
26
|
+
@base_oids == [@right_oid]
|
27
|
+
end
|
28
|
+
|
29
|
+
def fast_forward?
|
30
|
+
@base_oids == [@left_oid]
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def resolve_rev(rev)
|
36
|
+
Revision.new(@repo, rev).resolve(Revision::COMMIT)
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
CherryPick = Struct.new(*Inputs::ATTRS)
|
42
|
+
end
|
@@ -0,0 +1,178 @@
|
|
1
|
+
require_relative "./diff3"
|
2
|
+
|
3
|
+
module Merge
|
4
|
+
class Resolve
|
5
|
+
|
6
|
+
def initialize(repository, inputs)
|
7
|
+
@repo = repository
|
8
|
+
@inputs = inputs
|
9
|
+
|
10
|
+
@on_progress = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def on_progress(&block)
|
14
|
+
@on_progress = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def execute
|
18
|
+
prepare_tree_diffs
|
19
|
+
|
20
|
+
migration = @repo.migration(@clean_diff)
|
21
|
+
migration.apply_changes
|
22
|
+
|
23
|
+
add_conflicts_to_index
|
24
|
+
write_untracked_files
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def prepare_tree_diffs
|
30
|
+
base_oid = @inputs.base_oids.first
|
31
|
+
@left_diff = @repo.database.tree_diff(base_oid, @inputs.left_oid)
|
32
|
+
@right_diff = @repo.database.tree_diff(base_oid, @inputs.right_oid)
|
33
|
+
@clean_diff = {}
|
34
|
+
@conflicts = {}
|
35
|
+
@untracked = {}
|
36
|
+
|
37
|
+
@right_diff.each do |path, (old_item, new_item)|
|
38
|
+
file_dir_conflict(path, @left_diff, @inputs.left_name) if new_item
|
39
|
+
same_path_conflict(path, old_item, new_item)
|
40
|
+
end
|
41
|
+
|
42
|
+
@left_diff.each do |path, (_, new_item)|
|
43
|
+
file_dir_conflict(path, @right_diff, @inputs.right_name) if new_item
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def same_path_conflict(path, base, right)
|
48
|
+
return if @conflicts[path]
|
49
|
+
|
50
|
+
unless @left_diff.has_key?(path)
|
51
|
+
@clean_diff[path] = [base, right]
|
52
|
+
return
|
53
|
+
end
|
54
|
+
|
55
|
+
left = @left_diff[path][1]
|
56
|
+
return if left == right
|
57
|
+
|
58
|
+
log "Auto-merging #{ path }" if left and right
|
59
|
+
|
60
|
+
oid_ok, oid = merge_blobs(base&.oid, left&.oid, right&.oid)
|
61
|
+
mode_ok, mode = merge_modes(base&.mode, left&.mode, right&.mode)
|
62
|
+
|
63
|
+
@clean_diff[path] = [left, Database::Entry.new(oid, mode)]
|
64
|
+
return if oid_ok and mode_ok
|
65
|
+
|
66
|
+
@conflicts[path] = [base, left, right]
|
67
|
+
log_conflict(path)
|
68
|
+
end
|
69
|
+
|
70
|
+
def merge_blobs(base_oid, left_oid, right_oid)
|
71
|
+
result = merge3(base_oid, left_oid, right_oid)
|
72
|
+
return result if result
|
73
|
+
|
74
|
+
oids = [base_oid, left_oid, right_oid]
|
75
|
+
blobs = oids.map { |oid| oid ? @repo.database.load(oid).data : "" }
|
76
|
+
merge = Diff3.merge(*blobs)
|
77
|
+
|
78
|
+
data = merge.to_s(@inputs.left_name, @inputs.right_name)
|
79
|
+
blob = Database::Blob.new(data)
|
80
|
+
@repo.database.store(blob)
|
81
|
+
|
82
|
+
[merge.clean?, blob.oid]
|
83
|
+
end
|
84
|
+
|
85
|
+
def merge_modes(base_mode, left_mode, right_mode)
|
86
|
+
merge3(base_mode, left_mode, right_mode) || [false, left_mode]
|
87
|
+
end
|
88
|
+
|
89
|
+
def merge3(base, left, right)
|
90
|
+
return [false, right] unless left
|
91
|
+
return [false, left] unless right
|
92
|
+
|
93
|
+
if left == base or left == right
|
94
|
+
[true, right]
|
95
|
+
elsif right == base
|
96
|
+
[true, left]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def file_dir_conflict(path, diff, name)
|
101
|
+
path.dirname.ascend do |parent|
|
102
|
+
old_item, new_item = diff[parent]
|
103
|
+
next unless new_item
|
104
|
+
|
105
|
+
@conflicts[parent] = case name
|
106
|
+
when @inputs.left_name then [old_item, new_item, nil]
|
107
|
+
when @inputs.right_name then [old_item, nil, new_item]
|
108
|
+
end
|
109
|
+
|
110
|
+
@clean_diff.delete(parent)
|
111
|
+
rename = "#{ parent }~#{ name }"
|
112
|
+
@untracked[rename] = new_item
|
113
|
+
|
114
|
+
log "Adding #{ path }" unless diff[path]
|
115
|
+
log_conflict(parent, rename)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def add_conflicts_to_index
|
120
|
+
@conflicts.each do |path, items|
|
121
|
+
@repo.index.add_conflict_set(path, items)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def write_untracked_files
|
126
|
+
@untracked.each do |path, item|
|
127
|
+
blob = @repo.database.load(item.oid)
|
128
|
+
@repo.workspace.write_file(path, blob.data)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
def log(message)
|
133
|
+
@on_progress&.call(message)
|
134
|
+
end
|
135
|
+
|
136
|
+
def log_conflict(path, rename = nil)
|
137
|
+
base, left, right = @conflicts[path]
|
138
|
+
|
139
|
+
if left and right
|
140
|
+
log_left_right_conflict(path)
|
141
|
+
elsif base and (left or right)
|
142
|
+
log_modify_delete_conflict(path, rename)
|
143
|
+
else
|
144
|
+
log_file_directory_conflict(path, rename)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def log_left_right_conflict(path)
|
149
|
+
type = @conflicts[path][0] ? "content" : "add/add"
|
150
|
+
log "CONFLICT (#{ type }): Merge conflict in #{ path }"
|
151
|
+
end
|
152
|
+
|
153
|
+
def log_modify_delete_conflict(path, rename)
|
154
|
+
deleted, modified = log_branch_names(path)
|
155
|
+
|
156
|
+
rename = rename ? " at #{ rename }" : ""
|
157
|
+
|
158
|
+
log "CONFLICT (modify/delete): #{ path } " +
|
159
|
+
"deleted in #{ deleted } and modified in #{ modified }. " +
|
160
|
+
"Version #{ modified } of #{ path } left in tree#{ rename }."
|
161
|
+
end
|
162
|
+
|
163
|
+
def log_file_directory_conflict(path, rename)
|
164
|
+
type = @conflicts[path][1] ? "file/directory" : "directory/file"
|
165
|
+
branch, _ = log_branch_names(path)
|
166
|
+
|
167
|
+
log "CONFLICT (#{ type }): There is a directory " +
|
168
|
+
"with name #{ path } in #{ branch }. " +
|
169
|
+
"Adding #{ path } as #{ rename }"
|
170
|
+
end
|
171
|
+
|
172
|
+
def log_branch_names(path)
|
173
|
+
a, b = @inputs.left_name, @inputs.right_name
|
174
|
+
@conflicts[path][1] ? [b, a] : [a, b]
|
175
|
+
end
|
176
|
+
|
177
|
+
end
|
178
|
+
end
|
data/lib/pack.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
require_relative "./pack/reader"
|
2
|
+
require_relative "./pack/writer"
|
3
|
+
require_relative "./pack/stream"
|
4
|
+
require_relative "./pack/indexer"
|
5
|
+
require_relative "./pack/unpacker"
|
6
|
+
|
7
|
+
module Pack
|
8
|
+
HEADER_SIZE = 12
|
9
|
+
HEADER_FORMAT = "a4N2"
|
10
|
+
SIGNATURE = "PACK"
|
11
|
+
VERSION = 2
|
12
|
+
|
13
|
+
GIT_MAX_COPY = 0x10000
|
14
|
+
MAX_COPY_SIZE = 0xffffff
|
15
|
+
MAX_INSERT_SIZE = 0x7f
|
16
|
+
|
17
|
+
IDX_SIGNATURE = 0xff744f63
|
18
|
+
IDX_MAX_OFFSET = 0x80000000
|
19
|
+
|
20
|
+
COMMIT = 1
|
21
|
+
TREE = 2
|
22
|
+
BLOB = 3
|
23
|
+
|
24
|
+
OFS_DELTA = 6
|
25
|
+
REF_DELTA = 7
|
26
|
+
|
27
|
+
TYPE_CODES = {
|
28
|
+
"commit" => COMMIT,
|
29
|
+
"tree" => TREE,
|
30
|
+
"blob" => BLOB
|
31
|
+
}
|
32
|
+
|
33
|
+
InvalidPack = Class.new(StandardError)
|
34
|
+
|
35
|
+
Record = Struct.new(:type, :data) do
|
36
|
+
attr_accessor :oid
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
data
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
OfsDelta = Struct.new(:base_ofs, :delta_data)
|
44
|
+
RefDelta = Struct.new(:base_oid, :delta_data)
|
45
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require_relative "./delta"
|
2
|
+
require_relative "./window"
|
3
|
+
|
4
|
+
module Pack
|
5
|
+
class Compressor
|
6
|
+
|
7
|
+
OBJECT_SIZE = 50..0x20000000
|
8
|
+
MAX_DEPTH = 50
|
9
|
+
WINDOW_SIZE = 8
|
10
|
+
|
11
|
+
def initialize(database, progress)
|
12
|
+
@database = database
|
13
|
+
@window = Window.new(WINDOW_SIZE)
|
14
|
+
@progress = progress
|
15
|
+
@objects = []
|
16
|
+
end
|
17
|
+
|
18
|
+
def add(entry)
|
19
|
+
return unless OBJECT_SIZE.include?(entry.size)
|
20
|
+
@objects.push(entry)
|
21
|
+
end
|
22
|
+
|
23
|
+
def build_deltas
|
24
|
+
@progress&.start("Compressing objects", @objects.size)
|
25
|
+
|
26
|
+
@objects.sort! { |a, b| b.sort_key <=> a.sort_key }
|
27
|
+
|
28
|
+
@objects.each do |entry|
|
29
|
+
build_delta(entry)
|
30
|
+
@progress&.tick
|
31
|
+
end
|
32
|
+
@progress&.stop
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def build_delta(entry)
|
38
|
+
object = @database.load_raw(entry.oid)
|
39
|
+
target = @window.add(entry, object.data)
|
40
|
+
|
41
|
+
@window.each { |source| try_delta(source, target) }
|
42
|
+
end
|
43
|
+
|
44
|
+
def try_delta(source, target)
|
45
|
+
return unless source.type == target.type
|
46
|
+
return unless source.depth < MAX_DEPTH
|
47
|
+
|
48
|
+
max_size = max_size_heuristic(source, target)
|
49
|
+
return unless compatible_sizes?(source, target, max_size)
|
50
|
+
|
51
|
+
delta = Delta.new(source, target)
|
52
|
+
size = target.entry.packed_size
|
53
|
+
|
54
|
+
return if delta.size > max_size
|
55
|
+
return if delta.size == size and delta.base.depth + 1 >= target.depth
|
56
|
+
|
57
|
+
target.entry.assign_delta(delta)
|
58
|
+
end
|
59
|
+
|
60
|
+
def max_size_heuristic(source, target)
|
61
|
+
if target.delta
|
62
|
+
max_size = target.delta.size
|
63
|
+
ref_depth = target.depth
|
64
|
+
else
|
65
|
+
max_size = target.size / 2 - 20
|
66
|
+
ref_depth = 1
|
67
|
+
end
|
68
|
+
|
69
|
+
max_size * (MAX_DEPTH - source.depth) / (MAX_DEPTH + 1 - ref_depth)
|
70
|
+
end
|
71
|
+
|
72
|
+
def compatible_sizes?(source, target, max_size)
|
73
|
+
size_diff = [target.size - source.size, 0].max
|
74
|
+
|
75
|
+
return false if max_size == 0
|
76
|
+
return false if size_diff >= max_size
|
77
|
+
return false if target.size < source.size / 32
|
78
|
+
|
79
|
+
true
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|