rubysync 0.0.3 → 0.0.4

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 (45) hide show
  1. data/HISTORY.txt +4 -0
  2. data/Manifest.txt +25 -12
  3. data/README.txt +0 -2
  4. data/bin/rubysync +20 -6
  5. data/bin/rubysync.rb +333 -0
  6. data/docs/in_pipeline.graffle +2690 -0
  7. data/docs/init_openldap.ldif +11 -0
  8. data/docs/out_pipeline.graffle +3274 -0
  9. data/docs/schema/99rubysync.ldif +27 -0
  10. data/docs/schema/rubysync.schema +16 -0
  11. data/docs/to_sync.txt +15 -0
  12. data/docs/walkthru.txt +186 -0
  13. data/lib/ruby_sync.rb +7 -29
  14. data/lib/ruby_sync/connectors/base_connector.rb +55 -86
  15. data/lib/ruby_sync/connectors/csv_file_connector.rb +16 -4
  16. data/lib/ruby_sync/connectors/ldap_associations.rb +126 -0
  17. data/lib/ruby_sync/connectors/ldap_changelog_connector.rb +127 -0
  18. data/lib/ruby_sync/connectors/ldap_connector.rb +29 -192
  19. data/lib/ruby_sync/connectors/memory_connector.rb +1 -1
  20. data/lib/ruby_sync/connectors/xml_connector.rb +105 -32
  21. data/lib/ruby_sync/event.rb +40 -12
  22. data/lib/ruby_sync/operation.rb +18 -2
  23. data/lib/ruby_sync/pipelines/base_pipeline.rb +44 -6
  24. data/lib/ruby_sync/util/utilities.rb +97 -4
  25. data/lib/rubysync.rb +1 -1
  26. data/rubysync.tmproj +279 -59
  27. data/test/.LCKts_rubysync.rb~ +1 -0
  28. data/test/ruby_sync_test.rb +9 -4
  29. data/test/{test_active_record_vault.rb → tc_active_record_connector.rb} +11 -7
  30. data/test/{test_base_connector.rb → tc_base_connector.rb} +1 -1
  31. data/test/{test_base_pipeline.rb → tc_base_pipeline.rb} +1 -1
  32. data/test/tc_changelog_ldap_connector.rb +93 -0
  33. data/test/{test_csv_file_connector.rb → tc_csv_file_connector.rb} +14 -5
  34. data/test/{test_event.rb → tc_event.rb} +1 -1
  35. data/test/{test_ldap_changelog.rb → tc_ldap_changelog.rb} +1 -1
  36. data/test/{test_ldap_connector.rb → tc_ldap_connector.rb} +20 -22
  37. data/test/{test_ldap_vault.rb → tc_ldap_vault.rb} +2 -2
  38. data/test/{test_ldif.rb → tc_ldif.rb} +1 -1
  39. data/test/{test_memory_connectors.rb → tc_memory_connectors.rb} +10 -6
  40. data/test/{test_rubysync.rb → tc_rubysync.rb} +4 -4
  41. data/test/tc_transformation.rb +71 -0
  42. data/test/{test_utilities.rb → tc_utilities.rb} +28 -1
  43. data/test/tc_xml_connectors.rb +107 -6
  44. data/test/ts_rubysync.rb +11 -6
  45. metadata +33 -28
data/HISTORY.txt CHANGED
@@ -1,3 +1,7 @@
1
+ == 0.0.4 / 2007-09-18
2
+
3
+ * XML Connector now works correctly even if id used isn't a valid XML tag
4
+ * Improved transformations
1
5
 
2
6
  == 0.0.3 / 2007-08-27
3
7
 
data/Manifest.txt CHANGED
@@ -7,6 +7,14 @@ README.txt
7
7
  Rakefile
8
8
  bin/.DS_Store
9
9
  bin/rubysync
10
+ bin/rubysync.rb
11
+ docs/in_pipeline.graffle
12
+ docs/init_openldap.ldif
13
+ docs/out_pipeline.graffle
14
+ docs/schema/99rubysync.ldif
15
+ docs/schema/rubysync.schema
16
+ docs/to_sync.txt
17
+ docs/walkthru.txt
10
18
  examples/.DS_Store
11
19
  examples/ar_client_webapp/README
12
20
  examples/ar_client_webapp/Rakefile
@@ -179,6 +187,8 @@ lib/ruby_sync/connectors/base_connector.rb
179
187
  lib/ruby_sync/connectors/connector_event_processing.rb
180
188
  lib/ruby_sync/connectors/csv_file_connector.rb
181
189
  lib/ruby_sync/connectors/file_connector.rb
190
+ lib/ruby_sync/connectors/ldap_associations.rb
191
+ lib/ruby_sync/connectors/ldap_changelog_connector.rb
182
192
  lib/ruby_sync/connectors/ldap_connector.rb
183
193
  lib/ruby_sync/connectors/memory_connector.rb
184
194
  lib/ruby_sync/connectors/xml_connector.rb
@@ -193,6 +203,7 @@ nbproject/project.properties
193
203
  nbproject/project.xml
194
204
  rubysync.tmproj
195
205
  test/.DS_Store
206
+ test/.LCKts_rubysync.rb~
196
207
  test/data/example1.ldif
197
208
  test/data/example2.ldif
198
209
  test/data/example3.ldif
@@ -202,17 +213,19 @@ test/data/example6.ldif
202
213
  test/data/example7.ldif
203
214
  test/hashlike_tests.rb
204
215
  test/ruby_sync_test.rb
216
+ test/tc_active_record_connector.rb
217
+ test/tc_base_connector.rb
218
+ test/tc_base_pipeline.rb
219
+ test/tc_changelog_ldap_connector.rb
220
+ test/tc_csv_file_connector.rb
221
+ test/tc_event.rb
222
+ test/tc_ldap_changelog.rb
223
+ test/tc_ldap_connector.rb
224
+ test/tc_ldap_vault.rb
225
+ test/tc_ldif.rb
226
+ test/tc_memory_connectors.rb
227
+ test/tc_rubysync.rb
228
+ test/tc_transformation.rb
229
+ test/tc_utilities.rb
205
230
  test/tc_xml_connectors.rb
206
- test/test_active_record_vault.rb
207
- test/test_base_connector.rb
208
- test/test_base_pipeline.rb
209
- test/test_csv_file_connector.rb
210
- test/test_event.rb
211
- test/test_ldap_changelog.rb
212
- test/test_ldap_connector.rb
213
- test/test_ldap_vault.rb
214
- test/test_ldif.rb
215
- test/test_memory_connectors.rb
216
- test/test_rubysync.rb
217
- test/test_utilities.rb
218
231
  test/ts_rubysync.rb
data/README.txt CHANGED
@@ -17,8 +17,6 @@ for your organisation.
17
17
 
18
18
  == FEATURES/PROBLEMS:
19
19
 
20
- * Add support for running continually
21
- * Test suites. Individual tests work but test suites have trouble ???
22
20
 
23
21
  == SYNOPSIS:
24
22
 
data/bin/rubysync CHANGED
@@ -112,6 +112,18 @@ class Controller < SimpleConsole::Controller
112
112
  end
113
113
  end
114
114
 
115
+ def start
116
+ pipeline_name = params[:id]
117
+ pipeline = pipeline_called pipeline_name
118
+ if pipeline
119
+ pipeline.start
120
+ else
121
+ log.error "Couldn't find a pipeline called '#{pipeline_name}'"
122
+ end
123
+ end
124
+
125
+
126
+
115
127
  # Create a Rubysync project directory
116
128
  def create
117
129
  config_path = params[:id]
@@ -207,6 +219,8 @@ Usage:
207
219
  * once {name}
208
220
  ; Execute the named pipeline within the current
209
221
  ; configuration directory once and then exit
222
+
223
+ * start {name} ; Execute the named pipeline
210
224
 
211
225
  * example ; Show an example of how this command might be used
212
226
 
@@ -236,9 +250,13 @@ puts <<"END"
236
250
  You would then edit the file pipelines/my_pipeline.rb to configure the
237
251
  policy for synchronizing between the two connectors.
238
252
 
239
- You may then execute the pipeline in one-shot mode (daemon mode is coming):
253
+ You may then execute the pipeline in one-shot mode:
240
254
 
241
255
  $ rubysync once my
256
+
257
+ or continually:
258
+
259
+ $ rubysync start my
242
260
  END
243
261
  end
244
262
 
@@ -248,9 +266,6 @@ end
248
266
 
249
267
 
250
268
 
251
- def start
252
- puts "Not yet implemented"
253
- end
254
269
 
255
270
  end
256
271
 
@@ -266,7 +281,6 @@ class #{name.to_s.camelize}Connector < #{type_class_name}
266
281
  end
267
282
  end;
268
283
  end
269
-
270
284
 
271
285
 
272
286
  def pipeline_template name, vault_name, client_name
@@ -298,7 +312,7 @@ class #{name.to_s.camelize}Pipeline < RubySync::Pipelines::BasePipeline
298
312
  # 'first name' => 'givenName'
299
313
  # separate each mapping with a comma.
300
314
  # The following fields were detected on the client:
301
- # #{(client_fields.map {|f| "'#{f}'"}).join(", ")}
315
+ # #{(client_fields.map {|f| "'#{f}'"}).join(",")}
302
316
  map_vault_to_client({
303
317
  #{(vault_fields.map {|f| "#'#{f}' => 'a_client_field'"}).join(",\n\t\t")}
304
318
  })
data/bin/rubysync.rb ADDED
@@ -0,0 +1,333 @@
1
+ #!/opt/local/bin/ruby
2
+
3
+
4
+ # == Synopsis
5
+ #
6
+ # Command line tool for running *rubysync* <em>A Free MetaDirectory.</em>
7
+ #
8
+ # == Usage
9
+ #
10
+ # rubysync command name [options]
11
+ #
12
+ # Valid commands are::
13
+ # * create {name}:: Create a rubysync configuration directory
14
+ #
15
+ # * connector {name} -t {type} [--vault {name}] [--client {name}]
16
+ # ; Create a connector of the given name in
17
+ # ; the current rubysync configuration directory
18
+ #
19
+ # * fields {name} ; list the fields detected by the named connector
20
+ #
21
+ # * pipeline {name} ; Create a rubysync pipeline of the given name
22
+ # ; in the current rubysync configuration directory
23
+ #
24
+ # * once {name}::
25
+ # Execute the named pipeline within the current configuration directory once and then exit
26
+ #
27
+ # * example:: Show an example of how this command might be used
28
+ #
29
+ # == Example
30
+ #
31
+ # This sets up the skeleton of a configuration for importing comma delimeted
32
+ # text files into an xml file.
33
+ # <tt>
34
+ # $ rubysync create xml_demo
35
+ # $ cd xml_demo
36
+ # $ rubysync connector my_csv -t csv_file
37
+ # $ rubysync connector my_xml -t xml
38
+ # </tt>
39
+ #
40
+ # You would then edit the files::
41
+ #
42
+ # * +connectors/my_csv_connector.rb+:: where to get the CSV files, field names, etc
43
+ # * +connectors/my_xml_connector.rb+:: how to connect to your XML file.
44
+ #
45
+ # And enter::
46
+ # <tt>
47
+ # $ rubysync pipeline my_pipeline -C my_csv -V my_xml
48
+ # </tt>
49
+ #
50
+ # You would then edit the file +pipelines/my_pipeline.rb+ to configure the
51
+ # policy for synchronizing between the two connectors.
52
+ #
53
+ # You may then execute the pipeline in one-shot mode (daemon mode is coming)::
54
+ #
55
+ # <tt>
56
+ # $ rubysync once my_pipeline
57
+ # </tt>
58
+ #
59
+ # == Author
60
+ # Ritchie Young, 9 to 5 Magic (http://9to5magic.com.au)
61
+ #
62
+ # == Copyright
63
+ # Copyright (c) 2007 Ritchie Young. All rights reserved.
64
+ #
65
+ # This file is part of RubySync.
66
+ #
67
+ # RubySync is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License
68
+ # as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
69
+ #
70
+ # RubySync is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
71
+ # warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
72
+ #
73
+ # You should have received a copy of the GNU General Public License along with RubySync; if not, write to the
74
+ # Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
75
+
76
+
77
+ lib_path = File.dirname(__FILE__) + '/../lib'
78
+ $:.unshift lib_path unless $:.include?(lib_path) || $:.include?(File.expand_path(lib_path))
79
+ require "ruby_sync"
80
+ require "simpleconsole"
81
+ require 'rdoc/usage'
82
+
83
+
84
+ class Controller < SimpleConsole::Controller
85
+
86
+ include RubySync::Utilities
87
+
88
+ before_filter :configure_logging
89
+
90
+ params :string => {:p => :pipe,
91
+ :t => :type,
92
+ :V => :vault,
93
+ :C => :client},
94
+ :int =>{:v => :verbose}
95
+
96
+ def default
97
+ #RDoc::usage 'Usage'
98
+ end
99
+
100
+ def example
101
+ #RDoc::usage 'Example'
102
+ end
103
+
104
+ # Run specified pipeline once then exit
105
+ def once
106
+ pipeline_name = params[:id]
107
+ pipeline = pipeline_called pipeline_name
108
+ if pipeline
109
+ pipeline.run_once
110
+ else
111
+ log.error "Couldn't find a pipeline called '#{pipeline_name}'"
112
+ end
113
+ end
114
+
115
+ def start
116
+ pipeline_name = params[:id]
117
+ pipeline = pipeline_called pipeline_name
118
+ if pipeline
119
+ pipeline.start
120
+ else
121
+ log.error "Couldn't find a pipeline called '#{pipeline_name}'"
122
+ end
123
+ end
124
+
125
+
126
+
127
+ # Create a Rubysync project directory
128
+ def create
129
+ config_path = params[:id]
130
+ ensure_dir_exists([
131
+ config_path,
132
+ "#{config_path}/pipelines",
133
+ "#{config_path}/connectors",
134
+ "#{config_path}/shared",
135
+ "#{config_path}/shared/pipelines",
136
+ "#{config_path}/shared/connectors",
137
+ "#{config_path}/shared/lib",
138
+ "#{config_path}/log",
139
+ "#{config_path}/db"
140
+ ])
141
+ end
142
+
143
+ # Create a connector configuration file
144
+ def connector
145
+ name = params[:id]
146
+ type = params[:type]
147
+ unless name and type
148
+ puts "Usage: rubysync connector connector_name -t connector_type"
149
+ return
150
+ end
151
+ if base_path
152
+ File.open("#{base_path}/connectors/#{name}_connector.rb", "w") do |file|
153
+ file.puts connector_template(name, type)
154
+ end
155
+ else
156
+ puts 'Change into a config dir and try again or create a config dir with "rubysync create"'
157
+ end
158
+ end
159
+
160
+ # List the fields that the named connector can detect. This is
161
+ # a good way to test if a connector config is functional.
162
+ def fields
163
+ connector_name = params[:id]
164
+ connector = (connector_name)? ::RubySync::Connectors::BaseConnector.class_for(connector_name) : nil
165
+ @field_names = connector && connector.fields || []
166
+ end
167
+
168
+ def pipeline
169
+ name = params[:id]
170
+ vault_name = params[:vault]
171
+ client_name = params[:client]
172
+ unless name
173
+ puts "Usage: rubysync pipeline pipeline_name [-V vault] [-C client]"
174
+ return
175
+ end
176
+ if base_path
177
+ File.open("#{base_path}/pipelines/#{name}_pipeline.rb", "w") do |file|
178
+ file.puts pipeline_template(name, vault_name, client_name)
179
+ end
180
+ else
181
+ puts 'Change into a config dir and try again or create a config dir with "rubysync create"'
182
+ end
183
+
184
+ end
185
+
186
+
187
+ private
188
+
189
+ def configure_logging
190
+ log_levels = [Logger::WARN, Logger::INFO, Logger::DEBUG]
191
+ verbosity = [(params[:verbose]||0), log_levels.size-1].min
192
+ log.level = log_levels[verbosity]
193
+ end
194
+
195
+ end
196
+
197
+
198
+ class View < SimpleConsole::View
199
+
200
+
201
+ def default
202
+ puts <<"END"
203
+ Usage:
204
+
205
+ rubysync command name [options]
206
+
207
+ Valid commands are:
208
+ * create {name}: Create a rubysync configuration directory
209
+
210
+ * connector {name} -t {type} [--vault {name}] [--client {name}]
211
+ ; Create a connector of the given name in
212
+ ; the current rubysync configuration directory
213
+
214
+ * fields {name} ; list the fields detected by the named connector
215
+
216
+ * pipeline {name} ; Create a rubysync pipeline of the given name
217
+ ; in the current rubysync configuration directory
218
+
219
+ * once {name}
220
+ ; Execute the named pipeline within the current
221
+ ; configuration directory once and then exit
222
+
223
+ * start {name} ; Execute the named pipeline
224
+
225
+ * example ; Show an example of how this command might be used
226
+
227
+ END
228
+ end
229
+
230
+
231
+ def example
232
+ puts <<"END"
233
+ This sets up the skeleton of a configuration for importing comma delimeted
234
+ text files into a database. Note, if the application happens to be a Rails
235
+ app then it can also export changes.
236
+
237
+ $ rubysync create db_demo
238
+ $ cd db_demo
239
+ $ rubysync connector my_csv -t csv_file
240
+ $ rubysync connector my_db -t active_record
241
+
242
+ You would then edit the files:
243
+
244
+ connectors/my_csv_connector.rb ;where to get CSV files, field names, etc
245
+ connectors/my_db_connector.rb ;how to connect to your DB or Rails app.
246
+
247
+ And enter:
248
+ $ rubysync pipeline my -C my_csv -V my_db
249
+
250
+ You would then edit the file pipelines/my_pipeline.rb to configure the
251
+ policy for synchronizing between the two connectors.
252
+
253
+ You may then execute the pipeline in one-shot mode:
254
+
255
+ $ rubysync once my
256
+
257
+ or continually:
258
+
259
+ $ rubysync start my
260
+ END
261
+ end
262
+
263
+ def fields
264
+ puts @field_names.join("\n")
265
+ end
266
+
267
+
268
+
269
+
270
+ end
271
+
272
+
273
+ def connector_template name, type
274
+ type_class_name = "RubySync::Connectors::#{type.to_s.camelize}Connector"
275
+ type_class = eval(type_class_name)
276
+ sample_config = (type_class && type_class.respond_to?("sample_config")) ?
277
+ type_class.sample_config : ""
278
+ return <<-"end;"
279
+ class #{name.to_s.camelize}Connector < #{type_class_name}
280
+ #{sample_config}
281
+ end
282
+ end;
283
+ end
284
+
285
+
286
+ def pipeline_template name, vault_name, client_name
287
+ vault = (vault_name)? ::RubySync::Connectors::BaseConnector.class_for(vault_name) : nil
288
+ vault_fields = vault && vault.fields || %w{allow these fields through}
289
+ possible_fields = (vault_fields.map {|n| ":#{n}"}).join(", ")
290
+
291
+ client = (client_name)? ::RubySync::Connectors::BaseConnector.class_for(client_name) : nil
292
+ client_fields = client && client.fields || []
293
+
294
+ vault_specifier = (vault_name)? "vault :#{vault_name}" : "#vault :vault_connector_name"
295
+ client_specifier = (client_name)? "client :#{client_name}" : "#client :client_connector_name"
296
+ return <<-"end;"
297
+ class #{name.to_s.camelize}Pipeline < RubySync::Pipelines::BasePipeline
298
+
299
+ #{client_specifier}
300
+
301
+ #{vault_specifier}
302
+
303
+ # Remove any fields that you don't want to set in the client from the vault
304
+ allow_out #{possible_fields}
305
+
306
+ # Remove any fields that you don't want to set in the vault from the client
307
+ allow_in #{possible_fields}
308
+
309
+ # If the client and vault have different names for the same field, define the
310
+ # the mapping here. For example, if the vault has a field called "first name" and
311
+ # the client has a field called givenName you may put:
312
+ # 'first name' => 'givenName'
313
+ # separate each mapping with a comma.
314
+ # The following fields were detected on the client:
315
+ # #{(client_fields.map {|f| "'#{f}'"}).join(",")}
316
+ map_vault_to_client({
317
+ #{(vault_fields.map {|f| "#'#{f}' => 'a_client_field'"}).join(",\n\t\t")}
318
+ })
319
+
320
+ # "in" means going from client to vault
321
+ #in_transform do
322
+ #end
323
+
324
+ # "out" means going from vault to client
325
+ #out_transform do
326
+ #end
327
+
328
+ end
329
+ end;
330
+ end
331
+
332
+
333
+ SimpleConsole::Application.run(ARGV, Controller, View)