How do I apply a diff or patch file? - ruby

when using the rugged git library how can I apply that diff to my dest branch as a commit?.
# #param src [Rugged::Object] - the rugged object or string to compare from
# #param dst [Rugged::Object] - the rugged object or string to compare to, defaults to parent
# #return [Rugged::Diff] a rugged diff object between src and dst
def create_diff(src, dst = nil)
src = repo.lookup(find_ref(src))
dst ||= repo.lookup(src.parents.first)
dst = find_ref(dst)
src.diff(dst)
end
# #param sha_or_ref [String] - the name or sha of the ref
# #return [String] the oid of the sha or ref
def find_ref(sha_or_ref)
case sha_or_ref
when Rugged::Object
sha_or_ref.oid
else
repo.rev_parse_oid(sha_or_ref)
end
end
Is there not an easy way to apply a patch or diff? Seems silly that I would need to loop through each change in the diff and either add/rm the file.

Considering the:
libgit2/rugged is the ruby bindings to libgit2
libgit2's apply patch feature was requested from a long time (2013) and only recently merged (a year ago) for libgit2 0.24.4,
You would have to wait for that feature to be ported in rugged.
The last official release v0.24.0 does not include 0.24.4.

Related

get all commit of a file/path with rugged

I would like to get the list of all the commits for a file/path but I don't know how to do it.
For example I want all the commit of the file "test", to get oid of each commit and thanks to this oid, I will get the blob of all revision for this file.
Is it possible ?
Thanks !
We can get all commits by this way :
tab = []
walker = Rugged::Walker.new(repo)
walker.sorting(Rugged::SORT_DATE)
walker.push(repo.head.target)
walker.each do |commit|
if commit.diff(paths: ["path_of_file"]).size > 0
tab.push(commit)
end
end

How to detect a file rename using Rugged?

I'm a novice Rugged user, and I'm attempting to detect file renames in the commit history. I'm diffing each commit against its first parent, as follows:
repo = Rugged::Repository.discover("foo")
walker = Rugged::Walker.new(repo)
walker.sorting(Rugged::SORT_TOPO)
walker.push("master")
walker.each.take(200).each do |commit|
puts commit.oid
puts commit.message
diffs = nil
# Handle Root commit
if commit.parents.count > 0 then
diffs = commit.parents[0].diff(commit)
else
diffs = commit.diff(nil)
end
(files,additions,deletions) = diffs.stat
puts "Files changed: #{files}, Additions: #{additions}, Deletions: #{deletions}"
paths = [];
diffs.each_delta do |delta|
old_file_path = delta.old_file[:path]
new_file_path = delta.new_file[:path]
puts delta.status
puts delta.renamed?
puts delta.similarity
paths += [delta]
end
puts "Paths:"
puts paths
puts "===================================="
end
walker.reset
However, when I do have a rename, the program will output an addition and a removal (A and D status). This matches the output of git log --name-status.
On the other hand, I found out that using git log --name-status --format='%H' --follow -- b.txt correctly shows the rename as R100.
The repo history and the outputs of git can be seen in the following gist: https://gist.github.com/ifigueroap/60716bbf4aa2f205b9c9
My question is how to use the Diff, or Delta objects of Rugged to detect such a file rename...
Thanks
Before accessing diffs.stat, you should call diffs.find_similar! with :renames => true. That'll modify the diffs object to do include rename information. This is not done by default, as the underlying operation is quite complex and not needed in most cases.
Check the documentation for find_similar! here: https://github.com/libgit2/rugged/blob/e96d26174b2bf763e9dd5dd2370e79f5e29077c9/ext/rugged/rugged_diff.c#L310-L366 for more options.

Why does the file get removed when commiting second time via rugged?

I want to store text files in a Git repo. I am using Ruby rugged gem 0.19.0 for this. The problem is that adding a second file f2 seems to automatically delete the first one f1. I have isolated the code to reproduce this (basically code straight from rugged gem docs):
require 'rugged'
def commit(file_name, message, content)
user = { email: 'email', name: 'name', time: Time.now }
repo = Rugged::Repository.new('repo')
oid = repo.write(content, :blob)
index = repo.index
index.add(path: file_name, oid: oid, mode: 0100644)
options = {}
options[:tree] = index.write_tree(repo)
options[:author] = user
options[:committer] = user
options[:message] = message
options[:parents] = repo.empty? ? [] : [ repo.head.target ].compact
options[:update_ref] = 'HEAD'
Rugged::Commit.create(repo, options)
end
Rugged::Repository.init_at('repo', :bare)
commit('f1', 'create f1', 'f1 content')
commit('f2', 'create f2', 'f2 content')
After running above code and cloning the bare repo created, the git log --name-status shows that second commit removes f1 file.
How do I fix this to not mess with files stored previously in the repo?
Rugged README
oid = repo.write("This is a blob.", :blob)
index = repo.index
index.read_tree(repo.head.target.tree) # notice
index.add(:path => "README.md", :oid => oid, :mode => 0100644)
but repo.head.target is a string in 0.19.0
oid = repo.write(content, :blob)
index = repo.index
begin
commit = repo.lookup(repo.head.target)
tree = commit.tree
index.read_tree(tree)
rescue
end
index.add(path: file_name, oid: oid, mode: 0100644)
It works

Access git log data using ruby rugged gem?

For a given file in a git repo, I'd like to look up the SHA of the last commit in which the file was modified, along with the timestamp.
At the command line, this data is visible with git log for a particular file path, e.g.
git log -n 1 path/to/file
Using the "git" gem for ruby I can also do this:
require 'git'
g = Git.open("/path/to/repo")
modified = g.log(1).object(relative/path/to/file).first.date
sha = g.log(1).object(relative/path/to/file).first.sha
Which is great, but is running too slowly for me when looping through lots of paths. As Rugged uses C libraries instead, I was hoping it would be faster but cannot see how to construct the right query in the rugged syntax. Any suggestions?
This should work:
repo = Rugged::Repository.new("/path/to/repo")
walker = Rugged::Walker.new(repo)
walker.sorting(Rugged::SORT_DATE)
walker.push(repo.head.target)
commit = walker.find do |commit|
commit.parents.size == 1 && commit.diff(paths: ["relative/path/to/file"]).size > 0
end
sha = commit.oid
Taken and adapted from https://github.com/libgit2/pygit2/issues/200#issuecomment-15899713
As an aside: Just because rugged is written in C does not mean that costly operations suddenly become cheap and quick. Obviously, you save a lot of string parsing and stuff like that, but this is not always the bottleneck.
As you're not interested in the actual textual diff here, the libgit2 GIT_DIFF_FORCE_BINARY might be something that could also help in increasing the performance of this lookup - unfortunately this is not yet available in Rugged (but will be, soon).
Testing this with the Rugged repo itself, it works correctly:
repo = Rugged::Repository.new(".")
walker = Rugged::Walker.new(repo)
walker.sorting(Rugged::SORT_DATE)
walker.push(repo.head.target)
commit = walker.find do |commit|
commit.parents.size == 1 && commit.diff(paths: ["Gemfile"]).size > 0
end
sha = commit.oid # => "8f5c763377f5bf0fb88d196b7c45a7d715264ad4"
walker = Rugged::Walker.new(repo)
walker.sorting(Rugged::SORT_DATE)
walker.push(repo.head.target)
commit = walker.find do |commit|
commit.parents.size == 1 && commit.diff(paths: [".travis.yml"]).size > 0
end
sha = commit.oid # => "4e18e05944daa2ba8d63a2c6b149900e3b93a88f"

"resources"-directory for ruby gem

I'm currently experimenting with creating my own gem in Ruby. The gem requires some static resources (say an icon in ICO format). Where do I put such resources within my gem directory tree and how to I access them from code?
Also, parts of my extension are native C code and I would like the C-parts to have access to the resources too.
You can put resources anywhere you want, except in the lib directory. Since it will be will be part of Ruby's load path, the only files that should be there are the ones that you want people to require.
For example, I usually store translated text in the i18n/ directory. For icons, I'd just put them in resources/icons/.
As for how to access these resources... I ran into this problem enough that I wrote a little gem just to avoid repetition.
Basically, I was doing this all the time:
def Your::Gem.root
# Current file is /home/you/code/your/lib/your/gem.rb
File.expand_path '../..', File.dirname(__FILE__)
end
Your::Gem.root
# => /home/you/code/your/
I wrapped this up into a nice DSL, added some additional convenience stuff and ended up with this:
class Your::Gem < Jewel::Gem
root '../..'
end
root = Your::Gem.root
# => /home/you/code/your/
# No more joins!
path = root.resources.icons 'your.ico'
# => /home/you/code/your/resources/icons/your.ico
As for accessing your resources in C, path is just a Pathname. You can pass it to a C function as a string, open the file and just do what you need to do. You can even return an object to the Ruby world:
VALUE your_ico_new(VALUE klass, VALUE path) {
char * ico_file = NULL;
struct your_ico * ico = NULL;
ico_file = StringValueCStr(path);
ico = your_ico_load_from_file(ico_file); /* Implement this */
return Data_Wrap_Struct(your_ico_class, your_ico_mark, your_ico_free, ico);
}
Now you can access it from Ruby:
ico = Your::Ico.new path

Resources