Permalink
Browse files

Python and Ruby scripts to access CSS URL rewriting functions

  • Loading branch information...
1 parent d40a97b commit a4de58c7bca213bc153686835906222bd515153e @fidothe fidothe committed Apr 11, 2011
View
@@ -1,2 +1,6 @@
require 'bundler'
Bundler::GemHelper.install_tasks
+
+require 'rspec/core/rake_task'
+
+RSpec::Core::RakeTask.new :spec
View
@@ -23,4 +23,5 @@ Gem::Specification.new do |s|
s.require_paths = ["rb"]
s.add_dependency 'actionpack', '~> 3.0.0'
+ s.add_development_dependency 'rspec', '~> 2.5.0'
end
View
@@ -0,0 +1,10 @@
+#!/usr/bin/env ruby
+
+require File.expand_path('rb/cdn_helpers.rb', File.dirname(__FILE__))
+
+css_file_path = ARGV[0]
+css_file = File.open(css_file_path)
+public_root_path = ARGV[1]
+url_prefix = ARGV[2]
+
+CdnHelpers::CssRewriter.rewrite_css_file(css_file_path, public_root_path, url_prefix)
No changes.
@@ -0,0 +1,13 @@
+from django.core.management.base import BaseCommand
+from django.conf import settings
+import glob, os.path
+from subprocess import call
+
+class Command(BaseCommand):
+ def handle(self, *args, **options):
+ path_to_ruby_script = os.path.normpath(os.path.join(os.path.dirname(__file__), '../../../../process_css'))
+ css_file_paths = glob.glob(os.path.join(settings.MEDIA_ROOT, '**/*.css'))
+
+ for css_file_path in css_file_paths:
+ call([path_to_ruby_script, css_file_path, settings.MEDIA_ROOT, settings.MEDIA_URL])
+
View
@@ -6,13 +6,50 @@ def self.asset_cache
end
def self.call(path)
+ hash_file(path, Rails.root.join('public'))
+ end
+
+ def self.hash_file(path, public_root_path)
unless asset_cache.has_key?(path)
- file_path = Rails.root.join('public', path.sub(/^\//, '')).to_s
+ file_path = public_root_path.join(path.sub(/^\//, '')).to_s
sha1 = Digest::SHA1.file(file_path).hexdigest
extension = File.extname(path)
- return asset_cache[path] = path + "/#{sha1[0..7]}#{extension}"
+ return asset_cache[path] = path + "/#{sha1[0..7]}#{extension}"
end
asset_cache[path]
end
end
+
+ module CssRewriter
+ def self.rewrite_css_file(css_file_path, public_root_path, url_prefix = '/')
+ css_file = File.open(css_file_path)
+ output = process_css_file(css_file, css_file_path, public_root_path, url_prefix)
+ File.open(css_file_path, 'w') { |f| f.write(output) }
+ end
+
+ def self.process_css_file(css_file, css_file_path, public_root_path, url_prefix = '/')
+ out_lines = []
+ css_file_path = Pathname.new(css_file_path).realpath
+ context_path = css_file_path.parent
+ while line = css_file.gets
+ out_lines << line.gsub(/url\(["']?([^"'\)]+)["']?\)/) do |url_match|
+ if URI.parse($1).scheme.nil?
+ local_url = Pathname.new($1)
+ if local_url.relative?
+ url = context_path.join(local_url).cleanpath.relative_path_from(public_root_path).to_s
+ else
+ url_prefix = url_prefix + '/' unless url_prefix.rindex('/') == (url_prefix.length - 1)
+ local_url = local_url.to_s[(url_prefix.length - 1)..-1] if local_url.to_s.index(url_prefix) == 0
+ url = public_root_path.join(local_url[1..-1]).cleanpath.relative_path_from(public_root_path).to_s
+ end
+ "url(#{CdnHelpers::AssetPath.hash_file("/" + url, public_root_path)})"
+ else
+ "url(#{$1})"
+ end
+ end
+ end
+ css_file.close
+ out_lines.join("")
+ end
+ end
end
@@ -0,0 +1,13 @@
+namespace :cdn do
+ task :css_urls => :environment do
+ require 'cdn_helpers'
+ require 'pathname'
+
+ public_root_path = Pathname.new('public').realpath
+ FileList['public/**/*.css'].each do |css_file_path|
+ css_file_path = Pathname.new(css_file_path).realpath
+ public_path = Rails.root.join('public')
+ CdnHelpers.CssRewriter.rewrite_css_file(css_file_path, public_path)
+ end
+ end
+end
View
@@ -0,0 +1,12 @@
+require 'cdn_helpers'
+require 'rails'
+
+module CdnHelpers
+ class Railtie < Rails::Railtie
+ railtie_name :cdn_helpers
+
+ rake_tasks do
+ load "cdn_helpers.rake"
+ end
+ end
+end
View
@@ -0,0 +1,32 @@
+require 'spec_helper'
+require 'stringio'
+
+describe CdnHelpers::CssRewriter do
+ def css_path
+ File.expand_path('fixtures/dir/spec.css', File.dirname(__FILE__))
+ end
+
+ def public_root_path
+ Pathname.new(File.expand_path('fixtures', File.dirname(__FILE__)))
+ end
+
+ it "correctly rewrites a relative URL (no ../)" do
+ CdnHelpers::CssRewriter.process_css_file(StringIO.new('background-image: url("eg.txt")'), css_path, public_root_path).
+ should == 'background-image: url(/dir/eg.txt/1ba05a2d.txt)'
+ end
+
+ it "correctly rewrites a relative URL (with ../)" do
+ CdnHelpers::CssRewriter.process_css_file(StringIO.new("background-image: url('../eg.txt')"), css_path, public_root_path).
+ should == 'background-image: url(/eg.txt/13c1f102.txt)'
+ end
+
+ it "correctly rewrites an absolute local URL (starts with /)" do
+ CdnHelpers::CssRewriter.process_css_file(StringIO.new('background-image: url("/eg.txt")'), css_path, public_root_path).
+ should == 'background-image: url(/eg.txt/13c1f102.txt)'
+ end
+
+ it "correctly ignores an http:// url" do
+ CdnHelpers::CssRewriter.process_css_file(StringIO.new('background-image: url("http://things.com/nice.png")'), css_path, public_root_path).
+ should == 'background-image: url(http://things.com/nice.png)'
+ end
+end
View
@@ -0,0 +1 @@
+Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly. Some more text, repeatedly repeated repeatedly.
@@ -0,0 +1 @@
+/* Here to keep Pathname happy */
View
@@ -0,0 +1 @@
+Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly. Some text, repeated repeatedly.
View
@@ -0,0 +1,9 @@
+$:.unshift(File.expand_path(".")) unless $:.include?(File.expand_path("."))
+$:.unshift(File.expand_path("../rb")) unless $:.include?(File.expand_path("../rb"))
+
+require 'bundler'
+Bundler.require :default, :test
+
+require 'rspec/core'
+require 'rspec/expectations'
+require 'rspec/matchers'

0 comments on commit a4de58c

Please sign in to comment.