Dir.glob stuck and thread not moving - ruby

Following code is stuck and it is not moving further in a custom plugin (here temp_dir = /tmp)
METADATA_FILE_EXTENSION = '.metadata'
metadata_files = Dir.glob(File.join(temp_dir, "**" ,"*#{METADATA_FILE_EXTENSION}"))

Your example isn't valid Ruby, but assuming that's just a typo it looks like you need to use File.join first. Per the Dir.glob docs, glob needs multiple parts of the path to be File.join'd first. Something closer to this:
metadata_files_path = File.join(temp_dir, "**", "*#{METADATA_FILE_EXTENSION}")
metadata_files = Dir.glob(meta_data_files_path)

Related

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

How to navigate two directories up ruby

In Ruby,I have global variable $file_folder that gives me the location of the current config file:
$file_folder = "#{File}"
$file_folder = /repos/.../test-folder/features/support
I need to access a file sitting in a different folder and this folder is two levels up and two levels down. Is there any way to navigate to this target path using the current location?
target path = /repos/..../test-folder/lib/resources
There are two ways to do this (well, there are several, but here are two good ones). First, using File.expand_path:
original_path = "/repos/something/test-folder/features/support"
target_path = File.expand_path("../../lib/resources", original_path)
p target_path
# => "/repos/something/test-folder/lib/resources"
Note that File.expand_path will always return an absolute path, so it's not appropriate if you want to get a relative path back. If you use it, either make sure that the second argument is an absolute path, or, if it's a relative path, that you know what it will expand to (which will depend on the current working directory).
Next, using Pathname#join (which is aliased as Pathname#+):
require "pathname"
original_path = Pathname("/repos/something/test-folder/features/support")
target_path = original_path + "../../lib/resources"
p target_path
# => #<Pathname:/repos/something/test-folder/lib/resources>
You can also use Pathname#parent, but I think it's kind of ugly:
p original_path.parent.parent
# => #<Pathname:/repos/something/test-folder>
p original_path.parent.parent + "lib/resources"
# => #<Pathname:/repos/something/test-folder/lib/resources>
I prefer Pathname because it makes working with paths very easy. In general you can pass the Pathname object to any method that takes a path, but once in awhile a method will balk at anything other than a String, in which case you'll need to cast it as a string first:
p target_path.to_s
# => "/repos/something/test-folder/lib/resources"
P.S. foo = "#{bar}" is an antipattern in Ruby. If bar is already a String you should just use it directly, i.e. foo = bar. If bar isn't already a String (or you're not sure), you should cast it explicitly with to_s, i.e. foo = bar.to_s.
P.P.S. Global variables are a nasty code smell in Ruby. There is almost always a better way to go than using a global variable.

How do I find the location of the gem?

I'm developing a library that provides access to gem metadata, including it's location on the file system. The idea was to let gem authors set it to a relative path from any script:
# $root/example.gemspec
Example::Gem.root '.' # => $root/
# $root/lib/example/gem.rb
Example::Gem.root '../..' # => $root/
Then, the path of the current script would be used to compute the absolute path. My implementation is currently as follows:
def root(relative_to = nil, file = __FILE__)
unless relative_to.nil?
#root = File.expand_path relative_to, File.dirname(file)
end
#root
end
I thought __FILE__ would return the path to the caller's script, but that assumption is wrong.
It worked within the library itself, but broke down when I tried to integrate it with one of my other gems; the generated path was always relative to the support library itself.
How can I implement this without having to pass the current __FILE__ on every call? Otherwise, there isn't much value to be gained; writing root('../..', __FILE__) is almost the same as writing an actual method to do the same thing.
If it's possible to figure out the path without having to specify anything, that would be even better, but I couldn't think of anything. How does Rails do it?
By the way, I'm aware of Gem::Specification#gem_dir, but it always returns paths relative to the installation directory, even if the gem is not actually there, which makes it useless in a development environment.
You can always make use of the backtrace facility provided:
caller.first
It produces an amalgam of file and line but is usually separated by :. I'd be careful to allow for filenames or paths that may contain colon for whatever reason by ignoring the line information but preserving the rest. In other words, do not split but sub:
caller.first.sub(/:\d+:in .*$/, '')

Why isn't this glob working for a Rake FileList for my server?

How come I get an empty filelist from:
files = FileList.new("#{DEPLOYMENT_PATH}\**\*")
Where DEPLOYMENT_PATH is \\myserver\anndsomepath
How to get a filelist from a server like this? Is this an issue of Ruby/Rake?
UPDATE:
I tried:
files = FileList.new("#{DEPLOYMENT_PATH}\\**\\*")
files = Dir.glob("#{DEPLOYMENT_PATH}\\**\\*")
files = Dir.glob("#{DEPLOYMENT_PATH}\**\*")
UPDATE AGAIN: It works if I put server as:
//myserver/andsomepath
and get files like this:
files = FileList.new("#{DEPLOYMENT_PATH}/**/*")
Ruby' File.join is designed to be your helper when dealing with file paths, by building them in a system-independent way:
File.join('a','b','c')
=> "a/b/c"
So:
DEPLOYMENT_PATH = File.join('', 'myserver', 'andsomepath')
=> "/myserver/andsomepath"
Ruby determines the file path separator by sensing the OS, and is supposed to automatically supply the right value. On Windows XP, Linux and Mac OS it is:
File::SEPARATOR
=> "/"
File.join(DEPLOYMENT_PATH, '**', '*')
=> "/myserver/andsomepath/**/*"
While you can ignore the helper, it is there to make your life easier. Because you are working against a server, you might want to look into File::ALT_SEPARATOR, or just reassigning to SEPARATOR and ignore the warning, letting Ruby do the rest.
What happens if you do
Dir.glob("#{DEPLOYMENT_PATH}\**\*")
Edit: I think Ruby prefers you doing Unix-style slashes, even when you're on Windows. I assume the rationale is that it's better for the same code to work on both Unix and Windows, even if it looks weird on Windows.
tl;dr: If it works with / but not with \, then use what works.
Because:
> "\*" == "*"
=> true
Use "\\**\\*" instead.

A Ruby method for resolving relative paths while keeping absolute paths?

I am working on writing a rake build scrip which will work cross platform ( Mac OSX, Linux , Windows ). The build script will be consumed by a CI server.
I want the logic of my script to be as follows:
If the path is determined to be relative, make it absolute by making output_path = FOO_HOME + user_supplied_relative_path
If the path is determined to be absolute, take it as-is
I'm currently using Pathname.new(location).absolute? but it's not working correctly on windows.
What approach would you suggest for this?
require 'pathname'
(Pathname.new "/foo").absolute? # => true
(Pathname.new "foo").absolute? # => false
The method you're looking for is realpath.
Essentially you do this:
absolute_path = Pathname.new(path).realpath
N.B.: The Pathname module states that usage is experimental on machines that do not have unix like pathnames. So it's implementation dependent. Looks like JRuby should work on Windows.
There is a built-in function that covers both cases and does exactly what you want:
output_path = File.absolute_path(user_supplied_path, FOO_HOME)
The trick is supplying a second argument. It servers as a base directory if (and only if) the first argument is a relative path.
Pathname can do all that for you
require "pathname"
home= Pathname.new("/home/foo")
home + Pathname.new("/bin") # => #<Pathname:/bin>
home + Pathname.new("documents") # => #<Pathname:/home/foo/documents>
I am not sure about this on windows though.
You could also use File.expand_path if the relative directory is relative to the current working directory.
I checked on Linux and windows and didn't have any issues.
Assuming FOO_HOME is the working directory, the code would be:
output_path = File.expand_path user_supplied_relative_path

Resources