embarista 1.1.4 → 1.1.5
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.
- data/.rvmrc +49 -0
- data/.travis.yml +1 -1
- data/Gemfile +2 -1
- data/embarista.gemspec +1 -0
- data/lib/embarista.rb +5 -5
- data/lib/embarista/dynamic_index.rb +207 -0
- data/lib/embarista/filters.rb +2 -1
- data/lib/embarista/filters/manifest_url_filter.rb +39 -0
- data/lib/embarista/filters/precompile_handlebars_filter.rb +5 -78
- data/lib/embarista/helpers.rb +4 -0
- data/lib/embarista/manifest_builder.rb +44 -0
- data/lib/embarista/s3sync.rb +63 -13
- data/lib/embarista/sass_functions.rb +9 -2
- data/lib/embarista/server.rb +14 -12
- data/lib/embarista/tasks.rb +2 -0
- data/lib/embarista/tasks/coffeelint.rb +50 -0
- data/lib/embarista/tasks/updater.rb +121 -0
- data/lib/embarista/version.rb +1 -1
- data/spec/manifest_builder_spec.rb +77 -0
- data/spec/manifest_url_filter_spec.rb +79 -0
- metadata +114 -44
- data/lib/embarista/digest_helper.rb +0 -59
- data/lib/embarista/manifest_helper.rb +0 -14
data/lib/embarista/helpers.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
module Embarista
|
2
2
|
module Helpers
|
3
|
+
def rewrite_manifest_urls(*args, &block)
|
4
|
+
filter(Embarista::Filters::ManifestUrlFilter, *args, &block)
|
5
|
+
end
|
6
|
+
|
3
7
|
def precompile_handlebars(*args, &block)
|
4
8
|
filter(Embarista::Filters::PrecompileHandlebarsFilter, *args, &block)
|
5
9
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Embarista
|
5
|
+
class ManifestBuilder
|
6
|
+
include FileUtils
|
7
|
+
|
8
|
+
attr_reader :root, :tmp, :document_root, :tmp_document_root, :version, :manifest
|
9
|
+
|
10
|
+
def initialize(opts={})
|
11
|
+
@root = Pathname.new(opts[:root] || Dir.getwd).expand_path
|
12
|
+
@document_root = Pathname.new(opts[:document_root] || 'public').expand_path(@root)
|
13
|
+
@tmp = Pathname.new(opts[:tmp] || 'tmp').expand_path(@root)
|
14
|
+
@tmp_document_root = @tmp + @document_root.relative_path_from(@root)
|
15
|
+
@manifest = opts[:manifest] || {}
|
16
|
+
@version = opts[:version]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Pass in the file to be versioned and staged in the tmp document root.
|
20
|
+
def add(path, path_from_document_root=nil)
|
21
|
+
full_path = Pathname.new(path).expand_path(root)
|
22
|
+
path_from_document_root = Pathname.new(path_from_document_root || full_path.relative_path_from(document_root))
|
23
|
+
relative_dir = path_from_document_root.dirname
|
24
|
+
|
25
|
+
md5 = Digest::MD5.file(full_path).hexdigest
|
26
|
+
ext = full_path.extname
|
27
|
+
name_without_ext = full_path.basename.to_s.chomp(ext)
|
28
|
+
suffix = "-#{md5}"
|
29
|
+
suffix = "-#{version}#{suffix}" if version
|
30
|
+
versioned_file = "#{name_without_ext}#{suffix}#{ext}"
|
31
|
+
|
32
|
+
versioned_path_from_document_root = relative_dir + versioned_file
|
33
|
+
versioned_full_path = tmp_document_root + versioned_path_from_document_root
|
34
|
+
|
35
|
+
mkdir_p versioned_full_path.dirname
|
36
|
+
cp full_path, versioned_full_path
|
37
|
+
|
38
|
+
http_path = '/' + path_from_document_root.to_s
|
39
|
+
versioned_http_path = '/' + versioned_path_from_document_root.to_s
|
40
|
+
|
41
|
+
manifest[http_path] = versioned_http_path
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/embarista/s3sync.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module Embarista
|
2
2
|
class S3sync
|
3
|
-
attr_reader :origin, :bucket_name, :pwd, :tmp_root, :
|
3
|
+
attr_reader :origin, :bucket_name, :pwd, :tmp_root, :local_manifest_path, :remote_manifest_path
|
4
4
|
|
5
|
-
def initialize(origin, options)
|
6
|
-
bucket_name = options.fetch(:bucket_name)
|
7
|
-
|
5
|
+
def initialize(origin, options)
|
6
|
+
@bucket_name = options.fetch(:bucket_name)
|
7
|
+
@local_manifest_path = options[:local_manifest_path]
|
8
|
+
@remote_manifest_path = options[:remote_manifest_path]
|
8
9
|
aws_key = options.fetch(:aws_key)
|
9
10
|
aws_secret = options.fetch(:aws_secret)
|
10
11
|
|
@@ -15,9 +16,8 @@ module Embarista
|
|
15
16
|
|
16
17
|
@pwd = Pathname.new('').expand_path
|
17
18
|
@origin = origin
|
18
|
-
@bucket_name = bucket_name
|
19
19
|
@tmp_root = @pwd + @origin
|
20
|
-
@
|
20
|
+
@age = options[:age] || 31556900
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.sync(origin, options)
|
@@ -26,7 +26,19 @@ module Embarista
|
|
26
26
|
|
27
27
|
def store(name, file)
|
28
28
|
puts " -> #{name}"
|
29
|
-
|
29
|
+
|
30
|
+
opts = {
|
31
|
+
access: :public_read
|
32
|
+
}
|
33
|
+
|
34
|
+
if should_gzip?(name)
|
35
|
+
opts[:content_encoding] = 'gzip'
|
36
|
+
end
|
37
|
+
|
38
|
+
opts[:cache_control] = "max-age=#{@age.to_i}"
|
39
|
+
opts[:expires] = (Time.now + @age).httpdate
|
40
|
+
|
41
|
+
AWS::S3::S3Object.store(name, file, bucket_name, opts)
|
30
42
|
end
|
31
43
|
|
32
44
|
def sync
|
@@ -38,31 +50,69 @@ module Embarista
|
|
38
50
|
end
|
39
51
|
|
40
52
|
delta_manifest.values.each do |file_name|
|
41
|
-
|
53
|
+
compressed_open(file_name) do |file|
|
42
54
|
store(file_name, file)
|
43
55
|
end
|
44
56
|
end
|
45
57
|
|
46
|
-
open(
|
47
|
-
store(
|
58
|
+
open(local_manifest_path) do |file|
|
59
|
+
store(remote_manifest_file_name, file)
|
60
|
+
store(local_manifest_file_name, file)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def compressed_open(file_name)
|
65
|
+
if should_gzip?(file_name)
|
66
|
+
str_io = StringIO.new
|
67
|
+
open(tmp_root.to_s + file_name) do |f|
|
68
|
+
streaming_deflate(f, str_io)
|
69
|
+
end
|
70
|
+
str_io.reopen(str_io.string, "r")
|
71
|
+
yield str_io
|
72
|
+
str_io.close
|
73
|
+
else
|
74
|
+
open(tmp_root.to_s + file_name) do |f|
|
75
|
+
yield f
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def streaming_deflate(source_io, target_io, buffer_size = 4 * 1024)
|
81
|
+
gz = Zlib::GzipWriter.new(target_io, Zlib::BEST_COMPRESSION)
|
82
|
+
while(string = source_io.read(buffer_size)) do
|
83
|
+
gz.write(string)
|
48
84
|
end
|
85
|
+
gz.close
|
86
|
+
end
|
87
|
+
|
88
|
+
def should_gzip?(name)
|
89
|
+
name =~ /\.css|\.js\Z/
|
90
|
+
end
|
91
|
+
|
92
|
+
def remote_manifest_file_name
|
93
|
+
File.basename(remote_manifest_path)
|
94
|
+
end
|
95
|
+
|
96
|
+
def local_manifest_file_name
|
97
|
+
File.basename(local_manifest_path)
|
49
98
|
end
|
50
99
|
|
51
100
|
def build_delta_manifest
|
52
101
|
return local_manifest unless remote_manifest
|
53
102
|
|
54
103
|
new_manifest_values = local_manifest.values - remote_manifest.values
|
55
|
-
|
104
|
+
|
105
|
+
local_manifest.select {|key, value| new_manifest_values.include? value }
|
56
106
|
end
|
57
107
|
|
58
108
|
def remote_manifest
|
59
|
-
@remote_manifest ||= YAML.load(AWS::S3::S3Object.find(
|
109
|
+
@remote_manifest ||= YAML.load(AWS::S3::S3Object.find(remote_manifest_file_name, bucket_name).value)
|
60
110
|
rescue AWS::S3::NoSuchKey
|
61
111
|
puts 'no remote existing manifest, uploading everything'
|
62
112
|
end
|
63
113
|
|
64
114
|
def local_manifest
|
65
|
-
@local_manifest ||= YAML.load_file(
|
115
|
+
@local_manifest ||= YAML.load_file(local_manifest_path)
|
66
116
|
end
|
67
117
|
end
|
68
118
|
end
|
@@ -1,7 +1,13 @@
|
|
1
1
|
module Embarista
|
2
2
|
module SassFunctions
|
3
3
|
def manifest_url(path)
|
4
|
-
|
4
|
+
digested_path = lookup_manifest_path(path.value)
|
5
|
+
Sass::Script::String.new("url(#{digested_path})")
|
6
|
+
end
|
7
|
+
|
8
|
+
def manifest_path(path)
|
9
|
+
digested_path = lookup_manifest_path(path.value)
|
10
|
+
Sass::Script::String.new(digested_path)
|
5
11
|
end
|
6
12
|
|
7
13
|
private
|
@@ -17,7 +23,8 @@ module Embarista
|
|
17
23
|
|
18
24
|
def lookup_manifest_path(path)
|
19
25
|
if digest?
|
20
|
-
manifest
|
26
|
+
raise ::Sass::SyntaxError.new "manifest-url(#{path.inspect}) missing manifest entry" unless manifest.key? path
|
27
|
+
manifest[path]
|
21
28
|
else
|
22
29
|
path
|
23
30
|
end
|
data/lib/embarista/server.rb
CHANGED
@@ -70,25 +70,27 @@ module Embarista
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def start_testing
|
73
|
-
|
73
|
+
Thread.new do
|
74
74
|
while true
|
75
75
|
test_mutex.synchronize do
|
76
76
|
test_resource.wait(test_mutex)
|
77
77
|
end
|
78
78
|
puts 'RUNNING TESTS'
|
79
|
-
if system('rake test')
|
80
|
-
|
81
|
-
:
|
82
|
-
:
|
83
|
-
:
|
84
|
-
}
|
79
|
+
notification = if system('rake test')
|
80
|
+
{
|
81
|
+
app_name: project_name,
|
82
|
+
title: "#{project_name} error",
|
83
|
+
text: 'JS test GREEN!'
|
84
|
+
}
|
85
85
|
else
|
86
|
-
|
87
|
-
:
|
88
|
-
:
|
89
|
-
:
|
90
|
-
}
|
86
|
+
{
|
87
|
+
app_name: project_name,
|
88
|
+
title: "#{project_name} error",
|
89
|
+
text: 'JS test RED!'
|
90
|
+
}
|
91
91
|
end
|
92
|
+
|
93
|
+
GNTP.notify(notification) rescue nil
|
92
94
|
end
|
93
95
|
end
|
94
96
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module CoffeeLintHelper
|
2
|
+
extend Rake::DSL
|
3
|
+
|
4
|
+
def self.coffeelint(cmd_args)
|
5
|
+
tool = 'coffeelint'
|
6
|
+
cmd_args = cmd_args || ''
|
7
|
+
|
8
|
+
node = which('node')
|
9
|
+
if node.nil?
|
10
|
+
puts "Could not find node in your path."
|
11
|
+
return
|
12
|
+
end
|
13
|
+
|
14
|
+
npm = which('npm')
|
15
|
+
if npm.nil?
|
16
|
+
puts "Could not find npm in your path."
|
17
|
+
return
|
18
|
+
end
|
19
|
+
|
20
|
+
coffeelint = which('coffeelint')
|
21
|
+
|
22
|
+
if coffeelint
|
23
|
+
sh "coffeelint #{cmd_args}"
|
24
|
+
|
25
|
+
else
|
26
|
+
if !File.directory?("node_modules/#{tool}")
|
27
|
+
sh "\"#{npm}\" install #{tool}"
|
28
|
+
end
|
29
|
+
|
30
|
+
sh "\"#{node}\" node_modules/#{tool}/bin/#{tool} #{cmd_args}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.which(cmd)
|
35
|
+
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
36
|
+
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
37
|
+
exts.each { |ext|
|
38
|
+
sep = File::ALT_SEPARATOR || File::SEPARATOR
|
39
|
+
exe = "#{path}#{sep}#{cmd}#{ext}"
|
40
|
+
return exe if File.executable? exe
|
41
|
+
}
|
42
|
+
end
|
43
|
+
return nil
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
desc 'run coffeelint'
|
48
|
+
task :coffeelint do
|
49
|
+
CoffeeLintHelper.coffeelint '-q -f config/coffeelint.json -r app'
|
50
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/tasklib'
|
3
|
+
|
4
|
+
module Embarista
|
5
|
+
module Updater
|
6
|
+
extend self
|
7
|
+
def update_asset_file(regexp, replacement)
|
8
|
+
assetfile_contents = File.read('Assetfile')
|
9
|
+
assetfile_contents.gsub!(regexp, replacement)
|
10
|
+
File.open('Assetfile', 'w') do |f|
|
11
|
+
f.write(assetfile_contents)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class UpdateEmberTask < ::Rake::TaskLib
|
16
|
+
attr_accessor :name
|
17
|
+
|
18
|
+
def initialize(name = :update_ember)
|
19
|
+
@name = name
|
20
|
+
yield self if block_given?
|
21
|
+
define
|
22
|
+
end
|
23
|
+
|
24
|
+
def define
|
25
|
+
task name do |t, args|
|
26
|
+
old_sha, new_sha = nil, nil
|
27
|
+
regexp = /ember-([0-9a-f]{40})/
|
28
|
+
app_vendor_path = File.expand_path("app/vendor")
|
29
|
+
cd(app_vendor_path) do
|
30
|
+
old_filename = Dir['*'].grep(regexp)[0]
|
31
|
+
old_filename =~ regexp
|
32
|
+
old_sha = $1
|
33
|
+
end
|
34
|
+
raise "Couldn't find current ember.js version" if old_sha.nil?
|
35
|
+
cd('../ember.js') do
|
36
|
+
new_sha = `git rev-parse HEAD`.chomp
|
37
|
+
`bundle && bundle exec rake dist`
|
38
|
+
cd('./dist') do
|
39
|
+
cp('ember.js', "#{app_vendor_path}/ember-#{new_sha}.js")
|
40
|
+
cp('ember.min.js', "#{app_vendor_path}/ember-#{new_sha}.min.js")
|
41
|
+
end
|
42
|
+
end
|
43
|
+
if old_sha != new_sha
|
44
|
+
cd(app_vendor_path) do
|
45
|
+
rm("ember-#{old_sha}.js")
|
46
|
+
rm("ember-#{old_sha}.min.js")
|
47
|
+
end
|
48
|
+
Embarista::Updater.update_asset_file(old_sha, new_sha)
|
49
|
+
end
|
50
|
+
puts "Updated from #{old_sha} to #{new_sha}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class UpdateEmberDataTask < ::Rake::TaskLib
|
56
|
+
attr_accessor :name
|
57
|
+
|
58
|
+
def initialize(name = :update_ember_data)
|
59
|
+
@name = name
|
60
|
+
yield self if block_given?
|
61
|
+
define
|
62
|
+
end
|
63
|
+
|
64
|
+
def define
|
65
|
+
task name do |t, args|
|
66
|
+
old_sha, new_sha = nil, nil
|
67
|
+
regexp = /ember-data-([0-9a-f]{40})/
|
68
|
+
app_vendor_path = File.expand_path("app/vendor")
|
69
|
+
cd(app_vendor_path) do
|
70
|
+
old_filename = Dir['*'].grep(regexp)[0]
|
71
|
+
old_filename =~ regexp
|
72
|
+
old_sha = $1
|
73
|
+
end
|
74
|
+
raise "Couldn't find current ember-data js version" if old_sha.nil?
|
75
|
+
cd('../ember-data') do
|
76
|
+
new_sha = `git rev-parse HEAD`.chomp
|
77
|
+
`bundle && bundle exec rake dist`
|
78
|
+
cd('./dist') do
|
79
|
+
cp('ember-data.js', "#{app_vendor_path}/ember-data-#{new_sha}.js")
|
80
|
+
cp('ember-data.min.js', "#{app_vendor_path}/ember-data-#{new_sha}.min.js")
|
81
|
+
end
|
82
|
+
end
|
83
|
+
if old_sha != new_sha
|
84
|
+
cd(app_vendor_path) do
|
85
|
+
rm("ember-data-#{old_sha}.js")
|
86
|
+
rm("ember-data-#{old_sha}.min.js")
|
87
|
+
end
|
88
|
+
Embarista::Updater.update_asset_file(old_sha, new_sha)
|
89
|
+
end
|
90
|
+
puts "Updated from #{old_sha} to #{new_sha}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
class UpdateJqueryTask < ::Rake::TaskLib
|
96
|
+
attr_accessor :name
|
97
|
+
|
98
|
+
def initialize(name = :update_jquery)
|
99
|
+
@name = name
|
100
|
+
yield self if block_given?
|
101
|
+
define
|
102
|
+
end
|
103
|
+
|
104
|
+
def define
|
105
|
+
task name do |t, args|
|
106
|
+
version = ENV['VERSION']
|
107
|
+
raise "please supply VERSION env var to specify jQuery version" if version.nil?
|
108
|
+
cd('./app/vendor') do
|
109
|
+
# remove old jquerys
|
110
|
+
rm Dir['jquery-*.js']
|
111
|
+
sh "curl -O http://code.jquery.com/jquery-#{version}.js"
|
112
|
+
sh "curl -O http://code.jquery.com/jquery-#{version}.min.js"
|
113
|
+
end
|
114
|
+
Embarista::Updater.update_asset_file(%r{JQUERY_VERSION = '\d+\.\d+\.\d+'}, "JQUERY_VERSION = '#{version}'")
|
115
|
+
puts "Updated to jQuery #{version}"
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end
|
121
|
+
end
|
data/lib/embarista/version.rb
CHANGED
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pathname'
|
3
|
+
require 'fileutils'
|
4
|
+
|
5
|
+
describe Embarista::ManifestBuilder do
|
6
|
+
let(:document_root) {
|
7
|
+
Pathname.new('public').expand_path
|
8
|
+
}
|
9
|
+
|
10
|
+
let(:tmp_document_root) {
|
11
|
+
Pathname.new('tmp/public').expand_path
|
12
|
+
}
|
13
|
+
|
14
|
+
let(:options) {
|
15
|
+
{}
|
16
|
+
}
|
17
|
+
|
18
|
+
subject {
|
19
|
+
described_class.new(options)
|
20
|
+
}
|
21
|
+
|
22
|
+
its(:document_root) { should == document_root }
|
23
|
+
|
24
|
+
its(:tmp_document_root) { should == tmp_document_root }
|
25
|
+
|
26
|
+
its(:manifest) { should == {} }
|
27
|
+
|
28
|
+
its(:version) { should be_nil }
|
29
|
+
|
30
|
+
|
31
|
+
def make_file(path, contents)
|
32
|
+
FileUtils.mkdir_p File.dirname(path)
|
33
|
+
File.open(path, 'w') {|f| f << contents}
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#add" do
|
37
|
+
before do
|
38
|
+
make_file('public/foo/bar/hello.txt', <<-CONTENT)
|
39
|
+
Hello World!
|
40
|
+
CONTENT
|
41
|
+
make_file('public/foo/baz/goodbye.txt', <<-CONTENT)
|
42
|
+
Goodbye Cruel World...
|
43
|
+
CONTENT
|
44
|
+
make_file('images/foo.png', <<-CONTENT
|
45
|
+
image
|
46
|
+
CONTENT
|
47
|
+
)
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should digest and copy the file' do
|
51
|
+
# echo 'Hello World!' | md5
|
52
|
+
# > 8ddd8be4b179a529afa5f2ffae4b9858
|
53
|
+
|
54
|
+
|
55
|
+
subject.add('public/foo/bar/hello.txt')
|
56
|
+
File.exist?('tmp/public/foo/bar/hello-8ddd8be4b179a529afa5f2ffae4b9858.txt').should be_true
|
57
|
+
subject.manifest.should == {
|
58
|
+
'/foo/bar/hello.txt' => '/foo/bar/hello-8ddd8be4b179a529afa5f2ffae4b9858.txt'
|
59
|
+
}
|
60
|
+
|
61
|
+
subject.add('public/foo/baz/goodbye.txt')
|
62
|
+
File.exist?('tmp/public/foo/baz/goodbye-8dcca69d946ae9576734c2c91dfddec4.txt').should be_true
|
63
|
+
subject.manifest.should == {
|
64
|
+
'/foo/bar/hello.txt' => '/foo/bar/hello-8ddd8be4b179a529afa5f2ffae4b9858.txt',
|
65
|
+
'/foo/baz/goodbye.txt' => '/foo/baz/goodbye-8dcca69d946ae9576734c2c91dfddec4.txt'
|
66
|
+
}
|
67
|
+
|
68
|
+
subject.add('images/foo.png', 'editor/images/foo.png')
|
69
|
+
File.exist?('tmp/public/editor/images/foo-4802fcebd761ca4f04c9a6320330fd10.png').should be_true
|
70
|
+
subject.manifest.should == {
|
71
|
+
'/foo/bar/hello.txt' => '/foo/bar/hello-8ddd8be4b179a529afa5f2ffae4b9858.txt',
|
72
|
+
'/foo/baz/goodbye.txt' => '/foo/baz/goodbye-8dcca69d946ae9576734c2c91dfddec4.txt',
|
73
|
+
'/editor/images/foo.png' => '/editor/images/foo-4802fcebd761ca4f04c9a6320330fd10.png'
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|