Class: GitDS::Database
Overview
Actually DbConnection to the repository.
Note: all operations should be in exec or transaction blocks. These use a persistent staging index, and are more efficient.
Constant Summary
Constants inherited from Repo
Repo::DEFAULT_BRANCH, Repo::DEFAULT_TAG, Repo::GIT_DIR
Instance Attribute Summary collapse
-
#actor ⇒ Object
Actor to use when performing Database operations.
-
#stale ⇒ Object
readonly
Flag to mark if database has been closed (i.e. connection is invalid).
-
#subscribers ⇒ Object
readonly
Subcribers that are notified when the model is changed.
Attributes inherited from Repo
#current_branch, #last_branch_tag, #path
Class Method Summary collapse
-
.connect(path, create = true) ⇒ Object
Open a connection to database.
-
.connect_as(path, username, email, create = true) ⇒ Object
Connect to a git database as the specified user.
Instance Method Summary collapse
-
#add(path, data = '', on_fs = false) ⇒ Object
Add files to the database.
-
#batch(&block) ⇒ Object
Execute a block using an in-memory Staging index.
-
#branch_and_merge(name = next_branch_tag(), actor = nil, &block) ⇒ Object
Branch-and-merge: Run block in a transaction under a new branch.
-
#close(save = true) ⇒ Object
Close DB connection, writing all changes to disk.
-
#config ⇒ Object
Provides access to the Hash of Git-DS config variables.
-
#delete(path) ⇒ Object
Delete an object from the database.
-
#exec(&block) ⇒ Object
Execute a block in the context of the staging index.
-
#fast_add(path, data = '', on_fs = false) ⇒ Object
Add files to the database without using ExecCmd or Transaction.
-
#head ⇒ Object
Wrapper for Grit::Repo#head that checks if Database has been closed.
-
#index_new ⇒ Object
Wrapper for Grit::Repo#index that checks if Database has been closed.
-
#initialize(path, username = nil, email = nil) ⇒ Database
constructor
Return a connection to the Git DB.
-
#mark(msg) ⇒ Object
Generate a tag object for the most recent commit.
-
#notify ⇒ Object
Notify all subscribers that a change has occurred.
-
#purge ⇒ Object
Delete Database (including entire repository) from disk.
-
#repo_config ⇒ Object
Grit::Repo#config is wrapped by Database#config.
-
#set_author(name, email = nil) ⇒ Object
Set the Git author information for the database connection.
-
#staging ⇒ Object
Wrapper for Grit::Repo#staging that checks if Database has been closed.
-
#subscribe(ident, obj = nil, func = nil, &block) ⇒ Object
Subscribe to change notifications from the model.
-
#transaction(&block) ⇒ Object
Execute a transaction in the context of the staging index.
-
#tree(treeish = 'master', paths = []) ⇒ Object
Wrapper for Grit::Repo#tree that checks if Database has been closed.
-
#unsubscribe(ident) ⇒ Object
Unsubscribe from change notification.
-
#valid? ⇒ Boolean
(also: #connected?)
Return true if the database is valid (i.e. open).
Methods inherited from Repo
#add_files, #branch, #clean_tag, create, #create_branch, #exec_git_cmd, #exec_in_git_dir, #include?, #list, #list_blobs, #list_trees, #merge_branch, #next_branch_tag, #object_data, #path_to_object, #path_to_sha, #raw_tree, #root_sha, #set_branch, #stage, #stage_and_commit, #staging=, #staging?, #tag_object, top_level, #top_level, #tree_contents, #unstage
Constructor Details
#initialize(path, username = nil, email = nil) ⇒ Database
Return a connection to the Git DB. Creates the DB if it does not already exist.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/git-ds/database.rb', line 57 def initialize(path, username=nil, email=nil) @stale = true # DB is always stale until it is initialized init = false if not File.exist? path Repo.create(path) init = true end super(path) @stale = false # DB is connected! if init # initial commit is needed for branches to work smoothly stage { |idx| idx.add('.git-ds/version', "1.0\n") } staging.commit('Database initialized.') unstage end @actor = Grit::Actor.new(username, email) if username @subscribers = {} end |
Instance Attribute Details
#actor ⇒ Object
Actor to use when performing Database operations. All Transaction and ExecCmd objects will use this actor by default.
Default is nil (i.e. let Git read actor from .git/config or ENV).
44 45 46 |
# File 'lib/git-ds/database.rb', line 44 def actor @actor end |
#stale ⇒ Object (readonly)
Flag to mark if database has been closed (i.e. connection is invalid).
36 37 38 |
# File 'lib/git-ds/database.rb', line 36 def stale @stale end |
#subscribers ⇒ Object (readonly)
Subcribers that are notified when the model is changed. This is a Hash of an ident (e.g. a classname, UUID, or symbol) to a 2-element array: a callback method and an (optional) object to pass with that method.
51 52 53 |
# File 'lib/git-ds/database.rb', line 51 def subscribers @subscribers end |
Class Method Details
.connect(path, create = true) ⇒ Object
Open a connection to database.
If ‘create’ is true (the default), a database will be created if one does not exist at ‘path’.
87 88 89 90 |
# File 'lib/git-ds/database.rb', line 87 def self.connect(path, create=true) return nil if (not create) && (not File.exist? path) connect_as(path, nil, nil, create) end |
.connect_as(path, username, email, create = true) ⇒ Object
Connect to a git database as the specified user.
95 96 97 98 |
# File 'lib/git-ds/database.rb', line 95 def self.connect_as(path, username, email, create=true) return nil if (not create) && (not File.exist? path) new(path, username, email) end |
Instance Method Details
#add(path, data = '', on_fs = false) ⇒ Object
Add files to the database. Calls exec to ensure that a write is not performed if a staging index already exists.
237 238 239 |
# File 'lib/git-ds/database.rb', line 237 def add(path, data='', on_fs=false) exec { index.add(path, data, on_fs) } end |
#batch(&block) ⇒ Object
Execute a block using an in-memory Staging index.
This is an optimization. It writes the current index to the git staging index on disk, replaces it with an in-memory index that DOES NOT write to the object tree on disk, invokes the block, writes the in-memory index to the git staging index on disk, then reads the staging index into the repo/database and makes it the current index.
The idea is to reduce disk writes caused by exec and transaction, which can end up being very costly when nested.
NOTE: branch-and-merge will fail if in batch mode (TODO: FIX).
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 |
# File 'lib/git-ds/database.rb', line 355 def batch(&block) # NOTE: the use of 'self.staging' is quite important in this method. # write current index to git-staging-index idx = self.staging? ? self.staging : nil idx.sync if idx # replace current index with an in-mem staging index unstage self.staging=StageMemIndex.read(self) begin yield staging if block_given? rescue Exception => e # ensure index is discarded if there is a problem unstage self.staging if idx raise e end # write in-mem staging index to git-staging-index self.staging.force_sync # read git-staging-index if appropriate unstage self.staging if idx end |
#branch_and_merge(name = next_branch_tag(), actor = nil, &block) ⇒ Object
Branch-and-merge: Run block in a transaction under a new branch. If the transaction succeeds, the branch is merged back into master.
See Database#transaction .
307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 |
# File 'lib/git-ds/database.rb', line 307 def branch_and_merge(name=next_branch_tag(), actor=nil, &block) raise InvalidDbError if @stale # Force a commit before the merge # TODO: determine if this is really necessary staging.sync staging.commit('auto-commit before branch-and-merge', self.actor) # ensure staging index is nil [in case branch name was re-used] unstage # save old actor old_actor = self.actor self.actor = actor if actor sha = commits.last ? commits.last.id : nil tag = create_branch(name, sha) set_branch(tag, self.actor) # execute block in a transaction rv = true begin transaction(&block) merge_branch(tag, self.actor) rescue Exception =>e rv = false end # restore actor self.actor = old_actor if actor rv end |
#close(save = true) ⇒ Object
Close DB connection, writing all changes to disk.
NOTE: This does not create a commit! Ony the staging index changes.
105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/git-ds/database.rb', line 105 def close(save=true) raise InvalidDbError if @stale if save && staging? self.staging.write end unstage @stale = true # TODO: remove all locks etc end |
#config ⇒ Object
Provides access to the Hash of Git-DS config variables.
144 145 146 |
# File 'lib/git-ds/database.rb', line 144 def config @git_config ||= RepoConfig.new(self, 'git-ds') end |
#delete(path) ⇒ Object
Delete an object from the database.
257 258 259 |
# File 'lib/git-ds/database.rb', line 257 def delete(path) exec { index.delete(path) } end |
#exec(&block) ⇒ Object
Execute a block in the context of the staging index.
See ExecCmd.
200 201 202 203 204 205 206 207 208 209 210 211 212 213 |
# File 'lib/git-ds/database.rb', line 200 def exec(&block) raise InvalidDbError if @stale return exec_in_staging(true, &block) if self.staging? begin self.staging exec_in_staging(false, &block) self.staging.write ensure self.unstage end end |
#fast_add(path, data = '', on_fs = false) ⇒ Object
Add files to the database without using ExecCmd or Transaction. Care must be taken in using this as it does not sync/build the staging index, so it must be wrapped in an ExecCmd or Transaction, or the index must be synced/built after all of the fast_add calls are complete.
See Database#add.
249 250 251 252 |
# File 'lib/git-ds/database.rb', line 249 def fast_add(path, data='', on_fs=false) # TODO: verify that this will suffice index.add(path, data, on_fs) end |
#head ⇒ Object
Wrapper for Grit::Repo#head that checks if Database has been closed.
280 281 282 283 |
# File 'lib/git-ds/database.rb', line 280 def head raise InvalidDbError if @stale super end |
#index_new ⇒ Object
Wrapper for Grit::Repo#index that checks if Database has been closed.
264 265 266 267 |
# File 'lib/git-ds/database.rb', line 264 def index_new raise InvalidDbError if @stale super end |
#mark(msg) ⇒ Object
Generate a tag object for the most recent commit.
296 297 298 |
# File 'lib/git-ds/database.rb', line 296 def mark(msg) tag_object(msg, commits.last.id) end |
#notify ⇒ Object
Notify all subscribers that a change has occurred.
183 184 185 |
# File 'lib/git-ds/database.rb', line 183 def notify @subscribers.each { |ident, (block,obj)| block.call(obj) } end |
#purge ⇒ Object
Delete Database (including entire repository) from disk.
129 130 131 132 133 134 |
# File 'lib/git-ds/database.rb', line 129 def purge raise InvalidDbError if @stale close(false) FileUtils.remove_dir(@path) if ::File.exist?(@path) end |
#repo_config ⇒ Object
Grit::Repo#config is wrapped by Database#config.
139 |
# File 'lib/git-ds/database.rb', line 139 alias :repo_config :config |
#set_author(name, email = nil) ⇒ Object
Set the Git author information for the database connection. Wrapper for actor=.
152 153 154 |
# File 'lib/git-ds/database.rb', line 152 def (name, email=nil) self.actor = name ? Grit::Actor.new(name, (email ? email : '')) : nil end |
#staging ⇒ Object
Wrapper for Grit::Repo#staging that checks if Database has been closed.
272 273 274 275 |
# File 'lib/git-ds/database.rb', line 272 def staging raise InvalidDbError if @stale super end |
#subscribe(ident, obj = nil, func = nil, &block) ⇒ Object
Subscribe to change notifications from the model. The provided callback will be invoked whenever the model is modified (specifically, when an outer Transaction or ExecCmd is completed).
A subscriber can use either block or argument syntax:
def func_cb(arg)
...
end
model.subscribe( self.ident, arg, func_cb )
# block callback
model.subscribe( self.ident ) { ... }
# block callback where arg is specified in advance
model.subscribe( self.ident, arg ) { |arg| ... }
175 176 177 178 |
# File 'lib/git-ds/database.rb', line 175 def subscribe(ident, obj=nil, func=nil, &block) cb = (block_given?) ? block : func @subscribers[ident] = [cb, obj] end |
#transaction(&block) ⇒ Object
Execute a transaction in the context of the staging index.
See Transaction.
220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/git-ds/database.rb', line 220 def transaction(&block) raise InvalidDbError if @stale return transaction_in_staging(true, &block) if self.staging? begin transaction_in_staging(false, &block) ensure self.unstage end end |
#tree(treeish = 'master', paths = []) ⇒ Object
Wrapper for Grit::Repo#tree that checks if Database has been closed.
288 289 290 291 |
# File 'lib/git-ds/database.rb', line 288 def tree(treeish = 'master', paths = []) raise InvalidDbError if @stale super end |
#unsubscribe(ident) ⇒ Object
Unsubscribe from change notification.
190 191 192 |
# File 'lib/git-ds/database.rb', line 190 def unsubscribe(ident) @subscribers.delete(ident) end |
#valid? ⇒ Boolean Also known as: connected?
Return true if the database is valid (i.e. open)
120 121 122 |
# File 'lib/git-ds/database.rb', line 120 def valid? @stale == false end |