gifts 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/.gitignore +17 -0
  2. data/Gemfile +4 -0
  3. data/LICENSE.txt +22 -0
  4. data/README.md +29 -0
  5. data/Rakefile +9 -0
  6. data/gifts.gemspec +32 -0
  7. data/lib/gifts.rb +22 -0
  8. data/lib/gifts/commit_table.rb +70 -0
  9. data/lib/gifts/database.rb +49 -0
  10. data/lib/gifts/diff_table.rb +55 -0
  11. data/lib/gifts/file_table.rb +51 -0
  12. data/lib/gifts/repo_table.rb +31 -0
  13. data/lib/gifts/table_base.rb +18 -0
  14. data/lib/gifts/term_table.rb +28 -0
  15. data/lib/gifts/user_table.rb +19 -0
  16. data/lib/gifts/version.rb +3 -0
  17. data/spec/.gitkeeper +0 -0
  18. data/vendor/lib/LICENSE-grit +22 -0
  19. data/vendor/lib/LICENSE-grit_ext +22 -0
  20. data/vendor/lib/gifts/grit.rb +73 -0
  21. data/vendor/lib/gifts/grit/actor.rb +52 -0
  22. data/vendor/lib/gifts/grit/blame.rb +70 -0
  23. data/vendor/lib/gifts/grit/blob.rb +126 -0
  24. data/vendor/lib/gifts/grit/commit.rb +324 -0
  25. data/vendor/lib/gifts/grit/commit_stats.rb +128 -0
  26. data/vendor/lib/gifts/grit/config.rb +44 -0
  27. data/vendor/lib/gifts/grit/diff.rb +97 -0
  28. data/vendor/lib/gifts/grit/errors.rb +10 -0
  29. data/vendor/lib/gifts/grit/git-ruby.rb +262 -0
  30. data/vendor/lib/gifts/grit/git-ruby/commit_db.rb +52 -0
  31. data/vendor/lib/gifts/grit/git-ruby/git_object.rb +353 -0
  32. data/vendor/lib/gifts/grit/git-ruby/internal/file_window.rb +58 -0
  33. data/vendor/lib/gifts/grit/git-ruby/internal/loose.rb +137 -0
  34. data/vendor/lib/gifts/grit/git-ruby/internal/pack.rb +398 -0
  35. data/vendor/lib/gifts/grit/git-ruby/internal/raw_object.rb +44 -0
  36. data/vendor/lib/gifts/grit/git-ruby/repository.rb +784 -0
  37. data/vendor/lib/gifts/grit/git.rb +501 -0
  38. data/vendor/lib/gifts/grit/index.rb +222 -0
  39. data/vendor/lib/gifts/grit/lazy.rb +35 -0
  40. data/vendor/lib/gifts/grit/merge.rb +45 -0
  41. data/vendor/lib/gifts/grit/ref.rb +98 -0
  42. data/vendor/lib/gifts/grit/repo.rb +722 -0
  43. data/vendor/lib/gifts/grit/ruby1.9.rb +15 -0
  44. data/vendor/lib/gifts/grit/status.rb +153 -0
  45. data/vendor/lib/gifts/grit/submodule.rb +88 -0
  46. data/vendor/lib/gifts/grit/tag.rb +97 -0
  47. data/vendor/lib/gifts/grit/tree.rb +125 -0
  48. data/vendor/lib/gifts/grit_ext.rb +41 -0
  49. data/vendor/lib/gifts/grit_ext/actor.rb +15 -0
  50. data/vendor/lib/gifts/grit_ext/blob.rb +26 -0
  51. data/vendor/lib/gifts/grit_ext/commit.rb +15 -0
  52. data/vendor/lib/gifts/grit_ext/diff.rb +23 -0
  53. data/vendor/lib/gifts/grit_ext/tag.rb +10 -0
  54. data/vendor/lib/gifts/grit_ext/tree.rb +10 -0
  55. data/vendor/lib/gifts/grit_ext/version.rb +7 -0
  56. metadata +256 -0
@@ -0,0 +1,15 @@
1
+ class String
2
+ if self.method_defined?(:ord)
3
+ def getord(offset); self[offset].ord; end
4
+ else
5
+ alias :getord :[]
6
+ end
7
+
8
+ unless self.method_defined?(:b)
9
+ if self.method_defined?(:force_encoding)
10
+ def b; self.dup.force_encoding(Encoding::ASCII_8BIT); end
11
+ else
12
+ def b; self.dup; end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,153 @@
1
+ module Gifts::Grit
2
+
3
+ class Status
4
+ include Enumerable
5
+
6
+ attr_reader :files
7
+
8
+ @base = nil
9
+ @files = nil
10
+
11
+ def initialize(base)
12
+ @base = base
13
+ construct_status
14
+ end
15
+
16
+ def changed
17
+ @files.select { |k, f| f.type == 'M' }
18
+ end
19
+
20
+ def added
21
+ @files.select { |k, f| f.type == 'A' }
22
+ end
23
+
24
+ def deleted
25
+ @files.select { |k, f| f.type == 'D' }
26
+ end
27
+
28
+ def untracked
29
+ @files.select { |k, f| f.untracked }
30
+ end
31
+
32
+ def pretty
33
+ out = ''
34
+ self.each do |file|
35
+ out << file.path
36
+ out << "\n\tsha(r) " + file.sha_repo.to_s + ' ' + file.mode_repo.to_s
37
+ out << "\n\tsha(i) " + file.sha_index.to_s + ' ' + file.mode_index.to_s
38
+ out << "\n\ttype " + file.type.to_s
39
+ out << "\n\tstage " + file.stage.to_s
40
+ out << "\n\tuntrac " + file.untracked.to_s
41
+ out << "\n"
42
+ end
43
+ out << "\n"
44
+ out
45
+ end
46
+
47
+ # enumerable method
48
+
49
+ def [](file)
50
+ @files[file]
51
+ end
52
+
53
+ def each
54
+ @files.each do |k, file|
55
+ yield file
56
+ end
57
+ end
58
+
59
+ class StatusFile
60
+ attr_accessor :path, :type, :stage, :untracked
61
+ attr_accessor :mode_index, :mode_repo
62
+ attr_accessor :sha_index, :sha_repo
63
+
64
+ @base = nil
65
+
66
+ def initialize(base, hash)
67
+ @base = base
68
+ @path = hash[:path]
69
+ @type = hash[:type]
70
+ @stage = hash[:stage]
71
+ @mode_index = hash[:mode_index]
72
+ @mode_repo = hash[:mode_repo]
73
+ @sha_index = hash[:sha_index]
74
+ @sha_repo = hash[:sha_repo]
75
+ @untracked = hash[:untracked]
76
+ end
77
+
78
+ def blob(type = :index)
79
+ if type == :repo
80
+ @base.object(@sha_repo)
81
+ else
82
+ @base.object(@sha_index) rescue @base.object(@sha_repo)
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ private
89
+
90
+ def construct_status
91
+ @files = ls_files
92
+
93
+ Dir.chdir(@base.working_dir) do
94
+ # find untracked in working dir
95
+ Dir.glob('**/*') do |file|
96
+ if !@files[file]
97
+ @files[file] = {:path => file, :untracked => true} if !File.directory?(file)
98
+ end
99
+ end
100
+
101
+ # find modified in tree
102
+ diff_files.each do |path, data|
103
+ @files[path] ? @files[path].merge!(data) : @files[path] = data
104
+ end
105
+
106
+ # find added but not committed - new files
107
+ diff_index('HEAD').each do |path, data|
108
+ @files[path] ? @files[path].merge!(data) : @files[path] = data
109
+ end
110
+
111
+ @files.each do |k, file_hash|
112
+ @files[k] = StatusFile.new(@base, file_hash)
113
+ end
114
+ end
115
+ end
116
+
117
+ # compares the index and the working directory
118
+ def diff_files
119
+ hsh = {}
120
+ @base.git.diff_files.split("\n").each do |line|
121
+ (info, file) = line.split("\t")
122
+ (mode_src, mode_dest, sha_src, sha_dest, type) = info.split
123
+ hsh[file] = {:path => file, :mode_file => mode_src.to_s[1, 7], :mode_index => mode_dest,
124
+ :sha_file => sha_src, :sha_index => sha_dest, :type => type}
125
+ end
126
+ hsh
127
+ end
128
+
129
+ # compares the index and the repository
130
+ def diff_index(treeish)
131
+ hsh = {}
132
+ @base.git.diff_index({}, treeish).split("\n").each do |line|
133
+ (info, file) = line.split("\t")
134
+ (mode_src, mode_dest, sha_src, sha_dest, type) = info.split
135
+ hsh[file] = {:path => file, :mode_repo => mode_src.to_s[1, 7], :mode_index => mode_dest,
136
+ :sha_repo => sha_src, :sha_index => sha_dest, :type => type}
137
+ end
138
+ hsh
139
+ end
140
+
141
+ def ls_files
142
+ hsh = {}
143
+ lines = @base.git.ls_files({:stage => true})
144
+ lines.split("\n").each do |line|
145
+ (info, file) = line.split("\t")
146
+ (mode, sha, stage) = info.split
147
+ hsh[file] = {:path => file, :mode_index => mode, :sha_index => sha, :stage => stage}
148
+ end
149
+ hsh
150
+ end
151
+ end
152
+
153
+ end
@@ -0,0 +1,88 @@
1
+ module Gifts::Grit
2
+
3
+ class Submodule
4
+ attr_reader :id
5
+ attr_reader :mode
6
+ attr_reader :name
7
+
8
+ # Create a Submodule containing just the specified attributes
9
+ # +repo+ is the Repo
10
+ # +atts+ is a Hash of instance variable data
11
+ #
12
+ # Returns Gifts::Grit::Submodule (unbaked)
13
+ def self.create(repo, atts)
14
+ self.allocate.create_initialize(repo, atts)
15
+ end
16
+
17
+ # Initializer for Submodule.create
18
+ # +repo+ is the Repo
19
+ # +atts+ is a Hash of instance variable data
20
+ #
21
+ # Returns Gifts::Grit::Submodule
22
+ def create_initialize(repo, atts)
23
+ @repo = repo
24
+ atts.each do |k, v|
25
+ instance_variable_set("@#{k}".to_sym, v)
26
+ end
27
+ self
28
+ end
29
+
30
+ # The url of this submodule
31
+ # +ref+ is the committish that should be used to look up the url
32
+ #
33
+ # Returns String
34
+ def url(ref)
35
+ config = self.class.config(@repo, ref)
36
+
37
+ lookup = config.keys.inject({}) do |acc, key|
38
+ id = config[key]['id']
39
+ acc[id] = config[key]['url']
40
+ acc
41
+ end
42
+
43
+ lookup[@id]
44
+ end
45
+
46
+ # The configuration information for the given +repo+
47
+ # +repo+ is the Repo
48
+ # +ref+ is the committish (defaults to 'master')
49
+ #
50
+ # Returns a Hash of { <path:String> => { 'url' => <url:String>, 'id' => <id:String> } }
51
+ # Returns {} if no .gitmodules file was found
52
+ def self.config(repo, ref = "master")
53
+ commit = repo.commit(ref)
54
+ blob = commit.tree/'.gitmodules'
55
+ return {} unless blob
56
+
57
+ lines = blob.data.gsub(/\r\n?/, "\n" ).split("\n")
58
+
59
+ config = {}
60
+ current = nil
61
+
62
+ lines.each do |line|
63
+ if line =~ /^\[submodule "(.+)"\]$/
64
+ current = $1
65
+ config[current] = {}
66
+ config[current]['id'] = (commit.tree/current).id
67
+ elsif line =~ /^\t(\w+) = (.+)$/
68
+ config[current][$1] = $2
69
+ config[current]['id'] = (commit.tree/$2).id if $1 == 'path'
70
+ else
71
+ # ignore
72
+ end
73
+ end
74
+
75
+ config
76
+ end
77
+
78
+ def basename
79
+ File.basename(name)
80
+ end
81
+
82
+ # Pretty object inspection
83
+ def inspect
84
+ %Q{#<Gifts::Grit::Submodule "#{@id}">}
85
+ end
86
+ end # Submodule
87
+
88
+ end # Gifts::Grit
@@ -0,0 +1,97 @@
1
+ module Gifts::Grit
2
+
3
+ class Tag < Ref
4
+ extend Lazy
5
+
6
+ lazy_reader :message
7
+ lazy_reader :tagger
8
+ lazy_reader :tag_date
9
+
10
+ # Writes a new tag object from a hash
11
+ # +repo+ is a Gifts::Grit repo
12
+ # +hash+ is the hash of tag values
13
+ #
14
+ # Returns a hash with +sha+ and +size+ of the created object
15
+ def self.create_tag_object(repo, hash, default_actor = nil)
16
+ tagger = hash[:tagger]
17
+ if !tagger
18
+ tagger = default_actor ? default_actor : Actor.new("none", "none@none")
19
+ tagger_date = Time.now
20
+ else
21
+ tagger_date = tagger[:date] ? Time.parse(tagger[:date]) : Time.now
22
+ tagger = Actor.new(tagger[:name], tagger[:email])
23
+ end
24
+ data = []
25
+ data << "object #{hash[:object]}"
26
+ data << "type #{hash[:type]}"
27
+ data << "tag #{hash[:tag]}"
28
+ data << "tagger #{tagger.output(tagger_date)}"
29
+ data << ""
30
+ data << hash[:message]
31
+ data = data.join("\n")
32
+ sha = repo.git.put_raw_object(data, 'tag')
33
+ { :sha => sha, :size => data.size }
34
+ end
35
+
36
+ # Parses the results from `cat-file -p`
37
+ #
38
+ # data - String tag object data. Example:
39
+ # object 7bcc0ee821cdd133d8a53e8e7173a334fef448aa
40
+ # type commit
41
+ # tag v0.7.0
42
+ # tagger USER <EMAIL> DATE
43
+ #
44
+ # v0.7.0
45
+ #
46
+ # Returns parsed Hash. Example:
47
+ # {:message => "...", :tagger => "bob", :tag_date => ...}
48
+ def self.parse_tag_data(data)
49
+ return unless data =~ /^object/
50
+ parsed = {}
51
+ lines = data.split("\n")
52
+ parsed[:object] = lines.shift.sub(/^object /, '')
53
+ parsed[:type] = lines.shift.sub(/^type /, '')
54
+ parsed[:tag] = lines.shift.sub(/^tag /, '')
55
+ author_line = lines.shift
56
+ parsed[:tagger], parsed[:tag_date] = Commit.actor(author_line)
57
+ if !parsed[:tagger] || !parsed[:tagger].name
58
+ parsed[:tag_date] ||= Time.utc(1970)
59
+ parsed[:tagger] = Actor.from_string(author_line.sub(/^tagger /, ''))
60
+ end
61
+ lines.shift # blank line
62
+ parsed[:message] = []
63
+ while lines.first && lines.first !~ /-----BEGIN PGP SIGNATURE-----/
64
+ parsed[:message] << lines.shift
65
+ end
66
+ parsed[:message] = parsed[:message] * "\n"
67
+ parsed[:pgp] = []
68
+ while lines.first
69
+ parsed[:pgp] << lines.shift
70
+ end
71
+ parsed[:pgp] = parsed[:pgp] * "\n"
72
+ parsed
73
+ end
74
+
75
+ def lazy_source
76
+ data = commit.repo.git.cat_ref({:p => true}, name)
77
+ @message = commit.short_message
78
+ @tagger = commit.author
79
+ @tag_date = commit.authored_date
80
+ return self if data.empty?
81
+
82
+ if parsed = self.class.parse_tag_data(data)
83
+ @message = parsed[:message]
84
+ @tagger = parsed[:tagger]
85
+ @tag_date = parsed[:tag_date]
86
+ end
87
+ self
88
+ end
89
+
90
+ def get_commit
91
+ sha = @repo_ref.git.commit_from_sha(@commit_id)
92
+ raise "Unknown object type." if sha == ''
93
+ Commit.create(@repo_ref, :id => sha)
94
+ end
95
+ end
96
+
97
+ end
@@ -0,0 +1,125 @@
1
+ module Gifts::Grit
2
+
3
+ class Tree
4
+ extend Lazy
5
+
6
+ lazy_reader :contents
7
+ attr_reader :id
8
+ attr_reader :mode
9
+ attr_reader :name
10
+
11
+ # Construct the contents of the tree
12
+ # +repo+ is the Repo
13
+ # +treeish+ is the reference
14
+ # +paths+ is an optional Array of directory paths to restrict the tree
15
+ #
16
+ # Returns Gifts::Grit::Tree (baked)
17
+ def self.construct(repo, treeish, paths = [])
18
+ output = repo.git.ls_tree({:raise => true}, treeish, *paths)
19
+ self.allocate.construct_initialize(repo, treeish, output)
20
+ end
21
+
22
+ def construct_initialize(repo, id, text)
23
+ @repo = repo
24
+ @id = id
25
+ @contents = []
26
+
27
+ text.split("\n").each do |line|
28
+ @contents << content_from_string(repo, line)
29
+ end
30
+ @contents.compact!
31
+
32
+ self
33
+ end
34
+
35
+ def lazy_source
36
+ Tree.construct(@repo, @id, [])
37
+ end
38
+
39
+ # Create an unbaked Tree containing just the specified attributes
40
+ # +repo+ is the Repo
41
+ # +atts+ is a Hash of instance variable data
42
+ #
43
+ # Returns Gifts::Grit::Tree (unbaked)
44
+ def self.create(repo, atts)
45
+ self.allocate.create_initialize(repo, atts)
46
+ end
47
+
48
+ # Initializer for Tree.create
49
+ # +repo+ is the Repo
50
+ # +atts+ is a Hash of instance variable data
51
+ #
52
+ # Returns Gifts::Grit::Tree (unbaked)
53
+ def create_initialize(repo, atts)
54
+ @repo = repo
55
+
56
+ atts.each do |k, v|
57
+ instance_variable_set("@#{k}", v)
58
+ end
59
+ self
60
+ end
61
+
62
+ # Parse a content item and create the appropriate object
63
+ # +repo+ is the Repo
64
+ # +text+ is the single line containing the items data in `git ls-tree` format
65
+ #
66
+ # Returns Gifts::Grit::Blob or Gifts::Grit::Tree
67
+ def content_from_string(repo, text)
68
+ mode, type, id, name = text.split(/ |\t/, 4)
69
+ case type
70
+ when "tree"
71
+ Tree.create(repo, :id => id, :mode => mode, :name => name)
72
+ when "blob"
73
+ Blob.create(repo, :id => id, :mode => mode, :name => name)
74
+ when "link"
75
+ Blob.create(repo, :id => id, :mode => mode, :name => name)
76
+ when "commit"
77
+ Submodule.create(repo, :id => id, :mode => mode, :name => name)
78
+ else
79
+ raise Gifts::Grit::InvalidObjectType, type
80
+ end
81
+ end
82
+
83
+ # Find the named object in this tree's contents
84
+ #
85
+ # Examples
86
+ # Repo.new('/path/to/grit').tree/'lib'
87
+ # # => #<Gifts::Grit::Tree "6cc23ee138be09ff8c28b07162720018b244e95e">
88
+ # Repo.new('/path/to/grit').tree/'README.txt'
89
+ # # => #<Gifts::Grit::Blob "8b1e02c0fb554eed2ce2ef737a68bb369d7527df">
90
+ #
91
+ # Returns Gifts::Grit::Blob or Gifts::Grit::Tree or nil if not found
92
+ def /(file)
93
+ if file =~ /\//
94
+ file.split("/").inject(self) { |acc, x| acc/x } rescue nil
95
+ else
96
+ self.contents.find { |c| c.name == file }
97
+ end
98
+ end
99
+
100
+ def basename
101
+ File.basename(name)
102
+ end
103
+
104
+ # Pretty object inspection
105
+ def inspect
106
+ %Q{#<Gifts::Grit::Tree "#{@id}">}
107
+ end
108
+
109
+ # Find only Tree objects from contents
110
+ def trees
111
+ contents.select {|v| v.kind_of? Tree}
112
+ end
113
+
114
+ # Find only Blob objects from contents
115
+ def blobs
116
+ contents.select {|v| v.kind_of? Blob}
117
+ end
118
+
119
+ # Compares trees by name
120
+ def <=>(other)
121
+ name <=> other.name
122
+ end
123
+ end # Tree
124
+
125
+ end # Gifts::Grit