rubysync 0.0.2 → 0.0.3

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 (64) hide show
  1. data/.DS_Store +0 -0
  2. data/.project +17 -0
  3. data/COPYING +339 -0
  4. data/HISTORY.txt +8 -0
  5. data/Manifest.txt +218 -0
  6. data/README.txt +67 -0
  7. data/Rakefile +31 -0
  8. data/bin/.DS_Store +0 -0
  9. data/bin/rubysync +19 -12
  10. data/examples/.DS_Store +0 -0
  11. data/examples/ar_client_webapp/log/development.log +753 -0
  12. data/examples/ar_client_webapp/log/production.log +0 -0
  13. data/examples/ar_client_webapp/log/server.log +0 -0
  14. data/examples/ar_client_webapp/log/test.log +0 -0
  15. data/examples/ar_client_webapp/public/.htaccess +40 -0
  16. data/examples/ar_client_webapp/tmp/sessions/ruby_sess.e2e3c63a67baef6d +0 -0
  17. data/examples/ar_webapp/.DS_Store +0 -0
  18. data/examples/ar_webapp/app/.DS_Store +0 -0
  19. data/examples/ar_webapp/app/views/.DS_Store +0 -0
  20. data/examples/ar_webapp/app/views/people/.DS_Store +0 -0
  21. data/examples/ar_webapp/log/development.log +5518 -0
  22. data/examples/ar_webapp/log/production.log +0 -0
  23. data/examples/ar_webapp/log/server.log +0 -0
  24. data/examples/ar_webapp/log/test.log +2178 -0
  25. data/examples/ar_webapp/public/.htaccess +40 -0
  26. data/examples/ar_webapp/tmp/sessions/ruby_sess.2295696b0af5f6dd +0 -0
  27. data/examples/ar_webapp/tmp/sessions/ruby_sess.26687aeb19c87669 +0 -0
  28. data/examples/ar_webapp/tmp/sessions/ruby_sess.2855a3b0c8ea840b +0 -0
  29. data/examples/ar_webapp/tmp/sessions/ruby_sess.45d2d48a8330ff28 +0 -0
  30. data/examples/ar_webapp/tmp/sessions/ruby_sess.7366b840f4ce9f12 +0 -0
  31. data/examples/ar_webapp/tmp/sessions/ruby_sess.b2fc3f2e6d8ae555 +0 -0
  32. data/examples/ar_webapp/tmp/sessions/ruby_sess.b6bf8470a62c02b0 +0 -0
  33. data/examples/my_ims/.DS_Store +0 -0
  34. data/gemspec +48 -0
  35. data/lib/.DS_Store +0 -0
  36. data/lib/net/.DS_Store +0 -0
  37. data/lib/ruby_sync/connectors/active_record_association_handler.rb +66 -0
  38. data/lib/ruby_sync/connectors/active_record_connector.rb +14 -62
  39. data/lib/ruby_sync/connectors/active_record_event_handler.rb +47 -0
  40. data/lib/ruby_sync/connectors/base_connector.rb +139 -36
  41. data/lib/ruby_sync/connectors/connector_event_processing.rb +18 -0
  42. data/lib/ruby_sync/connectors/csv_file_connector.rb +3 -0
  43. data/lib/ruby_sync/connectors/file_connector.rb +1 -0
  44. data/lib/ruby_sync/connectors/memory_connector.rb +2 -104
  45. data/lib/ruby_sync/connectors/xml_connector.rb +98 -0
  46. data/lib/ruby_sync/event.rb +7 -1
  47. data/lib/ruby_sync/util/utilities.rb +27 -16
  48. data/lib/ruby_sync.rb +10 -1
  49. data/lib/rubysync.rb +19 -0
  50. data/nbproject/private/private.properties +3 -0
  51. data/nbproject/project.properties +8 -0
  52. data/nbproject/project.xml +16 -0
  53. data/rubysync.tmproj +348 -0
  54. data/test/.DS_Store +0 -0
  55. data/test/ruby_sync_test.rb +8 -1
  56. data/test/tc_xml_connectors.rb +47 -0
  57. data/test/test_active_record_vault.rb +17 -14
  58. data/test/test_base_connector.rb +38 -0
  59. data/test/test_ldap_changelog.rb +97 -0
  60. data/test/test_ldap_connector.rb +2 -48
  61. data/test/test_memory_connectors.rb +8 -3
  62. data/test/test_rubysync.rb +28 -0
  63. data/test/ts_rubysync.rb +5 -3
  64. metadata +129 -169
@@ -20,66 +20,10 @@ require "yaml"
20
20
  module RubySync::Connectors
21
21
  class MemoryConnector < RubySync::Connectors::BaseConnector
22
22
 
23
- def each_change
24
- while event = @events.shift
25
- yield event
26
- end
27
- end
28
23
 
29
24
  def each_entry
30
- # todo implement
31
- end
32
-
33
- def is_echo? event
34
- event.sets_value?(:modifier, 'rubysync')
35
- end
36
-
37
- def associate(association, path)
38
- path = normalize(path)
39
- log.info "Associating '#{association}' with '#{path}'"
40
- entry = @data[path]
41
- if entry
42
- (@association_index[association.context] ||= {})[association.key] = path
43
- (entry[:association] ||= {})[association.context] = association.key
44
- end
45
- end
46
-
47
- def path_for_association(association)
48
- context = @association_index[association.context] || {}
49
- context[association.key.to_s]
50
- end
51
-
52
- def association_key_for(context, path)
53
- path = normalize(path)
54
- log.debug "Retrieving association key for '#{path}' within '#{context}'"
55
- entry = @data[path]
56
- unless entry
57
- p @data
58
- end
59
- if entry && entry[:association] && key = entry[:association][context]
60
- return key
61
- end
62
- log.info "No association found."
63
- log.debug entry.inspect
64
- return nil
65
- end
66
-
67
- def associations_for path
68
- path = normalize path
69
- entry = @data[path]
70
- (entry[:association] || {}).map do |context, key|
71
- RubySync::Association.new(context, key)
72
- end
73
- end
74
-
75
- def remove_association(association)
76
- path = path_for_association association
77
- context = @association_index[association.context]
78
- context.delete(association.key) if context
79
- entry = @data[path]
80
- if entry
81
- entry_context = (entry[:association] || {})[association.context]
82
- entry_context.delete(association.key) if entry_context
25
+ @data.each do |key, entry|
26
+ yield key, entry
83
27
  end
84
28
  end
85
29
 
@@ -87,26 +31,14 @@ module RubySync::Connectors
87
31
  def initialize options
88
32
  super
89
33
  @data = {}
90
- @events = []
91
- @association_index = {}
92
34
  end
93
35
 
94
- # Normally, the add method is called by the pipeline and simply stores
95
- # the data to the datastore and that's it.
96
- # In this case, though, we also generate an add event.
97
- # This simulates the likely effect that an add would have on a proper datastore
98
- # where doing an add would very likely cause an event to be generated that the
99
- # pipeline should rightly ignore because it's just a side-effect.
100
- # In other words, we're simply simulating an undesirable behaviour for testing
101
- # purposes.
102
36
  def add id, operations
103
37
  id = normalize id
104
38
  raise Exception.new("Item already exists") if @data[id]
105
39
  log.debug "Adding new record with key '#{id}'"
106
40
  @data[id] = perform_operations operations
107
41
  association_key = (is_vault?)? nil : [nil, own_association_key_for(id)]
108
- log.info "#{name}: Injecting add event"
109
- @events << RubySync::Event.add(self, id, association_key, operations.dup)
110
42
  return id
111
43
  end
112
44
 
@@ -114,18 +46,6 @@ module RubySync::Connectors
114
46
  id = normalize id
115
47
  raise Exception.new("Attempting to modify non-existent record '#{id}'") unless @data[id]
116
48
  perform_operations operations, @data[id]
117
- association_key = (is_vault?)? nil : [nil, own_association_key_for(id)]
118
- log.info "#{name}: Injecting modify event"
119
- if is_vault?
120
- associations_for(id).each do |association|
121
- @events << (event = RubySync::Event.modify(self, id, association))
122
- end
123
- else
124
- association = [nil, own_association_key_for(id)]
125
- @events << (event = RubySync::Event.modify(self, id, association))
126
- end
127
-
128
- @events << RubySync::Event.modify(self, id, association_key, operations.dup)
129
49
  return id
130
50
  end
131
51
 
@@ -136,32 +56,10 @@ module RubySync::Connectors
136
56
  log.warn "Can't delete non-existent item '#{id}'"
137
57
  return
138
58
  end
139
- log.info "#{name}: Injecting delete events"
140
- if is_vault?
141
- associations_for(id).each do |association|
142
- @events << (event = RubySync::Event.delete(self, id, association))
143
- @association_index.delete association
144
- end
145
- else
146
- association = [nil, own_association_key_for(id)]
147
- @events << (event = RubySync::Event.delete(self, id, association))
148
- end
149
59
  @data.delete id
150
60
  end
151
61
 
152
- # Put a clue there that we did this change so that we can detect and filter
153
- # out the echo.
154
- def target_transform event
155
- event.payload << RubySync::Operation.new(:add, :modifier, ['rubysync'])
156
- end
157
62
 
158
- def source_transform event
159
- event.drop_changes_to [:modifier, :foreign_key]
160
- end
161
-
162
- def drop_pending_events
163
- @events = []
164
- end
165
63
 
166
64
  def [](key)
167
65
  @data[normalize(key)]
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env ruby -w
2
+ #
3
+ # Copyright (c) 2007 Ritchie Young. All rights reserved.
4
+ #
5
+ # This file is part of RubySync.
6
+ #
7
+ # RubySync is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
9
+ #
10
+ # RubySync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
11
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
14
+ # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15
+
16
+
17
+ lib_path = File.dirname(__FILE__) + '/../lib'
18
+ $:.unshift lib_path unless $:.include?(lib_path) || $:.include?(File.expand_path(lib_path))
19
+
20
+ require 'ruby_sync'
21
+ $VERBOSE = false
22
+ #require 'xmlsimple'
23
+ #$VERBOSE = true
24
+
25
+
26
+
27
+ module RubySync::Connectors
28
+ class XmlConnector < RubySync::Connectors::BaseConnector
29
+
30
+ option :filename
31
+
32
+ def each_entry
33
+ with_xml(:read_only=>true) do |content|
34
+ content.each do |entry|
35
+ yield entry[0], entry[1][0]
36
+ end
37
+ end
38
+ end
39
+
40
+ def add id, operations
41
+ with_xml do |content|
42
+ content[id] = perform_operations(operations)
43
+ end
44
+ id
45
+ end
46
+
47
+ def modify id, operations
48
+ with_xml do |content|
49
+ existing = content[id] && content[id][0] || {}
50
+ content[id] = perform_operations(operations, existing)
51
+ end
52
+ id
53
+ end
54
+
55
+ def delete id
56
+ with_xml do |content|
57
+ content.delete(id)
58
+ end
59
+ id
60
+ end
61
+
62
+ def [](id)
63
+ value = nil
64
+ with_xml(:read_only=>true) do |content|
65
+ value = content[id] && content[id][0]
66
+ end
67
+ value
68
+ end
69
+
70
+ def []=(id, value)
71
+ with_xml do |content|
72
+ content[id] = value
73
+ end
74
+ end
75
+
76
+
77
+ def self.sample_config
78
+ return <<END
79
+ #
80
+ # "filename" should be the full name of the file containing
81
+ # the xml representation of the synchronized content.
82
+ # You probably want to change this:
83
+ #
84
+ filename "/tmp/rubysync.xml"
85
+ END
86
+ end
87
+
88
+ private
89
+
90
+
91
+ def with_xml options={}
92
+ content = (File.exist?(filename))? content = XmlSimple.xml_in(filename) : {}
93
+ yield content
94
+ XmlSimple.xml_out(content, {'OutputFile'=>filename}) unless options[:read_only]
95
+ end
96
+
97
+ end
98
+ end
@@ -51,6 +51,9 @@ module RubySync
51
51
  :target_path,
52
52
  :association
53
53
 
54
+ def self.force_resync source
55
+ self.new(:force_resync, source)
56
+ end
54
57
 
55
58
  def self.delete source, source_path, association=nil
56
59
  self.new(:delete, source, source_path, association)
@@ -92,7 +95,7 @@ module RubySync
92
95
 
93
96
  def merge other
94
97
  # TODO implement merge
95
- log.warning "Event.merge not yet implemented"
98
+ log.warn "Event.merge not yet implemented"
96
99
  end
97
100
 
98
101
  # Retrieves all known values for the record affected by this event and
@@ -111,6 +114,9 @@ module RubySync
111
114
  def convert_to_modify
112
115
  log.info "Converting '#{type}' event to modify"
113
116
  @type = :modify
117
+ @payload.each do |op|
118
+ op.type = :replace
119
+ end
114
120
  end
115
121
 
116
122
 
@@ -18,11 +18,20 @@ require 'fileutils'
18
18
  require 'irb'
19
19
 
20
20
 
21
+ class ::File
22
+ def self.delete_if_exists(files)
23
+ files.kind_of?(Array) or files = [files]
24
+ files.each do |file|
25
+ File.delete(file) if File.exist?(file)
26
+ end
27
+ end
28
+ end
21
29
 
22
30
  # Generally useful methods
23
31
  module RubySync
24
32
  module Utilities
25
33
 
34
+ @@base_path=nil
26
35
 
27
36
  # Perform an action and rescue any exceptions thrown, display the exception with the specified text
28
37
  def with_rescue text
@@ -50,15 +59,17 @@ module RubySync
50
59
 
51
60
 
52
61
  # Ensure that a given path exists as a directory
53
- def ensure_dir_exists path
54
- raise Exception.new("Can't create nil directory") unless path
55
- if File.exist? path
56
- unless File.directory? path
57
- raise Exception.new("'#{path}' exists but is not a directory")
62
+ def ensure_dir_exists paths
63
+ paths.as_array.each do |path|
64
+ raise Exception.new("Can't create nil directory") unless path
65
+ if File.exist? path
66
+ unless File.directory? path
67
+ raise Exception.new("'#{path}' exists but is not a directory")
68
+ end
69
+ else
70
+ log.info "Creating directory '#{path}'"
71
+ FileUtils.mkpath path
58
72
  end
59
- else
60
- log.info "Creating directory '#{path}'"
61
- FileUtils.mkpath path
62
73
  end
63
74
  end
64
75
 
@@ -88,8 +99,8 @@ module RubySync
88
99
 
89
100
  # Return the base_path
90
101
  def base_path
91
- @base_path = find_base_path unless defined? @base_path
92
- @base_path
102
+ @@base_path = find_base_path unless @@base_path
103
+ @@base_path
93
104
  end
94
105
 
95
106
  # Locate a configuration directory by checking the current directory and
@@ -97,14 +108,14 @@ module RubySync
97
108
  # directory.
98
109
  # Returns false if no suitable directory was found
99
110
  def find_base_path
100
- base_path = File.expand_path(".")
111
+ bp = File.expand_path(".")
101
112
  last = nil
102
113
  # Keep going up until we start repeating ourselves
103
- while File.directory?(base_path) && base_path != last && base_path != "/"
104
- return base_path if File.directory?("#{base_path}/pipelines") &&
105
- File.directory?("#{base_path}/connectors")
106
- last = base_path
107
- base_path = File.expand_path("#{base_path}/..")
114
+ while File.directory?(bp) && bp != last && bp != "/"
115
+ return bp if File.directory?("#{bp}/pipelines") &&
116
+ File.directory?("#{bp}/connectors")
117
+ last = bp
118
+ bp = File.expand_path("#{bp}/..")
108
119
  end
109
120
  return false
110
121
  end
data/lib/ruby_sync.rb CHANGED
@@ -13,6 +13,7 @@
13
13
  # You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
14
14
  # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15
15
 
16
+
16
17
  lib_path = File.dirname(__FILE__)
17
18
  $:.unshift lib_path unless $:.include?(lib_path) || $:.include?(File.expand_path(lib_path))
18
19
 
@@ -67,10 +68,15 @@ class Configuration
67
68
  def initialize
68
69
  include_in_search_path "#{base_path}/pipelines"
69
70
  include_in_search_path "#{base_path}/connectors"
71
+ include_in_search_path "#{base_path}/shared/connectors"
72
+ include_in_search_path "#{base_path}/shared/pipelines"
73
+ include_in_search_path "#{base_path}/shared/lib"
70
74
 
71
75
  lib_path = File.dirname(__FILE__)
72
76
  require_all_in_dir "#{lib_path}/ruby_sync/connectors", "*_connector.rb"
77
+ require_all_in_dir "#{base_path}/shared/connectors", "*_connector.rb"
73
78
  require_all_in_dir "#{lib_path}/ruby_sync/pipelines", "*_pipeline.rb"
79
+ require_all_in_dir "#{base_path}/shared/pipelines", "*_pipeline.rb"
74
80
  end
75
81
 
76
82
  # We find the first directory in the search path that is a parent of the specified
@@ -78,11 +84,14 @@ class Configuration
78
84
  # that duplicate requires will be recognised.
79
85
  def require_all_in_dir(dir, glob="*.rb")
80
86
  expanded = File.expand_path dir
87
+ return unless File.directory? expanded
88
+
81
89
  base = $:.detect do |path_dir|
82
90
  expanded_pd = File.expand_path(path_dir)
83
91
  expanded[0, expanded_pd.length] == expanded_pd
84
92
  end
85
- prefix = (base)? expanded[File.expand_path(base).length+1, expanded.length]+"/" : ""
93
+
94
+ prefix = (base && File.expand_path(base) != expanded)? expanded[File.expand_path(base).length+1, expanded.length]+"/" : ""
86
95
 
87
96
  # puts $:.join "\n"
88
97
  # puts "expanded = '#{expanded}'"
data/lib/rubysync.rb ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby -w
2
+ #
3
+ # Copyright (c) 2007 Ritchie Young. All rights reserved.
4
+ #
5
+ # This file is part of RubySync.
6
+ #
7
+ # RubySync is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
8
+ # as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
9
+ #
10
+ # RubySync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
11
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12
+ #
13
+ # You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
14
+ # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
15
+
16
+
17
+ class Rubysync
18
+ VERSION = '0.0.3'
19
+ end
@@ -0,0 +1,3 @@
1
+ file.reference.rubysync-bin=/Users/ritchiey/Projects/rubysync/bin
2
+ file.reference.rubysync-lib=/Users/ritchiey/Projects/rubysync/lib
3
+ file.reference.rubysync-test=/Users/ritchiey/Projects/rubysync/test
@@ -0,0 +1,8 @@
1
+ bin.dir=${file.reference.rubysync-bin}
2
+ file.reference.rubysync-bin=bin
3
+ file.reference.rubysync-lib=lib
4
+ file.reference.rubysync-test=test
5
+ main.file=
6
+ source.encoding=UTF-8
7
+ src.dir=${file.reference.rubysync-lib}
8
+ test.src.dir=${file.reference.rubysync-test}
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <project xmlns="http://www.netbeans.org/ns/project/1">
3
+ <type>org.netbeans.modules.ruby.rubyproject</type>
4
+ <configuration>
5
+ <data xmlns="http://www.netbeans.org/ns/ruby-project/1">
6
+ <name>RubySync</name>
7
+ <source-roots>
8
+ <root id="src.dir"/>
9
+ <root id="bin.dir"/>
10
+ </source-roots>
11
+ <test-roots>
12
+ <root id="test.src.dir"/>
13
+ </test-roots>
14
+ </data>
15
+ </configuration>
16
+ </project>