td 0.11.8.2 → 0.11.9
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/ChangeLog +18 -9
 - data/Gemfile +2 -0
 - data/lib/td/command/connector.rb +299 -0
 - data/lib/td/command/job.rb +80 -87
 - data/lib/td/command/list.rb +16 -1
 - data/lib/td/command/runner.rb +1 -0
 - data/lib/td/command/table.rb +15 -4
 - data/lib/td/command/user.rb +1 -1
 - data/lib/td/updater.rb +26 -26
 - data/lib/td/version.rb +1 -1
 - data/spec/td/command/job_spec.rb +208 -12
 - data/spec/td/{command_sched_spec.rb → command/sched_spec.rb} +0 -0
 - data/spec/td/command/table_spec.rb +186 -0
 - data/spec/td/updater_spec.rb +37 -1
 - data/td.gemspec +1 -1
 - metadata +9 -6
 
    
        checksums.yaml
    CHANGED
    
    | 
         @@ -1,7 +1,7 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            ---
         
     | 
| 
       2 
2 
     | 
    
         
             
            SHA1:
         
     | 
| 
       3 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       4 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 3 
     | 
    
         
            +
              metadata.gz: 35121e210f89e8af8d88f3de09c5da1a46f465f5
         
     | 
| 
      
 4 
     | 
    
         
            +
              data.tar.gz: 2ed8a007214c1861d9653ad88a6e204b11959487
         
     | 
| 
       5 
5 
     | 
    
         
             
            SHA512:
         
     | 
| 
       6 
     | 
    
         
            -
              metadata.gz:  
     | 
| 
       7 
     | 
    
         
            -
              data.tar.gz:  
     | 
| 
      
 6 
     | 
    
         
            +
              metadata.gz: e29254a97c4170455119d3d0d11a8c026d05b431f3fe58ad69bbaeb7f6837805fcdbe51fdd91c8ebe3ae6a9c7077f3312cd681a0f865a3bf2eddb43399446be0
         
     | 
| 
      
 7 
     | 
    
         
            +
              data.tar.gz: 908f511b6ed2f6b293cdc809b203a367869607f7fd0d130c5f85919cc5d0462fec372a214c31df2ecde30cde248804c173fb9a5d32136d84f605d5557fc09cb3
         
     | 
    
        data/ChangeLog
    CHANGED
    
    | 
         @@ -1,12 +1,21 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            == 2015- 
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
     | 
    
         
            -
            *  
     | 
| 
       4 
     | 
    
         
            -
             
     | 
| 
       5 
     | 
    
         
            -
             
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
             
     | 
| 
       8 
     | 
    
         
            -
               
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
      
 1 
     | 
    
         
            +
            == 2015-04-17 version 0.11.9
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            * add connector commands.
         
     | 
| 
      
 4 
     | 
    
         
            +
            * add tsv.gz format to export command.
         
     | 
| 
      
 5 
     | 
    
         
            +
            * add --null option to job:show that specifies what character to represent
         
     | 
| 
      
 6 
     | 
    
         
            +
              null value in csv or tsv format. It emits 'null' by default for backward
         
     | 
| 
      
 7 
     | 
    
         
            +
              compatibility but you can specify '--null ""' to use empty string instead
         
     | 
| 
      
 8 
     | 
    
         
            +
              of 'null'.
         
     | 
| 
      
 9 
     | 
    
         
            +
            * fix: remove illegal TAB character at the end of header record. Thanks y-ken!
         
     | 
| 
      
 10 
     | 
    
         
            +
            * fix: do fancy format of numbers in table:list only if format is 'table'.
         
     | 
| 
      
 11 
     | 
    
         
            +
            * fix: job:show to convert NaN to empty String if format is csv or tsv. The
         
     | 
| 
      
 12 
     | 
    
         
            +
              column data NaN, Infinity and -Infinity caused an error if previous
         
     | 
| 
      
 13 
     | 
    
         
            +
              versions.  If json format is specified it still raises an error because JSON
         
     | 
| 
      
 14 
     | 
    
         
            +
              format does not have representation of those values.
         
     | 
| 
      
 15 
     | 
    
         
            +
            * fix: internal cwd handling for auto jar update that caused import:upload to
         
     | 
| 
      
 16 
     | 
    
         
            +
              fail by changing cwd before reading specified file.
         
     | 
| 
      
 17 
     | 
    
         
            +
            * fix: table:list to consider import_only databases. It just skips such
         
     | 
| 
      
 18 
     | 
    
         
            +
              databases and no longer crashes with insufficient permission.
         
     | 
| 
       10 
19 
     | 
    
         | 
| 
       11 
20 
     | 
    
         
             
            == 2015-02-20 version 0.11.8
         
     | 
| 
       12 
21 
     | 
    
         | 
    
        data/Gemfile
    CHANGED
    
    
| 
         @@ -0,0 +1,299 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'td/command/common'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'td/command/job'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'json'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'uri'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'yaml'
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            module TreasureData
         
     | 
| 
      
 8 
     | 
    
         
            +
            module Command
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              def required(opt, value)
         
     | 
| 
      
 11 
     | 
    
         
            +
                if value.nil?
         
     | 
| 
      
 12 
     | 
    
         
            +
                  raise ParameterConfigurationError, "#{opt} option required"
         
     | 
| 
      
 13 
     | 
    
         
            +
                end
         
     | 
| 
      
 14 
     | 
    
         
            +
              end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
              def connector_guess(op)
         
     | 
| 
      
 17 
     | 
    
         
            +
                type = 's3'
         
     | 
| 
      
 18 
     | 
    
         
            +
                id = secret = source = nil
         
     | 
| 
      
 19 
     | 
    
         
            +
                out = 'td-bulkload.yml'
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                op.on('--type[=TYPE]', "connector type; only 's3' is supported") { |s| type = s }
         
     | 
| 
      
 22 
     | 
    
         
            +
                op.on('--access-id ID', "access ID (S3 access key id for type: s3)") { |s| id = s }
         
     | 
| 
      
 23 
     | 
    
         
            +
                op.on('--access-secret SECRET', "access secret (S3 secret access key for type: s3)") { |s| secret = s }
         
     | 
| 
      
 24 
     | 
    
         
            +
                op.on('--source SOURCE', "resource(s) URI to be imported (e.g. https://s3-us-west-1.amazonaws.com/bucketname/path/prefix/to/import/)") { |s| source = s }
         
     | 
| 
      
 25 
     | 
    
         
            +
                op.on('--out FILE_NAME', "configuration file") { |s| out = s }
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                config = op.cmd_parse
         
     | 
| 
      
 28 
     | 
    
         
            +
                if config
         
     | 
| 
      
 29 
     | 
    
         
            +
                  job = prepare_bulkload_job_config(config)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  out ||= config
         
     | 
| 
      
 31 
     | 
    
         
            +
                else
         
     | 
| 
      
 32 
     | 
    
         
            +
                  required('--access-id', id)
         
     | 
| 
      
 33 
     | 
    
         
            +
                  required('--access-secret', secret)
         
     | 
| 
      
 34 
     | 
    
         
            +
                  required('--source', source)
         
     | 
| 
      
 35 
     | 
    
         
            +
                  required('--out', out)
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  uri = URI.parse(source)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  endpoint = uri.host
         
     | 
| 
      
 39 
     | 
    
         
            +
                  path_components = uri.path.scan(/\/[^\/]*/)
         
     | 
| 
      
 40 
     | 
    
         
            +
                  bucket = path_components.shift.sub(/\//, '')
         
     | 
| 
      
 41 
     | 
    
         
            +
                  path_prefix = path_components.join.sub(/\//, '')
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
                  job = API::BulkLoad::BulkLoad.from_hash(
         
     | 
| 
      
 44 
     | 
    
         
            +
                    :config => {
         
     | 
| 
      
 45 
     | 
    
         
            +
                      :type => type,
         
     | 
| 
      
 46 
     | 
    
         
            +
                      :access_key_id => id,
         
     | 
| 
      
 47 
     | 
    
         
            +
                      :secret_access_key => secret,
         
     | 
| 
      
 48 
     | 
    
         
            +
                      :endpoint => endpoint,
         
     | 
| 
      
 49 
     | 
    
         
            +
                      :bucket => bucket,
         
     | 
| 
      
 50 
     | 
    
         
            +
                      :path_prefix => path_prefix,
         
     | 
| 
      
 51 
     | 
    
         
            +
                    }
         
     | 
| 
      
 52 
     | 
    
         
            +
                  ).validate
         
     | 
| 
      
 53 
     | 
    
         
            +
                end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                client = get_client
         
     | 
| 
      
 56 
     | 
    
         
            +
                job = client.bulk_load_guess(job)
         
     | 
| 
      
 57 
     | 
    
         
            +
             
     | 
| 
      
 58 
     | 
    
         
            +
                create_bulkload_job_file_backup(out)
         
     | 
| 
      
 59 
     | 
    
         
            +
                if /\.json\z/ =~ out
         
     | 
| 
      
 60 
     | 
    
         
            +
                  config_str = JSON.pretty_generate(job.to_h)
         
     | 
| 
      
 61 
     | 
    
         
            +
                else
         
     | 
| 
      
 62 
     | 
    
         
            +
                  config_str = YAML.dump(job.to_h)
         
     | 
| 
      
 63 
     | 
    
         
            +
                end
         
     | 
| 
      
 64 
     | 
    
         
            +
                File.open(out, 'w') do |f|
         
     | 
| 
      
 65 
     | 
    
         
            +
                  f << config_str
         
     | 
| 
      
 66 
     | 
    
         
            +
                end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                puts "Created #{out} file."
         
     | 
| 
      
 69 
     | 
    
         
            +
                puts "Use '#{$prog} " + Config.cl_options_string + "connector:preview #{out}' to see bulk load preview."
         
     | 
| 
      
 70 
     | 
    
         
            +
              end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
              def connector_preview(op)
         
     | 
| 
      
 73 
     | 
    
         
            +
                set_render_format_option(op)
         
     | 
| 
      
 74 
     | 
    
         
            +
                config_file = op.cmd_parse
         
     | 
| 
      
 75 
     | 
    
         
            +
                job = prepare_bulkload_job_config(config_file)
         
     | 
| 
      
 76 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 77 
     | 
    
         
            +
                preview = client.bulk_load_preview(job)
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                cols = preview.schema.sort_by { |col|
         
     | 
| 
      
 80 
     | 
    
         
            +
                  col['index']
         
     | 
| 
      
 81 
     | 
    
         
            +
                }
         
     | 
| 
      
 82 
     | 
    
         
            +
                fields = cols.map { |col| col['name'] + ':' + col['type'] }
         
     | 
| 
      
 83 
     | 
    
         
            +
                types = cols.map { |col| col['type'] }
         
     | 
| 
      
 84 
     | 
    
         
            +
                rows = preview.records.map { |row|
         
     | 
| 
      
 85 
     | 
    
         
            +
                  cols = {}
         
     | 
| 
      
 86 
     | 
    
         
            +
                  row.each_with_index do |col, idx|
         
     | 
| 
      
 87 
     | 
    
         
            +
                    cols[fields[idx]] = col.inspect
         
     | 
| 
      
 88 
     | 
    
         
            +
                  end
         
     | 
| 
      
 89 
     | 
    
         
            +
                  cols
         
     | 
| 
      
 90 
     | 
    
         
            +
                } 
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                puts cmd_render_table(rows, :fields => fields, :render_format => op.render_format)
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                puts "Update #{config_file} and use '#{$prog} " + Config.cl_options_string + "connector:preview #{config_file}' to preview again."
         
     | 
| 
      
 95 
     | 
    
         
            +
                puts "Use '#{$prog} " + Config.cl_options_string + "connector:issue #{config_file}' to run Server-side bulk load."
         
     | 
| 
      
 96 
     | 
    
         
            +
              end
         
     | 
| 
      
 97 
     | 
    
         
            +
             
     | 
| 
      
 98 
     | 
    
         
            +
              def connector_issue(op)
         
     | 
| 
      
 99 
     | 
    
         
            +
                database = table = nil
         
     | 
| 
      
 100 
     | 
    
         
            +
                time_column = nil
         
     | 
| 
      
 101 
     | 
    
         
            +
                wait = exclude = false
         
     | 
| 
      
 102 
     | 
    
         
            +
                op.on('--database DB_NAME', "destination database") { |s| database = s }
         
     | 
| 
      
 103 
     | 
    
         
            +
                op.on('--table TABLE_NAME', "destination table") { |s| table = s }
         
     | 
| 
      
 104 
     | 
    
         
            +
                op.on('--time-column COLUMN_NAME', "data partitioning key") { |s| time_column = s }
         
     | 
| 
      
 105 
     | 
    
         
            +
                op.on('-w', '--wait', 'wait for finishing the job', TrueClass) { |b| wait = b }
         
     | 
| 
      
 106 
     | 
    
         
            +
                op.on('-x', '--exclude', 'do not automatically retrieve the job result', TrueClass) { |b| exclude = b }
         
     | 
| 
      
 107 
     | 
    
         
            +
             
     | 
| 
      
 108 
     | 
    
         
            +
                config_file = op.cmd_parse
         
     | 
| 
      
 109 
     | 
    
         
            +
             
     | 
| 
      
 110 
     | 
    
         
            +
                required('--database', database)
         
     | 
| 
      
 111 
     | 
    
         
            +
                required('--table', table)
         
     | 
| 
      
 112 
     | 
    
         
            +
             
     | 
| 
      
 113 
     | 
    
         
            +
                job = prepare_bulkload_job_config(config_file)
         
     | 
| 
      
 114 
     | 
    
         
            +
                job['time_column'] = time_column if time_column
         
     | 
| 
      
 115 
     | 
    
         
            +
             
     | 
| 
      
 116 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 117 
     | 
    
         
            +
                job_id = client.bulk_load_issue(database, table, job)
         
     | 
| 
      
 118 
     | 
    
         
            +
             
     | 
| 
      
 119 
     | 
    
         
            +
                puts "Job #{job_id} is queued."
         
     | 
| 
      
 120 
     | 
    
         
            +
                puts "Use '#{$prog} " + Config.cl_options_string + "job:show #{job_id}' to show the status."
         
     | 
| 
      
 121 
     | 
    
         
            +
             
     | 
| 
      
 122 
     | 
    
         
            +
                if wait
         
     | 
| 
      
 123 
     | 
    
         
            +
                  wait_connector_job(client, job_id, exclude)
         
     | 
| 
      
 124 
     | 
    
         
            +
                end
         
     | 
| 
      
 125 
     | 
    
         
            +
              end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
              def connector_list(op)
         
     | 
| 
      
 128 
     | 
    
         
            +
                set_render_format_option(op)
         
     | 
| 
      
 129 
     | 
    
         
            +
                op.cmd_parse
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 132 
     | 
    
         
            +
                # TODO database and table is empty at present. Fix API or Client.
         
     | 
| 
      
 133 
     | 
    
         
            +
                keys = ['name', 'cron', 'timezone', 'delay', 'database', 'table', 'config']
         
     | 
| 
      
 134 
     | 
    
         
            +
                fields = keys.map { |e| e.capitalize.to_sym }
         
     | 
| 
      
 135 
     | 
    
         
            +
                rows = client.bulk_load_list().sort_by { |e|
         
     | 
| 
      
 136 
     | 
    
         
            +
                  e['name']
         
     | 
| 
      
 137 
     | 
    
         
            +
                }.map { |e|
         
     | 
| 
      
 138 
     | 
    
         
            +
                  Hash[fields.zip(e.to_h.values_at(*keys))]
         
     | 
| 
      
 139 
     | 
    
         
            +
                }
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                puts cmd_render_table(rows, :fields => fields, :render_format => op.render_format)
         
     | 
| 
      
 142 
     | 
    
         
            +
              end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
              def connector_create(op)
         
     | 
| 
      
 145 
     | 
    
         
            +
                # TODO it's a must parameter at this moment but API should be fixed
         
     | 
| 
      
 146 
     | 
    
         
            +
                opts = {:timezone => 'UTC'}
         
     | 
| 
      
 147 
     | 
    
         
            +
                op.on('--time-column COLUMN_NAME', "data partitioning key") {|s|
         
     | 
| 
      
 148 
     | 
    
         
            +
                  opts[:time_column] = s
         
     | 
| 
      
 149 
     | 
    
         
            +
                }
         
     | 
| 
      
 150 
     | 
    
         
            +
                op.on('-t', '--timezone TZ', "name of the timezone.",
         
     | 
| 
      
 151 
     | 
    
         
            +
                                             "  Only extended timezones like 'Asia/Tokyo', 'America/Los_Angeles' are supported,",
         
     | 
| 
      
 152 
     | 
    
         
            +
                                             "  (no 'PST', 'PDT', etc...).",
         
     | 
| 
      
 153 
     | 
    
         
            +
                                             "  When a timezone is specified, the cron schedule is referred to that timezone.",
         
     | 
| 
      
 154 
     | 
    
         
            +
                                             "  Otherwise, the cron schedule is referred to the UTC timezone.",
         
     | 
| 
      
 155 
     | 
    
         
            +
                                             "  E.g. cron schedule '0 12 * * *' will execute daily at 5 AM without timezone option",
         
     | 
| 
      
 156 
     | 
    
         
            +
                                             "  and at 12PM with the -t / --timezone 'America/Los_Angeles' timezone option") {|s|
         
     | 
| 
      
 157 
     | 
    
         
            +
                  opts[:timezone] = s
         
     | 
| 
      
 158 
     | 
    
         
            +
                }
         
     | 
| 
      
 159 
     | 
    
         
            +
                op.on('-D', '--delay SECONDS', 'delay time of the schedule', Integer) {|i|
         
     | 
| 
      
 160 
     | 
    
         
            +
                  opts[:delay] = i
         
     | 
| 
      
 161 
     | 
    
         
            +
                }
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                name, cron, database, table, config_file = op.cmd_parse
         
     | 
| 
      
 164 
     | 
    
         
            +
             
     | 
| 
      
 165 
     | 
    
         
            +
                job = prepare_bulkload_job_config(config_file)
         
     | 
| 
      
 166 
     | 
    
         
            +
                opts[:cron] = cron
         
     | 
| 
      
 167 
     | 
    
         
            +
             
     | 
| 
      
 168 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 169 
     | 
    
         
            +
                get_table(client, database, table)
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                session = client.bulk_load_create(name, database, table, job, opts)
         
     | 
| 
      
 172 
     | 
    
         
            +
                dump_connector_session(session)
         
     | 
| 
      
 173 
     | 
    
         
            +
              end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
              def connector_show(op)
         
     | 
| 
      
 176 
     | 
    
         
            +
                name = op.cmd_parse
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 179 
     | 
    
         
            +
                session = client.bulk_load_show(name)
         
     | 
| 
      
 180 
     | 
    
         
            +
                dump_connector_session(session)
         
     | 
| 
      
 181 
     | 
    
         
            +
              end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
              def connector_update(op)
         
     | 
| 
      
 184 
     | 
    
         
            +
                name, config_file = op.cmd_parse
         
     | 
| 
      
 185 
     | 
    
         
            +
             
     | 
| 
      
 186 
     | 
    
         
            +
                job = prepare_bulkload_job_config(config_file)
         
     | 
| 
      
 187 
     | 
    
         
            +
             
     | 
| 
      
 188 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 189 
     | 
    
         
            +
                session = client.bulk_load_update(name, job)
         
     | 
| 
      
 190 
     | 
    
         
            +
                dump_connector_session(session)
         
     | 
| 
      
 191 
     | 
    
         
            +
              end
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
              def connector_delete(op)
         
     | 
| 
      
 194 
     | 
    
         
            +
                name = op.cmd_parse
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 197 
     | 
    
         
            +
                session = client.bulk_load_delete(name)
         
     | 
| 
      
 198 
     | 
    
         
            +
                puts 'Deleted session'
         
     | 
| 
      
 199 
     | 
    
         
            +
                puts '--'
         
     | 
| 
      
 200 
     | 
    
         
            +
                dump_connector_session(session)
         
     | 
| 
      
 201 
     | 
    
         
            +
              end
         
     | 
| 
      
 202 
     | 
    
         
            +
             
     | 
| 
      
 203 
     | 
    
         
            +
              def connector_history(op)
         
     | 
| 
      
 204 
     | 
    
         
            +
                set_render_format_option(op)
         
     | 
| 
      
 205 
     | 
    
         
            +
                name = op.cmd_parse
         
     | 
| 
      
 206 
     | 
    
         
            +
             
     | 
| 
      
 207 
     | 
    
         
            +
                fields = [:JobID, :Status, :Records, :Database, :Table, :Priority, :Started, :Duration]
         
     | 
| 
      
 208 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 209 
     | 
    
         
            +
                rows = client.bulk_load_history(name).map { |e|
         
     | 
| 
      
 210 
     | 
    
         
            +
                  {
         
     | 
| 
      
 211 
     | 
    
         
            +
                    :JobID => e.job_id,
         
     | 
| 
      
 212 
     | 
    
         
            +
                    :Status => e.status,
         
     | 
| 
      
 213 
     | 
    
         
            +
                    :Records => e.records,
         
     | 
| 
      
 214 
     | 
    
         
            +
                    # TODO: td-client-ruby should retuan only name
         
     | 
| 
      
 215 
     | 
    
         
            +
                    :Database => e.database['name'],
         
     | 
| 
      
 216 
     | 
    
         
            +
                    :Table => e.table['name'],
         
     | 
| 
      
 217 
     | 
    
         
            +
                    :Priority => e.priority,
         
     | 
| 
      
 218 
     | 
    
         
            +
                    :Started => Time.at(e.start_at),
         
     | 
| 
      
 219 
     | 
    
         
            +
                    :Duration => (e.end_at.nil? ? Time.now.to_i : e.end_at) - e.start_at,
         
     | 
| 
      
 220 
     | 
    
         
            +
                  }
         
     | 
| 
      
 221 
     | 
    
         
            +
                }
         
     | 
| 
      
 222 
     | 
    
         
            +
                puts cmd_render_table(rows, :fields => fields, :render_format => op.render_format)
         
     | 
| 
      
 223 
     | 
    
         
            +
              end
         
     | 
| 
      
 224 
     | 
    
         
            +
             
     | 
| 
      
 225 
     | 
    
         
            +
              def connector_run(op)
         
     | 
| 
      
 226 
     | 
    
         
            +
                wait = exclude = false
         
     | 
| 
      
 227 
     | 
    
         
            +
                op.on('-w', '--wait', 'wait for finishing the job', TrueClass) { |b| wait = b }
         
     | 
| 
      
 228 
     | 
    
         
            +
                op.on('-x', '--exclude', 'do not automatically retrieve the job result', TrueClass) { |b| exclude = b }
         
     | 
| 
      
 229 
     | 
    
         
            +
             
     | 
| 
      
 230 
     | 
    
         
            +
                name, scheduled_time = op.cmd_parse
         
     | 
| 
      
 231 
     | 
    
         
            +
             
     | 
| 
      
 232 
     | 
    
         
            +
                client = get_client()
         
     | 
| 
      
 233 
     | 
    
         
            +
                job_id = client.bulk_load_run(name)
         
     | 
| 
      
 234 
     | 
    
         
            +
                puts "Job #{job_id} is queued."
         
     | 
| 
      
 235 
     | 
    
         
            +
                puts "Use '#{$prog} " + Config.cl_options_string + "job:show #{job_id}' to show the status."
         
     | 
| 
      
 236 
     | 
    
         
            +
             
     | 
| 
      
 237 
     | 
    
         
            +
                if wait
         
     | 
| 
      
 238 
     | 
    
         
            +
                  wait_connector_job(client, job_id, exclude)
         
     | 
| 
      
 239 
     | 
    
         
            +
                end
         
     | 
| 
      
 240 
     | 
    
         
            +
              end
         
     | 
| 
      
 241 
     | 
    
         
            +
             
     | 
| 
      
 242 
     | 
    
         
            +
            private
         
     | 
| 
      
 243 
     | 
    
         
            +
             
     | 
| 
      
 244 
     | 
    
         
            +
              def file_type(str)
         
     | 
| 
      
 245 
     | 
    
         
            +
                begin
         
     | 
| 
      
 246 
     | 
    
         
            +
                  YAML.load(str)
         
     | 
| 
      
 247 
     | 
    
         
            +
                  return :yaml
         
     | 
| 
      
 248 
     | 
    
         
            +
                rescue
         
     | 
| 
      
 249 
     | 
    
         
            +
                end
         
     | 
| 
      
 250 
     | 
    
         
            +
                begin
         
     | 
| 
      
 251 
     | 
    
         
            +
                  JSON.parse(str)
         
     | 
| 
      
 252 
     | 
    
         
            +
                  return :json
         
     | 
| 
      
 253 
     | 
    
         
            +
                rescue
         
     | 
| 
      
 254 
     | 
    
         
            +
                end
         
     | 
| 
      
 255 
     | 
    
         
            +
                nil
         
     | 
| 
      
 256 
     | 
    
         
            +
              end
         
     | 
| 
      
 257 
     | 
    
         
            +
             
     | 
| 
      
 258 
     | 
    
         
            +
              def prepare_bulkload_job_config(config_file)
         
     | 
| 
      
 259 
     | 
    
         
            +
                unless File.exist?(config_file)
         
     | 
| 
      
 260 
     | 
    
         
            +
                  raise ParameterConfigurationError, "configuration file: #{config_file} not found"
         
     | 
| 
      
 261 
     | 
    
         
            +
                end
         
     | 
| 
      
 262 
     | 
    
         
            +
                config_str = File.read(config_file)
         
     | 
| 
      
 263 
     | 
    
         
            +
                if file_type(config_str) == :yaml
         
     | 
| 
      
 264 
     | 
    
         
            +
                  config_str = JSON.pretty_generate(YAML.load(config_str))
         
     | 
| 
      
 265 
     | 
    
         
            +
                end
         
     | 
| 
      
 266 
     | 
    
         
            +
                API::BulkLoad::BulkLoad.from_json(config_str)
         
     | 
| 
      
 267 
     | 
    
         
            +
              end
         
     | 
| 
      
 268 
     | 
    
         
            +
             
     | 
| 
      
 269 
     | 
    
         
            +
              def create_bulkload_job_file_backup(out)
         
     | 
| 
      
 270 
     | 
    
         
            +
                return unless File.exist?(out)
         
     | 
| 
      
 271 
     | 
    
         
            +
                0.upto(100) do |idx|
         
     | 
| 
      
 272 
     | 
    
         
            +
                  backup = "#{out}.#{idx}"
         
     | 
| 
      
 273 
     | 
    
         
            +
                  unless File.exist?(backup)
         
     | 
| 
      
 274 
     | 
    
         
            +
                    FileUtils.mv(out, backup)
         
     | 
| 
      
 275 
     | 
    
         
            +
                    return
         
     | 
| 
      
 276 
     | 
    
         
            +
                  end
         
     | 
| 
      
 277 
     | 
    
         
            +
                end
         
     | 
| 
      
 278 
     | 
    
         
            +
                raise "backup file creation failed"
         
     | 
| 
      
 279 
     | 
    
         
            +
              end
         
     | 
| 
      
 280 
     | 
    
         
            +
             
     | 
| 
      
 281 
     | 
    
         
            +
              def dump_connector_session(session)
         
     | 
| 
      
 282 
     | 
    
         
            +
                puts "Name     : #{session.name}"
         
     | 
| 
      
 283 
     | 
    
         
            +
                puts "Cron     : #{session.cron}"
         
     | 
| 
      
 284 
     | 
    
         
            +
                puts "Timezone : #{session.timezone}"
         
     | 
| 
      
 285 
     | 
    
         
            +
                puts "Delay    : #{session.delay}"
         
     | 
| 
      
 286 
     | 
    
         
            +
                puts "Database : #{session.database}"
         
     | 
| 
      
 287 
     | 
    
         
            +
                puts "Table    : #{session.table}"
         
     | 
| 
      
 288 
     | 
    
         
            +
                puts "Config"
         
     | 
| 
      
 289 
     | 
    
         
            +
                puts YAML.dump(session.config.to_h)
         
     | 
| 
      
 290 
     | 
    
         
            +
              end
         
     | 
| 
      
 291 
     | 
    
         
            +
             
     | 
| 
      
 292 
     | 
    
         
            +
              def wait_connector_job(client, job_id, exclude)
         
     | 
| 
      
 293 
     | 
    
         
            +
                job = client.job(job_id)
         
     | 
| 
      
 294 
     | 
    
         
            +
                wait_job(job, true)
         
     | 
| 
      
 295 
     | 
    
         
            +
                puts "Status     : #{job.status}"
         
     | 
| 
      
 296 
     | 
    
         
            +
              end
         
     | 
| 
      
 297 
     | 
    
         
            +
             
     | 
| 
      
 298 
     | 
    
         
            +
            end
         
     | 
| 
      
 299 
     | 
    
         
            +
            end
         
     | 
    
        data/lib/td/command/job.rb
    CHANGED
    
    | 
         @@ -1,4 +1,3 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
             
     | 
| 
       2 
1 
     | 
    
         
             
            module TreasureData
         
     | 
| 
       3 
2 
     | 
    
         
             
            module Command
         
     | 
| 
       4 
3 
     | 
    
         | 
| 
         @@ -143,6 +142,10 @@ module Command 
     | 
|
| 
       143 
142 
     | 
    
         
             
                  exclude = b
         
     | 
| 
       144 
143 
     | 
    
         
             
                }
         
     | 
| 
       145 
144 
     | 
    
         | 
| 
      
 145 
     | 
    
         
            +
                op.on('--null STRING', "null expression in csv or tsv") {|s|
         
     | 
| 
      
 146 
     | 
    
         
            +
                  render_opts[:null_expr] = s.to_s
         
     | 
| 
      
 147 
     | 
    
         
            +
                }
         
     | 
| 
      
 148 
     | 
    
         
            +
             
     | 
| 
       146 
149 
     | 
    
         
             
                job_id = op.cmd_parse
         
     | 
| 
       147 
150 
     | 
    
         | 
| 
       148 
151 
     | 
    
         
             
                # parameter concurrency validation
         
     | 
| 
         @@ -166,8 +169,38 @@ module Command 
     | 
|
| 
       166 
169 
     | 
    
         
             
                        "Option -l / --limit is only valid when not outputting to file (no -o / --output option provided)"
         
     | 
| 
       167 
170 
     | 
    
         
             
                end
         
     | 
| 
       168 
171 
     | 
    
         | 
| 
      
 172 
     | 
    
         
            +
                get_and_show_result(job_id, wait, exclude, output, limit, format, render_opts, verbose)
         
     | 
| 
      
 173 
     | 
    
         
            +
              end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
              def job_status(op)
         
     | 
| 
      
 176 
     | 
    
         
            +
                job_id = op.cmd_parse
         
     | 
| 
       169 
177 
     | 
    
         
             
                client = get_client
         
     | 
| 
       170 
178 
     | 
    
         | 
| 
      
 179 
     | 
    
         
            +
                puts client.job_status(job_id)
         
     | 
| 
      
 180 
     | 
    
         
            +
              end
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
              def job_kill(op)
         
     | 
| 
      
 183 
     | 
    
         
            +
                job_id = op.cmd_parse
         
     | 
| 
      
 184 
     | 
    
         
            +
             
     | 
| 
      
 185 
     | 
    
         
            +
                client = get_client
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                former_status = client.kill(job_id)
         
     | 
| 
      
 188 
     | 
    
         
            +
                if TreasureData::Job::FINISHED_STATUS.include?(former_status)
         
     | 
| 
      
 189 
     | 
    
         
            +
                  $stderr.puts "Job #{job_id} is already finished (#{former_status})"
         
     | 
| 
      
 190 
     | 
    
         
            +
                  exit 0
         
     | 
| 
      
 191 
     | 
    
         
            +
                end
         
     | 
| 
      
 192 
     | 
    
         
            +
             
     | 
| 
      
 193 
     | 
    
         
            +
                if former_status == TreasureData::Job::STATUS_RUNNING
         
     | 
| 
      
 194 
     | 
    
         
            +
                  $stderr.puts "Job #{job_id} is killed."
         
     | 
| 
      
 195 
     | 
    
         
            +
                else
         
     | 
| 
      
 196 
     | 
    
         
            +
                  $stderr.puts "Job #{job_id} is canceled."
         
     | 
| 
      
 197 
     | 
    
         
            +
                end
         
     | 
| 
      
 198 
     | 
    
         
            +
              end
         
     | 
| 
      
 199 
     | 
    
         
            +
             
     | 
| 
      
 200 
     | 
    
         
            +
            private
         
     | 
| 
      
 201 
     | 
    
         
            +
             
     | 
| 
      
 202 
     | 
    
         
            +
              def get_and_show_result(job_id, wait, exclude = false, output = nil, limit = nil, format = nil, render_opts = {}, verbose = false)
         
     | 
| 
      
 203 
     | 
    
         
            +
                client = get_client
         
     | 
| 
       171 
204 
     | 
    
         
             
                job = client.job(job_id)
         
     | 
| 
       172 
205 
     | 
    
         | 
| 
       173 
206 
     | 
    
         
             
                puts "JobID       : #{job.job_id}"
         
     | 
| 
         @@ -194,61 +227,14 @@ module Command 
     | 
|
| 
       194 
227 
     | 
    
         
             
                  end
         
     | 
| 
       195 
228 
     | 
    
         
             
                end
         
     | 
| 
       196 
229 
     | 
    
         | 
| 
       197 
     | 
    
         
            -
                # up to 7 retries with exponential (base 2) back-off starting at 'retry_delay'
         
     | 
| 
       198 
     | 
    
         
            -
                retry_delay = 5
         
     | 
| 
       199 
     | 
    
         
            -
                max_cumul_retry_delay = 200
         
     | 
| 
       200 
     | 
    
         
            -
                cumul_retry_delay = 0
         
     | 
| 
       201 
     | 
    
         
            -
             
     | 
| 
       202 
230 
     | 
    
         
             
                if wait && !job.finished?
         
     | 
| 
       203 
231 
     | 
    
         
             
                  wait_job(job)
         
     | 
| 
       204 
232 
     | 
    
         
             
                  if [:hive, :pig, :impala, :presto].include?(job.type) && !exclude
         
     | 
| 
       205 
     | 
    
         
            -
                     
     | 
| 
       206 
     | 
    
         
            -
             
     | 
| 
       207 
     | 
    
         
            -
                    begin
         
     | 
| 
       208 
     | 
    
         
            -
                      show_result(job, output, limit, format, render_opts)
         
     | 
| 
       209 
     | 
    
         
            -
                    rescue TreasureData::NotFoundError => e
         
     | 
| 
       210 
     | 
    
         
            -
                      # Got 404 because result not found.
         
     | 
| 
       211 
     | 
    
         
            -
                    rescue TreasureData::APIError, # HTTP status code 500 or more
         
     | 
| 
       212 
     | 
    
         
            -
                           Errno::ECONNREFUSED, Errno::ECONNRESET, Timeout::Error, EOFError,
         
     | 
| 
       213 
     | 
    
         
            -
                           OpenSSL::SSL::SSLError, SocketError => e
         
     | 
| 
       214 
     | 
    
         
            -
                      # don't retry on 300 and 400 errors
         
     | 
| 
       215 
     | 
    
         
            -
                      if e.class == TreasureData::APIError && e.message !~ /^5\d\d:\s+/
         
     | 
| 
       216 
     | 
    
         
            -
                        raise e
         
     | 
| 
       217 
     | 
    
         
            -
                      end
         
     | 
| 
       218 
     | 
    
         
            -
                      if cumul_retry_delay > max_cumul_retry_delay
         
     | 
| 
       219 
     | 
    
         
            -
                        raise e
         
     | 
| 
       220 
     | 
    
         
            -
                      end
         
     | 
| 
       221 
     | 
    
         
            -
                      $stderr.puts "Error #{e.class}: #{e.message}. Retrying after #{retry_delay} seconds..."
         
     | 
| 
       222 
     | 
    
         
            -
                      sleep retry_delay
         
     | 
| 
       223 
     | 
    
         
            -
                      cumul_retry_delay += retry_delay
         
     | 
| 
       224 
     | 
    
         
            -
                      retry_delay *= 2
         
     | 
| 
       225 
     | 
    
         
            -
                      retry
         
     | 
| 
       226 
     | 
    
         
            -
                    end
         
     | 
| 
      
 233 
     | 
    
         
            +
                    show_result_with_retry(job, output, limit, format, render_opts)
         
     | 
| 
       227 
234 
     | 
    
         
             
                  end
         
     | 
| 
       228 
     | 
    
         
            -
             
     | 
| 
       229 
235 
     | 
    
         
             
                else
         
     | 
| 
       230 
236 
     | 
    
         
             
                  if [:hive, :pig, :impala, :presto].include?(job.type) && !exclude && job.finished?
         
     | 
| 
       231 
     | 
    
         
            -
                     
     | 
| 
       232 
     | 
    
         
            -
                    begin
         
     | 
| 
       233 
     | 
    
         
            -
                      show_result(job, output, limit, format, render_opts)
         
     | 
| 
       234 
     | 
    
         
            -
                    rescue TreasureData::NotFoundError => e
         
     | 
| 
       235 
     | 
    
         
            -
                      # Got 404 because result not found.
         
     | 
| 
       236 
     | 
    
         
            -
                    rescue TreasureData::APIError,
         
     | 
| 
       237 
     | 
    
         
            -
                           Errno::ECONNREFUSED, Errno::ECONNRESET, Timeout::Error, EOFError,
         
     | 
| 
       238 
     | 
    
         
            -
                           OpenSSL::SSL::SSLError, SocketError => e
         
     | 
| 
       239 
     | 
    
         
            -
                      # don't retry on 300 and 400 errors
         
     | 
| 
       240 
     | 
    
         
            -
                      if e.class == TreasureData::APIError && e.message !~ /^5\d\d:\s+/
         
     | 
| 
       241 
     | 
    
         
            -
                        raise e
         
     | 
| 
       242 
     | 
    
         
            -
                      end
         
     | 
| 
       243 
     | 
    
         
            -
                      if cumul_retry_delay > max_cumul_retry_delay
         
     | 
| 
       244 
     | 
    
         
            -
                        raise e
         
     | 
| 
       245 
     | 
    
         
            -
                      end
         
     | 
| 
       246 
     | 
    
         
            -
                      $stderr.puts "Error #{e.class}: #{e.message}. Retrying after #{retry_delay} seconds..."
         
     | 
| 
       247 
     | 
    
         
            -
                      sleep retry_delay
         
     | 
| 
       248 
     | 
    
         
            -
                      cumul_retry_delay += retry_delay
         
     | 
| 
       249 
     | 
    
         
            -
                      retry_delay *= 2
         
     | 
| 
       250 
     | 
    
         
            -
                      retry
         
     | 
| 
       251 
     | 
    
         
            -
                    end
         
     | 
| 
      
 237 
     | 
    
         
            +
                    show_result_with_retry(job, output, limit, format, render_opts)
         
     | 
| 
       252 
238 
     | 
    
         
             
                  end
         
     | 
| 
       253 
239 
     | 
    
         | 
| 
       254 
240 
     | 
    
         
             
                  if verbose
         
     | 
| 
         @@ -272,32 +258,6 @@ module Command 
     | 
|
| 
       272 
258 
     | 
    
         
             
                puts "\rUse '-v' option to show detailed messages." + " " * 20 unless verbose
         
     | 
| 
       273 
259 
     | 
    
         
             
              end
         
     | 
| 
       274 
260 
     | 
    
         | 
| 
       275 
     | 
    
         
            -
              def job_status(op)
         
     | 
| 
       276 
     | 
    
         
            -
                job_id = op.cmd_parse
         
     | 
| 
       277 
     | 
    
         
            -
                client = get_client
         
     | 
| 
       278 
     | 
    
         
            -
             
     | 
| 
       279 
     | 
    
         
            -
                puts client.job_status(job_id)
         
     | 
| 
       280 
     | 
    
         
            -
              end
         
     | 
| 
       281 
     | 
    
         
            -
             
     | 
| 
       282 
     | 
    
         
            -
              def job_kill(op)
         
     | 
| 
       283 
     | 
    
         
            -
                job_id = op.cmd_parse
         
     | 
| 
       284 
     | 
    
         
            -
             
     | 
| 
       285 
     | 
    
         
            -
                client = get_client
         
     | 
| 
       286 
     | 
    
         
            -
             
     | 
| 
       287 
     | 
    
         
            -
                former_status = client.kill(job_id)
         
     | 
| 
       288 
     | 
    
         
            -
                if TreasureData::Job::FINISHED_STATUS.include?(former_status)
         
     | 
| 
       289 
     | 
    
         
            -
                  $stderr.puts "Job #{job_id} is already finished (#{former_status})"
         
     | 
| 
       290 
     | 
    
         
            -
                  exit 0
         
     | 
| 
       291 
     | 
    
         
            -
                end
         
     | 
| 
       292 
     | 
    
         
            -
             
     | 
| 
       293 
     | 
    
         
            -
                if former_status == TreasureData::Job::STATUS_RUNNING
         
     | 
| 
       294 
     | 
    
         
            -
                  $stderr.puts "Job #{job_id} is killed."
         
     | 
| 
       295 
     | 
    
         
            -
                else
         
     | 
| 
       296 
     | 
    
         
            -
                  $stderr.puts "Job #{job_id} is canceled."
         
     | 
| 
       297 
     | 
    
         
            -
                end
         
     | 
| 
       298 
     | 
    
         
            -
              end
         
     | 
| 
       299 
     | 
    
         
            -
             
     | 
| 
       300 
     | 
    
         
            -
              private
         
     | 
| 
       301 
261 
     | 
    
         
             
              def wait_job(job, first_call = false)
         
     | 
| 
       302 
262 
     | 
    
         
             
                $stderr.puts "queued..."
         
     | 
| 
       303 
263 
     | 
    
         | 
| 
         @@ -328,6 +288,35 @@ module Command 
     | 
|
| 
       328 
288 
     | 
    
         
             
                end
         
     | 
| 
       329 
289 
     | 
    
         
             
              end
         
     | 
| 
       330 
290 
     | 
    
         | 
| 
      
 291 
     | 
    
         
            +
              def show_result_with_retry(job, output, limit, format, render_opts)
         
     | 
| 
      
 292 
     | 
    
         
            +
                # up to 7 retries with exponential (base 2) back-off starting at 'retry_delay'
         
     | 
| 
      
 293 
     | 
    
         
            +
                retry_delay = 5
         
     | 
| 
      
 294 
     | 
    
         
            +
                max_cumul_retry_delay = 200
         
     | 
| 
      
 295 
     | 
    
         
            +
                cumul_retry_delay = 0
         
     | 
| 
      
 296 
     | 
    
         
            +
             
     | 
| 
      
 297 
     | 
    
         
            +
                puts "Result      :"
         
     | 
| 
      
 298 
     | 
    
         
            +
                begin
         
     | 
| 
      
 299 
     | 
    
         
            +
                  show_result(job, output, limit, format, render_opts)
         
     | 
| 
      
 300 
     | 
    
         
            +
                rescue TreasureData::NotFoundError => e
         
     | 
| 
      
 301 
     | 
    
         
            +
                  # Got 404 because result not found.
         
     | 
| 
      
 302 
     | 
    
         
            +
                rescue TreasureData::APIError, # HTTP status code 500 or more
         
     | 
| 
      
 303 
     | 
    
         
            +
                        Errno::ECONNREFUSED, Errno::ECONNRESET, Timeout::Error, EOFError,
         
     | 
| 
      
 304 
     | 
    
         
            +
                        OpenSSL::SSL::SSLError, SocketError => e
         
     | 
| 
      
 305 
     | 
    
         
            +
                  # don't retry on 300 and 400 errors
         
     | 
| 
      
 306 
     | 
    
         
            +
                  if e.class == TreasureData::APIError && e.message !~ /^5\d\d:\s+/
         
     | 
| 
      
 307 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 308 
     | 
    
         
            +
                  end
         
     | 
| 
      
 309 
     | 
    
         
            +
                  if cumul_retry_delay > max_cumul_retry_delay
         
     | 
| 
      
 310 
     | 
    
         
            +
                    raise e
         
     | 
| 
      
 311 
     | 
    
         
            +
                  end
         
     | 
| 
      
 312 
     | 
    
         
            +
                  $stderr.puts "Error #{e.class}: #{e.message}. Retrying after #{retry_delay} seconds..."
         
     | 
| 
      
 313 
     | 
    
         
            +
                  sleep retry_delay
         
     | 
| 
      
 314 
     | 
    
         
            +
                  cumul_retry_delay += retry_delay
         
     | 
| 
      
 315 
     | 
    
         
            +
                  retry_delay *= 2
         
     | 
| 
      
 316 
     | 
    
         
            +
                  retry
         
     | 
| 
      
 317 
     | 
    
         
            +
                end
         
     | 
| 
      
 318 
     | 
    
         
            +
              end
         
     | 
| 
      
 319 
     | 
    
         
            +
             
     | 
| 
       331 
320 
     | 
    
         
             
              def show_result(job, output, limit, format, render_opts={})
         
     | 
| 
       332 
321 
     | 
    
         
             
                if output
         
     | 
| 
       333 
322 
     | 
    
         
             
                  write_result(job, output, limit, format, render_opts)
         
     | 
| 
         @@ -387,7 +376,7 @@ module Command 
     | 
|
| 
       387 
376 
     | 
    
         
             
                    job.result_each_with_compr_size {|row, compr_size|
         
     | 
| 
       388 
377 
     | 
    
         
             
                      # TODO limit the # of columns
         
     | 
| 
       389 
378 
     | 
    
         
             
                      writer << row.map {|col|
         
     | 
| 
       390 
     | 
    
         
            -
                        dump_column(col)
         
     | 
| 
      
 379 
     | 
    
         
            +
                        dump_column(col, render_opts[:null_expr])
         
     | 
| 
       391 
380 
     | 
    
         
             
                      }
         
     | 
| 
       392 
381 
     | 
    
         
             
                      n_rows += 1
         
     | 
| 
       393 
382 
     | 
    
         
             
                      if n_rows % 100 == 0 # flush every 100 recods
         
     | 
| 
         @@ -405,10 +394,7 @@ module Command 
     | 
|
| 
       405 
394 
     | 
    
         
             
                  open_file(output, "w") {|f|
         
     | 
| 
       406 
395 
     | 
    
         
             
                    # output headers
         
     | 
| 
       407 
396 
     | 
    
         
             
                    if render_opts[:header] && job.hive_result_schema
         
     | 
| 
       408 
     | 
    
         
            -
                      job.hive_result_schema. 
     | 
| 
       409 
     | 
    
         
            -
                        f.write name + "\t"
         
     | 
| 
       410 
     | 
    
         
            -
                      }
         
     | 
| 
       411 
     | 
    
         
            -
                      f.write "\n"
         
     | 
| 
      
 397 
     | 
    
         
            +
                      f.write job.hive_result_schema.map {|name, type| name}.join("\t") + "\n"
         
     | 
| 
       412 
398 
     | 
    
         
             
                    end
         
     | 
| 
       413 
399 
     | 
    
         
             
                    # output data
         
     | 
| 
       414 
400 
     | 
    
         
             
                    n_rows = 0
         
     | 
| 
         @@ -417,8 +403,9 @@ module Command 
     | 
|
| 
       417 
403 
     | 
    
         
             
                        "NOTE: the job result is being written to #{output} in tsv format",
         
     | 
| 
       418 
404 
     | 
    
         
             
                        job.result_size, 0.1, 1)
         
     | 
| 
       419 
405 
     | 
    
         
             
                    end
         
     | 
| 
      
 406 
     | 
    
         
            +
             
     | 
| 
       420 
407 
     | 
    
         
             
                    job.result_each_with_compr_size {|row, compr_size|
         
     | 
| 
       421 
     | 
    
         
            -
                      f.write row.map {|col| dump_column(col)}.join("\t") + "\n"
         
     | 
| 
      
 408 
     | 
    
         
            +
                      f.write row.map {|col| dump_column(col, render_opts[:null_expr])}.join("\t") + "\n"
         
     | 
| 
       422 
409 
     | 
    
         
             
                      n_rows += 1
         
     | 
| 
       423 
410 
     | 
    
         
             
                      if n_rows % 100 == 0
         
     | 
| 
       424 
411 
     | 
    
         
             
                        f.flush # flush every 100 recods
         
     | 
| 
         @@ -493,7 +480,7 @@ module Command 
     | 
|
| 
       493 
480 
     | 
    
         
             
                  job.result_each_with_compr_size {|row, compr_size|
         
     | 
| 
       494 
481 
     | 
    
         
             
                    indicator.update(compr_size)
         
     | 
| 
       495 
482 
     | 
    
         
             
                    rows << row.map {|v|
         
     | 
| 
       496 
     | 
    
         
            -
                      dump_column_safe_utf8(v)
         
     | 
| 
      
 483 
     | 
    
         
            +
                      dump_column_safe_utf8(v, render_opts[:null_expr])
         
     | 
| 
       497 
484 
     | 
    
         
             
                    }
         
     | 
| 
       498 
485 
     | 
    
         
             
                    n_rows += 1
         
     | 
| 
       499 
486 
     | 
    
         
             
                    break if !limit.nil? and n_rows == limit
         
     | 
| 
         @@ -514,15 +501,17 @@ module Command 
     | 
|
| 
       514 
501 
     | 
    
         
             
                end
         
     | 
| 
       515 
502 
     | 
    
         
             
              end
         
     | 
| 
       516 
503 
     | 
    
         | 
| 
       517 
     | 
    
         
            -
              def dump_column(v)
         
     | 
| 
       518 
     | 
    
         
            -
                 
     | 
| 
      
 504 
     | 
    
         
            +
              def dump_column(v, null_expr = nil)
         
     | 
| 
      
 505 
     | 
    
         
            +
                v = null_expr if v.nil? && null_expr
         
     | 
| 
      
 506 
     | 
    
         
            +
             
     | 
| 
      
 507 
     | 
    
         
            +
                s = v.is_a?(String) ? v.to_s : Yajl.dump(sanitize_infinite_value(v))
         
     | 
| 
       519 
508 
     | 
    
         
             
                # CAUTION: msgpack-ruby populates byte sequences as Encoding.default_internal which should be BINARY
         
     | 
| 
       520 
509 
     | 
    
         
             
                s = s.force_encoding('BINARY') if s.respond_to?(:encode)
         
     | 
| 
       521 
510 
     | 
    
         
             
                s
         
     | 
| 
       522 
511 
     | 
    
         
             
              end
         
     | 
| 
       523 
512 
     | 
    
         | 
| 
       524 
     | 
    
         
            -
              def dump_column_safe_utf8(v)
         
     | 
| 
       525 
     | 
    
         
            -
                s = dump_column(v)
         
     | 
| 
      
 513 
     | 
    
         
            +
              def dump_column_safe_utf8(v, null_expr = false)
         
     | 
| 
      
 514 
     | 
    
         
            +
                s = dump_column(v, null_expr)
         
     | 
| 
       526 
515 
     | 
    
         
             
                # Here does UTF-8 -> UTF-16LE -> UTF8 conversion:
         
     | 
| 
       527 
516 
     | 
    
         
             
                #   a) to make sure the string doesn't include invalid byte sequence
         
     | 
| 
       528 
517 
     | 
    
         
             
                #   b) to display multi-byte characters as it is
         
     | 
| 
         @@ -532,6 +521,10 @@ module Command 
     | 
|
| 
       532 
521 
     | 
    
         
             
                s
         
     | 
| 
       533 
522 
     | 
    
         
             
              end
         
     | 
| 
       534 
523 
     | 
    
         | 
| 
      
 524 
     | 
    
         
            +
              def sanitize_infinite_value(v)
         
     | 
| 
      
 525 
     | 
    
         
            +
                (v.is_a?(Float) && !v.finite?) ? v.to_s : v
         
     | 
| 
      
 526 
     | 
    
         
            +
              end
         
     | 
| 
      
 527 
     | 
    
         
            +
             
     | 
| 
       535 
528 
     | 
    
         
             
              def job_priority_name_of(id)
         
     | 
| 
       536 
529 
     | 
    
         
             
                PRIORITY_FORMAT_MAP[id] || 'NORMAL'
         
     | 
| 
       537 
530 
     | 
    
         
             
              end
         
     | 
    
        data/lib/td/command/list.rb
    CHANGED
    
    | 
         @@ -311,7 +311,7 @@ module List 
     | 
|
| 
       311 
311 
     | 
    
         
             
              # TODO acl:test
         
     | 
| 
       312 
312 
     | 
    
         | 
| 
       313 
313 
     | 
    
         
             
              add_list 'server:status', %w[], 'Show status of the Treasure Data server'
         
     | 
| 
       314 
     | 
    
         
            -
              add_list 'server:endpoint', %w[api_endpoint], "Set the Treasure Data API server's endpoint (must be a valid URI)", [" 
     | 
| 
      
 314 
     | 
    
         
            +
              add_list 'server:endpoint', %w[api_endpoint], "Set the Treasure Data API server's endpoint (must be a valid URI)", ["server:endpoint 'https://api.treasuredata.com'"]
         
     | 
| 
       315 
315 
     | 
    
         | 
| 
       316 
316 
     | 
    
         
             
              add_list 'sample:apache', %w[path.json], 'Create a sample log file', [], false
         
     | 
| 
       317 
317 
     | 
    
         | 
| 
         @@ -320,6 +320,19 @@ module List 
     | 
|
| 
       320 
320 
     | 
    
         | 
| 
       321 
321 
     | 
    
         
             
              add_list 'update', %w[], 'Update td and related libraries for TreasureData toolbelt'
         
     | 
| 
       322 
322 
     | 
    
         | 
| 
      
 323 
     | 
    
         
            +
              add_list 'connector:guess', %w[config?], 'Run guess to generate connector config file', ['connector:guess td-bulkload.yml', 'connector:guess --access-id s3accessId --access-secret s3AccessKey --source https://s3.amazonaws.com/bucketname/path/prefix --database connector_database --table connector_table']
         
     | 
| 
      
 324 
     | 
    
         
            +
              add_list 'connector:preview', %w[config], 'Show preview of connector execution', ['connector:preview td-bulkload.yml']
         
     | 
| 
      
 325 
     | 
    
         
            +
             
     | 
| 
      
 326 
     | 
    
         
            +
              add_list 'connector:issue', %w[config], 'Run one time connector execution', ['connector:issue td-bulkload.yml']
         
     | 
| 
      
 327 
     | 
    
         
            +
             
     | 
| 
      
 328 
     | 
    
         
            +
              add_list 'connector:list', %w[], 'Show list of connector sessions', ['connector:list']
         
     | 
| 
      
 329 
     | 
    
         
            +
              add_list 'connector:create', %w[name cron database table config], 'Create new connector session', ['connector:create connector1 "0 * * * *" connector_database connector_table td-bulkload.yml']
         
     | 
| 
      
 330 
     | 
    
         
            +
              add_list 'connector:show', %w[name], 'Show connector session', ['connector:show connector1']
         
     | 
| 
      
 331 
     | 
    
         
            +
              add_list 'connector:update', %w[name config], 'Modify connector session', ['connector:update connector1 td-bulkload.yml']
         
     | 
| 
      
 332 
     | 
    
         
            +
              add_list 'connector:delete', %w[name], 'Delete connector session', ['connector:delete connector1']
         
     | 
| 
      
 333 
     | 
    
         
            +
              add_list 'connector:history', %w[name], 'Show job history of connector session', ['connector:history connector1']
         
     | 
| 
      
 334 
     | 
    
         
            +
              add_list 'connector:run', %w[name time], 'Run connector session for the specified time', ['connector:run connector1 "2016-01-01 00:00:00"']
         
     | 
| 
      
 335 
     | 
    
         
            +
             
     | 
| 
       323 
336 
     | 
    
         
             
              # aliases
         
     | 
| 
       324 
337 
     | 
    
         
             
              add_alias 'db', 'db:show'
         
     | 
| 
       325 
338 
     | 
    
         
             
              add_alias 'dbs', 'db:list'
         
     | 
| 
         @@ -377,6 +390,8 @@ module List 
     | 
|
| 
       377 
390 
     | 
    
         | 
| 
       378 
391 
     | 
    
         
             
              add_alias 's', 'status'
         
     | 
| 
       379 
392 
     | 
    
         | 
| 
      
 393 
     | 
    
         
            +
              add_alias 'connector', 'connector:guess'
         
     | 
| 
      
 394 
     | 
    
         
            +
             
     | 
| 
       380 
395 
     | 
    
         
             
              # backward compatibility
         
     | 
| 
       381 
396 
     | 
    
         
             
              add_alias 'show-databases',   'db:list'
         
     | 
| 
       382 
397 
     | 
    
         
             
              add_alias 'show-dbs',         'db:list'
         
     | 
    
        data/lib/td/command/runner.rb
    CHANGED
    
    
    
        data/lib/td/command/table.rb
    CHANGED
    
    | 
         @@ -144,18 +144,25 @@ module Command 
     | 
|
| 
       144 
144 
     | 
    
         
             
                  databases = client.databases
         
     | 
| 
       145 
145 
     | 
    
         
             
                end
         
     | 
| 
       146 
146 
     | 
    
         | 
| 
       147 
     | 
    
         
            -
                has_item = databases.select {|db| 
     | 
| 
      
 147 
     | 
    
         
            +
                has_item = databases.select {|db|
         
     | 
| 
      
 148 
     | 
    
         
            +
                  db.permission != :import_only ? (db.tables.select {|table| table.type == :item}.length > 0) : false
         
     | 
| 
      
 149 
     | 
    
         
            +
                }.length > 0
         
     | 
| 
       148 
150 
     | 
    
         | 
| 
      
 151 
     | 
    
         
            +
                # ref. https://github.com/treasure-data/td/issues/26
         
     | 
| 
      
 152 
     | 
    
         
            +
                should_number_format = [nil, "table"].include?(op.render_format)
         
     | 
| 
       149 
153 
     | 
    
         
             
                rows = []
         
     | 
| 
       150 
154 
     | 
    
         
             
                ::Parallel.each(databases, :in_threads => num_threads) {|db|
         
     | 
| 
       151 
155 
     | 
    
         
             
                  begin
         
     | 
| 
      
 156 
     | 
    
         
            +
                    if db.permission == :import_only
         
     | 
| 
      
 157 
     | 
    
         
            +
                      next
         
     | 
| 
      
 158 
     | 
    
         
            +
                    end
         
     | 
| 
       152 
159 
     | 
    
         
             
                    db.tables.each {}
         
     | 
| 
       153 
160 
     | 
    
         
             
                    db.tables.each {|table|
         
     | 
| 
       154 
161 
     | 
    
         
             
                      pschema = table.schema.fields.map {|f|
         
     | 
| 
       155 
162 
     | 
    
         
             
                        "#{f.name}:#{f.type}"
         
     | 
| 
       156 
163 
     | 
    
         
             
                      }.join(', ')
         
     | 
| 
       157 
164 
     | 
    
         
             
                      new_row = {
         
     | 
| 
       158 
     | 
    
         
            -
                        :Database => db.name, :Table => table.name, :Type => table.type.to_s, :Count => TreasureData::Helpers.format_with_delimiter(table.count),
         
     | 
| 
      
 165 
     | 
    
         
            +
                        :Database => db.name, :Table => table.name, :Type => table.type.to_s, :Count => (should_number_format ? TreasureData::Helpers.format_with_delimiter(table.count) : table.count),
         
     | 
| 
       159 
166 
     | 
    
         
             
                        :Size => show_size_in_bytes ? TreasureData::Helpers.format_with_delimiter(table.estimated_storage_size) : table.estimated_storage_size_string,
         
     | 
| 
       160 
167 
     | 
    
         
             
                        'Last import' => table.last_import ? table.last_import.localtime : nil,
         
     | 
| 
       161 
168 
     | 
    
         
             
                        'Last log timestamp' => table.last_log_timestamp ? table.last_log_timestamp.localtime : nil,
         
     | 
| 
         @@ -188,8 +195,12 @@ module Command 
     | 
|
| 
       188 
195 
     | 
    
         | 
| 
       189 
196 
     | 
    
         
             
                if rows.empty?
         
     | 
| 
       190 
197 
     | 
    
         
             
                  if db_name
         
     | 
| 
       191 
     | 
    
         
            -
                     
     | 
| 
       192 
     | 
    
         
            -
             
     | 
| 
      
 198 
     | 
    
         
            +
                    if databases.first.permission == :import_only
         
     | 
| 
      
 199 
     | 
    
         
            +
                      $stderr.puts "Database '#{db_name}' is import only, cannot list or create tables."
         
     | 
| 
      
 200 
     | 
    
         
            +
                    else
         
     | 
| 
      
 201 
     | 
    
         
            +
                      $stderr.puts "Database '#{db_name}' has no tables."
         
     | 
| 
      
 202 
     | 
    
         
            +
                      $stderr.puts "Use '#{$prog} " + Config.cl_options_string + "table:create <db> <table>' to create a table."
         
     | 
| 
      
 203 
     | 
    
         
            +
                    end
         
     | 
| 
       193 
204 
     | 
    
         
             
                  elsif databases.empty?
         
     | 
| 
       194 
205 
     | 
    
         
             
                    $stderr.puts "There are no databases."
         
     | 
| 
       195 
206 
     | 
    
         
             
                    $stderr.puts "Use '#{$prog} " + Config.cl_options_string + "db:create <db>' to create a database."
         
     | 
    
        data/lib/td/command/user.rb
    CHANGED
    
    | 
         @@ -120,7 +120,7 @@ module Command 
     | 
|
| 
       120 
120 
     | 
    
         
             
                client.add_user(name, nil, email, password)
         
     | 
| 
       121 
121 
     | 
    
         | 
| 
       122 
122 
     | 
    
         
             
                $stderr.puts "User '#{name}' is created."
         
     | 
| 
       123 
     | 
    
         
            -
                $stderr.puts "Use '#{$prog} " + Config.cl_options_string + "user:apikeys #{name}' to show the API key." 
     | 
| 
      
 123 
     | 
    
         
            +
                $stderr.puts "Use '#{$prog} " + Config.cl_options_string + "user:apikeys #{name}' to show the API key."
         
     | 
| 
       124 
124 
     | 
    
         
             
              end
         
     | 
| 
       125 
125 
     | 
    
         | 
| 
       126 
126 
     | 
    
         
             
              def user_delete(op)
         
     | 
    
        data/lib/td/updater.rb
    CHANGED
    
    | 
         @@ -330,35 +330,35 @@ end # module ModuleDefinition 
     | 
|
| 
       330 
330 
     | 
    
         | 
| 
       331 
331 
     | 
    
         
             
                if updated > last_updated
         
     | 
| 
       332 
332 
     | 
    
         
             
                  FileUtils.mkdir_p(Updater.jarfile_dest_path) unless File.exists?(Updater.jarfile_dest_path)
         
     | 
| 
       333 
     | 
    
         
            -
                  Dir.chdir 
     | 
| 
      
 333 
     | 
    
         
            +
                  Dir.chdir(Updater.jarfile_dest_path) do
         
     | 
| 
      
 334 
     | 
    
         
            +
                    File.open('VERSION', 'w') {|f|
         
     | 
| 
      
 335 
     | 
    
         
            +
                      if hourly
         
     | 
| 
      
 336 
     | 
    
         
            +
                        f.print "#{version} via hourly jar auto-update"
         
     | 
| 
      
 337 
     | 
    
         
            +
                      else
         
     | 
| 
      
 338 
     | 
    
         
            +
                        f.print "#{version} via import:jar_update command"
         
     | 
| 
      
 339 
     | 
    
         
            +
                      end
         
     | 
| 
      
 340 
     | 
    
         
            +
                    }
         
     | 
| 
      
 341 
     | 
    
         
            +
                    File.open('td-import-java.version', 'w') {|f|
         
     | 
| 
      
 342 
     | 
    
         
            +
                      f.print "#{version} #{updated}"
         
     | 
| 
      
 343 
     | 
    
         
            +
                    }
         
     | 
| 
       334 
344 
     | 
    
         | 
| 
       335 
     | 
    
         
            -
             
     | 
| 
       336 
     | 
    
         
            -
                     
     | 
| 
       337 
     | 
    
         
            -
                       
     | 
| 
       338 
     | 
    
         
            -
                     
     | 
| 
       339 
     | 
    
         
            -
                       
     | 
| 
       340 
     | 
    
         
            -
             
     | 
| 
       341 
     | 
    
         
            -
             
     | 
| 
       342 
     | 
    
         
            -
                  File.open('td-import-java.version', 'w') {|f|
         
     | 
| 
       343 
     | 
    
         
            -
                    f.print "#{version} #{updated}"
         
     | 
| 
       344 
     | 
    
         
            -
                  }
         
     | 
| 
       345 
     | 
    
         
            -
             
     | 
| 
       346 
     | 
    
         
            -
                  status = nil
         
     | 
| 
       347 
     | 
    
         
            -
                  indicator = Command::TimeBasedDownloadProgressIndicator.new(
         
     | 
| 
       348 
     | 
    
         
            -
                    "Updating td-import.jar", Time.new.to_i, 2)
         
     | 
| 
       349 
     | 
    
         
            -
                  File.open('td-import.jar.new', 'wb') {|binfile|
         
     | 
| 
       350 
     | 
    
         
            -
                    status = Updater.stream_fetch("#{maven_repo}/#{version}/td-import-#{version}-jar-with-dependencies.jar", binfile) {
         
     | 
| 
       351 
     | 
    
         
            -
                      indicator.update
         
     | 
| 
      
 345 
     | 
    
         
            +
                    status = nil
         
     | 
| 
      
 346 
     | 
    
         
            +
                    indicator = Command::TimeBasedDownloadProgressIndicator.new(
         
     | 
| 
      
 347 
     | 
    
         
            +
                      "Updating td-import.jar", Time.new.to_i, 2)
         
     | 
| 
      
 348 
     | 
    
         
            +
                    File.open('td-import.jar.new', 'wb') {|binfile|
         
     | 
| 
      
 349 
     | 
    
         
            +
                      status = Updater.stream_fetch("#{maven_repo}/#{version}/td-import-#{version}-jar-with-dependencies.jar", binfile) {
         
     | 
| 
      
 350 
     | 
    
         
            +
                        indicator.update
         
     | 
| 
      
 351 
     | 
    
         
            +
                      }
         
     | 
| 
       352 
352 
     | 
    
         
             
                    }
         
     | 
| 
       353 
     | 
    
         
            -
             
     | 
| 
       354 
     | 
    
         
            -
                  indicator.finish()
         
     | 
| 
      
 353 
     | 
    
         
            +
                    indicator.finish()
         
     | 
| 
       355 
354 
     | 
    
         | 
| 
       356 
     | 
    
         
            -
             
     | 
| 
       357 
     | 
    
         
            -
             
     | 
| 
       358 
     | 
    
         
            -
             
     | 
| 
       359 
     | 
    
         
            -
             
     | 
| 
       360 
     | 
    
         
            -
             
     | 
| 
       361 
     | 
    
         
            -
             
     | 
| 
      
 355 
     | 
    
         
            +
                    if status
         
     | 
| 
      
 356 
     | 
    
         
            +
                      puts "Installed td-import.jar v#{version} in '#{Updater.jarfile_dest_path}'.\n"
         
     | 
| 
      
 357 
     | 
    
         
            +
                      File.rename 'td-import.jar.new', 'td-import.jar'
         
     | 
| 
      
 358 
     | 
    
         
            +
                    else
         
     | 
| 
      
 359 
     | 
    
         
            +
                      puts "Update of td-import.jar failed." unless ENV['TD_TOOLBELT_DEBUG'].nil?
         
     | 
| 
      
 360 
     | 
    
         
            +
                      File.delete 'td-import.jar.new' if File.exists? 'td-import.jar.new'
         
     | 
| 
      
 361 
     | 
    
         
            +
                    end
         
     | 
| 
       362 
362 
     | 
    
         
             
                  end
         
     | 
| 
       363 
363 
     | 
    
         
             
                else
         
     | 
| 
       364 
364 
     | 
    
         
             
                  puts 'Installed td-import.jar is already at the latest version.' unless hourly
         
     | 
    
        data/lib/td/version.rb
    CHANGED
    
    
    
        data/spec/td/command/job_spec.rb
    CHANGED
    
    | 
         @@ -13,6 +13,8 @@ module TreasureData::Command 
     | 
|
| 
       13 
13 
     | 
    
         
             
                end
         
     | 
| 
       14 
14 
     | 
    
         | 
| 
       15 
15 
     | 
    
         
             
                describe 'write_result' do
         
     | 
| 
      
 16 
     | 
    
         
            +
                  let(:file) { Tempfile.new("job_spec") }
         
     | 
| 
      
 17 
     | 
    
         
            +
             
     | 
| 
       16 
18 
     | 
    
         
             
                  let :job do
         
     | 
| 
       17 
19 
     | 
    
         
             
                    job = TreasureData::Job.new(nil, 12345, 'hive', 'select * from employee')
         
     | 
| 
       18 
20 
     | 
    
         
             
                    job.instance_eval do
         
     | 
| 
         @@ -23,22 +25,216 @@ module TreasureData::Command 
     | 
|
| 
       23 
25 
     | 
    
         
             
                    job
         
     | 
| 
       24 
26 
     | 
    
         
             
                  end
         
     | 
| 
       25 
27 
     | 
    
         | 
| 
       26 
     | 
    
         
            -
                   
     | 
| 
       27 
     | 
    
         
            -
                     
     | 
| 
       28 
     | 
    
         
            -
             
     | 
| 
       29 
     | 
    
         
            -
             
     | 
| 
      
 28 
     | 
    
         
            +
                  context 'result without nil' do
         
     | 
| 
      
 29 
     | 
    
         
            +
                    it 'supports json output' do
         
     | 
| 
      
 30 
     | 
    
         
            +
                      command.send(:show_result, job, file, nil, 'json')
         
     | 
| 
      
 31 
     | 
    
         
            +
                      File.read(file.path).should == %Q([["1",2.0,{"key":3}],\n["4",5.0,{"key":6}],\n["7",8.0,{"key":9}]])
         
     | 
| 
      
 32 
     | 
    
         
            +
                    end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
                    it 'supports csv output' do
         
     | 
| 
      
 35 
     | 
    
         
            +
                      command.send(:show_result, job, file, nil, 'csv')
         
     | 
| 
      
 36 
     | 
    
         
            +
                      File.read(file.path).should == %Q(1,2.0,"{""key"":3}"\n4,5.0,"{""key"":6}"\n7,8.0,"{""key"":9}"\n)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    end
         
     | 
| 
      
 38 
     | 
    
         
            +
             
     | 
| 
      
 39 
     | 
    
         
            +
                    it 'supports tsv output' do
         
     | 
| 
      
 40 
     | 
    
         
            +
                      command.send(:show_result, job, file, nil, 'tsv')
         
     | 
| 
      
 41 
     | 
    
         
            +
                      File.read(file.path).should == %Q(1\t2.0\t{"key":3}\n4\t5.0\t{"key":6}\n7\t8.0\t{"key":9}\n)
         
     | 
| 
      
 42 
     | 
    
         
            +
                    end
         
     | 
| 
       30 
43 
     | 
    
         
             
                  end
         
     | 
| 
       31 
44 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
                   
     | 
| 
       33 
     | 
    
         
            -
                     
     | 
| 
       34 
     | 
    
         
            -
             
     | 
| 
       35 
     | 
    
         
            -
                     
     | 
| 
      
 45 
     | 
    
         
            +
                  context 'result with nil' do
         
     | 
| 
      
 46 
     | 
    
         
            +
                    let :job_id do
         
     | 
| 
      
 47 
     | 
    
         
            +
                      12345
         
     | 
| 
      
 48 
     | 
    
         
            +
                    end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
                    let :job do
         
     | 
| 
      
 51 
     | 
    
         
            +
                      job = TreasureData::Job.new(nil, job_id, 'hive', 'select * from employee')
         
     | 
| 
      
 52 
     | 
    
         
            +
                      job.instance_eval do
         
     | 
| 
      
 53 
     | 
    
         
            +
                        @result = [[[nil, 2.0, {key:3}], 1]]
         
     | 
| 
      
 54 
     | 
    
         
            +
                        @result_size = 3
         
     | 
| 
      
 55 
     | 
    
         
            +
                        @status = 'success'
         
     | 
| 
      
 56 
     | 
    
         
            +
                      end
         
     | 
| 
      
 57 
     | 
    
         
            +
                      job
         
     | 
| 
      
 58 
     | 
    
         
            +
                    end
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    context 'with --column-header option' do
         
     | 
| 
      
 61 
     | 
    
         
            +
                      before do
         
     | 
| 
      
 62 
     | 
    
         
            +
                        job.stub(:hive_result_schema).and_return([['c0', 'time'], ['c1', 'double'], ['v', nil], ['c3', 'long']])
         
     | 
| 
      
 63 
     | 
    
         
            +
                        client = Object.new
         
     | 
| 
      
 64 
     | 
    
         
            +
                        client.stub(:job).with(job_id).and_return(job)
         
     | 
| 
      
 65 
     | 
    
         
            +
                        command.stub(:get_client).and_return(client)
         
     | 
| 
      
 66 
     | 
    
         
            +
                      end
         
     | 
| 
      
 67 
     | 
    
         
            +
             
     | 
| 
      
 68 
     | 
    
         
            +
                      it 'supports json output' do
         
     | 
| 
      
 69 
     | 
    
         
            +
                        command.send(:show_result, job, file, nil, 'json', { header: true })
         
     | 
| 
      
 70 
     | 
    
         
            +
                        File.read(file.path).should == %Q([[null,2.0,{"key":3}]])
         
     | 
| 
      
 71 
     | 
    
         
            +
                      end
         
     | 
| 
      
 72 
     | 
    
         
            +
             
     | 
| 
      
 73 
     | 
    
         
            +
                      it 'supports csv output' do
         
     | 
| 
      
 74 
     | 
    
         
            +
                        command.send(:show_result, job, file, nil, 'csv', { header: true })
         
     | 
| 
      
 75 
     | 
    
         
            +
                        File.read(file.path).should == %Q(c0,c1,v,c3\nnull,2.0,"{""key"":3}"\n)
         
     | 
| 
      
 76 
     | 
    
         
            +
                      end
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                      it 'supports tsv output' do
         
     | 
| 
      
 79 
     | 
    
         
            +
                        command.send(:show_result, job, file, nil, 'tsv', { header: true })
         
     | 
| 
      
 80 
     | 
    
         
            +
                        File.read(file.path).should == %Q(c0\tc1\tv\tc3\nnull\t2.0\t{"key":3}\n)
         
     | 
| 
      
 81 
     | 
    
         
            +
                      end
         
     | 
| 
      
 82 
     | 
    
         
            +
                    end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                    context 'without --null option' do
         
     | 
| 
      
 85 
     | 
    
         
            +
                      it 'supports json output' do
         
     | 
| 
      
 86 
     | 
    
         
            +
                        command.send(:show_result, job, file, nil, 'json')
         
     | 
| 
      
 87 
     | 
    
         
            +
                        File.read(file.path).should == %Q([[null,2.0,{"key":3}]])
         
     | 
| 
      
 88 
     | 
    
         
            +
                      end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                      it 'supports csv output' do
         
     | 
| 
      
 91 
     | 
    
         
            +
                        command.send(:show_result, job, file, nil, 'csv')
         
     | 
| 
      
 92 
     | 
    
         
            +
                        File.read(file.path).should == %Q(null,2.0,"{""key"":3}"\n)
         
     | 
| 
      
 93 
     | 
    
         
            +
                      end
         
     | 
| 
      
 94 
     | 
    
         
            +
             
     | 
| 
      
 95 
     | 
    
         
            +
                      it 'supports tsv output' do
         
     | 
| 
      
 96 
     | 
    
         
            +
                        command.send(:show_result, job, file, nil, 'tsv')
         
     | 
| 
      
 97 
     | 
    
         
            +
                        File.read(file.path).should == %Q(null\t2.0\t{"key":3}\n)
         
     | 
| 
      
 98 
     | 
    
         
            +
                      end
         
     | 
| 
      
 99 
     | 
    
         
            +
                    end
         
     | 
| 
      
 100 
     | 
    
         
            +
             
     | 
| 
      
 101 
     | 
    
         
            +
                    context 'with --null option' do
         
     | 
| 
      
 102 
     | 
    
         
            +
                      it 'dose not effect json output (nil will be shown as null)' do
         
     | 
| 
      
 103 
     | 
    
         
            +
                        command.send(:show_result, job, file, nil, 'json', { null_expr: "NULL" })
         
     | 
| 
      
 104 
     | 
    
         
            +
                        File.read(file.path).should == %Q([[null,2.0,{"key":3}]])
         
     | 
| 
      
 105 
     | 
    
         
            +
                      end
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                      context 'csv format' do
         
     | 
| 
      
 108 
     | 
    
         
            +
                        context 'specified string is NULL' do
         
     | 
| 
      
 109 
     | 
    
         
            +
                          let!(:null_expr) { "NULL" }
         
     | 
| 
      
 110 
     | 
    
         
            +
             
     | 
| 
      
 111 
     | 
    
         
            +
                          it 'shows nill as specified string' do
         
     | 
| 
      
 112 
     | 
    
         
            +
                            command.send(:show_result, job, file, nil, 'csv', { null_expr: null_expr })
         
     | 
| 
      
 113 
     | 
    
         
            +
                            File.read(file.path).should == %Q(NULL,2.0,"{""key"":3}"\n)
         
     | 
| 
      
 114 
     | 
    
         
            +
                          end
         
     | 
| 
      
 115 
     | 
    
         
            +
                        end
         
     | 
| 
      
 116 
     | 
    
         
            +
             
     | 
| 
      
 117 
     | 
    
         
            +
                        context 'specified string is empty string' do
         
     | 
| 
      
 118 
     | 
    
         
            +
                          let!(:null_expr) { '' }
         
     | 
| 
      
 119 
     | 
    
         
            +
             
     | 
| 
      
 120 
     | 
    
         
            +
                          it 'shows nill as empty string' do
         
     | 
| 
      
 121 
     | 
    
         
            +
                            command.send(:show_result, job, file, nil, 'csv', { null_expr: null_expr })
         
     | 
| 
      
 122 
     | 
    
         
            +
                            File.read(file.path).should == %Q("",2.0,"{""key"":3}"\n)
         
     | 
| 
      
 123 
     | 
    
         
            +
                          end
         
     | 
| 
      
 124 
     | 
    
         
            +
                        end
         
     | 
| 
      
 125 
     | 
    
         
            +
                      end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                      it 'supports tsv output' do
         
     | 
| 
      
 128 
     | 
    
         
            +
                        command.send(:show_result, job, file, nil, 'tsv', { null_expr: "\"\"" })
         
     | 
| 
      
 129 
     | 
    
         
            +
                        File.read(file.path).should == %Q(""\t2.0\t{"key":3}\n)
         
     | 
| 
      
 130 
     | 
    
         
            +
                      end
         
     | 
| 
      
 131 
     | 
    
         
            +
                    end
         
     | 
| 
       36 
132 
     | 
    
         
             
                  end
         
     | 
| 
       37 
133 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
                   
     | 
| 
       39 
     | 
    
         
            -
             
     | 
| 
       40 
     | 
    
         
            -
                     
     | 
| 
       41 
     | 
    
         
            -
             
     | 
| 
      
 134 
     | 
    
         
            +
                  context 'without NaN/Infinity' do
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                    it 'supports json output' do
         
     | 
| 
      
 137 
     | 
    
         
            +
                      command.send(:show_result, job, file, nil, 'json')
         
     | 
| 
      
 138 
     | 
    
         
            +
                      File.read(file.path).should == %Q([["1",2.0,{"key":3}],\n["4",5.0,{"key":6}],\n["7",8.0,{"key":9}]])
         
     | 
| 
      
 139 
     | 
    
         
            +
                    end
         
     | 
| 
      
 140 
     | 
    
         
            +
             
     | 
| 
      
 141 
     | 
    
         
            +
                    it 'supports csv output' do
         
     | 
| 
      
 142 
     | 
    
         
            +
                      command.send(:show_result, job, file, nil, 'csv')
         
     | 
| 
      
 143 
     | 
    
         
            +
                      File.read(file.path).should == %Q(1,2.0,"{""key"":3}"\n4,5.0,"{""key"":6}"\n7,8.0,"{""key"":9}"\n)
         
     | 
| 
      
 144 
     | 
    
         
            +
                    end
         
     | 
| 
      
 145 
     | 
    
         
            +
             
     | 
| 
      
 146 
     | 
    
         
            +
                    it 'supports tsv output' do
         
     | 
| 
      
 147 
     | 
    
         
            +
                      command.send(:show_result, job, file, nil, 'tsv')
         
     | 
| 
      
 148 
     | 
    
         
            +
                      File.read(file.path).should == %Q(1\t2.0\t{"key":3}\n4\t5.0\t{"key":6}\n7\t8.0\t{"key":9}\n)
         
     | 
| 
      
 149 
     | 
    
         
            +
                    end
         
     | 
| 
      
 150 
     | 
    
         
            +
                  end
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
                  context 'with NaN/Infinity' do
         
     | 
| 
      
 153 
     | 
    
         
            +
                    let :job do
         
     | 
| 
      
 154 
     | 
    
         
            +
                      job = TreasureData::Job.new(nil, 12345, 'hive', 'select * from employee')
         
     | 
| 
      
 155 
     | 
    
         
            +
                      job.instance_eval do
         
     | 
| 
      
 156 
     | 
    
         
            +
                        @result = [[[0.0/0.0, 1.0/0.0, 1.0/-0.0], 1], [["4", 5.0, {key:6}], 2], [["7", 8.0, {key:9}], 3]]
         
     | 
| 
      
 157 
     | 
    
         
            +
                        @result_size = 3
         
     | 
| 
      
 158 
     | 
    
         
            +
                        @status = 'success'
         
     | 
| 
      
 159 
     | 
    
         
            +
                      end
         
     | 
| 
      
 160 
     | 
    
         
            +
                      job
         
     | 
| 
      
 161 
     | 
    
         
            +
                    end
         
     | 
| 
      
 162 
     | 
    
         
            +
             
     | 
| 
      
 163 
     | 
    
         
            +
                    it 'does not support json output' do
         
     | 
| 
      
 164 
     | 
    
         
            +
                      expect { command.send(:show_result, job, file, nil, 'json') }.to raise_error Yajl::EncodeError
         
     | 
| 
      
 165 
     | 
    
         
            +
                    end
         
     | 
| 
      
 166 
     | 
    
         
            +
             
     | 
| 
      
 167 
     | 
    
         
            +
                    it 'supports csv output' do
         
     | 
| 
      
 168 
     | 
    
         
            +
                      command.send(:show_result, job, file, nil, 'csv')
         
     | 
| 
      
 169 
     | 
    
         
            +
                      File.read(file.path).should == %Q("""NaN""","""Infinity""","""-Infinity"""\n4,5.0,"{""key"":6}"\n7,8.0,"{""key"":9}"\n)
         
     | 
| 
      
 170 
     | 
    
         
            +
                    end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                    it 'supports tsv output' do
         
     | 
| 
      
 173 
     | 
    
         
            +
                      command.send(:show_result, job, file, nil, 'tsv')
         
     | 
| 
      
 174 
     | 
    
         
            +
                      File.read(file.path).should == %Q("NaN"\t"Infinity"\t"-Infinity"\n4\t5.0\t{"key":6}\n7\t8.0\t{"key":9}\n)
         
     | 
| 
      
 175 
     | 
    
         
            +
                    end
         
     | 
| 
      
 176 
     | 
    
         
            +
                  end
         
     | 
| 
      
 177 
     | 
    
         
            +
                end
         
     | 
| 
      
 178 
     | 
    
         
            +
             
     | 
| 
      
 179 
     | 
    
         
            +
                describe '#job_show' do
         
     | 
| 
      
 180 
     | 
    
         
            +
                  let(:job_id) { "12345" }
         
     | 
| 
      
 181 
     | 
    
         
            +
             
     | 
| 
      
 182 
     | 
    
         
            +
                  let :job_classs do
         
     | 
| 
      
 183 
     | 
    
         
            +
                    Struct.new(:job_id,
         
     | 
| 
      
 184 
     | 
    
         
            +
                               :status,
         
     | 
| 
      
 185 
     | 
    
         
            +
                               :type,
         
     | 
| 
      
 186 
     | 
    
         
            +
                               :db_name,
         
     | 
| 
      
 187 
     | 
    
         
            +
                               :priority,
         
     | 
| 
      
 188 
     | 
    
         
            +
                               :retry_limit,
         
     | 
| 
      
 189 
     | 
    
         
            +
                               :result_url,
         
     | 
| 
      
 190 
     | 
    
         
            +
                               :query,
         
     | 
| 
      
 191 
     | 
    
         
            +
                               :cpu_time,
         
     | 
| 
      
 192 
     | 
    
         
            +
                               :result_size
         
     | 
| 
      
 193 
     | 
    
         
            +
                              )
         
     | 
| 
      
 194 
     | 
    
         
            +
                  end
         
     | 
| 
      
 195 
     | 
    
         
            +
             
     | 
| 
      
 196 
     | 
    
         
            +
                  let :job do
         
     | 
| 
      
 197 
     | 
    
         
            +
                    job_classs.new(job_id,
         
     | 
| 
      
 198 
     | 
    
         
            +
                                   nil,
         
     | 
| 
      
 199 
     | 
    
         
            +
                                   :hive,
         
     | 
| 
      
 200 
     | 
    
         
            +
                                   "db_name",
         
     | 
| 
      
 201 
     | 
    
         
            +
                                   1,
         
     | 
| 
      
 202 
     | 
    
         
            +
                                   1,
         
     | 
| 
      
 203 
     | 
    
         
            +
                                   "test_url",
         
     | 
| 
      
 204 
     | 
    
         
            +
                                   "test_qury",
         
     | 
| 
      
 205 
     | 
    
         
            +
                                   1,
         
     | 
| 
      
 206 
     | 
    
         
            +
                                   3
         
     | 
| 
      
 207 
     | 
    
         
            +
                                  )
         
     | 
| 
      
 208 
     | 
    
         
            +
                  end
         
     | 
| 
      
 209 
     | 
    
         
            +
             
     | 
| 
      
 210 
     | 
    
         
            +
                  before do
         
     | 
| 
      
 211 
     | 
    
         
            +
                    job.stub(:finished?).and_return(true)
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                    client = Object.new
         
     | 
| 
      
 214 
     | 
    
         
            +
                    client.stub(:job).with(job_id).and_return(job)
         
     | 
| 
      
 215 
     | 
    
         
            +
                    command.stub(:get_client).and_return(client)
         
     | 
| 
      
 216 
     | 
    
         
            +
                  end
         
     | 
| 
      
 217 
     | 
    
         
            +
             
     | 
| 
      
 218 
     | 
    
         
            +
                  context 'without --null option' do
         
     | 
| 
      
 219 
     | 
    
         
            +
                    it 'calls #show_result without null_expr option' do
         
     | 
| 
      
 220 
     | 
    
         
            +
                      command.stub(:show_result).with(job, nil, nil, nil, {:header=>false})
         
     | 
| 
      
 221 
     | 
    
         
            +
                      op = List::CommandParser.new("job:show", %w[job_id], %w[], nil, ["12345"], true)
         
     | 
| 
      
 222 
     | 
    
         
            +
                      command.job_show(op)
         
     | 
| 
      
 223 
     | 
    
         
            +
                    end
         
     | 
| 
      
 224 
     | 
    
         
            +
                  end
         
     | 
| 
      
 225 
     | 
    
         
            +
             
     | 
| 
      
 226 
     | 
    
         
            +
                  context 'with --null option' do
         
     | 
| 
      
 227 
     | 
    
         
            +
                    it 'calls #show_result with null_expr option' do
         
     | 
| 
      
 228 
     | 
    
         
            +
                      command.stub(:show_result).with(job, nil, nil, nil, {:header=>false, :null_expr=>"NULL"} )
         
     | 
| 
      
 229 
     | 
    
         
            +
                      op = List::CommandParser.new("job:show", %w[job_id], %w[], nil, ["12345", "--null", "NULL"], true)
         
     | 
| 
      
 230 
     | 
    
         
            +
                      command.job_show(op)
         
     | 
| 
      
 231 
     | 
    
         
            +
                    end
         
     | 
| 
      
 232 
     | 
    
         
            +
             
     | 
| 
      
 233 
     | 
    
         
            +
                    it 'calls #show_result with null_expr option' do
         
     | 
| 
      
 234 
     | 
    
         
            +
                      command.stub(:show_result).with(job, nil, nil, nil, {:header=>false, :null_expr=>'""'} )
         
     | 
| 
      
 235 
     | 
    
         
            +
                      op = List::CommandParser.new("job:show", %w[job_id], %w[], nil, ["12345", "--null", '""'], true)
         
     | 
| 
      
 236 
     | 
    
         
            +
                      command.job_show(op)
         
     | 
| 
      
 237 
     | 
    
         
            +
                    end
         
     | 
| 
       42 
238 
     | 
    
         
             
                  end
         
     | 
| 
       43 
239 
     | 
    
         
             
                end
         
     | 
| 
       44 
240 
     | 
    
         | 
| 
         
            File without changes
         
     | 
| 
         @@ -0,0 +1,186 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require 'spec_helper'
         
     | 
| 
      
 2 
     | 
    
         
            +
            require 'td/command/common'
         
     | 
| 
      
 3 
     | 
    
         
            +
            require 'td/config'
         
     | 
| 
      
 4 
     | 
    
         
            +
            require 'td/command/list'
         
     | 
| 
      
 5 
     | 
    
         
            +
            require 'td/command/table'
         
     | 
| 
      
 6 
     | 
    
         
            +
            require 'td/client/model'
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
            module TreasureData::Command
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
              describe 'table command' do
         
     | 
| 
      
 11 
     | 
    
         
            +
                describe 'table_list' do
         
     | 
| 
      
 12 
     | 
    
         
            +
                  it 'lists tables in a database' do
         
     | 
| 
      
 13 
     | 
    
         
            +
                    client = Object.new
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    db = TreasureData::Database.new(client, 'full_access_db', nil, 1000, Time.now.to_i, Time.now.to_i, nil, 'full_access')
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    create_tables = lambda {|db_name|
         
     | 
| 
      
 18 
     | 
    
         
            +
                      (1..6).map {|i|
         
     | 
| 
      
 19 
     | 
    
         
            +
                        schema = TreasureData::Schema.new.from_json(JSON.parse('[]'))
         
     | 
| 
      
 20 
     | 
    
         
            +
                        TreasureData::Table.new(client, db_name, db_name + "_table_#{i}", 'log', schema, 500, Time.now.to_i, Time.now.to_i, 0, nil, nil, nil, nil, nil)
         
     | 
| 
      
 21 
     | 
    
         
            +
                      }
         
     | 
| 
      
 22 
     | 
    
         
            +
                    }
         
     | 
| 
      
 23 
     | 
    
         
            +
                    db_tables = create_tables.call(db.name)
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    client.stub(:tables).with(db.name).and_return(db_tables)
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
                    command = Class.new { include TreasureData::Command }.new
         
     | 
| 
      
 28 
     | 
    
         
            +
                    command.stub(:get_client).and_return(client)
         
     | 
| 
      
 29 
     | 
    
         
            +
                    command.stub(:get_database).and_return(db)
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
                    op = List::CommandParser.new('table:list', %w[], %w[db], false, %w(full_access_db), true)
         
     | 
| 
      
 32 
     | 
    
         
            +
                    expect {
         
     | 
| 
      
 33 
     | 
    
         
            +
                      command.table_list(op)
         
     | 
| 
      
 34 
     | 
    
         
            +
                    }.to_not raise_exception
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  it 'lists all tables in all databases' do
         
     | 
| 
      
 38 
     | 
    
         
            +
                    client = Object.new
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                    qo_db = TreasureData::Database.new(client, 'query_only_db', nil, 2000, Time.now.to_i, Time.now.to_i, nil, 'query_only')
         
     | 
| 
      
 41 
     | 
    
         
            +
                    fa_db = TreasureData::Database.new(client, 'full_access_db', nil, 3000, Time.now.to_i, Time.now.to_i, nil, 'full_access')
         
     | 
| 
      
 42 
     | 
    
         
            +
                    own_db = TreasureData::Database.new(client, 'owner_db', nil, 4000, Time.now.to_i, Time.now.to_i, nil, 'owner')
         
     | 
| 
      
 43 
     | 
    
         
            +
             
     | 
| 
      
 44 
     | 
    
         
            +
                    create_tables = lambda {|db_name|
         
     | 
| 
      
 45 
     | 
    
         
            +
                      (1..6).map {|i|
         
     | 
| 
      
 46 
     | 
    
         
            +
                        schema = TreasureData::Schema.new.from_json(JSON.parse('[]'))
         
     | 
| 
      
 47 
     | 
    
         
            +
                        TreasureData::Table.new(client, db_name, db_name + "_table_#{i}", 'log', schema, 500, Time.now.to_i, Time.now.to_i, 0, nil, nil, nil, nil, nil)
         
     | 
| 
      
 48 
     | 
    
         
            +
                      }
         
     | 
| 
      
 49 
     | 
    
         
            +
                    }
         
     | 
| 
      
 50 
     | 
    
         
            +
                    qo_db_tables = create_tables.call(qo_db.name)
         
     | 
| 
      
 51 
     | 
    
         
            +
                    fa_db_tables = create_tables.call(fa_db.name)
         
     | 
| 
      
 52 
     | 
    
         
            +
                    own_db_tables = create_tables.call(own_db.name)
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
                    client.stub(:databases).and_return([qo_db, fa_db, own_db])
         
     | 
| 
      
 55 
     | 
    
         
            +
             
     | 
| 
      
 56 
     | 
    
         
            +
                    client.stub(:tables).with(qo_db.name).and_return(qo_db_tables)
         
     | 
| 
      
 57 
     | 
    
         
            +
                    client.stub(:tables).with(fa_db.name).and_return(fa_db_tables)
         
     | 
| 
      
 58 
     | 
    
         
            +
                    client.stub(:tables).with(own_db.name).and_return(own_db_tables)
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
                    command = Class.new { include TreasureData::Command }.new
         
     | 
| 
      
 61 
     | 
    
         
            +
                    command.stub(:get_client).and_return(client)
         
     | 
| 
      
 62 
     | 
    
         
            +
             
     | 
| 
      
 63 
     | 
    
         
            +
                    op = List::CommandParser.new('table:list', %w[], %w[db], false, %w(), true)
         
     | 
| 
      
 64 
     | 
    
         
            +
                    expect {
         
     | 
| 
      
 65 
     | 
    
         
            +
                      command.table_list(op)
         
     | 
| 
      
 66 
     | 
    
         
            +
                    }.to_not raise_exception
         
     | 
| 
      
 67 
     | 
    
         
            +
                  end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
                  it 'avoids listing tables of an \'import_only\' database' do
         
     | 
| 
      
 70 
     | 
    
         
            +
                    client = Object.new
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    db = TreasureData::Database.new(client, 'import_only_db', nil, 1234, Time.now.to_i, Time.now.to_i, nil, 'import_only')
         
     | 
| 
      
 73 
     | 
    
         
            +
             
     | 
| 
      
 74 
     | 
    
         
            +
                    command = Class.new { include TreasureData::Command }.new
         
     | 
| 
      
 75 
     | 
    
         
            +
                    command.stub(:get_client).and_return(client)
         
     | 
| 
      
 76 
     | 
    
         
            +
                    command.stub(:get_database).and_return(db)
         
     | 
| 
      
 77 
     | 
    
         
            +
             
     | 
| 
      
 78 
     | 
    
         
            +
                    op = List::CommandParser.new('table:list', %w[], %w[db], false, %w(import_only_db), true)
         
     | 
| 
      
 79 
     | 
    
         
            +
                    expect {
         
     | 
| 
      
 80 
     | 
    
         
            +
                      command.table_list(op)
         
     | 
| 
      
 81 
     | 
    
         
            +
                    }.to_not raise_exception
         
     | 
| 
      
 82 
     | 
    
         
            +
                  end
         
     | 
| 
      
 83 
     | 
    
         
            +
             
     | 
| 
      
 84 
     | 
    
         
            +
                  it 'avoids listing tables of the \'import_only\' databases in the list' do
         
     | 
| 
      
 85 
     | 
    
         
            +
                    client = Object.new
         
     | 
| 
      
 86 
     | 
    
         
            +
             
     | 
| 
      
 87 
     | 
    
         
            +
                    io_db = TreasureData::Database.new(client, 'import_only_db', nil, 1000, Time.now.to_i, Time.now.to_i, nil, 'import_only')
         
     | 
| 
      
 88 
     | 
    
         
            +
                    qo_db = TreasureData::Database.new(client, 'query_only_db', nil, 2000, Time.now.to_i, Time.now.to_i, nil, 'query_only')
         
     | 
| 
      
 89 
     | 
    
         
            +
                    fa_db = TreasureData::Database.new(client, 'full_access_db', nil, 3000, Time.now.to_i, Time.now.to_i, nil, 'full_access')
         
     | 
| 
      
 90 
     | 
    
         
            +
                    own_db = TreasureData::Database.new(client, 'owner_db', nil, 4000, Time.now.to_i, Time.now.to_i, nil, 'owner')
         
     | 
| 
      
 91 
     | 
    
         
            +
             
     | 
| 
      
 92 
     | 
    
         
            +
                    create_tables = lambda {|db_name|
         
     | 
| 
      
 93 
     | 
    
         
            +
                      (1..6).map {|i|
         
     | 
| 
      
 94 
     | 
    
         
            +
                        schema = TreasureData::Schema.new.from_json(JSON.parse('[]'))
         
     | 
| 
      
 95 
     | 
    
         
            +
                        TreasureData::Table.new(client, db_name, db_name + "_table_#{i}", 'log', schema, 500, Time.now.to_i, Time.now.to_i, 0, nil, nil, nil, nil, nil)
         
     | 
| 
      
 96 
     | 
    
         
            +
                      }
         
     | 
| 
      
 97 
     | 
    
         
            +
                    }
         
     | 
| 
      
 98 
     | 
    
         
            +
                    qo_db_tables = create_tables.call(qo_db.name)
         
     | 
| 
      
 99 
     | 
    
         
            +
                    fa_db_tables = create_tables.call(fa_db.name)
         
     | 
| 
      
 100 
     | 
    
         
            +
                    own_db_tables = create_tables.call(own_db.name)
         
     | 
| 
      
 101 
     | 
    
         
            +
             
     | 
| 
      
 102 
     | 
    
         
            +
                    client.stub(:databases).and_return([io_db, qo_db, fa_db, own_db])
         
     | 
| 
      
 103 
     | 
    
         
            +
             
     | 
| 
      
 104 
     | 
    
         
            +
                    client.stub(:tables).with(io_db.name).and_raise("not permitted")
         
     | 
| 
      
 105 
     | 
    
         
            +
                    client.stub(:tables).with(qo_db.name).and_return(qo_db_tables)
         
     | 
| 
      
 106 
     | 
    
         
            +
                    client.stub(:tables).with(fa_db.name).and_return(fa_db_tables)
         
     | 
| 
      
 107 
     | 
    
         
            +
                    client.stub(:tables).with(own_db.name).and_return(own_db_tables)
         
     | 
| 
      
 108 
     | 
    
         
            +
             
     | 
| 
      
 109 
     | 
    
         
            +
                    command = Class.new { include TreasureData::Command }.new
         
     | 
| 
      
 110 
     | 
    
         
            +
                    command.stub(:get_client).and_return(client)
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                    op = List::CommandParser.new('table:list', %w[], %w[db], false, %w(), true)
         
     | 
| 
      
 113 
     | 
    
         
            +
                    expect {
         
     | 
| 
      
 114 
     | 
    
         
            +
                      command.table_list(op)
         
     | 
| 
      
 115 
     | 
    
         
            +
                    }.to_not raise_exception
         
     | 
| 
      
 116 
     | 
    
         
            +
                  end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                  describe "number format" do
         
     | 
| 
      
 119 
     | 
    
         
            +
                    let(:number_raw) { "1234567" }
         
     | 
| 
      
 120 
     | 
    
         
            +
                    let(:number_format) { "1,234,567" }
         
     | 
| 
      
 121 
     | 
    
         
            +
                    let(:client) { double('null object').as_null_object }
         
     | 
| 
      
 122 
     | 
    
         
            +
                    let(:db) { TreasureData::Database.new(client, 'full_access_db', nil, 1000, Time.now.to_i, Time.now.to_i, nil, 'full_access') }
         
     | 
| 
      
 123 
     | 
    
         
            +
                    let(:command) do
         
     | 
| 
      
 124 
     | 
    
         
            +
                      command = Class.new { include TreasureData::Command }.new
         
     | 
| 
      
 125 
     | 
    
         
            +
                      command.stub(:get_client).and_return(client)
         
     | 
| 
      
 126 
     | 
    
         
            +
                      command.stub(:get_database).and_return(db)
         
     | 
| 
      
 127 
     | 
    
         
            +
                      command
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    before do
         
     | 
| 
      
 131 
     | 
    
         
            +
                      create_tables = lambda {|db_name|
         
     | 
| 
      
 132 
     | 
    
         
            +
                        (1..6).map {|i|
         
     | 
| 
      
 133 
     | 
    
         
            +
                          # NOTE: TreasureData::Helpers.format_with_delimiter uses `gsub!` to their argument
         
     | 
| 
      
 134 
     | 
    
         
            +
                          #       the argument (in our case, `number_raw`) will be rewritten by them
         
     | 
| 
      
 135 
     | 
    
         
            +
                          #       To avoid that behavior, pass `number_raw.dup` instead of `number_raw`
         
     | 
| 
      
 136 
     | 
    
         
            +
                          schema = TreasureData::Schema.new.from_json(JSON.parse('[]'))
         
     | 
| 
      
 137 
     | 
    
         
            +
                          TreasureData::Table.new(client, db_name, db_name + "_table_#{i}", 'log', schema, number_raw.dup, Time.now.to_i, Time.now.to_i, 0, nil, nil, nil, nil, nil)
         
     | 
| 
      
 138 
     | 
    
         
            +
                        }
         
     | 
| 
      
 139 
     | 
    
         
            +
                      }
         
     | 
| 
      
 140 
     | 
    
         
            +
                      db_tables = create_tables.call(db.name)
         
     | 
| 
      
 141 
     | 
    
         
            +
                      client.stub(:tables).with(db.name).and_return(db_tables)
         
     | 
| 
      
 142 
     | 
    
         
            +
                    end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
      
 144 
     | 
    
         
            +
                    subject do
         
     | 
| 
      
 145 
     | 
    
         
            +
                      # command.table_list uses `puts` to display result
         
     | 
| 
      
 146 
     | 
    
         
            +
                      # so temporary swapping $stdout with StringIO to fetch their output
         
     | 
| 
      
 147 
     | 
    
         
            +
                      backup = $stdout.dup
         
     | 
| 
      
 148 
     | 
    
         
            +
                      buf = StringIO.new
         
     | 
| 
      
 149 
     | 
    
         
            +
                      op = List::CommandParser.new('table:list', [], %w[db], false, options + %w(full_access_db), true)
         
     | 
| 
      
 150 
     | 
    
         
            +
                      begin
         
     | 
| 
      
 151 
     | 
    
         
            +
                        $stdout = buf
         
     | 
| 
      
 152 
     | 
    
         
            +
                        command.table_list(op)
         
     | 
| 
      
 153 
     | 
    
         
            +
                        $stdout.rewind
         
     | 
| 
      
 154 
     | 
    
         
            +
                        $stdout.read
         
     | 
| 
      
 155 
     | 
    
         
            +
                      ensure
         
     | 
| 
      
 156 
     | 
    
         
            +
                        $stdout = backup
         
     | 
| 
      
 157 
     | 
    
         
            +
                      end
         
     | 
| 
      
 158 
     | 
    
         
            +
                    end
         
     | 
| 
      
 159 
     | 
    
         
            +
             
     | 
| 
      
 160 
     | 
    
         
            +
                    context "without --format" do
         
     | 
| 
      
 161 
     | 
    
         
            +
                      let(:options) { [] }
         
     | 
| 
      
 162 
     | 
    
         
            +
                      it { should include(number_format) }
         
     | 
| 
      
 163 
     | 
    
         
            +
                      it { should_not include(number_raw) }
         
     | 
| 
      
 164 
     | 
    
         
            +
                    end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                    context "with --format table" do
         
     | 
| 
      
 167 
     | 
    
         
            +
                      let(:options) { %w(--format table) }
         
     | 
| 
      
 168 
     | 
    
         
            +
                      it { should include(number_format) }
         
     | 
| 
      
 169 
     | 
    
         
            +
                      it { should_not include(number_raw) }
         
     | 
| 
      
 170 
     | 
    
         
            +
                    end
         
     | 
| 
      
 171 
     | 
    
         
            +
             
     | 
| 
      
 172 
     | 
    
         
            +
                    context "with --format csv" do
         
     | 
| 
      
 173 
     | 
    
         
            +
                      let(:options) { %w(--format csv) }
         
     | 
| 
      
 174 
     | 
    
         
            +
                      it { should_not include(number_format) }
         
     | 
| 
      
 175 
     | 
    
         
            +
                      it { should include(number_raw) }
         
     | 
| 
      
 176 
     | 
    
         
            +
                    end
         
     | 
| 
      
 177 
     | 
    
         
            +
             
     | 
| 
      
 178 
     | 
    
         
            +
                    context "with --format tsv" do
         
     | 
| 
      
 179 
     | 
    
         
            +
                      let(:options) { %w(--format tsv) }
         
     | 
| 
      
 180 
     | 
    
         
            +
                      it { should_not include(number_format) }
         
     | 
| 
      
 181 
     | 
    
         
            +
                      it { should include(number_raw) }
         
     | 
| 
      
 182 
     | 
    
         
            +
                    end
         
     | 
| 
      
 183 
     | 
    
         
            +
                  end
         
     | 
| 
      
 184 
     | 
    
         
            +
                end
         
     | 
| 
      
 185 
     | 
    
         
            +
              end
         
     | 
| 
      
 186 
     | 
    
         
            +
            end
         
     | 
    
        data/spec/td/updater_spec.rb
    CHANGED
    
    | 
         @@ -105,6 +105,42 @@ module TreasureData::Updater 
     | 
|
| 
       105 
105 
     | 
    
         
             
                  end
         
     | 
| 
       106 
106 
     | 
    
         
             
                end
         
     | 
| 
       107 
107 
     | 
    
         | 
| 
      
 108 
     | 
    
         
            +
                describe "current working directory doesn't change after call `jar_update`" do
         
     | 
| 
      
 109 
     | 
    
         
            +
                  shared_examples_for("jar_update behavior") do
         
     | 
| 
      
 110 
     | 
    
         
            +
                    it "doesn't change cwd" do 
         
     | 
| 
      
 111 
     | 
    
         
            +
                      with_env('TD_TOOLBELT_JARUPDATE_ROOT', "https://localhost:#{@server.config[:Port]}") do
         
     | 
| 
      
 112 
     | 
    
         
            +
                        pwd = Dir.pwd
         
     | 
| 
      
 113 
     | 
    
         
            +
                        subject
         
     | 
| 
      
 114 
     | 
    
         
            +
                        expect(Dir.pwd).to eq pwd
         
     | 
| 
      
 115 
     | 
    
         
            +
                      end
         
     | 
| 
      
 116 
     | 
    
         
            +
                    end
         
     | 
| 
      
 117 
     | 
    
         
            +
             
     | 
| 
      
 118 
     | 
    
         
            +
                    it "don't exists td-import.jar.new" do
         
     | 
| 
      
 119 
     | 
    
         
            +
                      with_env('TD_TOOLBELT_JARUPDATE_ROOT', "https://localhost:#{@server.config[:Port]}") do
         
     | 
| 
      
 120 
     | 
    
         
            +
                        subject
         
     | 
| 
      
 121 
     | 
    
         
            +
                      end
         
     | 
| 
      
 122 
     | 
    
         
            +
                      tmpfile = File.join(TreasureData::Updater.jarfile_dest_path, 'td-import.jar.new')
         
     | 
| 
      
 123 
     | 
    
         
            +
                      expect(File.exists?(tmpfile)).to eq false
         
     | 
| 
      
 124 
     | 
    
         
            +
                    end
         
     | 
| 
      
 125 
     | 
    
         
            +
                  end
         
     | 
| 
      
 126 
     | 
    
         
            +
             
     | 
| 
      
 127 
     | 
    
         
            +
                  let(:updater) { JarUpdateTester.new }
         
     | 
| 
      
 128 
     | 
    
         
            +
             
     | 
| 
      
 129 
     | 
    
         
            +
                  subject { updater.kick }
         
     | 
| 
      
 130 
     | 
    
         
            +
             
     | 
| 
      
 131 
     | 
    
         
            +
                  context "not updated" do
         
     | 
| 
      
 132 
     | 
    
         
            +
                    before { updater.stub(:existent_jar_updated_time).and_return(Time.now) }
         
     | 
| 
      
 133 
     | 
    
         
            +
             
     | 
| 
      
 134 
     | 
    
         
            +
                    it_behaves_like "jar_update behavior"
         
     | 
| 
      
 135 
     | 
    
         
            +
                  end
         
     | 
| 
      
 136 
     | 
    
         
            +
             
     | 
| 
      
 137 
     | 
    
         
            +
                  context "updated" do
         
     | 
| 
      
 138 
     | 
    
         
            +
                    before { updater.stub(:existent_jar_updated_time).and_return(Time.at(0)) }
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                    it_behaves_like "jar_update behavior"
         
     | 
| 
      
 141 
     | 
    
         
            +
                  end
         
     | 
| 
      
 142 
     | 
    
         
            +
                end
         
     | 
| 
      
 143 
     | 
    
         
            +
             
     | 
| 
       108 
144 
     | 
    
         
             
                def with_proxy
         
     | 
| 
       109 
145 
     | 
    
         
             
                  with_env('HTTP_PROXY', "http://localhost:#{@proxy_server.config[:Port]}") do
         
     | 
| 
       110 
146 
     | 
    
         
             
                    yield
         
     | 
| 
         @@ -185,7 +221,7 @@ module TreasureData::Updater 
     | 
|
| 
       185 
221 
     | 
    
         
             
                  res.body = '<metadata><versioning><lastUpdated>20141204123456</lastUpdated><release>version</release></versioning></metadata>'
         
     | 
| 
       186 
222 
     | 
    
         
             
                end
         
     | 
| 
       187 
223 
     | 
    
         | 
| 
       188 
     | 
    
         
            -
                def jar
         
     | 
| 
      
 224 
     | 
    
         
            +
                def jar(req, res)
         
     | 
| 
       189 
225 
     | 
    
         
             
                  res['content-type'] = 'application/octet-stream'
         
     | 
| 
       190 
226 
     | 
    
         
             
                  res.body = File.read(fixture_file('tmp.zip'))
         
     | 
| 
       191 
227 
     | 
    
         
             
                end
         
     | 
    
        data/td.gemspec
    CHANGED
    
    | 
         @@ -21,7 +21,7 @@ Gem::Specification.new do |gem| 
     | 
|
| 
       21 
21 
     | 
    
         
             
              gem.add_dependency "yajl-ruby", "~> 1.1"
         
     | 
| 
       22 
22 
     | 
    
         
             
              gem.add_dependency "hirb", ">= 0.4.5"
         
     | 
| 
       23 
23 
     | 
    
         
             
              gem.add_dependency "parallel", "~> 0.6.1"
         
     | 
| 
       24 
     | 
    
         
            -
              gem.add_dependency "td-client", "~> 0.8. 
     | 
| 
      
 24 
     | 
    
         
            +
              gem.add_dependency "td-client", "~> 0.8.69"
         
     | 
| 
       25 
25 
     | 
    
         
             
              gem.add_dependency "td-logger", "~> 0.3.21"
         
     | 
| 
       26 
26 
     | 
    
         
             
              gem.add_dependency "rubyzip", "~> 0.9.9"
         
     | 
| 
       27 
27 
     | 
    
         
             
              gem.add_development_dependency "rake", "~> 0.9"
         
     | 
    
        metadata
    CHANGED
    
    | 
         @@ -1,14 +1,14 @@ 
     | 
|
| 
       1 
1 
     | 
    
         
             
            --- !ruby/object:Gem::Specification
         
     | 
| 
       2 
2 
     | 
    
         
             
            name: td
         
     | 
| 
       3 
3 
     | 
    
         
             
            version: !ruby/object:Gem::Version
         
     | 
| 
       4 
     | 
    
         
            -
              version: 0.11. 
     | 
| 
      
 4 
     | 
    
         
            +
              version: 0.11.9
         
     | 
| 
       5 
5 
     | 
    
         
             
            platform: ruby
         
     | 
| 
       6 
6 
     | 
    
         
             
            authors:
         
     | 
| 
       7 
7 
     | 
    
         
             
            - Treasure Data, Inc.
         
     | 
| 
       8 
8 
     | 
    
         
             
            autorequire: 
         
     | 
| 
       9 
9 
     | 
    
         
             
            bindir: bin
         
     | 
| 
       10 
10 
     | 
    
         
             
            cert_chain: []
         
     | 
| 
       11 
     | 
    
         
            -
            date: 2015- 
     | 
| 
      
 11 
     | 
    
         
            +
            date: 2015-04-16 00:00:00.000000000 Z
         
     | 
| 
       12 
12 
     | 
    
         
             
            dependencies:
         
     | 
| 
       13 
13 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       14 
14 
     | 
    
         
             
              name: msgpack
         
     | 
| 
         @@ -102,14 +102,14 @@ dependencies: 
     | 
|
| 
       102 
102 
     | 
    
         
             
                requirements:
         
     | 
| 
       103 
103 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       104 
104 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       105 
     | 
    
         
            -
                    version: 0.8. 
     | 
| 
      
 105 
     | 
    
         
            +
                    version: 0.8.69
         
     | 
| 
       106 
106 
     | 
    
         
             
              type: :runtime
         
     | 
| 
       107 
107 
     | 
    
         
             
              prerelease: false
         
     | 
| 
       108 
108 
     | 
    
         
             
              version_requirements: !ruby/object:Gem::Requirement
         
     | 
| 
       109 
109 
     | 
    
         
             
                requirements:
         
     | 
| 
       110 
110 
     | 
    
         
             
                - - "~>"
         
     | 
| 
       111 
111 
     | 
    
         
             
                  - !ruby/object:Gem::Version
         
     | 
| 
       112 
     | 
    
         
            -
                    version: 0.8. 
     | 
| 
      
 112 
     | 
    
         
            +
                    version: 0.8.69
         
     | 
| 
       113 
113 
     | 
    
         
             
            - !ruby/object:Gem::Dependency
         
     | 
| 
       114 
114 
     | 
    
         
             
              name: td-logger
         
     | 
| 
       115 
115 
     | 
    
         
             
              requirement: !ruby/object:Gem::Requirement
         
     | 
| 
         @@ -204,6 +204,7 @@ files: 
     | 
|
| 
       204 
204 
     | 
    
         
             
            - lib/td/command/apikey.rb
         
     | 
| 
       205 
205 
     | 
    
         
             
            - lib/td/command/bulk_import.rb
         
     | 
| 
       206 
206 
     | 
    
         
             
            - lib/td/command/common.rb
         
     | 
| 
      
 207 
     | 
    
         
            +
            - lib/td/command/connector.rb
         
     | 
| 
       207 
208 
     | 
    
         
             
            - lib/td/command/db.rb
         
     | 
| 
       208 
209 
     | 
    
         
             
            - lib/td/command/export.rb
         
     | 
| 
       209 
210 
     | 
    
         
             
            - lib/td/command/help.rb
         
     | 
| 
         @@ -239,7 +240,8 @@ files: 
     | 
|
| 
       239 
240 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
       240 
241 
     | 
    
         
             
            - spec/td/command/import_spec.rb
         
     | 
| 
       241 
242 
     | 
    
         
             
            - spec/td/command/job_spec.rb
         
     | 
| 
       242 
     | 
    
         
            -
            - spec/td/ 
     | 
| 
      
 243 
     | 
    
         
            +
            - spec/td/command/sched_spec.rb
         
     | 
| 
      
 244 
     | 
    
         
            +
            - spec/td/command/table_spec.rb
         
     | 
| 
       243 
245 
     | 
    
         
             
            - spec/td/common_spec.rb
         
     | 
| 
       244 
246 
     | 
    
         
             
            - spec/td/fixture/ca.cert
         
     | 
| 
       245 
247 
     | 
    
         
             
            - spec/td/fixture/server.cert
         
     | 
| 
         @@ -282,7 +284,8 @@ test_files: 
     | 
|
| 
       282 
284 
     | 
    
         
             
            - spec/spec_helper.rb
         
     | 
| 
       283 
285 
     | 
    
         
             
            - spec/td/command/import_spec.rb
         
     | 
| 
       284 
286 
     | 
    
         
             
            - spec/td/command/job_spec.rb
         
     | 
| 
       285 
     | 
    
         
            -
            - spec/td/ 
     | 
| 
      
 287 
     | 
    
         
            +
            - spec/td/command/sched_spec.rb
         
     | 
| 
      
 288 
     | 
    
         
            +
            - spec/td/command/table_spec.rb
         
     | 
| 
       286 
289 
     | 
    
         
             
            - spec/td/common_spec.rb
         
     | 
| 
       287 
290 
     | 
    
         
             
            - spec/td/fixture/ca.cert
         
     | 
| 
       288 
291 
     | 
    
         
             
            - spec/td/fixture/server.cert
         
     |