Index: app/helpers/repositories_helper.rb =================================================================== --- app/helpers/repositories_helper.rb (revision 1104) +++ app/helpers/repositories_helper.rb (working copy) @@ -76,6 +76,10 @@ content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) end + def git_field_tags(form, repository) + content_tag('p', form.text_field(:url, :label => 'Root directory', :size => 60, :required => true, :disabled => (repository && !repository.root_url.blank?))) + end + def cvs_field_tags(form, repository) content_tag('p', form.text_field(:root_url, :label => 'CVSROOT', :size => 60, :required => true, :disabled => !repository.new_record?)) + content_tag('p', form.text_field(:url, :label => 'Module', :size => 30, :required => true, :disabled => !repository.new_record?)) Index: app/models/repository/subversion.rb =================================================================== --- app/models/repository/subversion.rb (revision 1104) +++ app/models/repository/subversion.rb (working copy) @@ -36,13 +36,15 @@ end def fetch_changesets + RAILS_DEFAULT_LOGGER.info "\n\nFetching chanfesets...\n\n" scm_info = scm.info + RAILS_DEFAULT_LOGGER.info "\n\nscm_info:\n#{scm_info.inspect}\n\n" if scm_info # latest revision found in database db_revision = latest_changeset ? latest_changeset.revision : 0 # latest revision in the repository scm_revision = scm_info.lastrev.identifier.to_i - if db_revision < scm_revision + if db_revision.to_i < scm_revision logger.debug "Fetching changesets for repository #{url}" if logger && logger.debug? identifier_from = db_revision + 1 while (identifier_from <= scm_revision) Index: app/models/repository/git.rb =================================================================== --- app/models/repository/git.rb (revision 0) +++ app/models/repository/git.rb (revision 0) @@ -0,0 +1,90 @@ +# redMine - project management software +# Copyright (C) 2006-2007 Jean-Philippe Lang +# Copyright (C) 2007 Patrick Aljord patcito@Ĺ‹mail.com +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/git_adapter' + +class Repository::Git < Repository + attr_protected :root_url + validates_presence_of :url + + def scm_adapter + Redmine::Scm::Adapters::GitAdapter + end + + def self.scm_name + 'Git' + end + + def entries(path=nil, identifier=nil) + entries=scm.entries(path, identifier) + if entries + entries.each do |entry| + next unless entry.is_file? + # Search the DB for the entry's last change + change = changes.find(:first, :conditions => ["path = ?", scm.with_leading_slash(entry.path)], :order => "#{Changeset.table_name}.committed_on DESC") + if change + entry.lastrev.identifier = change.changeset.revision + entry.lastrev.name = change.changeset.revision + entry.lastrev.author = change.changeset.committer + entry.lastrev.revision = change.revision + end + end + end + entries + end + + def changesets_for_path(path) + path = "#{path}" unless path.starts_with?('/') + Change.find(:all, :include => :changeset, + :conditions => ["repository_id = ? AND path = ?", id, path], + :order => "committed_on DESC, #{Changeset.table_name}.revision DESC").collect(&:changeset) + end + + def fetch_changesets + scm_info = scm.info + + if scm_info + # latest revision found in database + db_revision = latest_changeset ? latest_changeset.revision : nil + # latest revision in the repository + scm_revision = scm_info.lastrev.identifier + + unless changesets.find_by_revision(scm_revision) + + revisions = scm.revisions('', db_revision, nil) + transaction do + revisions.reverse_each do |revision| + changeset = Changeset.create(:repository => self, + :revision => revision.identifier, + :scmid => revision.scmid, + :committer => revision.author, + :committed_on => revision.time, + :comments => revision.message) + + revision.paths.each do |change| + Change.create(:changeset => changeset, + :action => change[:action], + :path => change[:path], + :from_path => change[:from_path], + :from_revision => change[:from_revision]) + end + end + end + end + end + end +end Index: app/models/changeset.rb =================================================================== --- app/models/changeset.rb (revision 1104) +++ app/models/changeset.rb (working copy) @@ -32,7 +32,7 @@ :date_column => 'committed_on' validates_presence_of :repository_id, :revision, :committed_on, :commit_date - validates_numericality_of :revision, :only_integer => true +# validates_numericality_of :revision, :only_integer => true validates_uniqueness_of :revision, :scope => :repository_id validates_uniqueness_of :scmid, :scope => :repository_id, :allow_nil => true Index: app/controllers/sys_controller.rb =================================================================== --- app/controllers/sys_controller.rb (revision 1104) +++ app/controllers/sys_controller.rb (working copy) @@ -24,21 +24,25 @@ # Returns the projects list, with their repositories def projects - Project.find(:all, :include => :repository) + Project.find(:all, :include => [:repository, :users]) end # Registers a repository for the given project identifier # (Subversion specific) - def repository_created(identifier, url) + def repository_created(identifier, url, login = '', password = '') project = Project.find_by_identifier(identifier) # Do not create the repository if the project has already one return 0 unless project && project.repository.nil? logger.debug "Repository for #{project.name} was created" - repository = Repository.factory('Subversion', :project => project, :url => url) + repository = Repository.factory('Subversion', :project => project, :url => url, :login => login, :password => password) repository.save repository.id || 0 end + def users + Users.fund :all + end + protected def check_enabled(name, args) Index: app/controllers/repositories_controller.rb =================================================================== --- app/controllers/repositories_controller.rb (revision 1104) +++ app/controllers/repositories_controller.rb (working copy) @@ -134,7 +134,7 @@ end def diff - @rev_to = params[:rev_to] ? params[:rev_to].to_i : (@rev - 1) + get_rev_to @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) @@ -185,11 +185,16 @@ render_404 and return false unless @repository @path = params[:path].join('/') unless params[:path].nil? @path ||= '' - @rev = params[:rev].to_i if params[:rev] + @rev = params[:rev] if params[:rev] rescue ActiveRecord::RecordNotFound render_404 end + def get_rev_to + @rev_to = params[:rev_to].to_i ? params[:rev_to].to_i : (@rev.to_i - 1) if @rev !~ /\D/ + @rev_to = params[:rev_to] ? params[:rev_to] : (nil) if !(@rev !~ /\D/) + end + def show_error_not_found render_error l(:error_scm_not_found) end Index: app/views/repositories/_revisions.rhtml =================================================================== --- app/views/repositories/_revisions.rhtml (revision 1104) +++ app/views/repositories/_revisions.rhtml (working copy) @@ -13,11 +13,11 @@ <% line_num = 1 %> <% revisions.each do |changeset| %> -<%= link_to changeset.revision, :action => 'revision', :id => project, :rev => changeset.revision %> +<%= link_to changeset.revision[0..5], :action => 'revision', :id => project, :rev => changeset.revision %> <%= radio_button_tag('rev', changeset.revision, (line_num==1), :id => "cb-#{line_num}", :onclick => "$('cbto-#{line_num+1}').checked=true;") if show_diff && (line_num < revisions.size) %> <%= radio_button_tag('rev_to', changeset.revision, (line_num==2), :id => "cbto-#{line_num}", :onclick => "if ($('cb-#{line_num}').checked==true) {$('cb-#{line_num-1}').checked=true;}") if show_diff && (line_num > 1) %> <%= format_time(changeset.committed_on) %> -<%=h changeset.committer %> +<%=h changeset.committer.split('<').first %> <%= textilizable(changeset.comments) %> <% line_num += 1 %> Index: app/views/repositories/_dir_list_content.rhtml =================================================================== --- app/views/repositories/_dir_list_content.rhtml (revision 1104) +++ app/views/repositories/_dir_list_content.rhtml (working copy) @@ -23,9 +23,9 @@ end %> <%= (entry.size ? number_to_human_size(entry.size) : "?") unless entry.is_dir? %> -<%= link_to(entry.lastrev.name, :action => 'revision', :id => @project, :rev => entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> +<%= link_to(entry.lastrev.name[0..5], :action => 'revision', :id => @project, :rev => entry.lastrev.identifier) if entry.lastrev && entry.lastrev.identifier %> <%= distance_of_time_in_words(entry.lastrev.time, Time.now) if entry.lastrev && entry.lastrev.time %> -<%=h(entry.lastrev.author) if entry.lastrev %> +<%=h(entry.lastrev.author.split('<').first) if entry.lastrev %> <% changeset = @project.repository.changesets.find_by_revision(entry.lastrev.identifier) if entry.lastrev %> <%=h truncate(changeset.comments, 50) unless changeset.nil? %> Index: db/migrate/089_make_revisions_string.rb =================================================================== --- db/migrate/089_make_revisions_string.rb (revision 0) +++ db/migrate/089_make_revisions_string.rb (revision 0) @@ -0,0 +1,11 @@ +class MakeRevisionsString < ActiveRecord::Migration + def self.up + change_column :changes, :from_revision, :string + change_column :changesets, :revision, :string + end + + def self.down + change_column :changes, :from_revision, :integer + change_column :changesets, :revision, :integer + end +end Index: config/environment.rb =================================================================== --- config/environment.rb (revision 1104) +++ config/environment.rb (working copy) @@ -46,10 +46,10 @@ config.action_mailer.smtp_settings = { :address => "127.0.0.1", :port => 25, - :domain => "somenet.foo", + :domain => "dev.roach.org.ua", :authentication => :login, - :user_name => "redmine", - :password => "redmine", + :user_name => "evdev", + :password => "", } config.action_mailer.perform_deliveries = true @@ -58,7 +58,8 @@ # The :test delivery method accumulates sent emails in the # ActionMailer::Base.deliveries array. #config.action_mailer.delivery_method = :test - config.action_mailer.delivery_method = :smtp + #config.action_mailer.delivery_method = :smtp + #config.action_mailer.delivery_method = :sendmail end Index: lib/redmine/scm/adapters/subversion_adapter.rb =================================================================== --- lib/redmine/scm/adapters/subversion_adapter.rb (revision 1104) +++ lib/redmine/scm/adapters/subversion_adapter.rb (working copy) @@ -31,9 +31,14 @@ cmd = "#{SVN_BIN} info --xml #{target('')}" cmd << credentials_string info = nil + #RAILS_DEFAULT_LOGGER << "\n\n#{cmd}\n\n" shellout(cmd) do |io| begin + #RAILS_DEFAULT_LOGGER << "\n\nio:\n#{io.inspect}\n\n" + #io.seek 0, IO::SEEK_SET + #RAILS_DEFAULT_LOGGER << "\n\ndata:\n#{io.read}\n\n" doc = REXML::Document.new(io) + #RAILS_DEFAULT_LOGGER << "\n\ndoc:\n#{doc}\n\n" #root_url = doc.elements["info/entry/repository/root"].text info = Info.new({:root_url => doc.elements["info/entry/repository/root"].text, :lastrev => Revision.new({ @@ -42,9 +47,12 @@ :author => (doc.elements["info/entry/commit/author"] ? doc.elements["info/entry/commit/author"].text : "") }) }) - rescue + rescue => e + + #RAILS_DEFAULT_LOGGER << "\n\nscm_info error: #{e}\n#{e.backtrace.join "\n"}\n\n" end end + #RAILS_DEFAULT_LOGGER << "\n\ncmd error: #{$?}\n#{$?.inspect}\n\n" return nil if $? && $?.exitstatus != 0 info rescue CommandFailed Index: lib/redmine/scm/adapters/abstract_adapter.rb =================================================================== --- lib/redmine/scm/adapters/abstract_adapter.rb (revision 1104) +++ lib/redmine/scm/adapters/abstract_adapter.rb (working copy) @@ -182,7 +182,12 @@ end }.last end - end + end + + +def get_rev(rev,path) +Revision.new +end class Revision attr_accessor :identifier, :scmid, :name, :author, :time, :message, :paths, :revision, :branch Index: lib/redmine/scm/adapters/git_adapter.rb =================================================================== --- lib/redmine/scm/adapters/git_adapter.rb (revision 0) +++ lib/redmine/scm/adapters/git_adapter.rb (revision 0) @@ -0,0 +1,205 @@ +# redMine - project management software +# Copyright (C) 2006-2007 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +require 'redmine/scm/adapters/abstract_adapter' + +module Redmine + module Scm + module Adapters + class GitAdapter < AbstractAdapter + + # Git executable name + GIT_BIN = "git" + + + #get the revision of a particuliar file + def get_rev (rev,path) +cmd="cd #{target('')} && git show #{rev} #{path}" if rev!='latest' +cmd="cd #{target('')} && git log -1 master -- #{path}" if +rev=='latest' or rev.nil? +puts cmd +rev=[] + i=0 + shellout(cmd) do |io| + commit_files=[] + params={:commit=>'',:author=>'',:date=>'',:message=>'',:file=>{:path=>'',:action=>''}} + + message='' + io.each_line do |line| + + i=0 if line=~/^commit/ + params[:commit]=line.chomp.gsub("commit ",'') if i==0 + + params[:author]=line.chomp.gsub("Author: ",'') if i==1 + params[:date]=line.chomp.gsub("Date: ",'') if i==2 + params[:message]+= line.chomp.to_s if i==4 and line[0..0]!=':' + params[:file][:action], params[:file][:path]= line.chomp.slice(/[ACDMRTUXB].*/).split(' ', 2) if i>=4 and line[0..0]==':' + commit_files << {:action=>params[:file][:action],:path=>params[:file][:path]} if i>=4 and line[0..0]==':' + i+=1 + end + + rev = Revision.new({:identifier => params[:commit], + :scmid => params[:commit], + :author => params[:author], + :time => Time.parse(params[:date]), + :message => params[:message], + :paths => commit_files + }) + end + + get_rev('latest',path) if i==0 + + return nil if $? && $?.exitstatus != 0 + return rev +# rescue Errno::ENOENT => e +# raise CommandFailed +end + + + def info +# cmd = "#{GIT_BIN} -R #{target('')} root" +# root_url = nil +# shellout(cmd) do |io| + root_url = target('') +# end + return nil if $? && $?.exitstatus != 0 + info = Info.new({:root_url => target(''), + :lastrev => revisions(root_url,nil,nil,nil).first + }) + info + rescue Errno::ENOENT => e + return nil + end + + def entries(path=nil, identifier=nil) + path ||= '' + entries = Entries.new + cmd = "cd #{target('')} && #{GIT_BIN} show HEAD:#{path}" if identifier.nil? + cmd = "cd #{target('')} && #{GIT_BIN} show #{identifier}:#{path}" if identifier + shellout(cmd) do |io| + io.each_line do |line| + e = line.chomp.split('\\') + unless e.to_s.strip=='' or line[0..3]=='tree' + name=e.first.split('/')[0] + entries << Entry.new({:name => name, + :path => (path.empty? ? name : "#{path}/#{name}"), + :kind => ((e.first.include? '/') ? 'dir' : 'file'), + :lastrev => get_rev(identifier,(path.empty? ? name : "#{path}/#{name}")) + }) unless entries.detect{|entry| entry.name == name} + puts e[0..3] + end + end + end + return nil if $? && $?.exitstatus != 0 + entries.sort_by_name +# rescue Errno::ENOENT => e +# raise CommandFailed + end + + def entry(path=nil, identifier=nil) + path ||= '' + search_path = path.split('/')[0..-2].join('/') + entry_name = path.split('/').last + e = entries(search_path, identifier) + e ? e.detect{|entry| entry.name == entry_name} : nil + end + + def revisions(path, identifier_from, identifier_to, options={}) + revisions = Revisions.new + cmd = "cd #{target('')} && #{GIT_BIN} whatchanged " + cmd << " #{identifier_from}.. " if identifier_from + cmd << " #{identifier_to} " if identifier_to + #cmd << " HEAD " if !identifier_to + puts cmd + shellout(cmd) do |io| + files=[] + params={:commit=>'',:author=>'',:date=>'',:message=>'',:file=>{:path=>'',:action=>''}} + i=0 + message='' + io.each_line do |line| + + if line=~/^commit/ and i>0 + revisions << Revision.new({:identifier => params[:commit], + :scmid => params[:commit], + :author => params[:author], + :time => Time.parse(params[:date]), + :message => params[:message], + :paths => files + }) + + files=[] + i=0 + params={:commit=>'',:author=>'',:date=>'',:message=>'',:file=>{:path=>'',:action=>''}} + end + params[:commit]=line.chomp.gsub("commit ",'') if i==0 + params[:author]=line.chomp.gsub("Author: ",'') if i==1 + params[:date]=line.chomp.gsub("Date: ",'') if i==2 + params[:message]+= line.chomp.to_s if i>=4 and line[0..0]!=':' + params[:file][:action], params[:file][:path]= line.chomp.slice(/[ACDMRTUXB].*/).split(' ', 2) if i>=4 and line[0..0]==':' + files << {:action=>params[:file][:action],:path=>params[:file][:path]} if i>=4 and line[0..0]==':' + i+=1 + end + end + + return nil if $? && $?.exitstatus != 0 + revisions + rescue Errno::ENOENT => e + raise CommandFailed + puts 'revs: #{revisions}' + end + + def diff(path, identifier_from, identifier_to=nil, type="inline") + path ||= '' + if identifier_to + identifier_to = identifier_to + else + identifier_to = nil + end + cmd = "cd #{target('')} && #{GIT_BIN} diff #{identifier_from}^!" if identifier_to.nil? + cmd = "cd #{target('')} && #{GIT_BIN} diff #{identifier_to} #{identifier_from}" if !identifier_to.nil? + cmd << " #{path}" unless path.empty? + diff = [] + shellout(cmd) do |io| + io.each_line do |line| + diff << line + end + end + return nil if $? && $?.exitstatus != 0 + DiffTableList.new diff, type + + rescue Errno::ENOENT => e + raise CommandFailed + end + + def cat(path, identifier=nil) + cmd = "cd #{target('')} && #{GIT_BIN} show #{identifier}:#{path}" + cat = nil + shellout(cmd) do |io| + io.binmode + cat = io.read + end + return nil if $? && $?.exitstatus != 0 + cat + rescue Errno::ENOENT => e + raise CommandFailed + end + end + end + end + +end + Index: lib/redmine.rb =================================================================== --- lib/redmine.rb (revision 1104) +++ lib/redmine.rb (working copy) @@ -10,7 +10,7 @@ # RMagick is not available end -REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar ) +REDMINE_SUPPORTED_SCM = %w( Subversion Darcs Mercurial Cvs Bazaar Git ) # Permissions Redmine::AccessControl.map do |map|