From 27f54bebb29a1e56251ac2d669c2883aeaf1cb1c Mon Sep 17 00:00:00 2001 From: Bob Van Landuyt Date: Fri, 14 Apr 2017 19:29:22 +0200 Subject: Use objects for renaming namespaces and projects --- .../migration_classes.rb | 1 + .../rename_reserved_paths_migration/namespaces.rb | 70 -------------- .../rename_reserved_paths_migration/projects.rb | 38 -------- .../rename_reserved_paths_migration/rename_base.rb | 103 +++++++++++++++++++++ .../rename_namespaces.rb | 70 ++++++++++++++ .../rename_projects.rb | 38 ++++++++ 6 files changed, 212 insertions(+), 108 deletions(-) delete mode 100644 lib/gitlab/database/rename_reserved_paths_migration/namespaces.rb delete mode 100644 lib/gitlab/database/rename_reserved_paths_migration/projects.rb create mode 100644 lib/gitlab/database/rename_reserved_paths_migration/rename_base.rb create mode 100644 lib/gitlab/database/rename_reserved_paths_migration/rename_namespaces.rb create mode 100644 lib/gitlab/database/rename_reserved_paths_migration/rename_projects.rb (limited to 'lib/gitlab/database/rename_reserved_paths_migration') diff --git a/lib/gitlab/database/rename_reserved_paths_migration/migration_classes.rb b/lib/gitlab/database/rename_reserved_paths_migration/migration_classes.rb index d725402ace4..9133b97d239 100644 --- a/lib/gitlab/database/rename_reserved_paths_migration/migration_classes.rb +++ b/lib/gitlab/database/rename_reserved_paths_migration/migration_classes.rb @@ -76,6 +76,7 @@ module Gitlab class Project < ActiveRecord::Base include MigrationClasses::Routable + has_one :route, as: :source self.table_name = 'projects' def repository_storage_path diff --git a/lib/gitlab/database/rename_reserved_paths_migration/namespaces.rb b/lib/gitlab/database/rename_reserved_paths_migration/namespaces.rb deleted file mode 100644 index 2ef2629f4c2..00000000000 --- a/lib/gitlab/database/rename_reserved_paths_migration/namespaces.rb +++ /dev/null @@ -1,70 +0,0 @@ -module Gitlab - module Database - module RenameReservedPathsMigration - module Namespaces - include Gitlab::ShellAdapter - - def rename_namespaces(paths, type:) - namespaces_for_paths(paths, type: type).each do |namespace| - rename_namespace(namespace) - end - end - - def namespaces_for_paths(paths, type:) - namespaces = if type == :wildcard - MigrationClasses::Namespace.where.not(parent_id: nil) - elsif type == :top_level - MigrationClasses::Namespace.where(parent_id: nil) - end - with_paths = MigrationClasses::Namespace.arel_table[:path]. - matches_any(paths) - namespaces.where(with_paths) - end - - def rename_namespace(namespace) - old_full_path, new_full_path = rename_path_for_routable(namespace) - - move_repositories(namespace, old_full_path, new_full_path) - move_uploads(old_full_path, new_full_path) - move_pages(old_full_path, new_full_path) - end - - def move_repositories(namespace, old_full_path, new_full_path) - repo_paths_for_namespace(namespace).each do |repository_storage_path| - # Ensure old directory exists before moving it - gitlab_shell.add_namespace(repository_storage_path, old_full_path) - - unless gitlab_shell.mv_namespace(repository_storage_path, old_full_path, new_full_path) - message = "Exception moving path #{repository_storage_path} \ - from #{old_full_path} to #{new_full_path}" - Rails.logger.error message - end - end - end - - def repo_paths_for_namespace(namespace) - projects_for_namespace(namespace). - select('distinct(repository_storage)').map(&:repository_storage_path) - end - - def projects_for_namespace(namespace) - namespace_ids = child_ids_for_parent(namespace, ids: [namespace.id]) - namespace_or_children = MigrationClasses::Project. - arel_table[:namespace_id]. - in(namespace_ids) - MigrationClasses::Project.unscoped.where(namespace_or_children) - end - - # This won't scale to huge trees, but it should do for a handful of - # namespaces called `system`. - def child_ids_for_parent(namespace, ids: []) - namespace.children.each do |child| - ids << child.id - child_ids_for_parent(child, ids: ids) if child.children.any? - end - ids - end - end - end - end -end diff --git a/lib/gitlab/database/rename_reserved_paths_migration/projects.rb b/lib/gitlab/database/rename_reserved_paths_migration/projects.rb deleted file mode 100644 index a2c9354e430..00000000000 --- a/lib/gitlab/database/rename_reserved_paths_migration/projects.rb +++ /dev/null @@ -1,38 +0,0 @@ -module Gitlab - module Database - module RenameReservedPathsMigration - module Projects - include Gitlab::ShellAdapter - - def rename_projects(paths) - projects_for_paths(paths).each do |project| - rename_project(project) - end - end - - def rename_project(project) - old_full_path, new_full_path = rename_path_for_routable(project) - - move_repository(project, old_full_path, new_full_path) - move_repository(project, "#{old_full_path}.wiki", "#{new_full_path}.wiki") - move_uploads(old_full_path, new_full_path) - move_pages(old_full_path, new_full_path) - end - - def move_repository(project, old_path, new_path) - unless gitlab_shell.mv_repository(project.repository_storage_path, - old_path, - new_path) - Rails.logger.error "Error moving #{old_path} to #{new_path}" - end - end - - def projects_for_paths(paths) - with_paths = MigrationClasses::Project.arel_table[:path] - .matches_any(paths) - MigrationClasses::Project.where(with_paths) - end - end - end - end -end diff --git a/lib/gitlab/database/rename_reserved_paths_migration/rename_base.rb b/lib/gitlab/database/rename_reserved_paths_migration/rename_base.rb new file mode 100644 index 00000000000..367348a9a42 --- /dev/null +++ b/lib/gitlab/database/rename_reserved_paths_migration/rename_base.rb @@ -0,0 +1,103 @@ +module Gitlab + module Database + module RenameReservedPathsMigration + class RenameBase + attr_reader :paths, :migration + + delegate :update_column_in_batches, + :replace_sql, + to: :migration + + def initialize(paths, migration) + @paths = paths + @migration = migration + end + + def rename_path_for_routable(routable) + old_path = routable.path + old_full_path = routable.full_path + # Only remove the last occurrence of the path name to get the parent namespace path + namespace_path = remove_last_occurrence(old_full_path, old_path) + new_path = rename_path(namespace_path, old_path) + new_full_path = join_routable_path(namespace_path, new_path) + + # skips callbacks & validations + routable.class.where(id: routable). + update_all(path: new_path) + + rename_routes(old_full_path, new_full_path) + + [old_full_path, new_full_path] + end + + def rename_routes(old_full_path, new_full_path) + replace_statement = replace_sql(Route.arel_table[:path], + old_full_path, + new_full_path) + + update_column_in_batches(:routes, :path, replace_statement) do |table, query| + query.where(MigrationClasses::Route.arel_table[:path].matches("#{old_full_path}%")) + end + end + + def rename_path(namespace_path, path_was) + counter = 0 + path = "#{path_was}#{counter}" + + while route_exists?(join_routable_path(namespace_path, path)) + counter += 1 + path = "#{path_was}#{counter}" + end + + path + end + + def remove_last_occurrence(string, pattern) + string.reverse.sub(pattern.reverse, "").reverse + end + + def join_routable_path(namespace_path, top_level) + if namespace_path.present? + File.join(namespace_path, top_level) + else + top_level + end + end + + def route_exists?(full_path) + MigrationClasses::Route.where(Route.arel_table[:path].matches(full_path)).any? + end + + def move_pages(old_path, new_path) + move_folders(pages_dir, old_path, new_path) + end + + def move_uploads(old_path, new_path) + return unless file_storage? + + move_folders(uploads_dir, old_path, new_path) + end + + def move_folders(directory, old_relative_path, new_relative_path) + old_path = File.join(directory, old_relative_path) + return unless File.directory?(old_path) + + new_path = File.join(directory, new_relative_path) + FileUtils.mv(old_path, new_path) + end + + def file_storage? + CarrierWave::Uploader::Base.storage == CarrierWave::Storage::File + end + + def uploads_dir + File.join(CarrierWave.root, "uploads") + end + + def pages_dir + Settings.pages.path + end + end + end + end +end diff --git a/lib/gitlab/database/rename_reserved_paths_migration/rename_namespaces.rb b/lib/gitlab/database/rename_reserved_paths_migration/rename_namespaces.rb new file mode 100644 index 00000000000..80e8135ea93 --- /dev/null +++ b/lib/gitlab/database/rename_reserved_paths_migration/rename_namespaces.rb @@ -0,0 +1,70 @@ +module Gitlab + module Database + module RenameReservedPathsMigration + class RenameNamespaces < RenameBase + include Gitlab::ShellAdapter + + def rename_namespaces(type:) + namespaces_for_paths(type: type).each do |namespace| + rename_namespace(namespace) + end + end + + def namespaces_for_paths(type:) + namespaces = if type == :wildcard + MigrationClasses::Namespace.where.not(parent_id: nil) + elsif type == :top_level + MigrationClasses::Namespace.where(parent_id: nil) + end + with_paths = MigrationClasses::Namespace.arel_table[:path]. + matches_any(paths) + namespaces.where(with_paths) + end + + def rename_namespace(namespace) + old_full_path, new_full_path = rename_path_for_routable(namespace) + + move_repositories(namespace, old_full_path, new_full_path) + move_uploads(old_full_path, new_full_path) + move_pages(old_full_path, new_full_path) + end + + def move_repositories(namespace, old_full_path, new_full_path) + repo_paths_for_namespace(namespace).each do |repository_storage_path| + # Ensure old directory exists before moving it + gitlab_shell.add_namespace(repository_storage_path, old_full_path) + + unless gitlab_shell.mv_namespace(repository_storage_path, old_full_path, new_full_path) + message = "Exception moving path #{repository_storage_path} \ + from #{old_full_path} to #{new_full_path}" + Rails.logger.error message + end + end + end + + def repo_paths_for_namespace(namespace) + projects_for_namespace(namespace). + select('distinct(repository_storage)').map(&:repository_storage_path) + end + + def projects_for_namespace(namespace) + namespace_ids = child_ids_for_parent(namespace, ids: [namespace.id]) + namespace_or_children = MigrationClasses::Project. + arel_table[:namespace_id]. + in(namespace_ids) + MigrationClasses::Project.where(namespace_or_children) + end + + # This won't scale to huge trees, but it should do for a handful of + # namespaces called `system`. + def child_ids_for_parent(namespace, ids: []) + namespace.children.each do |child| + ids << child.id + child_ids_for_parent(child, ids: ids) if child.children.any? + end + ids + end + end + end + end +end diff --git a/lib/gitlab/database/rename_reserved_paths_migration/rename_projects.rb b/lib/gitlab/database/rename_reserved_paths_migration/rename_projects.rb new file mode 100644 index 00000000000..02f10d8e951 --- /dev/null +++ b/lib/gitlab/database/rename_reserved_paths_migration/rename_projects.rb @@ -0,0 +1,38 @@ +module Gitlab + module Database + module RenameReservedPathsMigration + class RenameProjects < RenameBase + include Gitlab::ShellAdapter + + def rename_projects + projects_for_paths.each do |project| + rename_project(project) + end + end + + def rename_project(project) + old_full_path, new_full_path = rename_path_for_routable(project) + + move_repository(project, old_full_path, new_full_path) + move_repository(project, "#{old_full_path}.wiki", "#{new_full_path}.wiki") + move_uploads(old_full_path, new_full_path) + move_pages(old_full_path, new_full_path) + end + + def move_repository(project, old_path, new_path) + unless gitlab_shell.mv_repository(project.repository_storage_path, + old_path, + new_path) + Rails.logger.error "Error moving #{old_path} to #{new_path}" + end + end + + def projects_for_paths + with_paths = MigrationClasses::Project.arel_table[:path] + .matches_any(paths) + MigrationClasses::Project.where(with_paths) + end + end + end + end +end -- cgit v1.2.3