Class: Gitlab::Git::Blob
- Inherits:
-
Object
- Object
- Gitlab::Git::Blob
- Includes:
- EncodingHelper, Linguist::BlobHelper
- Defined in:
- lib/gitlab_git/blob.rb
Constant Summary collapse
- DATA_FRAGMENT_SIZE =
This number needs to be large enough to allow reliable content / encoding detection (Linguist) and LFS pointer parsing. All other cases where we need full blob data should use load_all_data!.
1024
Constants included from EncodingHelper
EncodingHelper::ENCODING_CONFIDENCE_THRESHOLD
Instance Attribute Summary collapse
-
#commit_id ⇒ Object
Returns the value of attribute commit_id.
-
#data ⇒ Object
Returns the value of attribute data.
-
#id ⇒ Object
Returns the value of attribute id.
-
#mode ⇒ Object
Returns the value of attribute mode.
-
#name ⇒ Object
Returns the value of attribute name.
-
#path ⇒ Object
Returns the value of attribute path.
-
#size ⇒ Object
Returns the value of attribute size.
Class Method Summary collapse
-
.commit(repository, options, action = :add) ⇒ Object
Commit file in repository and return commit sha.
- .find(repository, sha, path) ⇒ Object
-
.find_entry_by_path(repository, root_id, path) ⇒ Object
Recursive search of blob id by path.
- .raw(repository, sha) ⇒ Object
-
.remove(repository, options) ⇒ Object
Remove file from repository and return commit sha.
- .submodule_blob(blob_entry, path, sha) ⇒ Object
Instance Method Summary collapse
- #empty? ⇒ Boolean
-
#initialize(options) ⇒ Blob
constructor
A new instance of Blob.
- #lfs_oid ⇒ Object
-
#lfs_pointer? ⇒ Boolean
Valid LFS object pointer is a text file consisting of version oid size see github.com/github/git-lfs/blob/v1.1.0/docs/spec.md#the-pointer.
- #lfs_size ⇒ Object
-
#load_all_data!(repository) ⇒ Object
Load all blob data (not just the first DATA_FRAGMENT_SIZE bytes) into memory as a Ruby string.
Methods included from EncodingHelper
Constructor Details
#initialize(options) ⇒ Blob
Returns a new instance of Blob.
211 212 213 214 215 |
# File 'lib/gitlab_git/blob.rb', line 211 def initialize() %w(id name path size data mode commit_id).each do |key| self.send("#{key}=", [key.to_sym]) end end |
Instance Attribute Details
#commit_id ⇒ Object
Returns the value of attribute commit_id.
15 16 17 |
# File 'lib/gitlab_git/blob.rb', line 15 def commit_id @commit_id end |
#data ⇒ Object
Returns the value of attribute data.
15 16 17 |
# File 'lib/gitlab_git/blob.rb', line 15 def data @data end |
#id ⇒ Object
Returns the value of attribute id.
15 16 17 |
# File 'lib/gitlab_git/blob.rb', line 15 def id @id end |
#mode ⇒ Object
Returns the value of attribute mode.
15 16 17 |
# File 'lib/gitlab_git/blob.rb', line 15 def mode @mode end |
#name ⇒ Object
Returns the value of attribute name.
15 16 17 |
# File 'lib/gitlab_git/blob.rb', line 15 def name @name end |
#path ⇒ Object
Returns the value of attribute path.
15 16 17 |
# File 'lib/gitlab_git/blob.rb', line 15 def path @path end |
#size ⇒ Object
Returns the value of attribute size.
15 16 17 |
# File 'lib/gitlab_git/blob.rb', line 15 def size @size end |
Class Method Details
.commit(repository, options, action = :add) ⇒ Object
Commit file in repository and return commit sha
options should contain next structure:
file: {
content: 'Lorem ipsum...',
path: 'documents/story.txt',
update: true
},
author: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
committer: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Wow such commit',
branch: 'master'
}
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 |
# File 'lib/gitlab_git/blob.rb', line 120 def commit(repository, , action = :add) file = [:file] update = file[:update].nil? ? true : file[:update] = [:author] committer = [:committer] commit = [:commit] repo = repository.rugged ref = commit[:branch] parents = [] unless ref.start_with?('refs/') ref = 'refs/heads/' + ref end path_name = PathHelper.normalize_path(file[:path]) # Abort if any invalid characters remain (e.g. ../foo) raise Repository::InvalidBlobName.new("Invalid path") if path_name.each_filename.to_a.include?('..') filename = path_name.to_s index = repo.index unless repo.empty? rugged_ref = repo.references[ref] raise Repository::InvalidRef.new("Invalid branch name") unless rugged_ref last_commit = rugged_ref.target index.read_tree(last_commit.tree) parents = [last_commit] end if action == :remove index.remove(filename) else mode = 0100644 file_entry = index.get(filename) if file_entry raise Repository::InvalidBlobName.new("Filename already exists; update not allowed") unless update # Preserve the current file mode if one is available mode = file_entry[:mode] if file_entry[:mode] end content = file[:content] detect = CharlockHolmes::EncodingDetector.new.detect(content) if content unless detect && detect[:type] == :binary # When writing to the repo directly as we are doing here, # the `core.autocrlf` config isn't taken into account. content.gsub!("\r\n", "\n") if repository.autocrlf end oid = repo.write(content, :blob) index.add(path: filename, oid: oid, mode: mode) end opts = {} opts[:tree] = index.write_tree(repo) opts[:author] = opts[:committer] = committer opts[:message] = commit[:message] opts[:parents] = parents opts[:update_ref] = ref Rugged::Commit.create(repo, opts) end |
.find(repository, sha, path) ⇒ Object
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 |
# File 'lib/gitlab_git/blob.rb', line 18 def find(repository, sha, path) commit = repository.lookup(sha) root_tree = commit.tree blob_entry = find_entry_by_path(repository, root_tree.oid, path) return nil unless blob_entry if blob_entry[:type] == :commit submodule_blob(blob_entry, path, sha) else blob = repository.lookup(blob_entry[:oid]) if blob Blob.new( id: blob.oid, name: blob_entry[:name], size: blob.size, data: blob.content(DATA_FRAGMENT_SIZE), mode: blob_entry[:filemode].to_s(8), path: path, commit_id: sha, ) end end end |
.find_entry_by_path(repository, root_id, path) ⇒ Object
Recursive search of blob id by path
Ex.
blog/ # oid: 1a
app/ # oid: 2a
models/ # oid: 3a
file.rb # oid: 4a
Blob.find_entry_by_path(repo, ‘1a’, ‘app/file.rb’) # => ‘4a’
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/gitlab_git/blob.rb', line 66 def find_entry_by_path(repository, root_id, path) root_tree = repository.lookup(root_id) # Strip leading slashes path[/^\/*/] = '' path_arr = path.split('/') entry = root_tree.find do |entry| entry[:name] == path_arr[0] end return nil unless entry if path_arr.size > 1 return nil unless entry[:type] == :tree path_arr.shift find_entry_by_path(repository, entry[:oid], path_arr.join('/')) else [:blob, :commit].include?(entry[:type]) ? entry : nil end end |
.raw(repository, sha) ⇒ Object
45 46 47 48 49 50 51 52 53 |
# File 'lib/gitlab_git/blob.rb', line 45 def raw(repository, sha) blob = repository.lookup(sha) Blob.new( id: blob.oid, size: blob.size, data: blob.content(DATA_FRAGMENT_SIZE), ) end |
.remove(repository, options) ⇒ Object
Remove file from repository and return commit sha
options should contain next structure:
file: {
path: 'documents/story.txt'
},
author: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
committer: {
email: '[email protected]',
name: 'Test User',
time: Time.now
},
commit: {
message: 'Remove FILENAME',
branch: 'master'
}
206 207 208 |
# File 'lib/gitlab_git/blob.rb', line 206 def remove(repository, ) commit(repository, , :remove) end |
Instance Method Details
#empty? ⇒ Boolean
217 218 219 |
# File 'lib/gitlab_git/blob.rb', line 217 def empty? !data || data == '' end |
#lfs_oid ⇒ Object
246 247 248 249 250 251 252 253 |
# File 'lib/gitlab_git/blob.rb', line 246 def lfs_oid if has_lfs_version_key? oid = data.match(/(?<=sha256:)([0-9a-f]{64})/) return oid[1] if oid end nil end |
#lfs_pointer? ⇒ Boolean
Valid LFS object pointer is a text file consisting of version oid size see github.com/github/git-lfs/blob/v1.1.0/docs/spec.md#the-pointer
242 243 244 |
# File 'lib/gitlab_git/blob.rb', line 242 def lfs_pointer? has_lfs_version_key? && lfs_oid.present? && lfs_size.present? end |
#lfs_size ⇒ Object
255 256 257 258 259 260 261 262 |
# File 'lib/gitlab_git/blob.rb', line 255 def lfs_size if has_lfs_version_key? size = data.match(/(?<=size )([0-9]+)/) return size[1] if size end nil end |
#load_all_data!(repository) ⇒ Object
Load all blob data (not just the first DATA_FRAGMENT_SIZE bytes) into memory as a Ruby string.
227 228 229 230 231 |
# File 'lib/gitlab_git/blob.rb', line 227 def load_all_data!(repository) return if @data == '' # don't mess with submodule blobs @data = repository.lookup(id).content end |