Class: GitKeyvalue::KeyValueRepo
- Inherits:
-
Object
- Object
- GitKeyvalue::KeyValueRepo
- Defined in:
- lib/git_keyvalue.rb
Overview
Provides a GET/PUT-style interface for a git repo. In effect, it presents the repo as a key/value store, where the keys are file paths (relative to the repo’s root) and the values are the contents of those files.
Requirements
Known good with ruby 1.9.3 and git 1.7.9.6.
Performance & resource usage
Not performant. Must clone the repo before performing any operations. Needs whatever disk space is required for a repo clone. Clears this space when the object is destroyed.
Object lifetime
Stores the local repo in the OS’s temporary directory. Therefore, you should not expect this object to remain valid across automated housekeeping events that might destroy this directory.
Footnote on shallow cloning
Okay, technically, this does not clone the entire repo. For better performance it does a “shallow clone” of the repo, which grabs only the files necessary to represent the HEAD commit. Such a shallow clone is officially enough to enable GET operations, which read only those files anyway. However, according to the git-clone docs, the shallow clone is not officially enough to enable git-push to update those files on the remote repo. However, this seems like a bug in the git-clone docs since, in reality, a shallow clone is enough and should be enough for pushing new commits, since a new commit only needs to reference its parent commit(s).
The bottom line: by using shallow cloning for better perf, this class is relying on undocumented behavior in git-push. This works fine as of git version 1.7.9.6. I see no reason to expect this to break in the future, since this undocumented behavior follows directly from git’s data model, which is stable. However, if it does break, and you want to switch to using the documented git behavior, then set USE_SHALLOW_CLONING to false.
Instance Attribute Summary collapse
-
#path_to_repo ⇒ String
readonly
Absolute filesystem path of the local repo.
-
#repo_url ⇒ String
readonly
URL of the remote git repo.
Instance Method Summary collapse
-
#get(path_in_repo) ⇒ String?
Get contents of a file, or nil if it does not exist.
-
#getfile(path_in_repo, dest_path) ⇒ Object
Copies the repo file at
path_in_repo
todest_path
. -
#initialize(repo_url) ⇒ KeyValueRepo
constructor
Clones the remote repo, failing if it is invalid or inaccessible.
-
#put(path_in_repo, string_value) ⇒ Object
Sets the contents of the file at
path_in_repo
, creating it if necessary. -
#putfile(path_in_repo, src_file_path) ⇒ Object
Sets the contents of the file at path, creating it if necessary.
Constructor Details
#initialize(repo_url) ⇒ KeyValueRepo
Clones the remote repo, failing if it is invalid or inaccessible.
As it clones the entire repo, this may take a long time if you are manipulating a large remote repo. Keeps the repo in the OS’s temporary directory, so you should not expect this object to remain valid across automated cleanups of that temporary directory (which happen, for instance, typically at restart).
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
# File 'lib/git_keyvalue.rb', line 185 def initialize(repo_url) @repo_url = repo_url @path_to_repo = Dir.mktmpdir('KeyValueGitTempDir') if USE_SHALLOW_CLONING # experimental variant. uses undocumented behaviour of # git-clone. This is because setting --depth 1 produces a # shallow clone, which according to the docs does not let you # git-push aftewards, but in reality should and does let you # git-push. This is a bug in the git documentation. success = system('git','clone','--depth','1',@repo_url,@path_to_repo) else # stable variant. uses documented behavior of git-clone success = system('git','clone',@repo_url,@path_to_repo) end if not success raise KeyValueGitError, 'Failed to initialize, because could not clone the remote repo: ' + repo_url + '. Please verify this is a valid git URL, and that any required network connection or login credentials are available.' end ObjectSpace.define_finalizer(self, self.class.make_finalizer(@path_to_repo)) end |
Instance Attribute Details
#path_to_repo ⇒ String (readonly)
Returns absolute filesystem path of the local repo.
171 172 173 |
# File 'lib/git_keyvalue.rb', line 171 def path_to_repo @path_to_repo end |
#repo_url ⇒ String (readonly)
Returns URL of the remote git repo.
169 170 171 |
# File 'lib/git_keyvalue.rb', line 169 def repo_url @repo_url end |
Instance Method Details
#get(path_in_repo) ⇒ String?
Get contents of a file, or nil if it does not exist
211 212 213 |
# File 'lib/git_keyvalue.rb', line 211 def get(path_in_repo) outer_get(path_in_repo) { |abspath| File.read(abspath) } end |
#getfile(path_in_repo, dest_path) ⇒ Object
Copies the repo file at path_in_repo
to dest_path
Does no validation regarding dest_path. If dest_path points to a file, it will overwrite that file. If it points to a directory, it will copy into that directory.
224 225 226 |
# File 'lib/git_keyvalue.rb', line 224 def getfile(path_in_repo, dest_path) outer_get(path_in_repo) { |abspath| FileUtils.cp(abspath, dest_path) } end |
#put(path_in_repo, string_value) ⇒ Object
Sets the contents of the file at path_in_repo
, creating it if necessary
234 235 236 237 238 239 240 241 242 |
# File 'lib/git_keyvalue.rb', line 234 def put(path_in_repo, string_value) path_in_repo = blindly_relativize_path(path_in_repo) outer_put(path_in_repo) { # create parent directories if needed FileUtils.mkdir_p(File.dirname(path_in_repo)) # write new file contents File.open(path_in_repo,'w') { |f| f.write(string_value) } } end |
#putfile(path_in_repo, src_file_path) ⇒ Object
Sets the contents of the file at path, creating it if necessary
250 251 252 253 254 255 256 257 258 259 |
# File 'lib/git_keyvalue.rb', line 250 def putfile(path_in_repo, src_file_path) path_in_repo = blindly_relativize_path(path_in_repo) outer_put(path_in_repo) { # create parent directories if needed FileUtils.mkdir_p(File.dirname(path_in_repo)) # copy file at src_file_path into the path_in_repo abspath = Pathname.new(File.join(@path_to_repo,path_in_repo)).to_s FileUtils.cp(src_file_path, abspath) } end |