akabei 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.travis.yml +10 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +55 -0
- data/Rakefile +14 -0
- data/akabei.gemspec +29 -0
- data/bin/akabei +9 -0
- data/lib/akabei.rb +5 -0
- data/lib/akabei/abs.rb +60 -0
- data/lib/akabei/archive_utils.rb +75 -0
- data/lib/akabei/attr_path.rb +20 -0
- data/lib/akabei/builder.rb +108 -0
- data/lib/akabei/chroot_tree.rb +81 -0
- data/lib/akabei/cli.rb +172 -0
- data/lib/akabei/error.rb +4 -0
- data/lib/akabei/package.rb +174 -0
- data/lib/akabei/package_entry.rb +110 -0
- data/lib/akabei/package_info.rb +68 -0
- data/lib/akabei/repository.rb +156 -0
- data/lib/akabei/signer.rb +75 -0
- data/lib/akabei/thor_handler.rb +14 -0
- data/lib/akabei/version.rb +3 -0
- data/spec/akabei/abs_spec.rb +95 -0
- data/spec/akabei/archive_utils_spec.rb +44 -0
- data/spec/akabei/builder_spec.rb +129 -0
- data/spec/akabei/chroot_tree_spec.rb +108 -0
- data/spec/akabei/cli_spec.rb +5 -0
- data/spec/akabei/package_entry_spec.rb +70 -0
- data/spec/akabei/package_info_spec.rb +17 -0
- data/spec/akabei/package_spec.rb +54 -0
- data/spec/akabei/repository_spec.rb +157 -0
- data/spec/akabei/signer_spec.rb +5 -0
- data/spec/data/input/abs.tar.gz +0 -0
- data/spec/data/input/htop-vi.tar.gz +0 -0
- data/spec/data/input/makepkg.x86_64.conf +140 -0
- data/spec/data/input/nkf-2.1.3-1-x86_64.pkg.tar.xz +0 -0
- data/spec/data/input/nkf.PKGINFO +22 -0
- data/spec/data/input/nkf.tar.gz +0 -0
- data/spec/data/input/pacman.x86_64.conf +99 -0
- data/spec/data/input/ruby.PKGINFO +38 -0
- data/spec/data/input/test.db +0 -0
- data/spec/data/input/test.files +0 -0
- data/spec/integration/build_spec.rb +105 -0
- data/spec/spec_helper.rb +110 -0
- metadata +225 -0
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'akabei/builder'
|
3
|
+
require 'akabei/signer'
|
4
|
+
|
5
|
+
describe Akabei::Builder do
|
6
|
+
let(:builder) { described_class.new }
|
7
|
+
let(:pkgdest) { test_dest('packages').tap(&:mkpath) }
|
8
|
+
let(:package_dir) { test_dest('nkf').tap(&:mkpath) }
|
9
|
+
let(:pkgname) { 'nkf-2.1.3-1' }
|
10
|
+
let(:arch) { 'x86_64' }
|
11
|
+
let(:src_fname) { 'nkf-2.1.3.tar.gz' }
|
12
|
+
let(:pkg_fname) { "#{pkgname}-#{arch}.pkg.tar.xz" }
|
13
|
+
let(:log_build_fname) { "#{pkgname}-#{arch}-build.log" }
|
14
|
+
let(:log_package_fname) { "#{pkgname}-#{arch}-package.log" }
|
15
|
+
let(:srcpkg_fname) { "#{pkgname}.src.tar.gz" }
|
16
|
+
|
17
|
+
before do
|
18
|
+
builder.pkgdest = pkgdest
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '#build_package' do
|
22
|
+
let(:chroot) { double('ChrootTree') }
|
23
|
+
|
24
|
+
before do
|
25
|
+
expect(chroot).to receive(:makechrootpkg).once.with(package_dir.to_s, anything) { |dir, env|
|
26
|
+
expect(env[:SRCDEST]).to be_directory
|
27
|
+
expect(env[:PKGDEST]).to be_directory
|
28
|
+
expect(env[:LOGDEST]).to be_directory
|
29
|
+
|
30
|
+
env[:PKGDEST].join(pkg_fname).open('w') {}
|
31
|
+
env[:SRCDEST].join(src_fname).open('w') {}
|
32
|
+
env[:LOGDEST].join(log_build_fname).open('w') {}
|
33
|
+
env[:LOGDEST].join(log_package_fname).open('w') {}
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'executes makechrootpkg' do
|
38
|
+
packages = builder.build_package(package_dir, chroot)
|
39
|
+
expect(packages.size).to eq(1)
|
40
|
+
package = packages.first
|
41
|
+
expect(package.path).to eq(pkgdest.join(pkg_fname))
|
42
|
+
expect(package.path).to be_readable
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'with signer' do
|
46
|
+
let(:signer) { double('Signer') }
|
47
|
+
|
48
|
+
before do
|
49
|
+
builder.signer = signer
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'creates a detached signature' do
|
53
|
+
expect(signer).to receive(:detach_sign).once { |path|
|
54
|
+
File.open("#{path}.sig", 'w') {}
|
55
|
+
}
|
56
|
+
|
57
|
+
packages = builder.build_package(package_dir, chroot)
|
58
|
+
expect(packages.size).to eq(1)
|
59
|
+
package = packages.first
|
60
|
+
expect(pkgdest.join("#{pkg_fname}.sig")).to be_readable
|
61
|
+
end
|
62
|
+
|
63
|
+
it "doesn't leave packages if signing failed" do
|
64
|
+
expect(signer).to receive(:detach_sign).once.and_raise(Akabei::Signer::InvalidSignature.new(double('path'), double('from')))
|
65
|
+
|
66
|
+
expect { builder.build_package(package_dir, chroot) }.to raise_error(Akabei::Signer::InvalidSignature)
|
67
|
+
expect(pkgdest.join(pkg_fname)).to_not be_readable
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'with srcdest' do
|
72
|
+
let(:dest) { test_dest('sources').tap(&:mkpath) }
|
73
|
+
|
74
|
+
before do
|
75
|
+
builder.srcdest = dest
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'stores sources' do
|
79
|
+
builder.build_package(package_dir, chroot)
|
80
|
+
expect(dest.join(src_fname)).to be_readable
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context 'with logdest' do
|
85
|
+
let(:dest) { test_dest('logs').tap(&:mkpath) }
|
86
|
+
|
87
|
+
before do
|
88
|
+
builder.logdest = dest
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'stores logs' do
|
92
|
+
builder.build_package(package_dir, chroot)
|
93
|
+
expect(dest.join(log_build_fname)).to be_readable
|
94
|
+
expect(dest.join(log_package_fname)).to be_readable
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#with_source_package' do
|
100
|
+
before do
|
101
|
+
expect(builder).to receive(:system).once.with(any_args) { |env, makepkg, source, opts|
|
102
|
+
srcdest = Pathname.new(env['SRCDEST'])
|
103
|
+
srcpkgdest = Pathname.new(env['SRCPKGDEST'])
|
104
|
+
builddir = Pathname.new(env['BUILDDIR'])
|
105
|
+
expect(srcdest).to be_directory
|
106
|
+
expect(srcpkgdest).to be_directory
|
107
|
+
expect(builddir).to be_directory
|
108
|
+
|
109
|
+
expect(makepkg).to eq('makepkg')
|
110
|
+
expect(source).to eq('--source')
|
111
|
+
expect(opts[:chdir]).to eq(package_dir)
|
112
|
+
|
113
|
+
# Simulate `makepkg --source`
|
114
|
+
srcdest.join(src_fname).open('w') {}
|
115
|
+
srcpkgdest.join(srcpkg_fname).open('w') { |f| f.write('AKABEI SPEC') }
|
116
|
+
builddir.join('nkf').mkpath
|
117
|
+
Pathname.new(opts[:chdir]).join(srcpkg_fname).make_symlink(srcpkgdest.join(srcpkg_fname))
|
118
|
+
true
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'creates only source package' do
|
123
|
+
builder.with_source_package(package_dir) do |srcpkg|
|
124
|
+
expect(srcpkg).to be_readable
|
125
|
+
expect(srcpkg.read).to eq('AKABEI SPEC')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'akabei/chroot_tree'
|
3
|
+
|
4
|
+
describe Akabei::ChrootTree do
|
5
|
+
let(:arch) { 'x86_64' }
|
6
|
+
let(:chroot_root) { Pathname.new('/tmp') }
|
7
|
+
let(:chroot) { described_class.new(chroot_root, arch) }
|
8
|
+
|
9
|
+
describe '#with_chroot' do
|
10
|
+
let(:action) { double('some action') }
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(chroot).to receive(:execute) { nil }
|
14
|
+
expect(action).to receive(:call).once
|
15
|
+
end
|
16
|
+
|
17
|
+
context 'without root' do
|
18
|
+
let(:chroot_root) { nil }
|
19
|
+
|
20
|
+
it 'creates a temporary chroot' do
|
21
|
+
expect(chroot).to receive(:mkarchroot).once
|
22
|
+
expect(Dir).to receive(:mktmpdir).once.and_call_original
|
23
|
+
|
24
|
+
chroot.with_chroot { action.call }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with root' do
|
29
|
+
it 'uses given root' do
|
30
|
+
expect(Dir).to_not receive(:mktmpdir)
|
31
|
+
expect(chroot).to receive(:execute).once.with(any_args) { |*args|
|
32
|
+
expect(args[0]).to eq('mkarchroot')
|
33
|
+
expect(args[1]).to eq(chroot_root.join('root').to_s)
|
34
|
+
}
|
35
|
+
|
36
|
+
chroot.with_chroot { action.call }
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'respects makepkg_config' do
|
41
|
+
path = '/path/to/makepkg.conf'
|
42
|
+
chroot.makepkg_config = path
|
43
|
+
expect(chroot).to receive(:execute).once.with(any_args) { |*args|
|
44
|
+
expect(args[0]).to eq('mkarchroot')
|
45
|
+
expect(args.each_cons(2)).to include(['-M', path])
|
46
|
+
}
|
47
|
+
|
48
|
+
chroot.with_chroot { action.call }
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'respects pacman_config' do
|
52
|
+
path = '/path/to/pacman.conf'
|
53
|
+
chroot.pacman_config = path
|
54
|
+
expect(chroot).to receive(:execute).once.with(any_args) { |*args|
|
55
|
+
expect(args[0]).to eq('mkarchroot')
|
56
|
+
expect(args.each_cons(2)).to include(['-C', path])
|
57
|
+
}
|
58
|
+
|
59
|
+
chroot.with_chroot { action.call }
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe '#execute' do
|
64
|
+
let(:command) { %w[rm -rf /] }
|
65
|
+
let(:opts) { { chdir: '/' } }
|
66
|
+
|
67
|
+
it 'calls sudo and setarch' do
|
68
|
+
expect(chroot).to receive(:system).once.with(any_args) { |*args|
|
69
|
+
expect(args).to eq(%W[sudo setarch #{arch}] + command + [opts])
|
70
|
+
}
|
71
|
+
|
72
|
+
stdout = capture_stdout do
|
73
|
+
chroot.execute(*command + [opts])
|
74
|
+
end
|
75
|
+
expect(stdout).to include('rm -rf /')
|
76
|
+
end
|
77
|
+
|
78
|
+
context 'with :env keyword' do
|
79
|
+
let(:key) { :FOO }
|
80
|
+
let(:value) { 'BAR' }
|
81
|
+
|
82
|
+
it 'calls sudo, setarch and env' do
|
83
|
+
expect(chroot).to receive(:system).once.with(any_args) { |*args|
|
84
|
+
expected_opts = opts.dup
|
85
|
+
expected_opts.delete(:env)
|
86
|
+
expect(args).to eq(%W[sudo setarch #{arch} env #{key}=#{value}] + command + [expected_opts])
|
87
|
+
}.and_return(true)
|
88
|
+
|
89
|
+
opts.merge!(env: { key => value })
|
90
|
+
stdout = capture_stdout do
|
91
|
+
chroot.execute(*command, opts)
|
92
|
+
end
|
93
|
+
expect(stdout).to include('rm -rf /')
|
94
|
+
expect(opts).to have_key(:env)
|
95
|
+
end
|
96
|
+
|
97
|
+
context 'with command failure' do
|
98
|
+
before do
|
99
|
+
allow(chroot).to receive(:system).and_return(false)
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'raises an error' do
|
103
|
+
expect { capture_stdout { chroot.execute(command + [opts]) } }.to raise_error(Akabei::ChrootTree::CommandFailed)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'akabei/package_entry'
|
3
|
+
|
4
|
+
describe Akabei::PackageEntry do
|
5
|
+
let(:entry) { described_class.new }
|
6
|
+
|
7
|
+
describe '#write_desc' do
|
8
|
+
it 'writes desc attributes' do
|
9
|
+
entry.add('name', 'akabei')
|
10
|
+
entry.add('desc', 'Custom repository manager for ArchLinux pacman')
|
11
|
+
entry.add('depends', 'ruby')
|
12
|
+
|
13
|
+
io = StringIO.new
|
14
|
+
entry.write_desc(io)
|
15
|
+
expect(io.string).to include('akabei')
|
16
|
+
expect(io.string).to include('pacman')
|
17
|
+
expect(io.string).to_not include('ruby')
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'rejects multiple descs' do
|
21
|
+
entry.add('desc', 'Custom repository manager for ArchLinux pacman')
|
22
|
+
expect { entry.add('desc', 'Awful repository manager') }.to raise_error(Akabei::Error)
|
23
|
+
expect(entry.desc).not_to include('Awful')
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'rejects unknown attribute' do
|
27
|
+
expect { entry.add('akabei', 'akabei') }.to raise_error(Akabei::Error)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#write_depends' do
|
32
|
+
it 'writes depends attributes' do
|
33
|
+
entry.add('name', 'akabei')
|
34
|
+
entry.add('depends', 'ruby')
|
35
|
+
entry.add('makedepends', 'gcc')
|
36
|
+
entry.add('makedepends', 'rubygems')
|
37
|
+
|
38
|
+
io = StringIO.new
|
39
|
+
entry.write_depends(io)
|
40
|
+
expect(io.string).not_to include('akabei')
|
41
|
+
expect(io.string).to include('ruby')
|
42
|
+
expect(io.string).to include('gcc')
|
43
|
+
expect(io.string).to include('rubygems')
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe '#write_files' do
|
48
|
+
it 'writes files attribute' do
|
49
|
+
entry.add('name', 'gcc')
|
50
|
+
entry.add('files', '/usr/bin/gcov')
|
51
|
+
entry.add('files', '/usr/bin/g++')
|
52
|
+
|
53
|
+
io = StringIO.new
|
54
|
+
entry.write_files(io)
|
55
|
+
expect(io.string).to_not include('gcc')
|
56
|
+
expect(io.string).to include('gcov')
|
57
|
+
expect(io.string).to include('g++')
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'warns if files is empty' do
|
61
|
+
entry.add('name', 'gcc')
|
62
|
+
entry.add('depends', 'glibc')
|
63
|
+
|
64
|
+
io = StringIO.new
|
65
|
+
stderr = capture_stderr { entry.write_files(io) }
|
66
|
+
expect(io.string).to be_empty
|
67
|
+
expect(stderr).to include('empty')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'akabei/package'
|
3
|
+
|
4
|
+
describe Akabei::PackageInfo do
|
5
|
+
describe '.parse' do
|
6
|
+
it 'parses .PKGINFO' do
|
7
|
+
pkginfo = described_class.parse(test_input('ruby.PKGINFO').read)
|
8
|
+
expect(pkginfo.pkgver).to eq('2.1.0-2')
|
9
|
+
expect(pkginfo.pkgbase).to eq('ruby')
|
10
|
+
expect(pkginfo.provides).to match_array(%w[rake rubygems])
|
11
|
+
expect(pkginfo.group).to eq([])
|
12
|
+
|
13
|
+
pkginfo = described_class.parse(test_input('nkf.PKGINFO').read)
|
14
|
+
expect(pkginfo.pkgbase).to be_nil
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'akabei/package'
|
3
|
+
|
4
|
+
describe Akabei::Package do
|
5
|
+
let(:package) { described_class.new(pkg_path) }
|
6
|
+
let(:pkg_path) { test_input('nkf-2.1.3-1-x86_64.pkg.tar.xz') }
|
7
|
+
|
8
|
+
describe '#pkginfo' do
|
9
|
+
it 'returns PackageInfo' do
|
10
|
+
pkginfo = package.pkginfo
|
11
|
+
expect(package.db_name).to eq('nkf-2.1.3-1')
|
12
|
+
end
|
13
|
+
|
14
|
+
context "when pkg_path doesn't exist" do
|
15
|
+
let(:pkg_path) { test_dest('does_not_exist.pkg.tar.xz') }
|
16
|
+
|
17
|
+
it 'raises an error' do
|
18
|
+
expect { package.pkginfo }.to raise_error(Archive::Error)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'with invalid archive' do
|
23
|
+
let(:pkg_path) { test_input('nkf.tar.gz') }
|
24
|
+
|
25
|
+
it 'raises an error' do
|
26
|
+
expect { package.pkginfo }.to raise_error(Akabei::Error)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe '#to_entry' do
|
32
|
+
it 'returns PackageEntry' do
|
33
|
+
entry = package.to_entry
|
34
|
+
expect(entry.sha256sum).to eq('8543fc47ce33a24bc6c0670b045f4b0381dff1472df895879e9a2cf86835a57b')
|
35
|
+
expect(entry.pgpsig).to be_nil
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with detached signature file' do
|
39
|
+
let(:pkg_path) { test_dest('nkf.pkg.tar.xz') }
|
40
|
+
let(:signature) { 'SOME SIGNATURE' }
|
41
|
+
|
42
|
+
before do
|
43
|
+
FileUtils.cp(test_input('nkf-2.1.3-1-x86_64.pkg.tar.xz'), pkg_path)
|
44
|
+
File.open("#{pkg_path}.sig", 'w') { |f| f.write(signature) }
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'returns PackageEntry with pgpsig' do
|
48
|
+
entry = package.to_entry
|
49
|
+
expect(entry.sha256sum).to eq('8543fc47ce33a24bc6c0670b045f4b0381dff1472df895879e9a2cf86835a57b')
|
50
|
+
expect(entry.pgpsig).to eq(Base64.strict_encode64(signature))
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,157 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'akabei/repository'
|
3
|
+
require 'akabei/signer'
|
4
|
+
|
5
|
+
describe Akabei::Repository do
|
6
|
+
let(:repo) { described_class.new }
|
7
|
+
let(:db_path) { test_input('test.db') }
|
8
|
+
|
9
|
+
describe '#load' do
|
10
|
+
context 'without database' do
|
11
|
+
let(:db_path) { test_dest('repo.db') }
|
12
|
+
|
13
|
+
it 'does nothing' do
|
14
|
+
repo.load(db_path)
|
15
|
+
expect(repo.count).to eq(0)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'with valid database' do
|
20
|
+
it 'loads package entries' do
|
21
|
+
repo.load(db_path)
|
22
|
+
entry = repo['htop-vi']
|
23
|
+
expect(entry).to_not be_nil
|
24
|
+
expect(entry.files).to be_empty
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
context 'with invalid database' do
|
29
|
+
let(:db_path) { test_input('abs.tar.gz') }
|
30
|
+
|
31
|
+
it 'raises an error' do
|
32
|
+
expect { repo.load(db_path) }.to raise_error(Akabei::Error)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with signer' do
|
37
|
+
let(:signer) { double('Signer') }
|
38
|
+
let(:db_path) { test_dest('test.db') }
|
39
|
+
let(:sig_path) { test_dest("test.db.sig") }
|
40
|
+
|
41
|
+
before do
|
42
|
+
repo.signer = signer
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'skips verification if signature is absent' do
|
46
|
+
expect { repo.load(db_path) }.to_not raise_error
|
47
|
+
end
|
48
|
+
|
49
|
+
context 'with signature' do
|
50
|
+
before do
|
51
|
+
FileUtils.cp(test_input('test.db'), db_path)
|
52
|
+
sig_path.open('w') {}
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'loads package entries if the signature is valid' do
|
56
|
+
expect(signer).to receive(:verify!).with(db_path)
|
57
|
+
repo.load(db_path)
|
58
|
+
expect(repo['htop-vi']).not_to be_nil
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'raises an error if the signature is invalid' do
|
62
|
+
expect(signer).to receive(:verify!).with(db_path).and_raise(Akabei::Signer::InvalidSignature.new(double('path'), double('from')))
|
63
|
+
expect { repo.load(db_path) }.to raise_error(Akabei::Signer::InvalidSignature)
|
64
|
+
expect(repo.count).to eq(0)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
context 'with files' do
|
70
|
+
let(:db_path) { test_input('test.files') }
|
71
|
+
|
72
|
+
it 'loads package entries with files' do
|
73
|
+
repo.load(db_path)
|
74
|
+
entry = repo['htop-vi']
|
75
|
+
expect(entry.files).to_not be_empty
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
describe '#add' do
|
81
|
+
it 'adds an entry' do
|
82
|
+
package = double('package')
|
83
|
+
entry = double('entry')
|
84
|
+
allow(package).to receive(:db_name).and_return('nkf-2.1.3-1')
|
85
|
+
expect(package).to receive(:to_entry).and_return(entry)
|
86
|
+
allow(entry).to receive(:name).and_return('nkf')
|
87
|
+
|
88
|
+
repo.add(package)
|
89
|
+
expect(repo['nkf']).to eql(entry)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#remove' do
|
94
|
+
before do
|
95
|
+
repo.load(db_path)
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'with entry present' do
|
99
|
+
it 'removes the package entry' do
|
100
|
+
expect { repo.remove('htop-vi') }.to change { repo.count }.by(-1)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
context 'with package absent' do
|
105
|
+
it 'does nothing' do
|
106
|
+
expect { repo.remove('nkf') }.not_to change { repo.count }
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe '#save' do
|
112
|
+
let(:dest_path) { test_dest('test.db') }
|
113
|
+
|
114
|
+
before do
|
115
|
+
repo.load(db_path)
|
116
|
+
end
|
117
|
+
|
118
|
+
it 'stores repository database' do
|
119
|
+
repo.save(dest_path)
|
120
|
+
expect(dest_path).to be_readable
|
121
|
+
new_repo = described_class.load(dest_path)
|
122
|
+
expect(repo).to eq(new_repo)
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'with signer' do
|
126
|
+
let(:signer) { double('Signer') }
|
127
|
+
|
128
|
+
before do
|
129
|
+
repo.signer = signer
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'stores repository database and sign it' do
|
133
|
+
expect(signer).to receive(:detach_sign).once.with(dest_path) { |path|
|
134
|
+
File.open("#{path}.sig", 'w') {}
|
135
|
+
}
|
136
|
+
|
137
|
+
repo.save(dest_path)
|
138
|
+
expect(Pathname.new("#{dest_path}.sig")).to be_readable
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context 'with include_files' do
|
143
|
+
let(:db_path) { test_input('test.files') }
|
144
|
+
|
145
|
+
before do
|
146
|
+
repo.include_files = true
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'stores repository database' do
|
150
|
+
repo.save(dest_path)
|
151
|
+
new_repo = described_class.load(dest_path)
|
152
|
+
new_repo.include_files = true
|
153
|
+
expect(repo).to eq(new_repo)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|