File: index.rb

package info (click to toggle)
ruby-grit 2.8.3-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 336 kB
  • sloc: ruby: 3,643; makefile: 4
file content (222 lines) | stat: -rw-r--r-- 7,456 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
module Grit

  class Index
    # Public: Gets/Sets the Grit::Repo to which this index belongs.
    attr_accessor :repo

    # Public: Gets/Sets the Hash tree map that holds the changes to be made
    # in the next commit.
    attr_accessor :tree

    # Public: Gets/Sets the Grit::Tree object representing the tree upon
    # which the next commit will be based.
    attr_accessor :current_tree

    # Public: if a tree or commit is written, this stores the size of that object
    attr_reader :last_tree_size
    attr_reader :last_commit_size

    # Initialize a new Index object.
    #
    # repo - The Grit::Repo to which the index belongs.
    #
    # Returns the newly initialized Grit::Index.
    def initialize(repo)
      self.repo = repo
      self.tree = {}
      self.current_tree = nil
    end

    # Public: Add a file to the index.
    #
    # path - The String file path including filename (no slash prefix).
    # data - The String binary contents of the file.
    #
    # Returns nothing.
    def add(path, data)
      path = path.split('/')
      filename = path.pop

      current = self.tree

      path.each do |dir|
        current[dir] ||= {}
        node = current[dir]
        current = node
      end

      current[filename] = data
    end

    # Public: Delete the given file from the index.
    #
    # path - The String file path including filename (no slash prefix).
    #
    # Returns nothing.
    def delete(path)
      add(path, false)
    end

    # Public: Read the contents of the given Tree into the index to use as a
    # starting point for the index.
    #
    # tree - The String branch/tag/sha of the Git tree object.
    #
    # Returns nothing.
    def read_tree(tree)
      self.current_tree = self.repo.tree(tree)
    end

    # Public: Commit the contents of the index.  This method supports two
    # formats for arguments:
    #
    # message - The String commit message.
    # options - An optional Hash of index options.
    #           :parents        - Array of String commit SHA1s or Grit::Commit
    #                             objects to attach this commit to to form a 
    #                             new head (default: nil).
    #           :actor          - The Grit::Actor details of the user making
    #                             the commit (default: nil).
    #           :last_tree      - The String SHA1 of a tree to compare with
    #                             in order to avoid making empty commits
    #                             (default: nil).
    #           :head           - The String branch name to write this head to
    #                             (default: nil).
    #           :committed_date - The Time that the commit was made.
    #                             (Default: Time.now)
    #           :authored_date  - The Time that the commit was authored.
    #                             (Default: committed_date)
    #
    # The legacy argument style looks like:
    #
    # message   - The String commit message.
    # parents   - Array of String commit SHA1s or Grit::Commit objects to
    #             attach this commit to to form a new head (default: nil).
    # actor     - The Grit::Actor details of the user making the commit
    #             (default: nil).
    # last_tree - The String SHA1 of a tree to compare with in order to avoid
    #             making empty commits (default: nil).
    # head      - The String branch name to write this head to
    #             (default: "master").
    #
    # Returns a String of the SHA1 of the new commit.
    def commit(message, parents = nil, actor = nil, last_tree = nil, head = 'master')
      commit_tree_sha = nil
      if parents.is_a?(Hash)
        commit_tree_sha = parents[:commit_tree_sha]
        actor          = parents[:actor]
        committer      = parents[:committer]
        author         = parents[:author]
        last_tree      = parents[:last_tree]
        head           = parents[:head]
        committed_date = parents[:committed_date]
        authored_date  = parents[:authored_date]
        parents        = parents[:parents]
      end

      committer ||= actor
      author    ||= committer

      if commit_tree_sha
        tree_sha1 = commit_tree_sha
      else
        tree_sha1 = write_tree(self.tree, self.current_tree)
      end

      # don't write identical commits
      return false if tree_sha1 == last_tree

      contents = []
      contents << ['tree', tree_sha1].join(' ')
      parents.each do |p|
        contents << ['parent', p].join(' ')
      end if parents

      committer      ||= begin
        config = Config.new(self.repo)
        Actor.new(config['user.name'], config['user.email'])
      end
      author         ||= committer
      committed_date ||= Time.now
      authored_date  ||= committed_date

      contents << ['author',    author.output(authored_date)].join(' ')
      contents << ['committer', committer.output(committed_date)].join(' ')
      contents << ''
      contents << message

      contents = contents.join("\n")
      @last_commit_size = contents.size
      commit_sha1 = self.repo.git.put_raw_object(contents, 'commit')

      self.repo.update_ref(head, commit_sha1) if head
      commit_sha1
    end

    # Recursively write a tree to the index.
    #
    # tree -     The Hash tree map:
    #            key - The String directory or filename.
    #            val - The Hash submap or the String contents of the file.
    # now_tree - The Grit::Tree representing the a previous tree upon which
    #            this tree will be based (default: nil).
    #
    # Returns the String SHA1 String of the tree.
    def write_tree(tree = nil, now_tree = nil)
      tree = self.tree if !tree
      tree_contents = {}

      # fill in original tree
      now_tree = read_tree(now_tree) if(now_tree && now_tree.is_a?(String))
      now_tree.contents.each do |obj|
        sha = [obj.id].pack("H*")
        k = obj.name
        k += '/' if (obj.class == Grit::Tree)
        tmode = obj.mode.to_i.to_s  ## remove zero-padding
        tree_contents[k] = "%s %s\0%s" % [tmode, obj.name, sha]
      end if now_tree

      # overwrite with new tree contents
      tree.each do |k, v|
        case v
          when Array
            sha, mode = v
            if sha.size == 40        # must be a sha
              sha = [sha].pack("H*")
              mode = mode.to_i.to_s  # leading 0s not allowed
              k = k.split('/').last  # slashes not allowed
              str = "%s %s\0%s" % [mode, k, sha]
              tree_contents[k] = str
            end
          when String
            sha = write_blob(v)
            sha = [sha].pack("H*")
            str = "%s %s\0%s" % ['100644', k, sha]
            tree_contents[k] = str
          when Hash
            ctree = now_tree/k if now_tree
            sha = write_tree(v, ctree)
            sha = [sha].pack("H*")
            str = "%s %s\0%s" % ['40000', k, sha]
            tree_contents[k + '/'] = str
          when false
            tree_contents.delete(k)
        end
      end

      tr = tree_contents.sort.map { |k, v| v }.join('')
      @last_tree_size = tr.size
      self.repo.git.put_raw_object(tr, 'tree')
    end

    # Write a blob to the index.
    #
    # data - The String data to write.
    #
    # Returns the String SHA1 of the new blob.
    def write_blob(data)
      self.repo.git.put_raw_object(data, 'blob')
    end
  end # Index

end # Grit