Commit c4299bb45a97314fd51962b91346c65ba564d388

Authored by Dmitriy Zaporozhets
1 parent 01033631

Move directory logic out of model. Use Gitlab:Shell class to interact with file system

app/models/namespace.rb
... ... @@ -13,6 +13,8 @@
13 13 #
14 14  
15 15 class Namespace < ActiveRecord::Base
  16 + include Gitlab::ShellAdapter
  17 +
16 18 attr_accessible :name, :description, :path
17 19  
18 20 has_many :projects, dependent: :destroy
... ... @@ -31,7 +33,7 @@ class Namespace &lt; ActiveRecord::Base
31 33 delegate :name, to: :owner, allow_nil: true, prefix: true
32 34  
33 35 after_create :ensure_dir_exist
34   - after_update :move_dir
  36 + after_update :move_dir, if: :path_changed?
35 37 after_destroy :rm_dir
36 38  
37 39 scope :root, -> { where('type IS NULL') }
... ... @@ -53,48 +55,34 @@ class Namespace &lt; ActiveRecord::Base
53 55 end
54 56  
55 57 def ensure_dir_exist
56   - unless dir_exists?
57   - FileUtils.mkdir( namespace_full_path, mode: 0770 )
58   - end
59   - end
60   -
61   - def dir_exists?
62   - File.exists?(namespace_full_path)
  58 + gitlab_shell.add_namespace(path)
63 59 end
64 60  
65   - def namespace_full_path
66   - @namespace_full_path ||= File.join(Gitlab.config.gitlab_shell.repos_path, path)
  61 + def rm_dir
  62 + gitlab_shell.rm_namespace(path)
67 63 end
68 64  
69 65 def move_dir
70   - if path_changed?
71   - old_path = File.join(Gitlab.config.gitlab_shell.repos_path, path_was)
72   - new_path = File.join(Gitlab.config.gitlab_shell.repos_path, path)
73   - if File.exists?(new_path)
74   - raise "Already exists"
75   - end
76   -
77   -
  66 + if gitlab_shell.mv_namespace(path_was, path)
  67 + # If repositories moved successfully we need to remove old satellites
  68 + # and send update instructions to users.
  69 + # However we cannot allow rollback since we moved namespace dir
  70 + # So we basically we mute exceptions in next actions
78 71 begin
79   - # Remove satellite when moving repo
80   - if path_was.present?
81   - satellites_path = File.join(Gitlab.config.satellites.path, path_was)
82   - FileUtils.rm_r( satellites_path, force: true )
83   - end
84   -
85   - FileUtils.mv( old_path, new_path )
  72 + gitlab_shell.rm_satellites(path_was)
86 73 send_update_instructions
87   - rescue Exception => e
88   - raise "Namespace move error #{old_path} #{new_path}"
  74 + rescue
  75 + # Returning false does not rolback after_* transaction but gives
  76 + # us information about failing some of tasks
  77 + false
89 78 end
  79 + else
  80 + # if we cannot move namespace directory we should rollback
  81 + # db changes in order to prevent out of sync between db and fs
  82 + raise Exception.new('namespace directory cannot be moved')
90 83 end
91 84 end
92 85  
93   - def rm_dir
94   - dir_path = File.join(Gitlab.config.gitlab_shell.repos_path, path)
95   - FileUtils.rm_r( dir_path, force: true )
96   - end
97   -
98 86 def send_update_instructions
99 87 projects.each(&:send_move_instructions)
100 88 end
... ...
lib/gitlab/backend/shell.rb
... ... @@ -65,13 +65,72 @@ module Gitlab
65 65 system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"")
66 66 end
67 67  
  68 + # Add empty directory for storing repositories
  69 + #
  70 + # Ex.
  71 + # add_namespace("gitlab")
  72 + #
  73 + def add_namespace(name)
  74 + FileUtils.mkdir(full_path(name), mode: 0770) unless exists?(name)
  75 + end
  76 +
  77 + # Remove directory from repositories storage
  78 + # Every repository inside this directory will be removed too
  79 + #
  80 + # Ex.
  81 + # rm_namespace("gitlab")
  82 + #
  83 + def rm_namespace(name)
  84 + FileUtils.rm_r(full_path(name), force: true)
  85 + end
  86 +
  87 + # Move namespace directory inside repositories storage
  88 + #
  89 + # Ex.
  90 + # mv_namespace("gitlab", "gitlabhq")
  91 + #
  92 + def mv_namespace(old_name, new_name)
  93 + return false if exists?(new_name) || !exists?(old_name)
  94 +
  95 + FileUtils.mv(full_path(old_name), full_path(new_name))
  96 + end
  97 +
  98 + # Remove GitLab Satellites for provided path (namespace or repo dir)
  99 + #
  100 + # Ex.
  101 + # rm_satellites("gitlab")
  102 + #
  103 + # rm_satellites("gitlab/gitlab-ci.git")
  104 + #
  105 + def rm_satellites(path)
  106 + raise ArgumentError.new("Path can't be blank") if path.blank?
  107 +
  108 + satellites_path = File.join(Gitlab.config.satellites.path, path)
  109 + FileUtils.rm_r(satellites_path, force: true)
  110 + end
  111 +
68 112 def url_to_repo path
69 113 Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git"
70 114 end
71 115  
  116 + protected
  117 +
72 118 def gitlab_shell_user_home
73 119 File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}")
74 120 end
75 121  
  122 + def repos_path
  123 + Gitlab.config.gitlab_shell.repos_path
  124 + end
  125 +
  126 + def full_path(dir_name)
  127 + raise ArgumentError.new("Directory name can't be blank") if dir_name.blank?
  128 +
  129 + File.join(repos_path, dir_name)
  130 + end
  131 +
  132 + def exists?(dir_name)
  133 + File.exists?(full_path(dir_name))
  134 + end
76 135 end
77 136 end
... ...
spec/models/namespace_spec.rb
... ... @@ -60,7 +60,7 @@ describe Namespace do
60 60 end
61 61  
62 62 it "should raise error when dirtory exists" do
63   - expect { @namespace.move_dir }.to raise_error("Already exists")
  63 + expect { @namespace.move_dir }.to raise_error("namespace directory cannot be moved")
64 64 end
65 65  
66 66 it "should move dir if path changed" do
... ...