niklas-vimmate 0.8.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. data/.autotest +10 -0
  2. data/CHANGELOG +108 -0
  3. data/COPYING +20 -0
  4. data/README +221 -0
  5. data/Rakefile +97 -0
  6. data/TODO +21 -0
  7. data/bin/vimmate +95 -0
  8. data/config/environment.rb +33 -0
  9. data/controllers/file_filter_controller.rb +85 -0
  10. data/controllers/file_popup_menu_controller.rb +40 -0
  11. data/controllers/vim_controller.rb +28 -0
  12. data/controllers/vim_mate_controller.rb +76 -0
  13. data/images/file.png +0 -0
  14. data/images/file_green.png +0 -0
  15. data/images/file_orange.png +0 -0
  16. data/images/file_red.png +0 -0
  17. data/images/folder.png +0 -0
  18. data/images/folder_green.png +0 -0
  19. data/images/folder_orange.png +0 -0
  20. data/images/folder_red.png +0 -0
  21. data/images/processing.png +0 -0
  22. data/images/svn_added.png +0 -0
  23. data/images/svn_conflict.png +0 -0
  24. data/images/svn_deleted.png +0 -0
  25. data/images/svn_locked.png +0 -0
  26. data/images/svn_modified.png +0 -0
  27. data/images/svn_normal.png +0 -0
  28. data/images/svn_readonly.png +0 -0
  29. data/images/vimmate16.png +0 -0
  30. data/images/vimmate32.png +0 -0
  31. data/images/vimmate48.png +0 -0
  32. data/lib/active_window.rb +8 -0
  33. data/lib/active_window/active_column.rb +218 -0
  34. data/lib/active_window/active_tree_store.rb +13 -0
  35. data/lib/active_window/active_tree_store/columns.rb +88 -0
  36. data/lib/active_window/active_tree_store/extentions.rb +81 -0
  37. data/lib/active_window/active_tree_store/index.rb +53 -0
  38. data/lib/active_window/application.rb +133 -0
  39. data/lib/active_window/controller.rb +58 -0
  40. data/lib/active_window/dot_file.rb +29 -0
  41. data/lib/active_window/filtered_active_tree_store.rb +114 -0
  42. data/lib/active_window/listed_item.rb +127 -0
  43. data/lib/active_window/signal.rb +46 -0
  44. data/lib/config_window.rb +90 -0
  45. data/lib/file_tree_store.rb +73 -0
  46. data/lib/filtered_file_tree_store.rb +34 -0
  47. data/lib/gtk_thread_helper.rb +73 -0
  48. data/lib/listed_directory.rb +43 -0
  49. data/lib/listed_file.rb +67 -0
  50. data/lib/try.rb +9 -0
  51. data/lib/vim/buffers.rb +18 -0
  52. data/lib/vim/integration.rb +36 -0
  53. data/lib/vim/netbeans.rb +156 -0
  54. data/lib/vim/source.vim +18 -0
  55. data/lib/vim_mate/config.rb +132 -0
  56. data/lib/vim_mate/dummy_window.rb +14 -0
  57. data/lib/vim_mate/files_menu.rb +110 -0
  58. data/lib/vim_mate/icons.rb +156 -0
  59. data/lib/vim_mate/nice_singleton.rb +53 -0
  60. data/lib/vim_mate/plugins.rb +6 -0
  61. data/lib/vim_mate/plugins/inotify/init.rb +4 -0
  62. data/lib/vim_mate/plugins/inotify/lib/INotify.rb +206 -0
  63. data/lib/vim_mate/plugins/inotify/lib/directory.rb +58 -0
  64. data/lib/vim_mate/plugins/subversion/init.rb +7 -0
  65. data/lib/vim_mate/plugins/subversion/lib/file.rb +59 -0
  66. data/lib/vim_mate/plugins/subversion/lib/menu.rb +96 -0
  67. data/lib/vim_mate/plugins/subversion/lib/subversion.rb +157 -0
  68. data/lib/vim_mate/requirer.rb +68 -0
  69. data/lib/vim_mate/search_window.rb +227 -0
  70. data/lib/vim_mate/tags_window.rb +167 -0
  71. data/lib/vim_mate/terminals_window.rb +163 -0
  72. data/lib/vim_mate/version.rb +29 -0
  73. data/lib/vim_mate/vim_widget.rb +150 -0
  74. data/spec/active_window/active_column_spec.rb +41 -0
  75. data/spec/active_window/active_tree_store_spec.rb +312 -0
  76. data/spec/active_window/controller_spec.rb +6 -0
  77. data/spec/lib/file_tree_store_spec.rb +40 -0
  78. data/spec/lib/listed_directory_spec.rb +26 -0
  79. data/spec/lib/listed_file_spec.rb +53 -0
  80. data/spec/nice_singleton_spec.rb +23 -0
  81. data/spec/spec.opts +6 -0
  82. data/spec/spec_helper.rb +10 -0
  83. data/views/vim_mate.glade +308 -0
  84. data/vimmate.gemspec +131 -0
  85. metadata +168 -0
@@ -0,0 +1,6 @@
1
+ plugin_dir = File.expand_path File.dirname(__FILE__) + '/plugins'
2
+
3
+ Dir["#{plugin_dir}/*/init.rb"].each do |plugin_init|
4
+ ActiveSupport::Dependencies::load_paths << File.dirname(plugin_init)
5
+ require_dependency plugin_init
6
+ end
@@ -0,0 +1,4 @@
1
+ require_dependency 'lib/INotify'
2
+ require_dependency 'lib/directory'
3
+ ListedDirectory.class_eval { include VimMate::Plugin::INotifyDirectory }
4
+
@@ -0,0 +1,206 @@
1
+ # Version 0.3.0 (2005-09-27) by James Le Cuirot <chewi@ffaura.com>
2
+ # masks updated
3
+ # syscalls instead of /dev/inotify for linux-2.6.13 (are the archs correct?)
4
+ # start/stop methods added for threading
5
+ # ignore_dir_recursively method added
6
+ # Events class removed : not necessary
7
+ # (wd <=> dir) hashed both ways : needed for ignore
8
+ # default watch mask is IN_ALL_EVENTS
9
+ # UnsupportedPlatformError class added to deal with unsupported CPUs and OSes
10
+ #
11
+ # Version 0.2.3 (2005-01-18) by oxman
12
+ # function ignore_dir : was added
13
+ #
14
+ # Version 0.2.2 (2005-01-18) by oxman
15
+ # cleaning code (big thanks to gnome at #ruby-lang)
16
+ # rename next_event in each_event (thanks kig)
17
+ #
18
+ # Version 0.2.1 (2005-01-18) by oxman
19
+ # class Events : use real mask
20
+ #
21
+ # Version 0.2.0 (2005-01-18) by oxman
22
+ # function watch_dir : only watch
23
+ # function next_event : was added
24
+ # function watch_dir_recursively : was added
25
+ #
26
+ # Version 0.1.1 (2005-01-17) by oxman
27
+ # Correct IN_ var for inotify 0.18
28
+
29
+ module INotify
30
+ require 'rbconfig'
31
+
32
+ class UnsupportedPlatformError < RuntimeError
33
+ end
34
+
35
+ case Config::CONFIG["arch"]
36
+
37
+ when /i[3-6]86-linux/
38
+ INOTIFY_INIT = 291
39
+ INOTIFY_ADD_WATCH = 292
40
+ INOTIFY_RM_WATCH = 293
41
+
42
+ when /x86_64-linux/
43
+ INOTIFY_INIT = 253
44
+ INOTIFY_ADD_WATCH = 254
45
+ INOTIFY_RM_WATCH = 255
46
+
47
+ when /powerpc(64)?-linux/
48
+ INOTIFY_INIT = 275
49
+ INOTIFY_ADD_WATCH = 276
50
+ INOTIFY_RM_WATCH = 277
51
+
52
+ when /ia64-linux/
53
+ INOTIFY_INIT = 1277
54
+ INOTIFY_ADD_WATCH = 1278
55
+ INOTIFY_RM_WATCH = 1279
56
+
57
+ when /s390-linux/
58
+ INOTIFY_INIT = 284
59
+ INOTIFY_ADD_WATCH = 285
60
+ INOTIFY_RM_WATCH = 286
61
+
62
+ when /alpha-linux/
63
+ INOTIFY_INIT = 444
64
+ INOTIFY_ADD_WATCH = 445
65
+ INOTIFY_RM_WATCH = 446
66
+
67
+ when /sparc(64)?-linux/
68
+ INOTIFY_INIT = 151
69
+ INOTIFY_ADD_WATCH = 152
70
+ INOTIFY_RM_WATCH = 156
71
+
72
+ when /arm-linux/
73
+ INOTIFY_INIT = 316
74
+ INOTIFY_ADD_WATCH = 317
75
+ INOTIFY_RM_WATCH = 318
76
+
77
+ when /sh-linux/
78
+ INOTIFY_INIT = 290
79
+ INOTIFY_ADD_WATCH = 291
80
+ INOTIFY_RM_WATCH = 292
81
+
82
+ else raise UnsupportedPlatformError, Config::CONFIG["arch"]
83
+
84
+ end
85
+
86
+ Mask = Struct::new(:value, :name)
87
+
88
+ Masks = {
89
+ :IN_ACCESS => Mask::new(0x00000001, 'access'),
90
+ :IN_MODIFY => Mask::new(0x00000002, 'modify'),
91
+ :IN_ATTRIB => Mask::new(0x00000004, 'attrib'),
92
+ :IN_CLOSE_WRITE => Mask::new(0x00000008, 'close_write'),
93
+ :IN_CLOSE_NOWRITE => Mask::new(0x00000010, 'close_nowrite'),
94
+ :IN_OPEN => Mask::new(0x00000020, 'open'),
95
+ :IN_MOVED_FROM => Mask::new(0x00000040, 'moved_from'),
96
+ :IN_MOVED_TO => Mask::new(0x00000080, 'moved_to'),
97
+ :IN_CREATE => Mask::new(0x00000100, 'create'),
98
+ :IN_DELETE => Mask::new(0x00000200, 'delete'),
99
+ :IN_DELETE_SELF => Mask::new(0x00000400, 'delete_self'),
100
+ :IN_UNMOUNT => Mask::new(0x00002000, 'unmount'),
101
+ :IN_Q_OVERFLOW => Mask::new(0x00004000, 'q_overflow'),
102
+ :IN_IGNORED => Mask::new(0x00008000, 'ignored'),
103
+ }
104
+
105
+ Masks.each {|key, value|
106
+ const_set(key, value)
107
+ }
108
+
109
+ OrMasks = {
110
+ :IN_CLOSE => Mask::new(IN_CLOSE_WRITE.value | IN_CLOSE_NOWRITE.value, 'close'),
111
+ :IN_MOVE => Mask::new(IN_MOVED_FROM.value | IN_MOVED_TO.value, 'moved'),
112
+ :IN_ALL_EVENTS => Mask::new(IN_ACCESS.value | IN_MODIFY.value | IN_ATTRIB.value | IN_CLOSE_WRITE.value | IN_CLOSE_NOWRITE.value | IN_OPEN.value | IN_MOVED_FROM.value | IN_MOVED_TO.value | IN_DELETE.value | IN_CREATE.value | IN_DELETE_SELF.value, 'all_events')
113
+ }
114
+
115
+ OrMasks.each {|key, value|
116
+ const_set(key, value)
117
+ }
118
+
119
+ AllMasks = Masks.merge OrMasks
120
+
121
+ require 'find'
122
+
123
+ class INotify
124
+ def initialize
125
+ @wd_dir = Hash.new
126
+ @dir_wd = Hash.new
127
+ @io = IO.open(syscall(INOTIFY_INIT))
128
+ end
129
+
130
+ def close
131
+ @io.close
132
+ end
133
+
134
+ def watch_dir (dir, option = IN_ALL_EVENTS)
135
+ wd = syscall(INOTIFY_ADD_WATCH, @io.fileno, dir, option.value)
136
+
137
+ if wd >= 0
138
+ @dir_wd[dir] = wd
139
+ @wd_dir[wd] = dir
140
+ end
141
+
142
+ return wd
143
+ end
144
+
145
+ def ignore_dir (dir)
146
+ syscall(INOTIFY_RM_WATCH, @io.fileno, @dir_wd[dir])
147
+ end
148
+
149
+ def watch_dir_recursively (dir, option = IN_ALL_EVENTS)
150
+ Find.find(dir) { |sub_dir| watch_dir(sub_dir, option) if (File::directory?(sub_dir) == true) }
151
+ end
152
+
153
+ def ignore_dir_recursively (dir)
154
+ Find.find(dir) { |sub_dir| ignore_dir(sub_dir) if (File::directory?(sub_dir) == true) }
155
+ end
156
+
157
+ def next_events
158
+ begin
159
+ read_cnt = @io.read(16)
160
+ wd, mask, cookie, len = read_cnt.unpack('lLLL')
161
+ read_cnt = @io.read(len)
162
+ filename = read_cnt.unpack('Z*')
163
+ end while (mask & IN_Q_OVERFLOW.value) != 0
164
+
165
+ events = Array.new
166
+
167
+ AllMasks.each_value do |m|
168
+ next if m.value == IN_ALL_EVENTS.value
169
+ events.push Event.new(@wd_dir[wd].to_s, filename.to_s, m.name.to_s, cookie) if (m.value & mask) != 0
170
+ end
171
+
172
+ return events
173
+ end
174
+
175
+ def each_event
176
+ loop { next_events.each { |event| yield event } }
177
+ end
178
+
179
+ def start
180
+ @thread = Thread.new { loop { next_events.each { |event| yield event } } }
181
+ end
182
+
183
+ def stop
184
+ @thread.exit
185
+ end
186
+ end
187
+
188
+ class Event
189
+ attr_reader :path, :filename, :type, :cookie
190
+
191
+ def initialize (path, filename, type, cookie)
192
+ @path = path
193
+ @filename = filename
194
+ @type = type
195
+ @cookie = cookie
196
+ end
197
+
198
+ def dump
199
+ "path: " + @path.to_s + ", filename: " + @filename.to_s + ", type: " + @type.to_s + ", cookie: " + @cookie.to_s
200
+ end
201
+
202
+ def to_s
203
+ dump
204
+ end
205
+ end
206
+ end
@@ -0,0 +1,58 @@
1
+ module VimMate
2
+ module Plugin
3
+ module INotifyDirectory
4
+ Mask = INotify::Mask.new(
5
+ INotify::IN_MODIFY.value |
6
+ INotify::IN_DELETE.value |
7
+ INotify::IN_CREATE.value |
8
+ INotify::IN_MOVED_TO.value |
9
+ INotify::IN_MOVED_FROM.value |
10
+ 0, 'filechange')
11
+
12
+ Exclusions = [ /(swp|~|rej|orig)$/, /\/\.?#/, /^\./ ]
13
+ def self.included(base)
14
+ base.class_eval do
15
+ include InstanceMethods
16
+ extend ClassMethods
17
+ alias_method_chain :initialize, :inotify
18
+ start_inotify_watcher
19
+ end
20
+
21
+ end
22
+
23
+ module InstanceMethods
24
+ def initialize_with_inotify(*args)
25
+ initialize_without_inotify(*args)
26
+ if directory?
27
+ self.class.inotify_watcher.watch_dir(full_path, Mask)
28
+ end
29
+ end
30
+ end
31
+
32
+ module ClassMethods
33
+ def inotify_watcher
34
+ @@inotify_watcher ||= INotify::INotify.new
35
+ end
36
+
37
+ def start_inotify_watcher
38
+ inotify_watcher.start do |event|
39
+ next if ignore_file_changes? event.filename
40
+ path = File.join(event.path, event.filename)
41
+ case event.type
42
+ when 'modify'
43
+ ActiveWindow::Signal.emit_file_modified(path)
44
+ when /^delete|moved_from$/
45
+ ActiveWindow::Signal.emit_file_deleted(path)
46
+ when /^create|moved_to$/
47
+ ActiveWindow::Signal.emit_file_created(path)
48
+ end
49
+ end
50
+ end
51
+
52
+ def ignore_file_changes?(filename)
53
+ Exclusions.any? { |exclusion| filename =~ exclusion }
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,7 @@
1
+ #VimMate::Requirer.require_if('lib/subversion') do
2
+ # require 'lib/file'
3
+ # require 'lib/menu'
4
+ # VimMate::ListedFile.class_eval { include VimMate::Plugin::SubversionFile }
5
+ # VimMate::ListedDirectory.class_eval { include VimMate::Plugin::SubversionFile }
6
+ # VimMate::FilesMenu.class_eval { include VimMate::Plugin::SubversionMenu }
7
+ #end
@@ -0,0 +1,59 @@
1
+ # All stuff for SVN handling of files
2
+
3
+ module VimMate
4
+ module Plugin
5
+ module SubversionFile
6
+ def self.included(base)
7
+ base.class_eval do
8
+ include InstanceMethods
9
+ modify_icon :svn do |file|
10
+ Icons.overlay_with file.icon_name_without_svn, file.svn_icon, 'scm'
11
+ end
12
+ end
13
+ end
14
+ module InstanceMethods
15
+ # Refresh the file. If the file status has changed, send a refresh
16
+ # signal
17
+ def refresh
18
+ status = Subversion.status(full_path)
19
+ if @last_status != status
20
+ @last_status = status
21
+ ListedTree.refreshed self
22
+ end
23
+ self
24
+ end
25
+
26
+
27
+ # Return the icon for this file depending on the file status
28
+ def svn_icon
29
+ status = Subversion.status(full_path)
30
+ if @last_status != status
31
+ @last_status = status
32
+ end
33
+ case status
34
+ when Subversion::UNVERSIONED, Subversion::EXTERNAL,
35
+ Subversion::IGNORED, Subversion::UNKNOWN
36
+ nil
37
+ when Subversion::NONE, Subversion::NORMAL
38
+ "svn_normal"
39
+ when Subversion::ADDED, Subversion::REPLACED
40
+ 'svn_added'
41
+ when Subversion::DELETED, Subversion::MISSING
42
+ 'svn_deleted'
43
+ when Subversion::MODIFIED
44
+ 'svn_modified'
45
+ when Subversion::CONFLICTED
46
+ 'svn_conflict'
47
+ when Subversion::MERGED, Subversion::OBSTRUCTED, Subversion::INCOMPLETE
48
+ 'svn_readonly' # FIXME for now, have no better
49
+ end
50
+ end
51
+
52
+ # Return the status text for this file depending on the file status
53
+ def status
54
+ Subversion.status_text(full_path)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,96 @@
1
+ module VimMate
2
+ module Plugin
3
+ module SubversionMenu
4
+ def self.included(base)
5
+ base.class_eval do
6
+ include InstanceMethods
7
+ alias_method :initialize_without_svn, :initialize
8
+ alias_method :initialize, :initialize_with_svn
9
+ end
10
+ end
11
+ module InstanceMethods
12
+ def initialize_with_svn(*args)
13
+ initialize_without_svn(*args)
14
+ svn_sub_menu = Gtk::Menu.new
15
+
16
+ svn_sub_menu.append(svn_add = Gtk::ImageMenuItem.new(Gtk::Stock::ADD))
17
+ svn_add.signal_connect("activate") do
18
+ menu_svn_add
19
+ end
20
+
21
+ svn_sub_menu.append(svn_rename = Gtk::MenuItem.new("R_ename"))
22
+ svn_rename.signal_connect("activate") do
23
+ menu_svn_rename
24
+ end
25
+
26
+ svn_sub_menu.append(svn_delete = Gtk::ImageMenuItem.new(Gtk::Stock::DELETE))
27
+ svn_delete.signal_connect("activate") do
28
+ menu_svn_delete
29
+ end
30
+
31
+ svn_sub_menu.append(svn_revert = Gtk::ImageMenuItem.new(Gtk::Stock::REVERT_TO_SAVED))
32
+ svn_revert.signal_connect("activate") do
33
+ menu_svn_revert
34
+ end
35
+
36
+ @gtk_menu.append(subversion = Gtk::MenuItem.new("S_ubversion"))
37
+ subversion.submenu = svn_sub_menu
38
+ @gtk_menu.show_all
39
+ end
40
+ # Add the selected file to subversion
41
+ def menu_svn_add
42
+ Subversion.add(@last_path)
43
+ menu_refresh
44
+ end
45
+
46
+ # Rename the selected file with subversion
47
+ def menu_svn_rename
48
+ dialog = Gtk::FileChooserDialog.new("Rename #{File.basename(@last_path)}",
49
+ @parent_window.gtk_window,
50
+ Gtk::FileChooser::ACTION_SAVE,
51
+ nil,
52
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
53
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
54
+ dialog.set_icon_list(Icons.window_icons)
55
+ dialog.current_folder = File.dirname(@last_path)
56
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
57
+ Subversion.move(@last_path, dialog.filename)
58
+ end
59
+ dialog.destroy
60
+ menu_refresh
61
+ end
62
+
63
+ # Revert the selected file in subversion
64
+ def menu_svn_revert
65
+ dialog = Gtk::MessageDialog.new(@parent_window.gtk_window,
66
+ Gtk::MessageDialog::Flags::MODAL,
67
+ Gtk::MessageDialog::Type::QUESTION,
68
+ Gtk::MessageDialog::ButtonsType::YES_NO,
69
+ "Do a Subversion Revert on #{File.basename(@last_path)} ?")
70
+ dialog.set_icon_list(Icons.window_icons)
71
+ if dialog.run == Gtk::Dialog::RESPONSE_YES
72
+ Subversion.revert(@last_path)
73
+ end
74
+ dialog.destroy
75
+ menu_refresh
76
+ end
77
+
78
+ # Delete the selected file from subversion
79
+ def menu_svn_delete
80
+ dialog = Gtk::MessageDialog.new(@parent_window.gtk_window,
81
+ Gtk::MessageDialog::Flags::MODAL,
82
+ Gtk::MessageDialog::Type::QUESTION,
83
+ Gtk::MessageDialog::ButtonsType::YES_NO,
84
+ "Do a Subversion Delete on #{File.basename(@last_path)} ?")
85
+ dialog.set_icon_list(Icons.window_icons)
86
+ if dialog.run == Gtk::Dialog::RESPONSE_YES
87
+ Subversion.remove(@last_path)
88
+ end
89
+ dialog.destroy
90
+ menu_refresh
91
+ end
92
+ end
93
+
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,157 @@
1
+ =begin
2
+ = VimMate: Vim graphical add-on
3
+ Copyright (c) 2006 Guillaume Benny
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
9
+ of the Software, and to permit persons to whom the Software is furnished to do
10
+ so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+ =end
23
+
24
+ require 'svn/core'
25
+ require 'svn/client'
26
+ require 'svn/wc'
27
+ require 'svn/repos'
28
+ require 'vimmatelib/nice_singleton'
29
+ require 'vimmatelib/requirer'
30
+
31
+ module VimMate
32
+
33
+ # Do not load Subversion if it's disabled
34
+ Requirer.raise_load_error_if do
35
+ not Config[:subversion_enabled]
36
+ end
37
+
38
+ # This class helps the integration of the Subversion version control system
39
+ class Subversion
40
+ include NiceSingleton
41
+
42
+ UNKNOWN = -1
43
+ NONE = 1
44
+ UNVERSIONED = 2
45
+ NORMAL = 3
46
+ ADDED = 4
47
+ MISSING = 5
48
+ DELETED = 6
49
+ REPLACED = 7
50
+ MODIFIED = 8
51
+ MERGED = 9
52
+ CONFLICTED = 10
53
+ IGNORED = 11
54
+ OBSTRUCTED = 12
55
+ EXTERNAL = 13
56
+ INCOMPLETE = 14
57
+
58
+ STATUS_TEXT = {
59
+ UNKNOWN => "",
60
+ NONE => "None",
61
+ UNVERSIONED => "Unversioned",
62
+ NORMAL => "Normal",
63
+ ADDED => "Added",
64
+ MISSING => "Missing",
65
+ DELETED => "Deleted",
66
+ REPLACED => "Replaced",
67
+ MODIFIED => "Modified",
68
+ MERGED => "Merged",
69
+ CONFLICTED => "Conflicted",
70
+ IGNORED => "Ignored",
71
+ OBSTRUCTED => "Obstructed",
72
+ EXTERNAL => "External",
73
+ INCOMPLETE => "Incomplete",
74
+ }.freeze
75
+
76
+ # Create the Subversion class. Cannot be called directly
77
+ def initialize
78
+ end
79
+
80
+ # Get the status of the specified file. The file must be a full path.
81
+ def status(path)
82
+ ret_status = UNKNOWN
83
+ begin
84
+ # Arguments: File, Revision, Recursive, Any files, Update
85
+ new_client.status(path, "HEAD", true, true, false) do |path, status|
86
+ ret_status = status.text_status if status.text_status > ret_status
87
+ end
88
+ rescue Svn::Error::WC_NOT_DIRECTORY
89
+ rescue Svn::Error::WC_NOT_LOCKED
90
+ end
91
+ ret_status
92
+ end
93
+
94
+ # Get the text that represents the status of the file
95
+ def status_text(path)
96
+ STATUS_TEXT[status(path)]
97
+ end
98
+
99
+ # Add the specified file (full path) to Subversion
100
+ def add(path)
101
+ cleanup(path)
102
+ new_client.add(path)
103
+ rescue
104
+ false
105
+ else
106
+ true
107
+ end
108
+
109
+ # Remove the specified file (full path) from Subversion's control
110
+ def remove(path)
111
+ cleanup(path)
112
+ new_client.remove(path)
113
+ rescue
114
+ false
115
+ else
116
+ true
117
+ end
118
+
119
+ # Revert the specified file (full path) to what it was before the local
120
+ # modifications
121
+ def revert(path)
122
+ cleanup(path)
123
+ new_client.revert(path)
124
+ rescue
125
+ false
126
+ else
127
+ true
128
+ end
129
+
130
+ # Move the specified file (full path) to a new file name
131
+ def move(path, new_path)
132
+ cleanup(path)
133
+ new_client.move(path, new_path)
134
+ rescue
135
+ false
136
+ else
137
+ true
138
+ end
139
+
140
+ # Cleanup the subversion path when something is locked
141
+ def cleanup(path)
142
+ new_client.cleanup(File.directory?(path) ? path : File.dirname(path))
143
+ rescue
144
+ false
145
+ else
146
+ true
147
+ end
148
+
149
+ private
150
+
151
+ # Create a new subversion client
152
+ def new_client
153
+ Svn::Client::Context.new
154
+ end
155
+
156
+ end
157
+ end