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,6 +13,8 @@
13 # 13 #
14 14
15 class Namespace < ActiveRecord::Base 15 class Namespace < ActiveRecord::Base
  16 + include Gitlab::ShellAdapter
  17 +
16 attr_accessible :name, :description, :path 18 attr_accessible :name, :description, :path
17 19
18 has_many :projects, dependent: :destroy 20 has_many :projects, dependent: :destroy
@@ -31,7 +33,7 @@ class Namespace &lt; ActiveRecord::Base @@ -31,7 +33,7 @@ class Namespace &lt; ActiveRecord::Base
31 delegate :name, to: :owner, allow_nil: true, prefix: true 33 delegate :name, to: :owner, allow_nil: true, prefix: true
32 34
33 after_create :ensure_dir_exist 35 after_create :ensure_dir_exist
34 - after_update :move_dir 36 + after_update :move_dir, if: :path_changed?
35 after_destroy :rm_dir 37 after_destroy :rm_dir
36 38
37 scope :root, -> { where('type IS NULL') } 39 scope :root, -> { where('type IS NULL') }
@@ -53,48 +55,34 @@ class Namespace &lt; ActiveRecord::Base @@ -53,48 +55,34 @@ class Namespace &lt; ActiveRecord::Base
53 end 55 end
54 56
55 def ensure_dir_exist 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 end 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 end 63 end
68 64
69 def move_dir 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 begin 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 send_update_instructions 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 end 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 end 83 end
91 end 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 def send_update_instructions 86 def send_update_instructions
99 projects.each(&:send_move_instructions) 87 projects.each(&:send_move_instructions)
100 end 88 end
lib/gitlab/backend/shell.rb
@@ -65,13 +65,72 @@ module Gitlab @@ -65,13 +65,72 @@ module Gitlab
65 system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"") 65 system("#{gitlab_shell_user_home}/gitlab-shell/bin/gitlab-keys rm-key #{key_id} \"#{key_content}\"")
66 end 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 def url_to_repo path 112 def url_to_repo path
69 Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git" 113 Gitlab.config.gitlab_shell.ssh_path_prefix + "#{path}.git"
70 end 114 end
71 115
  116 + protected
  117 +
72 def gitlab_shell_user_home 118 def gitlab_shell_user_home
73 File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}") 119 File.expand_path("~#{Gitlab.config.gitlab_shell.ssh_user}")
74 end 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 end 135 end
77 end 136 end
spec/models/namespace_spec.rb
@@ -60,7 +60,7 @@ describe Namespace do @@ -60,7 +60,7 @@ describe Namespace do
60 end 60 end
61 61
62 it "should raise error when dirtory exists" do 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 end 64 end
65 65
66 it "should move dir if path changed" do 66 it "should move dir if path changed" do