From a1237671ba3ec38f5b123ee6600e4352dc03196b Mon Sep 17 00:00:00 2001 From: scott Chacon Date: Sun, 11 Nov 2007 10:04:26 -0800 Subject: [PATCH] git add working, git status object working --- EXAMPLES | 6 +-- lib/git.rb | 1 + lib/git/base.rb | 12 +++++- lib/git/lib.rb | 97 ++++++++++++++++++++++++++++++++---------- lib/git/status.rb | 103 +++++++++++++++++++++++++++++++++++++++++++++ tests/units/test_config.rb | 7 ++- tests/units/test_index.rb | 48 +++++++++++++++++++++ tests/units/test_init.rb | 1 + 8 files changed, 247 insertions(+), 28 deletions(-) create mode 100644 lib/git/status.rb create mode 100644 tests/units/test_index.rb diff --git a/EXAMPLES b/EXAMPLES index 864db8d..b454a32 100644 --- a/EXAMPLES +++ b/EXAMPLES @@ -81,12 +81,12 @@ g = Git.init g = Git.clone(URI, :name => 'name', :path => '/tmp/checkout' (git_dir, index_file) +g.config('user.name', 'Scott Chacon') +g.config('user.email', 'email@email.com') + ***** IMPLEMENTED ***** - -g.config('user.name', 'Scott Chacon') -g.config('user.email', 'email@email.com') g.add('.') g.add([file1, file2]) diff --git a/lib/git.rb b/lib/git.rb index bb68388..cfcbc8c 100644 --- a/lib/git.rb +++ b/lib/git.rb @@ -20,6 +20,7 @@ require 'git/branch' require 'git/remote' require 'git/diff' +require 'git/status' =begin require 'git/author' require 'git/file' diff --git a/lib/git/base.rb b/lib/git/base.rb index 00495c7..eded12d 100644 --- a/lib/git/base.rb +++ b/lib/git/base.rb @@ -92,6 +92,7 @@ module Git def config(name = nil, value = nil) if(name && value) # set value + lib.config_set(name, value) elsif (name) # return value lib.config_get(name) @@ -114,7 +115,11 @@ module Git def log(count = 30) Git::Log.new(self, count) end - + + def status + Git::Status.new(self) + end + def branches Git::Branches.new(self) end @@ -131,6 +136,11 @@ module Git Git::Diff.new(self, objectish, obj2) end + # adds files from the working directory to the git repository + def add(path = '.') + self.lib.add(path) + end + # convenience methods def revparse(objectish) diff --git a/lib/git/lib.rb b/lib/git/lib.rb index 9fa3986..ec65e55 100644 --- a/lib/git/lib.rb +++ b/lib/git/lib.rb @@ -52,6 +52,10 @@ module Git opts[:bare] ? {:repository => clone_dir} : {:working_directory => clone_dir} end + + ## READ COMMANDS ## + + def log_commits(opts = {}) arr_opts = ['--pretty=oneline'] arr_opts << "-#{opts[:count]}" if opts[:count] @@ -89,28 +93,6 @@ module Git arr end - def config_get(name) - command('config', ['--get', name]) - end - - def config_list - hsh = {} - command_lines('config', ['--list']).each do |line| - (key, value) = line.split('=') - hsh[key] = value - end - hsh - end - - def config_remote(name) - hsh = {} - command_lines('config', ['--get-regexp', "remote.#{name}"]).each do |line| - (key, value) = line.split - hsh[key.gsub("remote.#{name}.", '')] = value - end - hsh - end - # returns hash # [tree-ish] = [[line_no, match], [line_no, match2]] # [tree-ish] = [[line_no, match], [line_no, match2]] @@ -161,10 +143,78 @@ module Git hsh end + + # compares the index and the working directory + def diff_files + hsh = {} + command_lines('diff-files').each do |line| + (info, file) = line.split("\t") + (mode_src, mode_dest, sha_src, sha_dest, type) = info.split + hsh[file] = {:path => file, :mode_file => mode_src, :mode_index => mode_dest, + :sha_file => sha_src, :sha_index => sha_dest, :type => type} + end + hsh + end + + # compares the index and the repository + def diff_index(treeish) + hsh = {} + command_lines('diff-index', treeish).each do |line| + (info, file) = line.split("\t") + (mode_src, mode_dest, sha_src, sha_dest, type) = info.split + hsh[file] = {:path => file, :mode_repo => mode_src, :mode_index => mode_dest, + :sha_repo => sha_src, :sha_index => sha_dest, :type => type} + end + hsh + end + + def ls_files + hsh = {} + command_lines('ls-files', '--stage').each do |line| + (info, file) = line.split("\t") + (mode, sha, stage) = info.split + hsh[file] = {:path => file, :mode_index => mode, :sha_index => sha, :stage => stage} + end + hsh + end + + + def config_remote(name) + hsh = {} + command_lines('config', ['--get-regexp', "remote.#{name}"]).each do |line| + (key, value) = line.split + hsh[key.gsub("remote.#{name}.", '')] = value + end + hsh + end + + def config_get(name) + command('config', ['--get', name]) + end + + def config_list + hsh = {} + command_lines('config', ['--list']).each do |line| + (key, value) = line.split('=') + hsh[key] = value + end + hsh + end + + ## WRITE COMMANDS ## + + def config_set(name, value) + command('config', [name, "'#{value}'"]) + end + + def add(path = '.') + command('add', path) + end + private - def command_lines(cmd, opts) + def command_lines(cmd, opts = {}) command(cmd, opts).split("\n") end @@ -177,6 +227,7 @@ module Git #puts "git #{cmd} #{opts}" out = `git #{cmd} #{opts} 2>&1`.chomp #puts out + #puts if $?.exitstatus > 1 raise Git::GitExecuteError.new(out) end diff --git a/lib/git/status.rb b/lib/git/status.rb new file mode 100644 index 0000000..24fd98d --- /dev/null +++ b/lib/git/status.rb @@ -0,0 +1,103 @@ +module Git + + class Status + include Enumerable + + @base = nil + @files = nil + + def initialize(base) + @base = base + construct_status + end + + def changed + @files.select { |k, f| f.type == 'M' } + end + + def added + @files.select { |k, f| f.type == 'A' } + end + + def untracked + @files.select { |k, f| f.untracked } + end + + def pretty + out = '' + self.each do |file| + out << file.path + out << "\n\tsha(r) " + file.sha_repo.to_s + out << "\n\tsha(i) " + file.sha_index.to_s + out << "\n\ttype " + file.type.to_s + out << "\n\tstage " + file.stage.to_s + out << "\n\tuntrac " + file.untracked.to_s + out << "\n" + end + out << "\n" + out + end + + # enumerable method + + def [](file) + @files[file] + end + + def each + @files.each do |k, file| + yield file + end + end + + class StatusFile + attr_accessor :path, :type, :stage, :untracked + attr_accessor :mode_index, :mode_repo + attr_accessor :sha_index, :sha_repo + + def initialize(hash) + @path = hash[:path] + @type = hash[:type] + @stage = hash[:stage] + @mode_index = hash[:mode_index] + @mode_repo = hash[:mode_repo] + @sha_index = hash[:sha_index] + @sha_repo = hash[:sha_repo] + @untracked = hash[:untracked] + end + + + end + + private + + def construct_status + @files = @base.lib.ls_files + + # find untracked in working dir + Dir.chdir(@base.dir.path) do + Dir.glob('**/*') do |file| + if !@files[file] + @files[file] = {:path => file, :untracked => true} if !File.directory?(file) + end + end + end + + # find modified in tree + @base.lib.diff_files.each do |path, data| + @files[path].merge!(data) + end + + # find added but not committed - new files + @base.lib.diff_index('HEAD').each do |path, data| + @files[path].merge!(data) + end + + @files.each do |k, file_hash| + @files[k] = StatusFile.new(file_hash) + end + end + + end + +end \ No newline at end of file diff --git a/tests/units/test_config.rb b/tests/units/test_config.rb index 5adb391..66dc9ff 100644 --- a/tests/units/test_config.rb +++ b/tests/units/test_config.rb @@ -20,7 +20,12 @@ class TestBranch < Test::Unit::TestCase end def test_set_config - # !! TODO !! + in_temp_dir do |path| + g = Git.clone(@wbare, 'bare') + assert_equal('scott Chacon', g.config('user.name')) + g.config('user.name', 'bully') + assert_equal('bully', g.config('user.name')) + end end end \ No newline at end of file diff --git a/tests/units/test_index.rb b/tests/units/test_index.rb new file mode 100644 index 0000000..cf20eaf --- /dev/null +++ b/tests/units/test_index.rb @@ -0,0 +1,48 @@ +#!/usr/bin/env ruby + +require File.dirname(__FILE__) + '/../test_helper' + +class TestIndex< Test::Unit::TestCase + + def setup + set_file_paths + @git = Git.open(@wdir) + end + + def test_add + in_temp_dir do |path| + #puts path + g = Git.clone(@wbare, 'new') + Dir.chdir('new') do + assert_equal('100644', g.status['example.txt'].mode_index) + new_file('test-file', 'blahblahblah') + assert(g.status.untracked.assoc('test-file')) + g.add + assert(g.status.added.assoc('test-file')) + assert(!g.status.untracked.assoc('test-file')) + assert(!g.status.changed.assoc('example.txt')) + append_file('example.txt', 'hahahaha') + assert(g.status.changed.assoc('example.txt')) + g.add + assert(g.status.changed.assoc('example.txt')) + g.commit('my message') + assert(!g.status.changed.assoc('example.txt')) + assert(!g.status.added.assoc('test-file')) + assert(!g.status.untracked.assoc('test-file')) + end + end + end + + def new_file(name, contents) + File.open(name, 'w') do |f| + f.puts contents + end + end + + def append_file(name, contents) + File.open(name, 'a') do |f| + f.puts contents + end + end + +end \ No newline at end of file diff --git a/tests/units/test_init.rb b/tests/units/test_init.rb index 4681ba0..c192dc0 100644 --- a/tests/units/test_init.rb +++ b/tests/units/test_init.rb @@ -53,6 +53,7 @@ class TestInit < Test::Unit::TestCase in_temp_dir do |path| g = Git.clone(@wbare, 'bare-co') assert(File.exists?(File.join(g.repo.path, 'config'))) + assert(g.dir) end end -- 2.11.4.GIT