Class: Redmine::Scm::Adapters::SubversionAdapter
  
  
  
  Constant Summary
  
    
      - SVN_BIN =
        
  
 
- Redmine::Configuration['scm_subversion_command'] || "svn" 
      Class Method Summary
      collapse
    
    
  
    
      Instance Method Summary
      collapse
    
    
      
        - 
  
    
      #annotate(path, identifier = nil)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #cat(path, identifier = nil)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #diff(path, identifier_from, identifier_to = nil)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #entries(path = nil, identifier = nil, options = {})  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Returns an Entries collection or nil if the given path doesn't exist in
the repository. 
 
- 
  
    
      #info  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
Get info about the svn repository. 
 
- 
  
    
      #properties(path, identifier = nil)  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
- 
  
    
      #revisions(path = nil, identifier_from = nil, identifier_to = nil, options = {})  ⇒ Object 
    
    
  
  
  
  
  
  
  
  
  
    
  
#adapter_name, #branches, client_version_above?, client_version_string, #default_branch, #entry, #initialize, #path_encoding, #root_url, shell_quote, #shell_quote, shell_quote_command, #supports_annotate?, #supports_cat?, #tags, #url, #with_leading_slash, #with_trailling_slash, #without_leading_slash, #without_trailling_slash
  
    Class Method Details
    
      
  
  
    .client_available  ⇒ Object 
  
  
  
  
    | 
42
43
44
45
46 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 42
def client_available
      client_version_above?([1, 3])
end | 
 
    
      
  
  
    .client_command  ⇒ Object 
  
  
  
  
    | 
30
31
32 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 30
def client_command
  @@bin    ||= SVN_BIN
end | 
 
    
      
  
  
    .client_version  ⇒ Object 
  
  
  
  
    | 
38
39
40 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 38
def client_version
  @@client_version ||= (svn_binary_version || [])
end | 
 
    
      
  
  
    .scm_version_from_command_line  ⇒ Object 
  
  
  
  
    | 
55
56
57 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 55
def scm_version_from_command_line
  shellout("#{sq_bin} --version") { |io| io.read }.to_s
end | 
 
    
      
  
  
    .sq_bin  ⇒ Object 
  
  
  
  
    | 
34
35
36 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 34
def sq_bin
  @@sq_bin ||= shell_quote_command
end | 
 
    
      
  
  
    .svn_binary_version  ⇒ Object 
  
  
  
  
    | 
48
49
50
51
52
53 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 48
def svn_binary_version
  scm_version = scm_version_from_command_line.dup.force_encoding('ASCII-8BIT')
  if m = scm_version.match(%r{\A(.*?)((\d+\.)+\d+)})
    m[2].scan(%r{\d+}).collect(&:to_i)
  end
end | 
 
    
   
  
    Instance Method Details
    
      
  
  
    #annotate(path, identifier = nil)  ⇒ Object 
  
  
  
  
    | 
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 221
def annotate(path, identifier=nil)
  identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
  cmd = "#{self.class.sq_bin} blame #{target(path)}@#{identifier}"
  cmd << credentials_string
  blame = Annotate.new
  shellout(cmd) do |io|
    io.each_line do |line|
      next unless line =~ %r{^\s*(\d+)\s*(\S+)\s(.*)$}
      rev = $1
      blame.add_line($3.rstrip,
           Revision.new(
              :identifier => rev,
              :revision   => rev,
              :author     => $2.strip
              ))
    end
  end
  return nil if $? && $?.exitstatus != 0
  blame
end | 
 
    
      
  
  
    #cat(path, identifier = nil)  ⇒ Object 
  
  
  
  
    | 
208
209
210
211
212
213
214
215
216
217
218
219 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 208
def cat(path, identifier=nil)
  identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
  cmd = "#{self.class.sq_bin} cat #{target(path)}@#{identifier}"
  cmd << credentials_string
  cat = nil
  shellout(cmd) do |io|
    io.binmode
    cat = io.read
  end
  return nil if $? && $?.exitstatus != 0
  cat
end | 
 
    
      
  
  
    #diff(path, identifier_from, identifier_to = nil)  ⇒ Object 
  
  
  
  
    | 
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 187
def diff(path, identifier_from, identifier_to=nil)
  path ||= ''
  identifier_from = (identifier_from and identifier_from.to_i > 0) ? identifier_from.to_i : ''
  identifier_to = (identifier_to and identifier_to.to_i > 0) ? identifier_to.to_i : (identifier_from.to_i - 1)
  cmd = "#{self.class.sq_bin} diff -r "
  cmd << "#{identifier_to}:"
  cmd << "#{identifier_from}"
  cmd << " #{target(path)}@#{identifier_from}"
  cmd << credentials_string
  diff = []
  shellout(cmd) do |io|
    io.each_line do |line|
      diff << line
    end
  end
  return nil if $? && $?.exitstatus != 0
  diff
end | 
 
    
      
  
  
    #entries(path = nil, identifier = nil, options = {})  ⇒ Object 
  
  
  
  
    
Returns an Entries collection or nil if the given path doesn't exist in
the repository
   
 
  
  
    | 
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 88
def entries(path=nil, identifier=nil, options={})
  path ||= ''
  identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
  entries = Entries.new
  cmd = "#{self.class.sq_bin} list --xml #{target(path)}@#{identifier}"
  cmd << credentials_string
  shellout(cmd) do |io|
    output = io.read.force_encoding('UTF-8')
    begin
      doc = parse_xml(output)
      each_xml_element(doc['lists']['list'], 'entry') do |entry|
        commit = entry['commit']
        commit_date = commit['date']
                        next if entry['kind'] == 'dir' && commit_date.nil?
        name = entry['name']['__content__']
        entries << Entry.new({:name => URI.unescape(name),
                    :path => ((path.empty? ? "" : "#{path}/") + name),
                    :kind => entry['kind'],
                    :size => ((s = entry['size']) ? s['__content__'].to_i : nil),
                    :lastrev => Revision.new({
                      :identifier => commit['revision'],
                      :time => Time.parse(commit_date['__content__'].to_s).localtime,
                      :author => ((a = commit['author']) ? a['__content__'] : nil)
                      })
                    })
      end
    rescue Exception => e
      logger.error("Error parsing svn output: #{e.message}")
      logger.error("Output was:\n #{output}")
    end
  end
  return nil if $? && $?.exitstatus != 0
  logger.debug("Found #{entries.size} entries in the repository for #{target(path)}") if logger && logger.debug?
  entries.sort_by_name
end | 
 
    
      
  
  
    #info  ⇒ Object 
  
  
  
  
    
Get info about the svn repository
   
 
  
  
    | 
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 61
def info
  cmd = "#{self.class.sq_bin} info --xml #{target}"
  cmd << credentials_string
  info = nil
  shellout(cmd) do |io|
    output = io.read.force_encoding('UTF-8')
    begin
      doc = parse_xml(output)
            info = Info.new({:root_url => doc['info']['entry']['repository']['root']['__content__'],
                       :lastrev => Revision.new({
                         :identifier => doc['info']['entry']['commit']['revision'],
                         :time => Time.parse(doc['info']['entry']['commit']['date']['__content__']).localtime,
                         :author => (doc['info']['entry']['commit']['author'] ? doc['info']['entry']['commit']['author']['__content__'] : "")
                       })
                     })
    rescue
    end
  end
  return nil if $? && $?.exitstatus != 0
  info
rescue CommandFailed
  return nil
end | 
 
    
      
  
  
    #properties(path, identifier = nil)  ⇒ Object 
  
  
  
  
    | 
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 126
def properties(path, identifier=nil)
    return nil unless self.class.client_version_above?([1, 5, 0])
  identifier = (identifier and identifier.to_i > 0) ? identifier.to_i : "HEAD"
  cmd = "#{self.class.sq_bin} proplist --verbose --xml #{target(path)}@#{identifier}"
  cmd << credentials_string
  properties = {}
  shellout(cmd) do |io|
    output = io.read.force_encoding('UTF-8')
    begin
      doc = parse_xml(output)
      each_xml_element(doc['properties']['target'], 'property') do |property|
        properties[ property['name'] ] = property['__content__'].to_s
      end
    rescue
    end
  end
  return nil if $? && $?.exitstatus != 0
  properties
end | 
 
    
      
  
  
    #revisions(path = nil, identifier_from = nil, identifier_to = nil, options = {})  ⇒ Object 
  
  
  
  
    | 
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185 | # File 'lib/redmine/scm/adapters/subversion_adapter.rb', line 148
def revisions(path=nil, identifier_from=nil, identifier_to=nil, options={})
  path ||= ''
  identifier_from = (identifier_from && identifier_from.to_i > 0) ? identifier_from.to_i : "HEAD"
  identifier_to = (identifier_to && identifier_to.to_i > 0) ? identifier_to.to_i : 1
  revisions = Revisions.new
  cmd = "#{self.class.sq_bin} log --xml -r #{identifier_from}:#{identifier_to}"
  cmd << credentials_string
  cmd << " --verbose " if  options[:with_paths]
  cmd << " --limit #{options[:limit].to_i}" if options[:limit]
  cmd << ' ' + target(path)
  shellout(cmd) do |io|
    output = io.read.force_encoding('UTF-8')
    begin
      doc = parse_xml(output)
      each_xml_element(doc['log'], 'logentry') do |logentry|
        paths = []
        each_xml_element(logentry['paths'], 'path') do |path|
          paths << {:action => path['action'],
                    :path => path['__content__'],
                    :from_path => path['copyfrom-path'],
                    :from_revision => path['copyfrom-rev']
                    }
        end if logentry['paths'] && logentry['paths']['path']
        paths.sort! { |x,y| x[:path] <=> y[:path] }
        revisions << Revision.new({:identifier => logentry['revision'],
                      :author => (logentry['author'] ? logentry['author']['__content__'] : ""),
                      :time => Time.parse(logentry['date']['__content__'].to_s).localtime,
                      :message => logentry['msg']['__content__'],
                      :paths => paths
                    })
      end
    rescue
    end
  end
  return nil if $? && $?.exitstatus != 0
  revisions
end |