chronicle-etl 0.1.1 → 0.2.1

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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/.ruby-version +1 -0
  4. data/.yardopts +1 -0
  5. data/CHANGELOG.md +23 -0
  6. data/Gemfile.lock +42 -10
  7. data/README.md +64 -11
  8. data/bin/console +16 -4
  9. data/chronicle-etl.gemspec +9 -7
  10. data/exe/chronicle-etl +2 -2
  11. data/lib/chronicle/etl.rb +5 -2
  12. data/lib/chronicle/etl/catalog.rb +62 -0
  13. data/lib/chronicle/etl/cli/connectors.rb +32 -0
  14. data/lib/chronicle/etl/cli/jobs.rb +111 -0
  15. data/lib/chronicle/etl/cli/main.rb +83 -0
  16. data/lib/chronicle/etl/cli/subcommand_base.rb +37 -0
  17. data/lib/chronicle/etl/config.rb +32 -0
  18. data/lib/chronicle/etl/extractors/{csv.rb → csv_extractor.rb} +3 -3
  19. data/lib/chronicle/etl/extractors/extractor.rb +23 -12
  20. data/lib/chronicle/etl/extractors/file_extractor.rb +52 -0
  21. data/lib/chronicle/etl/extractors/stdin_extractor.rb +11 -0
  22. data/lib/chronicle/etl/loaders/csv_loader.rb +29 -0
  23. data/lib/chronicle/etl/loaders/loader.rb +23 -16
  24. data/lib/chronicle/etl/loaders/rest_loader.rb +30 -0
  25. data/lib/chronicle/etl/loaders/stdout_loader.rb +9 -0
  26. data/lib/chronicle/etl/loaders/table_loader.rb +21 -0
  27. data/lib/chronicle/etl/runner.rb +33 -11
  28. data/lib/chronicle/etl/transformers/json_transformer.rb +11 -0
  29. data/lib/chronicle/etl/transformers/null_transformer.rb +10 -0
  30. data/lib/chronicle/etl/transformers/transformer.rb +27 -11
  31. data/lib/chronicle/etl/utils/progress_bar.rb +76 -0
  32. data/lib/chronicle/etl/version.rb +2 -2
  33. metadata +69 -30
  34. data/lib/chronicle/etl/cli.rb +0 -38
  35. data/lib/chronicle/etl/extractors/stdin.rb +0 -13
  36. data/lib/chronicle/etl/loaders/csv.rb +0 -31
  37. data/lib/chronicle/etl/loaders/stdout.rb +0 -11
  38. data/lib/chronicle/etl/loaders/table.rb +0 -22
  39. data/lib/chronicle/etl/transformers/json.rb +0 -13
  40. data/lib/chronicle/etl/transformers/null.rb +0 -11
  41. data/lib/chronicle/etl/utils/progress_bar_wrapper.rb +0 -43
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f364392d44aab353504c3daeb62c9e19b9a3bbc8c0e7d7efc0e3324457bb2921
4
- data.tar.gz: e79ba859fa67c6ddb2e7112fe213a23a4e0d692063aab9a8f9e86fd970e2b44c
3
+ metadata.gz: 3d9be4b073385d9758a8b709bb6726d8dae648b8c4dbef474343840c011d1178
4
+ data.tar.gz: 0d95395407d37f7e322287a0920bba60e1b4f81eb8649190d021e13580604a2d
5
5
  SHA512:
6
- metadata.gz: a0f0cbae079c6f1afef6b0b4f67cbfdd28b041b3247457913f6a07dfb6a21aef185286002d869293f1984b7c9806d57a788c58e9d92c2f7ae05ed61c7322633c
7
- data.tar.gz: c36e3c54539540406e5dcde64ac4b3ceccc070b4f81639ae337dccdcf6b1dc0f193966ce02291a568be22f8ffb0207225a5598f8f2e11d0790e3b130ff92815c
6
+ metadata.gz: 386c96518aa2d2810ae2a93bbe3af5bb08e26e132608b4e6ed8a278da076783e453854a2120c5016b6d02cd5dea406146d10ef3c7c1e77d854acd8ff2608eaf7
7
+ data.tar.gz: eb14402be5d6db44a6f06e6ec930acc5103b36e5c2e5a13e89137c9ee45f5f11c1e9e6ab13d4d44e6ee06bd9b02309e02ac33e81256645ef71d5b431c97eb199
@@ -0,0 +1,8 @@
1
+ AllCops:
2
+ EnabledByDefault: true
3
+
4
+ Style/StringLiterals:
5
+ Enabled: false
6
+
7
+ Style/MethodCallWithArgsParentheses:
8
+ Enabled: false
@@ -0,0 +1 @@
1
+ 2.7.1
@@ -0,0 +1 @@
1
+ --markup=markdown
@@ -0,0 +1,23 @@
1
+ # Changelog
2
+
3
+ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
4
+
5
+ ## [0.1.4] - 2020-08-18
6
+ ### Updated
7
+ - Better display of available ETL classes
8
+ - Updated documentation
9
+
10
+ ## [0.1.3] - 2020-08-13
11
+ ### Added
12
+ - Ability to list all available ETL classes
13
+ - Refactored E, T, L module and class structure
14
+ - Better progress bar
15
+
16
+ ## [0.1.2] - 2020-08-02
17
+ ### Added
18
+ - This changelog
19
+ - Ability to use extractors, transformers, and loaders from other gems
20
+
21
+ ## [0.1.0] - 2020-08-01
22
+ ### Added
23
+ - Basic job runner and ETL classes
@@ -1,11 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- chronicle-etl (0.1.1)
4
+ chronicle-etl (0.2.1)
5
5
  colorize (~> 0.8.1)
6
- ruby-progressbar (~> 1.10)
7
- table_print
8
6
  thor (~> 0.20)
7
+ tty-progressbar (~> 0.17)
8
+ tty-table (~> 0.11)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
@@ -14,14 +14,21 @@ GEM
14
14
  coderay (1.1.3)
15
15
  colorize (0.8.1)
16
16
  diff-lcs (1.4.4)
17
+ equatable (0.6.1)
17
18
  method_source (1.0.0)
19
+ necromancer (0.6.0)
20
+ pastel (0.7.4)
21
+ equatable (~> 0.6)
22
+ tty-color (~> 0.5)
18
23
  pry (0.13.1)
19
24
  coderay (~> 1.1)
20
25
  method_source (~> 1.0)
21
26
  pry-byebug (3.9.0)
22
27
  byebug (~> 11.0)
23
28
  pry (~> 0.13.0)
24
- rake (10.5.0)
29
+ rake (13.0.1)
30
+ redcarpet (3.5.0)
31
+ refinements (7.7.0)
25
32
  rspec (3.9.0)
26
33
  rspec-core (~> 3.9.0)
27
34
  rspec-expectations (~> 3.9.0)
@@ -35,19 +42,44 @@ GEM
35
42
  diff-lcs (>= 1.2.0, < 2.0)
36
43
  rspec-support (~> 3.9.0)
37
44
  rspec-support (3.9.3)
38
- ruby-progressbar (1.10.1)
39
- table_print (1.5.7)
45
+ runcom (6.2.0)
46
+ refinements (~> 7.4)
47
+ xdg (~> 4.0)
48
+ strings (0.1.8)
49
+ strings-ansi (~> 0.1)
50
+ unicode-display_width (~> 1.5)
51
+ unicode_utils (~> 1.4)
52
+ strings-ansi (0.1.0)
40
53
  thor (0.20.3)
54
+ tty-color (0.5.2)
55
+ tty-cursor (0.7.1)
56
+ tty-progressbar (0.17.0)
57
+ strings-ansi (~> 0.1.0)
58
+ tty-cursor (~> 0.7)
59
+ tty-screen (~> 0.7)
60
+ unicode-display_width (~> 1.6)
61
+ tty-screen (0.8.1)
62
+ tty-table (0.11.0)
63
+ equatable (~> 0.6)
64
+ necromancer (~> 0.5)
65
+ pastel (~> 0.7.2)
66
+ strings (~> 0.1.5)
67
+ tty-screen (~> 0.7)
68
+ unicode-display_width (1.7.0)
69
+ unicode_utils (1.4.0)
70
+ xdg (4.2.0)
41
71
 
42
72
  PLATFORMS
43
73
  ruby
44
74
 
45
75
  DEPENDENCIES
46
- bundler (~> 1.17)
76
+ bundler (~> 2.1)
47
77
  chronicle-etl!
48
78
  pry-byebug (~> 3.9)
49
- rake (~> 10.0)
50
- rspec (~> 3.0)
79
+ rake (~> 13.0)
80
+ redcarpet (~> 3.5)
81
+ rspec (~> 3.9)
82
+ runcom (~> 6.2)
51
83
 
52
84
  BUNDLED WITH
53
- 1.17.2
85
+ 2.1.4
data/README.md CHANGED
@@ -1,6 +1,10 @@
1
- # Chronicle::Etl
1
+ # Chronicle::ETL
2
2
 
3
- Chronicle ETL is a utility tool for manipulating personal data. You can extract it from a variety of source, transform it, and load it to different APIs or file formats.
3
+ [![Gem Version](https://badge.fury.io/rb/chronicle-etl.svg)](https://badge.fury.io/rb/chronicle-etl)
4
+
5
+ Chronicle ETL is a utility tool for archiving and processing personal data. You can extract it from a variety of source, transform it, and load it to different APIs or file formats.
6
+
7
+ This project is an adaptation of Andrew Louis's experimental [Memex project](https://hyfen.net/memex).
4
8
 
5
9
  ## Installation
6
10
 
@@ -8,28 +12,77 @@ Chronicle ETL is a utility tool for manipulating personal data. You can extract
8
12
  $ gem install chronicle-etl
9
13
  ```
10
14
 
11
- ## Examples
15
+ ## Usage
12
16
 
13
17
  After installing the gem, `chronicle-etl` is available to run in your shell.
14
18
 
19
+ ```bash
20
+ # read test.csv and display it as a table
21
+ $ chronicle-etl jobs:run --extractor csv --extractor-opts filename:test.csv --loader table
22
+
23
+ # Display help for the jobs:run command
24
+ $ chronicle-etl jobs help run
15
25
  ```
16
- chronicle-etl --extractor csv --extractor-opts filename:test.csv --loader table
17
- cat test.csv | chronicle-etl --extractor csv --loader table
26
+
27
+ ## Connectors
28
+
29
+ Connectors are available to read, process, and load data from different formats or external services.
30
+
31
+ ```bash
32
+ # List all available connectors
33
+ $ chronicle-etl connectors:list
18
34
  ```
19
35
 
20
- ## Full usage
36
+ Built in connectors:
37
+
38
+ ### Extractors
39
+ - `stdin` - (default) Load records from line-separated stdin
40
+ - `csv`
41
+ - `file` - load from a single file or directory (with a glob pattern)
42
+
43
+ ### Transformers
44
+ - `null` - (default) Don't do anything
45
+
46
+ ### Loaders
47
+ - `stdout` - (default) output transformed records to stdount
48
+ - `csv` - Load records to a csv file
49
+ - `table` - Output an ascii table of records. Useful for debugging.
50
+
51
+ ### Provider-specific importers
52
+
53
+ In addition to the built-in importers, importers for third-party platforms are available. They are packaged as individual Ruby gems.
54
+
55
+ - [email](https://github.com/chronicle-app/chronicle-email). Extractors for `mbox` files. Transformers for chronicle schema
56
+ - [bash](https://github.com/chronicle-app/chronicle-bash). Extract bash history from `~/.bash_history`. Transform it for chronicle schema
57
+
58
+ To install any of these, run `gem install chronicle-PROVIDER`.
59
+
60
+ If you don't want to use the available rubygem importers, `chronicle-etl` can use `stdin` as an Extractor source (newline separated records). You can also use `stdout` as a loader — transformed records will be outputted separated by newlines.
61
+
62
+ I'll be open-sourcing more importers. Please [contact me](mailto:andrew@hyfen.net) to chat about what will be available!
63
+
64
+ ### Full commands
21
65
 
22
66
  ```
23
- Commands:
24
- chronicle-etl help [COMMAND] # Describe available commands or one specific command
25
- chronicle-etl job # Runs an ETL job
67
+ $ chronicle-etl help
68
+
69
+ ALL COMMANDS
70
+ help # This help menu
71
+ connectors help [COMMAND] # Describe subcommands or one specific subcommand
72
+ connectors:install NAME # Installs connector NAME
73
+ connectors:list # Lists available connectors
74
+ jobs help [COMMAND] # Describe subcommands or one specific subcommand
75
+ jobs:create # Create a job
76
+ jobs:list # List all available jobs
77
+ jobs:run # Start a job
78
+ jobs:show # Show a job
26
79
  ```
27
80
 
28
81
  ### Job options
29
82
 
30
83
  ```
31
84
  Usage:
32
- chronicle-etl job
85
+ chronicle-etl jobs:run
33
86
 
34
87
  Options:
35
88
  -e, [--extractor=extractor-name] # Extractor class (available: stdin, csv, file)
@@ -62,4 +115,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
62
115
 
63
116
  ## Code of Conduct
64
117
 
65
- Everyone interacting in the Chronicle::Etl project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/chronicle-app/chronicle-etl/blob/master/CODE_OF_CONDUCT.md).
118
+ Everyone interacting in the Chronicle::ETL project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/chronicle-app/chronicle-etl/blob/master/CODE_OF_CONDUCT.md).
@@ -7,8 +7,20 @@ require "chronicle/etl"
7
7
  # with your gem easier. You can also use a different console, if you like.
8
8
 
9
9
  # (If you use this, don't forget to add pry to your Gemfile!)
10
- # require "pry"
11
- # Pry.start
10
+ require "pry"
11
+ Pry.start
12
+
13
+ def reload!(print = true)
14
+ puts 'Reloading ...' if print
15
+ # Main project directory.
16
+ root_dir = File.expand_path('..', __dir__)
17
+ # Directories within the project that should be reloaded.
18
+ reload_dirs = %w{lib}
19
+ # Loop through and reload every file in all relevant project directories.
20
+ reload_dirs.each do |dir|
21
+ Dir.glob("#{root_dir}/#{dir}/**/*.rb").each { |f| load(f) }
22
+ end
23
+ # Return true when complete.
24
+ true
25
+ end
12
26
 
13
- require "irb"
14
- IRB.start(__FILE__)
@@ -5,7 +5,7 @@ require "chronicle/etl/version"
5
5
 
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "chronicle-etl"
8
- spec.version = Chronicle::Etl::VERSION
8
+ spec.version = Chronicle::ETL::VERSION
9
9
  spec.authors = ["Andrew Louis"]
10
10
  spec.email = ["andrew@hyfen.net"]
11
11
 
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
21
21
 
22
22
  spec.metadata["homepage_uri"] = spec.homepage
23
23
  spec.metadata["source_code_uri"] = "https://github.com/chronicle-app/chronicle-etl"
24
- spec.metadata["changelog_uri"] = "https://github.com/chronicle-app/chronicle-etl"
24
+ spec.metadata["changelog_uri"] = "https://github.com/chronicle-app/chronicle-etl/blob/master/CHANGELOG.md"
25
25
  else
26
26
  raise "RubyGems 2.0 or newer is required to protect against " \
27
27
  "public gem pushes."
@@ -38,11 +38,13 @@ Gem::Specification.new do |spec|
38
38
 
39
39
  spec.add_dependency "thor", "~> 0.20"
40
40
  spec.add_dependency "colorize", "~> 0.8.1"
41
- spec.add_dependency "table_print"
42
- spec.add_dependency "ruby-progressbar", "~> 1.10"
41
+ spec.add_dependency "tty-table", "~> 0.11"
42
+ spec.add_dependency "tty-progressbar", "~> 0.17"
43
43
 
44
- spec.add_development_dependency "bundler", "~> 1.17"
45
- spec.add_development_dependency "rake", "~> 10.0"
46
- spec.add_development_dependency "rspec", "~> 3.0"
44
+ spec.add_development_dependency "bundler", "~> 2.1"
45
+ spec.add_development_dependency "rake", "~> 13.0"
46
+ spec.add_development_dependency "rspec", "~> 3.9"
47
47
  spec.add_development_dependency "pry-byebug", "~> 3.9"
48
+ spec.add_development_dependency 'runcom', '~> 6.2'
49
+ spec.add_development_dependency 'redcarpet', '~> 3.5'
48
50
  end
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require "chronicle/etl/cli"
3
+ require "chronicle/etl/cli/main"
4
4
 
5
- Chronicle::Etl::CLI.start(ARGV)
5
+ Chronicle::ETL::CLI::Main.start(ARGV)
@@ -1,5 +1,8 @@
1
+ require_relative 'etl/catalog'
2
+ require_relative 'etl/config'
1
3
  require_relative 'etl/extractors/extractor'
2
- require_relative 'etl/transformers/transformer'
3
4
  require_relative 'etl/loaders/loader'
4
- require_relative 'etl/utils/progress_bar_wrapper'
5
5
  require_relative 'etl/runner'
6
+ require_relative 'etl/transformers/transformer'
7
+ require_relative 'etl/utils/progress_bar'
8
+ require_relative 'etl/version'
@@ -0,0 +1,62 @@
1
+ module Chronicle
2
+ module ETL
3
+ # Utility methods to catalogue which Extractor, Transformer, and
4
+ # Loader connector classes are available to chronicle-etl
5
+ module Catalog
6
+ PLUGINS = ['email', 'bash']
7
+
8
+ # Return which ETL connectors are available, both built in and externally-defined
9
+ def self.available_classes
10
+ # TODO: have a registry of plugins
11
+
12
+ # Attempt to load each chronicle plugin that we might know about so
13
+ # that we can later search for subclasses to build our list of
14
+ # available classes
15
+ PLUGINS.each do |plugin|
16
+ require "chronicle/#{plugin}"
17
+ rescue LoadError
18
+ # this will happen if the gem isn't available globally
19
+ end
20
+
21
+ parent_klasses = [
22
+ ::Chronicle::ETL::Extractor,
23
+ ::Chronicle::ETL::Transformer,
24
+ ::Chronicle::ETL::Loader
25
+ ]
26
+ klasses = []
27
+ parent_klasses.map do |parent|
28
+ klasses += ::ObjectSpace.each_object(::Class).select { |klass| klass < parent }
29
+ end
30
+
31
+ klasses.map do |klass|
32
+ {
33
+ name: klass.name,
34
+ built_in: klass.built_in?,
35
+ provider: klass.provider,
36
+ phase: klass.phase
37
+ }
38
+ end
39
+ end
40
+
41
+ # Returns whether a class is an Extractor, Transformer, or Loader
42
+ def phase
43
+ ancestors = self.ancestors
44
+ return :extractor if ancestors.include? Chronicle::ETL::Extractor
45
+ return :transformer if ancestors.include? Chronicle::ETL::Transformer
46
+ return :loader if ancestors.include? Chronicle::ETL::Loader
47
+ end
48
+
49
+ # Returns which third-party provider this connector is associated wtih
50
+ def provider
51
+ # TODO: needs better convention for a gem reporting its provider name
52
+ provider = to_s.split('::')[1].downcase
53
+ provider == 'etl' ? 'chronicle' : provider
54
+ end
55
+
56
+ # Returns whether this connector is a built-in one
57
+ def built_in?
58
+ to_s.include? 'Chronicle::ETL'
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,32 @@
1
+ module Chronicle
2
+ module ETL
3
+ module CLI
4
+ # CLI commands for working with ETL connectors
5
+ class Connectors < SubcommandBase
6
+ default_task 'list'
7
+ namespace :connectors
8
+
9
+ desc "install NAME", "Installs connector NAME"
10
+ def install
11
+ puts "Installing"
12
+ end
13
+
14
+ desc "list", "Lists available connectors"
15
+ # Display all available connectors that chronicle-etl has access to
16
+ def list
17
+ klasses = Chronicle::ETL::Catalog.available_classes
18
+ klasses = klasses.sort_by do |a|
19
+ [a[:built_in].to_s, a[:provider], a[:phase]]
20
+ end
21
+
22
+ headers = klasses.first.keys.map do |key|
23
+ key.to_s.upcase.bold
24
+ end
25
+
26
+ table = TTY::Table.new(headers, klasses.map(&:values))
27
+ puts table.render(indent: 0, padding: [0, 2])
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,111 @@
1
+ require 'pp'
2
+ require 'pry'
3
+
4
+ module Chronicle
5
+ module ETL
6
+ module CLI
7
+ # CLI commands for working with ETL jobs
8
+ class Jobs < SubcommandBase
9
+ default_task "start"
10
+ namespace :jobs
11
+
12
+ class_option :extractor, aliases: '-e', desc: 'Extractor class (available: stdin, csv, file)', default: 'stdin', banner: 'extractor-name'
13
+ class_option :'extractor-opts', desc: 'Extractor options', type: :hash, default: {}
14
+ class_option :transformer, aliases: '-t', desc: 'Transformer class (available: null)', default: 'null', banner: 'transformer-name'
15
+ class_option :'transformer-opts', desc: 'Transformer options', type: :hash, default: {}
16
+ class_option :loader, aliases: '-l', desc: 'Loader class (available: stdout, csv, table)', default: 'stdout', banner: 'loader-name'
17
+ class_option :'loader-opts', desc: 'Loader options', type: :hash, default: {}
18
+ class_option :job, aliases: '-j', desc: 'Job configuration name (or filename)'
19
+
20
+ map run: :start # Thor doesn't like `run` as a command name
21
+ desc "run", "Start a job"
22
+ long_desc <<-LONG_DESC
23
+ This will run an ETL job. Each job needs three parts:
24
+
25
+ 1. #{'Extractor'.underline}: pulls data from an external source. By default, this is stdout. Other common options including pulling data from an API or reading JSON from a file.
26
+
27
+ 2. #{'Transformer'.underline}: transforms data into a new format. If none is specified, we use the `null` transformer which does nothing to the data.
28
+
29
+ 3. #{'Loader'.underline}: takes that transformed data and loads it externally. This can be an API, flat files, (or by default), stdout.
30
+
31
+ If you do not want to use the command line flags, you can also configure a job with a .yml config file. You can either specify the path to this file or use the filename and place the file in ~/.config/chronicle/etl/jobs/NAME.yml and call it with `--job NAME`
32
+ LONG_DESC
33
+ # Run an ETL job
34
+ def start
35
+ runner_options = build_runner_options(options)
36
+ runner = Chronicle::ETL::Runner.new(runner_options)
37
+ runner.run!
38
+ end
39
+
40
+ desc "create", "Create a job"
41
+ # Create an ETL job
42
+ def create
43
+ runner_options = build_runner_options(options)
44
+ path = File.join('chronicle', 'etl', 'jobs', options[:job])
45
+ Chronicle::ETL::Config.write(path, runner_options)
46
+ end
47
+
48
+ desc "show", "Show details about a job"
49
+ # Show an ETL job
50
+ def show
51
+ runner_options = build_runner_options(options)
52
+ pp runner_options
53
+ end
54
+
55
+ desc "list", "List all available jobs"
56
+ # List available ETL jobs
57
+ def list
58
+ jobs = Chronicle::ETL::Config.jobs
59
+
60
+ job_details = jobs.map do |job|
61
+ r = Chronicle::ETL::Config.load("chronicle/etl/jobs/#{job}.yml")
62
+
63
+ extractor = r[:extractor][:name] if r[:extractor]
64
+ transformer = r[:transformer][:name] if r[:transformer]
65
+ loader = r[:loader][:name] if r[:loader]
66
+
67
+ [job, extractor, transformer, loader]
68
+ end
69
+
70
+ headers = ['name', 'extractor', 'transformer', 'loader'].map{|h| h.upcase.bold }
71
+
72
+ table = TTY::Table.new(headers, job_details)
73
+ puts table.render(indent: 0, padding: [0, 2])
74
+ end
75
+
76
+ private
77
+
78
+ # Create runner options by reading config file and then overwriting with flag options
79
+ def build_runner_options options
80
+ flag_options = process_flag_options(options)
81
+ job_options = load_job(options[:job])
82
+ flag_options.merge(job_options)
83
+ end
84
+
85
+ def load_job job
86
+ yml_config = Chronicle::ETL::Config.load("chronicle/etl/jobs/#{job}.yml")
87
+ # FIXME: use better trick to depely symbolize keys
88
+ JSON.parse(yml_config.to_json, symbolize_names: true)
89
+ end
90
+
91
+ # Takes flag options and turns them into a runner config
92
+ def process_flag_options options
93
+ {
94
+ extractor: {
95
+ name: options[:extractor],
96
+ options: options[:'extractor-opts']
97
+ },
98
+ transformer: {
99
+ name: options[:transformer],
100
+ options: options[:'transformer-opts']
101
+ },
102
+ loader: {
103
+ name: options[:loader],
104
+ options: options[:'loader-opts']
105
+ }
106
+ }
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end