staticdctl 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a564980b186b0e719ec4b76086f6d79866c8493a
4
+ data.tar.gz: a154b91cbf0b56568a7a63590ace9b4e5f1be233
5
+ SHA512:
6
+ metadata.gz: 5e3b3d231e138732158caf657cf2b755709cc4fa310937cf214d5abf8636ac8c2cc80a511dea7426621ecf6a8b1b7a48745bbbba68cf772452e418f3bd466464
7
+ data.tar.gz: 60087771fcedfc6be518eb400289a3bfab1999a47ad393f2418046d18a12846ef24f010141b18b81590420551a427a41cfe44c3551a519130c0304879a94a2b2
data/bin/staticdctl ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+ require 'staticdctl/cli'
3
+
4
+ debugging = (ARGV.include?("--debug") || ARGV.include?("-d"))
5
+ cli = Staticdctl::CLI.new(debugging: debugging)
6
+ exit cli.run(ARGV)
@@ -0,0 +1,80 @@
1
+ require "zlib"
2
+ require "base64"
3
+ require "open-uri"
4
+ require "staticd_utils/memory_file"
5
+ require "staticd_utils/tar"
6
+
7
+ module StaticdUtils
8
+
9
+ # Manage Staticd archives.
10
+ #
11
+ # This class can manage the archives used as transport package to transfer
12
+ # files beetween Staticd client and Staticd API.
13
+ class Archive
14
+ attr_reader :stream
15
+
16
+ def self.open_file(url)
17
+ new(open(url))
18
+ end
19
+
20
+ # Create an archive from a folder.
21
+ #
22
+ # Can include a manifest as an array of files full path (from directory path
23
+ # as root).
24
+ #
25
+ # Example:
26
+ # StaticdUtils::Archive.create("/tmp/my_site", ["/index.html"])
27
+ # # Only the /tmp/my_site/index.html file will be included into
28
+ # the archive.
29
+ def self.create(directory_path, manifest=nil)
30
+ files =
31
+ if manifest
32
+ manifest.map { |entry| directory_path + entry }
33
+ else
34
+ Dir["#{directory_path}/**/*"].select { |f| File.file?(f) }
35
+ end
36
+ new(Tar.tar(files))
37
+ end
38
+
39
+ def initialize(stream)
40
+ @stream = stream
41
+ end
42
+
43
+ def open
44
+ Dir.mktmpdir do |tmp|
45
+ Dir.chdir(tmp) do
46
+ extract(tmp)
47
+ yield tmp
48
+ end
49
+ end
50
+ end
51
+
52
+ def close
53
+ @stream.close unless @stream.closed?
54
+ end
55
+
56
+ def extract(path)
57
+ return false if @stream.closed?
58
+
59
+ Tar.untar(@stream, path)
60
+ close
61
+ path
62
+ end
63
+
64
+ def size
65
+ @stream.size
66
+ end
67
+
68
+ def to_file(path)
69
+ return false if @stream.closed?
70
+
71
+ File.open(path, 'w') { |file| file.write(@stream.read) }
72
+ self.close
73
+ path
74
+ end
75
+
76
+ def to_memory_file
77
+ StaticdUtils::MemoryFile.new(@stream)
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,26 @@
1
+ module StaticdUtils
2
+
3
+ # Class to convert file size in octect to human readable size.
4
+ #
5
+ # Example:
6
+ # Staticd::FileSize.new(1000).to_s
7
+ # # => "1KB"
8
+ class FileSize
9
+
10
+ def initialize(size)
11
+ @size = size
12
+ end
13
+
14
+ def to_s
15
+ units = %w(B KB MB GB TB)
16
+ base = 1000
17
+ return "#{@size}#{units[0]}" if @size < base
18
+
19
+ exponent = (Math.log(@size) / Math.log(base)).to_i
20
+ exponent = units.size - 1 if exponent > units.size - 1
21
+
22
+ human_size = @size / base**exponent
23
+ "#{human_size}#{units[exponent]}"
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,14 @@
1
+ require "gli"
2
+
3
+ # Move the GLI::App module into its own class.
4
+ #
5
+ # It's usefull to build a GLI::App like object.
6
+ #
7
+ # Example:
8
+ # gli = GLIObject.new
9
+ # gli.program_desc("My Ultimate CLI")
10
+ # gli.version("1.0")
11
+ # gli.run(*args)
12
+ class GLIObject
13
+ include GLI::App
14
+ end
@@ -0,0 +1,36 @@
1
+ module StaticdUtils
2
+
3
+ # Make an IO object behave like File objects.
4
+ #
5
+ # Example:
6
+ # io = StringIO.new("Content")
7
+ # file = MemoryFile.new(io)
8
+ # file.read
9
+ # # => "Content"
10
+ # file.path
11
+ # # => "memory_file"
12
+ # file.content_type
13
+ # # => "application/octet-stream"
14
+ class MemoryFile
15
+
16
+ def initialize(stream)
17
+ @stream = stream
18
+ end
19
+
20
+ def read(*args)
21
+ @stream.read(*args)
22
+ end
23
+
24
+ def path
25
+ original_filename
26
+ end
27
+
28
+ def original_filename
29
+ "memory_file"
30
+ end
31
+
32
+ def content_type
33
+ "application/octet-stream"
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,100 @@
1
+ require "digest/sha1"
2
+ require "yaml"
3
+ require "staticd_utils/memory_file"
4
+
5
+ module StaticdUtils
6
+
7
+ # Manifest for Staticd releases.
8
+ #
9
+ # A Sitemap consist of an associative array representing each resources of a
10
+ # site release. Each entry consist of the sha1 digest of the resource content
11
+ # and the complete HTTP path this resource must be available to.
12
+ #
13
+ # Example:
14
+ # sitemap = StaticdUtils::Sitemap.create("/tmp/my_website")
15
+ # sitemap.to_h
16
+ # # => {
17
+ # "058ec3fa8aab4c0ccac27d80fd24f30a8730d3f6"=>"/index.html",
18
+ # "92136ff551f50188f46486ab80db269eda4dfd4e"=>"/hello/world.html"
19
+ # }
20
+ class Sitemap
21
+
22
+ # Create a sitemap from a directory content.
23
+ #
24
+ # It register each files digest and path inside the sitemap.
25
+ def self.create(path)
26
+ map = {}
27
+ if File.directory?(path)
28
+ Dir.chdir(path) do
29
+ Dir["**/*"].each do |object|
30
+ if File.file?(object)
31
+ sha1 = Digest::SHA1.hexdigest(File.read(object))
32
+ map[sha1] = "/#{object}"
33
+ end
34
+ end
35
+ end
36
+ end
37
+ new(map)
38
+ end
39
+
40
+ # Create a sitemap from a YAML string.
41
+ #
42
+ # The YAML string must reflect the sitemap associative array structure.
43
+ #
44
+ # Example:
45
+ # yaml = "---\n058ec3fa8aab4c0ccac27d80fd24f30a8730d3f6: \"/hi.html\"\n"
46
+ # sitemap = StaticdUtils::Sitemap.open(yaml)
47
+ def self.open(yaml)
48
+ new(YAML.load(yaml))
49
+ end
50
+
51
+ # Create a sitemap from a YAML file.
52
+ #
53
+ # The YAML file must reflect the sitemap associative array structure.
54
+ def self.open_file(path)
55
+ open(File.read(path))
56
+ end
57
+
58
+ # Create a sitemap from an associative array.
59
+ #
60
+ # The associative array must have the folowing structure:
61
+ # * Key: the sha1 of the ressource
62
+ # * Value: the HTTP path of the resource
63
+ #
64
+ # Example:
65
+ # sitemap = Sitemap.new({
66
+ # 058ec3fa8aab4c0ccac27d80fd24f30a8730d3f6: "hi.html"
67
+ # })
68
+ def initialize(map)
69
+ @map = map
70
+ end
71
+
72
+ # View all HTTP path of the sitemap.
73
+ def routes
74
+ @map.map { |sha1, path| path }
75
+ end
76
+
77
+ # View all sha1 digest of the sitemap.
78
+ def digests
79
+ @map.map { |sha1, path| sha1 }
80
+ end
81
+
82
+ # Iterate over each resources of the sitemap.
83
+ def each_resources
84
+ @map.each { |sha1, path| yield sha1, path }
85
+ end
86
+
87
+ def to_h
88
+ @map
89
+ end
90
+
91
+ def to_yaml
92
+ @map.to_yaml
93
+ end
94
+
95
+ # Export the sitemap to a YAML file stored into memory.
96
+ def to_memory_file
97
+ StaticdUtils::MemoryFile.new(StringIO.new(to_yaml))
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,43 @@
1
+ require "rubygems/package"
2
+ require "digest/sha1"
3
+
4
+ module StaticdUtils
5
+
6
+ # Creation and Extraction of Tarball Stream.
7
+ #
8
+ # Example:
9
+ # tar = Tar.tar(["/tmp/hello"])
10
+ # Tar.untar(tar, "/tmp")
11
+ class Tar
12
+
13
+ def self.tar(files)
14
+ io = StringIO.new
15
+ tar = Gem::Package::TarWriter.new(io)
16
+
17
+ # Gem::Package::TarReader raise an exeption extracting an empty tarball,
18
+ # this add at least one useless file to extract.
19
+ tar.add_file("about", 0644) { |file| file.write("Hello.") }
20
+
21
+ files.each do |file|
22
+ content = File.read(file)
23
+ sha1 = Digest::SHA1.hexdigest(content)
24
+ tar.add_file(sha1, 0644) { |entry| entry.write(content) }
25
+ end
26
+
27
+ io.rewind
28
+ io
29
+ end
30
+
31
+ def self.untar(io, path)
32
+ FileUtils.mkdir_p("#{path}")
33
+ tar = Gem::Package::TarReader.new(io)
34
+ tar.rewind
35
+ tar.each do |entry|
36
+ File.open("#{path}/#{entry.full_name}", "w+") do |file|
37
+ file.write(entry.read)
38
+ end
39
+ end
40
+ tar.close
41
+ end
42
+ end
43
+ end
data/lib/staticdctl.rb ADDED
@@ -0,0 +1,3 @@
1
+ Dir["#{File.dirname(__FILE__)}/staticdctl/**/*.rb"].each do |library|
2
+ require library
3
+ end
@@ -0,0 +1,330 @@
1
+ require "digest/sha1"
2
+ require "staticdctl"
3
+ require "yaml"
4
+ require "staticd_utils/gli_object"
5
+ require "staticd_utils/archive"
6
+ require "staticd_utils/sitemap"
7
+ require "staticd_utils/file_size"
8
+
9
+ module Staticdctl
10
+ class CLI
11
+
12
+ def initialize(options={})
13
+ @gli = GLIObject.new
14
+ @gli.program_desc("Staticd CLI client")
15
+ @gli.version(Staticdctl::VERSION)
16
+
17
+ enable_debugging if options[:debugging]
18
+ set_global_options
19
+ build_commands
20
+ end
21
+
22
+ def run(*args)
23
+ @gli.run(*args)
24
+ end
25
+
26
+ private
27
+
28
+ def enable_debugging
29
+ @gli.on_error { |exception| raise exception }
30
+ end
31
+
32
+ def load_global_config(config_file)
33
+ YAML.load_file(config_file)
34
+ rescue
35
+ {}
36
+ end
37
+
38
+ def load_config(config_file, host)
39
+ config = load_global_config(config_file)
40
+ config && config.has_key?(host) ? config[host] : {}
41
+ end
42
+
43
+ def staticd_client(options)
44
+ config = load_config(options[:config], options[:host])
45
+ client = Staticdctl::StaticdClient.new(
46
+ options[:host],
47
+ access_id: config["access_id"],
48
+ secret_key: config["secret_key"]
49
+ )
50
+ yield client
51
+ end
52
+
53
+ def set_global_options
54
+ set_global_option_config
55
+ set_global_option_host
56
+ set_global_option_site
57
+ set_global_option_debug
58
+ end
59
+
60
+ def set_global_option_config
61
+ @gli.desc("Staticd configuration file")
62
+ @gli.default_value("#{ENV['HOME']}/.staticdctl.yml")
63
+ @gli.arg_name("<Staticd configuration file>")
64
+ @gli.flag([:c, :config])
65
+ end
66
+
67
+ def set_global_option_host
68
+ @gli.desc("Staticd API endpoint")
69
+ @gli.default_value(
70
+ ENV["STATICDCTL_ENDPOINT"] || "http://localhost/api/v1"
71
+ )
72
+ @gli.arg_name("<Staticd API endpoint>")
73
+ @gli.flag([:h, :host])
74
+ end
75
+
76
+ def set_global_option_site
77
+ @gli.desc("Site name")
78
+ @gli.default_value(File.basename(Dir.pwd))
79
+ @gli.arg_name("<Site name>")
80
+ @gli.flag([:s, :site])
81
+ end
82
+
83
+ def set_global_option_debug
84
+ @gli.desc("Enable debugging (raise exception on error)")
85
+ @gli.default_value(false)
86
+ @gli.arg_name("debug")
87
+ @gli.switch([:d, :debug])
88
+ end
89
+
90
+ def build_commands
91
+ build_command_config
92
+ build_command_set_config
93
+ build_command_rm_config
94
+ build_command_sites
95
+ build_command_create_site
96
+ build_command_destroy_site
97
+ build_command_domains
98
+ build_command_attach_domain
99
+ build_command_detach_domain
100
+ build_command_releases
101
+ build_command_create_release
102
+ end
103
+
104
+ def build_command_config
105
+ @gli.desc("Display current configuration")
106
+ @gli.command(:config) do |c|
107
+ c.action do |global_options, options, args|
108
+ config = load_config(global_options[:config], global_options[:host])
109
+ puts "Current configuration for #{global_options[:host]}:"
110
+ puts "No config." unless config.any?
111
+ config.each do |key, value|
112
+ puts " * #{key}: #{value}"
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ def build_command_set_config
119
+ @gli.desc("Set a configuration option")
120
+ @gli.arg_name("config_key")
121
+ @gli.command(:"config:set") do |c|
122
+ c.action do |global_options, options, args|
123
+ global_config = load_global_config(global_options[:config])
124
+ global_config[global_options[:host]] ||= {}
125
+ global_config[global_options[:host]][args[0]] = args[1]
126
+ File.open(global_options[:config], 'w+') do |file|
127
+ file.write(global_config.to_yaml)
128
+ puts "The #{args[0]} config key has been set to #{args[1]}."
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ def build_command_rm_config
135
+ @gli.desc("Remove a configuration option")
136
+ @gli.arg_name("config_key")
137
+ @gli.command(:"config:rm") do |c|
138
+ c.action do |global_options, options, args|
139
+ global_config = load_global_config(global_options[:config])
140
+
141
+ unless (
142
+ global_config.has_key?(global_options[:host]) &&
143
+ global_config[global_options[:host]].has_key?(args.first)
144
+ ) then
145
+ puts "The #{args.first} config key cannot be found."
146
+ end
147
+
148
+ global_config[global_options[:host]].delete(args.first)
149
+ File.open(global_options[:config], 'w+') do |file|
150
+ file.write(global_config.to_yaml)
151
+ puts "The #{args.first} config key has been removed."
152
+ end
153
+ end
154
+ end
155
+ end
156
+
157
+ def build_command_sites
158
+ @gli.desc("List all sites")
159
+ @gli.command(:sites) do |c|
160
+ c.action do |global_options,options,args|
161
+ staticd_client(global_options) do |client|
162
+ client.sites do |sites|
163
+ puts "Sites hosted on #{global_options[:host]}:"
164
+ puts "No sites yet." unless sites.any?
165
+ sites.each do |site|
166
+ last_release = site.releases.last
167
+ last_release_string = last_release ? last_release.tag : "-"
168
+ domains =
169
+ site.domain_names.map{ |domain| domain.name }.join(", ")
170
+ domains_string = domains.empty? ? "no domains" : domains
171
+ puts " * #{site.name} (#{last_release_string}): #{site.url}"
172
+ end
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
178
+
179
+ def build_command_create_site
180
+ @gli.desc("Create a new site")
181
+ @gli.command(:"sites:create") do |c|
182
+ c.action do |global_options,options,args|
183
+ staticd_client global_options do |client|
184
+ client.create_site(name: global_options[:site]) do |site|
185
+ puts "The #{site.name} site has been created."
186
+ puts site.url if site.url
187
+ end
188
+ end
189
+ end
190
+ end
191
+ end
192
+
193
+ def build_command_destroy_site
194
+ @gli.desc("Destroy a site")
195
+ @gli.command(:"sites:destroy") do |c|
196
+ c.action do |global_options,options,args|
197
+ staticd_client(global_options) do |client|
198
+ client.destroy_site(global_options[:site]) do
199
+ puts "The #{global_options[:site]} site has been destroyed."
200
+ end
201
+ end
202
+ end
203
+ end
204
+ end
205
+
206
+ def build_command_domains
207
+ @gli.desc("List all domain attached to the current site")
208
+ @gli.command :domains do |c|
209
+ c.action do |global_options,options,args|
210
+ staticd_client(global_options) do |client|
211
+ client.domains(global_options[:site]) do |domains|
212
+ puts "Domain names attached to #{global_options[:site]}:"
213
+ puts "No domain names attached." unless domains.any?
214
+ domains.each do |domain|
215
+ puts " * #{domain.name}"
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+
223
+ def build_command_attach_domain
224
+ @gli.desc("Attach a domain name to a site")
225
+ @gli.arg_name("domain_name")
226
+ @gli.command(:"domains:attach") do |c|
227
+ c.action do |global_options,options,args|
228
+ staticd_client(global_options) do |client|
229
+ client.attach_domain(
230
+ global_options[:site],
231
+ name: args.first
232
+ ) do |domain|
233
+ puts "The #{domain.name} domain has been attached to the " +
234
+ "#{domain.site_name} site."
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
240
+
241
+ def build_command_detach_domain
242
+ @gli.desc("Detach a domain name from a site")
243
+ @gli.arg_name("domain_name")
244
+ @gli.command(:"domains:detach") do |c|
245
+ c.action do |global_options,options,args|
246
+ staticd_client(global_options) do |client|
247
+ client.detach_domain(global_options[:site], args.first) do |domain|
248
+ puts "The #{args.first} domain has been detached from the " +
249
+ "#{global_options[:site]} site."
250
+ end
251
+ end
252
+ end
253
+ end
254
+ end
255
+
256
+ def build_command_releases
257
+ @gli.desc("List all releases of the current site")
258
+ @gli.command(:releases) do |c|
259
+ c.action do |global_options,options,args|
260
+ staticd_client(global_options) do |client|
261
+ client.releases(global_options[:site]) do |releases|
262
+ releases_string =
263
+ if releases.any?
264
+ releases.map { |release| release.tag }.join(", ")
265
+ else
266
+ "no release deployed yet"
267
+ end
268
+ puts "Releases of #{global_options[:site]}: #{releases_string}."
269
+ end
270
+ end
271
+ end
272
+ end
273
+ end
274
+
275
+ def build_command_create_release
276
+ @gli.desc("Push a new release for the current app")
277
+ @gli.arg_name("[path]")
278
+ @gli.command(:push) do |c|
279
+ c.action do |global_options,options,args|
280
+ source_path = args.any? ? args.first : "."
281
+
282
+ print "Counting resources... "
283
+ sitemap = StaticdUtils::Sitemap.create(source_path)
284
+ if sitemap.routes.size < 1
285
+ puts "stop. No resources."
286
+ raise "No resources to send in '#{source_path}'"
287
+ end
288
+ puts "done (#{sitemap.routes.size} resources)."
289
+
290
+ print "Asking host to identify new resources... "
291
+ diff_sitemap = staticd_client(global_options) do |client|
292
+ client.cached_resources(sitemap.to_h) do |new_map|
293
+ StaticdUtils::Sitemap.new(new_map.to_h)
294
+ end
295
+ end
296
+ puts "done (#{diff_sitemap.routes.size} new resources to upload)."
297
+
298
+ print "Building the archive... "
299
+ archive = StaticdUtils::Archive.create(
300
+ source_path,
301
+ diff_sitemap.routes
302
+ )
303
+ file_size = StaticdUtils::FileSize.new(archive.size)
304
+ puts "done (#{file_size})."
305
+
306
+ staticd_client(global_options) do |client|
307
+
308
+ print "Uploading the archive... "
309
+ timer_start = Time.now
310
+ client.create_release(
311
+ global_options[:site],
312
+ archive.to_memory_file,
313
+ sitemap.to_memory_file
314
+ ) do |release|
315
+ time_spent = Time.now - timer_start
316
+ speed = archive.size / time_spent / 1000
317
+ puts "done (#{'%.2f' % time_spent}s / #{'%.2f' % speed}kbps)."
318
+ puts ""
319
+ puts "The #{release.site_name} release (#{release.tag}) has " +
320
+ "been created."
321
+ if release.site.url
322
+ puts release.site.url
323
+ end
324
+ end
325
+ end
326
+ end
327
+ end
328
+ end
329
+ end
330
+ end
@@ -0,0 +1,87 @@
1
+ require "rest_client"
2
+ require "api-auth"
3
+ require "json"
4
+
5
+ module Staticdctl
6
+
7
+ # Simple REST client library with HMAC authentication.
8
+ #
9
+ # Support for remote call on JSON REST API.
10
+ #
11
+ # Example:
12
+ # client = Staticdctl::RESTCLient.new(
13
+ # url: "http://api.domain.tld/v1",
14
+ # access_id: 1000,
15
+ # secret_key: "youshallnotpass"
16
+ # )
17
+ # client.call(:get, "/resources") { |response| puts response }
18
+ class RESTClient
19
+
20
+ def initialize(url, hmac={})
21
+ @url = url
22
+ @access_id = hmac[:access_id] || ""
23
+ @secret_key = hmac[:secret_key] || ""
24
+ end
25
+
26
+ # Call a remote REST API action.
27
+ #
28
+ # Example:
29
+ # client.call(:post, "/posts", {text: "hello_world"}) do |response|
30
+ # puts response
31
+ # end
32
+ def call(method, path, req_data=nil, &block)
33
+ headers = {
34
+ "Accept" => "application/json"
35
+ }
36
+ headers["Content-Type"] = "application/json" if req_data
37
+ payload = req_data ? req_data.to_json : nil
38
+ request = RestClient::Request.new(
39
+ url: @url + path,
40
+ method: method,
41
+ headers: headers,
42
+ payload: payload
43
+ )
44
+ send_request(request, block)
45
+ end
46
+
47
+ # Send files using the HTTP multipart/form-data content-type.
48
+ #
49
+ # Example:
50
+ # client.send_files("/attachments", {first: file1, second: file2})
51
+ def send_files(path, files, &block)
52
+ headers = {
53
+ "Accept" => "application/json",
54
+ "Content-Type" => "multipart/form-data"
55
+ }
56
+ request = RestClient::Request.new(
57
+ url: @url + path,
58
+ method: :post,
59
+ headers: headers,
60
+ payload: files,
61
+ timeout: -1
62
+ )
63
+ send_request(request, block)
64
+ end
65
+
66
+ private
67
+
68
+ def send_request(request, block)
69
+ signed_request = ApiAuth.sign!(request, @access_id, @secret_key)
70
+ signed_request.execute do |response, request, result|
71
+ res_data = JSON.parse(response.to_s) unless response.to_s.empty?
72
+ case response.code
73
+ when 200
74
+ block.call(res_data)
75
+ when 204
76
+ block.call
77
+ when 403
78
+ raise res_data["error"]
79
+ when 401
80
+ raise res_data["error"]
81
+ else
82
+ raise "Server returned an '#{response.code}' status code."
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,119 @@
1
+ require "staticdctl/rest_client"
2
+
3
+ module Staticdctl
4
+
5
+ # Class to interact with the Staticd API.
6
+ #
7
+ # Example:
8
+ # staticd_client = Staticdctl::StaticdClient.new(
9
+ # url: "http://staticd.domain.tld/api",
10
+ # access_id: ENV["STATICD_ACCESS_ID"],
11
+ # secret_key: ENV["STATICD_SECRET_KEY"]
12
+ # )
13
+ class StaticdClient
14
+
15
+ def initialize(url, hmac={})
16
+ url = url
17
+ access_id = hmac[:access_id] || ""
18
+ secret_key = hmac[:secret_key] || ""
19
+ @staticd_api = Staticdctl::RESTClient.new(
20
+ url,
21
+ access_id: access_id,
22
+ secret_key: secret_key
23
+ )
24
+ end
25
+
26
+ def sites
27
+ @staticd_api.call(:get, "/sites") do |data|
28
+ yield build_response(data)
29
+ end
30
+ end
31
+
32
+ def create_site(site_params)
33
+ @staticd_api.call(:post, "/sites", site_params) do |data|
34
+ yield build_response(data)
35
+ end
36
+ end
37
+
38
+ def destroy_site(site_name)
39
+ @staticd_api.call(:delete, "/sites/#{site_name}") do
40
+ yield
41
+ end
42
+ end
43
+
44
+ def domains(site_name)
45
+ @staticd_api.call(:get, "/sites/#{site_name}/domain_names") do |data|
46
+ yield build_response(data)
47
+ end
48
+ end
49
+
50
+ def attach_domain(site_name, domain_params)
51
+ @staticd_api.call(
52
+ :post,
53
+ "/sites/#{site_name}/domain_names",
54
+ domain_params
55
+ ) do |data|
56
+ yield build_response(data)
57
+ end
58
+ end
59
+
60
+ def detach_domain(site_name, domain_name)
61
+ @staticd_api.call(
62
+ :delete,
63
+ "/sites/#{site_name}/domain_names/#{domain_name}"
64
+ ) do
65
+ yield
66
+ end
67
+ end
68
+
69
+ def releases(site_name)
70
+ @staticd_api.call :get, "/sites/#{site_name}/releases" do |data|
71
+ yield build_response(data)
72
+ end
73
+ end
74
+
75
+ def create_release(site_name, archive_file, sitemap_file)
76
+ @staticd_api.send_files(
77
+ "/sites/#{site_name}/releases",
78
+ {file: archive_file, sitemap: sitemap_file}
79
+ ) do |data|
80
+ yield build_response(data)
81
+ end
82
+ end
83
+
84
+ # Parse a sitemap of resources digest and return of sitemap purged of
85
+ # already know resources.
86
+ #
87
+ # Submit a list of resources sha1 digests with HTTP path (in the sitemap
88
+ # format) and get a list purged of already known resources (resources
89
+ # already stored in database).
90
+ def cached_resources(digests)
91
+ @staticd_api.call(:post, "/resources/get_cached", digests) do |data|
92
+ yield build_response(data)
93
+ end
94
+ end
95
+
96
+ private
97
+
98
+ def build_response(data)
99
+ data.kind_of?(Array) ? build_collection(data) : build_object(data)
100
+ end
101
+
102
+ def build_collection(data)
103
+ data.map { |element| build_object(element) }
104
+ end
105
+
106
+ def build_object(data)
107
+ struct = OpenStruct.new
108
+ data.each do |key, value|
109
+ struct[key] =
110
+ case
111
+ when value.kind_of?(Array) then build_collection(value)
112
+ when value.kind_of?(Hash) then build_object(value)
113
+ else value
114
+ end
115
+ end
116
+ struct
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,3 @@
1
+ module Staticdctl
2
+ VERSION = '0.0.1'
3
+ end
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: staticdctl
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Etienne Garnier
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-26 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 10.3.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 10.3.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: gli
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 2.12.2
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 2.12.2
41
+ - !ruby/object:Gem::Dependency
42
+ name: rest_client
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - '='
46
+ - !ruby/object:Gem::Version
47
+ version: 1.8.1
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - '='
53
+ - !ruby/object:Gem::Version
54
+ version: 1.8.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: api-auth
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.2.6
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 1.2.6
69
+ description: CLI Client for the Staticd API service
70
+ email: garnier.etienne@gmail.com
71
+ executables:
72
+ - staticdctl
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/staticdctl/cli.rb
77
+ - lib/staticdctl/rest_client.rb
78
+ - lib/staticdctl/staticd_client.rb
79
+ - lib/staticdctl/version.rb
80
+ - lib/staticd_utils/memory_file.rb
81
+ - lib/staticd_utils/file_size.rb
82
+ - lib/staticd_utils/sitemap.rb
83
+ - lib/staticd_utils/gli_object.rb
84
+ - lib/staticd_utils/archive.rb
85
+ - lib/staticd_utils/tar.rb
86
+ - lib/staticdctl.rb
87
+ - bin/staticdctl
88
+ homepage: http://staticd.eggnet.io
89
+ licenses:
90
+ - MIT
91
+ metadata: {}
92
+ post_install_message:
93
+ rdoc_options: []
94
+ require_paths:
95
+ - lib
96
+ - lib
97
+ required_ruby_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ required_rubygems_version: !ruby/object:Gem::Requirement
103
+ requirements:
104
+ - - '>='
105
+ - !ruby/object:Gem::Version
106
+ version: '0'
107
+ requirements: []
108
+ rubyforge_project:
109
+ rubygems_version: 2.0.14
110
+ signing_key:
111
+ specification_version: 4
112
+ summary: Staticd CLI Client
113
+ test_files: []