vacation 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+