fingerjam 0.3.0 → 0.4.0

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/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