From de071dcd8dee3d853291a5077b9dcdec07dd5362 Mon Sep 17 00:00:00 2001 From: scott Chacon Date: Fri, 16 Nov 2007 11:23:24 -0800 Subject: [PATCH] added some low level tree operations and tests --- lib/git.rb | 2 +- lib/git/base.rb | 72 ++++++++++++++++++++++++++++- lib/git/index.rb | 1 + lib/git/lib.rb | 26 +++++++++++ lib/git/path.rb | 4 ++ tests/units/test_tree_ops.rb | 106 +++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 209 insertions(+), 2 deletions(-) create mode 100644 tests/units/test_tree_ops.rb diff --git a/lib/git.rb b/lib/git.rb index b1d55af..f18ad11 100644 --- a/lib/git.rb +++ b/lib/git.rb @@ -40,7 +40,7 @@ require 'git/author' # License:: MIT License module Git - VERSION = '1.0.2' + VERSION = '1.0.3' # open a bare repository # diff --git a/lib/git/base.rb b/lib/git/base.rb index 4e1e125..6372beb 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -90,6 +90,17 @@ module Git @index end + + def set_working(work_dir, check = true) + @lib = nil + @working_directory = Git::WorkingDirectory.new(work_dir.to_s, check) + end + + def set_index(index_file, check = true) + @lib = nil + @index = Git::Index.new(index_file.to_s, check) + end + # changes current working directory for a block # to the git working directory # @@ -186,7 +197,7 @@ module Git # actual 'git' forked system calls. At some point I hope to replace the Git::Lib # class with one that uses native methods or libgit C bindings def lib - Git::Lib.new(self) + @lib ||= Git::Lib.new(self) end # will run a grep for 'string' on the HEAD of the git repository @@ -330,6 +341,65 @@ module Git self.lib.repack end + + ## LOWER LEVEL INDEX OPERATIONS ## + + def with_index(new_index) + old_index = @index + set_index(new_index, false) + return_value = yield @index + set_index(old_index) + return_value + end + + def with_temp_index &blk + tempfile = Tempfile.new('temp-index') + temp_path = tempfile.path + tempfile.unlink + with_index(temp_path, &blk) + end + + def read_tree(treeish, opts = {}) + self.lib.read_tree(treeish, opts) + end + + def write_tree + self.lib.write_tree + end + + def commit_tree(tree = nil, opts = {}) + Git::Object::Commit.new(self, self.lib.commit_tree(tree, opts)) + end + + def write_and_commit_tree(opts = {}) + tree = write_tree + commit_tree(tree, opts) + end + + def ls_files + self.lib.ls_files + end + + def with_working(work_dir) + return_value = false + old_working = @working_directory + set_working(work_dir) + Dir.chdir work_dir do + return_value = yield @working_directory + end + set_working(old_working) + return_value + end + + def with_temp_working &blk + tempfile = Tempfile.new("temp-workdir") + temp_dir = tempfile.path + tempfile.unlink + Dir.mkdir(temp_dir, 0700) + with_working(temp_dir, &blk) + end + + # runs git rev-parse to convert the objectish to a full sha # # @git.revparse("HEAD^^") diff --git a/lib/git/index.rb b/lib/git/index.rb index b96eedb..c27820d 100644 --- a/lib/git/index.rb +++ b/lib/git/index.rb @@ -1,4 +1,5 @@ module Git class Index < Git::Path + end end diff --git a/lib/git/lib.rb b/lib/git/lib.rb index c196312..690043d 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -350,6 +350,32 @@ module Git command('repack', ['-a', '-d']) end + # reads a tree into the current index file + def read_tree(treeish, opts = {}) + arr_opts = [] + arr_opts << "--prefix=#{opts[:prefix]}" if opts[:prefix] + arr_opts << treeish.to_a.join(' ') + command('read-tree', arr_opts) + end + + def write_tree + command('write-tree') + end + + def commit_tree(tree, opts = {}) + opts[:message] = "commit tree #{tree}" if !opts[:message] + t = Tempfile.new('commit-message') do |t| + t.write(opts[:message]) + end + + arr_opts = [] + arr_opts << tree + arr_opts << "-p #{opts[:parent]}" if opts[:parent] + opts[:parents].each { |p| arr_opts << "-p #{p.to_s}" } if opts[:parents] + arr_opts << "< #{t.path}" + command('commit-tree', arr_opts) + end + # creates an archive file # # options diff --git a/lib/git/path.rb b/lib/git/path.rb index e429d6f..87f5c84 100644 --- a/lib/git/path.rb +++ b/lib/git/path.rb @@ -19,5 +19,9 @@ module Git File.writable?(@path) end + def to_s + @path + end + end end \ No newline at end of file diff --git a/tests/units/test_tree_ops.rb b/tests/units/test_tree_ops.rb new file mode 100644 index 0000000..7dba642 --- /dev/null +++ b/tests/units/test_tree_ops.rb @@ -0,0 +1,106 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../test_helper' + +class TestTreeOps < Test::Unit::TestCase + + def setup + set_file_paths + @git = Git.open(@wdir) + end + + def test_read_tree + + in_temp_dir do + g = Git.clone(@wbare, 'test') + + g.chdir do + g.branch('testbranch1').in_branch('tb commit 1') do + new_file('test-file1', 'blahblahblah2') + g.add + true + end + + g.branch('testbranch2').in_branch('tb commit 2') do + new_file('test-file2', 'blahblahblah3') + g.add + true + end + + g.branch('testbranch3').in_branch('tb commit 3') do + new_file('test-file3', 'blahblahblah4') + g.add + true + end + + # test some read-trees + tr = g.with_temp_index do + g.read_tree('testbranch1') + g.read_tree('testbranch2', :prefix => 'b2/') + g.read_tree('testbranch3', :prefix => 'b2/b3/') + index = g.ls_files + assert(index['b2/test-file2']) + assert(index['b2/b3/test-file3']) + g.write_tree + end + + assert_equal('2423ef1b38b3a140bbebf625ba024189c872e08b', tr) + + # only prefixed read-trees + tr = g.with_temp_index do + g.add # add whats in our working tree + g.read_tree('testbranch1', :prefix => 'b1/') + g.read_tree('testbranch3', :prefix => 'b2/b3/') + index = g.ls_files + assert(index['example.txt']) + assert(index['b1/test-file1']) + assert(!index['b2/test-file2']) + assert(index['b2/b3/test-file3']) + g.write_tree + end + + assert_equal('aa7349e1cdaf4b85cc6a6a0cf4f9b3f24879fa42', tr) + + # new working directory too + tr = nil + g.with_temp_working do + tr = g.with_temp_index do + assert_raises Git::GitExecuteError do + g.add # add whats in our working tree - should be nothing + end + g.read_tree('testbranch1', :prefix => 'b1/') + g.read_tree('testbranch3', :prefix => 'b1/b3/') + index = g.ls_files + assert(!index['example.txt']) + assert(index['b1/test-file1']) + assert(!index['b2/test-file2']) + assert(index['b1/b3/test-file3']) + g.write_tree + end + assert_equal('b40f7a9072cdec637725700668f8fdebe39e6d38', tr) + end + + c = g.commit_tree(tr, :parents => 'HEAD') + assert(c.commit?) + assert_equal('b40f7a9072cdec637725700668f8fdebe39e6d38', c.gtree.sha) + + tmp = Tempfile.new('tesxt') + tmppath = tmp.path + tmp.unlink + tr2 = g.with_index(tmppath) do + g.read_tree('testbranch1', :prefix => 'b1/') + g.read_tree('testbranch3', :prefix => 'b3/') + index = g.ls_files + assert(!index['b2/test-file2']) + assert(index['b3/test-file3']) + g.commit('hi') + end + + assert(c.commit?) + assert_equal('b40f7a9072cdec637725700668f8fdebe39e6d38', c.gtree.sha) + + end + end + end + +end -- 2.11.4.GIT