public
Fork of mojombo/grit
Description: Grit is a Ruby library for extracting information from a git repository in an object oriented manner.
Homepage: http://grit.rubyforge.org/
Clone URL: git://github.com/dustin/grit.git
Search Repo:
dustin (author)
Tue Apr 01 10:52:03 -0700 2008
commit  420eac97a826bfac8724b6b0eef35c20922124b7
tree    e20cd1de2a022aef9ddae66e3f8dd8184f156c0f
parent  d6016bc9fa3950ad18e3028f9d2d26f831061a62
grit / lib / grit / repo.rb
100644 299 lines (261 sloc) 9.038 kb
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
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
module Grit
  
  class Repo
    DAEMON_EXPORT_FILE = 'git-daemon-export-ok'
    
    # The path of the git repo as a String
    attr_accessor :path
    attr_reader :bare
    
    # The git command line interface object
    attr_accessor :git
    
    # Create a new Repo instance
    # +path+ is the path to either the root git directory or the bare git repo
    #
    # Examples
    # g = Repo.new("/Users/tom/dev/grit")
    # g = Repo.new("/Users/tom/public/grit.git")
    #
    # Returns Grit::Repo
    def initialize(path)
      epath = File.expand_path(path)
      
      if File.exist?(File.join(epath, '.git'))
        self.path = File.join(epath, '.git')
        @bare = false
      elsif File.exist?(epath) && epath =~ /\.git$/
        self.path = epath
        @bare = true
      elsif File.exist?(epath)
        raise InvalidGitRepositoryError.new(epath)
      else
        raise NoSuchPathError.new(epath)
      end
      
      self.git = Git.new(self.path)
    end
    
    # The project's description. Taken verbatim from GIT_REPO/description
    #
    # Returns String
    def description
      File.open(File.join(self.path, 'description')).read.chomp
    end
    
    # An array of Head objects representing the branch heads in
    # this repo
    #
    # Returns Grit::Head[] (baked)
    def heads
      Head.find_all(self)
    end
    
    alias_method :branches, :heads
 
    # Object reprsenting the current repo head.
    #
    # Returns Grit::Head (baked)
    def head
      Head.current(self)
    end
 
    # An array of Tag objects that are available in this repo
    #
    # Returns Grit::Tag[] (baked)
    def tags
      Tag.find_all(self)
    end
    
    # An array of Commit objects representing the history of a given ref/commit
    # +start+ is the branch/commit name (default 'master')
    # +max_count+ is the maximum number of commits to return (default 10)
    # +skip+ is the number of commits to skip (default 0)
    #
    # Returns Grit::Commit[] (baked)
    def commits(start = 'master', max_count = 10, skip = 0)
      options = {:max_count => max_count,
                 :skip => skip}
      
      Commit.find_all(self, start, options)
    end
    
    # The Commits objects that are reachable via +to+ but not via +from+
    # Commits are returned in chronological order.
    # +from+ is the branch/commit name of the younger item
    # +to+ is the branch/commit name of the older item
    #
    # Returns Grit::Commit[] (baked)
    def commits_between(from, to)
      Commit.find_all(self, "#{from}..#{to}").reverse
    end
    
    # The Commits objects that are newer than the specified date.
    # Commits are returned in chronological order.
    # +start+ is the branch/commit name (default 'master')
    # +since+ is a string represeting a date/time
    # +extra_options+ is a hash of extra options
    #
    # Returns Grit::Commit[] (baked)
    def commits_since(start = 'master', since = '1970-01-01', extra_options = {})
      options = {:since => since}.merge(extra_options)
      
      Commit.find_all(self, start, options)
    end
    
    # The number of commits reachable by the given branch/commit
    # +start+ is the branch/commit name (default 'master')
    #
    # Returns Integer
    def commit_count(start = 'master')
      Commit.count(self, start)
    end
    
    # The Commit object for the specified id
    # +id+ is the SHA1 identifier of the commit
    #
    # Returns Grit::Commit (baked)
    def commit(id)
      options = {:max_count => 1}
      
      Commit.find_all(self, id, options).first
    end
    
    # The Tree object for the given treeish reference
    # +treeish+ is the reference (default 'master')
    # +paths+ is an optional Array of directory paths to restrict the tree (deafult [])
    #
    # Examples
    # repo.tree('master', ['lib/'])
    #
    # Returns Grit::Tree (baked)
    def tree(treeish = 'master', paths = [])
      Tree.construct(self, treeish, paths)
    end
    
    # The Blob object for the given id
    # +id+ is the SHA1 id of the blob
    #
    # Returns Grit::Blob (unbaked)
    def blob(id)
      Blob.create(self, :id => id)
    end
 
    # The commit log for a treeish
    #
    # Returns Grit::Commit[]
    def log(commit = 'master', path = nil, options = {})
      default_options = {:pretty => "raw"}
      actual_options = default_options.merge(options)
      arg = path ? [commit, '--', path] : [commit]
      commits = self.git.log(actual_options, *arg)
      Commit.list_from_string(self, commits)
    end
    
    # The diff from commit +a+ to commit +b+, optionally restricted to the given file(s)
    # +a+ is the base commit
    # +b+ is the other commit
    # +paths+ is an optional list of file paths on which to restrict the diff
    def diff(a, b, *paths)
      self.git.diff({}, a, b, '--', *paths)
    end
    
    # The commit diff for the given commit
    # +commit+ is the commit name/id
    #
    # Returns Grit::Diff[]
    def commit_diff(commit)
      Commit.diff(self, commit)
    end
    
    # Initialize a bare git repository at the given path
    # +path+ is the full path to the repo (traditionally ends with /<name>.git)
    # +options+ is any additional options to the git init command
    #
    # Examples
    # Grit::Repo.init_bare('/var/git/myrepo.git')
    #
    # Returns Grit::Repo (the newly created repo)
    def self.init_bare(path, options = {})
      git = Git.new(path)
      git.init(options)
      self.new(path)
    end
    
    # Fork a bare git repository from this repo
    # +path+ is the full path of the new repo (traditionally ends with /<name>.git)
    # +options+ is any additional options to the git clone command
    #
    # Returns Grit::Repo (the newly forked repo)
    def fork_bare(path, options = {})
      default_options = {:bare => true, :shared => true}
      real_options = default_options.merge(options)
      self.git.clone(real_options, self.path, path)
      Repo.new(path)
    end
    
    # Archive the given treeish
    # +treeish+ is the treeish name/id (default 'master')
    # +prefix+ is the optional prefix
    #
    # Examples
    # repo.archive_tar
    # # => <String containing tar archive>
    #
    # repo.archive_tar('a87ff14')
    # # => <String containing tar archive for commit a87ff14>
    #
    # repo.archive_tar('master', 'myproject/')
    # # => <String containing tar archive and prefixed with 'myproject/'>
    #
    # Returns String (containing tar archive)
    def archive_tar(treeish = 'master', prefix = nil)
      options = {}
      options[:prefix] = prefix if prefix
      self.git.archive(options, treeish)
    end
    
    # Archive and gzip the given treeish
    # +treeish+ is the treeish name/id (default 'master')
    # +prefix+ is the optional prefix
    #
    # Examples
    # repo.archive_tar_gz
    # # => <String containing tar.gz archive>
    #
    # repo.archive_tar_gz('a87ff14')
    # # => <String containing tar.gz archive for commit a87ff14>
    #
    # repo.archive_tar_gz('master', 'myproject/')
    # # => <String containing tar.gz archive and prefixed with 'myproject/'>
    #
    # Returns String (containing tar.gz archive)
    def archive_tar_gz(treeish = 'master', prefix = nil)
      options = {}
      options[:prefix] = prefix if prefix
      self.git.archive(options, treeish, "| gzip")
    end
    
    # Enable git-daemon serving of this repository by writing the
    # git-daemon-export-ok file to its git directory
    #
    # Returns nothing
    def enable_daemon_serve
      FileUtils.touch(File.join(self.path, DAEMON_EXPORT_FILE))
    end
    
    # Disable git-daemon serving of this repository by ensuring there is no
    # git-daemon-export-ok file in its git directory
    #
    # Returns nothing
    def disable_daemon_serve
      FileUtils.rm_f(File.join(self.path, DAEMON_EXPORT_FILE))
    end
    
    # The list of alternates for this repo
    #
    # Returns Array[String] (pathnames of alternates)
    def alternates
      alternates_path = File.join(self.path, *%w{objects info alternates})
      
      if File.exist?(alternates_path)
        File.read(alternates_path).strip.split("\n")
      else
        []
      end
    end
    
    # Sets the alternates
    # +alts+ is the Array of String paths representing the alternates
    #
    # Returns nothing
    def alternates=(alts)
      alts.each do |alt|
        unless File.exist?(alt)
          raise "Could not set alternates. Alternate path #{alt} must exist"
        end
      end
      
      if alts.empty?
        File.delete(File.join(self.path, *%w{objects info alternates}))
      else
        File.open(File.join(self.path, *%w{objects info alternates}), 'w') do |f|
          f.write alts.join("\n")
        end
      end
    end
    
    def config
      @config ||= Config.new(self)
    end
    
    # Pretty object inspection
    def inspect
      %Q{#<Grit::Repo "#{@path}">}
    end
  end # Repo
  
end # Grit