jetel 0.0.6 → 0.0.7
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 +4 -4
- data/.idea/vcs.xml +1 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +14 -0
- data/README.md +9 -1
- data/bin/jetel +0 -2
- data/jetel.gemspec +1 -0
- data/lib/jetel/cli/cli.rb +0 -2
- data/lib/jetel/cli/cmd/config_cmd.rb +0 -4
- data/lib/jetel/cli/cmd/modules_cmd.rb +27 -15
- data/lib/jetel/helpers/general_helper.rb +18 -2
- data/lib/jetel/loaders/pg/pg.rb +81 -0
- data/lib/jetel/loaders/pg/sql/copy.sql.erb +6 -0
- data/lib/jetel/loaders/pg/sql/create_table.sql.erb +12 -0
- data/lib/jetel/loaders/pg/sql/drop_table.sql.erb +2 -0
- data/lib/jetel/loaders/pg/sql/header.sql.erb +2 -0
- data/lib/jetel/loaders/pg/sql/schema.sql.erb +12 -0
- data/lib/jetel/loaders/pg/sql/truncate_table.sql.erb +2 -0
- data/lib/jetel/modules/ip/ip.rb +33 -41
- data/lib/jetel/modules/iso3166/iso3166.rb +15 -14
- data/lib/jetel/modules/module.rb +22 -2
- data/lib/jetel/modules/nga/nga.rb +1037 -1036
- data/lib/jetel/modules/sfpd/sfpd.rb +31 -9
- data/lib/jetel/version.rb +1 -1
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 037ccf5c15decd72caae4f48d65c8d2525483cd2
|
4
|
+
data.tar.gz: 4bbf16791f9c6bbca7bfd52528dd2067e81aa56c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 58f2c194d83231c744c26fc28208812ad099e4accb635a84e4fc25f8091556c63043c862cdee054b88042427315994ea7a3ba5d62d81189055869d05d1c03358
|
7
|
+
data.tar.gz: e922b1cdea6f34d4abcd45fd20aa2a019c48e9a5ee9562ebfe7ceacbfa4a903c22e6a5a972342f3b82b3965cf4aba5167938e0048087d9e1d27e4c67665377be
|
data/.idea/vcs.xml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -3,6 +3,7 @@ PATH
|
|
3
3
|
specs:
|
4
4
|
jetel (0.0.6)
|
5
5
|
activesupport
|
6
|
+
csv2psql
|
6
7
|
gli
|
7
8
|
i18n
|
8
9
|
json_pure
|
@@ -14,6 +15,17 @@ PATH
|
|
14
15
|
terminal-table
|
15
16
|
zip
|
16
17
|
|
18
|
+
PATH
|
19
|
+
remote: /Users/tomaskorcak/dev/csv2psql
|
20
|
+
specs:
|
21
|
+
csv2psql (0.0.15)
|
22
|
+
gli (~> 2.13, >= 2.13.2)
|
23
|
+
json_pure (~> 1.8, >= 1.8.3)
|
24
|
+
lru (~> 0.1, >= 0.1.0)
|
25
|
+
multi_json (~> 1.11, >= 1.11.2)
|
26
|
+
rake (~> 10.4, >= 10.4.2)
|
27
|
+
terminal-table (~> 1.5, >= 1.5.2)
|
28
|
+
|
17
29
|
GEM
|
18
30
|
remote: https://rubygems.org/
|
19
31
|
specs:
|
@@ -42,6 +54,7 @@ GEM
|
|
42
54
|
i18n (0.7.0)
|
43
55
|
json (1.8.3)
|
44
56
|
json_pure (1.8.3)
|
57
|
+
lru (0.1.0)
|
45
58
|
mime-types (2.6.2)
|
46
59
|
mini_portile (0.6.2)
|
47
60
|
minitest (5.8.2)
|
@@ -105,6 +118,7 @@ PLATFORMS
|
|
105
118
|
DEPENDENCIES
|
106
119
|
bundler (~> 1.5)
|
107
120
|
coveralls
|
121
|
+
csv2psql!
|
108
122
|
jetel!
|
109
123
|
rake
|
110
124
|
rspec
|
data/README.md
CHANGED
@@ -49,7 +49,15 @@ COMMANDS
|
|
49
49
|
└── test
|
50
50
|
```
|
51
51
|
|
52
|
-
##
|
52
|
+
## Examples
|
53
|
+
|
54
|
+
**Plays nicely with [csv2psql](https://github.com/korczis/csv2psql)**
|
55
|
+
|
56
|
+
```
|
57
|
+
$ csv2psql convert -t --drop-table --create-table -t afrinic tmp/Ip/afrinic/transformed/delegated-afrinic-latest | psql -h 127.0.0.1 -U jetel
|
58
|
+
|
59
|
+
$ csv2psql convert -t --drop-table --create-table -t apnic tmp/Ip/apnic/transformed/delegated-apnic-latest | psql -h 127.0.0.1 -U jetel
|
60
|
+
```
|
53
61
|
|
54
62
|
### Rake
|
55
63
|
|
data/bin/jetel
CHANGED
data/jetel.gemspec
CHANGED
data/lib/jetel/cli/cli.rb
CHANGED
@@ -2,10 +2,6 @@
|
|
2
2
|
|
3
3
|
require 'terminal-table'
|
4
4
|
|
5
|
-
require_relative '../../version'
|
6
|
-
|
7
|
-
require_relative '../shared'
|
8
|
-
|
9
5
|
require_relative '../../modules/modules'
|
10
6
|
|
11
7
|
MODULES = Jetel::Modules.modules
|
@@ -14,7 +10,14 @@ MODULES_ACTIONS = {
|
|
14
10
|
download: nil,
|
15
11
|
extract: nil,
|
16
12
|
transform: nil,
|
17
|
-
load:
|
13
|
+
load: {
|
14
|
+
params: [{
|
15
|
+
desc: 'Column type',
|
16
|
+
default_value: nil,
|
17
|
+
arg_name: 'column-name=column-type',
|
18
|
+
flag: [:column_type]
|
19
|
+
}]
|
20
|
+
}
|
18
21
|
}
|
19
22
|
|
20
23
|
# Gets module name
|
@@ -32,9 +35,21 @@ end
|
|
32
35
|
# @param action_command [String] Nested command name
|
33
36
|
# @param action_desc [String] Nested command action description
|
34
37
|
# @return [Object] Return value
|
35
|
-
def register_module_action(c,
|
36
|
-
|
37
|
-
|
38
|
+
def register_module_action(c, modul, name, spec, &block)
|
39
|
+
module_name = modul[:name]
|
40
|
+
action_description = spec && spec[:description] || "#{name} #{module_name}"
|
41
|
+
|
42
|
+
params = spec && spec[:params] || []
|
43
|
+
|
44
|
+
|
45
|
+
c.desc(action_description)
|
46
|
+
c.command(name) do |cmd|
|
47
|
+
params.each do |param|
|
48
|
+
param.each do |name, val|
|
49
|
+
cmd.send name, val
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
38
53
|
cmd.action(&block)
|
39
54
|
end
|
40
55
|
end
|
@@ -45,15 +60,12 @@ def register_module(m)
|
|
45
60
|
desc "Module #{module_name}"
|
46
61
|
command(m[:name], m[:class_name]) do |c|
|
47
62
|
module_instance = m[:klass].new
|
48
|
-
module_name = m[:name]
|
49
63
|
|
50
|
-
MODULES_ACTIONS.each do |
|
51
|
-
next unless module_instance.respond_to?(
|
64
|
+
MODULES_ACTIONS.each do |name, spec|
|
65
|
+
next unless module_instance.respond_to?(name)
|
52
66
|
|
53
|
-
|
54
|
-
|
55
|
-
register_module_action(c, m, action_name, action_description) do |global_options, options, args|
|
56
|
-
module_instance.send(k, global_options, options, args)
|
67
|
+
register_module_action(c, m, name, spec) do |global_options, options, args|
|
68
|
+
module_instance.send(name, global_options, options, args)
|
57
69
|
end
|
58
70
|
end
|
59
71
|
end
|
@@ -2,16 +2,19 @@
|
|
2
2
|
|
3
3
|
require_relative '../config/config'
|
4
4
|
|
5
|
+
require_relative '../helpers/helpers'
|
5
6
|
require_relative '../loaders/loaders'
|
6
7
|
|
8
|
+
require 'erb'
|
7
9
|
require 'i18n'
|
10
|
+
require 'ostruct'
|
8
11
|
|
9
12
|
module Jetel
|
10
13
|
module Helper
|
11
14
|
class << self
|
12
15
|
def target_dir(modul, dir, source)
|
13
|
-
klass =
|
14
|
-
source_name =
|
16
|
+
klass = modul.class.name.split('::').last
|
17
|
+
source_name = Helper.sanitize(source[:name])
|
15
18
|
File.join(dir || Config[:DATA_DIRECTORY], klass, source_name)
|
16
19
|
end
|
17
20
|
|
@@ -24,6 +27,19 @@ module Jetel
|
|
24
27
|
|
25
28
|
res[:klass].new(uri)
|
26
29
|
end
|
30
|
+
|
31
|
+
def erb(template, vars)
|
32
|
+
ERB.new(template).result(OpenStruct.new(vars).instance_eval { binding })
|
33
|
+
end
|
34
|
+
|
35
|
+
def erb_template(file, vars)
|
36
|
+
template = File.open(file, 'r').read
|
37
|
+
ERB.new(template).result(OpenStruct.new(vars).instance_eval { binding })
|
38
|
+
end
|
39
|
+
|
40
|
+
def sanitize(str)
|
41
|
+
I18n.transliterate(str).gsub(/[^0-9a-z_\-]/i, '_')
|
42
|
+
end
|
27
43
|
end
|
28
44
|
end
|
29
45
|
end
|
data/lib/jetel/loaders/pg/pg.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
require_relative '../loader'
|
2
2
|
|
3
|
+
require_relative '../../helpers/helpers'
|
4
|
+
|
3
5
|
require 'pg'
|
6
|
+
require 'csv2psql/convert/convert'
|
7
|
+
require 'csv2psql/analyzer/analyzer'
|
4
8
|
|
5
9
|
module Jetel
|
6
10
|
module Loaders
|
@@ -31,6 +35,83 @@ module Jetel
|
|
31
35
|
|
32
36
|
@client = PG.connect(opts)
|
33
37
|
end
|
38
|
+
|
39
|
+
def load(modul, source, file, opts)
|
40
|
+
super
|
41
|
+
|
42
|
+
convert_opts = {
|
43
|
+
:l => 1_000,
|
44
|
+
:skip => 0,
|
45
|
+
:header => true
|
46
|
+
}
|
47
|
+
|
48
|
+
schema_list = Csv2Psql::Convert.generate_schema([file], convert_opts)
|
49
|
+
_file_name, schema = schema_list.first
|
50
|
+
|
51
|
+
return nil if schema.nil?
|
52
|
+
|
53
|
+
analyzer = Csv2Psql::Analyzer.new
|
54
|
+
column_types = (opts['column_type'] && opts['column_type'].split(/[;,]/)) || []
|
55
|
+
column_types.each do |ct|
|
56
|
+
name, type = ct.split('=')
|
57
|
+
|
58
|
+
columns = schema[:columns] || []
|
59
|
+
column = columns.find do |k, v|
|
60
|
+
k.downcase == name
|
61
|
+
end
|
62
|
+
|
63
|
+
analyzer_type = analyzer.analyzers.find do |spec|
|
64
|
+
spec[:class].name.split('::').last.downcase == type.downcase
|
65
|
+
end
|
66
|
+
|
67
|
+
type_val = analyzer_type ? analyzer_type[:class].const_get(:TYPE) : type
|
68
|
+
|
69
|
+
if column
|
70
|
+
columns[column[0]] = {
|
71
|
+
type: type_val.to_sym,
|
72
|
+
null: true
|
73
|
+
}
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
ctx = {
|
78
|
+
:ctx => {
|
79
|
+
:table => Helper.sanitize(source[:name]).downcase,
|
80
|
+
:columns => schema[:columns],
|
81
|
+
:source => source,
|
82
|
+
:module => modul,
|
83
|
+
:file => File.absolute_path(modul.transformed_file(source, opts))
|
84
|
+
}
|
85
|
+
}
|
86
|
+
|
87
|
+
sql = Helper.erb_template(File.expand_path('../sql/schema.sql.erb', __FILE__), ctx)
|
88
|
+
sql.gsub!("\n\n", "\n")
|
89
|
+
puts sql
|
90
|
+
@client.exec(sql)
|
91
|
+
|
92
|
+
sql = Helper.erb_template(File.expand_path('../sql/copy.sql.erb', __FILE__), ctx)
|
93
|
+
sql.gsub!("\n\n", "\n")
|
94
|
+
puts sql
|
95
|
+
@client.exec(sql)
|
96
|
+
|
97
|
+
file = File.open(ctx[:ctx][:file], 'r')
|
98
|
+
while !file.eof?
|
99
|
+
# Add row to copy data
|
100
|
+
@client.put_copy_data(file.readline)
|
101
|
+
end
|
102
|
+
|
103
|
+
# We are done adding copy data
|
104
|
+
@client.put_copy_end
|
105
|
+
|
106
|
+
# Display any error messages
|
107
|
+
while res = @client.get_result
|
108
|
+
if e_message = res.error_message
|
109
|
+
p e_message
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
sql
|
114
|
+
end
|
34
115
|
end
|
35
116
|
end
|
36
117
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
DROP TABLE IF EXISTS "<%= ctx[:table] %>";
|
2
|
+
|
3
|
+
CREATE TABLE "<%= ctx[:table] %>"
|
4
|
+
(
|
5
|
+
<% ctx[:columns].each_with_index do |item, index| %>
|
6
|
+
"<%= Csv2Psql::Generator.sanitize_header(item[0]) %>" <%= item[1][:type].upcase %><% if !item[1][:null] %> NOT NULL<% end %><%= ', ' if index < ctx[:columns].length - 1%>
|
7
|
+
<% end %>
|
8
|
+
)
|
9
|
+
WITH (
|
10
|
+
OIDS=FALSE
|
11
|
+
);
|
12
|
+
|
data/lib/jetel/modules/ip/ip.rb
CHANGED
@@ -10,41 +10,45 @@ require_relative '../../modules/module'
|
|
10
10
|
module Jetel
|
11
11
|
module Modules
|
12
12
|
class Ip < Module
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
13
|
+
class << self
|
14
|
+
def sources
|
15
|
+
[
|
16
|
+
{
|
17
|
+
name: 'afrinic',
|
18
|
+
url: 'ftp://ftp.afrinic.net/pub/stats/afrinic/delegated-afrinic-latest'
|
19
|
+
},
|
20
|
+
{
|
21
|
+
name: 'apnic',
|
22
|
+
url: 'ftp://ftp.apnic.net/pub/stats/apnic/delegated-apnic-latest'
|
23
|
+
},
|
24
|
+
{
|
25
|
+
name: 'arin',
|
26
|
+
url: 'ftp://ftp.arin.net/pub/stats/arin/delegated-arin-latest'
|
27
|
+
},
|
28
|
+
{
|
29
|
+
name: 'lacnic',
|
30
|
+
url: 'ftp://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-latest'
|
31
|
+
},
|
32
|
+
{
|
33
|
+
name: 'ripencc',
|
34
|
+
url: 'ftp://ftp.ripe.net/ripe/stats/delegated-ripencc-latest'
|
35
|
+
},
|
36
|
+
{
|
37
|
+
name: 'iana',
|
38
|
+
url: 'ftp://ftp.apnic.net/pub/stats/iana/delegated-iana-latest'
|
39
|
+
}
|
40
|
+
]
|
41
|
+
end
|
42
|
+
end
|
39
43
|
|
40
44
|
def download(global_options, options, args)
|
41
|
-
|
45
|
+
self.class.sources.pmap do |source|
|
42
46
|
download_source(source, global_options.merge(options))
|
43
47
|
end
|
44
48
|
end
|
45
49
|
|
46
50
|
def extract(global_options, options, args)
|
47
|
-
|
51
|
+
self.class.sources.pmap do |source|
|
48
52
|
downloaded_file = downloaded_file(source, global_options.merge(options))
|
49
53
|
dest_dir = extract_dir(source, global_options.merge(options))
|
50
54
|
|
@@ -56,7 +60,7 @@ module Jetel
|
|
56
60
|
end
|
57
61
|
|
58
62
|
def transform(global_options, options, args)
|
59
|
-
|
63
|
+
self.class.sources.pmap do |source|
|
60
64
|
opts = global_options.merge(options)
|
61
65
|
|
62
66
|
extracted_file = extracted_file(source, opts)
|
@@ -89,18 +93,6 @@ module Jetel
|
|
89
93
|
end
|
90
94
|
end
|
91
95
|
end
|
92
|
-
|
93
|
-
def load(global_options, options, args)
|
94
|
-
SOURCES.map do |source|
|
95
|
-
opts = global_options.merge(options)
|
96
|
-
|
97
|
-
transformed_file = transformed_file(source, opts)
|
98
|
-
|
99
|
-
loader = Helper.get_loader(opts['data_loader'])
|
100
|
-
|
101
|
-
loader.load(self, source, transformed_file, opts)
|
102
|
-
end
|
103
|
-
end
|
104
96
|
end
|
105
97
|
end
|
106
98
|
end
|
@@ -10,23 +10,27 @@ require_relative '../../modules/module'
|
|
10
10
|
module Jetel
|
11
11
|
module Modules
|
12
12
|
class Iso3166 < Module
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
13
|
+
class << self
|
14
|
+
def sources
|
15
|
+
[
|
16
|
+
{
|
17
|
+
name: 'iso366',
|
18
|
+
filename_extracted: 'IP2LOCATION-ISO3166-2.CSV',
|
19
|
+
filename_transformed: 'IP2LOCATION-ISO3166-2.CSV',
|
20
|
+
url: 'http://www.ip2location.com/downloads/Hi3sL9bnXfe/IP2LOCATION-ISO3166-2.ZIP'
|
21
|
+
}
|
22
|
+
]
|
23
|
+
end
|
24
|
+
end
|
21
25
|
|
22
26
|
def download(global_options, options, args)
|
23
|
-
|
27
|
+
self.class.sources.pmap do |source|
|
24
28
|
download_source(source, global_options.merge(options))
|
25
29
|
end
|
26
30
|
end
|
27
31
|
|
28
32
|
def extract(global_options, options, args)
|
29
|
-
|
33
|
+
self.class.sources.pmap do |source|
|
30
34
|
downloaded_file = downloaded_file(source, global_options.merge(options))
|
31
35
|
dest_dir = extract_dir(source, global_options.merge(options))
|
32
36
|
|
@@ -46,7 +50,7 @@ module Jetel
|
|
46
50
|
end
|
47
51
|
|
48
52
|
def transform(global_options, options, args)
|
49
|
-
|
53
|
+
self.class.sources.pmap do |source|
|
50
54
|
opts = global_options.merge(options)
|
51
55
|
|
52
56
|
extracted_file = extracted_file(source, opts)
|
@@ -74,9 +78,6 @@ module Jetel
|
|
74
78
|
end
|
75
79
|
end
|
76
80
|
end
|
77
|
-
|
78
|
-
def load(global_options, options, args)
|
79
|
-
end
|
80
81
|
end
|
81
82
|
end
|
82
83
|
end
|
data/lib/jetel/modules/module.rb
CHANGED
@@ -10,8 +10,8 @@ module Jetel
|
|
10
10
|
|
11
11
|
class << self
|
12
12
|
def target_dir(modul, source, dir, *path)
|
13
|
-
klass =
|
14
|
-
source_name =
|
13
|
+
klass = modul.class.name.split('::').last
|
14
|
+
source_name = Helper.sanitize(source[:name])
|
15
15
|
File.join(dir.kind_of?(String) ? dir : dir['download_dir'] || Config[:DATA_DIRECTORY], klass, source_name, path)
|
16
16
|
end
|
17
17
|
|
@@ -75,6 +75,26 @@ module Jetel
|
|
75
75
|
def transformed_file(source, opts)
|
76
76
|
Module.transformed_file(self, source, opts)
|
77
77
|
end
|
78
|
+
|
79
|
+
def load(global_options, options, args)
|
80
|
+
sources = self.class.sources
|
81
|
+
if args.length > 0
|
82
|
+
args = args.map(&:downcase)
|
83
|
+
sources = sources.select do |source|
|
84
|
+
args.index(source[:name].downcase)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
sources.pmap(8) do |source|
|
89
|
+
opts = global_options.merge(options)
|
90
|
+
|
91
|
+
transformed_file = transformed_file(source, opts)
|
92
|
+
|
93
|
+
loader = Helper.get_loader(opts['data_loader'])
|
94
|
+
|
95
|
+
loader.load(self, source, transformed_file, opts)
|
96
|
+
end
|
97
|
+
end
|
78
98
|
end
|
79
99
|
end
|
80
100
|
end
|