grit 2.4.1 → 2.5.0
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/History.txt +16 -0
- data/grit.gemspec +3 -6
- data/lib/grit.rb +1 -7
- data/lib/grit/actor.rb +7 -7
- data/lib/grit/blame.rb +7 -3
- data/lib/grit/commit.rb +23 -4
- data/lib/grit/git-ruby.rb +12 -25
- data/lib/grit/git-ruby/git_object.rb +4 -1
- data/lib/grit/git-ruby/internal/loose.rb +5 -5
- data/lib/grit/git-ruby/internal/pack.rb +21 -7
- data/lib/grit/git-ruby/internal/raw_object.rb +7 -0
- data/lib/grit/git-ruby/repository.rb +60 -60
- data/lib/grit/git.rb +72 -25
- data/lib/grit/index.rb +34 -9
- data/lib/grit/repo.rb +68 -14
- data/lib/grit/tag.rb +34 -3
- data/lib/grit/tree.rb +2 -2
- metadata +57 -79
- data/lib/grit/git-ruby/file_index.rb +0 -193
- data/lib/grit/git-ruby/object.rb +0 -325
- data/lib/grit/jruby.rb +0 -45
- data/lib/grit/process.rb +0 -294
data/History.txt
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
== 2.5.0 / 2012-04-22
|
2
|
+
* Minor Enhancements
|
3
|
+
* 100% Git-compliant actor creation.
|
4
|
+
* Handle newlines in author/committer.
|
5
|
+
* Grit::Git check_applies/patch related methods take command hash.
|
6
|
+
* Tags api now resty.
|
7
|
+
* Remove all the grit jruby hacks in favor of updated posix-spawn.
|
8
|
+
* Add Grit::Commit#patch_id.
|
9
|
+
* Support large packfiles with index v2.
|
10
|
+
* Bug Fixes
|
11
|
+
* Fix Loose Objects with non-ASCII content in Ruby 1.9
|
12
|
+
* Fix bugs in Grit::Repo #objects, #commit_objects, and #diff_objects
|
13
|
+
due to passing multiple arguments in a single argv element.
|
14
|
+
* ruby rev_list passes --verify to native rev_parse in fallback.
|
15
|
+
* Git ls-tree raises on non-zero exit.
|
16
|
+
|
1
17
|
== 2.4.1 / 2011-01-13
|
2
18
|
* Minor Enhancements
|
3
19
|
* Grit::Process is used to implement Grit::Git#check_applies,
|
data/grit.gemspec
CHANGED
@@ -4,8 +4,8 @@ Gem::Specification.new do |s|
|
|
4
4
|
s.rubygems_version = '1.3.5'
|
5
5
|
|
6
6
|
s.name = 'grit'
|
7
|
-
s.version = '2.
|
8
|
-
s.date = '
|
7
|
+
s.version = '2.5.0'
|
8
|
+
s.date = '2012-04-22'
|
9
9
|
s.rubyforge_project = 'grit'
|
10
10
|
|
11
11
|
s.summary = "Ruby Git bindings."
|
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.rdoc_options = ["--charset=UTF-8"]
|
21
21
|
s.extra_rdoc_files = %w[README.md LICENSE]
|
22
22
|
|
23
|
+
s.add_dependency('posix-spawn', "~> 0.3.6")
|
23
24
|
s.add_dependency('mime-types', "~> 1.15")
|
24
25
|
s.add_dependency('diff-lcs', "~> 1.1")
|
25
26
|
|
@@ -49,20 +50,16 @@ Gem::Specification.new do |s|
|
|
49
50
|
lib/grit/errors.rb
|
50
51
|
lib/grit/git-ruby.rb
|
51
52
|
lib/grit/git-ruby/commit_db.rb
|
52
|
-
lib/grit/git-ruby/file_index.rb
|
53
53
|
lib/grit/git-ruby/git_object.rb
|
54
54
|
lib/grit/git-ruby/internal/file_window.rb
|
55
55
|
lib/grit/git-ruby/internal/loose.rb
|
56
56
|
lib/grit/git-ruby/internal/pack.rb
|
57
57
|
lib/grit/git-ruby/internal/raw_object.rb
|
58
|
-
lib/grit/git-ruby/object.rb
|
59
58
|
lib/grit/git-ruby/repository.rb
|
60
59
|
lib/grit/git.rb
|
61
60
|
lib/grit/index.rb
|
62
|
-
lib/grit/jruby.rb
|
63
61
|
lib/grit/lazy.rb
|
64
62
|
lib/grit/merge.rb
|
65
|
-
lib/grit/process.rb
|
66
63
|
lib/grit/ref.rb
|
67
64
|
lib/grit/repo.rb
|
68
65
|
lib/grit/ruby1.9.rb
|
data/lib/grit.rb
CHANGED
@@ -28,7 +28,6 @@ end
|
|
28
28
|
require 'grit/ruby1.9'
|
29
29
|
|
30
30
|
# internal requires
|
31
|
-
require 'grit/process'
|
32
31
|
require 'grit/lazy'
|
33
32
|
require 'grit/errors'
|
34
33
|
require 'grit/git-ruby'
|
@@ -49,13 +48,8 @@ require 'grit/submodule'
|
|
49
48
|
require 'grit/blame'
|
50
49
|
require 'grit/merge'
|
51
50
|
|
52
|
-
# platform specific requires
|
53
|
-
if defined?(RUBY_ENGINE) && RUBY_ENGINE =~ /jruby/
|
54
|
-
require 'grit/jruby'
|
55
|
-
end
|
56
|
-
|
57
51
|
module Grit
|
58
|
-
VERSION = '2.
|
52
|
+
VERSION = '2.5.0'
|
59
53
|
|
60
54
|
class << self
|
61
55
|
# Set +debug+ to true to log all git calls and responses
|
data/lib/grit/actor.rb
CHANGED
@@ -34,13 +34,13 @@ module Grit
|
|
34
34
|
#
|
35
35
|
# Returns a String.
|
36
36
|
def output(time)
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
37
|
+
offset = time.utc_offset / 60
|
38
|
+
"%s <%s> %d %+.2d%.2d" % [
|
39
|
+
@name,
|
40
|
+
@email || "null",
|
41
|
+
time.to_i,
|
42
|
+
offset / 60,
|
43
|
+
offset.abs % 60]
|
44
44
|
end
|
45
45
|
|
46
46
|
# Pretty object inspection
|
data/lib/grit/blame.rb
CHANGED
@@ -4,12 +4,16 @@ module Grit
|
|
4
4
|
|
5
5
|
attr_reader :lines
|
6
6
|
|
7
|
-
def initialize(repo, file, commit)
|
7
|
+
def initialize(repo, file, commit, lines=nil)
|
8
8
|
@repo = repo
|
9
9
|
@file = file
|
10
10
|
@commit = commit
|
11
|
-
|
12
|
-
|
11
|
+
if lines.nil?
|
12
|
+
@lines = []
|
13
|
+
load_blame
|
14
|
+
else
|
15
|
+
@lines = lines
|
16
|
+
end
|
13
17
|
end
|
14
18
|
|
15
19
|
def load_blame
|
data/lib/grit/commit.rb
CHANGED
@@ -13,7 +13,6 @@ module Grit
|
|
13
13
|
lazy_reader :committed_date
|
14
14
|
lazy_reader :message
|
15
15
|
lazy_reader :short_message
|
16
|
-
lazy_reader :author_string
|
17
16
|
|
18
17
|
# Parses output from the `git-cat-file --batch'.
|
19
18
|
#
|
@@ -61,7 +60,7 @@ module Grit
|
|
61
60
|
@committer = committer
|
62
61
|
@committed_date = committed_date
|
63
62
|
@message = message.join("\n")
|
64
|
-
@short_message = message.
|
63
|
+
@short_message = message.find { |x| !x.strip.empty? } || ''
|
65
64
|
end
|
66
65
|
|
67
66
|
def id_abbrev
|
@@ -149,8 +148,13 @@ module Grit
|
|
149
148
|
parents = []
|
150
149
|
parents << lines.shift.split.last while lines.first =~ /^parent/
|
151
150
|
|
152
|
-
|
153
|
-
|
151
|
+
author_line = lines.shift
|
152
|
+
author_line << lines.shift if lines[0] !~ /^committer /
|
153
|
+
author, authored_date = self.actor(author_line)
|
154
|
+
|
155
|
+
committer_line = lines.shift
|
156
|
+
committer_line << lines.shift if lines[0] && lines[0] != '' && lines[0] !~ /^encoding/
|
157
|
+
committer, committed_date = self.actor(committer_line)
|
154
158
|
|
155
159
|
# not doing anything with this yet, but it's sometimes there
|
156
160
|
encoding = lines.shift.split.last if lines.first =~ /^encoding/
|
@@ -252,6 +256,21 @@ module Grit
|
|
252
256
|
ret
|
253
257
|
end
|
254
258
|
|
259
|
+
# Calculates the commit's Patch ID. The Patch ID is essentially the SHA1
|
260
|
+
# of the diff that the commit is introducing.
|
261
|
+
#
|
262
|
+
# Returns the 40 character hex String if a patch-id could be calculated
|
263
|
+
# or nil otherwise.
|
264
|
+
def patch_id
|
265
|
+
show = @repo.git.show({}, @id)
|
266
|
+
patch_line = @repo.git.native(:patch_id, :input => show)
|
267
|
+
if patch_line =~ /^([0-9a-f]{40}) [0-9a-f]{40}\n$/
|
268
|
+
$1
|
269
|
+
else
|
270
|
+
nil
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
255
274
|
# Pretty object inspection
|
256
275
|
def inspect
|
257
276
|
%Q{#<Grit::Commit "#{@id}">}
|
data/lib/grit/git-ruby.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'grit/git-ruby/repository'
|
2
|
-
require 'grit/git-ruby/file_index'
|
3
2
|
|
4
3
|
module Grit
|
5
4
|
|
@@ -48,30 +47,33 @@ module Grit
|
|
48
47
|
try_run { ruby_git.diff(sha1, sha2, options) }
|
49
48
|
end
|
50
49
|
|
51
|
-
def rev_list(options,
|
50
|
+
def rev_list(options, *refs)
|
51
|
+
refs = ['master'] if refs.empty?
|
52
52
|
options.delete(:skip) if options[:skip].to_i == 0
|
53
53
|
allowed_options = [:max_count, :since, :until, :pretty] # this is all I can do right now
|
54
|
-
if ((options.keys - allowed_options).size > 0)
|
55
|
-
|
54
|
+
if ((options.keys - allowed_options).size > 0) || refs.size > 1
|
55
|
+
method_missing('rev-list', options, *refs)
|
56
56
|
elsif (options.size == 0)
|
57
57
|
# pure rev-list
|
58
|
+
ref = refs.first
|
58
59
|
begin
|
59
|
-
|
60
|
+
file_index.commits_from(rev_parse({}, ref)).join("\n") + "\n"
|
60
61
|
rescue
|
61
|
-
|
62
|
+
method_missing('rev-list', options, *refs)
|
62
63
|
end
|
63
64
|
else
|
64
|
-
|
65
|
+
ref = refs.first
|
66
|
+
aref = rev_parse({:verify => true}, ref)
|
65
67
|
if aref.is_a? Array
|
66
|
-
|
68
|
+
method_missing('rev-list', options, *refs)
|
67
69
|
else
|
68
|
-
|
70
|
+
try_run { ruby_git.rev_list(aref, options) }
|
69
71
|
end
|
70
72
|
end
|
71
73
|
end
|
72
74
|
|
73
75
|
def rev_parse(options, string)
|
74
|
-
raise RuntimeError, "invalid string: #{string}" unless string.is_a?(String)
|
76
|
+
raise RuntimeError, "invalid string: #{string.inspect}" unless string.is_a?(String)
|
75
77
|
|
76
78
|
if string =~ /\.\./
|
77
79
|
(sha1, sha2) = string.split('..')
|
@@ -197,21 +199,6 @@ module Grit
|
|
197
199
|
try_run { ruby_git.cat_file_type(ref).to_s }
|
198
200
|
end
|
199
201
|
|
200
|
-
def blame_tree(commit, path = nil)
|
201
|
-
begin
|
202
|
-
path = [path].join('/').to_s + '/' if (path && path != '')
|
203
|
-
path = '' if !path.is_a? String
|
204
|
-
commits = file_index.last_commits(rev_parse({}, commit), looking_for(commit, path))
|
205
|
-
clean_paths(commits)
|
206
|
-
rescue FileIndex::IndexFileNotFound
|
207
|
-
{}
|
208
|
-
end
|
209
|
-
end
|
210
|
-
|
211
|
-
def file_index
|
212
|
-
@git_file_index ||= FileIndex.new(@git_dir)
|
213
|
-
end
|
214
|
-
|
215
202
|
def ruby_git
|
216
203
|
@ruby_git_repo ||= Repository.new(@git_dir)
|
217
204
|
end
|
@@ -49,6 +49,7 @@ module Grit
|
|
49
49
|
# base class for all git objects (blob, tree, commit, tag)
|
50
50
|
class GitObject
|
51
51
|
attr_accessor :repository
|
52
|
+
attr_accessor :sha
|
52
53
|
|
53
54
|
def GitObject.from_raw(rawobject, repository = nil)
|
54
55
|
case rawobject.type
|
@@ -290,7 +291,8 @@ module Grit
|
|
290
291
|
end
|
291
292
|
|
292
293
|
class Tag < GitObject
|
293
|
-
attr_accessor :object, :
|
294
|
+
attr_accessor :object, :tag, :tagger, :message, :object_type
|
295
|
+
attr_writer :type
|
294
296
|
|
295
297
|
def self.from_raw(rawobject, repository=nil)
|
296
298
|
|
@@ -330,6 +332,7 @@ module Grit
|
|
330
332
|
def initialize(object, type, tag, tagger, message, repository=nil)
|
331
333
|
@object = object
|
332
334
|
@type = type
|
335
|
+
@object_type = type
|
333
336
|
@tag = tag
|
334
337
|
@tagger = tagger
|
335
338
|
@repository = repository
|
@@ -36,7 +36,7 @@ module Grit
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def get_raw_object(buf)
|
39
|
-
if buf.
|
39
|
+
if buf.bytesize < 2
|
40
40
|
raise LooseObjectError, "object file too small"
|
41
41
|
end
|
42
42
|
|
@@ -56,14 +56,14 @@ module Grit
|
|
56
56
|
type, size, used = unpack_object_header_gently(buf)
|
57
57
|
content = Zlib::Inflate.inflate(buf[used..-1])
|
58
58
|
end
|
59
|
-
raise LooseObjectError, "size mismatch" if content.
|
59
|
+
raise LooseObjectError, "size mismatch" if content.bytesize != size
|
60
60
|
return RawObject.new(type, content)
|
61
61
|
end
|
62
62
|
|
63
63
|
# currently, I'm using the legacy format because it's easier to do
|
64
64
|
# this function takes content and a type and writes out the loose object and returns a sha
|
65
65
|
def put_raw_object(content, type)
|
66
|
-
size = content.
|
66
|
+
size = content.bytesize.to_s
|
67
67
|
LooseStorage.verify_header(type, size)
|
68
68
|
|
69
69
|
header = "#{type} #{size}\0"
|
@@ -85,7 +85,7 @@ module Grit
|
|
85
85
|
|
86
86
|
# simply figure out the sha
|
87
87
|
def self.calculate_sha(content, type)
|
88
|
-
size = content.
|
88
|
+
size = content.bytesize.to_s
|
89
89
|
verify_header(type, size)
|
90
90
|
header = "#{type} #{size}\0"
|
91
91
|
store = header + content
|
@@ -109,7 +109,7 @@ module Grit
|
|
109
109
|
size = c & 15;
|
110
110
|
shift = 4;
|
111
111
|
while c & 0x80 != 0
|
112
|
-
if buf.
|
112
|
+
if buf.bytesize <= used
|
113
113
|
raise LooseObjectError, "object file too short"
|
114
114
|
end
|
115
115
|
c = buf.getord(used)
|
@@ -30,6 +30,7 @@ module Grit
|
|
30
30
|
SHA1Size = 20
|
31
31
|
IdxOffsetSize = 4
|
32
32
|
OffsetSize = 4
|
33
|
+
ExtendedOffsetSize = 8
|
33
34
|
CrcSize = 4
|
34
35
|
OffsetStart = FanOutCount * IdxOffsetSize
|
35
36
|
SHA1Start = OffsetStart + OffsetSize
|
@@ -46,11 +47,13 @@ module Grit
|
|
46
47
|
end
|
47
48
|
|
48
49
|
def with_idx(index_file = nil)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
else
|
50
|
+
index_file ||= @name[0...-4] + 'idx'
|
51
|
+
|
52
|
+
begin
|
53
53
|
idxfile = File.open(index_file, 'rb')
|
54
|
+
rescue Errno::ENOENT => boom
|
55
|
+
# file went away. bail out without yielding.
|
56
|
+
return
|
54
57
|
end
|
55
58
|
|
56
59
|
# read header
|
@@ -70,14 +73,19 @@ module Grit
|
|
70
73
|
yield idx
|
71
74
|
idx.unmap
|
72
75
|
ensure
|
73
|
-
idxfile.close
|
76
|
+
idxfile.close if idxfile
|
74
77
|
end
|
75
78
|
|
76
79
|
def with_packfile
|
77
|
-
|
80
|
+
begin
|
81
|
+
packfile = File.open(@name, 'rb')
|
82
|
+
rescue Errno::ENOENT
|
83
|
+
# file went away. bail out without yielding.
|
84
|
+
return
|
85
|
+
end
|
78
86
|
yield packfile
|
79
87
|
ensure
|
80
|
-
packfile.close
|
88
|
+
packfile.close if packfile
|
81
89
|
end
|
82
90
|
|
83
91
|
def cache_objects
|
@@ -207,6 +215,12 @@ module Grit
|
|
207
215
|
else
|
208
216
|
pos = OffsetStart + (@size * (SHA1Size + CrcSize)) + (mid * OffsetSize)
|
209
217
|
offset = idx[pos, OffsetSize].unpack('N')[0]
|
218
|
+
if offset & 0x80000000 > 0
|
219
|
+
offset &= 0x7fffffff
|
220
|
+
pos = OffsetStart + (@size * (SHA1Size + CrcSize + OffsetSize)) + (offset * ExtendedOffsetSize)
|
221
|
+
words = idx[pos, ExtendedOffsetSize].unpack('NN')
|
222
|
+
offset = (words[0] << 32) | words[1]
|
223
|
+
end
|
210
224
|
return offset
|
211
225
|
end
|
212
226
|
else
|
@@ -475,60 +475,60 @@ module Grit
|
|
475
475
|
# [full_path, 'modified', tree1_hash, tree2_hash]
|
476
476
|
# ]
|
477
477
|
def quick_diff(tree1, tree2, path = '.', recurse = true)
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
|
510
|
-
|
511
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
478
|
+
# handle empty trees
|
479
|
+
changed = []
|
480
|
+
return changed if tree1 == tree2
|
481
|
+
|
482
|
+
t1 = list_tree(tree1) if tree1
|
483
|
+
t2 = list_tree(tree2) if tree2
|
484
|
+
|
485
|
+
# finding files that are different
|
486
|
+
t1['blob'].each do |file, hsh|
|
487
|
+
t2_file = t2['blob'][file] rescue nil
|
488
|
+
full = File.join(path, file)
|
489
|
+
if !t2_file
|
490
|
+
changed << [full, 'added', hsh[:sha], nil] # not in parent
|
491
|
+
elsif (hsh[:sha] != t2_file[:sha])
|
492
|
+
changed << [full, 'modified', hsh[:sha], t2_file[:sha]] # file changed
|
493
|
+
end
|
494
|
+
end if t1
|
495
|
+
t2['blob'].each do |file, hsh|
|
496
|
+
if !t1 || !t1['blob'][file]
|
497
|
+
changed << [File.join(path, file), 'removed', nil, hsh[:sha]]
|
498
|
+
end
|
499
|
+
end if t2
|
500
|
+
|
501
|
+
t1['tree'].each do |dir, hsh|
|
502
|
+
t2_tree = t2['tree'][dir] rescue nil
|
503
|
+
full = File.join(path, dir)
|
504
|
+
if !t2_tree
|
505
|
+
if recurse
|
506
|
+
changed += quick_diff(hsh[:sha], nil, full, true)
|
507
|
+
else
|
508
|
+
changed << [full, 'added', hsh[:sha], nil] # not in parent
|
509
|
+
end
|
510
|
+
elsif (hsh[:sha] != t2_tree[:sha])
|
511
|
+
if recurse
|
512
|
+
changed += quick_diff(hsh[:sha], t2_tree[:sha], full, true)
|
513
|
+
else
|
514
|
+
changed << [full, 'modified', hsh[:sha], t2_tree[:sha]] # file changed
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end if t1
|
518
|
+
t2['tree'].each do |dir, hsh|
|
519
|
+
t1_tree = t1['tree'][dir] rescue nil
|
520
|
+
full = File.join(path, dir)
|
521
|
+
if !t1_tree
|
522
|
+
if recurse
|
523
|
+
changed += quick_diff(nil, hsh[:sha], full, true)
|
524
|
+
else
|
525
|
+
changed << [full, 'removed', nil, hsh[:sha]]
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end if t2
|
529
|
+
|
530
|
+
changed
|
531
|
+
end
|
532
532
|
|
533
533
|
# returns true if the files in path_limiter were changed, or no path limiter
|
534
534
|
# used by the log() function when passed with a path_limiter
|
@@ -551,9 +551,9 @@ module Grit
|
|
551
551
|
|
552
552
|
if path && !(path == '' || path == '.' || path == './')
|
553
553
|
paths = path.split('/')
|
554
|
-
paths.each do |
|
554
|
+
paths.each do |pathname|
|
555
555
|
tree = get_object_by_sha1(tree_sha)
|
556
|
-
if entry = tree.entry.select { |e| e.name ==
|
556
|
+
if entry = tree.entry.select { |e| e.name == pathname }.first
|
557
557
|
tree_sha = entry.sha1 rescue nil
|
558
558
|
else
|
559
559
|
return false
|
@@ -720,9 +720,9 @@ module Grit
|
|
720
720
|
end
|
721
721
|
end
|
722
722
|
|
723
|
-
def load_alternate_loose(
|
723
|
+
def load_alternate_loose(pathname)
|
724
724
|
# load alternate loose, too
|
725
|
-
each_alternate_path
|
725
|
+
each_alternate_path pathname do |path|
|
726
726
|
next if @loaded.include?(path)
|
727
727
|
next if !File.exist?(path)
|
728
728
|
load_loose(path)
|
@@ -745,8 +745,8 @@ module Grit
|
|
745
745
|
@packs
|
746
746
|
end
|
747
747
|
|
748
|
-
def load_alternate_packs(
|
749
|
-
each_alternate_path
|
748
|
+
def load_alternate_packs(pathname)
|
749
|
+
each_alternate_path pathname do |path|
|
750
750
|
full_pack = File.join(path, 'pack')
|
751
751
|
next if @loaded_packs.include?(full_pack)
|
752
752
|
load_packs(full_pack)
|