Refactored Diff::Display classes
[gitorious:yousource.git] / app / models / repository.rb
1 class Repository < ActiveRecord::Base
2   belongs_to  :user
3   belongs_to  :project
4   belongs_to  :parent, :class_name => "Repository"
5   has_many    :committerships, :dependent => :destroy
6   has_many    :committers, :through => :committerships, :source => :user
7   has_many    :comments, :dependent => :destroy
8   
9   validates_presence_of :user_id, :project_id, :name
10   validates_format_of :name, :with => /^[a-z0-9_\-]+$/i,
11     :message => "is invalid, must match something like /[a-z0-9_\\-]+/"
12   validates_uniqueness_of :name, :scope => :project_id, :case_sensitive => false
13   
14   before_save :set_as_mainline_if_first
15   after_create :add_user_as_committer, :create_new_repos_task
16   after_destroy :create_delete_repos_task
17   
18   def self.new_by_cloning(other, username=nil)
19     suggested_name = username ? "#{username}s-#{other.name}-clone" : nil
20     new(:parent => other, :project => other.project, :name => suggested_name)
21   end
22   
23   def self.find_by_name!(name)
24     find_by_name(name) || raise(ActiveRecord::RecordNotFound)
25   end
26   
27   BASE_REPOSITORY_URL = "gitorious.org"
28   
29   def gitdir
30     File.join(project.slug, "#{name}.git")
31   end
32   
33   def clone_url
34     "git://#{BASE_REPOSITORY_URL}/#{gitdir}"
35   end
36   
37   def push_url
38     "git@#{BASE_REPOSITORY_URL}:#{gitdir}"
39   end
40   
41   def full_repository_path
42     self.class.full_path_from_partial_path(gitdir)
43   end
44   
45   def self.create_git_repository(path)
46     git_backend.create(full_path_from_partial_path(path))
47   end
48   
49   def self.clone_git_repository(target_path, source_path)
50     git_backend.clone(full_path_from_partial_path(target_path), 
51       full_path_from_partial_path(source_path))
52   end
53   
54   def self.delete_git_repository(path)
55     git_backend.delete!(full_path_from_partial_path(path))
56   end
57   
58   def has_commits?
59     git_backend.repository_has_commits?(full_repository_path)
60   end
61   
62   def self.git_backend
63     RAILS_ENV == "test" ? MockGitBackend : GitBackend
64   end
65   
66   def git_backend
67     RAILS_ENV == "test" ? MockGitBackend : GitBackend
68   end
69   
70   def to_param
71     name
72   end
73   
74   def to_xml
75     super(:methods => [:gitdir, :clone_url, :push_url])
76   end
77   
78   def add_committer(user)
79     unless user.can_write_to?(self)
80       committers << user
81     end
82   end
83   
84   def last_commit
85     if has_commits?
86       @last_commit ||= Git.bare(full_repository_path).log(1).first
87     end
88     @last_commit
89   end
90   
91   def create_new_repos_task
92     Task.create!(:target_class => self.class.name, 
93       :command => parent ? "clone_git_repository" : "create_git_repository", 
94       :arguments => parent ? [gitdir, parent.gitdir] : [gitdir], 
95       :target_id => self.id)
96   end
97   
98   def create_delete_repos_task
99     Task.create!(:target_class => self.class.name, 
100       :command => "delete_git_repository", :arguments => [gitdir]) # fixme: gitdir is probably gone in after_destroy
101   end
102     
103   protected
104     def set_as_mainline_if_first
105       unless project.repositories.size >= 1
106         self.mainline = true
107       end
108     end
109     
110     def add_user_as_committer
111       committers << user
112     end
113     
114     def self.full_path_from_partial_path(path)
115       File.expand_path(File.join(GitoriousConfig["repository_base_path"], path))
116     end
117 end