akabei 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|