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.
@@ -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