Determine which git files have changed using Ruby? - ruby

I've got a Rails app with blog entries that I want to update from a separate Blog.git repo.
I envision my workflow as something like:
Write new blog entry
Push to remote Git repo
Call cap deploy:update, which will invoke a Rake task to update the database with any changed or new entries
The hitch here is finding which files have changed. I'd like to harness Git for this, and I know I could do some awk or Perl scripting on git diff.
But is there a better way? I've briefly looked at Grit but can't find a good solution.
Update: It turns out Grit is the best solution to this problem, at least as far as I can tell. Here's what I used to solve the problem:
desc 'Posts all entries to database'
task :post_all do
Dir.chdir REPO do
Grit::Repo.new('.').tree.contents.each do |file|
# post_entry cleans up my blog entries and posts them via Post.create()
post_entry(file.data, :text) unless file.basename =~ /\.gitignore/
end
end
end
desc 'Posts all new or changed entries to database'
task :post_new do
Dir.chdir REPO do
Grit::Repo.new('.').head.commit.diffs.each do |diff|
post_entry diff.b_blob.data, :text
end
end
end
desc 'Deletes entries from database'
task :remove_all do
Post.destroy_all
end
desc 'Synchronizes the remote blog repo and the database'
task :sync => [ :remove_all, :post_all ]

is a database really necessary? check out the jekyll gem. hundreds (if not thousands) of simple blogs use it, including two of mine.
http://github.com/mojombo/jekyll
otherwise, grit is a good solution. i've used it for a few things and it works well.

Related

Database cleaner not working with vim-rspec plugin

I use vim-rspec plugin to be able to run rspec tests from within vim, and it was working very well so far. But suddenly the database_cleaner gem stopped working.
Here is my configuration:
# spec/rspec_rails.rb
Rspec.configure do |config|
config.before(:suite) do
puts "Setting up the database cleaner."
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
end
config.around(:each) do |example|
puts "Cleaning the database"
DatabaseCleaner.cleaning do
example.run
end
end
end
I put those two messages to find out if the two blocks run. but they don't. Even if I stop spring than I run again it does not correct it. The strange thing is that if I run the rspec command from the command line every thing works well and I get both of the messages and the database cleaned, the first one time on running, and the second on every example run.
Problem might be in spring itself, remove it and try again. Also you can take a look at a g:rspec_command in your .vimrc file, maybe you bind any specific script to it?

Update Local Workspace to SVN Repository 'Head' With Ruby SVN Bindings

I am writing a program in Ruby that necessitates downloading the most current version of my team's software from SVN upon start up.
The checkout function (from the Ruby SVN bindings) is what I believe I want to use, because an update would not ADD any files that do not exist on my machine's local "trunk" workspace. A checkout statement would both update files that do not match to HEAD, and it would download ones that don't exist at all. Effectively, after running a fully recursive checkout, I would hope to have an exact copy of the most recent SVN repository.
According to this API, a checkout statement basically takes the following:
an exact SVN URL
a local root project directory
a revision (I would be using the string 'HEAD')
recursive (integer 1 or 0)
a pool object (I cannot determine what this is for exactly, but I don't think it affects me)
Here's what I wrote, inside a block that iterates for each file in the SVN repository:
if status != NORMAL #any file that changed or is 'missing'
ctx.checkout(status.entry.url, ROOTDIR, 'HEAD', 0, nil) #update abnormal file to HEAD
end
As a test, I erased a directory from my local workspace, and attempted to restore it with this command. It runs through until it reaches one of the missing files, at which point it raises an error:
`svn_client_checkout3': subversion/libsvn_fs_fs/tree.c:663: Svn::Error::FsNotFound: File not found: revision 0, path '/trunk/project-gadfly/SocketServer/DiscoveryServer.cpp' (Svn::Error::FsNotFound)
I do not understand why this error would be raised, because I thought that a checkout statement would see that the directory (i.e. file) does not exist locally and then create it. Perhaps I am doing something wrong?
Looking back on what I've written, I think all of this was a long-winded way of asking the following simple question: How do I get the most current version of SVN repository onto my local hard drive with an SVN Ruby command?
Thanks in advance,
Elwood Hopkins
I don't know about Ruby-specific part of the question, but it's clear that you asked SVN API to checkout "status.entry.url" at revision 0, which of course doesn't exist here.
It's also strange that you looked into Perl documentation for writing in Ruby. I would recommend you to look at Subversion sources instead.
Here's Ruby method declaration:
http://svn.apache.org/repos/asf/subversion/branches/1.7.x/subversion/bindings/swig/ruby/svn/client.rb
def checkout(url, path, revision=nil, peg_rev=nil,
depth=nil, ignore_externals=false,
allow_unver_obstruction=false)
revision ||= "HEAD"
Client.checkout3(url, path, peg_rev, revision, depth,
ignore_externals, allow_unver_obstruction,
self)
end
So as you can see, you've specified 0 as peg revision. But you should specify HEAD instead.
What about pools --- they are parts of SVN memory managements. Here's the explanation: http://subversion.apache.org/docs/community-guide/conventions.html#apr-pools

Why does this Albacore zip task not create the zip file?

When I run the zip task with rake –-trace, it shows the calls to default and zip_up_files, but it doesn't create the zip file. It doesn't give me an error message. What am I doing wrong?
require 'albacore'
task :default => :zip_up_files
zip :zip_up_files do |zip|
zip.directories_to_zip 'C:\\Temp\\StuffToZip'
zip.output_file = 'out.zip'
zip.output_path = 'C:\\Temp'
end
I tried your rakefile on my machine and got no errors and no zip file! I looked into the Albacore zip task and it uses the Ruby ZipFile class. That seems to be a pure Ruby implementation of the zip archive. So, next thing I tried was fixing up the paths to use forward slashes. That worked!
zip :zip_up_files do |zip|
zip.directories_to_zip 'C:/Temp/StuffToZip'
zip.output_file = 'out.zip'
zip.output_path = 'C:/Temp'
end
I had another thought, that maybe you didn't have permissions to write on the C drive. I wasn't able to reproduce that, but it's my recommendation to maybe be in a User controlled directory. Even if it's an automated build user. Just double check.

Ruby require a code snippet from github

Is there anyway to get Ruby's require statement to download a file from somewhere like github rather than just the local file system?
Update: Sorry I should have made the question clearer. I want to download a file that contains Ruby module and import it into my script rather than just downloading an image or some other arbitrary file within my script.
In other words something like this
require 'http:\\github.com\myrepo\snippet.rb'
puts 'hi'
By default, this is not possible. Also, it's not a good idea for security reasons.
You have a couple of alternatives. If the file you want to include is a Gem and Git repository, then you can use Bundler to download and package the dependency in your project. Then you'll be able to require the file directly in your source code.
This is the best and safest way to include an external dependency.
If you trust the source and you really know what you are doing, you can download the file using Net::HTTP (or any other HTTP library) and eval the body directly in your Ruby code.
You can package everything in a custom require_remote function.
You could download and eval it
require "open-uri"
alias :require_old :require
def require(path)
return false if $".include?(path)
unless path=~ /\Ahttp:\/\/
return require_old(path)
end
eval(open(path).read)
$"<< path
true
end
Be aware, this code has no error checking for network outages nonexisting files, ... . I also believe it is in general not a good idea to require libraries this way, there are security and reliability problems in this approach. But maybe you have a valid usecase for this.
you can include a remote gem from within Gemfiles then it will download when you run bundle install
After reading this question and answers I wanted something a little more bullet proof and verbose that used a paradigm of creating a local file from a repo and then requiring it, only if it didn't already exist locally already. The request for the repo version is explicit via the method repo_require. Used on files you control, this approach improves security IMO.
# try local load
def local_require(filename, relative_path)
relative_flname = File.join(relative_path, filename)
require_relative(relative_flname)
end
# try loading locally first, try repo version on load error
# caution: only use with files you control access to!
def repo_require(raw_repo_prefix, filename, relative_path = '')
local_require(filename, relative_path)
rescue LoadError => e
puts e.message
require 'open-uri'
tempdir = Dir.mktmpdir("repo_require-")
temp_flname = File.join(tempdir, File.basename(filename))
return false if $LOADED_FEATURES.include?(temp_flname)
remote_flname = File.join(raw_repo_prefix, filename)
puts "file not found locally, checking repo: #{remote_flname}"
begin
File.open(temp_flname, 'w') do |f|
f.write(URI.parse(remote_flname).read)
end
rescue OpenURI::HTTPError => e
raise "Error: Can't load #{filename} from repo: #{e.message} - #{remote_flname}"
end
require(temp_flname)
FileUtils.remove_entry(tempdir)
end
Then you could call repo_require like this:
repo_require('https://raw.githubusercontent.com/username/reponame/branch',
'filename', 'relative_path')
The relative_path would the the relative path you would use for the file if the repo was locally installed. For example, you may have something like require_relative '../lib/utils.rb'. In this example filename='lib/utils.rb' and relative_path='..'. This information allows the repo url to be constructed correctly as it does not use the relative path portion.

How can I modify/extend a rake file from another rake file?

I'm trying to find a way to modify/extend a RakeFile from another RakeFile without actually changing it.
When I run my rake task I retrieve a solution from SVN which contains a rakefile. I want to:
Change a variable in this rakefile.
Add a new task to this rakefile
which makes use of existing tasks.
Execute the new task.
I want to do this preferably without actually modifying the original RakeFile on disc.
Here's a way to run arbitrary code prior to executing the task.
your_task = Rake::Task['task:name']
your_task.enhance { this_runs_before_the_task_executes }
You can execute rake tasks similarly.
your_task.invoke
Full docs here.
This is the code which I ended up with to solve the particular problem I was having.
Dir.chdir File.dirname(__FILE__) + '/their_app'
load 'RakeFile'
# Modify stuff from original RakeFile
COMPILE_TARGET = "release"
# Add my task
task :my_task =>[:my_pre_task, :their_task]
I don't know if this is the right way to do it and would appreciate comments/edits if anyone knows a better way.
Thanks to leethal for submitting a answer which helped me on the way and was very useful for another problem I was having.

Resources