vacation 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.
@@ -0,0 +1,12 @@
1
+ *.gem
2
+ *.rbc
3
+ *.sw?
4
+ .bundle
5
+ .DS_Store
6
+ _site/*
7
+ coverage
8
+ doc/*
9
+ rdoc
10
+ pkg
11
+ spec/support/credentials.yml
12
+ *~
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm use --create ruby-1.8.7@vacation
data/Gemfile ADDED
@@ -0,0 +1,9 @@
1
+ source :rubygems
2
+
3
+ gem 'jekyll'
4
+ gem 'fog'
5
+
6
+ group :development do
7
+ gem 'rspec'
8
+ gem 'nokogiri'
9
+ end
@@ -0,0 +1,51 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ builder (3.0.0)
5
+ classifier (1.3.3)
6
+ fast-stemmer (>= 1.0.0)
7
+ diff-lcs (1.1.2)
8
+ directory_watcher (1.3.2)
9
+ excon (0.5.6)
10
+ fast-stemmer (1.0.0)
11
+ fog (0.6.0)
12
+ builder
13
+ excon (>= 0.5.5)
14
+ formatador (>= 0.0.16)
15
+ json
16
+ mime-types
17
+ net-ssh (>= 2.0.23)
18
+ nokogiri (>= 1.4.4)
19
+ ruby-hmac
20
+ formatador (0.0.16)
21
+ jekyll (0.10.0)
22
+ classifier (>= 1.3.1)
23
+ directory_watcher (>= 1.1.1)
24
+ liquid (>= 1.9.0)
25
+ maruku (>= 0.5.9)
26
+ json (1.5.1)
27
+ liquid (2.2.2)
28
+ maruku (0.6.0)
29
+ syntax (>= 1.0.0)
30
+ mime-types (1.16)
31
+ net-ssh (2.1.3)
32
+ nokogiri (1.4.4)
33
+ rspec (2.5.0)
34
+ rspec-core (~> 2.5.0)
35
+ rspec-expectations (~> 2.5.0)
36
+ rspec-mocks (~> 2.5.0)
37
+ rspec-core (2.5.1)
38
+ rspec-expectations (2.5.0)
39
+ diff-lcs (~> 1.1.2)
40
+ rspec-mocks (2.5.0)
41
+ ruby-hmac (0.4.0)
42
+ syntax (1.0.0)
43
+
44
+ PLATFORMS
45
+ ruby
46
+
47
+ DEPENDENCIES
48
+ fog
49
+ jekyll
50
+ nokogiri
51
+ rspec
@@ -0,0 +1,66 @@
1
+ # Vacation
2
+
3
+ Vacation lets you host Jekyll sites on S3. It is a gem. You add it via `gem install vacation`.
4
+
5
+ Then you take a vacation.
6
+
7
+ ## Creating a Jekyll site
8
+
9
+ Make site.
10
+
11
+ ## Identify your AWS access credentials
12
+
13
+ These should look something like the ones you get from Amazon. Not Rackspace.
14
+
15
+ Full `~/.fog` support will land in a bit.
16
+
17
+ Then identify the name of the bucket you want to hork things into.
18
+
19
+ ## Backups
20
+
21
+ Vacation destructively overwrites the contents of the target bucket for now.
22
+ Previous content is (optionally, if you use the `vacation` executable) backed
23
+ up to a secondary bucket.
24
+
25
+ If you deploy to `bucket_name` bucket is called `bucket_name`-vacation-backup.
26
+
27
+ ## Deploying
28
+
29
+ Vacation gets invoked via a command line executable script, also called `vacation`!
30
+
31
+ Vacation is a way of deploying Jekyll sites to S3.
32
+
33
+ Basic Command Line Usage:
34
+ vacation <bucket name>
35
+ vacation <bucket name> <path to source>
36
+
37
+ Your AWS information can be read from the environment as
38
+ AWS_ID and AWS_KEY or using the following variables:
39
+
40
+ --[no-]backup Back up the contents of the destination bucket
41
+ --id [ID] Your AWS access key id
42
+ --key [KEY] Your AWS secret key
43
+ --version Display current version
44
+
45
+
46
+ ## MIT License
47
+
48
+ Copyright (c) 2011 Eric "Doc" Ritezel
49
+
50
+ Permission is hereby granted, free of charge, to any person obtaining a copy
51
+ of this software and associated documentation files (the 'Software'), to deal
52
+ in the Software without restriction, including without limitation the rights
53
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
54
+ copies of the Software, and to permit persons to whom the Software is
55
+ furnished to do so, subject to the following conditions:
56
+
57
+ The above copyright notice and this permission notice shall be included in all
58
+ copies or substantial portions of the Software.
59
+
60
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66
+ SOFTWARE.
@@ -0,0 +1,21 @@
1
+ require 'rspec/core/rake_task'
2
+ import 'lib/tasks/deploy.rake'
3
+
4
+ desc "Run all examples"
5
+ RSpec::Core::RakeTask.new(:spec) do |t|
6
+ t.rspec_path = 'rspec'
7
+ t.rspec_opts = %w[--color]
8
+ t.verbose = false
9
+ end
10
+
11
+ namespace :hammer do
12
+ require 'vacation'
13
+ desc "Fire a given S3 bucket out of a cannon into the sun"
14
+ task :drop, :aws_access_id, :aws_secret_key, :s3_bucket do |t, args|
15
+ s3 = Vacation::S3.new(args[:aws_access_id], args[:aws_secret_key], args[:s3_bucket])
16
+ s3.strip_bucket
17
+ s3.bucket.destroy
18
+ end
19
+ end
20
+
21
+ task :default => [:spec]
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path('../../lib', __FILE__)
4
+
5
+ help = <<HELP
6
+ Vacation is a way of deploying Jekyll sites to S3.
7
+
8
+ Basic Command Line Usage:
9
+ vacation <bucket name>
10
+ vacation <bucket name> <path to source>
11
+
12
+ Your AWS information can be read from the environment as
13
+ AWS_ID and AWS_KEY or using the following variables:
14
+
15
+ HELP
16
+
17
+ require 'optparse'
18
+ require 'vacation'
19
+
20
+ options = { 'backup' => true }
21
+ opts = OptionParser.new do |opts|
22
+ opts.banner = help
23
+
24
+ opts.on("--[no-]backup", "Back up the contents of the destination bucket") do |backup|
25
+ options['backup'] = backup
26
+ end
27
+
28
+ opts.on("--id [ID]", "Your AWS access key id") do |id|
29
+ options['access_id'] = id
30
+ end
31
+
32
+ opts.on("--key [KEY]", "Your AWS secret key") do |secret_key|
33
+ options['secret_key'] = secret_key
34
+ end
35
+
36
+ opts.on("--version", "Display current version") do
37
+ puts "Vacation " + Vacation::VERSION
38
+ exit 0
39
+ end
40
+ end
41
+
42
+ opts.parse!
43
+
44
+ # Get source and destintation from command line
45
+ case ARGV.size
46
+ when 1
47
+ options['bucket'] = ARGV[0]
48
+ when 2
49
+ options['bucket'] = ARGV[0]
50
+ options['source'] = ARGV[1]
51
+ else
52
+ puts "Invalid options. Run `vacation --help` for assistance."
53
+ exit(1)
54
+ end
55
+
56
+ options['access_id'] ||= ENV['AWS_ID']
57
+ options['secret_key'] ||= ENV['AWS_KEY']
58
+
59
+ unless options['access_id'] && options['secret_key']
60
+ puts "AWS credentials not found. Run `vacation --help` for assistance."
61
+ exit(1)
62
+ end
63
+
64
+ Dir.mktmpdir do |temp_dir|
65
+ jekyll = Vacation::Jekyll.new(options['source'])
66
+ jekyll.compile_to(temp_dir)
67
+
68
+ s3 = Vacation::S3.new(options['access_id'], options['secret_key'], options['bucket'])
69
+ s3.deploy_to_bucket(temp_dir, :backup => options['backup'])
70
+ end
@@ -0,0 +1,16 @@
1
+ require File.expand_path('../../vacation', __FILE__)
2
+
3
+ namespace :vacation do
4
+ require 'tmpdir'
5
+
6
+ desc 'Compile and deploy a Jekyll directory to S3'
7
+ task :deploy, :aws_access_id, :aws_secret_key, :s3_bucket, :target do |t, args|
8
+ Dir.mktmpdir do |temp_dir|
9
+ jekyll = Vacation::Jekyll.new(args[:target])
10
+ jekyll.compile_to(temp_dir)
11
+
12
+ s3 = Vacation::S3.new(args[:aws_access_id], args[:aws_secret_key], args[:s3_bucket])
13
+ s3.deploy_to_bucket(temp_dir)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require File.expand_path('../vacation/s3', __FILE__)
3
+ require File.expand_path('../vacation/jekyll', __FILE__)
4
+
5
+ module Vacation
6
+ unless const_defined?(:VERSION)
7
+ VERSION = '0.1.2'
8
+ end
9
+ end
10
+
@@ -0,0 +1,29 @@
1
+ require 'jekyll'
2
+
3
+ module Vacation
4
+ class Jekyll
5
+ attr_accessor :source
6
+
7
+ def initialize(source)
8
+ @source = source
9
+ throw StandardError unless File::readable_real?(source) and File::directory?(source)
10
+ end
11
+
12
+ def config_hash
13
+ config_file = File.join(source, '_config.yml')
14
+ begin
15
+ config = YAML.load_file(config_file)
16
+ rescue => err
17
+ config = {}
18
+ end
19
+
20
+ ::Jekyll::DEFAULTS.deep_merge(config).deep_merge('source' => source)
21
+ end
22
+
23
+ def compile_to(destination, options = {})
24
+ options = config_hash.deep_merge('destination' => destination).deep_merge(options)
25
+ site = ::Jekyll::Site.new options
26
+ site.process
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,76 @@
1
+ require 'fog'
2
+ require 'tmpdir'
3
+
4
+ module Vacation
5
+ class S3
6
+ attr_reader :access_key_id, :secret_access_key, :storage, :bucket_name
7
+
8
+ def initialize(id, key, bucket)
9
+ @access_key_id = id
10
+ @secret_access_key = key
11
+ @bucket_name = bucket
12
+ @storage = Fog::Storage.new(
13
+ :provider => 'AWS',
14
+ :aws_access_key_id => access_key_id,
15
+ :aws_secret_access_key => secret_access_key
16
+ )
17
+ end
18
+
19
+ def bucket
20
+ @_bucket ||= storage.directories.create(:key => bucket_name, :privacy => 'public-read')
21
+ end
22
+
23
+ def backup_bucket
24
+ @_backup_bucket ||= storage.directories.create(:key => "#{bucket_name}-vacation-backup",
25
+ :privacy => 'private')
26
+ end
27
+
28
+ def strip_bucket
29
+ bucket.files.reload.each { |file| file.destroy }
30
+ bucket.files.reload
31
+ end
32
+
33
+ def download_from_bucket(path)
34
+ return unless storage.directories.get(bucket_name)
35
+ FileUtils.mkdir_p(path)
36
+
37
+ bucket.files.each do |file|
38
+ location = File.join(path, file.key)
39
+ FileUtils.mkdir_p(File.dirname(location))
40
+ File.open(location, 'w') do |local|
41
+ local.write(file.body)
42
+ end
43
+ end
44
+ end
45
+
46
+ def upload_to_bucket(path, is_backup = false)
47
+ return unless File.exists? path
48
+
49
+ strip_bucket unless is_backup
50
+ target = is_backup ? backup_bucket : bucket
51
+
52
+ Dir[File.join(path, '**', '*')].each do |file|
53
+ relative_path = file[path.length + 1..-1]
54
+ target.files.create(:key => relative_path, :body => File.read(file)) if File.file?(file)
55
+ end
56
+
57
+ target.files.reload
58
+ end
59
+
60
+ def deploy_to_bucket(path, options = { :backup => true })
61
+ if options[:backup] && options[:backup] == true
62
+ Dir.mktmpdir do |temp_dir|
63
+ backup_dir = File.expand_path(Time.now.strftime("%Y-%m-%d@%H:%M:%S(%Z)"), temp_dir)
64
+ FileUtils.mkdir backup_dir
65
+
66
+ download_from_bucket backup_dir
67
+ upload_to_bucket temp_dir, true
68
+ end
69
+ end
70
+
71
+ upload_to_bucket path
72
+
73
+ storage.put_bucket_website bucket_name, 'index.html', :key => '404.html'
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,20 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'vacation'
5
+ require 'rspec'
6
+ require 'tmpdir'
7
+ require 'yaml'
8
+ require 'nokogiri'
9
+
10
+ def fake_jekyll
11
+ File.expand_path('../support/jekyll', __FILE__)
12
+ end
13
+
14
+ def aws_creds
15
+ YAML.load(File.expand_path('../support/credentials.yml', __FILE__))['aws']
16
+ end
17
+
18
+ RSpec.configure do |c|
19
+ c.mock_with :rspec
20
+ end
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <link rel="stylesheet" href="/stylesheets/reset.css" type="text/css" />
5
+ <title>{{ page.title }}</title>
6
+ </head>
7
+ <body>
8
+ <h1>{{ page.title }}</h1>
9
+ <h2>{{ page.synopsis }}</h2>
10
+ {{ content }}
11
+ <h3 class="posted">Posted by {{ page.author }} on {{ page.date | date_to_long_string }}</h3>
12
+ </body>
13
+ </html>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <link rel="stylesheet" href="/stylesheets/reset.css" type="text/css" />
5
+ <title>{{ page.title }}</title>
6
+ </head>
7
+ <body>
8
+ <h1>Sample Site</h1>
9
+ {{ content }}
10
+ </body>
11
+ </html>
@@ -0,0 +1,8 @@
1
+ ---
2
+ layout: blog
3
+ title: Ramen
4
+ author: Doc
5
+ synopsis: It is still soup
6
+ ---
7
+
8
+ It stopped being fun once the noodles cooled down.
@@ -0,0 +1,8 @@
1
+ ---
2
+ layout: blog
3
+ title: Testing
4
+ author: Doc
5
+ synopsis: About last night
6
+ ---
7
+
8
+ Let's call it a draw.
@@ -0,0 +1,13 @@
1
+ ---
2
+ layout: default
3
+ title: Index
4
+ ---
5
+
6
+ <h2>Bloggage</h2>
7
+ <img src="/images/geocities.png" class="lulz" />
8
+
9
+ {% for post in site.posts limit:5 %}
10
+ <h3 class="chunk"><a href=".{{ post.url }}">{{ post.title }}</a></h3>
11
+ <q>{{ post.synopsis }}</q>
12
+ <h4>Posted by {{ post.author }} on {{ post.date | date_to_long_string }}.</h4>
13
+ {% endfor %}
@@ -0,0 +1,260 @@
1
+ /**
2
+ * HTML5 ✰ Boilerplate
3
+ *
4
+ * style.css contains a reset, font normalization and some base styles.
5
+ *
6
+ * Credit is left where credit is due.
7
+ * Much inspiration was taken from these projects:
8
+ * - yui.yahooapis.com/2.8.1/build/base/base.css
9
+ * - camendesign.com/design/
10
+ * - praegnanz.de/weblog/htmlcssjs-kickstart
11
+ */
12
+
13
+
14
+ /**
15
+ * html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline)
16
+ * v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark
17
+ * html5doctor.com/html-5-reset-stylesheet/
18
+ */
19
+
20
+ html, body, div, span, object, iframe,
21
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
22
+ abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
23
+ small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
24
+ fieldset, form, label, legend,
25
+ table, caption, tbody, tfoot, thead, tr, th, td,
26
+ article, aside, canvas, details, figcaption, figure,
27
+ footer, header, hgroup, menu, nav, section, summary,
28
+ time, mark, audio, video {
29
+ margin: 0;
30
+ padding: 0;
31
+ border: 0;
32
+ font-size: 100%;
33
+ font: inherit;
34
+ vertical-align: baseline;
35
+ }
36
+
37
+ article, aside, details, figcaption, figure,
38
+ footer, header, hgroup, menu, nav, section {
39
+ display: block;
40
+ }
41
+
42
+ blockquote, q { quotes: none; }
43
+
44
+ blockquote:before, blockquote:after,
45
+ q:before, q:after { content: ''; content: none; }
46
+
47
+ ins { background-color: #ff9; color: #000; text-decoration: none; }
48
+
49
+ mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
50
+
51
+ del { text-decoration: line-through; }
52
+
53
+ abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
54
+
55
+ table { border-collapse: collapse; border-spacing: 0; }
56
+
57
+ hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
58
+
59
+ input, select { vertical-align: middle; }
60
+
61
+
62
+ /**
63
+ * Font normalization inspired by YUI Library's fonts.css: developer.yahoo.com/yui/
64
+ */
65
+
66
+ body { font:13px/1.231 sans-serif; *font-size:small; } /* Hack retained to preserve specificity */
67
+ select, input, textarea, button { font:99% sans-serif; }
68
+
69
+ /* Normalize monospace sizing:
70
+ en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */
71
+ pre, code, kbd, samp { font-family: monospace, sans-serif; }
72
+
73
+
74
+ /**
75
+ * Minimal base styles.
76
+ */
77
+
78
+ /* Always force a scrollbar in non-IE */
79
+ html { overflow-y: scroll; }
80
+
81
+ /* Accessible focus treatment: people.opera.com/patrickl/experiments/keyboard/test */
82
+ a:hover, a:active { outline: none; }
83
+
84
+ ul, ol { margin-left: 2em; }
85
+ ol { list-style-type: decimal; }
86
+
87
+ /* Remove margins for navigation lists */
88
+ nav ul, nav li { margin: 0; list-style:none; list-style-image: none; }
89
+
90
+ small { font-size: 85%; }
91
+ strong, th { font-weight: bold; }
92
+
93
+ td { vertical-align: top; }
94
+
95
+ /* Set sub, sup without affecting line-height: gist.github.com/413930 */
96
+ sub, sup { font-size: 75%; line-height: 0; position: relative; }
97
+ sup { top: -0.5em; }
98
+ sub { bottom: -0.25em; }
99
+
100
+ pre {
101
+ /* www.pathf.com/blogs/2008/05/formatting-quoted-code-in-blog-posts-css21-white-space-pre-wrap/ */
102
+ white-space: pre; white-space: pre-wrap; word-wrap: break-word;
103
+ padding: 15px;
104
+ }
105
+
106
+ textarea { overflow: auto; } /* www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars/ */
107
+
108
+ .ie6 legend, .ie7 legend { margin-left: -7px; }
109
+
110
+ /* Align checkboxes, radios, text inputs with their label by: Thierry Koblentz tjkdesign.com/ez-css/css/base.css */
111
+ input[type="radio"] { vertical-align: text-bottom; }
112
+ input[type="checkbox"] { vertical-align: bottom; }
113
+ .ie7 input[type="checkbox"] { vertical-align: baseline; }
114
+ .ie6 input { vertical-align: text-bottom; }
115
+
116
+ /* Hand cursor on clickable input elements */
117
+ label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; }
118
+
119
+ /* Webkit browsers add a 2px margin outside the chrome of form elements */
120
+ button, input, select, textarea { margin: 0; }
121
+
122
+ /* Colors for form validity */
123
+ input:valid, textarea:valid { }
124
+ input:invalid, textarea:invalid {
125
+ border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red;
126
+ }
127
+ .no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; }
128
+
129
+
130
+ /* These selection declarations have to be separate
131
+ No text-shadow: twitter.com/miketaylr/status/12228805301
132
+ Also: hot pink! */
133
+ ::-moz-selection{ background: #FF5E99; color:#fff; text-shadow: none; }
134
+ ::selection { background:#FF5E99; color:#fff; text-shadow: none; }
135
+
136
+ /* j.mp/webkit-tap-highlight-color */
137
+ a:link { -webkit-tap-highlight-color: #FF5E99; }
138
+
139
+ /* Make buttons play nice in IE:
140
+ www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ */
141
+ button { width: auto; overflow: visible; }
142
+
143
+ /* Bicubic resizing for non-native sized IMG:
144
+ code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ */
145
+ .ie7 img { -ms-interpolation-mode: bicubic; }
146
+
147
+ /**
148
+ * You might tweak these..
149
+ */
150
+
151
+ body, select, input, textarea {
152
+ /* #444 looks better than black: twitter.com/H_FJ/statuses/11800719859 */
153
+ color: #444;
154
+ /* Set your base font here, to apply evenly */
155
+ /* font-family: Georgia, serif; */
156
+ }
157
+
158
+ /* Headers (h1, h2, etc) have no default font-size or margin; define those yourself */
159
+ h1, h2, h3, h4, h5, h6 { font-weight: bold; }
160
+
161
+ a, a:active, a:visited { color: #607890; }
162
+ a:hover { color: #036; }
163
+
164
+
165
+ /**
166
+ * Primary styles
167
+ *
168
+ * Author:
169
+ */
170
+
171
+
172
+
173
+
174
+
175
+
176
+
177
+
178
+
179
+
180
+
181
+
182
+
183
+
184
+
185
+
186
+ /**
187
+ * Non-semantic helper classes: please define your styles before this section.
188
+ */
189
+
190
+ /* For image replacement */
191
+ .ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; }
192
+
193
+ /* Hide for both screenreaders and browsers:
194
+ css-discuss.incutio.com/wiki/Screenreader_Visibility */
195
+ .hidden { display: none; visibility: hidden; }
196
+
197
+ /* Hide only visually, but have it available for screenreaders: by Jon Neal.
198
+ www.webaim.org/techniques/css/invisiblecontent/ & j.mp/visuallyhidden */
199
+ .visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
200
+ /* Extends the .visuallyhidden class to allow the element to be focusable when navigated to via the keyboard: drupal.org/node/897638 */
201
+ .visuallyhidden.focusable:active,
202
+ .visuallyhidden.focusable:focus { clip: auto; height: auto; margin: 0; overflow: visible; position: static; width: auto; }
203
+
204
+ /* Hide visually and from screenreaders, but maintain layout */
205
+ .invisible { visibility: hidden; }
206
+
207
+ /* The Magnificent Clearfix: Updated to prevent margin-collapsing on child elements.
208
+ j.mp/bestclearfix */
209
+ .clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; overflow: hidden; }
210
+ .clearfix:after { clear: both; }
211
+ /* Fix clearfix: blueprintcss.lighthouseapp.com/projects/15318/tickets/5-extra-margin-padding-bottom-of-page */
212
+ .clearfix { zoom: 1; }
213
+
214
+
215
+
216
+ /**
217
+ * Media queries for responsive design.
218
+ *
219
+ * These follow after primary styles so they will successfully override.
220
+ */
221
+
222
+ @media all and (orientation:portrait) {
223
+ /* Style adjustments for portrait mode goes here */
224
+
225
+ }
226
+
227
+ @media all and (orientation:landscape) {
228
+ /* Style adjustments for landscape mode goes here */
229
+
230
+ }
231
+
232
+ /* Grade-A Mobile Browsers (Opera Mobile, Mobile Safari, Android Chrome)
233
+ consider this: www.cloudfour.com/css-media-query-for-mobile-is-fools-gold/ */
234
+ @media screen and (max-device-width: 480px) {
235
+
236
+
237
+ /* Uncomment if you don't want iOS and WinMobile to mobile-optimize the text for you: j.mp/textsizeadjust */
238
+ /* html { -webkit-text-size-adjust:none; -ms-text-size-adjust:none; } */
239
+ }
240
+
241
+
242
+ /**
243
+ * Print styles.
244
+ *
245
+ * Inlined to avoid required HTTP connection: www.phpied.com/delay-loading-your-print-css/
246
+ */
247
+ @media print {
248
+ * { background: transparent !important; color: black !important; text-shadow: none !important; filter:none !important;
249
+ -ms-filter: none !important; } /* Black prints faster: sanbeiji.com/archives/953 */
250
+ a, a:visited { color: #444 !important; text-decoration: underline; }
251
+ a[href]:after { content: " (" attr(href) ")"; }
252
+ abbr[title]:after { content: " (" attr(title) ")"; }
253
+ .ir a:after, a[href^="javascript:"]:after, a[href^="#"]:after { content: ""; } /* Don't show links for images, or javascript/internal links */
254
+ pre, blockquote { border: 1px solid #999; page-break-inside: avoid; }
255
+ thead { display: table-header-group; } /* css-discuss.incutio.com/wiki/Printing_Tables */
256
+ tr, img { page-break-inside: avoid; }
257
+ @page { margin: 0.5cm; }
258
+ p, h2, h3 { orphans: 3; widows: 3; }
259
+ h2, h3{ page-break-after: avoid; }
260
+ }
@@ -0,0 +1,50 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Vacation::Jekyll do
4
+ let (:jk) { Vacation::Jekyll.new(fake_jekyll) }
5
+
6
+ describe '#initialize' do
7
+ it 'should assign the path to a Jekyll blog' do
8
+ jk.source.should == fake_jekyll
9
+ end
10
+
11
+ { 'not valid' => '/trøløløl', 'not readable' => '/var/root', 'not a directory' => __FILE__ }.each do |reason, path|
12
+ it "should bail if the path is #{reason}" do
13
+ lambda {
14
+ Vacation::Jekyll.new(path)
15
+ }.should raise_exception
16
+ end
17
+ end
18
+ end
19
+
20
+ describe '#compile_to' do
21
+ let(:temp_dir) { Dir.mktmpdir }
22
+ let(:index_path) { File.expand_path('index.html', temp_dir) }
23
+ after { FileUtils.remove_entry_secure temp_dir }
24
+
25
+ it 'should compile that sumbitch to a tempdir' do
26
+ jk.compile_to(temp_dir)
27
+
28
+ File.exists?(index_path).should be_true
29
+ index_content = IO.read(index_path)
30
+
31
+ index = Nokogiri::HTML.parse(index_content)
32
+ index.css('title').inner_text.should == 'Index'
33
+ index.css('h4').count.should == 2
34
+ end
35
+
36
+ it 'should create the destination directory if it does not exist' do
37
+ Dir.rmdir(temp_dir)
38
+ File.exists?(temp_dir).should be_false
39
+
40
+ jk.compile_to(temp_dir)
41
+ File.exists?(index_path).should be_true
42
+ end
43
+
44
+ it 'should throw an exception if the destination is not writable' do
45
+ lambda {
46
+ jk.compile_to('/var/root')
47
+ }.should raise_exception
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,89 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Vacation::S3 do
4
+ before { Fog.mock! }
5
+
6
+ let(:bucket_name) { 'pants' }
7
+ let(:s3) { Vacation::S3.new('fake', 'key', bucket_name)}
8
+ let(:file) { s3.bucket.files.create(:key => 'socks/feet', :body => 'toes') }
9
+ before { s3 && file }
10
+
11
+ describe '#initialize' do
12
+ it 'should assign AWS credentials' do
13
+ s3.access_key_id.should == 'fake'
14
+ s3.secret_access_key.should == 'key'
15
+ s3.bucket_name.should == 'pants'
16
+ end
17
+ end
18
+
19
+ describe '#strip_bucket' do
20
+ it 'should destroy existing files' do
21
+ s3.strip_bucket
22
+ s3.bucket.files.count.should == 0
23
+ end
24
+ end
25
+
26
+ describe '#download_from_bucket' do
27
+ let(:temp_dir) { Dir.mktmpdir }
28
+ after { FileUtils.remove_entry_secure temp_dir }
29
+
30
+ it 'should create directories and files existing in the bucket' do
31
+ s3.download_from_bucket temp_dir
32
+
33
+ File.exists?(File.expand_path('socks', temp_dir)).should be_true
34
+ File.exists?(File.expand_path('socks/feet', temp_dir)).should be_true
35
+ File.read(File.expand_path('socks/feet', temp_dir)).should == 'toes'
36
+ end
37
+ end
38
+
39
+ describe '#upload_to_bucket' do
40
+ let(:temp_dir) { Dir.mktmpdir }
41
+ after { FileUtils.remove_entry_secure temp_dir }
42
+
43
+ it 'should pave over existing files' do
44
+ lambda {
45
+ s3.upload_to_bucket temp_dir
46
+ }.should change { s3.bucket.files.reload.count }.by -1
47
+ end
48
+
49
+ it 'should create directories and files existing on the filesystem' do
50
+ FileUtils.mkdir(File.expand_path('pocket', temp_dir))
51
+ File.open(File.expand_path('pocket/chili', temp_dir), 'w') { |local| local.write('beans')}
52
+
53
+ s3.upload_to_bucket temp_dir
54
+
55
+ s3.bucket.files.count.should == 1
56
+ s3.bucket.files.first.key.should == 'pocket/chili'
57
+ s3.bucket.files.first.body.should == 'beans'
58
+ end
59
+ end
60
+
61
+ describe '#deploy_to_bucket' do
62
+ let(:backup_bucket) { s3.storage.directories.create(:key => "#{bucket_name}-vacation-backup") }
63
+ before do
64
+ s3.storage.stub!(:put_bucket_website) do |name, index, opts|
65
+ name.should == s3.bucket.key
66
+ index.should == 'index.html'
67
+ opts[:key].should == '404.html'
68
+ end
69
+ end
70
+
71
+ it 'should deploy to the specified bucket' do
72
+ s3.deploy_to_bucket fake_jekyll
73
+ s3.bucket.files.count.should == 7
74
+ end
75
+
76
+ it 'should obey a no-backup parameter' do
77
+ lambda {
78
+ s3.deploy_to_bucket fake_jekyll, :backup => false
79
+ }.should_not change{ s3.backup_bucket.files.count }
80
+ end
81
+
82
+ it 'should enable the static hosting parameter and pages' do
83
+ pending 'this functionality is not mocked out in Fog yet'
84
+ s3.deploy_to_bucket fake_jekyll, :backup => false
85
+ s3.storage.get_bucket_website(s3.bucket.key).body['IndexDocument']['Suffix'].should == 'index.html'
86
+ s3.storage.get_bucket_website(s3.bucket.key).body['ErrorDocument']['Key'].should == '404.html'
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,27 @@
1
+ lib = File.expand_path('../lib/', __FILE__)
2
+ $:.unshift lib unless $:.include?(lib)
3
+
4
+ require 'vacation'
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "vacation"
8
+ s.version = Vacation::VERSION
9
+ s.platform = Gem::Platform::RUBY
10
+ s.authors = ["Doc Ritezel"]
11
+ s.email = ['ritezel+doc@gmail.com']
12
+ s.homepage = "http://github.com/ohrite/vacation"
13
+ s.summary = "Send your Jekyll blog on an S3 vacation"
14
+ s.description = "You got your peanut butter on my static file host! You got your static blog content on my chocolate!"
15
+
16
+ s.required_rubygems_version = ">= 1.3.6"
17
+
18
+ s.add_development_dependency "rspec"
19
+ s.add_dependency "fog"
20
+ s.add_dependency "jekyll"
21
+
22
+ s.files = `git ls-files`.split("\n")
23
+ s.test_files = `git ls-files -- {spec}/*`.split("\n")
24
+ s.require_path = 'lib'
25
+ s.executables = %w(vacation)
26
+ s.default_executable = "vacation"
27
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: vacation
3
+ version: !ruby/object:Gem::Version
4
+ hash: 31
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 1
9
+ - 2
10
+ version: 0.1.2
11
+ platform: ruby
12
+ authors:
13
+ - Doc Ritezel
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2011-03-06 00:00:00 -08:00
19
+ default_executable: vacation
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: rspec
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :development
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: fog
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ hash: 3
44
+ segments:
45
+ - 0
46
+ version: "0"
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: jekyll
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ hash: 3
58
+ segments:
59
+ - 0
60
+ version: "0"
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ description: You got your peanut butter on my static file host! You got your static blog content on my chocolate!
64
+ email:
65
+ - ritezel+doc@gmail.com
66
+ executables:
67
+ - vacation
68
+ extensions: []
69
+
70
+ extra_rdoc_files: []
71
+
72
+ files:
73
+ - .gitignore
74
+ - .rvmrc
75
+ - Gemfile
76
+ - Gemfile.lock
77
+ - README.md
78
+ - Rakefile
79
+ - bin/vacation
80
+ - lib/tasks/deploy.rake
81
+ - lib/vacation.rb
82
+ - lib/vacation/jekyll.rb
83
+ - lib/vacation/s3.rb
84
+ - spec/spec_helper.rb
85
+ - spec/support/jekyll/_layouts/blog.html
86
+ - spec/support/jekyll/_layouts/default.html
87
+ - spec/support/jekyll/_posts/2011-03-04-i-am-wearing-ramen.markdown
88
+ - spec/support/jekyll/_posts/2011-03-05-about-last-night.markdown
89
+ - spec/support/jekyll/images/geocities.png
90
+ - spec/support/jekyll/index.html
91
+ - spec/support/jekyll/stylesheets/reset.css
92
+ - spec/unit/jekyll_spec.rb
93
+ - spec/unit/s3_spec.rb
94
+ - vacation.gemspec
95
+ has_rdoc: true
96
+ homepage: http://github.com/ohrite/vacation
97
+ licenses: []
98
+
99
+ post_install_message:
100
+ rdoc_options: []
101
+
102
+ require_paths:
103
+ - lib
104
+ required_ruby_version: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ hash: 3
110
+ segments:
111
+ - 0
112
+ version: "0"
113
+ required_rubygems_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ hash: 23
119
+ segments:
120
+ - 1
121
+ - 3
122
+ - 6
123
+ version: 1.3.6
124
+ requirements: []
125
+
126
+ rubyforge_project:
127
+ rubygems_version: 1.6.1
128
+ signing_key:
129
+ specification_version: 3
130
+ summary: Send your Jekyll blog on an S3 vacation
131
+ test_files: []
132
+