skypager 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +20 -0
  3. data/Gemfile +9 -0
  4. data/LICENSE.txt +22 -0
  5. data/Rakefile +21 -0
  6. data/bin/skypager +17 -0
  7. data/examples/.gitignore +4 -0
  8. data/examples/blog-site/.gitignore +18 -0
  9. data/examples/blog-site/.pryrc +4 -0
  10. data/examples/blog-site/Gemfile +8 -0
  11. data/examples/blog-site/config.rb +17 -0
  12. data/examples/blog-site/data/dropbox.json +1 -0
  13. data/examples/blog-site/source/images/background.png +0 -0
  14. data/examples/blog-site/source/images/middleman.png +0 -0
  15. data/examples/blog-site/source/index.html.erb +10 -0
  16. data/examples/blog-site/source/javascripts/all.js +1 -0
  17. data/examples/blog-site/source/layouts/layout.erb +19 -0
  18. data/examples/blog-site/source/posts/introduction-to-skypager.html.md +23 -0
  19. data/examples/blog-site/source/posts/skypager-and-dnsimple-and-amazon-web-services-combo.html.md +9 -0
  20. data/examples/blog-site/source/stylesheets/all.css +55 -0
  21. data/examples/blog-site/source/stylesheets/normalize.css +375 -0
  22. data/examples/gallery-site/.gitignore +18 -0
  23. data/examples/gallery-site/.pryrc +4 -0
  24. data/examples/gallery-site/Gemfile +11 -0
  25. data/examples/gallery-site/config.rb +38 -0
  26. data/examples/gallery-site/data/dropbox.json +1 -0
  27. data/examples/gallery-site/data/galleries.json +1 -0
  28. data/examples/gallery-site/source/gallery.html.erb +7 -0
  29. data/examples/gallery-site/source/images/background.png +0 -0
  30. data/examples/gallery-site/source/images/galleries/cristian-gallery-1/001.jpg +0 -0
  31. data/examples/gallery-site/source/images/galleries/cristian-gallery-1/002.jpg +0 -0
  32. data/examples/gallery-site/source/images/galleries/cristian-gallery-1/003.jpg +0 -0
  33. data/examples/gallery-site/source/images/galleries/cristian-gallery-1/004.jpg +0 -0
  34. data/examples/gallery-site/source/images/galleries/luca-gallery-1/001.jpg +0 -0
  35. data/examples/gallery-site/source/images/galleries/luca-gallery-1/002.JPG +0 -0
  36. data/examples/gallery-site/source/images/galleries/luca-gallery-1/003.jpg +0 -0
  37. data/examples/gallery-site/source/images/galleries/luca-gallery-1/004.JPG +0 -0
  38. data/examples/gallery-site/source/images/middleman.png +0 -0
  39. data/examples/gallery-site/source/index.html.erb +10 -0
  40. data/examples/gallery-site/source/javascripts/all.js +1 -0
  41. data/examples/gallery-site/source/layouts/layout.erb +20 -0
  42. data/examples/gallery-site/source/stylesheets/all.css +0 -0
  43. data/examples/gallery-site/source/stylesheets/normalize.css +375 -0
  44. data/examples/gallery-site/source/tutorial.md +151 -0
  45. data/lib/skypager.rb +92 -0
  46. data/lib/skypager/build_server.rb +17 -0
  47. data/lib/skypager/cli/commands/config.rb +58 -0
  48. data/lib/skypager/cli/commands/create.rb +98 -0
  49. data/lib/skypager/cli/commands/deploy.rb +30 -0
  50. data/lib/skypager/cli/commands/edit.rb +32 -0
  51. data/lib/skypager/cli/commands/list.rb +12 -0
  52. data/lib/skypager/cli/commands/setup.rb +124 -0
  53. data/lib/skypager/cli/commands/sync.rb +18 -0
  54. data/lib/skypager/configuration.rb +173 -0
  55. data/lib/skypager/data.rb +8 -0
  56. data/lib/skypager/data/excel_spreadsheet.rb +8 -0
  57. data/lib/skypager/data/google_spreadsheet.rb +225 -0
  58. data/lib/skypager/data/request.rb +12 -0
  59. data/lib/skypager/data/source.rb +171 -0
  60. data/lib/skypager/data/source_routes_proxy.rb +30 -0
  61. data/lib/skypager/dns.rb +65 -0
  62. data/lib/skypager/extension.rb +203 -0
  63. data/lib/skypager/middleman/commands/data.rb +0 -0
  64. data/lib/skypager/middleman/commands/deploy.rb +0 -0
  65. data/lib/skypager/middleman/commands/sync.rb +0 -0
  66. data/lib/skypager/site.rb +208 -0
  67. data/lib/skypager/sync.rb +23 -0
  68. data/lib/skypager/sync/amazon.rb +171 -0
  69. data/lib/skypager/sync/dropbox.rb +173 -0
  70. data/lib/skypager/sync/dropbox/delta.rb +67 -0
  71. data/lib/skypager/sync/folder.rb +235 -0
  72. data/lib/skypager/sync/google.rb +143 -0
  73. data/lib/skypager/tar.rb +77 -0
  74. data/lib/skypager/version.rb +3 -0
  75. data/skypager.gemspec +40 -0
  76. data/spec/lib/skypager/configuration_spec.rb +5 -0
  77. data/spec/lib/skypager/data_spec.rb +5 -0
  78. data/spec/lib/skypager/site_spec.rb +5 -0
  79. data/spec/spec_helper.rb +14 -0
  80. data/spec/support/json_helper.rb +7 -0
  81. metadata +383 -0
@@ -0,0 +1,151 @@
1
+ # Using the skypager gem to build dynamic, data driven sites with middleman
2
+
3
+ Skypager takes an already powerful website creation tool 'Middleman' and adds a few key integrations
4
+ with services like Dropbox and Google Drive / Google Documents, as well as Amazon S3, Cloudfront, and DNSimple.
5
+
6
+ This automates a ton of boring setup chores and allows designers and developers to crank out dynamic, data driven websites
7
+ without having to worry too much about servers. And since these websites are all technically 'static', and backed by a global CDN,
8
+ Skypager websites will be fast as hell.
9
+
10
+ The skypager gem is open source. If you want to automate your builds and releases every time files change on Dropbox or any time data changes in a Google Spreadsheet, you
11
+ can either run the skypager build server on your own server or you can sign up on skypager.io and we will set all of that up for you as well.
12
+
13
+ ## Using the skypager gem in your own projecs
14
+
15
+ In this tutorial, we are going to use the skypager gem and the skypager middleman extension to build a photo gallery website.
16
+
17
+ The information about our photo galleries is going to be stored in a google spreadsheet. The photo galleries themselves, are going to be stored on Dropbox.
18
+
19
+ - 1) create a new middleman project
20
+
21
+ ```bash
22
+ middleman init
23
+ ```
24
+
25
+ - 2) add the skypager gem, and activate it in your config.rb
26
+
27
+ ```ruby
28
+ # Gemfile
29
+
30
+ gem 'skypager', github: "architects/skypager", branch: "master"
31
+
32
+ # config.rb
33
+
34
+ activate :skypager
35
+ ```
36
+
37
+ - 3) setup the google drive and dropbox integrations. this requires you
38
+ to create applications in the respective developer consoles for google
39
+ and dropbox
40
+
41
+ ```bash
42
+ alias be='bundle exec'
43
+ be skypager setup
44
+ ```
45
+
46
+ - 4) once your applications are setup, you can create a google
47
+ spreadsheet datasource. the spreadsheet data source will be used to
48
+ generate dynamic pages and content to be displayed with our html
49
+ templates
50
+
51
+ ```bash
52
+ be skypager create datasource galleries
53
+ ```
54
+
55
+ follow the prompts, selecting 'google spreadsheet' and enter in
56
+ some fields for this data source.
57
+
58
+ for this example we will use:
59
+
60
+ `title description cover_image status release_date`
61
+
62
+ this will end up creating the following line in our `config.rb`
63
+
64
+ ```ruby
65
+ # config.rb
66
+
67
+ data_source :galleries, :type => "google", :key => "..."
68
+ ```
69
+
70
+ - 5) in order to get pretty urls from our data source, we are going to
71
+ configure the data source to make 'slugs' out of the title column.
72
+
73
+ edit the config.rb file:
74
+
75
+ ```ruby
76
+ # config.rb
77
+
78
+ data_source :galleries, :type => "google", :key => "...", :slug_column => 'title'
79
+ ```
80
+
81
+ - 6) with this done, we will now have access to the galleries data
82
+ source from within any template, or from within the `config.rb` file
83
+ itself which means we can use the data source to generate dynamic
84
+ urls such as: `/galleries/my-gallery-title` which will display the
85
+ info in the spreasheet.
86
+
87
+ - 7) let's open up the actual spreadsheet and add some rows to it.
88
+
89
+ ```bash
90
+ be skypager edit datasource galleries
91
+ ```
92
+
93
+ this will open up the spreadsheet in your browser for you.
94
+
95
+ - 8) with some actual data in our spreadsheet, lets get a couple of
96
+ pages rendered with it. open up the `source/index.html.erb` file and
97
+ put in the following content.
98
+
99
+ ```erb
100
+ <h1>Galleries</h1>
101
+
102
+ <ul>
103
+ <% data.galleries.each do |gallery| %>
104
+ <li>
105
+ <p><%= gallery.title %></p>
106
+ </li>
107
+ <% end %>
108
+ </ul>
109
+ ```
110
+
111
+ here we are accessing the data from the galleries spreadsheet in our template
112
+ by iterating over `data.galleries` and listing each one. If we edit the spreadsheet,
113
+ and add a new row, and then refresh the page, you will see the new data show up.
114
+
115
+ **note:** if you don't see data showing up, you can restart your development server. in development,
116
+ skypager attempts to keep up to date, but in order not to keep nagging the server we do
117
+ some checking and sometimes this might make data stale.
118
+
119
+ - 9) we can create separate pages for each row in the spreadsheet.
120
+
121
+ ```ruby
122
+ # config.rb
123
+ map_data_source(:galleries, :url => "/galleries/:slug", :to => "gallery.html.erb", :as => :gallery)
124
+ ```
125
+
126
+ this will dynamically add routes for every row in the galleries data source, and display that individual
127
+ row using the `gallery.html.erb` template
128
+
129
+ since we added the `slug_column` option and set it to title, then it will turn our title column data
130
+ into a friendly url. for example: `My Awesome Gallery` becomes available at `/galleries/my-awesome-gallery`
131
+
132
+ editing the `source/gallery.html.erb` template file:
133
+
134
+ ```erb
135
+ <h1><%= gallery.title %></h1>
136
+ <%= image_tag(gallery.cover_image) %>
137
+ <p><%= gallery.description %></p>
138
+ ```
139
+
140
+ and now editing the `source/index.html.erb` template file we can link to our galleries.
141
+
142
+ ```erb
143
+ <a href="/galleries/<%= gallery.slug %>">
144
+ <%= gallery.title %>
145
+ </a>
146
+ ```
147
+
148
+ ### Using dropbox as a media store for your website content
149
+
150
+ - 10) a gallery isn't much without some images. in this tutorial, we are going to integrate with Dropbox to store our
151
+ image files.
data/lib/skypager.rb ADDED
@@ -0,0 +1,92 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+
3
+ require 'hashie'
4
+ require 'pathname'
5
+ require 'google_drive'
6
+ require 'google/api_client'
7
+ require 'google_drive/session'
8
+ require 'dropbox-api'
9
+ require 'cgi'
10
+ require 'launchy'
11
+ require 'active_support/core_ext'
12
+ require 'uri_template'
13
+
14
+ require 'skypager/version'
15
+ require 'skypager/configuration'
16
+
17
+ module Skypager
18
+ def self.app(environment="build", &block)
19
+ @app ||= ::Middleman::Application.server.inst do
20
+ set :environment, environment
21
+ instance_eval(&block) unless block.nil?
22
+ end
23
+ end
24
+
25
+ def self.config
26
+ Skypager::Configuration.instance
27
+ end
28
+
29
+ def self.sites
30
+ Skypager::Site.directory
31
+ end
32
+
33
+ def self.amazon
34
+ Skypager::Sync::Amazon.client
35
+ end
36
+
37
+ def self.google
38
+ Skypager::Sync::Google.client
39
+ end
40
+
41
+ def self.dropbox
42
+ Skypager::Sync::Dropbox.client
43
+ end
44
+
45
+ def self.dns
46
+ require 'dnsimple'
47
+ require 'skypager/dns'
48
+ Skypager::DNS::Manager.client
49
+ end
50
+
51
+ def self.root
52
+ Skypager::Configuration.skypager_root
53
+ end
54
+
55
+ def self.lib
56
+ Pathname(File.dirname(__FILE__))
57
+ end
58
+
59
+ def self.load_commands
60
+ Dir["#{lib.join('skypager','cli', 'commands')}/**/*.rb"].each {|f| require(f) }
61
+ end
62
+
63
+ def self.append_config line, options={}
64
+ file = Pathname(app.root).join('config.rb')
65
+
66
+ if file.exist?
67
+ file.open("a+") do |fh|
68
+ unless options[:silent]
69
+ puts "Appending\n\t#{line}"
70
+ end
71
+
72
+ fh.write("\n#{line}")
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ require 'skypager/site'
79
+ require 'skypager/data'
80
+ require 'skypager/data/source'
81
+ require 'skypager/data/request'
82
+ require 'skypager/data/google_spreadsheet'
83
+ require 'skypager/data/excel_spreadsheet'
84
+ require 'skypager/data/source_routes_proxy'
85
+ require 'skypager/sync'
86
+ require 'skypager/sync/dropbox'
87
+ require 'skypager/sync/dropbox/delta'
88
+ require 'skypager/sync/google'
89
+ require 'skypager/sync/folder'
90
+ require 'skypager/sync/amazon'
91
+ require 'skypager/dns'
92
+ require 'skypager/extension'
@@ -0,0 +1,17 @@
1
+ # The Skypager Build server provides REST endpoints which can be hit by
2
+ # external services, such as the Dropbox Webhooks system, Google Drive webhooks system,
3
+ # or the Github Webhook system, etc.
4
+ #
5
+ # Given a parameter from the Webhook request,
6
+ # the Build server will find the appropriate site,
7
+ # build and deploy it
8
+
9
+ require 'sinatra'
10
+
11
+ class Skypager::BuildServer < Sinatra::Base
12
+ post "/webhooks/:provider" do
13
+ end
14
+
15
+ post "/webhooks/:provider/:site_name" do
16
+ end
17
+ end
@@ -0,0 +1,58 @@
1
+ command 'config localize' do |c|
2
+ c.syntax = "skypager config localize"
3
+ c.description = "sets up a local skypager config file for this project"
4
+
5
+ c.action do |args, options|
6
+ path = Skypager.config.cwd_config_path
7
+
8
+ unless path.exist?
9
+ path.open("w+") do |fh|
10
+ fh.write(Skypager.config.home_config.to_json)
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ command 'config' do |c|
17
+ c.syntax = 'skypager config [options]'
18
+ c.description = 'list skypager configuration settings'
19
+
20
+ c.action do |_args, _options|
21
+ Skypager::Configuration.initialize!
22
+
23
+ Skypager.config.show
24
+ end
25
+ end
26
+
27
+ command 'config get' do |c|
28
+ c.syntax = 'skypager config:get [options]'
29
+ c.description = 'manipulate skypager configuration settings'
30
+
31
+ c.action do |args, _options|
32
+ Skypager::Configuration.initialize!
33
+
34
+ puts Skypager.config.get(args.first)
35
+ end
36
+ end
37
+
38
+ command 'config set' do |c|
39
+ c.syntax = 'skypager config:set KEY=VALUE KEY=VALUE [options]'
40
+ c.description = 'manipulate skypager configuration settings'
41
+
42
+ c.option '--global', nil, 'Set the configuration globally'
43
+
44
+ c.action do |args, _options|
45
+ Skypager::Configuration.initialize!
46
+
47
+ args.select { |pair| pair.match(/=/) }
48
+ .map { |pair| pair.split('=') }
49
+ .each do |group|
50
+ key, value = group
51
+ Skypager.config.set(key, value, false, global: !!(_options.global))
52
+ end
53
+
54
+ Skypager.config.save!
55
+
56
+ Skypager.config.show
57
+ end
58
+ end
@@ -0,0 +1,98 @@
1
+ create_command = lambda do |c|
2
+ c.syntax = 'skypager create data source NAME [options]'
3
+ c.description = "Create a data source"
4
+
5
+ c.option "--type", nil, "What type of data source? google-spreadsheet, dropbox-excel, rest-endpoint"
6
+ c.option "--spreadsheet-name", nil, "What is the spreadsheet name? will be used to find the key"
7
+ c.option "--dropbox-path", nil, "What is the path to the excel?"
8
+ c.option "--fields", "", "comma separated list of fields"
9
+ c.option "--collaborators", "", "comma separated list of email address to share this data source with"
10
+
11
+ c.action do |args, options|
12
+ name = args.first
13
+
14
+ options.default :fields => "",
15
+ :collaborators => ""
16
+
17
+ name ||= ask("What should the name of this data source be?", String)
18
+
19
+ type = options.type
20
+ type ||= choose("Where will this data be stored?", "Google Spreadsheet", "Excel on Dropbox")
21
+
22
+ types = {
23
+ "Google Spreadsheet" => "google",
24
+ "Excel on Dropbox" => "dropbox-excel",
25
+ "REST API Endpoint" => "rest-endpoint"
26
+ }
27
+
28
+ type = types.fetch(type) { type }
29
+ fields = options.fields.split(",").map(&:strip)
30
+ collaborators = options.collaborators.split(",").map(&:strip)
31
+
32
+ if fields.empty?
33
+ fields = ask("Enter the names of the columns. Make sure to use underscore_instead_of_space:", Array)
34
+ end
35
+
36
+ case type
37
+
38
+ when "google"
39
+ spreadsheet = Skypager::Data::GoogleSpreadsheet.create_from_data([], title: name, headers: fields, skypager_config_info: true)
40
+
41
+ if !collaborators.empty?
42
+ spreadsheet.share_write_access_with(*collaborators)
43
+ end
44
+
45
+ when "dropbox-excel"
46
+
47
+ end
48
+ end
49
+ end
50
+
51
+ command 'create datasource' do |c|
52
+ create_command.call(c)
53
+ end
54
+
55
+ command 'create data source' do |c|
56
+ create_command.call(c)
57
+ end
58
+
59
+ command 'create syncable' do |c|
60
+ c.syntax = 'skypager create synced folder NAME [options]'
61
+ c.description = "Create a synced folder"
62
+
63
+ c.option "--type", nil, "What service is holding the folder? dropbox, google-drive"
64
+ c.option "--skip-config", nil, 'Skip modifying the config'
65
+
66
+ c.action do |args, options|
67
+ type = options.type
68
+ type ||= choose("What service is holding the folder?", "Google Drive", "Dropbox")
69
+
70
+ types = {
71
+ "Google Drive" => "google-drive",
72
+ "Dropbox" => "dropbox"
73
+ }
74
+
75
+ if defined?(::Middleman)
76
+ app = ::Middleman::Application.server.inst do
77
+ set :environment, 'development'
78
+ end
79
+ end
80
+
81
+ type = types.fetch(type) { type }
82
+
83
+ if type == "dropbox"
84
+ Skypager::Sync::Dropbox.create_site_folder(app.site_name)
85
+
86
+ puts "\n\n"
87
+ local_path = ask("Enter a relative path to the folder in this project that you would like to sync with Dropbox. e.g. source/images or source", String)
88
+ puts "\n\n"
89
+ remote_path = ask("Enter the remote path. leave blank to use the same", String)
90
+ remote_path = local_path if remote_path.to_s.length == 0
91
+
92
+ Skypager.dropbox.sync_folders(local_path, remote_path, app: app, append_config: !!!options.skip_config)
93
+
94
+ elsif type == "google-drive"
95
+ Skypager::Sync::Google.create_site_folder(app.site_name)
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,30 @@
1
+ command 'deploy' do |c|
2
+ c.syntax = 'skypager deploy [options]'
3
+ c.description = 'deploy this site'
4
+
5
+ c.option '--verbose', nil, 'Display verbose status information'
6
+
7
+ c.action do |args, options|
8
+ app = Skypager.app
9
+ site = app.site
10
+
11
+ site.deploy(app.build_path)
12
+
13
+ if site.use_cdn?
14
+ cdn = site.cdn
15
+
16
+ paths = app.sitemap.resources.map do |resource|
17
+ "/#{ resource.request_path }"
18
+ end
19
+
20
+ begin
21
+ service = cdn.service
22
+ puts "Posting CDN Invalidations"
23
+ puts paths.inspect
24
+ service.post_invalidation cdn, paths
25
+ rescue => e
26
+ puts "Error invalidating the CDN: #{ e.message }"
27
+ end
28
+ end
29
+ end
30
+ end