Ruby fileutils: Forcing symlink creation from within cp_r - ruby

I'm attempting to recursively copy directories with Ruby's cp_r method in fileutils. However, it crashes in the (silly but out of my control) case where in the directory I copy there is a file and a symbolic link to that file. I get the following error:
/usr/lib/ruby/1.8/fileutils.rb:1223:in `symlink': File exists - real_file_name or symbolic_link_filename (Errno::EEXIST)
Now, I might be wrong, but it seems like something that symlink's :force option should take care of; however, cp_r cannot take a :force option, and I see no way to make it pass that option to its internal calls to symlink. Also, catching the EEXISTS error doesn't seem to be a solution since the run of cp_r would still be interrupted.
Is there a clean way to get around this problem?

You can use FileUtils.cp_r and pass it the option remove_destination: true to accomplish this.

Related

Chef compile error when capturing shell output

I have a chef recipe that looks something like this:
package 'build-essential' do
action :install
end
cmd = Mixlib::ShellOut.new("gcc -dumpversion")
cmd.run_command
gcc_version = cmd.stdout.strip()
If I execute the recipe on a system where gcc is installed, the recipe runs fine without errors. However, if I run the recipe on a system which doesn't have gcc install I get the error 'no such file or directory - gcc'.
I came to know about the chef two-phases stuff when trying to find a solution to my problem. I was expecting the package installation to satisfy the gcc requirement. How can I tell chef that this requirement will be satisfied later and not throw an error at compile time?
I tried the following, but the attribute does not get updated.
Chef::Resource::RubyBlock.send(:include, Chef::Mixin::ShellOut)
ruby_block "gcc_version" do
block do
s = shell_out("gcc -dumpversion")
node.default['gcc_version'] = s.stdout.strip()
end
end
echo "echo #{node[:gcc_version]}" do
command "echo #{node[:gcc_version]}"
end
Any help is appreciated. Thanks.
So okay, a few issues here. First, forget that Chef::Resource::whatever.send(:include trick. Never do it, literally never. In this case, the ShellOut mixin is already available in all the places anyway.
Next, and more importantly, you've still got a two-pass confusion issue. See https://coderanger.net/two-pass/ for details but basically the strings in that echo resource (I assume that said execute originally and you messed up the coping?) get interpolated at compile time. You haven't said what you are trying to do, but you probably need to use the lazy{} helper method.
And last, don't store things in node attributes like that, it's super brittle and hard to work with.

shell cd command in Ruby

Im trying to execute shell commands using ruby, but i cant change directory to PATH with blank spaces.
variable = %x[cd #{ENV["HOME"]}/Virtual\\ VMs/]
This is not working.
Thank you
To be absolutely safe:
path = File.join [ENV["HOME"], 'Virtual VMs']
variable = %x[cd '#{path}']
Please note, that cd has empty output, so to make sure it works one probably wants to do smth like:
path = File.join [ENV["HOME"], 'Virtual VMs']
variable = %x[cd '#{path}' && ls -la]
#⇒ "total 32\ndrwxr-xr-x ....."
What is ist supposed to do? You try to chdir into a directory, but then don't do anything in it. Your variable will be empty in any case. Aside from the fact that it is pointless to do, you can not reliably execute a cd by itself in this way, because it is not an executable file. You can see this if you just execute %x[cd]. You will get an Errno::ENOENT exception.
Maybe you should first describe in a broader context, what you want to achieve with your code. Where would you like to change the working directory? Within the Ruby process - in which case you have to use Dir.chdir - or in the child process - in which case you have to execute some command after the cd.

FileUtils.mkdir_p support for wildcards in ruby?

I have for example directory structure like this:
./DIRECTORY/PROJECT_A/cars/
./DIRECTORY/PROJECT_B/planes/
./DIRECTORY/PROJECT_C/bikes/
I would like to recourse through them using wildcards and create other directory's, like this:
Dir['/DIRECTORY/PROJECT_*/*/'].each do FileUtils.mkdir_p 'TheNewDirectory'.
It seems "FileUtils" doesn't support wildcards.
I'm doing the same for creation of files on this way:
Dir['/DIRECTORY/PROJECT_*/*/'].each do |dir|
File.new File.join(dir, 'myFile.txt'), 'w+'
end
So I would like to do the same but for creation of directories. Any idea?
FileUtils is a module. It doesn't make sense to claim that a module "does not use wildcards".
Moreover, you are using only the function mkdir_p from FileUtils, and do not use any wildcard in its argument, so what you say, doesn't apply to your case either.
What happened is, that your are iterating through all the directories entries created by your Dir[...] expression, but then don't use the actual directory! A first step to write this better would be
Dir['/DIRECTORY/PROJECT_*/*/'].each { |d| FileUtils.mkdir_p("#{d}/TheNewDirectory") }
This works however only if it is guaranteed that d never takes the value of a plain file, and of course you can run this code only once (because the second time, you would obviously create directories of the form /DIRECTORY/PROJECT_FOO/BAR/TheNewDirectory/TheNewDirectory. I would therefore check, for the safe side, that it indeed makes sense to create the directory, before doing it.
To create directory, you need to specify full path of new directory using the current folder name:
Dir['/DIRECTORY/PROJECT_*/*/'].each do |f|
FileUtils.mkdir_p "#{f}/TheNewDirectory" if File.directory?(f)
end

Forcing a copy with a Thor action

I'm using the Thor built-in action "copy_file" to copy a file from my template source, overwriting an existing file.
I always want to overwrite, and don't want to have to confirm this interactively.
The documentation doesn't suggest there is a force option in the config hash for this action, but http://textmate.rubyforge.org/thor/Thor/Actions.html does indicate that config[:behavior] can be set to force, but I can't see how to do this.
If anyone has an example of doing this that they could share, I'd be most grateful.
Thanks.
Look at the source of copy_file action at https://github.com/erikhuda/thor/blob/master/lib/thor/actions/file_manipulation.rb it uses create_file and passes config Hash to it. Ok, let us see specs for create_file https://github.com/erikhuda/thor/blob/master/spec/actions/create_file_spec.rb . Search the file for 'force', action can be invoked with:
create_file("doc/config.rb", :force => true)
Try that with your copy_file action, append :force => true at the end, it is treated as config hash, passed to create_file and it should work.

Unable to figure out ruby method "directory" and what it does

I am very new to ruby and was trying to understand some code when I got stuck at this snippet:
directory "test_dir" do
action :create
recursive true
end
I tried googling directory class but was unsuccessful. I found a class Dir but its not the same. I see that intuitively this snippet should create a new directory and name it test_dir but I do not want to assume things and move forward.
EDIT
This was a part of a chef-recipe which is used to launch a particular task. For the purposes of launching, it needs to create a directory and download some jars to it. There is an execute method below which goes like this:
execute 'deploy' do
action :nothing
# ignore exit status of storm kill command
command <<-EOH
set -e
storm kill #{name} -w 1 || true
sleep 3
storm jar #{points to the jar}
EOH
end
Sorry I have to be a bit obfuscated as some of the things are not open sourced.
It is the Directory resource of the Chef framework. (DSL stands for domain-specific language. Ruby is well suited for them.)
It's the Chef internal DSL for Directory management. Read more here: http://wiki.opscode.com/display/chef/Resources#Resources-Directory
PS: The recursive true tells it to create the folder much like mkdir -p.
The snippet you pasted is not really enough information to go on (need context; where is the snippet from?)
That said directory looks more like a method than a class. First, it's lowercased and classes are CamelCased.
If it's a method, it's defined somewhere within the application. Have you tried something like this:
grep -r "def directory" ./ or
grep -r "directory" ./| grep "def"
If not in the application itself, it would be defined in one of the application's dependencies (grep -r "..." $GEM_HOME/gems instead)
directory is not a class, it is a method. I do not know what module it is a part of, but that snippet is about equivalent to this:
Kernel.directory.call("test_dir",lambda {action :create; recursive true})
That snippet uses some gem that adds a directory method to the Kernel object.
As others have mentioned, it is part of the directory management DSL Chef. A DSL is a set of methods integrated into the Kernel object; because of the very flexible method calling syntax of Ruby, method calls can look a lot like language keywords. That makes task specific commands (Domain Specific Languages: DSL) look very nice in Ruby; easy to use and flexible. Thus gems that add DSLs are very common.

Resources