sqlite2dbf 0.1.8 → 0.2

Sign up to get free protection for your applications and to get access to all the features.
data/lib/sqlite2dbf.rb CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env ruby
2
1
  #encoding: UTF-8
3
2
  =begin
4
3
  /***************************************************************************
@@ -24,140 +23,168 @@
24
23
 
25
24
  require_relative 'file_checking'
26
25
  require_relative 'logging'
26
+ require_relative 'configuration'
27
+ require_relative 'mapping'
27
28
  require 'shp'
28
29
  require 'sqlite3'
29
30
  require_relative 'argparser'
30
31
 
31
32
  =begin
32
- The main program class. Does it.
33
+ The main program class. Does it.
33
34
  =end
34
35
 
35
36
  class SQLite2DBF
36
- include Logging
37
- include Translating
38
-
39
- def initialize(*args)
40
- options = ArgParser::parse(args)
41
- init_logger
42
- level = (options.debug ? Logger::DEBUG : @log.level)
43
- @log.level = level
44
- @log.debug('options are: ' << options.to_s)
45
-
46
- @date_fields = options.datetime ? options.datetime : []
47
- @time_fields = options.time ? options.time : []
48
-
49
- if(options.source)
50
- @dbf_path = nil
51
- sqlite_file = options.source
52
- dbf_file = options.target if options.target
53
- if(options.table_name && options.out_dir)
54
- @dbf_path = options.out_dir
55
- dbf_file = :table
56
- end
57
- dbf_file ||= File.dirname(sqlite_file) << File::Separator << File.basename(sqlite_file, '.*')
58
- msg = nil
59
-
60
- if(dbf_file != :table)
61
- if(File.exist?(dbf_file))
62
- msg = File_Checking.file_check(dbf_file, :file, :writable)
63
- elsif(File.exist?(File.dirname(dbf_file)))
64
- msg = File_Checking.file_check(File.dirname(dbf_file), :directory, :writable)
65
- end
66
- end
67
-
68
- msg ||= File_Checking.file_check(sqlite_file, :exist, :readable, :file)
69
-
70
- if(!msg)
71
- @log.debug('will transform ' << sqlite_file << ' to ' << dbf_file.to_s << '.dbf')
72
- transform(sqlite_file, dbf_file)
73
- else
74
- msg = trl("ERROR! Unsuitable file") << " : %s" %msg
75
- @log.error(msg)
76
- exit false
77
- end
78
- else
79
- puts trl("ERROR! Source-file is a mandatory program parameter!")
80
- puts trl("Start this program with parameter -h or --help to see the usage-message.")
81
- end
82
-
83
- end
84
-
85
- private
86
-
87
- def transform(sqlite_file, dbf_file)
88
- # <------------ mapping SQLite-types to SHP/XBase ------------>
89
- tmap = {'INT' => 1, 'TINYINT' => 1, 'SMALLINT' => 1, 'MEDIUMINT' => 1, 'BIGINT' => 1, 'UNSIGNED BIGINT' => 1, 'VARCHAR' => 0, 'CHARACTER' => 0, 'VARYING CHARACTER' => 0, 'LONGVARCHAR' => 0, 'TEXT' => 0, 'BLOB' => 0, 'INTEGER' => 1, 'FLOAT' => 2, 'REAL' => 2, 'DOUBLE' => 2}
90
- # -----------> in a way ... <--------------
91
-
92
- begin
93
- SQLite3::Database.new(sqlite_file) do |db|
94
- table_names = db.execute('select name from sqlite_master WHERE type="table"')
95
- @log.debug('sqlite contains ' << table_names.size.to_s << ' table(s): ' << table_names.join(', '))
96
- table_names.each_with_index do |tn, num|
97
- tname = tn.join
98
- table_info = db.table_info(tname)
99
- @log.debug(tn[0] << ': ' << table_info.join)
100
- content = db.execute('select * from ' << tname )
101
- if(:table == dbf_file)
102
- dbf_name = @dbf_path << File::Separator << tname << (content.empty? ? '_empty' : '')<< '.dbf'
103
- else
104
- dbf_name = dbf_file.dup << num.to_s << (content.empty? ? '_empty' : '')<< '.dbf'
105
- end
106
- @log.debug('dbf will be ' << dbf_name)
107
- dbt = SHP::DBF.create(dbf_name)
108
- table_info.each_with_index do |field, index|
109
- ftype = 0
110
- field_name = field['name']
111
- if( !@date_fields.include?(field_name) && !@time_fields.include?(field_name) )
112
- @log.debug('field is ' << field.to_s)
113
- # -----> determine the simple dbf data-type that has to do. <----
114
- type_mapping = tmap.detect{|key, value| field['type'].upcase.start_with?(key) }
115
- @log.debug('type_mapping is ' << type_mapping.to_s)
116
- ftype = type_mapping[1] if type_mapping && type_mapping.respond_to?(:to_ary)
117
- # <---- Yes. I know. ---->
118
- end
119
-
120
- dbt.add_field(field_name, ftype, 200, 0)
121
- end
122
-
123
- content.each_with_index do |row, record_no|
124
- @log.debug('row is ' << row.to_s)
125
- row.each_with_index do |svalue, field_index|
126
- sql_type = table_info[field_index]['type']
127
- field_name = table_info[field_index]['name']
128
- @log.debug('field is ' << field_name << ', svalue is ' << svalue.to_s << ', type is ' << sql_type)
129
- if(svalue && !svalue.to_s.empty?)
130
- if( @date_fields.include?(field_name) )
131
- conv_date = db.execute("select strftime('%Y-%m-%d %H:%M:%S', " << svalue.to_s << ", 'unixepoch')").join
132
- @log.debug('conv_date is ' << conv_date)
133
- dbt.write_string_attribute(record_no, field_index, conv_date)
134
- elsif( @time_fields.include?(field_name) )
135
- conv_time = db.execute("select strftime('%s', " << svalue.to_s << ", 'unixepoch')").join
136
- @log.debug('conv_time is ' << conv_time)
137
- dbt.write_string_attribute(record_no, field_index, conv_time)
138
-
139
- else
140
- type_mapping = tmap.detect{|key, value| sql_type.upcase.start_with?(key) }
141
- ftype = type_mapping[1] if type_mapping && type_mapping.respond_to?(:to_ary)
142
- begin
143
- dbt.write_string_attribute(record_no, field_index, svalue ) if 0 == ftype
144
- dbt.write_integer_attribute(record_no, field_index, svalue) if 1 == ftype
145
- dbt.write_double_attribute(record_no, field_index, svalue) if 2 == ftype
146
- rescue StandardError => ex
147
- @log.error(trl("ERROR! cannot write value of type %s" %sql_type) << ': ' << ex.message )
148
- end
149
- end
150
- else
151
- dbt.write_null_attribute(record_no, field_index) if (!svalue || sql_type.empty?)
152
- end
153
- end
154
- end
155
- dbt.close
156
- end
157
- end
158
- puts trl('DONE. Bye.')
159
- end
160
- rescue SQLite3::Exception => er
161
- @log.error trl("ERROR! Cannot read the source-file") << ' (' << sqlite_file << "): %s" %er.message << '.'
162
- end
37
+ include Logging
38
+ include Translating
39
+
40
+ def initialize(*args)
41
+ options = ArgParser::parse(args)
42
+ @config = Configuration.instance()
43
+ @config.set(options)
44
+
45
+ init_logger
46
+ level = (@config.debug ? Logger::DEBUG : @log.level)
47
+ @log.level = level
48
+
49
+ @date_fields = @config.date ? @config.date : []
50
+ @time_fields = @config.time ? @config.time : []
51
+
52
+ if(@config.source)
53
+ @dbf_path = nil
54
+ sqlite_file = @config.source
55
+
56
+ msg = File_Checking::file_check(sqlite_file, :exist, :readable)
57
+ if msg
58
+ @log.error(trl("ERROR! Cannot read the source-file" ) << ": " << msg)
59
+ exit false
60
+ end
61
+
62
+ SQLite3::Database.new(sqlite_file) do |db|
63
+ tables = list(db)
64
+ if(@config.list)
65
+ puts "\n" << trl("Tables in the database") << ":\n\t" << tables.join("\n\t") << "\n\n"
66
+ exit true
67
+ elsif tables.include?(@config.name)
68
+ @mapping = mapping(db)
69
+ else
70
+ @log.error(trl("Verify table-name! %s is not found in the database!") %(@config.name))
71
+ @log.error(trl("Tables are %s") %tables.join(', ') )
72
+
73
+ exit false
74
+ end
75
+
76
+ dbf_file = @config.target if @config.target
77
+ if(@config.out)
78
+ dbf_file = @config.out << File::Separator << @config.name
79
+ end
80
+ dbf_file ||= File.dirname(sqlite_file) << File::Separator << File.basename(sqlite_file, '.*')
81
+
82
+ msg = nil
83
+
84
+ if(File.exist?(dbf_file))
85
+ msg = File_Checking.file_check(dbf_file, :file, :writable)
86
+ elsif(File.exist?(File.dirname(dbf_file)))
87
+ msg = File_Checking.file_check(File.dirname(dbf_file), :directory, :writable)
88
+ end
89
+
90
+ if(!msg)
91
+ @log.debug('will transform ' << sqlite_file << ' to ' << dbf_file.to_s << '.dbf')
92
+ transform(db, dbf_file)
93
+ else
94
+ msg = trl("ERROR! Unsuitable file") << " : %s" %msg
95
+ @log.error(msg)
96
+ exit false
97
+ end
98
+ end
99
+ else
100
+ log.error trl("ERROR! Source-file is a mandatory program parameter!")
101
+ log.error trl("Start this program with parameter -h or --help to see the usage-message.")
102
+ end
103
+
104
+ end
105
+
106
+ private
107
+
108
+ # Create a list of table-names from SQLite
109
+ def list(db)
110
+ table_names = []
111
+ table_names = db.execute('select name from sqlite_master WHERE type="table"').map {|tn| tn[0]}
112
+ @log.debug('sqlite contains ' << table_names.size.to_s << ' table(s): ' << table_names.join(', '))
113
+ return table_names
114
+ end
115
+
116
+ def mapping(db)
117
+ return Mapping.new(@config, db.table_info(@config.name), db.execute('select * from ' << @config.name ) )
118
+ end
119
+
120
+ def create_base(dbase)
121
+ @log.debug('creating fields')
122
+ @mapping.each do |field|
123
+ dbase.add_field(field.name, field.type, 200, 0)
124
+ end
125
+ end
126
+
127
+ def date(db, value)
128
+ dbf_value = db.execute("select strftime('%Y-%m-%d %H:%M:%S', " << value.to_s << ", 'unixepoch')").join
129
+ @log.warn(trl("ATTN! SQLite2DBF cannot convert the date-value %s into DBF-compatible format.") %value.to_s) if dbf_value.start_with?('-')
130
+ dbf_value = db.execute("select strftime('%s', " << value.to_s << ")").join if dbf_value.start_with?('-')
131
+ end
132
+
133
+ def time(db, value)
134
+ db.execute("select strftime('%s', " << value.to_s << ", 'unixepoch')").join
135
+ end
136
+
137
+
138
+
139
+ def transform(db, dbf_file)
140
+
141
+ begin
142
+ tname = @config.name
143
+ table_info = db.table_info(tname)
144
+ content = db.execute('select * from ' << tname )
145
+ @log.debug('have content')
146
+
147
+ if(:table == dbf_file)
148
+ dbf_file = @dbf_path << File::Separator << tname << (content.empty? ? '_empty' : '')<< '.dbf'
149
+ end
150
+ @log.debug('dbf will be ' << dbf_file)
151
+ dbase = SHP::DBF.create(dbf_file)
152
+
153
+ create_base(dbase)
154
+
155
+ content.each_with_index do |row, record_no|
156
+ @log.debug('row is ' << row.to_s)
157
+
158
+ row.each_with_index do |svalue, field_index|
159
+ @log.debug('object is ' << @mapping[field_index].to_s)
160
+ dbf_type = @mapping[field_index].type
161
+ field_name = @mapping[field_index].name
162
+
163
+ if(svalue && !svalue.to_s.empty? && dbf_type)
164
+ svalue = date(db, svalue) if @date_fields.include?(field_name)
165
+ svalue = date(db, svalue) if @time_fields.include?(field_name)
166
+
167
+ @log.debug('field is ' << field_name << ', svalue is ' << svalue.to_s << ', type is ' << dbf_type.to_s)
168
+ begin
169
+ case dbf_type
170
+ when 0
171
+ dbase.write_string_attribute(record_no, field_index, svalue )
172
+ when 1
173
+ dbase.write_integer_attribute(record_no, field_index, svalue)
174
+ when 2
175
+ dbase.write_double_attribute(record_no, field_index, svalue)
176
+ else
177
+ dbase.write_null_attribute(record_no, field_index)
178
+ end
179
+ rescue StandardError => ex
180
+ @log.warn(trl("ATTN! Field %s - Cannot write value of type %s") %[field_name, dbf_type] << ': ' << ex.message )
181
+ end
182
+ end
183
+ end
184
+ end
185
+ puts trl('DONE. Bye.')
186
+ rescue SQLite3::Exception => er
187
+ @log.error trl("ERROR! Cannot read the source-file") << ' (' << db.filename << "): %s" %er.message << '.'
188
+ end
189
+ end
163
190
  end
data/lib/translating.rb CHANGED
@@ -26,6 +26,7 @@ RD = File.expand_path(File.dirname(__FILE__) ) + File::SEPARATOR if !defined?(R
26
26
 
27
27
  require 'yaml'
28
28
  require_relative 'file_checking'
29
+ require_relative 'logging'
29
30
 
30
31
 
31
32
  =begin
@@ -33,59 +34,62 @@ require_relative 'file_checking'
33
34
  Translations are read from a file "translations" in the program folder.
34
35
  =end
35
36
  module Translating
36
- # There are better ways to extend a translated
37
- # string, but I keep the 'wild-card' for
38
- # historical reasons.
39
- @@awild = 'XX'
37
+ self.extend(Logging)
38
+ @@log = init_logger(STDOUT)
39
+ # There are better ways to extend a translated
40
+ # string, but I keep the 'wild-card' for
41
+ # historical reasons.
42
+ @@awild = 'XX'
40
43
 
41
- @@lang = nil
42
- @@lang_file = format("%s%s", RD, 'LANG')
43
- @@tr = YAML::load_file("#{RD}translations")
44
-
45
- # find the current language-setting and return it.
46
- def self.language()
47
- if @@lang == nil
48
- r = ENV['LANG']
49
- if(r)
50
- @@lang = r[0, 2]
51
- elsif( !File_Checking::file_check(@@lang_file, [:exist?, :readable?]) && File::size(@@lang_file) >= 2)
52
- File::open(@@lang_file, 'r') {|f| @@lang = f.readline}
53
- @@lang.chomp!.downcase! if @@lang
54
- end
55
- end
56
- @@lang = 'en' if !@@lang
57
- end
44
+ @@lang = nil
45
+ @@lang_file = format("%s%s", RD, 'LANG')
46
+ @@tr = YAML::load_file("#{RD}translations")
47
+ # find the current language-setting and return it.
48
+ def self.language()
49
+ if @@lang == nil
50
+ r = ENV['LANG']
51
+ if(r)
52
+ @@lang = r[0, 2]
53
+ elsif( !File_Checking::file_check(@@lang_file, [:exist?, :readable?]) && File::size(@@lang_file) >= 2)
54
+ File::open(@@lang_file, 'r') {|f| @@lang = f.readline}
55
+ @@lang.chomp!.downcase! if @@lang
56
+ end
57
+ end
58
+ @@lang = 'en' if !@@lang
59
+ end
58
60
 
59
- # Translate a string to the currently set langage.
60
- # The args parameter may contain replacement-text which
61
- # will appear at the positions indicated by wildcard-characters
62
- # in the original string.
63
- def self.trl(t, *args)
64
- Translating::language()
65
- lt = @@tr[t]
66
- if(lt)
67
- lt = lt[@@lang]
68
- else
69
- # File.open('/tmp/mtf', 'a+') {|f| f << t << "\n"}
70
- puts "\nTRANSLATION MISSING: \"" << t << "\""
71
- end
72
- lt ||= t
73
- if(args && !args.empty?)
74
- i = -1
75
- lt = lt.gsub(@@awild) do |a|
76
- i += 1
77
- args.flatten[i]
78
- end
79
- lt += args[i + 1, args.length].join
80
- end
81
- return lt
82
- end
61
+ # Translate a string to the currently set langage.
62
+ # The args parameter may contain replacement-text which
63
+ # will appear at the positions indicated by wildcard-characters
64
+ # in the original string.
65
+ def self.trl(t, *args)
66
+
67
+ @@log.debug('@tr is ' << @@tr.to_s)
68
+ Translating::language()
69
+ lt = @@tr[t]
70
+ if(lt)
71
+ lt = lt[@@lang]
72
+ else
73
+ # File.open('/tmp/mtf', 'a+') {|f| f << t << "\n"}
74
+ puts "\nTRANSLATION MISSING: \"" << t << "\""
75
+ end
76
+ lt ||= t
77
+ if(args && !args.empty?)
78
+ i = -1
79
+ lt = lt.gsub(@@awild) do |a|
80
+ i += 1
81
+ args.flatten[i]
82
+ end
83
+ lt += args[i + 1, args.length].join
84
+ end
85
+ return lt
86
+ end
83
87
 
84
- # Translate a string to the currently set langage.
85
- # The args parameter may contain replacement-text which
86
- # will appear at the positions indicated by wildcard-characters
87
- # in the original string.
88
- def trl(t, *args )
89
- Translating::trl(t, args)
90
- end
88
+ # Translate a string to the currently set langage.
89
+ # The args parameter may contain replacement-text which
90
+ # will appear at the positions indicated by wildcard-characters
91
+ # in the original string.
92
+ def trl(t, *args )
93
+ Translating::trl(t, args)
94
+ end
91
95
  end