Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
84 changes: 70 additions & 14 deletions lib/fileutils.rb
Original file line number Diff line number Diff line change
Expand Up @@ -501,25 +501,81 @@ def cp_lr(src, dest, noop: nil, verbose: nil,
end
module_function :cp_lr

# Creates {symbolic links}[https://en.wikipedia.org/wiki/Symbolic_link].
#
# :call-seq:
# FileUtils.ln_s(target, link, force: nil, noop: nil, verbose: nil)
# FileUtils.ln_s(target, dir, force: nil, noop: nil, verbose: nil)
# FileUtils.ln_s(targets, dir, force: nil, noop: nil, verbose: nil)
# When +src+ is the path to an existing file:
#
# - When +dest+ is the path to a non-existent file,
# creates a symbolic link at +dest+ pointing to +src+:
#
# FileUtils.touch('src0.txt')
# File.exist?('dest0.txt') # => false
# FileUtils.ln_s('src0.txt', 'dest0.txt')
# File.symlink?('dest0.txt') # => true
#
# - When +dest+ is the path to a directory,
# creates a symbolic link at <tt>dest/src</tt> pointing to +src+:
#
# FileUtils.touch('src1.txt')
# FileUtils.mkdir('destdir1')
# FileUtils.ln_s('src1.txt', 'destdir1')
# File.symlink?('destdir1/src1.txt') # => true
#
# - When +dest+ is the path to an existing file,
# creates a symbolic link at +dest+ pointing to +src+
# if and only if keyword argument <tt>force: true</tt> is given
# (raises an exception otherwise):
#
# FileUtils.touch('src2.txt')
# FileUtils.touch('dest2.txt')
# FileUtils.ln_s('src2.txt', 'dest2.txt', force: true)
# FileTest.symlink?('dest2.txt') # => true
#
# FileUtils.ln_s('src2.txt', 'dest2.txt') # Raises Errno::EEXIST.
#
# When +src+ and +dest+ are both paths to directories,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This behavior when dest is a directory is the same when src is a file or a directory. I don't think we need a separate example block for it, maybe just update the above text to mention that it applies both when src is a file and when it is a directory.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cannot add this to the relevant list item above b/c the covering text says "When +src+ is the path to an existing file:".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Then consider reorganizing the sections to avoid the repetition.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. One section now, with examples with src as both file and directory.

# creates a symbolic link at <tt>dest/src</tt> pointing to +src+:
#
# FileUtils.mkdir('srcdir3')
# FileUtils.touch('srcdir3/src1.txt')
# FileUtils.touch('srcdir3/src2.txt')
# FileUtils.mkdir('destdir3')
# FileUtils.ln_s('srcdir3', 'destdir3')
# File.symlink?('destdir3/srcdir3') # => true
#
# In the first form, creates a symbolic link +link+ which points to +target+.
# If +link+ already exists, raises Errno::EEXIST.
# But if the <tt>force</tt> option is set, overwrites +link+.
# When +src+ is an array of paths to existing files and +dest+ is a directory:
#
# FileUtils.mkdir('srcdir4')
# FileUtils.touch('srcdir4/src0.txt')
# FileUtils.touch('srcdir4/src1.txt')
# FileUtils.mkdir('destdir4')
# FileUtils.ln_s(['srcdir4/src0.txt', 'srcdir4/src1.txt'], 'destdir4')
# File.symlink?('destdir4/src0.txt') # => true
# File.symlink?('destdir4/src1.txt') # => true
#
# Keyword arguments:
#
# - <tt>force: true</tt> - overwrites +dest+ if it exists.
# - <tt>noop: true</tt> - does not create links.
# - <tt>verbose: true</tt> - prints an equivalent command:
#
# FileUtils.ln_s('src0.txt', 'dest0.txt', noop: true, verbose: true)
# FileUtils.ln_s('src1.txt', 'destdir1', noop: true, verbose: true)
# FileUtils.ln_s('src2.txt', 'dest2.txt', force: true, noop: true, verbose: true)
# FileUtils.ln_s('srcdir3', 'destdir3', noop: true, verbose: true)
# FileUtils.ln_s(['srcdir4/src0.txt', 'srcdir4/src1.txt'], 'destdir4', noop: true, verbose: true)
#
# Output:
#
# FileUtils.ln_s '/usr/bin/ruby', '/usr/local/bin/ruby'
# FileUtils.ln_s 'verylongsourcefilename.c', 'c', force: true
# ln -s src0.txt dest0.txt
# ln -s src1.txt destdir1
# ln -sf src2.txt dest2.txt
# ln -s srcdir3 destdir3
# ln -s srcdir4/src0.txt srcdir4/src1.txt destdir4
#
# In the second form, creates a link +dir/target+ pointing to +target+.
# In the third form, creates several symbolic links in the directory +dir+,
# pointing to each item in +targets+.
# If +dir+ is not a directory, raises Errno::ENOTDIR.
# FileUtils.symlink is an alias for FileUtils.ln_s.
#
# FileUtils.ln_s Dir.glob('/bin/*.rb'), '/home/foo/bin'
# Raises an exception if +src+ is not the path to a file or directory.
#
def ln_s(src, dest, force: nil, noop: nil, verbose: nil)
fu_output_message "ln -s#{force ? 'f' : ''} #{[src,dest].flatten.join ' '}" if verbose
Expand Down