hubic 0.0.1 → 0.0.2

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.
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License (MIT)
2
2
 
3
- Copyright (c) 2014 sdalu
3
+ Copyright (c) 2014 Stephane D'Alu
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.md CHANGED
@@ -4,11 +4,25 @@ Hubic
4
4
  Requirement
5
5
  -----------
6
6
  You need to retrieve the client id, secret key, and redirection url.
7
- For that if not alredy done you need to register an application into your account.
8
- To start the registration process you will need to go to ``My Account``, select ``Your application``, and click on ``Add an application``.
7
+ For that if not already done you need to register an application into
8
+ your account.
9
+ To start the registration process you will need to go to ``My Account``,
10
+ select ``Your application``, and click on ``Add an application``.
9
11
 
10
12
  Quick example
11
13
  -------------
14
+ From the commande line:
15
+
16
+ ```sh
17
+ HUBIC_USER=foo@bar.com # Set the user on which we will act
18
+ hubic client config # Configure the client API key
19
+ hubic auth # Authenticate the user
20
+ hubic upload file.txt cloud/file.txt # Upload file
21
+ hubic download cloud/file.txt # Download file
22
+ hubic delete cloud/file.txt # Remove file
23
+ ```
24
+
25
+ From a ruby script:
12
26
  ```ruby
13
27
  require 'hubic'
14
28
 
data/Rakefile CHANGED
@@ -3,9 +3,14 @@
3
3
  require "rbconfig"
4
4
  require "rubygems"
5
5
  require "bundler/setup"
6
+ require "yard"
6
7
 
7
8
  include Rake::DSL
8
9
 
9
10
 
10
11
  Bundler::GemHelper.install_tasks
11
12
 
13
+ YARD::Rake::YardocTask.new do |t|
14
+ t.files = ['lib/**/*.rb'] # optional
15
+ # t.options = ['--any', '--extra', '--opts'] # optional
16
+ end
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'optparse'
5
+ require 'hubic'
6
+ require 'highline'
7
+
8
+
9
+ HUBIC_CLIENT_CFG = "#{ENV['HOME']}/.hubic-client"
10
+
11
+ exclusive_options = []
12
+ container = nil
13
+ user = ENV['HUBIC_USER']
14
+
15
+ error_proc = lambda do |msg|
16
+ $stderr.puts(msg)
17
+ exit 1
18
+ end
19
+
20
+
21
+ options = OptionParser.new do |opts|
22
+ opts.banner = "Hubic: access your data"
23
+ opts.define_head "Usage: hubic [options] <uri|path> [file]"
24
+ opts.separator ""
25
+ opts.separator "Examples:"
26
+ opts.separator " HUBIC_USER=foo@bar.com"
27
+ opts.separator " hubic client config"
28
+ opts.separator " hubic auth"
29
+ opts.separator " hubic upload local-file.txt documents/cloud-file.txt"
30
+ opts.separator " hubic download documents/cloud-file.txt"
31
+ opts.separator " hubic delete documents/cloud-file.txt"
32
+ opts.separator ""
33
+ opts.separator "Options:"
34
+
35
+ opts.on_tail("-h", "--help", "Show this message") do
36
+ puts opts
37
+ exit
38
+ end
39
+
40
+ opts.on("-c", "--container STRING", "Use the give container as default") do |v|
41
+ container = v
42
+ exclusive_options << :container
43
+ end
44
+
45
+
46
+ opts.on("-u", "--user STRING", "User account to use") do |v|
47
+ user = v
48
+ end
49
+
50
+ opts.on("-V", "--verbose", "Be verbose about action performed") do
51
+ require 'logger'
52
+ loggers << Logger.new($stdout)
53
+ end
54
+
55
+ opts.on_tail("-v", "--version", "Show version") do
56
+ puts "Hubic #{Hubic::VERSION}"
57
+ exit
58
+ end
59
+ end
60
+ opts = options
61
+ opts.parse!
62
+
63
+ $term = HighLine.new
64
+
65
+ action = ARGV.shift
66
+
67
+ # Manage client configuration
68
+ if action == 'client'
69
+ case ARGV[0]
70
+ when 'config'
71
+ ARGV.shift
72
+ cfg = case ARGV.length
73
+ when 0
74
+ [ $term.ask("Client ID : ").to_s,
75
+ $term.ask("Client Secret: ").to_s,
76
+ $term.ask("Redirect URI : ").to_s ]
77
+ when 3
78
+ ARGV
79
+ else
80
+ error_proc["hubic client config [client_id client_secret_ redirect_uri"]
81
+ end
82
+ File.open(HUBIC_CLIENT_CFG, 'w', 0600) {|io|
83
+ io.write({ 'client_id' => cfg[0],
84
+ 'client_secret' => cfg[1],
85
+ 'redirect_uri' => cfg[2], }.to_yaml)
86
+ }
87
+ exit
88
+ when 'reset'
89
+ File.unlink(HUBIC_CLIENT_CFG)
90
+ exit
91
+ end
92
+ end
93
+
94
+
95
+ # Configure Hubic client
96
+ if ENV.include?('HUBIC_REDIRECT_URI' ) &&
97
+ ENV.include?('HUBIC_CLIENT_ID' ) &&
98
+ ENV.include?('HUBIC_CLIENT_SECRET')
99
+ Hubic.default_redirect_uri = ENV['HUBIC_REDIRECT_URI' ]
100
+ Hubic.default_client_id = ENV['HUBIC_CLIENT_ID' ]
101
+ Hubic.default_client_secret = ENV['HUBIC_CLIENT_SECRET']
102
+ else
103
+ begin
104
+ cfg = YAML.load_file(HUBIC_CLIENT_CFG)
105
+ Hubic.default_redirect_uri = cfg['redirect_uri' ]
106
+ Hubic.default_client_id = cfg['client_id' ]
107
+ Hubic.default_client_secret = cfg['client_secret']
108
+ rescue Errno::ENOENT
109
+ error_proc["Plase run: hubic client config"]
110
+ end
111
+ end
112
+
113
+ if user.nil?
114
+
115
+ end
116
+
117
+
118
+ case action
119
+ when 'auth'
120
+ Hubic.for_user(user, ARGV[0], force: true) {|user|
121
+ ($term.ask("Password for #{user}: ", String) {|q| q.echo = 'x' }).to_s
122
+ }
123
+ when 'download' # hubic / local
124
+ obj = ARGV[0]
125
+ dst = ARGV[1] || File.basename(obj)
126
+ Hubic.for_user(user).download(obj, dst)
127
+ when 'upload' # local / hubic
128
+ src = ARGV[0]
129
+ obj = ARGV[1]
130
+ Hubic.for_user(user).upload(src, obj)
131
+ end
@@ -13,8 +13,11 @@ Gem::Specification.new do |s|
13
13
  s.description = "Manage your Hubic account from Ruby"
14
14
 
15
15
  s.add_dependency "faraday", "~>0.9"
16
+ s.add_dependency "mime-types"
17
+ s.add_dependency "highline"
16
18
  s.add_dependency "nokogiri"
17
19
  s.add_development_dependency "rake"
20
+ s.add_development_dependency "yard"
18
21
 
19
22
  s.files = `git ls-files`.split("\n")
20
23
  s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
@@ -32,32 +32,46 @@ class Hubic
32
32
  end
33
33
  end
34
34
 
35
-
35
+ # Set the default client Id to use
36
36
  def self.default_client_id=(client_id)
37
37
  @@client_id = client_id
38
38
  end
39
39
 
40
+ # Set the default client Secret to use
40
41
  def self.default_client_secret=(client_secret)
41
42
  @@client_secret = client_secret
42
43
  end
43
44
 
45
+ # Set the default redirect URI to use
44
46
  def self.default_redirect_uri=(redirect_uri)
45
47
  @@redirect_uri = redirect_uri
46
48
  end
47
49
 
48
-
49
- def self.for_user(user, password=nil, store: Store[user],
50
- &password_requester)
50
+ # Create a Hubic handler
51
+ # @param user [String]
52
+ # @param password [String]
53
+ # @param store
54
+ # @param force [true, false]
55
+ # @param password_requester
56
+ # @return [Hubic] an Hubic handler
57
+ def self.for_user(user, password=nil,
58
+ store: Store[user], force: false, &password_requester)
51
59
  h = Hubic.new(@@client_id, @@client_secret, @@redirect_uri)
52
- h.for_user(user, password, store: store, &password_requester)
60
+ h.for_user(user, password,
61
+ store: store, force: force, &password_requester)
53
62
  h
54
63
  end
55
64
 
56
65
 
66
+ # Create a Hubic handler
67
+ # @param client_id
68
+ # @param client_secret
69
+ # @param redirect_uri
57
70
  def initialize(client_id = @@client_id,
58
71
  client_secret = @@client_secret,
59
72
  redirect_uri = @@redirect_uri)
60
73
  @store = nil
74
+ @refresh_token = nil
61
75
  @client_id = client_id
62
76
  @client_secret = client_secret
63
77
  @redirect_uri = redirect_uri
@@ -69,9 +83,16 @@ class Hubic
69
83
  @default_container = "default"
70
84
  end
71
85
 
72
- def for_user(user, password=nil, store: Store[user], &password_requester)
86
+ # Initialize the Hubic handler to perform operations on behalf of the user
87
+ # @param user [String]
88
+ # @param password [String]
89
+ # @param store
90
+ # @param force [true, false]
91
+ # @param password_requester
92
+ def for_user(user, password=nil,
93
+ store: Store[user], force: false, &password_requester)
73
94
  @store = store
74
- @refresh_token = @store['refresh_token'] if @store
95
+ @refresh_token = @store['refresh_token'] if @store && !force
75
96
 
76
97
  if @refresh_token
77
98
  data = refresh_access_token
@@ -95,6 +116,10 @@ class Hubic
95
116
  end
96
117
 
97
118
 
119
+
120
+
121
+
122
+
98
123
  def account
99
124
  api_hubic(:get, '/1.0/account')
100
125
  end
@@ -103,14 +128,17 @@ class Hubic
103
128
  api_hubic(:get, '/1.0/account/credentials')
104
129
  end
105
130
 
106
-
107
-
108
- def [](path=nil, container=@default_container)
109
- # objects(path, container: container)
131
+ def usage
132
+ api_hubic(:get, '/1.0/account/usage')
110
133
  end
111
134
 
112
-
113
135
 
136
+
137
+ # Make a call to the Hubic API
138
+ # @param method [:get, :post, :delete]
139
+ # @param path
140
+ # @param params [Hash]
141
+ # @return [Hash]
114
142
  def api_hubic(method, path, params=nil)
115
143
  r = @conn.method(method).call(path) do |req|
116
144
  req.headers['Authorization'] = "Bearer #{@access_token}"
@@ -121,7 +149,12 @@ class Hubic
121
149
 
122
150
  private
123
151
 
124
-
152
+ # Obtain a request code from the Hubic server.
153
+ # We will ask for the code, and validate the form on the user behalf.
154
+ #
155
+ # @param user [String]
156
+ # @param password [String]
157
+ # @return [String] the request code
125
158
  def get_request_code(user, password)
126
159
  # Request code (retrieve user confirmation form)
127
160
  r = @conn.get '/oauth/auth', {
@@ -168,6 +201,9 @@ class Hubic
168
201
  end
169
202
  end
170
203
 
204
+ # Request an access token, this will also acquiere a refresh token.
205
+ # @param code [String] the request code
206
+ # @return Hash
171
207
  def get_access_token(code)
172
208
  r = @conn.post '/oauth/token', {
173
209
  :code => code,
@@ -190,6 +226,8 @@ class Hubic
190
226
  end
191
227
  end
192
228
 
229
+ # Refresh the access token
230
+ # @return Hash
193
231
  def refresh_access_token
194
232
  if @refresh_token.nil?
195
233
  raise Error, "refresh_token was not previously acquiered"
@@ -1,9 +1,9 @@
1
- class Hubic
1
+ require 'mime/types'
2
2
 
3
- # File operations
4
- #######################################################################
3
+ class Hubic
5
4
 
6
5
  def download(obj, dst=nil, size: nil, offset: 0, &block)
6
+ # Handle file name or nil as a posible destination
7
7
  io = nil
8
8
  dst = Pathname(dst) if String === dst
9
9
  _dst = case dst
@@ -12,12 +12,16 @@ class Hubic
12
12
  else dst
13
13
  end
14
14
 
15
+ # Get object
15
16
  meta = get_object(obj, _dst, size: size, offset: offset, &block)
16
17
 
18
+ # If file name update the timestamp
17
19
  if (Pathname === dst) && meta[:lastmod]
18
20
  dst.utime(meta[:lastmod], meta[:lastmod])
19
21
  end
20
-
22
+
23
+ # If destination is nil, returns the downloaded file
24
+ # insteaded of the meta data
21
25
  if dst.nil?
22
26
  then io.flush.string
23
27
  else meta
@@ -26,8 +30,13 @@ class Hubic
26
30
  io.close unless io.nil?
27
31
  end
28
32
 
29
- def upload(src, obj, &block)
30
- put_object(src, obj, &block)
33
+ def upload(src, obj, type='application/octet-stream', &block)
34
+ case src
35
+ when String, Pathname
36
+ type = (MIME::Types.of(src).first ||
37
+ MIME::Types['application/octet-stream'].first).content_type
38
+ end
39
+ put_object(obj, src, type, &block)
31
40
  end
32
41
 
33
42
  def copy(src, dst)
@@ -118,16 +118,49 @@ class Hubic
118
118
  http.finish unless http.nil?
119
119
  end
120
120
 
121
- def put_object(src, obj, &block)
121
+ def put_object(obj, src, type='application/octet-stream', &block)
122
122
  container, path, uri = normalize_object(obj)
123
+ io = File.open(src)
123
124
 
124
- r = @conn.put(uri) do |req|
125
- req.headers['X-Auth-Token'] = @os[:token]
126
- req.params[:file] = Faraday::UploadIO.new(src, 'text/plain')
125
+ hdrs = {}
126
+ hdrs['X-Auth-Token' ] = @os[:token]
127
+ hdrs['Transfer-Encoding'] = 'chunked'
128
+ hdrs['Content-Type' ] = type
129
+
130
+ http = Net::HTTP.new(uri.host, uri.port)
131
+ if uri.scheme == 'https'
132
+ http.use_ssl = true
133
+ # http.verify_mode = OpenSSL::SSL::VERIFY_NONE
127
134
  end
128
- puts r.inspect
135
+ http.start
136
+
137
+ request = Net::HTTP::Put.new(uri.request_uri, hdrs)
138
+ request.body_stream = io
139
+ http.request(request) {|response|
140
+ case response
141
+ when Net::HTTPSuccess
142
+ when Net::HTTPRedirection
143
+ fail "http redirect is not currently handled"
144
+ when Net::HTTPUnauthorized
145
+ # TODO: Need to refresh token
146
+ else
147
+ fail "resource unavailable: #{uri} (#{response.class})"
148
+ end
149
+
150
+ puts response.inspect
151
+ }
152
+ if block
153
+ block.call(:done)
154
+ end
155
+ ensure
156
+ io.close unless io.nil?
157
+ http.finish unless http.nil?
129
158
  end
130
159
 
160
+ # List objects store in a container.
161
+ #
162
+ # @param container [String] the name of the container.
163
+ # @return [Array] the list of objects (as a Hash)
131
164
  def objects(container = @default_container,
132
165
  path: nil, limit: nil, gt: nil, lt: nil)
133
166
  path = path[1..-1] if path && path[0] == ?/
@@ -163,7 +196,7 @@ class Hubic
163
196
  params[:format] ||= :json
164
197
 
165
198
  p = "#{@os[:endpoint]}#{'/' if path[0] != ?/}#{path}"
166
- r = @conn.method(method).call(p) do |req|
199
+ r = @os[:conn].method(method).call(p) do |req|
167
200
  req.headers['X-Auth-Token'] = @os[:token]
168
201
  req.params = params
169
202
  end
@@ -188,6 +221,7 @@ class Hubic
188
221
 
189
222
  def openstack_setup(endpoint, token, expires)
190
223
  conn = Faraday.new do |faraday|
224
+ faraday.request :multipart
191
225
  faraday.request :url_encoded
192
226
  faraday.adapter :net_http
193
227
  faraday.options.params_encoder = Faraday::FlatParamsEncoder
@@ -201,6 +235,8 @@ class Hubic
201
235
  end
202
236
 
203
237
  def normalize_object(obj)
238
+ openstack_setup_refresh
239
+
204
240
  c, p = case obj
205
241
  when String
206
242
  [ @default_container, obj ]
@@ -213,6 +249,8 @@ class Hubic
213
249
  when 2 then Symbol === obj[1] ? [ obj[1], obj[0] ] : obj
214
250
  else raise ArguementError
215
251
  end
252
+ else
253
+ raise ArgumentError
216
254
  end
217
255
  c = c.to_s
218
256
  p = p[1..-1] if p[0] == ?/
@@ -1,3 +1,3 @@
1
1
  class Hubic
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hubic
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-05-20 00:00:00.000000000 Z
12
+ date: 2014-05-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: faraday
@@ -27,6 +27,38 @@ dependencies:
27
27
  - - ~>
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0.9'
30
+ - !ruby/object:Gem::Dependency
31
+ name: mime-types
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: highline
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
30
62
  - !ruby/object:Gem::Dependency
31
63
  name: nokogiri
32
64
  requirement: !ruby/object:Gem::Requirement
@@ -59,10 +91,27 @@ dependencies:
59
91
  - - '>='
60
92
  - !ruby/object:Gem::Version
61
93
  version: '0'
94
+ - !ruby/object:Gem::Dependency
95
+ name: yard
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '0'
62
110
  description: Manage your Hubic account from Ruby
63
111
  email:
64
112
  - sdalu@sdalu.com
65
- executables: []
113
+ executables:
114
+ - hubic
66
115
  extensions: []
67
116
  extra_rdoc_files: []
68
117
  files:
@@ -71,6 +120,7 @@ files:
71
120
  - LICENSE
72
121
  - README.md
73
122
  - Rakefile
123
+ - bin/hubic
74
124
  - hubic.gemspec
75
125
  - lib/hubic.rb
76
126
  - lib/hubic/file_ops.rb
@@ -91,7 +141,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
91
141
  version: '0'
92
142
  segments:
93
143
  - 0
94
- hash: 4363560357882864147
144
+ hash: 254901150746708933
95
145
  required_rubygems_version: !ruby/object:Gem::Requirement
96
146
  none: false
97
147
  requirements:
@@ -100,7 +150,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
100
150
  version: '0'
101
151
  segments:
102
152
  - 0
103
- hash: 4363560357882864147
153
+ hash: 254901150746708933
104
154
  requirements: []
105
155
  rubyforge_project:
106
156
  rubygems_version: 1.8.29
@@ -108,3 +158,4 @@ signing_key:
108
158
  specification_version: 3
109
159
  summary: Manage your Hubic account from Ruby
110
160
  test_files: []
161
+ has_rdoc: