SvnLog 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/bin/svnlog +3 -0
  2. data/lib/svnlog.rb +221 -0
  3. data/lib/svnlog/index.rb +111 -0
  4. data/lib/svnlog/log.rb +37 -0
  5. data/test/data/repos/README.txt +5 -0
  6. data/test/data/repos/conf/authz +21 -0
  7. data/test/data/repos/conf/passwd +8 -0
  8. data/test/data/repos/conf/svnserve.conf +30 -0
  9. data/test/data/repos/db/current +1 -0
  10. data/test/data/repos/db/format +1 -0
  11. data/test/data/repos/db/fs-type +1 -0
  12. data/test/data/repos/db/revprops/0 +5 -0
  13. data/test/data/repos/db/revprops/1 +13 -0
  14. data/test/data/repos/db/revprops/2 +13 -0
  15. data/test/data/repos/db/revprops/3 +13 -0
  16. data/test/data/repos/db/revs/0 +11 -0
  17. data/test/data/repos/db/revs/1 +0 -0
  18. data/test/data/repos/db/revs/2 +0 -0
  19. data/test/data/repos/db/revs/3 +0 -0
  20. data/test/data/repos/db/uuid +1 -0
  21. data/test/data/repos/db/write-lock +0 -0
  22. data/test/data/repos/format +1 -0
  23. data/test/data/repos/hooks/post-commit.tmpl +51 -0
  24. data/test/data/repos/hooks/post-lock.tmpl +44 -0
  25. data/test/data/repos/hooks/post-revprop-change.tmpl +56 -0
  26. data/test/data/repos/hooks/post-unlock.tmpl +42 -0
  27. data/test/data/repos/hooks/pre-commit.tmpl +70 -0
  28. data/test/data/repos/hooks/pre-lock.tmpl +64 -0
  29. data/test/data/repos/hooks/pre-revprop-change.tmpl +66 -0
  30. data/test/data/repos/hooks/pre-unlock.tmpl +60 -0
  31. data/test/data/repos/hooks/start-commit.tmpl +54 -0
  32. data/test/data/repos/locks/db-logs.lock +3 -0
  33. data/test/data/repos/locks/db.lock +3 -0
  34. data/test/helper.rb +9 -0
  35. data/test/test_all.rb +4 -0
  36. data/test/test_index.rb +71 -0
  37. data/test/test_log.rb +29 -0
  38. metadata +96 -0
@@ -0,0 +1,3 @@
1
+ require 'svnlog'
2
+
3
+ Svn::Log::Application.new.run
@@ -0,0 +1,221 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'svnlog/log'
4
+ require 'svnlog/index'
5
+
6
+ require 'optparse'
7
+ require 'time'
8
+
9
+ module Svn
10
+ module Log
11
+
12
+ # The main program
13
+ class Application
14
+
15
+ def initialize(argv = ARGV)
16
+ @argv = argv
17
+ end
18
+
19
+ # Run the program
20
+ def run
21
+ begin
22
+ create_command(@argv).run
23
+ rescue
24
+ puts $!
25
+ end
26
+ end
27
+
28
+ # Creates the command
29
+ def create_command(argv)
30
+ command = nil
31
+ name = argv[0]
32
+ if name
33
+ command = Application.commands[name.downcase]
34
+ end
35
+ command ||= HelpCommand
36
+ command.new(argv)
37
+ end
38
+
39
+ # Returns a list of the available commands
40
+ def self.commands
41
+ commands = {}
42
+ Application.constants.each do |c|
43
+ if c =~ /(.+)Command/
44
+ commands[$1.downcase] = eval(c)
45
+ end
46
+ end
47
+ commands
48
+ end
49
+
50
+ # A command for displaying command usage
51
+ class HelpCommand
52
+
53
+ def initialize(argv)
54
+ end
55
+
56
+ def run
57
+ puts "Usage: svnlog <command> [options]"
58
+ puts
59
+ puts "Available commands are:"
60
+ for name in Application.commands.keys.sort
61
+ puts " #{name}"
62
+ end
63
+ puts
64
+ puts "Type \"svnlog <command> --help\" for help on a specific command."
65
+ end
66
+ end
67
+
68
+ # A command for populating an index
69
+ class IndexCommand
70
+
71
+ def initialize(argv)
72
+ parse_options(argv)
73
+ end
74
+
75
+ def parse_options(argv)
76
+ OptionParser.new do |opt|
77
+ opt.banner = <<END
78
+ Populates an index with log entries from an SVN repository.
79
+
80
+ Examples:
81
+ svnlog index -p C:\\MyIndex -r svn://server/repos/path/to/something
82
+ svnlog index -p C:\\MyIndex
83
+
84
+ Usage: svnlog index [options]
85
+ END
86
+ opt.on("-p", "--path <val>", "The path to the index") { |@path| }
87
+ opt.on("-r", "--repository-url <val>", "The url of the SVN repository") { |@repository_url| }
88
+ opt.parse!(argv)
89
+ end
90
+ end
91
+
92
+ def run
93
+ Index.new(@path, @repository_url).update
94
+ end
95
+ end
96
+
97
+ # A command for displaying information about an index
98
+ class InfoCommand
99
+
100
+ def initialize(argv)
101
+ parse_options(argv)
102
+ end
103
+
104
+ def parse_options(argv)
105
+ OptionParser.new do |opt|
106
+ opt.banner = <<END
107
+ Displays information about an index.
108
+
109
+ Example:
110
+ svnlog info -p C:\\MyIndex
111
+
112
+ Usage: svnlog info [options]
113
+ END
114
+ opt.on("-p", "--path <val>", "The path to the index") { |@path| }
115
+ opt.parse!(argv)
116
+ end
117
+ end
118
+
119
+ def run
120
+ index = Index.new(@path)
121
+ return if index.size == 0
122
+ puts "Repository URL: #{index.repository_url}"
123
+ puts "Last Revision: #{index.last_revision}"
124
+ end
125
+ end
126
+
127
+ # A command for searching an index
128
+ class SearchCommand
129
+
130
+ def initialize(argv)
131
+ parse_options(argv)
132
+ @printer ||= SvnLogTextPrinter
133
+ end
134
+
135
+ def parse_options(argv)
136
+ OptionParser.new do |opt|
137
+ opt.banner = <<END
138
+ Searches an index for log entries that match a query.
139
+
140
+ Examples:
141
+ svnlog search -p C:\\MyIndex -q \"Fixed\"
142
+ svnlog search -p C:\\MyIndex -q \"Fixed\" --xml
143
+
144
+ Usage: svnlog search [options]
145
+ END
146
+ opt.on("-p", "--path <val>", "The path to the index") { |@path| }
147
+ opt.on("-q", "--query <val>", "The search query") { |@query| }
148
+ opt.on("-x", "--xml", "Output in XML") { @printer = SvnLogXmlPrinter }
149
+ opt.parse!(argv)
150
+ end
151
+ end
152
+
153
+ def run
154
+ entries = Index.new(@path).search(@query)
155
+ @printer.print entries
156
+ end
157
+
158
+ # Prints entries in the 'svn log' text format
159
+ class SvnLogTextPrinter
160
+
161
+ def self.print(entries)
162
+ print_entry_separator
163
+ for entry in entries
164
+ print_entry(entry)
165
+ print_entry_separator
166
+ end
167
+ end
168
+
169
+ private
170
+
171
+ def self.print_entry(entry)
172
+ puts "r#{entry[:revision]} | #{entry[:author]} | #{date(entry)} | #{line_count(entry)}"
173
+ puts
174
+ puts entry[:message]
175
+ end
176
+
177
+ def self.print_entry_separator
178
+ puts "-" * 72
179
+ end
180
+
181
+ def self.date(entry)
182
+ time = Time.parse(entry[:date]).localtime
183
+ time.strftime("%Y-%m-%d %H:%M:%S #{DateTime.parse(time.rfc822).zone} (%a, %d %B %Y)")
184
+ end
185
+
186
+ def self.line_count(entry)
187
+ line_count = entry[:message].count("\n") + 1
188
+ str = "#{line_count} line"
189
+ str += "s" if line_count > 1
190
+ str
191
+ end
192
+ end
193
+
194
+ # Prints entries in the 'svn log' xml format
195
+ class SvnLogXmlPrinter
196
+
197
+ def self.print(entries)
198
+ return unless entries.size > 0
199
+ puts "<?xml version=\"1.0\"?>"
200
+ puts "<log>"
201
+ for entry in entries
202
+ puts "<logentry revision=\"#{entry[:revision]}\">"
203
+ puts "<author>#{entry[:author]}</author>"
204
+ puts "<date>#{entry[:date]}</date>"
205
+ puts "<msg>#{entry[:message]}</msg>"
206
+ puts "</logentry>"
207
+ end
208
+ puts "</log>"
209
+ end
210
+ end
211
+ end
212
+ end
213
+
214
+ end
215
+ end
216
+
217
+ if __FILE__ == $0 then
218
+ Svn::Log::Application.new.run
219
+ end
220
+
221
+
@@ -0,0 +1,111 @@
1
+ require 'ferret'
2
+ include Ferret
3
+ include Ferret::Document
4
+ include Ferret::Search
5
+
6
+ require 'yaml'
7
+
8
+ module Svn
9
+ module Log
10
+
11
+ # An index of svn log entries
12
+ class Index
13
+
14
+ def initialize(path = nil, repository_url = nil)
15
+ @path = path
16
+ @index = Ferret::Index::Index.new(:path => @path, :key => :revision)
17
+ # load the properties
18
+ properties_path = @path && File.join(@path, "properties.yml")
19
+ @props = Properties.new(properties_path)
20
+ @props[:repository_url] ||= repository_url
21
+ end
22
+
23
+ # Returns the path to the index
24
+ def path
25
+ @path
26
+ end
27
+
28
+ # Returns the url of the repository that is indexed
29
+ def repository_url
30
+ @props[:repository_url]
31
+ end
32
+
33
+ # Returns the revision number of the last entry indexed
34
+ def last_revision
35
+ @props[:last_revision]
36
+ end
37
+
38
+ # Returns the number of entries in the index
39
+ def size
40
+ @index.size
41
+ end
42
+
43
+ # Updates the index with the latest entries
44
+ def update
45
+ revision = "#{last_revision.to_i}:HEAD"
46
+ entries = Log.new(repository_url).find(revision)
47
+ return if entries.size == 0
48
+ for entry in entries
49
+ add_entry(entry)
50
+ end
51
+ @index.flush
52
+ @props[:last_revision] = entries.last[:revision]
53
+ end
54
+
55
+ # Returns all entries that match the query
56
+ def search(query)
57
+ entries = []
58
+ options = {:num_docs => @index.size, :sort => SortField::FIELD_DOC }
59
+ for doc_id, score in @index.search(query, options)
60
+ entries << @index[doc_id]
61
+ end
62
+ entries
63
+ end
64
+
65
+ # Close the index when you're done with it
66
+ def close
67
+ @index.close
68
+ end
69
+
70
+ private
71
+
72
+ # Adds a new entry to the index
73
+ def add_entry(entry)
74
+ doc = Document.new
75
+ doc << Field.new(:revision, entry[:revision], Field::Store::YES, Field::Index::UNTOKENIZED)
76
+ doc << Field.new(:author, entry[:author], Field::Store::YES, Field::Index::UNTOKENIZED)
77
+ doc << Field.new(:message, entry[:message], Field::Store::YES, Field::Index::TOKENIZED)
78
+ doc << Field.new(:date, entry[:date], Field::Store::YES, Field::Index::UNTOKENIZED)
79
+ @index << doc
80
+ end
81
+ end
82
+
83
+ # A set of persistent properties
84
+ class Properties
85
+
86
+ def initialize(path = nil)
87
+ @data = {}
88
+ @path = path
89
+ if @path && File.exists?(@path)
90
+ File.open(@path) do |file|
91
+ @data = YAML.load(file)
92
+ end
93
+ end
94
+ end
95
+
96
+ def [](name)
97
+ @data[name]
98
+ end
99
+
100
+ def []=(name, value)
101
+ @data[name] = value
102
+ if @path
103
+ File.open(@path, "w") do |file|
104
+ YAML.dump(@data, file)
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ end
111
+ end
@@ -0,0 +1,37 @@
1
+ require 'rexml/document'
2
+
3
+ module Svn
4
+ module Log
5
+
6
+ # An svn log
7
+ class Log
8
+
9
+ def initialize(repository_url)
10
+ @repository_url = repository_url
11
+ end
12
+
13
+ # Returns all entries
14
+ def entries
15
+ find("1:HEAD")
16
+ end
17
+
18
+ # Returns entries that match the specified revision (which can be a range)
19
+ def find(revision)
20
+ entries = []
21
+ doc = REXML::Document.new(`svn log \"#{@repository_url}\" --revision #{revision} --xml`)
22
+ doc.elements.each('/log/logentry') do |element|
23
+ entry = {}
24
+ entry[:revision] = element.attribute('revision').value
25
+ entry[:author] = element.text('author')
26
+ entry[:message] = element.text('msg')
27
+ entry[:date] = element.text('date')
28
+ entries << entry
29
+ end
30
+ entries
31
+ end
32
+
33
+ alias [] find
34
+ end
35
+
36
+ end
37
+ end
@@ -0,0 +1,5 @@
1
+ This is a Subversion repository; use the 'svnadmin' tool to examine
2
+ it. Do not add, delete, or modify files here unless you know how
3
+ to avoid corrupting the repository.
4
+
5
+ Visit http://subversion.tigris.org/ for more information.
@@ -0,0 +1,21 @@
1
+ ### This file is an example authorization file for svnserve.
2
+ ### Its format is identical to that of mod_authz_svn authorization
3
+ ### files.
4
+ ### As shown below each section defines authorizations for the path and
5
+ ### (optional) repository specified by the section name.
6
+ ### The authorizations follow. An authorization line can refer to a
7
+ ### single user, to a group of users defined in a special [groups]
8
+ ### section, or to anyone using the '*' wildcard. Each definition can
9
+ ### grant read ('r') access, read-write ('rw') access, or no access
10
+ ### ('').
11
+
12
+ # [groups]
13
+ # harry_and_sally = harry,sally
14
+
15
+ # [/foo/bar]
16
+ # harry = rw
17
+ # * =
18
+
19
+ # [repository:/baz/fuz]
20
+ # @harry_and_sally = rw
21
+ # * = r
@@ -0,0 +1,8 @@
1
+ ### This file is an example password file for svnserve.
2
+ ### Its format is similar to that of svnserve.conf. As shown in the
3
+ ### example below it contains one section labelled [users].
4
+ ### The name and password for each user follow, one account per line.
5
+
6
+ # [users]
7
+ # harry = harryssecret
8
+ # sally = sallyssecret
@@ -0,0 +1,30 @@
1
+ ### This file controls the configuration of the svnserve daemon, if you
2
+ ### use it to allow access to this repository. (If you only allow
3
+ ### access through http: and/or file: URLs, then this file is
4
+ ### irrelevant.)
5
+
6
+ ### Visit http://subversion.tigris.org/ for more information.
7
+
8
+ # [general]
9
+ ### These options control access to the repository for unauthenticated
10
+ ### and authenticated users. Valid values are "write", "read",
11
+ ### and "none". The sample settings below are the defaults.
12
+ # anon-access = read
13
+ # auth-access = write
14
+ ### The password-db option controls the location of the password
15
+ ### database file. Unless you specify a path starting with a /,
16
+ ### the file's location is relative to the conf directory.
17
+ ### Uncomment the line below to use the default password file.
18
+ # password-db = passwd
19
+ ### The authz-db option controls the location of the authorization
20
+ ### rules for path-based access control. Unless you specify a path
21
+ ### starting with a /, the file's location is relative to the conf
22
+ ### directory. If you don't specify an authz-db, no path-based access
23
+ ### control is done.
24
+ ### Uncomment the line below to use the default authorization file.
25
+ # authz-db = authz
26
+ ### This option specifies the authentication realm of the repository.
27
+ ### If two repositories have the same authentication realm, they should
28
+ ### have the same password database, and vice versa. The default realm
29
+ ### is repository's uuid.
30
+ # realm = My First Repository
@@ -0,0 +1 @@
1
+ 3 2 1
@@ -0,0 +1 @@
1
+ 1
@@ -0,0 +1 @@
1
+ fsfs
@@ -0,0 +1,5 @@
1
+ K 8
2
+ svn:date
3
+ V 27
4
+ 2006-05-27T14:45:25.061201Z
5
+ END
@@ -0,0 +1,13 @@
1
+ K 10
2
+ svn:author
3
+ V 4
4
+ Josh
5
+ K 8
6
+ svn:date
7
+ V 27
8
+ 2006-05-27T14:47:41.978078Z
9
+ K 7
10
+ svn:log
11
+ V 19
12
+ Initial add of file
13
+ END
@@ -0,0 +1,13 @@
1
+ K 10
2
+ svn:author
3
+ V 4
4
+ Josh
5
+ K 8
6
+ svn:date
7
+ V 27
8
+ 2006-05-27T14:48:12.852473Z
9
+ K 7
10
+ svn:log
11
+ V 20
12
+ Changed a few things
13
+ END
@@ -0,0 +1,13 @@
1
+ K 10
2
+ svn:author
3
+ V 4
4
+ Josh
5
+ K 8
6
+ svn:date
7
+ V 27
8
+ 2006-05-27T14:49:01.762803Z
9
+ K 7
10
+ svn:log
11
+ V 18
12
+ Yet another change
13
+ END
@@ -0,0 +1,11 @@
1
+ PLAIN
2
+ END
3
+ ENDREP
4
+ id: 0.0.r0/17
5
+ type: dir
6
+ count: 0
7
+ text: 0 0 4 4 2d2977d1c96f487abe4a1e202dd03b4e
8
+ cpath: /
9
+
10
+
11
+ 17 107
Binary file
Binary file
Binary file
@@ -0,0 +1 @@
1
+ 27638544-d82e-7546-8798-448353dc9678
File without changes
@@ -0,0 +1 @@
1
+ 3
@@ -0,0 +1,51 @@
1
+ #!/bin/sh
2
+
3
+ # POST-COMMIT HOOK
4
+ #
5
+ # The post-commit hook is invoked after a commit. Subversion runs
6
+ # this hook by invoking a program (script, executable, binary, etc.)
7
+ # named 'post-commit' (for which this file is a template) with the
8
+ # following ordered arguments:
9
+ #
10
+ # [1] REPOS-PATH (the path to this repository)
11
+ # [2] REV (the number of the revision just committed)
12
+ #
13
+ # The default working directory for the invocation is undefined, so
14
+ # the program should set one explicitly if it cares.
15
+ #
16
+ # Because the commit has already completed and cannot be undone,
17
+ # the exit code of the hook program is ignored. The hook program
18
+ # can use the 'svnlook' utility to help it examine the
19
+ # newly-committed tree.
20
+ #
21
+ # On a Unix system, the normal procedure is to have 'post-commit'
22
+ # invoke other programs to do the real work, though it may do the
23
+ # work itself too.
24
+ #
25
+ # Note that 'post-commit' must be executable by the user(s) who will
26
+ # invoke it (typically the user httpd runs as), and that user must
27
+ # have filesystem-level permission to access the repository.
28
+ #
29
+ # On a Windows system, you should name the hook program
30
+ # 'post-commit.bat' or 'post-commit.exe',
31
+ # but the basic idea is the same.
32
+ #
33
+ # The hook program typically does not inherit the environment of
34
+ # its parent process. For example, a common problem is for the
35
+ # PATH environment variable to not be set to its usual value, so
36
+ # that subprograms fail to launch unless invoked via absolute path.
37
+ # If you're having unexpected problems with a hook program, the
38
+ # culprit may be unusual (or missing) environment variables.
39
+ #
40
+ # Here is an example hook script, for a Unix /bin/sh interpreter.
41
+ # For more examples and pre-written hooks, see those in
42
+ # the Subversion repository at
43
+ # http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/ and
44
+ # http://svn.collab.net/repos/svn/trunk/contrib/hook-scripts/
45
+
46
+
47
+ REPOS="$1"
48
+ REV="$2"
49
+
50
+ commit-email.pl "$REPOS" "$REV" commit-watchers@example.org
51
+ log-commit.py --repository "$REPOS" --revision "$REV"
@@ -0,0 +1,44 @@
1
+ #!/bin/sh
2
+
3
+ # POST-LOCK HOOK
4
+ #
5
+ # The post-lock hook is run after a path is locked. Subversion runs
6
+ # this hook by invoking a program (script, executable, binary, etc.)
7
+ # named 'post-lock' (for which this file is a template) with the
8
+ # following ordered arguments:
9
+ #
10
+ # [1] REPOS-PATH (the path to this repository)
11
+ # [2] USER (the user who created the lock)
12
+ #
13
+ # The paths that were just locked are passed to the hook via STDIN (as
14
+ # of Subversion 1.2, only one path is passed per invocation, but the
15
+ # plan is to pass all locked paths at once, so the hook program
16
+ # should be written accordingly).
17
+ #
18
+ # The default working directory for the invocation is undefined, so
19
+ # the program should set one explicitly if it cares.
20
+ #
21
+ # Because the lock has already been created and cannot be undone,
22
+ # the exit code of the hook program is ignored. The hook program
23
+ # can use the 'svnlook' utility to help it examine the
24
+ # newly-created lock.
25
+ #
26
+ # On a Unix system, the normal procedure is to have 'post-lock'
27
+ # invoke other programs to do the real work, though it may do the
28
+ # work itself too.
29
+ #
30
+ # Note that 'post-lock' must be executable by the user(s) who will
31
+ # invoke it (typically the user httpd runs as), and that user must
32
+ # have filesystem-level permission to access the repository.
33
+ #
34
+ # On a Windows system, you should name the hook program
35
+ # 'post-lock.bat' or 'post-lock.exe',
36
+ # but the basic idea is the same.
37
+ #
38
+ # Here is an example hook script, for a Unix /bin/sh interpreter:
39
+
40
+ REPOS="$1"
41
+ USER="$2"
42
+
43
+ # Send email to interested parties, let them know a lock was created:
44
+ mailer.py lock "$REPOS" "$USER" /path/to/mailer.conf
@@ -0,0 +1,56 @@
1
+ #!/bin/sh
2
+
3
+ # POST-REVPROP-CHANGE HOOK
4
+ #
5
+ # The post-revprop-change hook is invoked after a revision property
6
+ # has been added, modified or deleted. Subversion runs this hook by
7
+ # invoking a program (script, executable, binary, etc.) named
8
+ # 'post-revprop-change' (for which this file is a template), with the
9
+ # following ordered arguments:
10
+ #
11
+ # [1] REPOS-PATH (the path to this repository)
12
+ # [2] REV (the revision that was tweaked)
13
+ # [3] USER (the username of the person tweaking the property)
14
+ # [4] PROPNAME (the property that was changed)
15
+ # [5] ACTION (the property was 'A'dded, 'M'odified, or 'D'eleted)
16
+ #
17
+ # [STDIN] PROPVAL ** the old property value is passed via STDIN.
18
+ #
19
+ # Because the propchange has already completed and cannot be undone,
20
+ # the exit code of the hook program is ignored. The hook program
21
+ # can use the 'svnlook' utility to help it examine the
22
+ # new property value.
23
+ #
24
+ # On a Unix system, the normal procedure is to have 'post-revprop-change'
25
+ # invoke other programs to do the real work, though it may do the
26
+ # work itself too.
27
+ #
28
+ # Note that 'post-revprop-change' must be executable by the user(s) who will
29
+ # invoke it (typically the user httpd runs as), and that user must
30
+ # have filesystem-level permission to access the repository.
31
+ #
32
+ # On a Windows system, you should name the hook program
33
+ # 'post-revprop-change.bat' or 'post-revprop-change.exe',
34
+ # but the basic idea is the same.
35
+ #
36
+ # The hook program typically does not inherit the environment of
37
+ # its parent process. For example, a common problem is for the
38
+ # PATH environment variable to not be set to its usual value, so
39
+ # that subprograms fail to launch unless invoked via absolute path.
40
+ # If you're having unexpected problems with a hook program, the
41
+ # culprit may be unusual (or missing) environment variables.
42
+ #
43
+ # Here is an example hook script, for a Unix /bin/sh interpreter.
44
+ # For more examples and pre-written hooks, see those in
45
+ # the Subversion repository at
46
+ # http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/ and
47
+ # http://svn.collab.net/repos/svn/trunk/contrib/hook-scripts/
48
+
49
+
50
+ REPOS="$1"
51
+ REV="$2"
52
+ USER="$3"
53
+ PROPNAME="$4"
54
+ ACTION="$5"
55
+
56
+ propchange-email.pl "$REPOS" "$REV" "$USER" "$PROPNAME" watchers@example.org
@@ -0,0 +1,42 @@
1
+ #!/bin/sh
2
+
3
+ # POST-UNLOCK HOOK
4
+ #
5
+ # The post-unlock hook runs after a path is unlocked. Subversion runs
6
+ # this hook by invoking a program (script, executable, binary, etc.)
7
+ # named 'post-unlock' (for which this file is a template) with the
8
+ # following ordered arguments:
9
+ #
10
+ # [1] REPOS-PATH (the path to this repository)
11
+ # [2] USER (the user who destroyed the lock)
12
+ #
13
+ # The paths that were just unlocked are passed to the hook via STDIN
14
+ # (as of Subversion 1.2, only one path is passed per invocation, but
15
+ # the plan is to pass all unlocked paths at once, so the hook program
16
+ # should be written accordingly).
17
+ #
18
+ # The default working directory for the invocation is undefined, so
19
+ # the program should set one explicitly if it cares.
20
+ #
21
+ # Because the lock has already been destroyed and cannot be undone,
22
+ # the exit code of the hook program is ignored.
23
+ #
24
+ # On a Unix system, the normal procedure is to have 'post-unlock'
25
+ # invoke other programs to do the real work, though it may do the
26
+ # work itself too.
27
+ #
28
+ # Note that 'post-unlock' must be executable by the user(s) who will
29
+ # invoke it (typically the user httpd runs as), and that user must
30
+ # have filesystem-level permission to access the repository.
31
+ #
32
+ # On a Windows system, you should name the hook program
33
+ # 'post-unlock.bat' or 'post-unlock.exe',
34
+ # but the basic idea is the same.
35
+ #
36
+ # Here is an example hook script, for a Unix /bin/sh interpreter:
37
+
38
+ REPOS="$1"
39
+ USER="$2"
40
+
41
+ # Send email to interested parties, let them know a lock was removed:
42
+ mailer.py unlock "$REPOS" "$USER" /path/to/mailer.conf
@@ -0,0 +1,70 @@
1
+ #!/bin/sh
2
+
3
+ # PRE-COMMIT HOOK
4
+ #
5
+ # The pre-commit hook is invoked before a Subversion txn is
6
+ # committed. Subversion runs this hook by invoking a program
7
+ # (script, executable, binary, etc.) named 'pre-commit' (for which
8
+ # this file is a template), with the following ordered arguments:
9
+ #
10
+ # [1] REPOS-PATH (the path to this repository)
11
+ # [2] TXN-NAME (the name of the txn about to be committed)
12
+ #
13
+ # The default working directory for the invocation is undefined, so
14
+ # the program should set one explicitly if it cares.
15
+ #
16
+ # If the hook program exits with success, the txn is committed; but
17
+ # if it exits with failure (non-zero), the txn is aborted, no commit
18
+ # takes place, and STDERR is returned to the client. The hook
19
+ # program can use the 'svnlook' utility to help it examine the txn.
20
+ #
21
+ # On a Unix system, the normal procedure is to have 'pre-commit'
22
+ # invoke other programs to do the real work, though it may do the
23
+ # work itself too.
24
+ #
25
+ # *** NOTE: THE HOOK PROGRAM MUST NOT MODIFY THE TXN, EXCEPT ***
26
+ # *** FOR REVISION PROPERTIES (like svn:log or svn:author). ***
27
+ #
28
+ # This is why we recommend using the read-only 'svnlook' utility.
29
+ # In the future, Subversion may enforce the rule that pre-commit
30
+ # hooks should not modify the versioned data in txns, or else come
31
+ # up with a mechanism to make it safe to do so (by informing the
32
+ # committing client of the changes). However, right now neither
33
+ # mechanism is implemented, so hook writers just have to be careful.
34
+ #
35
+ # Note that 'pre-commit' must be executable by the user(s) who will
36
+ # invoke it (typically the user httpd runs as), and that user must
37
+ # have filesystem-level permission to access the repository.
38
+ #
39
+ # On a Windows system, you should name the hook program
40
+ # 'pre-commit.bat' or 'pre-commit.exe',
41
+ # but the basic idea is the same.
42
+ #
43
+ # The hook program typically does not inherit the environment of
44
+ # its parent process. For example, a common problem is for the
45
+ # PATH environment variable to not be set to its usual value, so
46
+ # that subprograms fail to launch unless invoked via absolute path.
47
+ # If you're having unexpected problems with a hook program, the
48
+ # culprit may be unusual (or missing) environment variables.
49
+ #
50
+ # Here is an example hook script, for a Unix /bin/sh interpreter.
51
+ # For more examples and pre-written hooks, see those in
52
+ # the Subversion repository at
53
+ # http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/ and
54
+ # http://svn.collab.net/repos/svn/trunk/contrib/hook-scripts/
55
+
56
+
57
+ REPOS="$1"
58
+ TXN="$2"
59
+
60
+ # Make sure that the log message contains some text.
61
+ SVNLOOK=/usr/local/bin/svnlook
62
+ $SVNLOOK log -t "$TXN" "$REPOS" | \
63
+ grep "[a-zA-Z0-9]" > /dev/null || exit 1
64
+
65
+ # Check that the author of this commit has the rights to perform
66
+ # the commit on the files and directories being modified.
67
+ commit-access-control.pl "$REPOS" "$TXN" commit-access-control.cfg || exit 1
68
+
69
+ # All checks passed, so allow the commit.
70
+ exit 0
@@ -0,0 +1,64 @@
1
+ #!/bin/sh
2
+
3
+ # PRE-LOCK HOOK
4
+ #
5
+ # The pre-lock hook is invoked before an exclusive lock is
6
+ # created. Subversion runs this hook by invoking a program
7
+ # (script, executable, binary, etc.) named 'pre-lock' (for which
8
+ # this file is a template), with the following ordered arguments:
9
+ #
10
+ # [1] REPOS-PATH (the path to this repository)
11
+ # [2] PATH (the path in the repository about to be locked)
12
+ # [3] USER (the user creating the lock)
13
+ #
14
+ # The default working directory for the invocation is undefined, so
15
+ # the program should set one explicitly if it cares.
16
+ #
17
+ # If the hook program exits with success, the lock is created; but
18
+ # if it exits with failure (non-zero), the lock action is aborted
19
+ # and STDERR is returned to the client.
20
+
21
+ # On a Unix system, the normal procedure is to have 'pre-lock'
22
+ # invoke other programs to do the real work, though it may do the
23
+ # work itself too.
24
+ #
25
+ # Note that 'pre-lock' must be executable by the user(s) who will
26
+ # invoke it (typically the user httpd runs as), and that user must
27
+ # have filesystem-level permission to access the repository.
28
+ #
29
+ # On a Windows system, you should name the hook program
30
+ # 'pre-lock.bat' or 'pre-lock.exe',
31
+ # but the basic idea is the same.
32
+ #
33
+ # Here is an example hook script, for a Unix /bin/sh interpreter:
34
+
35
+ REPOS="$1"
36
+ PATH="$2"
37
+ USER="$3"
38
+
39
+ # If a lock exists and is owned by a different person, don't allow it
40
+ # to be stolen (e.g., with 'svn lock --force ...').
41
+
42
+ # (Maybe this script could send email to the lock owner?)
43
+ SVNLOOK=/usr/local/bin/svnlook
44
+ GREP=/bin/grep
45
+ SED=/bin/sed
46
+
47
+ LOCK_OWNER=`$SVNLOOK lock "$REPOS" "$PATH" | \
48
+ $GREP '^Owner: ' | $SED 's/Owner: //'`
49
+
50
+ # If we get no result from svnlook, there's no lock, allow the lock to
51
+ # happen:
52
+ if [ "$LOCK_OWNER" == "" ]; then
53
+ exit 0
54
+ fi
55
+
56
+ # If the person locking matches the lock's owner, allow the lock to
57
+ # happen:
58
+ if [ "$LOCK_OWNER" == "$USER" ]; then
59
+ exit 0
60
+ fi
61
+
62
+ # Otherwise, we've got an owner mismatch, so return failure:
63
+ echo "Error: $PATH already locked by ${LOCK_OWNER}." 1>&2
64
+ exit 1
@@ -0,0 +1,66 @@
1
+ #!/bin/sh
2
+
3
+ # PRE-REVPROP-CHANGE HOOK
4
+ #
5
+ # The pre-revprop-change hook is invoked before a revision property
6
+ # is added, modified or deleted. Subversion runs this hook by invoking
7
+ # a program (script, executable, binary, etc.) named 'pre-revprop-change'
8
+ # (for which this file is a template), with the following ordered
9
+ # arguments:
10
+ #
11
+ # [1] REPOS-PATH (the path to this repository)
12
+ # [2] REVISION (the revision being tweaked)
13
+ # [3] USER (the username of the person tweaking the property)
14
+ # [4] PROPNAME (the property being set on the revision)
15
+ # [5] ACTION (the property is being 'A'dded, 'M'odified, or 'D'eleted)
16
+ #
17
+ # [STDIN] PROPVAL ** the new property value is passed via STDIN.
18
+ #
19
+ # If the hook program exits with success, the propchange happens; but
20
+ # if it exits with failure (non-zero), the propchange doesn't happen.
21
+ # The hook program can use the 'svnlook' utility to examine the
22
+ # existing value of the revision property.
23
+ #
24
+ # WARNING: unlike other hooks, this hook MUST exist for revision
25
+ # properties to be changed. If the hook does not exist, Subversion
26
+ # will behave as if the hook were present, but failed. The reason
27
+ # for this is that revision properties are UNVERSIONED, meaning that
28
+ # a successful propchange is destructive; the old value is gone
29
+ # forever. We recommend the hook back up the old value somewhere.
30
+ #
31
+ # On a Unix system, the normal procedure is to have 'pre-revprop-change'
32
+ # invoke other programs to do the real work, though it may do the
33
+ # work itself too.
34
+ #
35
+ # Note that 'pre-revprop-change' must be executable by the user(s) who will
36
+ # invoke it (typically the user httpd runs as), and that user must
37
+ # have filesystem-level permission to access the repository.
38
+ #
39
+ # On a Windows system, you should name the hook program
40
+ # 'pre-revprop-change.bat' or 'pre-revprop-change.exe',
41
+ # but the basic idea is the same.
42
+ #
43
+ # The hook program typically does not inherit the environment of
44
+ # its parent process. For example, a common problem is for the
45
+ # PATH environment variable to not be set to its usual value, so
46
+ # that subprograms fail to launch unless invoked via absolute path.
47
+ # If you're having unexpected problems with a hook program, the
48
+ # culprit may be unusual (or missing) environment variables.
49
+ #
50
+ # Here is an example hook script, for a Unix /bin/sh interpreter.
51
+ # For more examples and pre-written hooks, see those in
52
+ # the Subversion repository at
53
+ # http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/ and
54
+ # http://svn.collab.net/repos/svn/trunk/contrib/hook-scripts/
55
+
56
+
57
+ REPOS="$1"
58
+ REV="$2"
59
+ USER="$3"
60
+ PROPNAME="$4"
61
+ ACTION="$5"
62
+
63
+ if [ "$ACTION" = "M" -a "$PROPNAME" = "svn:log" ]; then exit 0; fi
64
+
65
+ echo "Changing revision properties other than svn:log is prohibited" >&2
66
+ exit 1
@@ -0,0 +1,60 @@
1
+ #!/bin/sh
2
+
3
+ # PRE-UNLOCK HOOK
4
+ #
5
+ # The pre-unlock hook is invoked before an exclusive lock is
6
+ # destroyed. Subversion runs this hook by invoking a program
7
+ # (script, executable, binary, etc.) named 'pre-unlock' (for which
8
+ # this file is a template), with the following ordered arguments:
9
+ #
10
+ # [1] REPOS-PATH (the path to this repository)
11
+ # [2] PATH (the path in the repository about to be unlocked)
12
+ # [3] USER (the user destroying the lock)
13
+ #
14
+ # The default working directory for the invocation is undefined, so
15
+ # the program should set one explicitly if it cares.
16
+ #
17
+ # If the hook program exits with success, the lock is destroyed; but
18
+ # if it exits with failure (non-zero), the unlock action is aborted
19
+ # and STDERR is returned to the client.
20
+
21
+ # On a Unix system, the normal procedure is to have 'pre-unlock'
22
+ # invoke other programs to do the real work, though it may do the
23
+ # work itself too.
24
+ #
25
+ # Note that 'pre-unlock' must be executable by the user(s) who will
26
+ # invoke it (typically the user httpd runs as), and that user must
27
+ # have filesystem-level permission to access the repository.
28
+ #
29
+ # On a Windows system, you should name the hook program
30
+ # 'pre-unlock.bat' or 'pre-unlock.exe',
31
+ # but the basic idea is the same.
32
+ #
33
+ # Here is an example hook script, for a Unix /bin/sh interpreter:
34
+
35
+ REPOS="$1"
36
+ PATH="$2"
37
+ USER="$3"
38
+
39
+ # If a lock is owned by a different person, don't allow it be broken.
40
+ # (Maybe this script could send email to the lock owner?)
41
+
42
+ SVNLOOK=/usr/local/bin/svnlook
43
+ GREP=/bin/grep
44
+ SED=/bin/sed
45
+
46
+ LOCK_OWNER=`$SVNLOOK lock "$REPOS" "$PATH" | \
47
+ $GREP '^Owner: ' | $SED 's/Owner: //'`
48
+
49
+ # If we get no result from svnlook, there's no lock, return success:
50
+ if [ "$LOCK_OWNER" == "" ]; then
51
+ exit 0
52
+ fi
53
+ # If the person unlocking matches the lock's owner, return success:
54
+ if [ "$LOCK_OWNER" == "$USER" ]; then
55
+ exit 0
56
+ fi
57
+
58
+ # Otherwise, we've got an owner mismatch, so return failure:
59
+ echo "Error: $PATH locked by ${LOCK_OWNER}." 1>&2
60
+ exit 1
@@ -0,0 +1,54 @@
1
+ #!/bin/sh
2
+
3
+ # START-COMMIT HOOK
4
+ #
5
+ # The start-commit hook is invoked before a Subversion txn is created
6
+ # in the process of doing a commit. Subversion runs this hook
7
+ # by invoking a program (script, executable, binary, etc.) named
8
+ # 'start-commit' (for which this file is a template)
9
+ # with the following ordered arguments:
10
+ #
11
+ # [1] REPOS-PATH (the path to this repository)
12
+ # [2] USER (the authenticated user attempting to commit)
13
+ #
14
+ # The default working directory for the invocation is undefined, so
15
+ # the program should set one explicitly if it cares.
16
+ #
17
+ # If the hook program exits with success, the commit continues; but
18
+ # if it exits with failure (non-zero), the commit is stopped before
19
+ # a Subversion txn is created, and STDERR is returned to the client.
20
+ #
21
+ # On a Unix system, the normal procedure is to have 'start-commit'
22
+ # invoke other programs to do the real work, though it may do the
23
+ # work itself too.
24
+ #
25
+ # Note that 'start-commit' must be executable by the user(s) who will
26
+ # invoke it (typically the user httpd runs as), and that user must
27
+ # have filesystem-level permission to access the repository.
28
+ #
29
+ # On a Windows system, you should name the hook program
30
+ # 'start-commit.bat' or 'start-commit.exe',
31
+ # but the basic idea is the same.
32
+ #
33
+ # The hook program typically does not inherit the environment of
34
+ # its parent process. For example, a common problem is for the
35
+ # PATH environment variable to not be set to its usual value, so
36
+ # that subprograms fail to launch unless invoked via absolute path.
37
+ # If you're having unexpected problems with a hook program, the
38
+ # culprit may be unusual (or missing) environment variables.
39
+ #
40
+ # Here is an example hook script, for a Unix /bin/sh interpreter.
41
+ # For more examples and pre-written hooks, see those in
42
+ # the Subversion repository at
43
+ # http://svn.collab.net/repos/svn/trunk/tools/hook-scripts/ and
44
+ # http://svn.collab.net/repos/svn/trunk/contrib/hook-scripts/
45
+
46
+
47
+ REPOS="$1"
48
+ USER="$2"
49
+
50
+ commit-allower.pl --repository "$REPOS" --user "$USER" || exit 1
51
+ special-auth-check.py --user "$USER" --auth-level 3 || exit 1
52
+
53
+ # All checks passed, so allow the commit.
54
+ exit 0
@@ -0,0 +1,3 @@
1
+ This file is not used by Subversion 1.3.x or later.
2
+ However, its existence is required for compatibility with
3
+ Subversion 1.2.x or earlier.
@@ -0,0 +1,3 @@
1
+ This file is not used by Subversion 1.3.x or later.
2
+ However, its existence is required for compatibility with
3
+ Subversion 1.2.x or earlier.
@@ -0,0 +1,9 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
3
+
4
+ require 'test/unit'
5
+
6
+ require 'svnlog'
7
+ include Svn::Log
8
+
9
+ REPOSITORY_URL = "file:///" + File.join(File.dirname(File.expand_path(__FILE__)), "data", "repos")
@@ -0,0 +1,4 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ require 'test_log'
4
+ require 'test_index'
@@ -0,0 +1,71 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ require 'tmpdir'
4
+ require 'fileutils'
5
+
6
+ class IndexTest < Test::Unit::TestCase
7
+
8
+ TEMP_DIR = File.join(Dir.tmpdir, "SvnLogTest")
9
+
10
+ # Create the index
11
+ def setup
12
+ FileUtils.makedirs(TEMP_DIR)
13
+ path = File.join(TEMP_DIR, "index")
14
+ @index = Index.new(path, REPOSITORY_URL)
15
+ @index.update
16
+ end
17
+
18
+ # Delete the index
19
+ def teardown
20
+ @index.close
21
+ FileUtils.remove_dir(TEMP_DIR, true)
22
+ end
23
+
24
+ def test_duplicate_entries_not_added
25
+ assert_equal 3, @index.size
26
+ @index.update
27
+ assert_equal 3, @index.size
28
+ end
29
+
30
+ # The index should remember the url of the repository resource it is indexing
31
+ def test_remember_repository_url
32
+ index = Index.new(@index.path)
33
+ assert_equal REPOSITORY_URL, index.repository_url
34
+ end
35
+
36
+ # The index should remember the revision of the last entry indexed
37
+ def test_remember_last_revision
38
+ index = Index.new(@index.path)
39
+ assert_equal "3", index.last_revision
40
+ end
41
+
42
+ def test_default_search
43
+ entries = @index.search("Changed")
44
+ assert_equal 1, entries.size
45
+ entries.each do |entry|
46
+ assert_equal "2", entry[:revision]
47
+ assert_equal "Josh", entry[:author]
48
+ assert_equal "Changed a few things", entry[:message]
49
+ end
50
+ end
51
+
52
+ def test_message_search
53
+ entries = @index.search("message:Changed")
54
+ assert_equal 1, entries.size
55
+ entries.each do |entry|
56
+ assert_equal "2", entry[:revision]
57
+ assert_equal "Josh", entry[:author]
58
+ assert_equal "Changed a few things", entry[:message]
59
+ end
60
+ end
61
+
62
+ def test_revision_search
63
+ entries = @index.search("revision:2")
64
+ assert_equal 1, entries.size
65
+ entries.each do |entry|
66
+ assert_equal "2", entry[:revision]
67
+ assert_equal "Josh", entry[:author]
68
+ assert_equal "Changed a few things", entry[:message]
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,29 @@
1
+ require File.dirname(__FILE__) + '/helper'
2
+
3
+ class LogTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @log = Log.new(REPOSITORY_URL)
7
+ end
8
+
9
+ def test_find_single_entry
10
+ entries = @log.find("2")
11
+ assert_equal 1, entries.size
12
+ entry = entries[0]
13
+ assert_equal "Josh", entry[:author]
14
+ assert_equal "Changed a few things", entry[:message]
15
+ entries = @log["2"]
16
+ assert_equal 1, entries.size
17
+ entry = entries[0]
18
+ assert_equal "Josh", entry[:author]
19
+ assert_equal "Changed a few things", entry[:message]
20
+ end
21
+
22
+ def test_find_all_entries
23
+ entries = @log.entries
24
+ assert_equal 3, entries.size
25
+ assert_equal "1", entries[0][:revision]
26
+ assert_equal "2", entries[1][:revision]
27
+ assert_equal "3", entries[2][:revision]
28
+ end
29
+ end
metadata ADDED
@@ -0,0 +1,96 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.8.10
3
+ specification_version: 1
4
+ name: SvnLog
5
+ version: !ruby/object:Gem::Version
6
+ version: 1.0.0
7
+ date: 2006-06-13
8
+ summary: Full-text search of Subversion commit logs
9
+ require_paths:
10
+ - lib
11
+ email: jdaltry@gmail.com
12
+ homepage:
13
+ rubyforge_project:
14
+ description:
15
+ autorequire:
16
+ default_executable: svnlog
17
+ bindir: bin
18
+ has_rdoc: false
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ -
22
+ - ">"
23
+ - !ruby/object:Gem::Version
24
+ version: 0.0.0
25
+ version:
26
+ platform: ruby
27
+ authors:
28
+ - Josh Daltry
29
+ files:
30
+ - bin/svnlog
31
+ - lib/svnlog
32
+ - lib/svnlog.rb
33
+ - lib/svnlog/index.rb
34
+ - lib/svnlog/log.rb
35
+ - test/data
36
+ - test/helper.rb
37
+ - test/test_all.rb
38
+ - test/test_index.rb
39
+ - test/test_log.rb
40
+ - test/data/repos
41
+ - test/data/repos/conf
42
+ - test/data/repos/dav
43
+ - test/data/repos/db
44
+ - test/data/repos/format
45
+ - test/data/repos/hooks
46
+ - test/data/repos/locks
47
+ - test/data/repos/README.txt
48
+ - test/data/repos/conf/authz
49
+ - test/data/repos/conf/passwd
50
+ - test/data/repos/conf/svnserve.conf
51
+ - test/data/repos/db/current
52
+ - test/data/repos/db/format
53
+ - test/data/repos/db/fs-type
54
+ - test/data/repos/db/revprops
55
+ - test/data/repos/db/revs
56
+ - test/data/repos/db/transactions
57
+ - test/data/repos/db/uuid
58
+ - test/data/repos/db/write-lock
59
+ - test/data/repos/db/revprops/0
60
+ - test/data/repos/db/revprops/1
61
+ - test/data/repos/db/revprops/2
62
+ - test/data/repos/db/revprops/3
63
+ - test/data/repos/db/revs/0
64
+ - test/data/repos/db/revs/1
65
+ - test/data/repos/db/revs/2
66
+ - test/data/repos/db/revs/3
67
+ - test/data/repos/hooks/post-commit.tmpl
68
+ - test/data/repos/hooks/post-lock.tmpl
69
+ - test/data/repos/hooks/post-revprop-change.tmpl
70
+ - test/data/repos/hooks/post-unlock.tmpl
71
+ - test/data/repos/hooks/pre-commit.tmpl
72
+ - test/data/repos/hooks/pre-lock.tmpl
73
+ - test/data/repos/hooks/pre-revprop-change.tmpl
74
+ - test/data/repos/hooks/pre-unlock.tmpl
75
+ - test/data/repos/hooks/start-commit.tmpl
76
+ - test/data/repos/locks/db-logs.lock
77
+ - test/data/repos/locks/db.lock
78
+ test_files:
79
+ - test/test_all.rb
80
+ rdoc_options: []
81
+ extra_rdoc_files: []
82
+ executables:
83
+ - svnlog
84
+ extensions: []
85
+ requirements: []
86
+ dependencies:
87
+ - !ruby/object:Gem::Dependency
88
+ name: ferret
89
+ version_requirement:
90
+ version_requirements: !ruby/object:Gem::Version::Requirement
91
+ requirements:
92
+ -
93
+ - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 0.9.0
96
+ version: