fingerjam 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -3,6 +3,7 @@ source "http://rubygems.org"
3
3
  gem "rails", ">= 3.0.0"
4
4
  gem "jammit"
5
5
  gem "capistrano"
6
+ gem "activesupport"
6
7
 
7
8
  group :development do
8
9
  gem "rspec", "~> 2.1.0"
data/Gemfile.lock CHANGED
@@ -102,6 +102,7 @@ PLATFORMS
102
102
  ruby
103
103
 
104
104
  DEPENDENCIES
105
+ activesupport
105
106
  bundler (~> 1.0.0)
106
107
  capistrano
107
108
  jammit
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.3.0
1
+ 0.4.0
data/fingerjam.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{fingerjam}
8
- s.version = "0.3.0"
8
+ s.version = "0.4.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Steve Hoeksema"]
12
- s.date = %q{2010-12-09}
12
+ s.date = %q{2011-01-27}
13
13
  s.description = %q{Fingerjam uploads your Jammit-compressed assets with fingerprinted filenames so they can be cached indefinitely}
14
14
  s.email = %q{steve@seven.net.nz}
15
15
  s.extra_rdoc_files = [
@@ -30,11 +30,12 @@ Gem::Specification.new do |s|
30
30
  "lib/fingerjam.rb",
31
31
  "lib/fingerjam/base.rb",
32
32
  "lib/fingerjam/capistrano.rb",
33
+ "lib/fingerjam/capistrano/configuration.rb",
34
+ "lib/fingerjam/capistrano/strategy.rb",
33
35
  "lib/fingerjam/fix_jammit_encoding.rb",
34
36
  "lib/fingerjam/helpers.rb",
35
37
  "lib/fingerjam/jammit.rb",
36
38
  "lib/fingerjam/railtie.rb",
37
- "lib/tasks/fingerjam.rake",
38
39
  "spec/fingerjam_spec.rb",
39
40
  "spec/spec_helper.rb"
40
41
  ]
@@ -56,6 +57,7 @@ Gem::Specification.new do |s|
56
57
  s.add_runtime_dependency(%q<rails>, [">= 3.0.0"])
57
58
  s.add_runtime_dependency(%q<jammit>, [">= 0"])
58
59
  s.add_runtime_dependency(%q<capistrano>, [">= 0"])
60
+ s.add_runtime_dependency(%q<activesupport>, [">= 0"])
59
61
  s.add_development_dependency(%q<rspec>, ["~> 2.1.0"])
60
62
  s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
61
63
  s.add_development_dependency(%q<jeweler>, ["~> 1.5.1"])
@@ -64,6 +66,7 @@ Gem::Specification.new do |s|
64
66
  s.add_dependency(%q<rails>, [">= 3.0.0"])
65
67
  s.add_dependency(%q<jammit>, [">= 0"])
66
68
  s.add_dependency(%q<capistrano>, [">= 0"])
69
+ s.add_dependency(%q<activesupport>, [">= 0"])
67
70
  s.add_dependency(%q<rspec>, ["~> 2.1.0"])
68
71
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
72
  s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
@@ -73,6 +76,7 @@ Gem::Specification.new do |s|
73
76
  s.add_dependency(%q<rails>, [">= 3.0.0"])
74
77
  s.add_dependency(%q<jammit>, [">= 0"])
75
78
  s.add_dependency(%q<capistrano>, [">= 0"])
79
+ s.add_dependency(%q<activesupport>, [">= 0"])
76
80
  s.add_dependency(%q<rspec>, ["~> 2.1.0"])
77
81
  s.add_dependency(%q<bundler>, ["~> 1.0.0"])
78
82
  s.add_dependency(%q<jeweler>, ["~> 1.5.1"])
@@ -1,49 +1,154 @@
1
- require "digest/md5"
2
- require "yaml"
3
-
4
1
  module Fingerjam
5
2
  class Base
6
3
 
4
+ cattr_accessor :protocol
7
5
  cattr_accessor :host
8
- cattr_accessor :lockfile
6
+ cattr_accessor :cache_prefix
7
+
8
+ cattr_accessor :root_path
9
+ cattr_accessor :assets_yml_path
10
+ cattr_accessor :lock_yml_path
11
+ cattr_accessor :public_path
12
+ cattr_accessor :packages_path
13
+ cattr_accessor :cache_path
14
+
15
+ cattr_accessor :cached_paths
16
+ cattr_accessor :cached_urls
17
+
9
18
  cattr_accessor :enabled
10
- cattr_accessor :hashes
11
19
 
12
20
  class << self
13
21
 
14
- def configure(opts = {})
15
- self.host = opts.delete(:host)
16
- self.lockfile = opts.delete(:lockfile) || File.join(Rails.root, "config", "assets.lock.yml")
17
- self.hashes = YAML.load_file(lockfile)
18
- self.enabled = hashes.present? && Rails.env.production?
19
- rescue Errno::ENOENT
20
- self.hashes = {}
21
- self.enabled = false
22
+ def configure(options = {})
23
+ self.protocol = options.delete(:protocol) || "https"
24
+ self.host = options.delete(:host) || "www.example.com"
25
+ self.cache_prefix = options.delete(:cache_prefix) || "/cache/"
26
+
27
+ self.root_path = options.delete(:root_path)
28
+ self.assets_yml_path = options.delete(:assets_yml_path) || File.join(root_path, "config", "assets.yml")
29
+ self.lock_yml_path = options.delete(:lock_yml_path) || File.join(root_path, "config", "assets.lock.yml")
30
+ self.public_path = options.delete(:public_path) || File.join(root_path, "public")
31
+ self.packages_path = options.delete(:packages_path) || File.join(public_path, "packages")
32
+ self.cache_path = options.delete(:cache_path) || File.join(public_path, cache_prefix)
33
+
34
+ self.cached_paths = {}
35
+
36
+ begin
37
+ self.cached_urls = YAML.load_file(lock_yml_path)
38
+ rescue
39
+ self.cached_urls = {}
40
+ end
41
+
42
+ self.enabled = !cached_urls.empty? && Rails.env.production?
43
+
44
+ Jammit.const_set("ASSET_ROOT", root_path)
22
45
  end
23
46
 
24
47
  def enabled?
25
48
  enabled
26
49
  end
27
50
 
28
- def hashed?(relative_path)
29
- hashes.has_key?(relative_path)
51
+ def cached?(relative_path)
52
+ self.cached_urls.include?(relative_path)
30
53
  end
31
54
 
32
- def hashed_path(relative_path)
33
- generate_path(relative_path, hashes[relative_path])
55
+ def cached_url(relative_path)
56
+ self.cached_urls[relative_path]
34
57
  end
35
58
 
36
- def generate_path(relative_path, hash)
37
- "http://%s/%s%s" % [host, hashes[relative_path], relative_path]
59
+ def save_cached_url_from_path(relative_path, absolute_path)
60
+ save_cached_path_from_path(relative_path, absolute_path)
61
+ generate_cached_url(relative_path)
38
62
  end
39
63
 
40
- def extensions
41
- %w{js css png jpg gif}
64
+ def package_and_lock!
65
+ package
66
+ scan_public
67
+ symlink
68
+ write_lockfile
42
69
  end
43
70
 
44
- def generate_hash(absolute_path)
45
- Digest::MD5.hexdigest(absolute_path.to_s)
46
- end
71
+ private
72
+
73
+ def extensions
74
+ %w{js css png jpg gif}
75
+ end
76
+
77
+ def save_cached_path_from_path(relative_path, absolute_path)
78
+ self.cached_paths[relative_path] = generate_cached_path_from_absolute(relative_path, absolute_path)
79
+ self.cached_paths[relative_path]
80
+ end
81
+
82
+ def calculate_hash(absolute_path)
83
+ Digest::MD5.file(absolute_path.to_s).hexdigest
84
+ end
85
+
86
+ def generate_cached_path_from_absolute(relative_path, absolute_path)
87
+ hash = calculate_hash(absolute_path)
88
+ generate_cached_path_from_hash(relative_path, hash)
89
+ end
90
+
91
+ def generate_cached_path_from_hash(relative_path, hash)
92
+ extname = File.extname(relative_path)
93
+ "%s%s%s" % [cache_prefix, hash, extname]
94
+ end
95
+
96
+ def generate_cached_url(relative_path)
97
+ cached_path = self.cached_paths[relative_path]
98
+ "%s://%s%s" % [protocol, host, cached_path]
99
+ end
100
+
101
+ def package
102
+ Jammit.package!({
103
+ :config_path => assets_yml_path,
104
+ :output_folder => packages_path,
105
+ :force => true
106
+ })
107
+ end
108
+
109
+ def public_pathname
110
+ Pathname.new(public_path)
111
+ end
112
+
113
+ def cacheable_public_files
114
+ Pathname.glob(public_pathname + "**" + "*.{#{extensions.join(",")}}")
115
+ end
116
+
117
+ def scan_public
118
+ cacheable_public_files.each do |absolute_pathname|
119
+ relative_path = "/" + absolute_pathname.relative_path_from(public_pathname).to_s
120
+ save_cached_path_from_path(relative_path, absolute_pathname.to_s)
121
+ end
122
+ end
123
+
124
+ def symlink
125
+ cached_paths.each_pair do |relative_path, cached_path|
126
+ # Strip leading / from relative path to determine absolute path
127
+ src_u_path = File.join(public_path, relative_path[1..relative_path.length])
128
+ dst_u_path = File.join(public_path, cached_path[1..cached_path.length])
129
+
130
+ # Gzip version of asset
131
+ src_c_path = File.join(public_path, (relative_path[1..relative_path.length] + ".gz"))
132
+ dst_c_path = File.join(public_path, (cached_path[1..cached_path.length] + ".gz"))
133
+
134
+ # Create root directory
135
+ FileUtils.mkdir_p(File.dirname(dst_u_path))
136
+
137
+ # Create relative symlink from RAILS_ROOT/public/cache/$MD5SUM.$EXT to original file
138
+ File.symlink(".." + relative_path, dst_u_path.to_s) if !File.exists?(dst_u_path)
139
+ File.symlink(".." + relative_path, dst_c_path.to_s) if !File.exists?(dst_c_path) && File.exists?(src_c_path)
140
+
141
+ cached_urls[relative_path] = generate_cached_url(relative_path)
142
+ end
143
+ end
144
+
145
+ def write_lockfile
146
+ puts "writing lockfile #{lock_yml_path}"
147
+
148
+ File.open(lock_yml_path, "w") do |lockfile|
149
+ lockfile.puts cached_urls.to_yaml
150
+ end
151
+ end
47
152
 
48
153
  end
49
154
 
@@ -0,0 +1,9 @@
1
+ Capistrano::Configuration.instance(:must_exist).load do
2
+
3
+ set :strategy, Capistrano::Deploy::Strategy::Fingerjam.new(self)
4
+ set :copy_cache, true
5
+
6
+ _cset(:cache_host) { "www.example.com" }
7
+
8
+ end
9
+
@@ -0,0 +1,75 @@
1
+ require "pathname"
2
+ require "jammit"
3
+ require "fingerjam"
4
+ require "capistrano/recipes/deploy/strategy/copy"
5
+
6
+ module Capistrano
7
+ module Deploy
8
+ module Strategy
9
+ class Fingerjam < Copy
10
+
11
+ def deploy!
12
+ if File.exists?(copy_cache)
13
+ logger.debug "refreshing local cache to revision #{revision} at #{copy_cache}"
14
+ system(source.sync(revision, copy_cache))
15
+ else
16
+ logger.debug "preparing local cache at #{copy_cache}"
17
+ system(source.checkout(revision, copy_cache))
18
+ end
19
+
20
+ # Check the return code of last system command and rollback if not 0
21
+ unless $? == 0
22
+ raise Capistrano::Error, "shell command failed with return code #{$?}"
23
+ end
24
+
25
+ logger.debug "copying cache to deployment staging area #{destination}"
26
+ Dir.chdir(copy_cache) do
27
+ FileUtils.mkdir_p(destination)
28
+ queue = Dir.glob("*", File::FNM_DOTMATCH)
29
+ while queue.any?
30
+ item = queue.shift
31
+ name = File.basename(item)
32
+
33
+ next if name == "." || name == ".."
34
+ next if copy_exclude.any? { |pattern| File.fnmatch(pattern, item) }
35
+
36
+ if File.symlink?(item)
37
+ FileUtils.ln_s(File.readlink(File.join(copy_cache, item)), File.join(destination, item))
38
+ elsif File.directory?(item)
39
+ queue += Dir.glob("#{item}/*", File::FNM_DOTMATCH)
40
+ FileUtils.mkdir(File.join(destination, item))
41
+ else
42
+ FileUtils.ln(File.join(copy_cache, item), File.join(destination, item))
43
+ end
44
+ end
45
+ end
46
+
47
+ File.open(File.join(destination, "REVISION"), "w") { |f| f.puts(revision) }
48
+
49
+ fingerjam
50
+
51
+ logger.trace "compressing #{destination} to #{filename}"
52
+ Dir.chdir(tmpdir) { system(compress(File.basename(destination), File.basename(filename)).join(" ")) }
53
+
54
+ upload(filename, remote_filename)
55
+ run "cd #{configuration[:releases_path]} && #{decompress(remote_filename).join(" ")} && rm #{remote_filename}"
56
+ ensure
57
+ FileUtils.rm filename rescue nil
58
+ FileUtils.rm_rf destination rescue nil
59
+ end
60
+
61
+ def fingerjam
62
+ logger.trace "packaging assets with fingerjam for #{cache_host} to #{destination}"
63
+
64
+ ::Fingerjam::Base.configure(
65
+ :host => cache_host,
66
+ :root_path => destination
67
+ )
68
+
69
+ ::Fingerjam::Base.package_and_lock!
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,34 +1,3 @@
1
- Capistrano::Configuration.instance(:must_exist).load do
1
+ require "fingerjam/capistrano/strategy"
2
+ require "fingerjam/capistrano/configuration"
2
3
 
3
- namespace :fingerjam do
4
-
5
- desc "Package, lock and upload assets"
6
- task :upload_public, { :roles => :web } do
7
- run_locally "rake fingerjam:package"
8
- run_locally "rake fingerjam:lock"
9
-
10
- lockfile = File.realpath(File.join("config", "assets.lock.yml"))
11
- public_path = File.realpath(File.join("public"))
12
-
13
- YAML.load_file(lockfile).each do |path, hash|
14
- local_path = File.join(public_path, path)
15
- remote_path = File.join(cache_to, hash, path)
16
- run "mkdir -p #{File.dirname(remote_path)}"
17
- top.upload(local_path, remote_path)
18
- end
19
-
20
- top.upload(lockfile, File.join(release_path, "config", "assets.lock.yml"))
21
- end
22
-
23
- desc "Upload lockfile"
24
- task :upload_lockfile, { :roles => :app } do
25
- lockfile = File.realpath(File.join("config", "assets.lock.yml"))
26
- top.upload(lockfile, File.join(release_path, "config", "assets.lock.yml"))
27
- end
28
-
29
- end
30
-
31
- after "deploy:finalize_update", "fingerjam:upload_public"
32
- after "deploy:finalize_update", "fingerjam:upload_lockfile"
33
-
34
- end
@@ -3,19 +3,21 @@ module Fingerjam
3
3
 
4
4
  # Used by Rails view helpers
5
5
  def rewrite_asset_path(source, path = nil)
6
- return Fingerjam::Base.hashed_path(source) if Fingerjam::Base.enabled? && Fingerjam::Base.hashed?(source)
7
-
8
- if path && path.respond_to?(:call)
9
- return path.call(source)
10
- elsif path && path.is_a?(String)
11
- return path % [source]
12
- end
13
-
14
- asset_id = rails_asset_id(source)
15
- if asset_id.blank?
16
- source
6
+ if Fingerjam::Base.enabled? && Fingerjam::Base.cached?(source)
7
+ Fingerjam::Base.cached_url(source)
17
8
  else
18
- source + "?#{asset_id}"
9
+ if path && path.respond_to?(:call)
10
+ return path.call(source)
11
+ elsif path && path.is_a?(String)
12
+ return path % [source]
13
+ end
14
+
15
+ asset_id = rails_asset_id(source)
16
+ if asset_id.blank?
17
+ source
18
+ else
19
+ source + "?#{asset_id}"
20
+ end
19
21
  end
20
22
  end
21
23
 
@@ -2,11 +2,8 @@ module Jammit
2
2
  class Compressor
3
3
 
4
4
  # Used by rake fingerjam:package
5
- def rewrite_asset_path(path, file_path)
6
- return Fingerjam::Base.generate_path(path, Fingerjam::Base.generate_hash(file_path))
7
-
8
- asset_id = rails_asset_id(file_path)
9
- (!asset_id || asset_id == '') ? path : "#{path}?#{asset_id}"
5
+ def rewrite_asset_path(relative_path, absolute_path)
6
+ Fingerjam::Base.save_cached_url_from_path(relative_path, absolute_path)
10
7
  end
11
8
 
12
9
  end
@@ -6,9 +6,5 @@ module Fingerjam
6
6
  initializer "fingerjam.configure_rails_initialization" do
7
7
  ActionView::Base.send(:include, Fingerjam::Helpers)
8
8
  end
9
-
10
- rake_tasks do
11
- load "tasks/fingerjam.rake"
12
- end
13
9
  end
14
10
  end
data/lib/fingerjam.rb CHANGED
@@ -1,3 +1,7 @@
1
+ require "active_support/core_ext/class/attribute_accessors"
2
+ require "digest/md5"
3
+ require "yaml"
4
+
1
5
  require "fingerjam/base"
2
6
  require "fingerjam/helpers"
3
7
  require "fingerjam/jammit"
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 3
7
+ - 4
8
8
  - 0
9
- version: 0.3.0
9
+ version: 0.4.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Steve Hoeksema
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-09 00:00:00 +13:00
17
+ date: 2011-01-27 00:00:00 +13:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -59,8 +59,21 @@ dependencies:
59
59
  prerelease: false
60
60
  version_requirements: *id003
61
61
  - !ruby/object:Gem::Dependency
62
- name: rspec
62
+ name: activesupport
63
63
  requirement: &id004 !ruby/object:Gem::Requirement
64
+ none: false
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ segments:
69
+ - 0
70
+ version: "0"
71
+ type: :runtime
72
+ prerelease: false
73
+ version_requirements: *id004
74
+ - !ruby/object:Gem::Dependency
75
+ name: rspec
76
+ requirement: &id005 !ruby/object:Gem::Requirement
64
77
  none: false
65
78
  requirements:
66
79
  - - ~>
@@ -72,10 +85,10 @@ dependencies:
72
85
  version: 2.1.0
73
86
  type: :development
74
87
  prerelease: false
75
- version_requirements: *id004
88
+ version_requirements: *id005
76
89
  - !ruby/object:Gem::Dependency
77
90
  name: bundler
78
- requirement: &id005 !ruby/object:Gem::Requirement
91
+ requirement: &id006 !ruby/object:Gem::Requirement
79
92
  none: false
80
93
  requirements:
81
94
  - - ~>
@@ -87,10 +100,10 @@ dependencies:
87
100
  version: 1.0.0
88
101
  type: :development
89
102
  prerelease: false
90
- version_requirements: *id005
103
+ version_requirements: *id006
91
104
  - !ruby/object:Gem::Dependency
92
105
  name: jeweler
93
- requirement: &id006 !ruby/object:Gem::Requirement
106
+ requirement: &id007 !ruby/object:Gem::Requirement
94
107
  none: false
95
108
  requirements:
96
109
  - - ~>
@@ -102,10 +115,10 @@ dependencies:
102
115
  version: 1.5.1
103
116
  type: :development
104
117
  prerelease: false
105
- version_requirements: *id006
118
+ version_requirements: *id007
106
119
  - !ruby/object:Gem::Dependency
107
120
  name: rcov
108
- requirement: &id007 !ruby/object:Gem::Requirement
121
+ requirement: &id008 !ruby/object:Gem::Requirement
109
122
  none: false
110
123
  requirements:
111
124
  - - ">="
@@ -115,7 +128,7 @@ dependencies:
115
128
  version: "0"
116
129
  type: :development
117
130
  prerelease: false
118
- version_requirements: *id007
131
+ version_requirements: *id008
119
132
  description: Fingerjam uploads your Jammit-compressed assets with fingerprinted filenames so they can be cached indefinitely
120
133
  email: steve@seven.net.nz
121
134
  executables: []
@@ -139,11 +152,12 @@ files:
139
152
  - lib/fingerjam.rb
140
153
  - lib/fingerjam/base.rb
141
154
  - lib/fingerjam/capistrano.rb
155
+ - lib/fingerjam/capistrano/configuration.rb
156
+ - lib/fingerjam/capistrano/strategy.rb
142
157
  - lib/fingerjam/fix_jammit_encoding.rb
143
158
  - lib/fingerjam/helpers.rb
144
159
  - lib/fingerjam/jammit.rb
145
160
  - lib/fingerjam/railtie.rb
146
- - lib/tasks/fingerjam.rake
147
161
  - spec/fingerjam_spec.rb
148
162
  - spec/spec_helper.rb
149
163
  has_rdoc: true
@@ -160,7 +174,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
160
174
  requirements:
161
175
  - - ">="
162
176
  - !ruby/object:Gem::Version
163
- hash: -2735618090215588831
177
+ hash: -4335170652372307643
164
178
  segments:
165
179
  - 0
166
180
  version: "0"
@@ -1,28 +0,0 @@
1
- require "pathname"
2
- require "yaml"
3
- require "jammit"
4
-
5
- namespace :fingerjam do
6
-
7
- desc "Package assets with Jammit"
8
- task :package => :environment do
9
- Jammit.package!(:force => true)
10
- end
11
-
12
- desc "Lock packages to assets.lock.yml"
13
- task :lock => :environment do
14
- relative_root = Pathname.new(Rails.root) + "public"
15
-
16
- hashes = {}
17
-
18
- Pathname.glob(relative_root + "**" + "*.{#{Fingerjam::Base.extensions.join(",")}}").each do |absolute_path|
19
- relative_path = "/" + absolute_path.relative_path_from(relative_root).to_s
20
- hashes[relative_path] = Fingerjam::Base.generate_hash(absolute_path)
21
- end
22
-
23
- File.open(Fingerjam::Base.lockfile, "w") do |lockfile|
24
- lockfile.puts hashes.to_yaml
25
- end
26
- end
27
-
28
- end