summaryrefslogtreecommitdiff
path: root/lib/gitlab/git/index.rb
diff options
context:
space:
mode:
authorDouwe Maan <douwe@selenight.nl>2017-02-13 15:09:36 -0600
committerDouwe Maan <douwe@selenight.nl>2017-02-24 09:55:01 -0600
commit0625af3bcb75b3186a3286eee662a7ff8442f130 (patch)
treeb35fbb083efa3b5c39c8c154f02e38e0e5ee29c7 /lib/gitlab/git/index.rb
parentfaaca5e191f9fe3894ad7587b42495fcbcab9328 (diff)
downloadgitlab-ce-0625af3bcb75b3186a3286eee662a7ff8442f130.tar.gz
Consistently create, update, and delete files, taking CRLF settings into account
Diffstat (limited to 'lib/gitlab/git/index.rb')
-rw-r--r--lib/gitlab/git/index.rb124
1 files changed, 124 insertions, 0 deletions
diff --git a/lib/gitlab/git/index.rb b/lib/gitlab/git/index.rb
new file mode 100644
index 00000000000..3d0000879f8
--- /dev/null
+++ b/lib/gitlab/git/index.rb
@@ -0,0 +1,124 @@
+module Gitlab
+ module Git
+ class Index
+ DEFAULT_MODE = 0o100644
+
+ attr_reader :repository, :raw_index
+
+ def initialize(repository)
+ @repository = repository
+ @raw_index = repository.rugged.index
+ end
+
+ def read_tree(tree)
+ raw_index.read_tree(tree)
+ end
+
+ def write_tree
+ raw_index.write_tree(repository.rugged)
+ end
+
+ def get(*args)
+ raw_index.get(*args)
+ end
+
+ def create(options)
+ normalize_options!(options)
+
+ file_entry = raw_index.get(options[:file_path])
+ if file_entry
+ raise Gitlab::Git::Repository::InvalidBlobName.new("Filename already exists")
+ end
+
+ add_blob(options)
+ end
+
+ def create_dir(options)
+ normalize_options!(options)
+
+ file_entry = raw_index.get(options[:file_path])
+ if file_entry
+ raise Gitlab::Git::Repository::InvalidBlobName.new("Directory already exists as a file")
+ end
+
+ options = options.dup
+ options[:file_path] += '/.gitkeep'
+ options[:content] = ''
+
+ add_blob(options)
+ end
+
+ def update(options)
+ normalize_options!(options)
+
+ file_entry = raw_index.get(options[:file_path])
+ unless file_entry
+ raise Gitlab::Git::Repository::InvalidBlobName.new("File doesn't exist")
+ end
+
+ add_blob(options, mode: file_entry[:mode])
+ end
+
+ def move(options)
+ normalize_options!(options)
+
+ file_entry = raw_index.get(options[:previous_path])
+ unless file_entry
+ raise Gitlab::Git::Repository::InvalidBlobName.new("File doesn't exist")
+ end
+
+ raw_index.remove(options[:previous_path])
+
+ add_blob(options, mode: file_entry[:mode])
+ end
+
+ def delete(options)
+ normalize_options!(options)
+
+ file_entry = raw_index.get(options[:file_path])
+ unless file_entry
+ raise Gitlab::Git::Repository::InvalidBlobName.new("File doesn't exist")
+ end
+
+ raw_index.remove(options[:file_path])
+ end
+
+ private
+
+ def normalize_options!(options)
+ options[:file_path] = normalize_path(options[:file_path]) if options[:file_path]
+ options[:previous_path] = normalize_path(options[:previous_path]) if options[:previous_path]
+ end
+
+ def normalize_path(path)
+ pathname = Gitlab::Git::PathHelper.normalize_path(path)
+
+ if pathname.each_filename.include?('..')
+ raise Gitlab::Git::Repository::InvalidBlobName.new('Invalid path')
+ end
+
+ pathname.to_s
+ end
+
+ def add_blob(options, mode: nil)
+ content = options[:content]
+ return unless content
+
+ content = Base64.decode64(content) if options[:encoding] == 'base64'
+
+ detect = CharlockHolmes::EncodingDetector.new.detect(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 = repository.rugged.write(content, :blob)
+
+ raw_index.add(path: options[:file_path], oid: oid, mode: mode || DEFAULT_MODE)
+ rescue Rugged::IndexError => e
+ raise Gitlab::Git::Repository::InvalidBlobName.new(e.message)
+ end
+ end
+ end
+end