diff --git a/CHANGELOG.md b/CHANGELOG.md index 7bd6c47a5..c93b81ca4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,7 +8,9 @@ ##### Bug Fixes -* None. +* Cover more cases of the Dir.chdir breakages. + [Danielle Tomlinson](https://github.com/dantoml) + [#421](https://github.com/CocoaPods/Xcodeproj/pull/421) ## 1.3.1 (2016-09-10) diff --git a/lib/xcodeproj/plist/ffi.rb b/lib/xcodeproj/plist/ffi.rb index 881bc854b..0b67557be 100644 --- a/lib/xcodeproj/plist/ffi.rb +++ b/lib/xcodeproj/plist/ffi.rb @@ -1,35 +1,6 @@ + module Xcodeproj module Plist - module Extensions - # Since Xcode 8 beta 4, calling `PBXProject.projectWithFile` breaks subsequent calls to - # `chdir`. While sounding ridiculous, this is unfortunately true and debugging it from the - # userland side showed no difference at all to successful calls to `chdir`, but the working - # directory is simply not changed in the end. This workaround is even more absurd, monkey - # patching all calls to `chdir` to use `__pthread_chdir` which appears to work. - module Dir - def self.chdir(path) - old_dir = Dir.getwd - res = actually_chdir(path) - - if block_given? - begin - return yield - ensure - actually_chdir(old_dir) - end - end - - res - end - - def self.actually_chdir(path) - libc = Fiddle.dlopen '/usr/lib/libc.dylib' - f = Fiddle::Function.new(libc['__pthread_chdir'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) - f.call(path.to_s) - end - end - end - # Provides support for loading and serializing property list files via # Fiddle and CoreFoundation / Xcode. # @@ -171,7 +142,10 @@ def ruby_hash_write_devtoolscore(hash, path) end def monkey_patch_chdir - Dir.send(:include, Extensions::Dir) + require 'xcodeproj/plist/ffi/chdir_override' + class << Dir + alias_method :chdir, :cp_chdir + end end end end diff --git a/lib/xcodeproj/plist/ffi/chdir_override.rb b/lib/xcodeproj/plist/ffi/chdir_override.rb new file mode 100644 index 000000000..86f66aa84 --- /dev/null +++ b/lib/xcodeproj/plist/ffi/chdir_override.rb @@ -0,0 +1,27 @@ +# Since Xcode 8 beta 4, calling `PBXProject.projectWithFile` breaks subsequent calls to +# `chdir`. While sounding ridiculous, this is unfortunately true and debugging it from the +# userland side showed no difference at all to successful calls to `chdir`, but the working +# directory is simply not changed in the end. This workaround is even more absurd, monkey +# patching all calls to `chdir` to use `__pthread_chdir` which appears to work. +class Dir + def self.cp_chdir(path) + old_dir = Dir.getwd + res = cp_actually_chdir(path) + + if block_given? + begin + return yield + ensure + cp_actually_chdir(old_dir) + end + end + + res + end + + def self.cp_actually_chdir(path) + libc = Fiddle.dlopen '/usr/lib/libc.dylib' + f = Fiddle::Function.new(libc['__pthread_chdir'], [Fiddle::TYPE_VOIDP], Fiddle::TYPE_INT) + f.call(path.to_s) + end +end diff --git a/spec/project_spec.rb b/spec/project_spec.rb index b84620f99..f840ec8d9 100644 --- a/spec/project_spec.rb +++ b/spec/project_spec.rb @@ -87,6 +87,15 @@ module ProjectSpecs @project = Xcodeproj::Project.open(@path) end + it 'does not break the chdir system call' do + require 'pathname' + Dir.mktmpdir do |dir| + Dir.chdir(dir) do + Pathname(dir).realpath.to_s.should == Dir.getwd + end + end + end + it 'sets itself as the owner of the root object' do # The root object might be referenced by other objects like # the PBXContainerItemProxy