Add Dir#chdir
This uses Dir.fchdir if supported, or Dir.chdir otherwise. Implements [Feature #19347]
This commit is contained in:
parent
466ca7ae20
commit
3be65f63c7
Notes:
git
2023-03-24 18:19:19 +00:00
2
NEWS.md
2
NEWS.md
@ -19,6 +19,8 @@ Note: We're only listing outstanding class updates.
|
||||
|
||||
* `Dir.fchdir` added for changing the directory to the directory specified
|
||||
by the provided directory file descriptor. [[Feature #19347]]
|
||||
* `Dir#chdir` added for changing the directory to the directory specified
|
||||
by the provided `Dir` object. [[Feature #19347]]
|
||||
|
||||
* String
|
||||
|
||||
|
31
dir.c
31
dir.c
@ -972,7 +972,7 @@ nogvl_chdir(void *ptr)
|
||||
}
|
||||
|
||||
static void
|
||||
dir_chdir(VALUE path)
|
||||
dir_chdir0(VALUE path)
|
||||
{
|
||||
if (chdir(RSTRING_PTR(path)) < 0)
|
||||
rb_sys_fail_path(path);
|
||||
@ -990,7 +990,7 @@ static VALUE
|
||||
chdir_yield(VALUE v)
|
||||
{
|
||||
struct chdir_data *args = (void *)v;
|
||||
dir_chdir(args->new_path);
|
||||
dir_chdir0(args->new_path);
|
||||
args->done = TRUE;
|
||||
chdir_blocking++;
|
||||
if (NIL_P(chdir_thread))
|
||||
@ -1006,7 +1006,7 @@ chdir_restore(VALUE v)
|
||||
chdir_blocking--;
|
||||
if (chdir_blocking == 0)
|
||||
chdir_thread = Qnil;
|
||||
dir_chdir(args->old_path);
|
||||
dir_chdir0(args->old_path);
|
||||
}
|
||||
return Qnil;
|
||||
}
|
||||
@ -1223,6 +1223,30 @@ dir_s_fchdir(VALUE klass, VALUE fd_value)
|
||||
#define dir_s_fchdir rb_f_notimplement
|
||||
#endif
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* dir.chdir -> nil
|
||||
*
|
||||
* Changes the current working directory to the receiver.
|
||||
*
|
||||
* # Assume current directory is /path
|
||||
* Dir.new("testdir").chdir
|
||||
* Dir.pwd # => '/path/testdir'
|
||||
*/
|
||||
static VALUE
|
||||
dir_chdir(VALUE dir)
|
||||
{
|
||||
#if defined(HAVE_FCHDIR) && defined(HAVE_DIRFD) && HAVE_FCHDIR && HAVE_DIRFD
|
||||
dir_s_fchdir(rb_cDir, dir_fileno(dir));
|
||||
#else
|
||||
struct dir_data *dirp;
|
||||
dirp = dir_get(dir);
|
||||
dir_s_chdir(1, &dirp->path, rb_cDir);
|
||||
#endif
|
||||
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
VALUE
|
||||
rb_dir_getwd_ospath(void)
|
||||
@ -3502,6 +3526,7 @@ Init_Dir(void)
|
||||
rb_define_method(rb_cDir,"pos", dir_tell, 0);
|
||||
rb_define_method(rb_cDir,"pos=", dir_set_pos, 1);
|
||||
rb_define_method(rb_cDir,"close", dir_close, 0);
|
||||
rb_define_method(rb_cDir,"chdir", dir_chdir, 0);
|
||||
|
||||
rb_define_singleton_method(rb_cDir,"fchdir", dir_s_fchdir, 1);
|
||||
rb_define_singleton_method(rb_cDir,"chdir", dir_s_chdir, -1);
|
||||
|
@ -96,7 +96,7 @@ class TestDir < Test::Unit::TestCase
|
||||
d.close
|
||||
end
|
||||
|
||||
def test_chdir
|
||||
def test_class_chdir
|
||||
pwd = Dir.pwd
|
||||
setup_envs
|
||||
|
||||
@ -134,6 +134,45 @@ class TestDir < Test::Unit::TestCase
|
||||
end
|
||||
end
|
||||
|
||||
def test_instance_chdir
|
||||
pwd = Dir.pwd
|
||||
dir = Dir.new(pwd)
|
||||
root_dir = Dir.new(@root)
|
||||
setup_envs
|
||||
|
||||
ENV["HOME"] = pwd
|
||||
root_dir.chdir do
|
||||
assert_warning(/conflicting chdir during another chdir block/) { dir.chdir }
|
||||
assert_warning(/conflicting chdir during another chdir block/) { root_dir.chdir }
|
||||
|
||||
assert_equal(@root, Dir.pwd)
|
||||
|
||||
assert_raise(RuntimeError) { Thread.new { Thread.current.report_on_exception = false; dir.chdir }.join }
|
||||
assert_raise(RuntimeError) { Thread.new { Thread.current.report_on_exception = false; dir.chdir{} }.join }
|
||||
|
||||
assert_warning(/conflicting chdir during another chdir block/) { dir.chdir }
|
||||
assert_equal(pwd, Dir.pwd)
|
||||
|
||||
assert_warning(/conflicting chdir during another chdir block/) { root_dir.chdir }
|
||||
assert_equal(@root, Dir.pwd)
|
||||
|
||||
assert_warning(/conflicting chdir during another chdir block/) { dir.chdir }
|
||||
|
||||
root_dir.chdir do
|
||||
assert_equal(@root, Dir.pwd)
|
||||
end
|
||||
assert_equal(pwd, Dir.pwd)
|
||||
end
|
||||
ensure
|
||||
begin
|
||||
dir.chdir
|
||||
rescue
|
||||
abort("cannot return the original directory: #{ pwd }")
|
||||
end
|
||||
dir.close
|
||||
root_dir.close
|
||||
end
|
||||
|
||||
def test_chdir_conflict
|
||||
pwd = Dir.pwd
|
||||
q = Thread::Queue.new
|
||||
|
Loading…
x
Reference in New Issue
Block a user