Permalink
Browse files

Merge pull request #659 from jordansissel/build-on-623

Add tests and some style cleanup - builds on #623
  • Loading branch information...
2 parents d18986f + 4958b8f commit 91b1c4fbd888de51e7183420c74e1ca8c18ad117 @jordansissel committed Mar 7, 2014
Showing with 53 additions and 3 deletions.
  1. +25 −3 lib/fpm/util.rb
  2. +28 −0 spec/fpm/util_spec.rb
View
@@ -166,7 +166,29 @@ def copy_entry(src, dst)
when 'directory'
FileUtils.mkdir(dst) unless File.exists? dst
else
- FileUtils.copy_entry(src, dst)
- end
- end
+ # if the file with the same dev and inode has been copied already -
+ # hard link it's copy to `dst`, otherwise make an actual copy
+ st = File.lstat(src)
+ known_entry = copied_entries[[st.dev, st.ino]]
+ if known_entry
+ FileUtils.ln(known_entry, dst)
+ else
+ FileUtils.copy_entry(src, dst)
+ copied_entries[[st.dev, st.ino]] = dst
+ end
+ end # else...
+ end # def copy_entry
+
+ def copied_entries
+ # TODO(sissel): I wonder that this entry-copy knowledge needs to be put
+ # into a separate class/module. As is, calling copy_entry the same way
+ # in slightly different contexts will result in weird or bad behavior.
+ # What I mean is if we do:
+ # pkg = FPM::Package::Dir...
+ # pkg.output()...
+ # pkg.output()...
+ # The 2nd output call will fail or behave weirdly because @copied_entries
+ # is already populated. even though this is anew round of copying.
+ return @copied_entries ||= {}
+ end # def copied_entries
end # module FPM::Util
View
@@ -1,5 +1,8 @@
require "spec_setup"
require "fpm" # local
+require "fpm/util" # local
+require "stud/temporary"
+
describe FPM::Util do
subject do
@@ -11,6 +14,31 @@ def initialize
end.new
end
+ context "#copy_entry" do
+ context "when given files that are hardlinks" do
+ it "should keep those files as hardlinks" do
+ Stud::Temporary.directory do |path|
+ a = File.join(path, "a")
+ b = File.join(path, "b")
+ File.write(a, "hello")
+ File.link(a, b)
+
+ Stud::Temporary.directory do |target|
+ ta = File.join(target, "a")
+ tb = File.join(target, "b")
+ subject.copy_entry(a, ta)
+ subject.copy_entry(b, tb)
+
+ # This seems to work to compare file stat calls.
+ # target 'a' and 'b' should have the same stat result because
+ # they are linked to the same file.
+ insist { File.lstat(ta) } == File.lstat(tb)
+ end
+ end
+ end
+ end
+ end # #copy_entry
+
describe "#safesystem" do
context "with a missing $SHELL" do
before do

0 comments on commit 91b1c4f

Please sign in to comment.