diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/api/commits.rb | 7 | ||||
-rw-r--r-- | lib/gitlab/git/blob.rb | 157 | ||||
-rw-r--r-- | lib/gitlab/git/index.rb | 124 | ||||
-rw-r--r-- | lib/gitlab/git/repository.rb | 51 |
4 files changed, 124 insertions, 215 deletions
diff --git a/lib/api/commits.rb b/lib/api/commits.rb index 9ce396d4660..fd03e92264d 100644 --- a/lib/api/commits.rb +++ b/lib/api/commits.rb @@ -52,13 +52,6 @@ module API attrs = declared_params.merge(start_branch: declared_params[:branch], target_branch: declared_params[:branch]) - attrs[:actions].map! do |action| - action[:action] = action[:action].to_sym - action[:file_path].slice!(0) if action[:file_path] && action[:file_path].start_with?('/') - action[:previous_path].slice!(0) if action[:previous_path] && action[:previous_path].start_with?('/') - action - end - result = ::Files::MultiService.new(user_project, current_user, attrs).execute if result[:status] == :success diff --git a/lib/gitlab/git/blob.rb b/lib/gitlab/git/blob.rb index b742d9e1e4b..e56eb0d3beb 100644 --- a/lib/gitlab/git/blob.rb +++ b/lib/gitlab/git/blob.rb @@ -93,163 +93,6 @@ module Gitlab commit_id: sha, ) end - - # 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: 'user@example.com', - # name: 'Test User', - # time: Time.now - # }, - # committer: { - # email: 'user@example.com', - # name: 'Test User', - # time: Time.now - # }, - # commit: { - # message: 'Wow such commit', - # branch: 'master', - # update_ref: false - # } - # - # rubocop:disable Metrics/AbcSize - # rubocop:disable Metrics/CyclomaticComplexity - # rubocop:disable Metrics/PerceivedComplexity - def commit(repository, options, action = :add) - file = options[:file] - update = file[:update].nil? ? true : file[:update] - author = options[:author] - committer = options[:committer] - commit = options[:commit] - repo = repository.rugged - ref = commit[:branch] - update_ref = commit[:update_ref].nil? ? true : commit[:update_ref] - parents = [] - mode = 0o100644 - - unless ref.start_with?('refs/') - ref = 'refs/heads/' + ref - end - - path_name = Gitlab::Git::PathHelper.normalize_path(file[:path]) - # Abort if any invalid characters remain (e.g. ../foo) - raise Gitlab::Git::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 Gitlab::Git::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 - file_entry = index.get(filename) - - if action == :rename - old_path_name = Gitlab::Git::PathHelper.normalize_path(file[:previous_path]) - old_filename = old_path_name.to_s - file_entry = index.get(old_filename) - index.remove(old_filename) unless file_entry.blank? - end - - if file_entry - raise Gitlab::Git::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] = author - opts[:committer] = committer - opts[:message] = commit[:message] - opts[:parents] = parents - opts[:update_ref] = ref if update_ref - - Rugged::Commit.create(repo, opts) - end - # rubocop:enable Metrics/AbcSize - # rubocop:enable Metrics/CyclomaticComplexity - # rubocop:enable Metrics/PerceivedComplexity - - # Remove file from repository and return commit sha - # - # options should contain next structure: - # file: { - # path: 'documents/story.txt' - # }, - # author: { - # email: 'user@example.com', - # name: 'Test User', - # time: Time.now - # }, - # committer: { - # email: 'user@example.com', - # name: 'Test User', - # time: Time.now - # }, - # commit: { - # message: 'Remove FILENAME', - # branch: 'master' - # } - # - def remove(repository, options) - commit(repository, options, :remove) - end - - # Rename file from repository and return commit sha - # - # options should contain next structure: - # file: { - # previous_path: 'documents/old_story.txt' - # path: 'documents/story.txt' - # content: 'Lorem ipsum...', - # update: true - # }, - # author: { - # email: 'user@example.com', - # name: 'Test User', - # time: Time.now - # }, - # committer: { - # email: 'user@example.com', - # name: 'Test User', - # time: Time.now - # }, - # commit: { - # message: 'Rename FILENAME', - # branch: 'master' - # } - # - def rename(repository, options) - commit(repository, options, :rename) - end end def initialize(options) 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 diff --git a/lib/gitlab/git/repository.rb b/lib/gitlab/git/repository.rb index 4b6ad8037ce..b8354d7bf04 100644 --- a/lib/gitlab/git/repository.rb +++ b/lib/gitlab/git/repository.rb @@ -837,57 +837,6 @@ module Gitlab rugged.config['core.autocrlf'] = AUTOCRLF_VALUES.invert[value] end - # Create a new directory with a .gitkeep file. Creates - # all required nested directories (i.e. mkdir -p behavior) - # - # options should contain next structure: - # author: { - # email: 'user@example.com', - # name: 'Test User', - # time: Time.now - # }, - # committer: { - # email: 'user@example.com', - # name: 'Test User', - # time: Time.now - # }, - # commit: { - # message: 'Wow such commit', - # branch: 'master', - # update_ref: false - # } - def mkdir(path, options = {}) - # Check if this directory exists; if it does, then don't bother - # adding .gitkeep file. - ref = options[:commit][:branch] - path = Gitlab::Git::PathHelper.normalize_path(path).to_s - rugged_ref = rugged.ref(ref) - - raise InvalidRef.new("Invalid ref") if rugged_ref.nil? - - target_commit = rugged_ref.target - - raise InvalidRef.new("Invalid target commit") if target_commit.nil? - - entry = tree_entry(target_commit, path) - - if entry - if entry[:type] == :blob - raise InvalidBlobName.new("Directory already exists as a file") - else - raise InvalidBlobName.new("Directory already exists") - end - end - - options[:file] = { - content: '', - path: "#{path}/.gitkeep", - update: true - } - - Gitlab::Git::Blob.commit(self, options) - end - # Returns result like "git ls-files" , recursive and full file path # # Ex. |