dply 0.2.19 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.rspec +4 -0
- data/Rakefile +0 -14
- data/TODO +0 -1
- data/code_dump/old_remote_task.rb +2 -0
- data/{dev_bin → dev_exe}/dplyr +0 -0
- data/{dev_bin → dev_exe}/drake +1 -1
- data/dply.gemspec +2 -2
- data/{bin → exe}/dplyr +0 -0
- data/{bin → exe}/drake +12 -14
- data/lib/dply/TEST_TODO +50 -0
- data/lib/dply/app_config.rb +108 -0
- data/lib/dply/base_config.rb +110 -0
- data/lib/dply/build.rb +17 -11
- data/lib/dply/build_config.rb +28 -96
- data/lib/dply/bundle.rb +7 -30
- data/lib/dply/cli/build.rb +5 -12
- data/lib/dply/cli/ctl.rb +7 -8
- data/lib/dply/cli/deploy.rb +6 -10
- data/lib/dply/cli/devbuild.rb +6 -10
- data/lib/dply/cli/install_pkgs.rb +2 -3
- data/lib/dply/cli/run.rb +27 -0
- data/lib/dply/cli/status.rb +1 -2
- data/lib/dply/cli/task.rb +6 -12
- data/lib/dply/code_archive.rb +123 -0
- data/lib/dply/command.rb +57 -0
- data/lib/dply/config_downloader.rb +3 -2
- data/lib/dply/curl.rb +1 -5
- data/lib/dply/custom_logger.rb +18 -1
- data/lib/dply/deplist.rb +16 -48
- data/lib/dply/deploy_config.rb +34 -0
- data/lib/dply/elf.rb +60 -0
- data/lib/dply/env.rb +9 -0
- data/lib/dply/git.rb +15 -8
- data/lib/dply/helper.rb +21 -33
- data/lib/dply/linker.rb +27 -27
- data/lib/dply/lock.rb +2 -9
- data/lib/dply/logger.rb +1 -1
- data/lib/dply/pkgs.rb +9 -11
- data/lib/dply/release.rb +2 -2
- data/lib/dply/{archive.rb → remote_archive.rb} +1 -1
- data/lib/dply/repo.rb +3 -3
- data/lib/dply/rpm.rb +12 -20
- data/lib/dply/scripts/depcheck.rb +4 -0
- data/lib/dply/shared_dirs.rb +1 -1
- data/lib/dply/strategy/archive.rb +15 -22
- data/lib/dply/strategy/base.rb +82 -0
- data/lib/dply/strategy/git.rb +18 -19
- data/lib/dply/task_dsl.rb +101 -0
- data/lib/dply/util.rb +75 -0
- data/lib/dply/venv.rb +53 -0
- data/lib/dply/version.rb +1 -1
- data/lib/dply/yum.rb +21 -31
- data/lib/dplyr/consul.rb +1 -1
- data/spec/dply/base_config_spec.rb +178 -0
- data/spec/dply/bundle_spec.rb +100 -0
- data/spec/dply/command_spec.rb +190 -0
- data/spec/dply/curl_spec.rb +41 -0
- data/spec/dply/deplist_spec.rb +48 -0
- data/spec/dply/elf_spec.rb +64 -0
- data/spec/dply/env_spec.rb +57 -0
- data/spec/dply/git_spec.rb +136 -0
- data/spec/dply/helper_spec.rb +168 -0
- data/spec/dply/linker_spec.rb +81 -0
- data/spec/dply/lock_spec.rb +24 -0
- data/spec/dply/pkgs_spec.rb +105 -0
- data/spec/dply/repo_spec.rb +58 -0
- data/spec/dply/rpm_spec.rb +32 -0
- data/spec/dply/yum_spec.rb +29 -0
- data/spec/integration/archive_flow_spec.rb +87 -0
- data/spec/integration/git_flow_spec.rb +63 -0
- data/spec/repo.rb +27 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/test_data/build.tar.gz +0 -0
- data/spec/test_data/build.tar.gz.md5 +1 -0
- data/spec/test_data/bundle/gems_installed/Gemfile +1 -0
- data/spec/test_data/bundle/gems_not_installed/Gemfile +2 -0
- data/spec/test_data/bundle/no_gemfile/.gitkeep +0 -0
- data/spec/test_data/command/test.rb +7 -0
- data/spec/test_data/elf/elf +0 -0
- data/spec/test_data/elf/libpgtypes.so.3 +0 -0
- data/spec/test_data/elf/not_elf +1 -0
- data/spec/test_data/sample_repo/.dply.lock +0 -0
- data/spec/test_data/sample_repo/Gemfile +2 -0
- data/spec/test_data/sample_repo/Rakefile +3 -0
- data/spec/test_data/sample_repo/app.rb +1 -0
- data/spec/test_data/sample_repo/dply/app.rb +33 -0
- data/spec/test_data/sample_repo/lib/libacl.so.1 +0 -0
- data/spec/test_data/sample_repo/pkgs.yml +2 -0
- data/spec/webserver.rb +21 -0
- metadata +96 -28
- data/lib/dply/cli/app_task.rb +0 -38
- data/lib/dply/config.rb +0 -120
- data/lib/dply/config_struct.rb +0 -52
- data/lib/dply/rakelib/drake.rake +0 -33
- data/lib/dply/tasks.rb +0 -136
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'dply/curl'
|
2
|
+
|
3
|
+
module Dply
|
4
|
+
describe Curl do
|
5
|
+
|
6
|
+
let(:url) { "http://127.0.0.1:8000/build.tar.gz" }
|
7
|
+
|
8
|
+
describe "#download(url, file)" do
|
9
|
+
it "downloads the url to file" do
|
10
|
+
Dir.mktmpdir do |dir|
|
11
|
+
f = "#{dir}/f"
|
12
|
+
curl = Curl.new
|
13
|
+
expect(Logger.logger).to receive(:bullet).with("downloading #{url}")
|
14
|
+
curl.download(url, f)
|
15
|
+
expect(File).to exist(f)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "raises error when url doesn't exist" do
|
20
|
+
url = "http://127.0.0.1:8000/build"
|
21
|
+
Dir.mktmpdir do |dir|
|
22
|
+
f = "#{dir}/f"
|
23
|
+
curl = Curl.new
|
24
|
+
expect(Logger.logger).to receive(:bullet).with("downloading #{url}")
|
25
|
+
expect { curl.download(url, f) }.to raise_error(Error)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "logs message to debug when quiet: true" do
|
30
|
+
Dir.mktmpdir do |dir|
|
31
|
+
f = "#{dir}/f"
|
32
|
+
curl = Curl.new(quiet: true)
|
33
|
+
expect(Logger.logger).to receive(:debug).with("downloading #{url}")
|
34
|
+
curl.download(url, f)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
|
@@ -0,0 +1,48 @@
|
|
1
|
+
silence_warnings do
|
2
|
+
require 'dply/deplist'
|
3
|
+
end
|
4
|
+
|
5
|
+
module Dply
|
6
|
+
describe Deplist do
|
7
|
+
|
8
|
+
before :all do
|
9
|
+
@work_dir = "tmp/deplist"
|
10
|
+
FileUtils.rm_rf @work_dir
|
11
|
+
FileUtils.mkdir_p @work_dir
|
12
|
+
end
|
13
|
+
|
14
|
+
def tmp_dir(&block)
|
15
|
+
d = Dir.mktmpdir nil, "#{Dir.pwd}/#{@work_dir}"
|
16
|
+
FileUtils.cp "spec/test_data/sample_repo/lib/libacl.so.1", "#{d}/libacl.so.1"
|
17
|
+
Dir.chdir(d) { yield d }
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#verify!" do
|
21
|
+
|
22
|
+
it "doesn't throw an error when pkgs.yml has the required pkgs" do
|
23
|
+
pkgs_data = { "pkgs" => ["libattr"], "build_pkgs" => [] }
|
24
|
+
tmp_dir do
|
25
|
+
File.write "pkgs.yml", YAML.dump(pkgs_data)
|
26
|
+
system! "tar czf test.tar.gz pkgs.yml libacl.so.1"
|
27
|
+
deplist = Deplist.new("test.tar.gz")
|
28
|
+
silence_warnings do
|
29
|
+
expect { deplist.verify! }.to output(/all dependencies satisfied/).to_stdout_from_any_process
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "throws an error when pkgs.yml doesn't have the required pkgs" do
|
35
|
+
pkgs_data = { "pkgs" => [], "build_pkgs" => [] }
|
36
|
+
tmp_dir do
|
37
|
+
File.write "pkgs.yml", YAML.dump(pkgs_data)
|
38
|
+
system! "tar czf test.tar.gz pkgs.yml libacl.so.1"
|
39
|
+
deplist = Deplist.new("test.tar.gz")
|
40
|
+
silence_warnings do
|
41
|
+
expect { deplist.verify! }.to raise_error(Error).and output(/any of \["libattr"\]/).to_stdout_from_any_process
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
silence_warnings do
|
2
|
+
require 'elf'
|
3
|
+
end
|
4
|
+
require 'dply/elf'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
module Dply
|
8
|
+
describe Elf do
|
9
|
+
|
10
|
+
before :all do
|
11
|
+
@verbose = $VERBOSE
|
12
|
+
$VERBOSE = false
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:work_dir) { Pathname.new("#{__dir__}/../test_data/elf").realpath }
|
16
|
+
|
17
|
+
def map_64bit(list)
|
18
|
+
list.map { |i| "#{i}()(64bit)" }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe ".elf?" do
|
22
|
+
it "returns true if file is an ELF" do
|
23
|
+
expect(Elf.elf? "#{work_dir}/elf").to eq(true)
|
24
|
+
end
|
25
|
+
|
26
|
+
it "returns false if file is not an ELF" do
|
27
|
+
expect(Elf.elf? "#{work_dir}/not_elf").to eq(false)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "returns false if file doesn't exist" do
|
31
|
+
expect(Elf.elf? "#{work_dir}/nofile").to eq(false)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#external_libs" do
|
36
|
+
it "returns a list of external libs when elf has no rpath section" do
|
37
|
+
libs = map_64bit ["libattr.so.1", "libc.so.6"]
|
38
|
+
elf = Elf.new("#{work_dir}/elf")
|
39
|
+
expect(elf.external_libs).to match_array(libs)
|
40
|
+
end
|
41
|
+
|
42
|
+
context "when elf has absolute rpath or runpath" do
|
43
|
+
it "returns all external libs ignoring rpath" do
|
44
|
+
libs = map_64bit ["libpq.so.5", "libc.so.6", "libpgtypes.so.3", "libpthread.so.0"]
|
45
|
+
elf = Elf.new("#{work_dir}/libecpg.so")
|
46
|
+
expect(elf.external_libs).to match_array(libs)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
context "when elf contains a relative rpath or runpath" do
|
51
|
+
it "returns all external libs excluding the ones found in relative rpath" do
|
52
|
+
libs = map_64bit ["libpq.so.5", "libc.so.6", "libpthread.so.0"]
|
53
|
+
elf = Elf.new("#{work_dir}/rpath_libecpg.so")
|
54
|
+
expect(elf.external_libs).to match_array(libs)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
after :all do
|
60
|
+
$VERBOSE = @verbose
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'dply/env'
|
2
|
+
|
3
|
+
module Dply
|
4
|
+
describe Env do
|
5
|
+
|
6
|
+
ORIGINAL_ENV = { "O1" => "1", "O2" => "2" }
|
7
|
+
CURRENT_ENV = { "C1" => "1", "C2" => "2" }
|
8
|
+
EXTRA_ENV = { "O1" => "E", "C1" => "E" }
|
9
|
+
|
10
|
+
def stub_env(with_bundler:)
|
11
|
+
allow(ENV).to receive(:to_h).and_return(CURRENT_ENV)
|
12
|
+
if with_bundler
|
13
|
+
stub_const("Bundler", "bundler")
|
14
|
+
allow(Bundler).to receive(:original_env).and_return(ORIGINAL_ENV)
|
15
|
+
else
|
16
|
+
hide_const("Bundler")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '.build_env (extra_env, bundled_env:)' do
|
21
|
+
context "when bundler is defined and bundled_env: true" do
|
22
|
+
it "merges current_env with extra_env" do
|
23
|
+
stub_env with_bundler: true
|
24
|
+
env = Env.build_env(EXTRA_ENV, bundled_env: true)
|
25
|
+
expect(env).to eq(CURRENT_ENV.merge(EXTRA_ENV))
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when bundler is defined and bundled_env: false" do
|
30
|
+
it "merges original_env with extra_env" do
|
31
|
+
stub_env with_bundler: true
|
32
|
+
env = Env.build_env(EXTRA_ENV, bundled_env: false)
|
33
|
+
expect(env).to eq(ORIGINAL_ENV.merge(EXTRA_ENV))
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "when bundler is not defined and bundled_env: true" do
|
38
|
+
it "merges current_env with extra_env" do
|
39
|
+
stub_env with_bundler: false
|
40
|
+
env = Env.build_env(EXTRA_ENV, bundled_env: true)
|
41
|
+
expect(env).to eq(CURRENT_ENV.merge(EXTRA_ENV))
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "when bundler is defined and bundled_env: false" do
|
46
|
+
it "merges current_env with extra_env" do
|
47
|
+
stub_env with_bundler: false
|
48
|
+
env = Env.build_env(EXTRA_ENV, bundled_env: true)
|
49
|
+
expect(env).to eq(CURRENT_ENV.merge(EXTRA_ENV))
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require 'dply/git'
|
2
|
+
require 'repo'
|
3
|
+
|
4
|
+
module Dply
|
5
|
+
describe Git do
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
@work_dir = "tmp/git"
|
9
|
+
@source_repo = "#{Dir.pwd}/tmp/repo.git"
|
10
|
+
FileUtils.rm_rf @work_dir
|
11
|
+
FileUtils.mkdir_p @work_dir
|
12
|
+
end
|
13
|
+
|
14
|
+
def source_repo
|
15
|
+
@source_repo
|
16
|
+
end
|
17
|
+
|
18
|
+
def tmp_dir(&block)
|
19
|
+
d = Dir.mktmpdir nil, "#{Dir.pwd}/#{@work_dir}"
|
20
|
+
Dir.chdir(d) { yield d }
|
21
|
+
end
|
22
|
+
|
23
|
+
describe ".pull" do
|
24
|
+
it "checks out the given branch and pulls any changes to it from upstream" do
|
25
|
+
tmp_dir do |d|
|
26
|
+
upstream = "#{d}/upstream"
|
27
|
+
system! "git clone #{source_repo} upstream"
|
28
|
+
system! "git clone #{upstream} repo"
|
29
|
+
Dir.chdir "upstream" do
|
30
|
+
system! "git checkout -b new_data"
|
31
|
+
system! "echo 'new_data' > new_data"
|
32
|
+
system! "git add new_data; git commit -m 'commit'"
|
33
|
+
end
|
34
|
+
|
35
|
+
Dir.chdir "repo" do
|
36
|
+
suppress_output { Git.pull "new_data" }
|
37
|
+
expect(`git rev-parse --abbrev-ref HEAD`.chomp).to eq('new_data')
|
38
|
+
expect(File).to exist('new_data')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe ".checkout" do
|
45
|
+
it "checks out the given branch" do
|
46
|
+
upstream = source_repo
|
47
|
+
tmp_dir do
|
48
|
+
system! "git clone #{upstream} repo", quiet: true
|
49
|
+
Dir.chdir "repo" do
|
50
|
+
# local tracking branch doesn't exist
|
51
|
+
suppress_output { Git.checkout "some_branch" }
|
52
|
+
expect(`git rev-parse --abbrev-ref HEAD`.chomp).to eq("some_branch")
|
53
|
+
|
54
|
+
#local tracking branch exists
|
55
|
+
suppress_output { Git.checkout "master" }
|
56
|
+
expect(`git rev-parse --abbrev-ref HEAD`.chomp).to eq("master")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe ".clone" do
|
63
|
+
it "clones the repo from mirror and sets the upstream to original" do
|
64
|
+
mirror = source_repo
|
65
|
+
original = "/some/original/repo.git"
|
66
|
+
tmp_dir do
|
67
|
+
suppress_output { Git.clone original, "repo", mirror: mirror }
|
68
|
+
Dir.chdir "repo" do
|
69
|
+
expect(Git.remote_url).to eq(original)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
it "clones the repo from original source when mirror is not specified" do
|
75
|
+
original = source_repo
|
76
|
+
tmp_dir do
|
77
|
+
suppress_output { Git.clone original, "repo", mirror: nil }
|
78
|
+
Dir.chdir "repo" do
|
79
|
+
expect(Git.remote_url).to eq(original)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe ".clean" do
|
86
|
+
it "cleans any changes made to the working tree (resets HEAD state and removes untracked files)" do
|
87
|
+
upstream = source_repo
|
88
|
+
tmp_dir do
|
89
|
+
system! "git clone #{upstream} repo", quiet: true
|
90
|
+
Dir.chdir "repo" do
|
91
|
+
system! "echo asda > my_new_file" #new
|
92
|
+
system! "echo existing > Gemfile" #existing
|
93
|
+
suppress_output { Git.clean }
|
94
|
+
lines = IO.popen(%w(git status --porcelain)) { |f| f.readlines }
|
95
|
+
expect(lines.size).to eq(0)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe ".tracking_branch" do
|
102
|
+
it "returns the tracking branch for given branch" do
|
103
|
+
upstream = source_repo
|
104
|
+
branch = "some_branch"
|
105
|
+
tmp_dir do
|
106
|
+
system! "git clone #{upstream} repo", quiet: true
|
107
|
+
Dir.chdir "repo" do
|
108
|
+
system! "git checkout -b #{branch} -t origin/#{branch}", quiet: true
|
109
|
+
expect(Git.tracking_branch(branch)).to eq("origin/#{branch}")
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe ".remote_url" do
|
116
|
+
it "returns the url for origin upstream" do
|
117
|
+
upstream = source_repo
|
118
|
+
tmp_dir do |d|
|
119
|
+
system! "git clone #{upstream} repo", quiet: true
|
120
|
+
Dir.chdir("repo") do
|
121
|
+
expect(Git.remote_url).to eq(upstream)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe ".commit_id" do
|
128
|
+
it "returns the commit id" do
|
129
|
+
Dir.chdir source_repo do
|
130
|
+
commit_id = `git rev-parse HEAD`.chomp
|
131
|
+
expect(Git.commit_id).to eq(commit_id)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,168 @@
|
|
1
|
+
require 'dply/helper'
|
2
|
+
require 'pathname'
|
3
|
+
|
4
|
+
module Dply
|
5
|
+
describe Helper do
|
6
|
+
|
7
|
+
before :all do
|
8
|
+
@work_dir = "tmp/helper"
|
9
|
+
FileUtils.rm_rf @work_dir
|
10
|
+
FileUtils.mkdir_p @work_dir
|
11
|
+
end
|
12
|
+
|
13
|
+
klass = Class.new { include Helper }
|
14
|
+
subject { klass.new }
|
15
|
+
|
16
|
+
def tmp_dir(&block)
|
17
|
+
d = Dir.mktmpdir nil, "#{Dir.pwd}/#{@work_dir}"
|
18
|
+
Dir.chdir(d) { yield d }
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#cmd" do
|
22
|
+
command = "touch a"
|
23
|
+
display = :a
|
24
|
+
env = {"a" => "1" }
|
25
|
+
bundled_env = :benv
|
26
|
+
new_env = {"e" => "1"}
|
27
|
+
|
28
|
+
let(:cmd_proc) do
|
29
|
+
Proc.new do |return_output|
|
30
|
+
subject.cmd command, env: env, bundled_env: bundled_env,
|
31
|
+
return_output: return_output, display: display
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "runs the command as expected when return_output: true" do
|
36
|
+
return_output = true
|
37
|
+
cmd_double = double
|
38
|
+
output = "output"
|
39
|
+
expect(Logger.logger).to receive(:command).with(command, mode: display)
|
40
|
+
expect(Env).to receive(:build_env).with(env, bundled_env: bundled_env).and_return(new_env)
|
41
|
+
expect(Command).to receive(:new).with(command, env: new_env, shell: false).and_return(cmd_double)
|
42
|
+
expect(cmd_double).to receive(:capture).and_return(output)
|
43
|
+
out = cmd_proc.call(return_output)
|
44
|
+
expect(out).to eq(output)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "runs the command as expected when return_output: false" do
|
48
|
+
return_output = false
|
49
|
+
cmd_double = double
|
50
|
+
expect(Logger.logger).to receive(:command).with(command, mode: display)
|
51
|
+
expect(Env).to receive(:build_env).with(env, bundled_env: bundled_env).and_return(new_env)
|
52
|
+
expect(Command).to receive(:new).with(command, env: new_env, shell: false).and_return(cmd_double)
|
53
|
+
expect(cmd_double).to receive(:run)
|
54
|
+
cmd_proc.call(return_output)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "#sh" do
|
59
|
+
command = "touch a"
|
60
|
+
display = :a
|
61
|
+
env = {"a" => "1" }
|
62
|
+
bundled_env = :benv
|
63
|
+
new_env = {"e" => "1"}
|
64
|
+
|
65
|
+
let(:sh_proc) do
|
66
|
+
Proc.new do |return_output|
|
67
|
+
subject.sh command, env: env, bundled_env: bundled_env,
|
68
|
+
return_output: return_output, display: display
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "runs the command as expected when return_output: true" do
|
73
|
+
return_output = true
|
74
|
+
sh_double = double
|
75
|
+
output = "output"
|
76
|
+
expect(Logger.logger).to receive(:command).with(command, mode: display)
|
77
|
+
expect(Env).to receive(:build_env).with(env, bundled_env: bundled_env).and_return(new_env)
|
78
|
+
expect(Command).to receive(:new).with(command, env: new_env, shell: true).and_return(sh_double)
|
79
|
+
expect(sh_double).to receive(:capture).and_return(output)
|
80
|
+
out = sh_proc.call(return_output)
|
81
|
+
expect(out).to eq(output)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "runs the command as expected when return_output: false" do
|
85
|
+
return_output = false
|
86
|
+
sh_double = double
|
87
|
+
expect(Logger.logger).to receive(:command).with(command, mode: display)
|
88
|
+
expect(Env).to receive(:build_env).with(env, bundled_env: bundled_env).and_return(new_env)
|
89
|
+
expect(Command).to receive(:new).with(command, env: new_env, shell: true).and_return(sh_double)
|
90
|
+
expect(sh_double).to receive(:run)
|
91
|
+
sh_proc.call(return_output)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "#symlink" do
|
96
|
+
it "creates symlink dst -> src" do
|
97
|
+
tmp_dir do
|
98
|
+
FileUtils.touch "src"
|
99
|
+
subject.symlink "src", "dst"
|
100
|
+
expect(File.realpath("dst")).to eq(File.realpath("src"))
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
it "does nothing if the link exists" do
|
105
|
+
tmp_dir do
|
106
|
+
FileUtils.touch "src"
|
107
|
+
FileUtils.ln_s "src", "dst"
|
108
|
+
expect(FileUtils).not_to receive(:ln_s)
|
109
|
+
subject.symlink "src", "dst"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
it "does not call ln_s when link exists and src/dest are Pathnames" do
|
114
|
+
tmp_dir do
|
115
|
+
FileUtils.touch "src"
|
116
|
+
FileUtils.ln_s "src", "dst"
|
117
|
+
expect(FileUtils).not_to receive(:ln_s)
|
118
|
+
subject.symlink Pathname.new("src"), Pathname.new("dst")
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
it "replaces existing dst -> src(file) link atomically (using move op)" do
|
123
|
+
tmp_dir do
|
124
|
+
FileUtils.touch "src"
|
125
|
+
FileUtils.touch "src1"
|
126
|
+
FileUtils.ln_s "src1", "dst"
|
127
|
+
prev_inode = File.stat("dst").ino
|
128
|
+
|
129
|
+
#atomic rename
|
130
|
+
dir = File.dirname("dst")
|
131
|
+
expect(subject).to receive(:cmd).with(array_including("mv", dir), display: false).and_call_original
|
132
|
+
|
133
|
+
subject.symlink "src", "dst"
|
134
|
+
current_inode = File.stat("dst").ino
|
135
|
+
expect(File.realpath("dst")).to eq(File.realpath("src"))
|
136
|
+
expect(prev_inode).not_to eq(current_inode)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "replaces existing dst -> src(dir) link atomically" do
|
141
|
+
tmp_dir do
|
142
|
+
FileUtils.mkdir "src1"
|
143
|
+
FileUtils.mkdir "src"
|
144
|
+
FileUtils.ln_s "src1", "dst"
|
145
|
+
prev_inode = File.stat("dst").ino
|
146
|
+
|
147
|
+
dir = File.dirname("dst")
|
148
|
+
|
149
|
+
expect(subject).to receive(:cmd).with(array_including("mv", dir), display: false).and_call_original
|
150
|
+
|
151
|
+
subject.symlink "src", "dst"
|
152
|
+
current_inode = File.stat("dst").ino
|
153
|
+
expect(File.realpath("dst")).to eq(File.realpath("src"))
|
154
|
+
expect(prev_inode).not_to eq(current_inode)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
it "raises an error when dst file already exists" do
|
159
|
+
tmp_dir do
|
160
|
+
FileUtils.touch "src"
|
161
|
+
FileUtils.touch "dst"
|
162
|
+
expect { subject.symlink "src", "dst" }.to raise_error(Error)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|