syncevolution 0.1.5

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e66f23c24c893a5c3f65f05bb4c01b68969e9480
4
+ data.tar.gz: 72711fca4d295007d661967514962f9628435f56
5
+ SHA512:
6
+ metadata.gz: 6bc97d40e0e1f7385c91e3c46c5834d7e9e17b661fa8e50af1db63516b70b26c9ff0ec4ac6548f47ecd35ed49f0910d363fee0430fcf7e16dcfdce3494933dac
7
+ data.tar.gz: 77ecb22582ae6c2669bb5180fdd90848fcd072350b2e979d1ce56de1c3cb208be74c09619ac2a5c7db861566168ba6e374b329cfeab76aadb32a77e92a79d003
data/.gitignore ADDED
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,7 @@
1
+ #ruby=2.1
2
+ #ruby-gemset=syncevolution
3
+
4
+ source 'https://rubygems.org'
5
+
6
+ # Specify your gem's dependencies in syncevolution.gemspec
7
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 friflaj
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # SyncEvolution
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'syncevolution'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install syncevolution
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ require 'rake/testtask'
4
+
5
+ Rake::TestTask.new do |t|
6
+ t.libs << 'test'
7
+ end
8
+
9
+ desc "Run tests"
10
+ task :default => :test
data/bin/se-config ADDED
@@ -0,0 +1,326 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'inifile'
4
+ require 'nokogiri'
5
+ require 'pp'
6
+ require 'trollop'
7
+
8
+ module SyncEvolution
9
+ class SyncEvolution
10
+ def to_params(params, indent, postfix = " \\\n")
11
+ return '' if params.size == 0
12
+ sep = indent ? "\\\n " : ''
13
+ return sep + params.keys.select{|k| params[k]}.collect{|k| "#{k}=#{params[k]}"}.collect{|kv| escape(kv) }.join(" #{sep}") + (indent ? postfix : '')
14
+ end
15
+
16
+ def escape(s)
17
+ return s if s !~ / / && s != "\"#{s}\""
18
+ return _inspect(s)
19
+ end
20
+
21
+ def to_gv
22
+ gv = "digraph syncevolution {\n"
23
+
24
+ objects = {}
25
+ syncs = 0
26
+
27
+ @doc.xpath('//context').each{|context|
28
+ objects[context['name']] ||= "o#{objects.size}"
29
+ gv << " subgraph cluster_#{objects[context['name']]} {\n"
30
+ gv << " label = #{context['name'].inspect};\n"
31
+
32
+ context.xpath('./store').each{|store|
33
+ objects[context['name'] + ':' + store['name']] ||= "o#{objects.size}"
34
+ gv << " #{objects[context['name'] + ':' + store['name']]} [ shape = folder, label = #{store['name'].inspect}];\n"
35
+ }
36
+
37
+ context.xpath('./sync').each{|sync|
38
+ objects[context['name'] + ':' + sync['name']] ||= "o#{objects.size}"
39
+ gv << " #{objects[context['name'] + ':' + sync['name']]} [ shape = component, label = #{sync['name'].inspect}];\n"
40
+
41
+
42
+ sync.xpath('./store').each{|store|
43
+ }
44
+ }
45
+
46
+ gv << " }\n"
47
+ }
48
+
49
+ @doc.xpath('//sync/store').each{|store|
50
+ sync = store.parent
51
+ context = sync.parent
52
+
53
+ if sync['syncURL'] =~ /^local:\/\/@(.+)/
54
+ targetcontext = $1.downcase
55
+ else
56
+ next
57
+ end
58
+
59
+ syncs += 1
60
+
61
+ objects["#{targetcontext}:target-config"] ||= "o#{objects.size}"
62
+ objects["#{targetcontext}:#{store['uri']}"] ||= "o#{objects.size}"
63
+
64
+ dir = case store['sync']
65
+ when 'two-way' then 'both'
66
+ else throw store['sync'].inspect
67
+ end
68
+
69
+ gv << " #{objects[context['name'] + ':' + store['name']]} -> #{objects[context['name'] + ':' + sync['name']]} [label=\"#{syncs}\", dir=#{dir}, style=dashed];\n"
70
+ gv << " #{objects[context['name'] + ':' + sync['name']]} -> #{objects["#{targetcontext}:target-config"]} [label=\"#{syncs}\", dir=#{dir}, style=dashed];\n"
71
+ gv << " #{objects["#{targetcontext}:target-config"]} -> #{objects["#{targetcontext}:#{store['uri']}"]} [label=\"#{syncs}\", dir=#{dir}, style=dashed];\n"
72
+ }
73
+
74
+ gv << "}\n"
75
+
76
+ gv
77
+ end
78
+
79
+ def import(xml)
80
+ doc = Nokogiri::XML(open(xml))
81
+
82
+ set(@doc.root, doc.root.attributes)
83
+
84
+ doc.xpath('//context').each {|ctx_s|
85
+ ctx_t = @doc.at("//context[@name=#{_inspect(ctx_s['name'])}]")
86
+ if ctx_s.at('./clear') && ctx_t
87
+ ctx_t.unlink
88
+ ctx_t = add(context: ctx_s['name'])
89
+ ctx_t << '<clear/>'
90
+ end
91
+ set(add(context: ctx_s['name']), ctx_s.attributes) if ctx_s.attributes.size > 0
92
+
93
+ ctx_s.xpath('./store').each{|st_s|
94
+ st_t = @doc.at("//context[@name=#{_inspect(ctx_s['name'])}]/store[@name=#{_inspect(st_s['name'])}]")
95
+ if st_s.at('./clear') && st_t
96
+ st_t.unlink
97
+ st_t = add(context: ctx_s['name'], store: st_s['name'])
98
+ st_t << '<clear/>'
99
+ end
100
+ set(add(context: ctx_s['name'], store: st_s['name']), st_s.attributes) if st_s.attributes.size > 0
101
+ }
102
+
103
+ ctx_s.xpath('./sync').each{|sn_s|
104
+ sn_t = @doc.at("//context[@name=#{_inspect(ctx_s['name'])}]/store[@name=#{_inspect(sn_s['name'])}]")
105
+ if sn_s.at('./clear') && sn_t
106
+ sn_t.unlink
107
+ sn_t = add(context: ctx_s['name'], sync: sn_s['name'])
108
+ sn_t << '<clear/>'
109
+ end
110
+ set(add(context: ctx_s['name'], sync: sn_s['name']), sn_s.attributes) if sn_s.attributes.size > 0
111
+
112
+ sn_s.xpath('./store').each{|st_s|
113
+ st_t = @doc.at("//context[@name=#{_inspect(ctx_s['name'])}]/sync[@name=#{_inspect(sn_s['name'])}]/store[@name=#{_inspect(st_s['name'])}]")
114
+ if st_s.at('./clear') && st_t
115
+ st_t.unlink
116
+ st_t = add(context: ctx_s['name'], sync: sn_s['name'], store: st_s['name'])
117
+ st_t << '<clear/>'
118
+ end
119
+ set(add(context: ctx_s['name'], sync: sn_s['name'], store: st_s['name']), st_s.attributes) if st_s.attributes.size > 0
120
+ }
121
+ }
122
+ }
123
+ end
124
+
125
+ def to_bash(indent)
126
+ bash = ''
127
+
128
+ params = to_params(@doc.root.attributes.reject{|k, v| k == 'name'}, indent, '')
129
+ bash << "syncevolution --configure --template none #{params}\n" if params != ''
130
+
131
+ @doc.xpath('//context').each{|context|
132
+ bash << "syncevolution --remove #{escape('@' + context['name'])}\n" if context.at('./clear')
133
+
134
+ params = to_params(context.attributes.reject{|k, v| k == 'name'}, indent)
135
+ bash << "syncevolution --configure --template none #{params} @#{escape(context['name'])}\n" if params != ''
136
+
137
+ context.xpath('./store').each{|store|
138
+ bash << "syncevolution --remove-database #{escape('@' + context['name'])} #{escape(store['name'])}\n" if store.at('./clear')
139
+
140
+ params = to_params(store.attributes.reject{|k, v| k == 'name'}, indent)
141
+ bash << "syncevolution --configure --template none #{params} @#{escape(context['name'])} #{escape(store['name'])}\n" if params != ''
142
+ }
143
+
144
+ context.xpath('./sync').each{|sync|
145
+ bash << "syncevolution --remove #{escape(sync['name'] + '@' + context['name'])}\n" if sync.at('./clear')
146
+ params = to_params(sync.attributes.reject{|k, v| k == 'name'}, indent)
147
+ bash << "syncevolution --configure --template none #{params} #{escape(sync['name'] + '@' + context['name'])}\n" if params != ''
148
+ sync.xpath('./store').each{|store|
149
+ params = to_params(store.attributes.reject{|k, v| k == 'name'}, indent)
150
+ bash << "syncevolution --configure --template none #{params} #{escape(sync['name'] + '@' + context['name'])} #{escape(store['name'])}\n" if params != ''
151
+ }
152
+ }
153
+ }
154
+
155
+ bash
156
+ end
157
+
158
+ def _inspect(s)
159
+ "'#{s.gsub("'", %q(\\\'))}'"
160
+ end
161
+
162
+ def add(options={})
163
+ context = @doc.at("//context[@name=#{_inspect(options[:context].downcase)}]")
164
+ if !context
165
+ context = Nokogiri::XML::Node.new('context', @doc)
166
+ context['name'] = options[:context].downcase
167
+ @doc.root.add_child(context)
168
+ end
169
+ return context if !(options[:store] || options[:sync])
170
+
171
+ if options[:sync]
172
+ sync = context.at("./*[@name=#{_inspect(options[:sync].downcase)}]")
173
+ if !sync
174
+ sync = Nokogiri::XML::Node.new('sync', @doc)
175
+ sync['name'] = options[:sync].downcase
176
+ context.add_child(sync)
177
+ elsif sync.name != 'sync'
178
+ throw "#{options[:context].downcase}/#{options[:sync].downcase} added as a sync, but exists as a #{sync.name}"
179
+ end
180
+
181
+ return sync unless options[:store]
182
+ context = sync
183
+ end
184
+
185
+ store = context.at("./*[@name=#{_inspect(options[:store].downcase)}]")
186
+ if !store
187
+ store = Nokogiri::XML::Node.new('store', @doc)
188
+ store['name'] = options[:store].downcase
189
+ context.add_child(store)
190
+ elsif store.name != 'store'
191
+ throw "#{options[:context].downcase}/#{options[:sync] ? options[:sync] + '/' : ''}#{options[:store].downcase} added as a store, but exists as a #{store.name}"
192
+ end
193
+ return store
194
+ end
195
+
196
+ def set(node, params)
197
+ params.each_pair{|k, v|
198
+ node[k] = v
199
+ }
200
+ end
201
+
202
+ def initialize(root=nil)
203
+ root = '~/.config/syncevolution/' if root == '~'
204
+ root = File.expand_path(root)
205
+ @doc = Nokogiri::XML('<syncevolution/>')
206
+
207
+ Dir["#{root}/**/config.ini"].sort.reverse.each{|ini|
208
+ params = {}
209
+ settings = IniFile.load(ini)
210
+ settings.each { |section, parameter, value|
211
+ next if parameter == 'synthesisID'
212
+ raise section unless section == 'global'
213
+
214
+ value = 'eas-events' if parameter == 'backend' && value == 'ActiveSync Events'
215
+ value = 'eas-contacts' if parameter == 'backend' && value == 'ActiveSync Address Book'
216
+
217
+ params[parameter] = value.to_s.strip == '' ? nil : value
218
+ }
219
+
220
+ node = nil
221
+ case File.dirname(ini)[root.size, ini.size].gsub(/^\//, '')
222
+ when ''
223
+ node = @doc.root
224
+
225
+ when /^([^\/]+)$/
226
+ node = add(context: $1)
227
+
228
+ when /^([^\/]+)\/sources\/([^\/]+)$/
229
+ node = add(context: $1, store: $2)
230
+
231
+ when /^([^\/]+)\/peers\/([^\/]+)$/
232
+ node = add(context: $1, sync: $2)
233
+
234
+ when /^([^\/]+)\/peers\/([^\/]+)\/sources\/([^\/]+)$/
235
+ node = add(context: $1, sync: $2, store: $3)
236
+
237
+ else throw ini
238
+ end
239
+
240
+ set(node, params)
241
+ }
242
+ end
243
+
244
+ def to_xml
245
+ return @doc.to_xml
246
+ end
247
+
248
+ def backend_type(store)
249
+ case store['backend']
250
+ when 'file'
251
+ case store['databaseFormat']
252
+ when 'text/vcard' then return :contacts
253
+ when 'text/calendar' then return :events
254
+ end
255
+ when 'eas-events', 'ActiveSync Events' then return :events
256
+ when 'eas-contacts', 'ActiveSync Address Book' then return :contacts
257
+ end
258
+ throw "Cannot determine backend type from #{store.inspect}"
259
+ end
260
+
261
+ def verify
262
+ @doc.xpath("//sync[@name='target-config']/store[@sync != 'none' and @sync != 'disabled']").each{|store|
263
+ puts "target-config@#{store.parent.parent['name']} has set sync of #{store['name']} to #{store['sync']}, but sync is not used in a target-config"
264
+ }
265
+
266
+ @doc.xpath("//sync[@name='target-config' and @syncURL]").each{|sync|
267
+ puts "target-config@#{sync.parent['name']} has set an syncURL, but syncURL is not used in a target-config"
268
+ }
269
+
270
+ @doc.xpath("//sync").each{|sync|
271
+ if !sync['syncURL']
272
+ puts "sync-config #{sync['name']}@#{sync.parent['name']} has no syncURL" unless sync['name'] == 'target-config'
273
+ else
274
+ targetcontext = sync['syncURL'].gsub(/^local:\/\//i, '')
275
+
276
+ if targetcontext != sync['syncURL'].to_s
277
+ puts "sync-config #{sync['name']}@#{sync.parent['name']} set up for local sync with #{targetcontext}, which doesn't start with '@'" if targetcontext !~ /^@/
278
+ targetcontext.sub!(/^@/, '')
279
+ targetcontext.downcase!
280
+ if !@doc.at("//context[@name=#{_inspect(targetcontext)}]")
281
+ puts "sync-config #{sync['name']}@#{sync.parent['name']} set up for local sync with non-existent context #{targetcontext}"
282
+ elsif !@doc.at("//context[@name=#{_inspect(targetcontext)}]/sync[@name='target-config']")
283
+ puts "sync-config #{sync['name']}@#{sync.parent['name']} set up for local sync with non-existent target-config@#{targetcontext}"
284
+ else
285
+ sync.xpath('./store').each{|store|
286
+ local = @doc.at("//context[@name=#{_inspect(sync.parent['name'])}]/store[@name=#{_inspect(store['name'])}]")
287
+ if local
288
+ remote = @doc.at("//context[@name=#{_inspect(targetcontext)}]/store[@name=#{_inspect(store['uri'])}]")
289
+ if remote
290
+ lbe = backend_type(local)
291
+ rbe = backend_type(remote)
292
+ puts "sync-config #{sync['name']}@#{sync.parent['name']} connects store #{local['name']}@#{sync.parent['name']} of type #{lbe} to incompatible #{remote['name']}@#{targetcontext} of type #{rbe}" if lbe != rbe
293
+ else
294
+ puts "sync-config #{sync['name']}@#{sync.parent['name']} connects store #{store['name']}@#{sync.parent['name']} to non-existent #{store['uri']}@#{targetcontext}"
295
+ end
296
+ end
297
+ }
298
+ end
299
+ end
300
+ end
301
+ }
302
+
303
+ @doc.xpath("//sync/store").each{|store|
304
+ if !store.parent.at(".//store[@name=#{_inspect(store['name'])}]")
305
+ puts "sync-config #{store.parent['name']}@#{store.parent.parent['name']} references non-existent store #{store['name']}"
306
+ end
307
+ }
308
+ end
309
+ end
310
+ end
311
+
312
+ OPTS = Trollop::options do
313
+ opt :xml, "Output xml"
314
+ opt :import, "Output xml", :type => :string
315
+ opt :bash, "Output bash code"
316
+ opt :graphviz, "Output graphviz code"
317
+ opt :indent, "Indent bash code"
318
+ opt :verify, "Verify configuration"
319
+ end
320
+
321
+ SE = SyncEvolution::SyncEvolution.new('~')
322
+ SE.verify
323
+ SE.import(OPTS[:import]) if OPTS[:import]
324
+ puts SE.to_xml if OPTS[:xml]
325
+ puts SE.to_bash(OPTS[:indent]) if OPTS[:bash]
326
+ puts SE.to_gv if OPTS[:graphviz]
@@ -0,0 +1,3 @@
1
+ module SyncEvolution
2
+ VERSION = "0.1.5"
3
+ end
data/publish.sh ADDED
@@ -0,0 +1,11 @@
1
+ #!/bin/sh
2
+
3
+ set -e
4
+
5
+ git tag `ruby -e 'require "./lib/syncevolution/version.rb"; puts SyncEvolution::VERSION'`
6
+ git push
7
+ rm -f pkg/*
8
+ rake install
9
+ for f in pkg/*.gem; do
10
+ gem push $f
11
+ done
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'syncevolution/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "syncevolution"
8
+ spec.version = SyncEvolution::VERSION
9
+ spec.executables << 'se-config'
10
+ spec.authors = ["Emiliano Heyns"]
11
+ spec.email = ["Emiliano.Heyns@iris-advies.com"]
12
+ spec.description = %q{Manage SyncEvolution configuration}
13
+ spec.summary = %q{Manage SyncEvolution configuration}
14
+ spec.homepage = ""
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files`.split($/)
18
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
19
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency 'nokogiri'
23
+ spec.add_dependency 'inifile'
24
+ spec.add_dependency 'trollop'
25
+
26
+ spec.add_development_dependency "bundler", "~> 1.3"
27
+ spec.add_development_dependency "rake"
28
+ end
@@ -0,0 +1,10 @@
1
+ require 'test/unit'
2
+ require 'syncevolution'
3
+
4
+ class TALTest < Test::Unit::TestCase
5
+ def test_basics
6
+ assert_equal "$".to_latex, '{\\textdollar}'
7
+ assert_equal "\u0027".to_latex, "'"
8
+ assert_equal "\u00D6".to_latex, '\"{O}'
9
+ end
10
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: syncevolution
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Emiliano Heyns
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: nokogiri
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: inifile
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: trollop
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '1.3'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ description: Manage SyncEvolution configuration
84
+ email:
85
+ - Emiliano.Heyns@iris-advies.com
86
+ executables:
87
+ - se-config
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - Gemfile
93
+ - LICENSE.txt
94
+ - README.md
95
+ - Rakefile
96
+ - bin/se-config
97
+ - lib/syncevolution/version.rb
98
+ - publish.sh
99
+ - syncevolution.gemspec
100
+ - test/syncevolution.rb
101
+ homepage: ''
102
+ licenses:
103
+ - MIT
104
+ metadata: {}
105
+ post_install_message:
106
+ rdoc_options: []
107
+ require_paths:
108
+ - lib
109
+ required_ruby_version: !ruby/object:Gem::Requirement
110
+ requirements:
111
+ - - ">="
112
+ - !ruby/object:Gem::Version
113
+ version: '0'
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ requirements: []
120
+ rubyforge_project:
121
+ rubygems_version: 2.2.2
122
+ signing_key:
123
+ specification_version: 4
124
+ summary: Manage SyncEvolution configuration
125
+ test_files:
126
+ - test/syncevolution.rb