Check if the file is newer then some other file in Ruby? - ruby

In Ruby, how do I check if the file is newer than the target before copying?
I found in Ruby-doc.org the FileUtils.uptodate?, but it doesn't seems to work.
I have this error message when running:
/Users/bprov/.rvm/rubies/ruby-2.0.0-p451/lib/ruby/2.0.0/fileutils.rb:148:in uptodate?': undefined methodeach' for "/Users/bprov/folder2/homecontroller":String (NoMethodError)
from Test_Copy.rb:11:in block in <main>'
from Test_Copy.rb:6:inforeach'
from Test_Copy.rb:6:in `'
I have something like that:
require 'fileutils'
$sourcepath = "/Users/bprov/railsbridge"
$destinationpath = "/Users/bprov/folder2"
Dir.foreach($sourcepath) do |file|
if (file =~ /^\./ )
# Do nothing
else
puts file
if FileUtils.uptodate?($sourcepath + "/" + file, $destinationpath + "/" + file)
# Do nothing
else
# If newer
FileUtils.cp($sourcepath + "/" + file, $destinationpath + "/" + file)
end
end
end

So, just use it properly:
FileUtils.uptodate?($sourcepath + "/" + file, [$destinationpath + "/" + file])

Related

Method to call other methods multiple times using hash length as iterator

I have 2 methods that I want to call multiple times. The number of times that I want to call them is based on the count of a hash I'm using. I'm trying to create a new method that calls the other 2 and repeats for the length of the hash count. My issue is that I'm getting an error
"findfiles2.rb:61:in` `chdir': no implicit conversion of Enumerator into String (TypeError)
from findfiles2.rb:61:in `store_directories'
from findfiles2.rb:138:in `block in repeat'
from findfiles2.rb:134:in `loop'
from findfiles2.rb:134:in `repeat'
from findfiles2.rb:153:in `<main>'"
Here's my code:
require 'date'
require "mail"
options = { :address => "smtp.gmail.com",
:port => 587,
:domain => 'gmail.com',
:user_name => 'username',
:password => 'password/',
:authentication => 'plain',
:enable_starttls_auto => true }
mail_sender = "somename#gmail.com"
mail_recipient = "somename#yahoo.com"
directories = {
"directory1" => "/path/to/folder1/",
"directory2" => "/path/to/folder2/",
"directory3" => "/path/to/folder3/",
"directory4" => "/path/to/folder4/",
"directory5" => "/path/to/folder5/"
}
directory_count = directories.count.to_i
file_output = "/path/to/output/"
exclude_folder = 'sample'
output_file_name = "directory_list"
output_file_extension = ".csv"
date_today = Date.today.to_s
log_file_path = "/path/to/output/"
log_name = "script_log_" + date_today + ".txt"
log_file_name = log_file_path + log_name
# starts log file
def start_log(file_output, log_name)
Dir.chdir(file_output)
log_output = File.open(log_name, 'a+')
$stdout = log_output
puts Time.now.to_s + " > " + "Starting Script..."
puts "_______________________________________________"
end
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
# changes working directory to the directory variable
puts Time.now.to_s + " > " + "Updating search directory..."
Dir.chdir(directory)
# outputs only subdirectories with a creation date of older than 24 hours, except for folders names 'test'
Dir.glob("*.*").map(&File.method(:realpath))
puts Time.now.to_s + " > " + "Gathering subdirectories..."
subdir_list=Dir.glob("*").map(&File.method(:realpath)).reject{|files| (not File.directory?(files) && (File.mtime(files) < (Time.now - (60*1440))) && (not files == directory + folder_to_exclude)) }
return subdir_list
end
# checks to see if there are any directories in the array
def directory_check(directory_list, save_to_file, today_date, output_file, output_extension)
if directory_list.empty? == false
# changes the working directory to the file output directory for the file
Dir.chdir(save_to_file)
# writes the array contents into a new file
file_name = output_file + "_" + today_date + output_extension
puts Time.now.to_s + " > " + "Saving contents to: " + file_name
File.open(file_name, "a+") do |f|
directory_list.each { |element| f.puts(element) }
end
else
puts Time.now.to_s + " > " + "This directory does not contain any subdirectories that are older than 24 hours"
exit
end
end
# sends an email containing today's report if a file was created today
def send_email(today_date, output_file_path, output_file_name, output_file_extension, mail_options, email_sender, email_recipient)
backlog_file = output_file_path + output_file_name + "_" + today_date + output_file_extension
if File.exist?(backlog_file) == true
puts Time.now.to_s + " > " + "Sending email report to: " + email_recipient + "..."
Mail.defaults do
delivery_method :smtp, mail_options
end
Mail.deliver do
to email_recipient
from email_sender
subject 'Backlog for ' + today_date
body 'Attached is a report showing any batches that have not been processed within the last 24 hours.'
add_file backlog_file
end
else
puts Time.now.to_s + " > " + "No batches older than 24 hours to report"
exit
end
end
This is the method that is giving me trouble
def repeat(directory, times, exclude_folder)
# fail "times must be 1 or more" if times < 1
counter = 1
# counter_string = counter.to_s
# puts counter_string
# directory_counter = directory + counter_string
loop do
if counter != times
subdir_list_contents = store_directories(directory, exclude_folder)
directory_check(subdir_list_contents, file_output, date_today, output_file_name, output_file_extension)
counter = counter + 1
else
break
end
end
end
This is where I'm starting to run everything.
# Starting log file...
start_log(file_output, log_name)
repeat(directories.each, directory_count, exclude_folder)
# # outputs contents of directory 1 to the file (I want to perform this for the amount of times equal to the hash length, which is what I'm creating the repeat method for)
subdir_list_contents = store_directories(directory1, exclude_folder)
directory_check(subdir_list_contents, file_output, date_today, output_file_name, output_file_extension)
# # # If there is a new file from today, sends an email with file as attachment
send_email(date_today, file_output, output_file_name, output_file_extension, options, mail_sender, mail_recipient)
Your code is much too long. As you can see, nobody helps you.
$ ruby -w t.rb
t.rb:125: warning: mismatched indentations at 'end' with 'def' at 104
t.rb:37: warning: assigned but unused variable - log_file_name
/Users/b/.rvm/rubies/ruby-2.4.0-rc1/lib/ruby/site_ruby/2.4.0/rubygems/core_ext/kernel_require.rb:55:
in `require': cannot load such file -- mail (LoadError)
Post code that we can run. I'm not going to install a whole mail server. So I comment out
#require "mail"
then
t.rb:44:in `chdir': No such file or directory # dir_chdir - /path/to/output/ (Errno::ENOENT)
etc, etc.
Follow the error message :
t.rb:62:in `chdir': no implicit conversion of Enumerator into String (TypeError)
from t.rb:62:in `store_directories'
from t.rb:139:in `block in repeat'
from t.rb:136:in `loop'
from t.rb:136:in `repeat'
from t.rb:149:in `<main>'
All what you need to trace is repeat and store_directories, so you could have reduced the posted code to this strict minimum to reproduce the error :
directories = {
"directory1" => "/path/to/folder1/",
"directory2" => "/path/to/folder2/",
}
directory_count = directories.count.to_i
exclude_folder = 'sample'
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
puts "directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
Dir.chdir(directory)
end
def repeat(directory, times, exclude_folder)
store_directories(directory, exclude_folder)
end
repeat(directories.each, directory_count, exclude_folder)
Execution :
$ ruby -w t.rb
directory=#<Enumerator: {"directory1"=>"/path/to/folder1/", "directory2"=>"/path/to/folder2/"}:each> folder_to_exclude=sample
t.rb:12:in `chdir': no implicit conversion of Enumerator into String (TypeError)
from t.rb:12:in `store_directories'
from t.rb:16:in `repeat'
from t.rb:19:in `<main>'
Had you done this, you don't even had to post a question, because the cause of the error is obvious. In
repeat(directories.each, directory_count, exclude_folder)
directories.each returns an Enumerator. Remove each :
$ ruby -w t.rb
directory={"directory1"=>"/path/to/folder1/", "directory2"=>"/path/to/folder2/"} folder_to_exclude=sample
t.rb:12:in `chdir': no implicit conversion of Hash into String (TypeError)
from t.rb:12:in `store_directories'
from t.rb:16:in `repeat'
from t.rb:20:in `<main>'
I suppose that what you wanted to do is call repeat once for each directory :
def repeat(directory, exclude_folder)
puts "in repeat directory=#{directory} exclude_folder=#{exclude_folder}"
store_directories(directory, exclude_folder)
end
directories.each { | _key, directory | repeat(directory, exclude_folder) }
Execution :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
t.rb:18:in `chdir': No such file or directory # dir_chdir - dir2 (Errno::ENOENT)
from t.rb:18:in `store_directories'
from t.rb:53:in `repeat'
chdir has a side effect : it changes the current directory, and the next time, it will start searching in the new current directory. To avoid this, you need to restore the previous state :
def store_directories(directory, folder_to_exclude)
puts "in store_directories directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
current_directory = Dir.getwd
Dir.chdir(directory)
# ...
# Restore the directory that was current when entering the method.
# Without it, the next chdir will start from the directory left by the previous chdir.
Dir.chdir(current_directory)
end
Now it works :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
After a few more changes, I end up with this :
require 'date'
directories = {
"directory1" => 'dir1',
"directory2" => 'dir2'
}
exclude_folder = 'sample'
#file_output = '.'
#date_today = Date.today.to_s
#output_file_name = 'directory_list'
#output_file_extension = '.csv'
# stores subdirectory contents into an array
def store_directories(directory, folder_to_exclude)
puts "in store_directories directory=#{directory.inspect} folder_to_exclude=#{folder_to_exclude}"
current_directory = Dir.getwd
puts Time.now.to_s + " > " + "Updating search directory..."
# changes working directory to the directory variable
Dir.chdir(directory)
# outputs only subdirectories with a creation date of older than 24 hours, except for folders names 'test'
puts Time.now.to_s + " > " + "Gathering subdirectories..."
subdir_list = Dir.glob("*").map { | file | File.realpath(file) }
puts "all files : subdir_list=#{subdir_list}"
puts "directory + folder_to_exclude=#{directory + folder_to_exclude}" # nonsense
subdir_list = subdir_list.reject do | file |
not File.directory?(file) \
&& File.mtime(file) < Time.now - 86400 \
&& (not file == folder_to_exclude)
end
puts "after reject : subdir_list=#{subdir_list}"
# Restore the directory that was current when entering the method.
# Without it, the next chdir will start from the directory left by the previous chdir.
Dir.chdir(current_directory)
puts "subdir_list=#{subdir_list.inspect}"
subdir_list
end
# checks to see if there are any directories in the array
def directory_check(directory_list, save_to_file, today_date, output_file, output_extension)
if directory_list.empty? == false
# changes the working directory to the file output directory for the file
Dir.chdir(save_to_file) # <----------------- problem !!!!
# writes the array contents into a new file
file_name = output_file + "_" + today_date + output_extension
puts Time.now.to_s + " > " + "Saving contents to: " + file_name
File.open(file_name, "a+") do |f|
directory_list.each { |element| f.puts(element) }
end
else
puts Time.now.to_s + " > " + "This directory does not contain any subdirectories that are older than 24 hours"
end
end
def repeat(directory, exclude_folder)
puts "in repeat directory=#{directory} exclude_folder=#{exclude_folder}"
subdir_list_contents = store_directories(directory, exclude_folder)
directory_check(subdir_list_contents, #file_output, #date_today, #output_file_name, #output_file_extension)
end
directories.each { | _key, directory | repeat(directory, exclude_folder) }
Execution :
$ ruby -w t.rb
in repeat directory=dir1 exclude_folder=sample
in store_directories directory="dir1" folder_to_exclude=sample
2017-10-27 08:05:24 +0200 > Updating search directory...
2017-10-27 08:05:24 +0200 > Gathering subdirectories...
all files : subdir_list=["/userdata/devl/ruby/zintlist/directories/dir1/x1.txt", "/userdata/devl/ruby/zintlist/directories/dir1/x2.txt"]
directory + folder_to_exclude=dir1sample
after reject : subdir_list=[]
subdir_list=[]
2017-10-27 08:05:24 +0200 > This directory does not contain any subdirectories that are older than 24 hours
in repeat directory=dir2 exclude_folder=sample
in store_directories directory="dir2" folder_to_exclude=sample
2017-10-27 08:05:24 +0200 > Updating search directory...
2017-10-27 08:05:24 +0200 > Gathering subdirectories...
all files : subdir_list=["/userdata/devl/ruby/zintlist/directories/dir2/x3.txt"]
directory + folder_to_exclude=dir2sample
after reject : subdir_list=[]
subdir_list=[]
2017-10-27 08:05:24 +0200 > This directory does not contain any subdirectories that are older than 24 hours

Appending a parameter's value in parameters.yml when deploying symfony application

First of all I've never used ruby and capifony so this question might be very easy for some of you but not for me. I tried to find examples related to my question but couldn't find any or I'm too new to ruby to miss!
When deploying my Symfony app, the value of a particular key in my parameters file should be dynamically appended so, rather than using exact generic value coming from distribution file below:
parameters_prod.yml.dist
parameters:
my_prefix: my_value_prefix_
Straight after deployment, parameters.yml should read like below:
parameters.yml
parameters:
my_prefix: my_value_prefix_8235647895
8235647895 part above is going to be timestamp.
How can I do this?
My current deploy.rb
namespace :mytest do
desc "Upload the parameters.yml"
task :upload_parameters do
origin_file = parameters_dir + "/" + parameters_file if parameters_dir && parameters_file
origin_file_append = parameters_dir + "/" + parameters_file_append if parameters_dir && parameters_file_append
if origin_file && File.exists?(origin_file)
relative_path = "app/config/parameters.yml"
files = [origin_file]
files << origin_file_append if origin_file_append && File.exists?(origin_file_append)
tmp_origin_file = origin_file + '.tmp'
File.open(tmp_origin_file, 'w') do |fo|
files.each do |file|
File.foreach(file) do |li|
fo.puts li
end
end
end
if shared_files && shared_files.include?(relative_path)
destination_file = shared_path + "/" + relative_path
else
destination_file = latest_release + "/" + relative_path
end
try_sudo "mkdir -p #{File.dirname(destination_file)}"
top.upload(tmp_origin_file, destination_file)
File.delete(tmp_origin_file)
end
end
end

Downloading files with HTTP via Ruby: file cannot be opened, may be damaged

I am using this snippet of code:
puts u.host + "/" + u.path
resp = http.get(u.host + "/" + u.path)
File.open(filename, "w") do |file|
file.write resp.body
end
If I just type the result from puts u.host + "/" + u.path in the browser, I can clearly see the file. However, the file that downloads can't be opened because it's "damaged". What is the reason for this? Is it because it's from an HTTPS server? What can I do to fix this?
Solved it by changing my get code following this format:
http://www.dotnetguy.co.uk/post/2011/09/27/large-ruby-file-downloads-done-right/

Ruby: Writing to file in subdirectory

I am trying to write to a file inside a subdirectory. This file is created by the code but, once the file is created, it is empty after the script finishes its execution. What am I doing wrong?
# Creating output files
print "Creating output files and filling root menu..."
FileUtils.cd(outdir) do
file = File.new("directory.xml", "w")
file.puts "<?php header(\"Content-type: text/xml\"); ?>"
file.puts "<CiscoIPPhoneMenu>"
file.puts "<Title>Telefonbuch</Title>"
file.puts "<Prompt>Dir External</Prompt>"
letters_used.each do |letter|
filename = "contacts_" + letter + ".xml"
FileUtils.touch(filename)
file.puts "<MenuItem>"
file.puts "<Name>" + letter.upcase + "</Name>"
file.puts "<URL>http://" + HOSTNAME + WEBSERV_DIR + "/" + filename + "</URL>"
file.puts "</MenuItem>"
end
file.puts "</CiscoIPPhoneMenu>"
file.rewind
end
print "Done\n"
"directory.xml" should link to each "contacts_letter.xml" file, which is created by the script too, however directory.xml is empty. Why?
Idiomatic Ruby would write to the file using a block:
File.new("directory.xml", "w") do |fo|
fo.puts "<?php header(\"Content-type: text/xml\"); ?>"
fo.puts "<CiscoIPPhoneMenu>"
fo.puts "<Title>Telefonbuch</Title>"
fo.puts "<Prompt>Dir External</Prompt>"
letters_used.each do |letter|
filename = "contacts_" + letter + ".xml"
FileUtils.touch(filename)
fo.puts "<MenuItem>"
fo.puts "<Name>" + letter.upcase + "</Name>"
fo.puts "<URL>http://" + HOSTNAME + WEBSERV_DIR + "/" + filename + "</URL>"
fo.puts "</MenuItem>"
end
fo.puts "</CiscoIPPhoneMenu>"
end
This closes the file automatically at the end of the block.

Ruby, Mac, Geektool question, file access rights?

I have a Ruby script that I built in TextMate and can successfully run in TextMate.
I can also successfully run this script straight from the terminal.
The script has this chunk of code in it:
# Get the XML file
puts 'Opening the file'
open("messages.xml", "r") do |f|
puts 'File is opened'
theXML = Hpricot::XML(f)
puts 'Trying to get the message_entity'
message_entity = GetMessage(theXML)
# Build the system command
puts 'Getting the author and the message'
theAuthor = message_entity.search(:author).text
theMessage = message_entity.search(:messagetext).text
# Get the correct image for this author
theAuthorImage = ''
case theAuthor
when 'James' : theAuthorImage = 'images/me32.png'
when 'Zuzu' : theAuthorImage = 'images/Zuzu32.png'
end
puts "/usr/local/bin/growlnotify '" + theAuthor + " says' -m '" + theMessage + "' -n 'Laurens Notes' --image '" + theAuthorImage + "'"
#system("/usr/local/bin/growlnotify '" + theAuthor + " says' -m '" + theMessage + "' -n 'Laurens Notes' --image '" + theAuthorImage + "'")
end
puts 'The End'
When the script is run by GeekTool, it never gets past puts 'File is opened'. It doesn't even hit puts 'The End'. It gives no error at all.
The script is under a folder under the /System folder on my Mac, but I have changed the file permissions to allow "everyone" to have "read & write" access.
EDIT
I just copied the files to a folder directly under my user home folder, and it still has the issue in GeekTool but not in TextMate or straight through the Terminal.
END EDIT
2nd Edit
I think GeekTool may have an issue with paths to files maybe.
For example, I changed the program to just read the XML file straight from the Internet for now and it does that just fine, but there are some images that the program is using for the icons in growlnotify. When run through TextMate, these icons display perfectly. When run using GeekTool...nope. No custom icon at all.
It's as if GeekTool just can't handle the file paths correctly.
When I do puts __FILE__.to_s it gives me the correct filepath to my .rb file though.
** end 2nd edit**
What should I do?
Geektool runs all the commands from / so relative path names will not work when trying to run growlnotify.
puts Dir.pwd #outputs "/"
You will need to pass the absolute paths of the images to growlnotify.
The current path can be retrieved with
File.dirname(__FILE__)
So you would use
theAuthorImage = File.dirname(__FILE__)
case theAuthor
when 'James' : theAuthorImage += '/images/me32.png'
when 'Zuzu' : theAuthorImage += '/images/Zuzu32.png'
end
cmd = "/usr/local/bin/growlnotify '#{theAuthor} says' -m '#{theMessage}' -n 'Laurens Notes' --image '#{theAuthorImage}'"
puts cmd
system cmd
Try wrapping it all in a block like below, which will log to /tmp/geektool.txt. Then you can see if there are any exceptions happening that you aren't aware of (like file permission).
begin
#file.open... etc
rescue Exception => e
file.open('/tmp/geektool.txt', 'w'){|f| f.puts "#{e}\n\n#{e.backtrace}"}
end
Also, don't forget there's the ruby-growl gem.
Have you checked if GeekTool spews any output to console.log or system.log?
Also, if it never gets past 'File is opened', it might be an issue with gems and requiring Hpricot?

Resources