Class: Silo::Repository
- Inherits:
-
Object
- Object
- Silo::Repository
- Defined in:
- lib/silo/repository.rb
Overview
Represents a Silo repository
This provides the core features of Silo to initialize a repository and work with it.
Instance Attribute Summary collapse
-
#git ⇒ Grit::Repo
readonly
The Grit object to access the Git repository.
-
#path ⇒ String
readonly
The file system path of the repository.
-
#remotes ⇒ Hash<Remote::Base>
readonly
The remote repositories configured for this repository.
Instance Method Summary collapse
-
#add(path, prefix = nil) ⇒ Object
Stores a file or full directory structure into the repository inside an optional prefix path.
-
#add_remote(name, url) ⇒ Object
Adds a new remote to this Repository.
-
#contents(path = nil) ⇒ Array<String>
Gets a list of files and directories in the specified path inside the repository.
-
#distribute ⇒ Object
Push the current state of the repository to each attached remote repository.
-
#find_object(path = '/') ⇒ Grit::Blob, Grit::Tree
Returns the object (tree or blob) at the given path inside the repository.
-
#git_remotes ⇒ Object
Loads remotes from the backing Git repository's configuration.
-
#history(path = nil) ⇒ Array<Grit::Commit>
Generate a history of Git commits for either the complete repository or a specified file or directory.
-
#in_work_tree(path) {|path| ... } ⇒ Object
Run a block of code with +$GIT_WORK_TREE+ set to a specified path.
-
#info(path) ⇒ Hash<Symbol, Object>
Get information about a file or directory in the repository.
-
#initialize(path, options = {}) ⇒ Repository
constructor
Creates a new repository instance on the given path.
-
#object!(path) ⇒ Grit::Blob, Grit::Tree
Returns the object (tree or blob) at the given path inside the repository or fail if it does not exist.
-
#prepare ⇒ Object
Prepares the Git repository backing this Silo repository for use with Silo.
-
#prepared? ⇒ Boolean
Return whether the Git repository backing this Silo repository has already been prepared for use with Silo.
-
#purge(path, prune = true) ⇒ Object
Purges a single file or the complete structure of a directory with the given path from the repository.
-
#remove(path) ⇒ Object
(also: #rm)
Removes a single file or the complete structure of a directory with the given path from the HEAD revision of the repository.
-
#remove_remote(name) ⇒ Object
Removes the remote with the given name from this repository.
-
#restore(path, prefix = '.') ⇒ Object
Restores a single file or the complete structure of a directory with the given path from the repository.
Constructor Details
#initialize(path, options = {}) ⇒ Repository
Creates a new repository instance on the given path
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 |
# File 'lib/silo/repository.rb', line 47 def initialize(path, = {}) = { :create => true, :prepare => true }.merge @path = File. path if File.exist?(@path) && Dir.entries(@path).size > 2 unless File.exist?(File.join(@path, 'HEAD')) && File.stat(File.join(@path, 'objects')).directory? && File.stat(File.join(@path, 'refs')).directory? raise Grit::InvalidGitRepositoryError.new(@path) end @git = Grit::Repo.new(@path, { :is_bare => true }) else if [:create] @git = Grit::Repo.(@path, {}, { :is_bare => true }) else raise Grit::NoSuchPathError.new(@path) end end if !prepared? && @git.commit_count > 0 raise InvalidRepositoryError.new(@path) end @remotes = {} @remotes.merge! git_remotes prepare if [:prepare] && !prepared? end |
Instance Attribute Details
#git ⇒ Grit::Repo (readonly)
Returns The Grit object to access the Git repository.
24 25 26 |
# File 'lib/silo/repository.rb', line 24 def git @git end |
#path ⇒ String (readonly)
Returns The file system path of the repository.
27 28 29 |
# File 'lib/silo/repository.rb', line 27 def path @path end |
#remotes ⇒ Hash<Remote::Base> (readonly)
Returns The remote repositories configured for this repository.
31 32 33 |
# File 'lib/silo/repository.rb', line 31 def remotes @remotes end |
Instance Method Details
#add(path, prefix = nil) ⇒ Object
Stores a file or full directory structure into the repository inside an optional prefix path
This adds one commit to the history of the repository including the file or directory structure. If the file or directory already existed inside the prefix, Git will only save the changes.
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 |
# File 'lib/silo/repository.rb', line 91 def add(path, prefix = nil) path = File. path prefix ||= '/' in_work_tree File.dirname(path) do index = @git.index index.read_tree 'HEAD' add = lambda do |f, p| file = File.basename f pre = (p == '/') ? file : File.join(p, file) dir = File.stat(f).directory? if dir (Dir.entries(f) - %w{. ..}).each do |child| add.call File.join(f, child), pre end else index.add pre, IO.read(f) end dir end dir = add.call path, prefix type = dir ? 'directory' : 'file' commit_msg = "Added #{type} #{path} into '#{prefix}'" index.commit commit_msg, [@git.head.commit.sha] end end |
#add_remote(name, url) ⇒ Object
Adds a new remote to this Repository
122 123 124 125 |
# File 'lib/silo/repository.rb', line 122 def add_remote(name, url) @remotes[name] = Remote::Git.new(self, name, url) @remotes[name].add end |
#contents(path = nil) ⇒ Array<String>
Gets a list of files and directories in the specified path inside the repository
133 134 135 136 137 138 139 140 141 142 143 144 145 |
# File 'lib/silo/repository.rb', line 133 def contents(path = nil) contents = [] object = find_object(path || '/') contents << path unless path.nil? || object.nil? if object.is_a? Grit::Tree (object.blobs + object.trees).each do |obj| contents += contents(path.nil? ? obj.basename : File.join(path, obj.basename)) end end contents end |
#distribute ⇒ Object
Push the current state of the repository to each attached remote repository
151 152 153 |
# File 'lib/silo/repository.rb', line 151 def distribute @remotes.each_value { |remote| remote.push } end |
#find_object(path = '/') ⇒ Grit::Blob, Grit::Tree
Returns the object (tree or blob) at the given path inside the repository
160 161 162 |
# File 'lib/silo/repository.rb', line 160 def find_object(path = '/') (path == '/') ? @git.tree : @git.tree/path end |
#git_remotes ⇒ Object
Loads remotes from the backing Git repository's configuration
167 168 169 170 171 172 173 174 |
# File 'lib/silo/repository.rb', line 167 def git_remotes remotes = {} @git.git.remote.split.each do |remote| url = @git.git.config({}, '--get', "remote.#{remote}.url").strip remotes[remote] = Remote::Git.new(self, remote, url) end remotes end |
#history(path = nil) ⇒ Array<Grit::Commit>
Generate a history of Git commits for either the complete repository or a specified file or directory
184 185 186 187 188 189 |
# File 'lib/silo/repository.rb', line 184 def history(path = nil) params = ['--format=raw'] params += ['--', path] unless path.nil? output = @git.git.log({}, *params) Grit::Commit.list_from_string @git, output end |
#in_work_tree(path) {|path| ... } ⇒ Object
Run a block of code with +$GIT_WORK_TREE+ set to a specified path
This executes a block of code while the environment variable +$GIT_WORK_TREE+ is set to a specified path or alternatively the path of a temporary directory.
202 203 204 205 206 207 208 209 210 |
# File 'lib/silo/repository.rb', line 202 def in_work_tree(path) tmp_dir = path == :tmp path = Dir.mktmpdir if tmp_dir old_work_tree = ENV['GIT_WORK_TREE'] ENV['GIT_WORK_TREE'] = path Dir.chdir(path) { yield path } ENV['GIT_WORK_TREE'] = old_work_tree FileUtils.rm_rf path, :secure => true if tmp_dir end |
#info(path) ⇒ Hash<Symbol, Object>
Get information about a file or directory in the repository
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 |
# File 'lib/silo/repository.rb', line 218 def info(path) info = {} object = object! path info[:history] = history path info[:mode] = object.mode info[:name] = object.name info[:path] = path info[:sha] = object.id info[:created] = info[:history].last.committed_date info[:modified] = info[:history].first.committed_date if object.is_a? Grit::Blob info[:mime] = object.mime_type info[:size] = object.size info[:type] = :blob else info[:path] += '/' info[:type] = :tree end info end |
#object!(path) ⇒ Grit::Blob, Grit::Tree
Returns the object (tree or blob) at the given path inside the repository or fail if it does not exist
249 250 251 252 253 |
# File 'lib/silo/repository.rb', line 249 def object!(path) object = find_object path raise FileNotFoundError.new(path) if object.nil? object end |
#prepare ⇒ Object
Prepares the Git repository backing this Silo repository for use with Silo
259 260 261 262 263 264 265 266 |
# File 'lib/silo/repository.rb', line 259 def prepare raise AlreadyPreparedError.new(@path) if prepared? in_work_tree :tmp do FileUtils.touch '.silo' @git.add '.silo' @git.commit_index 'Enabled Silo for this repository' end end |
#prepared? ⇒ Boolean
Return whether the Git repository backing this Silo repository has already been prepared for use with Silo
272 273 274 |
# File 'lib/silo/repository.rb', line 272 def prepared? !(@git.tree/'.silo').nil? end |
#purge(path, prune = true) ⇒ Object
Purges a single file or the complete structure of a directory with the given path from the repository
WARNING: This will cause a complete rewrite of the repository history and therefore deletes the data completely.
285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/silo/repository.rb', line 285 def purge(path, prune = true) object = object! path if object.is_a? Grit::Tree (object.blobs + object.trees).each do |blob| purge File.join(path, blob.basename), prune end else params = ['-f', '--index-filter', "git rm --cached --ignore-unmatch #{path}"] params << '--prune-empty' if prune params << 'HEAD' @git.git.filter_branch({}, *params) end end |
#remove(path) ⇒ Object Also known as: rm
Removes a single file or the complete structure of a directory with the given path from the HEAD revision of the repository
NOTE: The data won't be lost as it will be preserved in the history of the Git repository.
308 309 310 311 312 313 314 315 316 317 |
# File 'lib/silo/repository.rb', line 308 def remove(path) object = object! path path += '/' if object.is_a?(Grit::Tree) && path[-1].chr != '/' index = @git.index index.read_tree 'HEAD' index.delete path type = object.is_a?(Grit::Tree) ? 'directory' : 'file' commit_msg = "Removed #{type} #{path}" index.commit commit_msg, [@git.head.commit.sha] end |
#remove_remote(name) ⇒ Object
Removes the remote with the given name from this repository
324 325 326 327 328 329 |
# File 'lib/silo/repository.rb', line 324 def remove_remote(name) remote = @remotes[name] raise UndefinedRemoteError.new(name) if remote.nil? remote.remove @remotes[name] = nil end |
#restore(path, prefix = '.') ⇒ Object
Restores a single file or the complete structure of a directory with the given path from the repository
337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
# File 'lib/silo/repository.rb', line 337 def restore(path, prefix = '.') object = object! path prefix = File. prefix FileUtils.mkdir_p prefix unless File.exists? prefix file_path = File.join prefix, File.basename(path) if object.is_a? Grit::Tree FileUtils.mkdir file_path unless File.directory? file_path (object.blobs + object.trees).each do |obj| restore File.join(path, obj.basename), file_path end else file = File.new file_path, 'w' file.write object.data file.close end end |