quandl 0.3.7 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZDJmODE5YjMxZDJlNjFiNTZiN2I0NmVhMGYzMTIwZjU2YWFjZDIyYQ==
4
+ MWZhODVmN2E1YzI4MTVhNDdlZDBjNmExOWUzNDYzMDM3M2IwNTNhMw==
5
5
  data.tar.gz: !binary |-
6
- NDEwZmVhNGQ2YWE1YmYwYzM5ODZhY2I5MDI4N2Y5YjU1MmMyOWU0Mw==
6
+ ZTNhZmQ0OGI3MmNiNzQyZTQxYTA5YzYzMjQzMzcyN2QxNDVmMWNiOA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ZDE4YjcyM2Y0MTExMDE1MTYzZmY5ZDE1YzAzMTU1NmNhNzY0YTdiMmUwZjdj
10
- NzhiMjVjYmI4MWY5YzU5Y2U1NjE1MzRlZDU3ZDc5NmIwNDRlZTczNWQ4ODE5
11
- ODBlMDg1MzYzM2EyYmFlMzA5NmIzN2M5ZDJiZDNjOTUyZGI1YWE=
9
+ MDI5MjJhNDQwZjU5YTE1MmU0YTJjN2FiNDAwYWFkNmY2YTA2NTk3YzQ4ZTM5
10
+ OTIyYzAzZjhmNjYyNjJiYWNiYzBjOTgwMzA2OTkzZGIxMzkwOGVhODU0MGY1
11
+ MmEzNmZmZGZjZjJhZTA1ZmFhZGU2MjhhZTcwYzM1YmUwMDhkMDc=
12
12
  data.tar.gz: !binary |-
13
- YWYzYTViMWEzZjIxMTMzYzJhOWJjMDY3NDQ3NjdlYzhkMzAxMGJmZGFiNTkw
14
- MGRmM2Y3ODk4NzZlYjJiNDA0YmM4MzM5ODU2MTUwMTc0MWZiMTI0MDBiNjEw
15
- ZWZjNWNhN2UxN2ZiYzhmZWYwYjQxYTI5YzEzYjFkNTdjYTNmMTg=
13
+ MDM2MDRhOTRlMTkzN2I4ZTJlZGI0MGEwNGExMjVmNGE5MzdkMzYzOWRmN2Uy
14
+ Zjk1MDRlOTJkNmZjZTVjYmJmODRiNTE5MzczNDhlMGE4OTExMjI1NTQ0OGI4
15
+ ODBiMzA4ZjNjOTFjOWEzNTllMTU1ZTc2YzVhZDU0Zjc2YzRhMDY=
data/Rakefile CHANGED
@@ -12,10 +12,6 @@ Dir[File.expand_path("../tasks/*.rake", __FILE__)].each do |task|
12
12
  load task
13
13
  end
14
14
 
15
- task :console do |t,args|
16
- binding.pry
17
- end
18
-
19
15
  desc "Run all specs"
20
16
  RSpec::Core::RakeTask.new(:spec) do |task|
21
17
  task.pattern = "spec/**/*_spec.rb"
data/UPGRADE.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.4.0
2
+
3
+ * QUGC-166 fix quandl schedule list --token incorrect_token
4
+ * QUGC-182. OK -> Updated
5
+ * QUGC-164 fixes the issue
6
+
7
+
8
+
1
9
  ## 0.3.7
2
10
 
3
11
  * add production flag
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.7
1
+ 0.4.0
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="utf-8"?>
2
2
  <installer-script minSpecVersion="1.000000" authoringTool="org.ruby-lang.rake" authoringToolVersion="10.1.1">
3
- <title>Quandl Toolbelt <%= version %></title>
3
+ <title>Quandl Toolbelt <%= version %> <%= prerelease_information %></title>
4
4
  <options customize="allow" allow-external-scripts="no"/>
5
5
  <domains enable_localSystem="true"/>
6
6
  <choices-outline>
@@ -42,4 +42,6 @@ case $(which quandl) in
42
42
  esac
43
43
 
44
44
  # symlink binary to /usr/bin/quandl
45
- ln -sf /usr/local/quandl/bin/quandl /usr/bin/quandl
45
+ ln -sf /usr/local/quandl/releases/<%= timestamp %> /usr/local/quandl/current
46
+ chown -h $USER /usr/local/quandl/current
47
+ ln -sf /usr/local/quandl/bin/quandl /usr/bin/quandl
@@ -5,7 +5,7 @@ require "pathname"
5
5
  bin_file = Pathname.new(__FILE__).realpath
6
6
 
7
7
  # vendored gems path
8
- gem_dir = File.expand_path("../../vendor/gems", bin_file)
8
+ gem_dir = File.expand_path("../../current/vendor/gems", bin_file)
9
9
  # vendored gems?
10
10
  if Dir.exists?(gem_dir)
11
11
  Dir["#{gem_dir}/**/lib"].each do |libdir|
@@ -16,7 +16,7 @@ else
16
16
  end
17
17
 
18
18
  # add self to libpath
19
- $:.unshift File.expand_path("../../lib", bin_file)
19
+ $:.unshift File.expand_path("../../current/lib", bin_file)
20
20
 
21
21
  require 'quandl/command'
22
22
  require 'commander/import'
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: UTF-8
3
+
4
+ require "pathname"
5
+ bin_file = Pathname.new(__FILE__).realpath
6
+
7
+ # vendored gems path
8
+ gem_dir = File.expand_path("../../current/vendor/gems", bin_file)
9
+ # vendored gems?
10
+ if Dir.exists?(gem_dir)
11
+ Dir["#{gem_dir}/**/lib"].each do |libdir|
12
+ $:.unshift libdir
13
+ end
14
+ else
15
+ require 'rubygems'
16
+ end
17
+
18
+ # add self to libpath
19
+ $:.unshift File.expand_path("../../current/lib", bin_file)
20
+
21
+ require 'quandl/command'
22
+ require 'commander/import'
23
+ require 'commander/command/quandl_ext'
24
+
25
+ include Quandl::Command
@@ -38,7 +38,7 @@ module Quandl::Command
38
38
  global_option '--stdout STRING', 'where to redirect stdout'
39
39
  global_option '--stderr STRING', 'where to redirect stderr'
40
40
  global_option '--force-yes', 'force y/n with yes'
41
- global_option '--production', 'skip extra output'
41
+ global_option '--sandbox', 'sandbox specific default options'
42
42
 
43
43
  Tasks.each{|t| t.configure(self) }
44
44
 
@@ -44,6 +44,10 @@ class Config
44
44
  @auth_token = read_attribute(:token) if @auth_token.blank?
45
45
  @auth_token
46
46
  end
47
+
48
+ def request_platform
49
+ 'sandbox' if options[:sandbox].present?
50
+ end
47
51
 
48
52
  def file_path
49
53
  options[:file_path]
@@ -7,7 +7,7 @@ module Configurable
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- delegate :auth_token, :quandl_url, to: :config
10
+ delegate :auth_token, :request_platform, :quandl_url, to: :config
11
11
  end
12
12
 
13
13
  module ClassMethods
@@ -61,6 +61,7 @@ module Dependable
61
61
  Quandl::Client.token = auth_token
62
62
  Quandl::Client.request_source = 'quandl_command'
63
63
  Quandl::Client.request_version = Quandl::Command::VERSION
64
+ Quandl::Client.request_platform = request_platform
64
65
  end
65
66
 
66
67
  end
@@ -6,7 +6,7 @@ module Updatable
6
6
 
7
7
  extend ActiveSupport::Concern
8
8
 
9
- VERSION_URL="https://raw.github.com/quandl/quandl_command/master/lib/quandl/command/version.rb"
9
+ VERSION_URL="https://s3.amazonaws.com/quandl-command/VERSION"
10
10
 
11
11
  included do
12
12
  before_execute :check_for_update_once_daily
@@ -14,7 +14,7 @@ module Updatable
14
14
 
15
15
  def check_for_update_once_daily
16
16
  # short circuit
17
- return if options.production
17
+ return if options.sandbox
18
18
  # onwards
19
19
  check_time = config.last_checked_for_update
20
20
  # check time present?
@@ -38,8 +38,8 @@ module Updatable
38
38
  # handle output
39
39
  handle_update_response(response)
40
40
  rescue => err
41
- error("An unexpected error occured while checking for updates ... #{err}")
42
- error err.backtrace.join("\n") if trace?
41
+ info("An unexpected error occured while checking for updates ... #{err}")
42
+ info err.backtrace.join("\n") if trace?
43
43
  ensure
44
44
  config.last_checked_for_update = Time.now
45
45
  end
@@ -64,7 +64,7 @@ module Updatable
64
64
  # send request
65
65
  response = http.request(request)
66
66
  # fetch version number
67
- response.body.split("\n").detect{|r| r =~ /VERSION/ }.split("'").last
67
+ response.body.strip.rstrip
68
68
  end
69
69
 
70
70
  def handle_update_response(response)
@@ -1,34 +1,30 @@
1
1
  class Quandl::Command::Tasks::Schedule < Quandl::Command::Task
2
2
 
3
- depends 'chronic', 'whedon', 'open-uri'
3
+ depends 'chronic', 'whedon', 'open-uri', 'zlib', 'archive/tar/minitar'
4
4
 
5
5
  autoload_quandl_client
6
6
  authenticated_users_only!
7
7
 
8
8
  description "Schedule a script to be run in the quandl cloud."
9
- syntax %{quandl schedule command [file]
9
+ syntax %{quandl schedule command [file(s)]
10
10
 
11
11
  COMMANDS:
12
12
 
13
- schedule list [file]
14
- schedule add file [--at TIME]
15
- schedule delete file
16
- schedule replace file [--at NEW_TIME]
17
-
13
+ schedule list [FILE]
14
+ schedule add RUN_FILE [DEPENDENT_FILE1] [DEPENDENT_FILE2] [--at TIME]
15
+ schedule delete FILE
16
+
18
17
  EXAMPLES:
19
18
 
20
19
  $ quandl schedule add scraper.rb
21
20
  You have successfully scheduled scraper.rb.
22
21
 
23
- $ quandl schedule add scraper.rb --remote-name scraper.rb --at "7pm Monday"
24
- You have successfully scheduled scraper.rb. [weekly scraper]
25
-
26
- $ quandl schedule replace scraper.rb --at "13:00"
27
- You have successfully replaced scraper.rb. [daily scraper]}
28
-
22
+ $ quandl schedule add scraper.rb helper.txt helper2.txt --at "7pm Monday"
23
+ You have successfully scheduled scraper.rb to run alongside helper.txt, helper2.txt. [weekly scraper]
24
+ }
25
+
29
26
  options({
30
27
  String => {
31
- :'remote-name' => "The name used to reference your scraper in the quandl cloud.",
32
28
  at: "Time to run your script in UTC timezone. e.g. '14:30','7pm Monday', 'friday 13:00'"
33
29
  }
34
30
  })
@@ -41,7 +37,7 @@ class Quandl::Command::Tasks::Schedule < Quandl::Command::Task
41
37
  # fire a subcommand if specified
42
38
  return self.send(args.shift) if args.first.present? && self.respond_to?(args.first)
43
39
  # otherwise fire add
44
- return add if args.first.present?
40
+ return add if args.first.present? && args.first.downcase != "help"
45
41
  # otherwise display syntax
46
42
  info(syntax)
47
43
  end
@@ -56,18 +52,24 @@ class Quandl::Command::Tasks::Schedule < Quandl::Command::Task
56
52
  end
57
53
 
58
54
  def add
59
- result=Quandl::Client::Scraper.create( name: name, scraper: args.first, schedule_at: cron_at_utc)
60
- if result.valid?
61
- info("You have successfully scheduled '#{scraper.name}'.")
62
- info("#{schedule_message}")
63
- else
64
- error "#{Quandl::Command::Presenter.pretty_errors(result.errors.messages).to_s.gsub("\n", ' ')}"
55
+ upload_file = Tempfile.new('temp')
56
+ begin
57
+ result=Quandl::Client::Scraper.create( name: name, scraper: file_to_send(args, upload_file), schedule_at: cron_at_utc)
58
+ if result.valid?
59
+ info("You have successfully scheduled '#{scraper.name}'.")
60
+ info("#{schedule_message}")
61
+ else
62
+ error "#{Quandl::Command::Presenter.pretty_errors(result.errors.messages).to_s.gsub("\n", ' ')}"
63
+ end
64
+ ensure
65
+ upload_file.close!
65
66
  end
66
67
  end
67
68
 
68
69
  def download
69
70
  begin
70
- $stdout << open(scraper.scraper_url, {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
71
+ $stdout.binmode
72
+ $stdout << open(scraper.scraper_url, "rb", {ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE}).read
71
73
  rescue => err
72
74
  present err
73
75
  end
@@ -87,44 +89,41 @@ class Quandl::Command::Tasks::Schedule < Quandl::Command::Task
87
89
  end
88
90
 
89
91
 
92
+ #not supported for now
93
+ =begin
90
94
  def replace
91
- (info("'#{name}' does not exist "); return;) if scraper.blank?
92
- info("You are about to replace '#{scraper.name}'")
93
- return unless confirmed?
94
- scraper.scraper = args.first
95
- scraper.schedule_at = cron_at_utc
96
- scraper.save
97
- if scraper.valid?
98
- info("You have successfully replaced '#{scraper.name}'.")
99
- info("#{schedule_message}") if cron_at
100
- else
101
- error "#{Quandl::Command::Presenter.pretty_errors(scraper.errors.messages).to_s.gsub("\n", ' ')}"
95
+ upload_file = Tempfile.new('temp')
96
+ begin
97
+ (info("'#{name}' does not exist "); return;) if scraper.blank?
98
+ info("You are about to replace '#{scraper.name}'")
99
+ return unless confirmed?
100
+ scraper.scraper = file_to_send(args, upload_file)
101
+ scraper.schedule_at = cron_at_utc
102
+ scraper.save
103
+ if scraper.valid?
104
+ info("You have successfully replaced '#{scraper.name}'.")
105
+ info("#{schedule_message}") if cron_at
106
+ else
107
+ error "#{Quandl::Command::Presenter.pretty_errors(scraper.errors.messages).to_s.gsub("\n", ' ')}"
108
+ end
109
+ ensure
110
+ upload_file.close!
102
111
  end
103
112
  end
113
+ =end
104
114
 
105
115
  private
106
116
 
107
117
  def script_info(script)
108
- unless script.schedule_at.empty?
109
- info("#{(script.name+'.').ljust(20)} Scheduled: #{script_run_time(script.schedule_at)}")
110
- else
111
- info("#{(script.name+'.').ljust(20)} Scheduled: 3 times a day")
112
- end
113
- end
114
-
115
-
116
- def script_run_time(cron_time)
117
- "every #{cron_time.ends_with?('*') ? 'day' : DAYS_OF_THE_WEEK[cron_time[-1].to_i]} at #{script_next_run(cron_time).strftime("%H:%M (UTC)")}"
118
- end
119
-
120
- def script_next_run(cron_time)
121
- Whedon::Schedule.new(cron_time).next
118
+ message = script.name.to_s.ljust(20)
119
+ message += " Scheduled: #{script.schedule_run_time.to_s.ljust(30)}"
120
+ message += " Next: in #{script.schedule_next}" if script.schedule_next.present?
121
+ info message
122
122
  end
123
123
 
124
-
125
124
  def schedule_message
126
125
  if options.at
127
- "Your script first run will happen #{script_next_run(cron_at).strftime("on %d %B at %H:%M")}. It will continue to run #{script_run_time(cron_at_utc)}
126
+ "Your script first run will happen in #{scraper.schedule_next}. It will continue to run #{scraper.schedule_run_time}
128
127
  Check your scrapers run status at #{quandl_url.gsub(/\/api\/?/,'')}/scrapers"
129
128
  else
130
129
  "It will run 3 times a day starting immediately.\nCheck your scrapers run status at #{quandl_url.gsub(/\/api\/?/,'')}/scrapers"
@@ -159,11 +158,10 @@ Check your scrapers run status at #{quandl_url.gsub(/\/api\/?/,'')}/scrapers"
159
158
 
160
159
  def time_to_cron(time_value)
161
160
  day_of_the_week = options.at =~ (/Mon|Tue|Wed|Thu|Fri|Sat|Sun/i) ? time_value.wday : '*'
162
- "#{time_value.min} #{time_value.hour} * * #{day_of_the_week}"
161
+ "* #{time_value.min} #{time_value.hour} * * #{day_of_the_week}"
163
162
  end
164
163
 
165
164
  def name
166
- return options.remote_name if options.remote_name.present?
167
165
  return File.basename(args.first) if args.first.present?
168
166
  end
169
167
 
@@ -175,5 +173,15 @@ Check your scrapers run status at #{quandl_url.gsub(/\/api\/?/,'')}/scrapers"
175
173
  true
176
174
  end
177
175
 
176
+ def file_to_send(values, upload_file)
177
+ if [*values].count > 1
178
+ file = upload_file
179
+ Archive::Tar::Minitar.pack( values, Zlib::GzipWriter.new( File.new( file, 'wb' ) ) )
180
+ else
181
+ file = [*values].first
182
+ end
183
+ file
184
+ end
185
+
178
186
 
179
187
  end
@@ -1,8 +1,6 @@
1
1
  class Quandl::Command::Tasks::Update < Quandl::Command::Task
2
2
 
3
3
  depends 'uri', 'net/http', 'quandl/utility/config', 'zlib', 'archive/tar/minitar'
4
-
5
- # curl -s https://s3.amazonaws.com/quandl-command/install.sh | bash
6
4
 
7
5
  description "Update Quandl Toolbelt to the latest version."
8
6
  syntax %Q{quandl update [revision]
@@ -10,12 +8,12 @@ class Quandl::Command::Tasks::Update < Quandl::Command::Task
10
8
  EXAMPLES:
11
9
 
12
10
  $ quandl update
13
- Updating from 0.2.18 ...
14
- You are up to date! ( 0.3.1 )
11
+ Updating from a.b.c ...
12
+ You are up to date! ( x.y.z )
15
13
 
16
- $ quandl update beta1
17
- Updating from 0.3.1 ...
18
- You are up to date! ( 0.3.1-beta1 )}
14
+ $ quandl update prerelease
15
+ Updating from x.y.z ...
16
+ You are up to date! ( x.y.z-prerelease )}
19
17
 
20
18
  PACKAGE_URL = 'http://s3.amazonaws.com/quandl-command/'
21
19
 
@@ -33,6 +31,22 @@ class Quandl::Command::Tasks::Update < Quandl::Command::Task
33
31
  end
34
32
 
35
33
  def execute
34
+ if args[0] == 'rollback'
35
+ execute_rollback
36
+ else
37
+ execute_update
38
+ end
39
+ rescue => err
40
+ # log error
41
+ error(err)
42
+ debug(err.backtrace.join("\n"))
43
+ # report failure and rollback
44
+ error("----\nAn error has occured! Rolling back to previous version ... ")
45
+ error("If the problem persists reinstall with: #{installer_url}")
46
+ rollback_update
47
+ end
48
+
49
+ def execute_update
36
50
  info "Updating from #{Quandl::Command::VERSION} ... "
37
51
  # wipe update/ and backup/ folders
38
52
  prepare_for_update
@@ -41,22 +55,26 @@ class Quandl::Command::Tasks::Update < Quandl::Command::Task
41
55
  return error("'#{package_url}' not found") unless File.exists?(tarball_path)
42
56
  # install
43
57
  extract_tarball
44
- copy_windows_specific_files if Quandl::Utility::Config.windows?
45
58
  install_update
46
- configure_update
47
- ensure_correct_permissions
59
+ install_executable
48
60
  # success
49
61
  version = %x{quandl -v}.to_s.strip.rstrip
50
- info "You are up to date! ( #{version} )"
62
+ cleanup_releases
51
63
 
52
- rescue => err
53
- # log error
54
- info(err)
55
- debug(err.backtrace.join("\n"))
56
- # report failure and rollback
57
- info("----\nAn error has occured! Rolling back to previous version ... ")
58
- info("If the problem persists reinstall with: #{installer_url}")
59
- rollback_update
64
+ info "You are up to date! ( #{version} )"
65
+ end
66
+
67
+ def execute_rollback
68
+ info "Rolling back from #{current_timestamp} ... "
69
+ previous_timestamp = find_timestamp_before(current_timestamp)
70
+ if previous_timestamp.blank?
71
+ info("nothing to rollback to!")
72
+ return false
73
+ end
74
+ info "to: #{previous_timestamp}"
75
+ install_timestamp( previous_timestamp )
76
+ version = %x{quandl -v}.to_s.strip.rstrip
77
+ info "You have rolled back! ( #{version} )"
60
78
  end
61
79
 
62
80
  def installer_url
@@ -64,40 +82,12 @@ class Quandl::Command::Tasks::Update < Quandl::Command::Task
64
82
  return File.join(PACKAGE_URL, "quandl-toolbelt.pkg") if Quandl::Utility::Config.macosx?
65
83
  end
66
84
 
67
- def package_path
68
- @package_path ||= File.join(update_path, "quandl-command")
69
- end
70
-
71
- def tarball_path
72
- @tarball_path ||= File.join(update_path, "update.tar.gz")
73
- end
74
-
75
- def package_url
76
- @package_url ||= self.class.package_url(args.first)
77
- end
78
-
79
- def update_path
80
- @update_path ||= File.join( root_path, 'update' )
81
- end
82
-
83
- def backup_path
84
- @backup_path ||= File.join( root_path, 'backup' )
85
- end
86
-
87
- def root_path
88
- Quandl::Command::Tasks.root
89
- end
85
+ private
90
86
 
87
+ delegate :chmod, :cp, :ln_sf, :mv, :rm_rf, :rm, :mkdir_p, :cp_r, to: :qu
91
88
 
92
- private
93
-
94
89
  def prepare_for_update
95
- [backup_path, update_path].each do |path|
96
- # remove previous directory if present
97
- rm_rf(path) if Dir.exists?(path)
98
- # create new directory
99
- mkdir_p(path) unless Dir.exists?(path)
100
- end
90
+ FileUtils.mkdir_p(releases_path) unless Dir.exists?(releases_path)
101
91
  end
102
92
 
103
93
  def download_tarball
@@ -114,82 +104,146 @@ class Quandl::Command::Tasks::Update < Quandl::Command::Task
114
104
  end
115
105
 
116
106
  def extract_tarball
117
- debug "Archive::Tar::Minitar.unpack( '#{tarball_path}', '#{update_path}' )"
118
- # extract into update_path
119
- Archive::Tar::Minitar.unpack( Zlib::GzipReader.open(tarball_path), update_path )
107
+ debug "Archive::Tar::Minitar.unpack( '#{tarball_path}', '#{releases_path}' )"
108
+ # extract into releases_path
109
+ Archive::Tar::Minitar.unpack( Zlib::GzipReader.open(tarball_path), releases_path )
110
+ # rename quandl-command to release name
111
+ mv( package_path, timestamp_path )
120
112
  end
121
113
 
122
- def copy_windows_specific_files
123
- files = ['bin/quandl.bat']
124
- files.each do |file|
125
- source_path = File.join(root_path, file)
126
- cp source_path, File.join(package_path, file) if File.exists?(source_path)
127
- end
114
+ def install_update
115
+ install_timestamp(new_timestamp)
128
116
  end
129
117
 
130
- def install_update
131
- debug "Installing '#{update_path}' to '#{root_path}'"
132
- # install each folder into the live directory
133
- Dir.glob(File.join(package_path, "/*")) do |update_dir|
134
- # current folder
135
- folder_name = File.basename(update_dir)
136
- # get live dir
137
- live_dir = File.join(root_path, folder_name )
138
- # move live to backup (skip this step if it doesn't exist since it might be a new folder)
139
- mv live_dir, File.join(backup_path, folder_name) if File.exists?(live_dir)
140
- # move update to live
141
- mv update_dir, live_dir
118
+ def rollback_update
119
+ # remove the failed release
120
+ rm_rf(timestamp_path) if Dir.exists?(timestamp_path)
121
+ # install previous release
122
+ install_timestamp(current_timestamp)
123
+ end
124
+
125
+ def install_executable
126
+ new_executable = File.join(timestamp_path, 'pkg', 'quandl')
127
+ return unless File.exists?(new_executable)
128
+ rm executable_path if File.exists?(executable_path)
129
+ cp new_executable, executable_path
130
+ end
131
+
132
+ def install_timestamp(stamp)
133
+ # remove previous
134
+ rm_rf(current_path) if File.exists?(current_path)
135
+ # install timestamp
136
+ path = File.join( releases_path, stamp.to_s )
137
+ # copy or link
138
+ if Quandl::Utility::Config.windows?
139
+ cp_r(path, current_path)
140
+
141
+ else
142
+ ln_sf(path, current_path)
143
+
142
144
  end
145
+ update_current_timestamp(stamp)
143
146
  end
144
147
 
145
- def configure_update
146
- if Dir.exists?("#{root_path}/ruby")
147
- bin_file = File.read("#{root_path}/bin/quandl")
148
- bin_file.gsub!("#!/usr/bin/env ruby", "#!/#{root_path}/ruby/bin/ruby")
149
- File.write("#{root_path}/bin/quandl", bin_file)
150
- end
148
+ def update_current_timestamp(stamp)
149
+ File.open( timestamp_release_path, 'wb' ){|f| f.write(stamp.to_s) }
151
150
  end
152
151
 
153
- def rollback_update
154
- Dir.glob(File.join(backup_path, "/*")) do |backup_dir|
155
- # current folder
156
- folder_name = File.basename(backup_dir)
157
- # get live dir
158
- live_dir = File.join(root_path, folder_name )
159
- # move live to update
160
- mv live_dir, File.join(package_path, folder_name)
161
- # move backup to live
162
- mv backup_dir, live_dir
163
- end
152
+ def delete_timestamp(stamp)
153
+ path = File.join(releases_path, stamp.to_s)
154
+ rm_rf(path) if Dir.exists?(path)
155
+ end
156
+
157
+ def cleanup_releases
158
+ return unless release_timestamps.count > 5
159
+ release_timestamps.reverse[5..-1].each{|stamp| delete_timestamp(stamp) }
160
+ end
161
+
162
+ def executable_path
163
+ @executable_path ||= File.join(root_path, 'bin', 'quandl')
164
164
  end
165
165
 
166
- def ensure_correct_permissions
167
- chmod("+x", File.join(root_path, 'bin/quandl'))
166
+ def timestamp_release_path
167
+ @timestamp_release_path ||= File.join(root_path, '.timestamp')
168
168
  end
169
169
 
170
- def chmod(*args)
171
- debug("FileUtils.chmod #{args.to_a.join(' ')}")
172
- FileUtils.chmod(*args)
170
+ def timestamp_path
171
+ @timestamp_path ||= File.join( releases_path, new_timestamp )
172
+ end
173
+
174
+ def tarball_path
175
+ @tarball_path ||= File.join(releases_path, "update.tar.gz")
176
+ end
177
+
178
+ def package_path
179
+ @package_path ||= File.join(releases_path, "quandl-command")
180
+ end
181
+
182
+ def releases_path
183
+ @releases_path ||= File.expand_path(File.join( root_path, 'releases' ))
184
+ end
185
+
186
+ def package_url
187
+ @package_url ||= self.class.package_url(args.first)
188
+ end
189
+
190
+ def current_path
191
+ @current_path ||= File.join(root_path, 'current')
192
+ end
193
+
194
+ def root_path
195
+ return @root_path if defined?(@root_path)
196
+ parent_root = File.expand_path(File.join(Quandl::Command::Tasks.root, '../'))
197
+ if Dir.exists?(File.join(parent_root, 'releases')) && Dir.exists?(File.join(parent_root, 'bin'))
198
+ @root_path = parent_root
199
+ else
200
+ @root_path = Quandl::Command::Tasks.root
201
+ end
202
+ @root_path
173
203
  end
174
204
 
175
- def cp(old_path, new_path)
176
- debug("FileUtils.cp #{old_path} #{new_path}")
177
- FileUtils.cp( old_path, new_path )
205
+ def new_timestamp
206
+ @new_timestamp ||= (Time.now.getutc.to_f * 10000).to_i.to_s.gsub('.','')
207
+ end
208
+
209
+ def find_timestamp_before(stamp)
210
+ release_timestamps.sort.each do |rstamp|
211
+ return rstamp if rstamp.to_i < stamp.to_i
212
+ end
213
+ nil
214
+ end
215
+
216
+ def current_timestamp
217
+ # largest to smallest
218
+ @current_timestamp ||= File.read(timestamp_release_path).strip.rstrip.to_i if File.exists?(timestamp_release_path)
219
+ @current_timestamp ||= release_timestamps.sort.reverse.detect{|t| t < new_timestamp.to_i }
178
220
  end
179
221
 
180
- def mv(old_path, new_path)
181
- debug("FileUtils.mv #{old_path} #{new_path}")
182
- FileUtils.mv( old_path, new_path )
222
+ def release_timestamps
223
+ @release_timestamps ||= Dir["#{releases_path}/*"].select{|f| File.directory?(f) }.collect{|f| File.basename(f).to_i }
183
224
  end
184
225
 
185
- def rm_rf(*args)
186
- debug( "FileUtils.rm_rf #{args.to_a.join(" ")}")
187
- FileUtils.rm_rf(*args)
226
+ def qu
227
+ @qu ||= QuandlUtils.new(self)
188
228
  end
189
229
 
190
- def mkdir_p(*args)
191
- debug( "FileUtils.mkdir_p #{args.to_a.join(" ")}")
192
- FileUtils.mkdir_p(*args)
230
+ class QuandlUtils
231
+ attr_accessor :task
232
+
233
+ def initialize(task=nil)
234
+ self.task = task
235
+ end
236
+
237
+ def method_missing(method_name, *args, &block)
238
+ fu(method_name, *args, &block)
239
+ end
240
+
241
+ private
242
+
243
+ def fu(method_name, *args, &block)
244
+ task.debug("#{method_name} #{args}") unless task.nil?
245
+ FileUtils.send(method_name, *args, &block)
246
+ end
193
247
  end
194
248
 
195
249
  end