embarista 1.1.4 → 1.1.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -1,10 +1,11 @@
1
1
  module Embarista
2
2
  class S3sync
3
- attr_reader :origin, :bucket_name, :pwd, :tmp_root, :manifest_path
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
- manifest_path = options.fetch(:manifest_path)
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
- @manifest_path = manifest_path
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
- AWS::S3::S3Object.store(name, file, bucket_name)
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
- open(tmp_root.to_s + file_name) do |file|
53
+ compressed_open(file_name) do |file|
42
54
  store(file_name, file)
43
55
  end
44
56
  end
45
57
 
46
- open(manifest_path) do |file|
47
- store('manifest-latest.yml', file)
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
- local_manifest.invert.slice(*new_manifest_values).invert
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('manifest-latest.yml', bucket_name).value)
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('public/manifest.yml')
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
- Sass::Script::String.new("url(#{lookup_manifest_path(path)})")
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.fetch(path.value)
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
@@ -70,25 +70,27 @@ module Embarista
70
70
  end
71
71
 
72
72
  def start_testing
73
- test_thread = Thread.new do
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
- GNTP.notify({
81
- :app_name => "yapp-dashboard",
82
- :title => "yapp-dashboard error",
83
- :text => "JS test GREEN!"
84
- }) rescue nil
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
- GNTP.notify({
87
- :app_name => "yapp-dashboard",
88
- :title => "yapp-dashboard error",
89
- :text => "JS test RED!"
90
- }) rescue nil
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,2 @@
1
+ require 'embarista/tasks/coffeelint'
2
+ require 'embarista/tasks/updater'
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Embarista
2
- VERSION = '1.1.4'
2
+ VERSION = '1.1.5'
3
3
  end
@@ -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