2020-10-10 14:16:11 +02:00
|
|
|
# typed: false
|
2019-04-19 15:38:03 +09:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2017-02-15 02:02:25 +01:00
|
|
|
require "extend/pathname"
|
|
|
|
require "install_renamed"
|
|
|
|
|
|
|
|
describe Pathname do
|
|
|
|
include FileUtils
|
|
|
|
|
2017-02-28 14:50:46 +01:00
|
|
|
let(:src) { mktmpdir }
|
|
|
|
let(:dst) { mktmpdir }
|
2017-02-15 02:02:25 +01:00
|
|
|
let(:file) { src/"foo" }
|
|
|
|
let(:dir) { src/"bar" }
|
|
|
|
|
|
|
|
describe DiskUsageExtension do
|
2018-03-25 13:30:37 +01:00
|
|
|
before do
|
2017-02-15 02:02:25 +01:00
|
|
|
mkdir_p dir/"a-directory"
|
|
|
|
touch [dir/".DS_Store", dir/"a-file"]
|
|
|
|
File.truncate(dir/"a-file", 1_048_576)
|
|
|
|
ln_s dir/"a-file", dir/"a-symlink"
|
|
|
|
ln dir/"a-file", dir/"a-hardlink"
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#file_count" do
|
|
|
|
it "returns the number of files in a directory" do
|
|
|
|
expect(dir.file_count).to eq(3)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#abv" do
|
|
|
|
context "when called on a directory" do
|
|
|
|
it "returns a string with the file count and disk usage" do
|
2017-02-25 11:09:57 +00:00
|
|
|
expect(dir.abv).to eq("3 files, 1MB")
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
context "when called on a file" do
|
|
|
|
it "returns the disk usage" do
|
2017-02-25 11:09:57 +00:00
|
|
|
expect((dir/"a-file").abv).to eq("1MB")
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#rmdir_if_possible" do
|
2018-03-25 13:30:37 +01:00
|
|
|
before { mkdir_p dir }
|
2017-02-15 02:02:25 +01:00
|
|
|
|
|
|
|
it "returns true and removes a directory if it doesn't contain files" do
|
|
|
|
expect(dir.rmdir_if_possible).to be true
|
|
|
|
expect(dir).not_to exist
|
|
|
|
end
|
|
|
|
|
|
|
|
it "returns false and doesn't delete a directory if it contains files" do
|
|
|
|
touch dir/"foo"
|
|
|
|
expect(dir.rmdir_if_possible).to be false
|
|
|
|
expect(dir).to be_a_directory
|
|
|
|
end
|
|
|
|
|
|
|
|
it "ignores .DS_Store files" do
|
|
|
|
touch dir/".DS_Store"
|
|
|
|
expect(dir.rmdir_if_possible).to be true
|
|
|
|
expect(dir).not_to exist
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#append_lines" do
|
|
|
|
it "appends lines to a file" do
|
|
|
|
touch file
|
|
|
|
|
|
|
|
file.append_lines("CONTENT")
|
2017-10-15 02:28:32 +02:00
|
|
|
expect(File.read(file)).to eq <<~EOS
|
2017-02-15 02:02:25 +01:00
|
|
|
CONTENT
|
|
|
|
EOS
|
|
|
|
|
|
|
|
file.append_lines("CONTENTS")
|
2017-10-15 02:28:32 +02:00
|
|
|
expect(File.read(file)).to eq <<~EOS
|
2017-02-15 02:02:25 +01:00
|
|
|
CONTENT
|
|
|
|
CONTENTS
|
|
|
|
EOS
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an error if the file does not exist" do
|
|
|
|
expect(file).not_to exist
|
|
|
|
expect { file.append_lines("CONTENT") }.to raise_error(RuntimeError)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#atomic_write" do
|
|
|
|
it "atomically replaces a file" do
|
|
|
|
touch file
|
|
|
|
file.atomic_write("CONTENT")
|
|
|
|
expect(File.read(file)).to eq("CONTENT")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "preserves permissions" do
|
2017-05-29 18:24:52 +01:00
|
|
|
File.open(file, "w", 0100777) {}
|
2017-02-15 02:02:25 +01:00
|
|
|
file.atomic_write("CONTENT")
|
2023-01-02 19:18:51 +00:00
|
|
|
expect(file.stat.mode.to_s(8)).to eq((~File.umask & 0100777).to_s(8))
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
it "preserves default permissions" do
|
|
|
|
file.atomic_write("CONTENT")
|
2018-09-17 15:23:17 +01:00
|
|
|
sentinel = file.dirname.join("sentinel")
|
2017-02-15 02:02:25 +01:00
|
|
|
touch sentinel
|
2018-09-17 15:23:17 +01:00
|
|
|
expect(file.stat.mode.to_s(8)).to eq(sentinel.stat.mode.to_s(8))
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#ensure_writable" do
|
|
|
|
it "makes a file writable and restores permissions afterwards" do
|
2019-02-16 12:16:02 -08:00
|
|
|
skip "User is root so everything is writable." if Process.euid.zero?
|
2017-02-15 02:02:25 +01:00
|
|
|
touch file
|
|
|
|
chmod 0555, file
|
|
|
|
expect(file).not_to be_writable
|
|
|
|
file.ensure_writable do
|
|
|
|
expect(file).to be_writable
|
|
|
|
end
|
|
|
|
expect(file).not_to be_writable
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#extname" do
|
|
|
|
it "supports common multi-level archives" do
|
2018-03-25 13:30:37 +01:00
|
|
|
expect(described_class.new("foo-0.1.tar.gz").extname).to eq(".tar.gz")
|
|
|
|
expect(described_class.new("foo-0.1.cpio.gz").extname).to eq(".cpio.gz")
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
2018-08-10 00:54:03 +02:00
|
|
|
|
|
|
|
it "does not treat version numbers as extensions" do
|
|
|
|
expect(described_class.new("foo-0.1").extname).to eq("")
|
|
|
|
expect(described_class.new("foo-1.0-rc1").extname).to eq("")
|
2018-09-29 10:32:18 +02:00
|
|
|
expect(described_class.new("foo-1.2.3").extname).to eq ""
|
|
|
|
end
|
|
|
|
|
|
|
|
it "supports `.7z` with version numbers" do
|
|
|
|
expect(described_class.new("snap7-full-1.4.2.7z").extname).to eq ".7z"
|
2018-08-10 00:54:03 +02:00
|
|
|
end
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
describe "#stem" do
|
|
|
|
it "returns the basename without double extensions" do
|
|
|
|
expect(Pathname("foo-0.1.tar.gz").stem).to eq("foo-0.1")
|
|
|
|
expect(Pathname("foo-0.1.cpio.gz").stem).to eq("foo-0.1")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#install" do
|
2018-03-25 13:30:37 +01:00
|
|
|
before do
|
2017-02-15 02:02:25 +01:00
|
|
|
(src/"a.txt").write "This is sample file a."
|
|
|
|
(src/"b.txt").write "This is sample file b."
|
|
|
|
end
|
|
|
|
|
|
|
|
it "raises an error if the file doesn't exist" do
|
|
|
|
expect { dst.install "non_existent_file" }.to raise_error(Errno::ENOENT)
|
|
|
|
end
|
|
|
|
|
|
|
|
it "installs a file to a directory with its basename" do
|
|
|
|
touch file
|
|
|
|
dst.install(file)
|
|
|
|
expect(dst/file.basename).to exist
|
|
|
|
expect(file).not_to exist
|
|
|
|
end
|
|
|
|
|
|
|
|
it "creates intermediate directories" do
|
|
|
|
touch file
|
|
|
|
expect(dir).not_to be_a_directory
|
|
|
|
dir.install(file)
|
|
|
|
expect(dir).to be_a_directory
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can install a file" do
|
|
|
|
dst.install src/"a.txt"
|
|
|
|
expect(dst/"a.txt").to exist, "a.txt was not installed"
|
|
|
|
expect(dst/"b.txt").not_to exist, "b.txt was installed."
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can install an array of files" do
|
|
|
|
dst.install [src/"a.txt", src/"b.txt"]
|
|
|
|
|
|
|
|
expect(dst/"a.txt").to exist, "a.txt was not installed"
|
|
|
|
expect(dst/"b.txt").to exist, "b.txt was not installed"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can install a directory" do
|
|
|
|
bin = src/"bin"
|
|
|
|
bin.mkpath
|
|
|
|
mv Dir[src/"*.txt"], bin
|
|
|
|
dst.install bin
|
|
|
|
|
|
|
|
expect(dst/"bin/a.txt").to exist, "a.txt was not installed"
|
|
|
|
expect(dst/"bin/b.txt").to exist, "b.txt was not installed"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "supports renaming files" do
|
|
|
|
dst.install src/"a.txt" => "c.txt"
|
|
|
|
|
|
|
|
expect(dst/"c.txt").to exist, "c.txt was not installed"
|
|
|
|
expect(dst/"a.txt").not_to exist, "a.txt was installed but not renamed"
|
|
|
|
expect(dst/"b.txt").not_to exist, "b.txt was installed"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "supports renaming multiple files" do
|
|
|
|
dst.install(src/"a.txt" => "c.txt", src/"b.txt" => "d.txt")
|
|
|
|
|
|
|
|
expect(dst/"c.txt").to exist, "c.txt was not installed"
|
|
|
|
expect(dst/"d.txt").to exist, "d.txt was not installed"
|
|
|
|
expect(dst/"a.txt").not_to exist, "a.txt was installed but not renamed"
|
|
|
|
expect(dst/"b.txt").not_to exist, "b.txt was installed but not renamed"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "supports renaming directories" do
|
|
|
|
bin = src/"bin"
|
|
|
|
bin.mkpath
|
|
|
|
mv Dir[src/"*.txt"], bin
|
|
|
|
dst.install bin => "libexec"
|
|
|
|
|
|
|
|
expect(dst/"bin").not_to exist, "bin was installed but not renamed"
|
|
|
|
expect(dst/"libexec/a.txt").to exist, "a.txt was not installed"
|
|
|
|
expect(dst/"libexec/b.txt").to exist, "b.txt was not installed"
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can install directories as relative symlinks" do
|
|
|
|
bin = src/"bin"
|
|
|
|
bin.mkpath
|
|
|
|
mv Dir[src/"*.txt"], bin
|
|
|
|
dst.install_symlink bin
|
|
|
|
|
|
|
|
expect(dst/"bin").to be_a_symlink
|
|
|
|
expect(dst/"bin").to be_a_directory
|
|
|
|
expect(dst/"bin/a.txt").to exist
|
|
|
|
expect(dst/"bin/b.txt").to exist
|
|
|
|
expect((dst/"bin").readlink).to be_relative
|
|
|
|
end
|
|
|
|
|
|
|
|
it "can install relative paths as symlinks" do
|
|
|
|
dst.install_symlink "foo" => "bar"
|
2018-03-25 13:30:37 +01:00
|
|
|
expect((dst/"bar").readlink).to eq(described_class.new("foo"))
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
2019-02-22 13:18:47 -08:00
|
|
|
|
|
|
|
it "can install relative symlinks in a symlinked directory" do
|
|
|
|
mkdir_p dst/"1/2"
|
|
|
|
dst.install_symlink "1/2" => "12"
|
|
|
|
expect((dst/"12").readlink).to eq(described_class.new("1/2"))
|
|
|
|
(dst/"12").install_symlink dst/"foo"
|
|
|
|
expect((dst/"12/foo").readlink).to eq(described_class.new("../../foo"))
|
|
|
|
end
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
describe InstallRenamed do
|
2018-03-25 13:30:37 +01:00
|
|
|
before do
|
2019-07-23 17:09:57 +01:00
|
|
|
dst.extend(described_class)
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|
|
|
|
|
|
|
|
it "renames the installed file if it already exists" do
|
|
|
|
file.write "a"
|
|
|
|
dst.install file
|
|
|
|
|
|
|
|
file.write "b"
|
|
|
|
dst.install file
|
|
|
|
|
|
|
|
expect(File.read(dst/file.basename)).to eq("a")
|
|
|
|
expect(File.read(dst/"#{file.basename}.default")).to eq("b")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "renames the installed directory" do
|
|
|
|
file.write "a"
|
|
|
|
dst.install src
|
|
|
|
expect(File.read(dst/src.basename/file.basename)).to eq("a")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "recursively renames directories" do
|
|
|
|
(dst/dir.basename).mkpath
|
|
|
|
(dst/dir.basename/"another_file").write "a"
|
|
|
|
dir.mkpath
|
|
|
|
(dir/"another_file").write "b"
|
|
|
|
dst.install dir
|
|
|
|
expect(File.read(dst/dir.basename/"another_file.default")).to eq("b")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
describe "#cp_path_sub" do
|
|
|
|
it "copies a file and replaces the given pattern" do
|
|
|
|
file.write "a"
|
|
|
|
file.cp_path_sub src, dst
|
|
|
|
expect(File.read(dst/file.basename)).to eq("a")
|
|
|
|
end
|
|
|
|
|
|
|
|
it "copies a directory and replaces the given pattern" do
|
|
|
|
dir.mkpath
|
|
|
|
dir.cp_path_sub src, dst
|
|
|
|
expect(dst/dir.basename).to be_a_directory
|
|
|
|
end
|
|
|
|
end
|
2017-02-27 14:23:53 +09:00
|
|
|
|
|
|
|
describe "#ds_store?" do
|
|
|
|
it "returns whether a file is .DS_Store or not" do
|
|
|
|
expect(file).not_to be_ds_store
|
|
|
|
expect(file/".DS_Store").to be_ds_store
|
|
|
|
end
|
|
|
|
end
|
2017-02-15 02:02:25 +01:00
|
|
|
end
|