20161226122833_remove_dot_git_from_usernames.rb 3.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
# See http://doc.gitlab.com/ce/development/migration_style_guide.html
# for more information on how to write migrations for GitLab.

class RemoveDotGitFromUsernames < ActiveRecord::Migration
  include Gitlab::Database::MigrationHelpers
  include Gitlab::ShellAdapter

  # Set this constant to true if this migration requires downtime.
  DOWNTIME = false

  def up
    invalid_users.each do |user|
      id = user['id']
      namespace_id = user['namespace_id']
      path_was = user['username']
      path_was_wildcard = quote_string("#{path_was}/%")
17
      path = quote_string(new_path(path_was))
18

19
      move_namespace(namespace_id, path_was, path)
20 21 22 23 24 25 26 27 28 29 30

      begin
        execute "UPDATE routes SET path = '#{path}' WHERE source_type = 'Namespace' AND source_id = #{namespace_id}"
        execute "UPDATE namespaces SET path = '#{path}' WHERE id = #{namespace_id}"
        execute "UPDATE users SET username = '#{path}' WHERE id = #{id}"

        select_all("SELECT id, path FROM routes WHERE path LIKE '#{path_was_wildcard}'").each do |route|
          new_path = "#{path}/#{route['path'].split('/').last}"
          execute "UPDATE routes SET path = '#{new_path}' WHERE id = #{route['id']}"
        end
      rescue => e
31
        say("Couldn't update routes for path #{path_was} to #{path}")
32 33
        # Move namespace back
        move_namespace(namespace_id, path, path_was)
34 35

        raise e
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
      end
    end
  end

  def down
    # nothing to do here
  end

  private

  def invalid_users
    select_all("SELECT u.id, u.username, n.path AS namespace_path, n.id AS namespace_id FROM users u
                INNER JOIN namespaces n ON n.owner_id = u.id
                WHERE n.type is NULL AND n.path LIKE '%.git'")
  end

  def route_exists?(path)
    select_all("SELECT id, path FROM routes WHERE path = '#{quote_string(path)}'").present?
  end

56 57
  def path_exists?(path, repository_storage_path)
    repository_storage_path && gitlab_shell.exists?(repository_storage_path, path)
J
James Lopez 已提交
58 59
  end

60 61
  # Accepts invalid path like test.git and returns test_git or
  # test_git1 if test_git already taken
62
  def new_path(path)
63 64 65 66
    # To stay closer with original name and reduce risk of duplicates
    # we rename suffix instead of removing it
    path = path.sub(/\.git\z/, '_git')

67 68 69 70
    check_routes(path.dup, 0, path)
  end

  def check_routes(base, counter, path)
J
James Lopez 已提交
71 72
    route_exists = route_exists?(path)

J
James Lopez 已提交
73
    Gitlab.config.repositories.storages.each_value do |storage|
74
      if route_exists || path_exists?(path, storage['path'])
75 76
        counter += 1
        path = "#{base}#{counter}"
77

J
James Lopez 已提交
78
        return check_routes(base, counter, path)
79
      end
80 81 82 83 84
    end

    path
  end

85
  def move_namespace(namespace_id, path_was, path)
86
    repository_storage_paths = select_all("SELECT distinct(repository_storage) FROM projects WHERE namespace_id = #{namespace_id}").map do |row|
87
      Gitlab.config.repositories.storages[row['repository_storage']]['path']
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
    end.compact

    # Move the namespace directory in all storages paths used by member projects
    repository_storage_paths.each do |repository_storage_path|
      # Ensure old directory exists before moving it
      gitlab_shell.add_namespace(repository_storage_path, path_was)

      unless gitlab_shell.mv_namespace(repository_storage_path, path_was, path)
        Rails.logger.error "Exception moving path #{repository_storage_path} from #{path_was} to #{path}"

        # if we cannot move namespace directory we should rollback
        # db changes in order to prevent out of sync between db and fs
        raise Exception.new('namespace directory cannot be moved')
      end
    end

104 105 106 107 108 109 110 111 112
    begin
      Gitlab::UploadsTransfer.new.rename_namespace(path_was, path)
    rescue => e
      if path.nil?
        say("Couldn't find a storage path for #{namespace_id}, #{path_was} -- skipping")
      else
        raise e
      end
    end
113 114
  end
end