rake directory command silently fails? - rake

I'm a newbie to rake so there's probably a simple explanation. I wanted to create some directories and copy in some files for a simple install script e.g.
task :default => ['mktd1', 'mktd2' ] do
end
task :mktd1 do
mkdir "testdata"
cp "x.tmp", "testdata/x.tmp"
end
task :mktd2 do
directory "testdata1"
cp "x.tmp", "testdata1/x.tmp"
end
mkdir works as long as the testdata directory doesnt already exist, but "directory" silently fails (i.e. does nothing) leading to a rake abort because the directory isn't there for the cp command.
Have I misunderstood what directory directive is supposed to do?

So the answer was I had misunderstood how rake is supposed to work. To achieve what I wanted I needed to declare a task that had a dependency on the testdata1 directory. e.g.
task :default => [ 'testdata1/x.tmp' ] do
end
directory "testdata1"
file "testdata1/x.tmp" => ["testdata1"] do
cp "x.tmp", "testdata1/x.tmp"
end
This of course creates a file_creation task x.tmp which depends on the testdata1 directory, and a default task that depends on the x.tmp file creation task. I feel dumb.

Related

Using "rm" to remove files remotely from another directory?

I'm unable to use the rm command to remove files remotely from another directory. I'm a beginner so I apologise for my inability to elaborate properly.
Here's what I'm trying to do:
I'm trying to delete all .srt files from a sub directory. It works when I cd into the specific directory like so:
Command 1:
cd /users/jakubdonovan/library/cloudstorage/iCloud\ drive/the-modern-python3-bootcamp/target_folder
Command 2:
rm *.srt
However, let's say I want to quickly delete a specific file type from a folder without first using the "cd" command, like so:
rm *.srt /users/jakubdonovan/library/cloudstorage/iCloud\ drive/the-modern-python3-bootcamp/target_folder
It returns with "No matches for wildcard '*.srt'. See help expand."
Which is strange because I can use the touch, cp and and all the other commands remotely without a problem.
Is there a way to make the command "rm *.filetype" remove all the files with that specific filetype from a folder and all its subfolders in one swoop?
If you would like to rm in a sub-directory you just have to specify that sub-directory in the command.
rm /path/to/folder/*.filetype
or if you know that the folder is inside your current directory you can try...
rm ./folder/*.filetype

How to make a file executable using Makefile

I want to copy a particular file using Makefile and then make this file executable. How can this be done?
The file I want to copy is a .pl file.
For copying I am using the general cp -rp command. This is done successfully. But now I want to make this file executable using Makefile
Its a bad practice to use cp and chmod, instead use install command.
all:
install -m 0777 hello ../hello
You can use -m option with install to set the permission mode, and even note that by using the install you will preserve not only the permission but also the owner of the file.
You can still use chmod accordingly but it would be a bad practice
all:
cp hello ../hello
chmod +x ../hello
Update: install vs cp
cp would simply copy files with current permissions, install not only copies, but also can change perms/ownership as arg flags. (This is what your requirement was)
One significant difference is that cp truncates the destination file and starts copying data from the source into the destination file. install, on the other hand, removes the destination file first.
This is significant because if the destination file is already in use, bad things could happen to whomever is using that file in case you cp a new file on top of it. e.g. overwriting an executable that is running might fail. Truncating a data file that an existing process is busy reading/writing to could cause pretty weird behavior. If you just remove the destination file first, as install does, things continue much like normal - the removed file isn't actually removed until all processes close that file.[source]
For more details check these,
install vs. cp; and mmap
How is install -c different from cp

Capistrano creating task to change current symlink

I am trying to setup Capistrano deployment for my website, I have got the deploy working, all authentication fine, but I host with Media temple so the default symlink will not work as apache won't have access to the path specified for current to the latest release.
I am trying to make a task that will unlink the current symlink, then recreate it with a relative path, however the Capistrano documentation is severely lacking and I cannot find any more information anywhere of how exactly to set this up.
I have tried using sh, but that seems to run the commands on my computer rather than on the server, run command is not found, and I tried execute but cannot find the right format to do things like rm, or ln, etc...
Currently I am trying the following:
namespace :deploy do
desc "Change HTML Symlink to relative path"
task :create_symlink do
#latest_release_relative = relative_path(deploy_to, release_path + '/html')
#sh "rm -f #{current_path} && ln -s #{latest_release_relative} #{current_path}"
#sh "echo #{File.basename release_path}"
info "echo Modifying symlink to be relative"
#run "rm -d #{current_path}"
#run "ln releases/#{File.basename release_path} #{current_path}"
#execute :rm, '-d', #{current_path}
end
desc "Create environment file"
task :create_env_conf
file 'env.conf' do |t|
sh "touch env.conf"
end
end
after :deploy, "deploy:create_symlink", "deploy:create_env_conf"
After a huge amount of trial and error, I found that the issue was that;
Need to use execute in cap v3
Need to cd then chain command with && for running directory specific commands
Capistrano needs more documentation...
This is how I got mine working, I think there is a better way of doing it with Capistrano 3 but I could not find adequate documentation describing how anywhere.
#config valid only for Capistrano 3.1
lock '3.1.0'
set :application, 'prism-credentials'
set :repo_url, 'REPO URL'
# Default deploy_to directory is /var/www/my_app
set :deploy_to, 'DEPLOY FOLDER'
# Default value for keep_releases is 5
set :keep_releases, 5
set :branch, "master"
if ENV['branch']
set :branch, ENV['branch']
end
namespace :deploy do
desc "Change HTML Symlink to relative path"
task :create_symlink do
on roles(:app) do
#execute "ls -l"
info "Modifying symlink to be relative"
execute "rm -d #{current_path}"
info "Deleted current symlink"
execute "cd ../DEPLOY FOLDER && ln -s ./releases/#{File.basename release_path} current"
info "Created relative current symlink"
execute "cd ~/../DEPLOY FOLDER && touch env.conf && echo 'live' >> env.conf"
info "Created environment file"
end
end
end
after :deploy, "deploy:create_symlink"

Capistrano - How to put files in the shared folder?

I am new to Capistranoand I saw there is shared folder and also option :linked_files. I think shared folder is used to keep files between releases. But my question is, how do files end up being in the shared folder?
Also, if I want to symlink another directory to the current directory e.g. static folder at some path, how do I put it at the linked_dirs ?
Lastly how to set chmod 755 to linked_files and linked_dirs.
Thank you.
Folders inside your app are symlinks to folders in the shared directory. If your app writes to log/production.log, it will actually write to ../shared/log/production.log. That's how the files end up being in the shared folder.
You can see how this works by looking at the feature specs or tests in Capistrano.
If you want to chmod these shared files, you can just do it once directly over ssh since they won't ever be modified by Capistrano after they've been created.
To add a linked directory, in your deploy.rb:
set :linked_dirs, %w{bin log tmp/backup tmp/pids tmp/cache tmp/sockets vendor/bundle}
or
set :linked_dirs, fetch(:linked_dirs) + %w{public/system}
Capistrano 3.5+
Capistrano 3.5 introduced append for array fields. From the official docs, you should use these:
For Shared Files:
append :linked_files, %w{config/database.yml}
For Shared Directories:
append :linked_dirs, %w{bin log public/uploads vendor/bundle}
I've written a task for Capistrano 3 to upload your config files to the shared folder of each of your servers, it'll check these directories in order:
config/deploy/config/:stage/*.yml
config/deploy/config/*.yml
And upload all config files found. It'll only upload the files if they've changed. Note also that if you have the same file on both directories then the second one will be ignored.
Here's the code: https://gist.github.com/Jesus/448d618c83fb0445ebbf
One last thing, this task is just uploading the config. files to your remote shared folder, you still need to set linked_files in config/deploy.rb, eg:
set :linked_files, %w{config/database.yml config/aws.yml}
UPDATE:
If you're using Git, you'll probably want to ignore these files:
echo "config/deploy/config/*" >> .gitignore
There are 3 simple steps you can follow to put a file that you don't want to change in consecutive releases; add your file to linked_files list.
set :linked_files, fetch(:linked_files, []).push('config.php')
Select all the files that you want to share. Put this file from your local to remote server through scp
scp config.php deployer#amazon:~/capistrano/shared/config.php
Now, deploy through the command given below:
bundle exec cap staging deploy
of course, staging can be changed as per requirements may be production,sandbox etc.
One more thing, because you don't want your team members to commit such files. So, put this file to your .gitignore file. And push it to git remote repo.
For Capistrano 3.5+, as specified in official doc :
append :linked_dirs, ".bundle", "tmp"
For me non of the above worked so I ended up adding two functions to the end of the deployment process:
namespace :your_company do
desc "remove index.php"
task :rm_files do
on roles(:all) do
execute "rm -rf #{release_path}/index.php"
end
end
end
namespace :your_company do
desc "add symlink to index.php"
task :add_files do
on roles(:all) do
execute "ln -sf #{shared_path }/index.php #{release_path}/index.php"
end
end
end
after "deploy:finished", "your_company:rm_files"
after "deploy:finished", "your_company:add_files"

rake runs dependents when file already exists

I thought by doing
file 'myfile' => [ :some_task ]
the task would not be run since the file already exists, but when the file does exist the task runs. So is there a way to have the task not run when the file exists?
It depends. what :some_task is.
:some_task is a Symbol, no String. It seems, myfile depends not on another file, but on a task.
If you have this situation:
require 'rake'
file 'myfile' => [ :some_task ] do |tsk|
puts "Start #{tsk}" #some action
end
task :some_task do |tsk|
puts "Start #{tsk}" #some action
end
the question if :some_task is newer, makes no sense. It is a task to be executed always.
And if myfile has a prerequsite, that must be executed, then myfile will be created.