amazon_static_site 0.1.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4eb7bca91606801e7d0f5119a155b8eb88cbb07b167e669a45eb4f2ffc7800a9
4
+ data.tar.gz: 782abe744733815240cd87da5dc4af08fafe78237828987fa2e03a8502af9dae
5
+ SHA512:
6
+ metadata.gz: 896f57be534e465b6d87b27cdd7a97e0b8f0e93145b5cb726da681dd46c7c5753109cb17e5c80e0a5c6d15c97673aac2ba8ec1d13658f872f04e3dcd7350a12b
7
+ data.tar.gz: d328337e0852467e00d8bccdccc75b82ed45c15488fbd3586d927fb462eee029c35c39f84be9cca760e4349642df698d8becafaec87226f601660d68dfee4e70
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) {|repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in amazon_static_site.gemspec
6
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,131 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ amazon_static_site (0.1.2)
5
+ activesupport
6
+ aws-sdk-s3
7
+ better_tempfile
8
+ cloudflare
9
+ mime-types
10
+ nokogiri
11
+ sinatra
12
+ terminal-table
13
+
14
+ GEM
15
+ remote: https://rubygems.org/
16
+ specs:
17
+ activesupport (7.0.2.2)
18
+ concurrent-ruby (~> 1.0, >= 1.0.2)
19
+ i18n (>= 1.6, < 2)
20
+ minitest (>= 5.1)
21
+ tzinfo (~> 2.0)
22
+ async (1.30.1)
23
+ console (~> 1.10)
24
+ nio4r (~> 2.3)
25
+ timers (~> 4.1)
26
+ async-http (0.56.5)
27
+ async (>= 1.25)
28
+ async-io (>= 1.28)
29
+ async-pool (>= 0.2)
30
+ protocol-http (~> 0.22.0)
31
+ protocol-http1 (~> 0.14.0)
32
+ protocol-http2 (~> 0.14.0)
33
+ async-io (1.32.2)
34
+ async
35
+ async-pool (0.3.9)
36
+ async (>= 1.25)
37
+ async-rest (0.12.4)
38
+ async-http (~> 0.42)
39
+ protocol-http (~> 0.7)
40
+ aws-eventstream (1.2.0)
41
+ aws-partitions (1.554.0)
42
+ aws-sdk-core (3.126.2)
43
+ aws-eventstream (~> 1, >= 1.0.2)
44
+ aws-partitions (~> 1, >= 1.525.0)
45
+ aws-sigv4 (~> 1.1)
46
+ jmespath (~> 1.0)
47
+ aws-sdk-kms (1.54.0)
48
+ aws-sdk-core (~> 3, >= 3.126.0)
49
+ aws-sigv4 (~> 1.1)
50
+ aws-sdk-s3 (1.112.0)
51
+ aws-sdk-core (~> 3, >= 3.126.0)
52
+ aws-sdk-kms (~> 1)
53
+ aws-sigv4 (~> 1.4)
54
+ aws-sigv4 (1.4.0)
55
+ aws-eventstream (~> 1, >= 1.0.2)
56
+ better_tempfile (0.1.0)
57
+ cloudflare (4.3.0)
58
+ async-rest (~> 0.12.3)
59
+ coderay (1.1.3)
60
+ concurrent-ruby (1.1.9)
61
+ console (1.14.0)
62
+ fiber-local
63
+ diff-lcs (1.5.0)
64
+ fiber-local (1.0.0)
65
+ i18n (1.10.0)
66
+ concurrent-ruby (~> 1.0)
67
+ jmespath (1.6.0)
68
+ method_source (1.0.0)
69
+ mime-types (3.4.1)
70
+ mime-types-data (~> 3.2015)
71
+ mime-types-data (3.2022.0105)
72
+ minitest (5.15.0)
73
+ mustermann (1.1.1)
74
+ ruby2_keywords (~> 0.0.1)
75
+ nio4r (2.5.8)
76
+ nokogiri (1.13.1-x86_64-linux)
77
+ racc (~> 1.4)
78
+ protocol-hpack (1.4.2)
79
+ protocol-http (0.22.5)
80
+ protocol-http1 (0.14.2)
81
+ protocol-http (~> 0.22)
82
+ protocol-http2 (0.14.2)
83
+ protocol-hpack (~> 1.4)
84
+ protocol-http (~> 0.18)
85
+ pry (0.14.1)
86
+ coderay (~> 1.1)
87
+ method_source (~> 1.0)
88
+ racc (1.6.0)
89
+ rack (2.2.3)
90
+ rack-protection (2.2.0)
91
+ rack
92
+ rake (10.5.0)
93
+ rspec (3.11.0)
94
+ rspec-core (~> 3.11.0)
95
+ rspec-expectations (~> 3.11.0)
96
+ rspec-mocks (~> 3.11.0)
97
+ rspec-core (3.11.0)
98
+ rspec-support (~> 3.11.0)
99
+ rspec-expectations (3.11.0)
100
+ diff-lcs (>= 1.2.0, < 2.0)
101
+ rspec-support (~> 3.11.0)
102
+ rspec-mocks (3.11.0)
103
+ diff-lcs (>= 1.2.0, < 2.0)
104
+ rspec-support (~> 3.11.0)
105
+ rspec-support (3.11.0)
106
+ ruby2_keywords (0.0.5)
107
+ sinatra (2.2.0)
108
+ mustermann (~> 1.0)
109
+ rack (~> 2.2)
110
+ rack-protection (= 2.2.0)
111
+ tilt (~> 2.0)
112
+ terminal-table (3.0.2)
113
+ unicode-display_width (>= 1.1.1, < 3)
114
+ tilt (2.0.10)
115
+ timers (4.3.3)
116
+ tzinfo (2.0.4)
117
+ concurrent-ruby (~> 1.0)
118
+ unicode-display_width (2.1.0)
119
+
120
+ PLATFORMS
121
+ ruby
122
+
123
+ DEPENDENCIES
124
+ amazon_static_site!
125
+ bundler
126
+ pry
127
+ rake (~> 10.0)
128
+ rspec (~> 3.0)
129
+
130
+ BUNDLED WITH
131
+ 2.3.7
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../lib/amazon_static_site.rb"
3
+ begin
4
+ require "pry"
5
+ rescue LoadError
6
+ end
7
+
8
+ case ARGV[0].to_s
9
+ when /^(serve|s|start|server)$/i
10
+ AmazonStaticSite::Server.new.start
11
+ when /^(generate|g|new|n)$/i
12
+ AmazonStaticSite::Generator.new.start
13
+ when /^(deploy|d|push|p|production)$/i
14
+ AmazonStaticSite::Worker.new(file: ARGV[1], folder: ARGV[2])
15
+ else
16
+ puts "amazon_static_site wrong parameters".red
17
+ puts "How to use:".yellow
18
+ puts "amazon_static_site generate <NAME> # create new application using template in the gem"
19
+ puts "amazon_static_site server # to start server and develop your HTML/CSS/JS locally in browser"
20
+ puts "amazon_static_site deploy <CONFIG> <PATH-TO-PUBLIC> # to start server and develop your HTML/CSS/JS locally in browser"
21
+ puts "example:"
22
+ puts "amazon_static_site deploy site-folder/config.yml site-folder/public"
23
+ end
@@ -0,0 +1,13 @@
1
+ module AmazonStaticSite
2
+ module Client
3
+ class Base
4
+ attr_reader :service
5
+ delegate :config, to: :service
6
+
7
+ def initialize(service)
8
+ @service = service
9
+ end
10
+
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,76 @@
1
+ module AmazonStaticSite
2
+ module Client
3
+ class Cloudflare < Base
4
+ def configure_dns
5
+ in_cloudflare do |connection|
6
+ account_id = cloudflare_account_id(connection)
7
+
8
+ puts " find or create #{domain_for_cloudflare} in account: #{account_id}"
9
+
10
+ zone = fetch_zone(connection)
11
+ unless zone
12
+ connection.zones.create(domain_for_cloudflare, { id: account_id })
13
+ zone = fetch_zone(connection)
14
+ end
15
+
16
+ puts "Creating DNS records:".yellow
17
+ puts " - #{service.s3.s3_primary}"
18
+ puts " - #{service.s3.s3_secondary}"
19
+
20
+ puts "Generating ...".yellow
21
+ zone.dns_records.to_a.each do |record|
22
+ if record.type == 'CNAME' && (record.name == config.domain.secondary || record.name == config.domain.primary)
23
+ record.delete
24
+ end
25
+ end
26
+ www = zone.dns_records.create('CNAME', 'www', service.s3.s3_primary, proxied: true)
27
+ non_www = zone.dns_records.create('CNAME', '.', service.s3.s3_secondary, proxied: true)
28
+
29
+ zone_info = []
30
+ zone_info << [
31
+ zone.value[:name],
32
+ zone.value[:name_servers].join('; '),
33
+ zone.value[:status]
34
+ ]
35
+ puts
36
+ puts "Domain settings (you need to chang nameservers for your domain)".green
37
+ puts Terminal::Table.new(headings: ["Name", "Name Servers", "Status"], rows: zone_info)
38
+ puts
39
+ puts "DNS settings".green
40
+ summary_info = []
41
+ [www, non_www].each do |e|
42
+ summary_info << [ e.type, e.name, ' => ', e.content, e.proxied ]
43
+ end
44
+ puts Terminal::Table.new(headings: ['Type', 'Name', nil, 'Destination', 'Proxied'], rows: summary_info)
45
+ puts "=> Done!".green
46
+ end
47
+ end
48
+
49
+ def primary_www?
50
+ config.domain.primary =~ /^www\./
51
+ end
52
+
53
+ def domain_for_cloudflare
54
+ primary_www? ? config.domain.secondary : config.domain.primary
55
+ end
56
+
57
+ private
58
+
59
+ def fetch_zone(connection)
60
+ connection.zones.find_by_name(domain_for_cloudflare)
61
+ end
62
+
63
+ def in_cloudflare
64
+ # use Cloadflare API client
65
+ ::Cloudflare.connect(key: config.cloudflare.api_key, email: config.cloudflare.email) do |connection|
66
+ yield(connection)
67
+ end
68
+ end
69
+
70
+ def cloudflare_account_id(connection)
71
+ connection.accounts.first.value[:id]
72
+ end
73
+
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,78 @@
1
+ module AmazonStaticSite
2
+ module Client
3
+ class S3 < Base
4
+ def create_buckets
5
+ primary
6
+ secondary
7
+ end
8
+
9
+ def primary
10
+ @primary ||= get_bucket(config.domain.primary)
11
+ end
12
+
13
+ def secondary
14
+ @secondary ||= get_bucket(config.domain.secondary)
15
+ end
16
+
17
+ def publish_static_website_on_s3
18
+ puts "Publish static web site:".yellow
19
+ s3_client.put_bucket_website(
20
+ bucket: config.domain.primary,
21
+ website_configuration: {
22
+ index_document: {
23
+ suffix: "index.html"
24
+ },
25
+ error_document: {
26
+ key: "error.html"
27
+ }
28
+ }
29
+ )
30
+ puts " Primary #{config.domain.primary} DONE"
31
+ s3_client.put_bucket_website(
32
+ bucket: config.domain.secondary,
33
+ website_configuration: {
34
+ redirect_all_requests_to: {
35
+ host_name: config.domain.primary,
36
+ protocol: "https",
37
+ },
38
+ }
39
+ )
40
+ puts " Secondary #{config.domain.secondary} DONE"
41
+ end
42
+
43
+ def s3_primary; s3_domain(config.domain.primary); end
44
+ def s3_secondary; s3_domain(config.domain.secondary); end
45
+
46
+ private
47
+
48
+ def get_bucket(name)
49
+ s3_resource.bucket(name).exists? ?
50
+ s3_resource.bucket(name) : s3_client.create_bucket(bucket: name, acl: 'public-read')
51
+ end
52
+
53
+ def s3_client
54
+ @s3_client ||= Aws::S3::Client.new(aws_credentials)
55
+ end
56
+
57
+ def s3_resource
58
+ @s3_resource ||= Aws::S3::Resource.new(aws_credentials)
59
+ end
60
+
61
+ def aws_credentials
62
+ {
63
+ region: config.s3.region,
64
+ access_key_id: config.s3.access_key_id,
65
+ secret_access_key: config.s3.secret_access_key
66
+ }
67
+ end
68
+
69
+ def s3_domain(domain)
70
+ [
71
+ domain,
72
+ ".s3-website-#{config.s3.region}.amazonaws.com"
73
+ ].join
74
+ end
75
+
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,74 @@
1
+ # http://www.railsjazz.com.s3-website-us-west-1.amazonaws.com/
2
+
3
+ module AmazonStaticSite
4
+ module Client
5
+ class Upload < Base
6
+ GZIP_FILES = /\.(js|css)$/
7
+
8
+ def upload_to(destination)
9
+ result = FileList.new(config.folder + "/**/*.*")
10
+ result -= [config.file] # don not upload config file
11
+
12
+ puts "Uploading:"
13
+
14
+ total_uploaded = 0
15
+
16
+ result.each do |file|
17
+ pathname = Pathname.new(file)
18
+ basename = pathname.basename
19
+ upload_to = pathname.to_s.gsub(config.folder, "").gsub(/^\//, "")
20
+
21
+ size = File.size(file)
22
+ total_uploaded += size
23
+
24
+ puts " #{file}...#{filesize(size)}".green
25
+ upload_file(file: file, upload_to: upload_to, destination: destination)
26
+
27
+ if file.downcase =~ GZIP_FILES
28
+ temp_filename = "#{basename}.gz"
29
+ temp = BetterTempfile.new(temp_filename)
30
+ # gzip file in temp folder
31
+ Zlib::GzipWriter.open(temp.path) do |gz|
32
+ gz.mtime = File.mtime(file)
33
+ gz.orig_name = temp_filename
34
+ gz.write IO.binread(file)
35
+ end
36
+
37
+ size = File.size(temp.path)
38
+ total_uploaded += size
39
+
40
+ # print progress
41
+ print " GZip: #{temp_filename}".dark_green
42
+ print "...#{filesize(size)}\n".green
43
+
44
+ upload_file(file: temp.path, upload_to: upload_to + ".gz", destination: destination)
45
+ # delete temp file
46
+ temp.unlink
47
+ end
48
+ end
49
+ puts "Total uploaded: #{filesize(total_uploaded)}"
50
+ result
51
+ end
52
+
53
+ def upload_file(file:, upload_to:, destination:)
54
+ aws_options = {
55
+ acl: "public-read",
56
+ content_type: MIME::Types.type_for(file).first&.content_type
57
+ }
58
+ destination.object(upload_to).upload_file(file, aws_options)
59
+ end
60
+
61
+ def filesize(size)
62
+ units = ['B', 'KB', 'MB', 'GB', 'TB', 'Pb', 'EB']
63
+
64
+ return '0.0 B' if size == 0
65
+ exp = (Math.log(size) / Math.log(1024)).to_i
66
+ exp += 1 if (size.to_f / 1024 ** exp >= 1024 - 0.05)
67
+ exp = 6 if exp > 6
68
+
69
+ '%.1f %s' % [size.to_f / 1024 ** exp, units[exp]]
70
+ end
71
+
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,14 @@
1
+ module AmazonStaticSite
2
+ class Config
3
+ attr_reader :worker, :options, :file, :folder
4
+
5
+ delegate_missing_to :options
6
+
7
+ def initialize(file: "./config.yml", folder: "./public")
8
+ @file = file
9
+ @folder = folder.gsub(/\/$/, '')
10
+ @worker = worker
11
+ @options = JSON.parse(YAML.load_file(file).to_json, object_class: OpenStruct)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,43 @@
1
+ module AmazonStaticSite
2
+ class Generator
3
+ attr_reader :folder
4
+
5
+ def initialize(folder = ARGV[1] || '.')
6
+ require 'fileutils'
7
+ @folder = folder.gsub(/\/$/, '')
8
+ end
9
+
10
+ def start
11
+ print "Creating folder #{folder} ...".green
12
+ FileUtils.mkdir_p(folder)
13
+ print "OK\n".yellow
14
+
15
+ print "Copying #{template} to #{destination} ...".green
16
+ FileUtils.copy_entry template, destination
17
+ print "OK\n".yellow
18
+
19
+ print "Generating config #{destination}/config/site.yml ...".green
20
+ generate_config
21
+ print "OK\n".yellow
22
+ end
23
+
24
+ private
25
+
26
+ def template
27
+ File.dirname(File.expand_path('..', __dir__)) + "/template"
28
+ end
29
+
30
+ def destination
31
+ Dir.pwd + "/" + folder
32
+ end
33
+
34
+ def generate_config
35
+ FileUtils.mv "#{destination}/config.yml.sample", "#{destination}/config.yml"
36
+ end
37
+
38
+ end
39
+ end
40
+
41
+
42
+
43
+
@@ -0,0 +1,5 @@
1
+ class LocalStaticSite < Sinatra::Base
2
+ get "/" do
3
+ redirect '/index.html'
4
+ end
5
+ end
@@ -0,0 +1,23 @@
1
+ module AmazonStaticSite
2
+ class Server
3
+ attr_reader :folder
4
+
5
+ def initialize(folder = ARGV[1] || './public')
6
+ require 'rack'
7
+ @folder = folder.gsub(/\/$/, '')
8
+ end
9
+
10
+ def start(host: '0.0.0.0', port: 8080)
11
+ handler = Rack::Handler::WEBrick
12
+ app = LocalStaticSite.new
13
+ app.settings.public_folder = folder
14
+ puts "Starting server on folder: #{app.settings.public_folder} on http://#{host}:#{port}".green
15
+ handler.run app, Host: host, Port: port
16
+ end
17
+
18
+ end
19
+ end
20
+
21
+
22
+
23
+
@@ -0,0 +1,26 @@
1
+ module AmazonStaticSite
2
+ class Service
3
+ attr_reader :config, :s3, :cloudflare, :uploader
4
+
5
+ def initialize(config)
6
+ @config = config
7
+ @s3 = Client::S3.new(self)
8
+ @cloudflare = Client::Cloudflare.new(self)
9
+ @uploader = Client::Upload.new(self)
10
+ end
11
+
12
+ def run_s3
13
+ s3.create_buckets
14
+ s3.publish_static_website_on_s3
15
+ end
16
+
17
+ def run_upload
18
+ uploader.upload_to(s3.primary)
19
+ end
20
+
21
+ def run_cloudflare
22
+ cloudflare.configure_dns
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,10 @@
1
+ class String
2
+ def red; colorize(self, "\e[1m\e[31m"); end
3
+ def green; colorize(self, "\e[1m\e[32m"); end
4
+ def dark_green; colorize(self, "\e[32m"); end
5
+ def yellow; colorize(self, "\e[1m\e[33m"); end
6
+ def blue; colorize(self, "\e[1m\e[34m"); end
7
+ def dark_blue; colorize(self, "\e[34m"); end
8
+ def pur; colorize(self, "\e[1m\e[35m"); end
9
+ def colorize(text, color_code) "#{color_code}#{text}\e[0m" end
10
+ end
@@ -0,0 +1,3 @@
1
+ module AmazonStaticSite
2
+ VERSION = "0.1.2"
3
+ end
@@ -0,0 +1,23 @@
1
+ module AmazonStaticSite
2
+ class Worker
3
+ attr_reader :config, :service
4
+
5
+ def initialize(file:, folder:)
6
+ @config = Config.new(file: file, folder: folder)
7
+ @service = Service.new(config)
8
+
9
+ puts "Starting...".yellow
10
+ puts " Config file: #{config.file}"
11
+ puts " Folder to upload: #{config.folder}"
12
+
13
+ puts "Connecting to Amazon:".yellow
14
+ service.run_s3
15
+
16
+ puts "Uploading to Amazon:".yellow
17
+ service.run_upload
18
+
19
+ puts "Configure Cloudflare:".yellow
20
+ service.run_cloudflare
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,30 @@
1
+ require 'active_support/all'
2
+ require 'yaml'
3
+ require 'rake'
4
+ require 'nokogiri'
5
+ require 'aws-sdk-s3'
6
+ require 'json'
7
+ require 'cloudflare'
8
+ require 'sinatra/base'
9
+ require 'zlib'
10
+ require 'better_tempfile'
11
+ require 'mime/types'
12
+ require 'terminal-table'
13
+
14
+ require_relative './amazon_static_site/version'
15
+
16
+ module AmazonStaticSite
17
+ class Error < StandardError; end
18
+ end
19
+
20
+ require_relative './amazon_static_site/utils/string_ext.rb'
21
+ require_relative './amazon_static_site/server.rb'
22
+ require_relative './amazon_static_site/generator.rb'
23
+ require_relative './amazon_static_site/client/base.rb'
24
+ require_relative './amazon_static_site/client/s3.rb'
25
+ require_relative './amazon_static_site/client/upload.rb'
26
+ require_relative './amazon_static_site/client/cloudflare.rb'
27
+ require_relative './amazon_static_site/config.rb'
28
+ require_relative './amazon_static_site/service.rb'
29
+ require_relative './amazon_static_site/worker.rb'
30
+ require_relative './amazon_static_site/local_static_site.rb'
@@ -0,0 +1,5 @@
1
+ RSpec.describe AmazonStaticSite do
2
+ it "has a version number" do
3
+ expect(AmazonStaticSite::VERSION).not_to be nil
4
+ end
5
+ end
@@ -0,0 +1,14 @@
1
+ require "bundler/setup"
2
+ require "amazon_static_site"
3
+
4
+ RSpec.configure do |config|
5
+ # Enable flags like --only-failures and --next-failure
6
+ config.example_status_persistence_file_path = ".rspec_status"
7
+
8
+ # Disable RSpec exposing methods globally on `Module` and `main`
9
+ config.disable_monkey_patching!
10
+
11
+ config.expect_with :rspec do |c|
12
+ c.syntax = :expect
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ domain:
2
+ primary: "www.site.com"
3
+ secondary: "site.com"
4
+ s3:
5
+ region: us-west-1
6
+ access_key_id: "KEY"
7
+ secret_access_key: "SECRET"
8
+ cloudflare:
9
+ email: email@site.org
10
+ api_key: "API"