Class: VCLog::Adapters::Svn

Inherits:
Abstract show all
Defined in:
lib/vclog/adapters/svn.rb

Overview

SVN Adapter.

NOTE: Unfortunately the SVN adapater is very slow. If hits the server every time the ‘svn log’ command is issued. When generating a History that’s two hits for every tag. If anyone knows a better way please have at it –maybe future versions of SVN will improve the situation.

Instance Attribute Summary

Attributes inherited from Abstract

#config, #heuristics, #root

Instance Method Summary collapse

Methods inherited from Abstract

#change_by_date, #change_points, #changes, #initialize_framework, #tag?, #tags, #tempfile, #version, #version_tag?

Constructor Details

#initialize(root) ⇒ Svn

Returns a new instance of Svn.



16
17
18
19
20
21
22
23
# File 'lib/vclog/adapters/svn.rb', line 16

def initialize(root)
  begin
    require 'xmlsimple'
  rescue LoadError
    raise LoadError, "VCLog requires xml-simple for SVN support."
  end
  super(root)
end

Instance Method Details

#emailObject

TODO: Best solution to SVN email?



119
120
121
# File 'lib/vclog/adapters/svn.rb', line 119

def email
  @email ||= ENV['EMAIL']
end

#extract_changesObject

Extract changes.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/vclog/adapters/svn.rb', line 26

def extract_changes
  log = []

  xml = `svn log -v --xml`.strip

  commits = XmlSimple.xml_in(xml, {'KeyAttr' => 'rev'})
  commits = commits['logentry']

  commits.each do |com|
    rev  = com['revision']
    msg  = [com['msg']].flatten.compact.join('').strip
    who  = [com['author']].flatten.compact.join('').strip
    date = [com['date']].flatten.compact.join('').strip

    files = com['paths'].map{ |h| h['path'].map{ |y| y['content'] } }.flatten

    next if msg.empty?
    next if msg == "*** empty log message ***"

    date = Time.parse(date)

    log << Change.new(:id=>rev, :date=>date, :who=>who, :msg=>msg, :files=>files)
  end

  log
end

#extract_tagsObject

Extract tags.



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/vclog/adapters/svn.rb', line 54

def extract_tags
  list = []
  tagdir = tag_directory

  if tagdir
    tags = Dir.entries(tagdir).select{ |e| e.index('.') != 0 && e =~ /\d(.*)$/ }
  else
    tags = []
  end

  tags.each do |path|
    dir = File.join(tagdir, path)

    # using yaml, but maybe use xml instead?
    info = `svn info #{dir}`
    info = YAML.load(info)
    md = /(\d.*)$/.match(info['Path'])
    name = md ? md[1] : path
    date = info['Last Changed Date']
    who  = info['Last Changed Author']
    rev  = info['Revision']

    # get last commit
    xml = `svn log -l1 --xml #{dir}`
    commits = XmlSimple.xml_in(xml, {'KeyAttr' => 'rev'})
    commit = commits['logentry'].first

    msg  = [commit["msg"]].flatten.compact.join('').strip
    date = [commit["date"]].flatten.compact.join('').strip

    list << Tag.new(:name=>name, :id=>rev, :date=>date, :who=>who, :msg=>msg)
  end
  list
end

#infoObject (private)



147
148
149
# File 'lib/vclog/adapters/svn.rb', line 147

def info
  @info ||= YAML.load(`svn info`.strip)
end

#repositoryObject



124
125
126
# File 'lib/vclog/adapters/svn.rb', line 124

def repository
  info['Repository Root']
end

#tag(ref, label, date, message) ⇒ Object

TODO: Need to effect svn tag date. How?



134
135
136
137
138
139
140
141
142
# File 'lib/vclog/adapters/svn.rb', line 134

def tag(ref, label, date, message)
  file = tempfile("message", message)

  Dir.chdir(root) do
    cmd = %[svn copy -r #{ref} -F "#{mfile.path}" . #{tag_directory}/#{label}]
    puts cmd if $DEBUG
    `#{cmd}` unless $DRYRUN
  end
end

#tag_directoryObject

This isn’t perfect, but is there really anyway for it to be? It ascends up the current directory tree looking for the best candidate for a tags directory.



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/vclog/adapters/svn.rb', line 92

def tag_directory
  fnd = nil
  dir = root
  while dir != '/' do
    entries = Dir.entries(dir)
    if entries.include?('.svn')
      if entries.include?('tags')
        break(fnd = File.join(dir, 'tags'))
      else
        entries = entries.reject{ |e| e.index('.') == 0 }
        entries = entries.reject{ |e| e !~ /\d$/ }
        break(fnd = dir) unless entries.empty?
      end
    else
      break(fnd=nil)
    end
    dir = File.dirname(dir)
  end
  fnd
end

#userObject



114
115
116
# File 'lib/vclog/adapters/svn.rb', line 114

def user
  @email ||= `svn propget svn:author`.strip
end

#uuidObject



129
130
131
# File 'lib/vclog/adapters/svn.rb', line 129

def uuid
  info['Repository UUID']
end