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.
- data/.DS_Store +0 -0
- data/.project +17 -0
- data/COPYING +339 -0
- data/HISTORY.txt +8 -0
- data/Manifest.txt +218 -0
- data/README.txt +67 -0
- data/Rakefile +31 -0
- data/bin/.DS_Store +0 -0
- data/bin/rubysync +19 -12
- data/examples/.DS_Store +0 -0
- data/examples/ar_client_webapp/log/development.log +753 -0
- data/examples/ar_client_webapp/log/production.log +0 -0
- data/examples/ar_client_webapp/log/server.log +0 -0
- data/examples/ar_client_webapp/log/test.log +0 -0
- data/examples/ar_client_webapp/public/.htaccess +40 -0
- data/examples/ar_client_webapp/tmp/sessions/ruby_sess.e2e3c63a67baef6d +0 -0
- data/examples/ar_webapp/.DS_Store +0 -0
- data/examples/ar_webapp/app/.DS_Store +0 -0
- data/examples/ar_webapp/app/views/.DS_Store +0 -0
- data/examples/ar_webapp/app/views/people/.DS_Store +0 -0
- data/examples/ar_webapp/log/development.log +5518 -0
- data/examples/ar_webapp/log/production.log +0 -0
- data/examples/ar_webapp/log/server.log +0 -0
- data/examples/ar_webapp/log/test.log +2178 -0
- data/examples/ar_webapp/public/.htaccess +40 -0
- data/examples/ar_webapp/tmp/sessions/ruby_sess.2295696b0af5f6dd +0 -0
- data/examples/ar_webapp/tmp/sessions/ruby_sess.26687aeb19c87669 +0 -0
- data/examples/ar_webapp/tmp/sessions/ruby_sess.2855a3b0c8ea840b +0 -0
- data/examples/ar_webapp/tmp/sessions/ruby_sess.45d2d48a8330ff28 +0 -0
- data/examples/ar_webapp/tmp/sessions/ruby_sess.7366b840f4ce9f12 +0 -0
- data/examples/ar_webapp/tmp/sessions/ruby_sess.b2fc3f2e6d8ae555 +0 -0
- data/examples/ar_webapp/tmp/sessions/ruby_sess.b6bf8470a62c02b0 +0 -0
- data/examples/my_ims/.DS_Store +0 -0
- data/gemspec +48 -0
- data/lib/.DS_Store +0 -0
- data/lib/net/.DS_Store +0 -0
- data/lib/ruby_sync/connectors/active_record_association_handler.rb +66 -0
- data/lib/ruby_sync/connectors/active_record_connector.rb +14 -62
- data/lib/ruby_sync/connectors/active_record_event_handler.rb +47 -0
- data/lib/ruby_sync/connectors/base_connector.rb +139 -36
- data/lib/ruby_sync/connectors/connector_event_processing.rb +18 -0
- data/lib/ruby_sync/connectors/csv_file_connector.rb +3 -0
- data/lib/ruby_sync/connectors/file_connector.rb +1 -0
- data/lib/ruby_sync/connectors/memory_connector.rb +2 -104
- data/lib/ruby_sync/connectors/xml_connector.rb +98 -0
- data/lib/ruby_sync/event.rb +7 -1
- data/lib/ruby_sync/util/utilities.rb +27 -16
- data/lib/ruby_sync.rb +10 -1
- data/lib/rubysync.rb +19 -0
- data/nbproject/private/private.properties +3 -0
- data/nbproject/project.properties +8 -0
- data/nbproject/project.xml +16 -0
- data/rubysync.tmproj +348 -0
- data/test/.DS_Store +0 -0
- data/test/ruby_sync_test.rb +8 -1
- data/test/tc_xml_connectors.rb +47 -0
- data/test/test_active_record_vault.rb +17 -14
- data/test/test_base_connector.rb +38 -0
- data/test/test_ldap_changelog.rb +97 -0
- data/test/test_ldap_connector.rb +2 -48
- data/test/test_memory_connectors.rb +8 -3
- data/test/test_rubysync.rb +28 -0
- data/test/ts_rubysync.rb +5 -3
- 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
|
-
|
31
|
-
|
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
|
data/lib/ruby_sync/event.rb
CHANGED
@@ -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.
|
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
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
92
|
-
|
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
|
-
|
111
|
+
bp = File.expand_path(".")
|
101
112
|
last = nil
|
102
113
|
# Keep going up until we start repeating ourselves
|
103
|
-
while File.directory?(
|
104
|
-
return
|
105
|
-
File.directory?("#{
|
106
|
-
last =
|
107
|
-
|
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
|
-
|
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,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>
|