require 'json' require 'pp' require 'find' include BeforeHook namespace :bower do desc "Install components from bower" task :install, :options do |_, args| args.with_defaults(:options => '') perform do |bower| sh "#{bower} install #{args[:options]}" end end desc "Update bower components" task :update, :options do |_, args| args.with_defaults(:options => '') perform do |bower| sh "#{bower} update #{args[:options]}" end end desc "List bower components" task :list do perform false do |bower| sh "#{bower} list" end end namespace :update do desc "Update existing components and uninstalls extraneous components" task :prune, :options do |_, args| args.with_defaults(:options => '') perform do |bower| sh "#{bower} update #{args[:options]} && #{bower} prune #{args[:options]}" end end end desc "Resolve assets paths in bower components" task :resolve do perform false do resolve_asset_paths end end desc "Attempt to keep only files listed in 'main' of each component's bower.json" task :clean do perform false do remove_extra_files end end end before 'assets:precompile' do BowerRails.tasks.map do |task| Rake::Task[task].invoke end end def perform remove_components = true, &block entries = Dir.entries(get_bower_root_path) npm_path = File.join(get_bower_root_path, 'node_modules', '.bin') bower = find_command('bower', [npm_path]) if bower.nil? $stderr.puts < #{image_path}" "url(<%= asset_path '#{image_path}' %>)" end # Replace CSS with ERB CSS file with resolved asset paths FileUtils.rm(filename) File.write(filename + '.erb', new_contents) end end end def remove_extra_files puts "\nAttempting to remove all but main files as specified by bower\n" Dir['bower_components/*'].each do |component_dir| if File.exists?(File.join(component_dir, 'bower.json')) bower_file = File.read(File.join(component_dir, 'bower.json')) elsif File.exists?(File.join(component_dir, '.bower.json')) bower_file = File.read(File.join(component_dir, '.bower.json')) else next end # parse bower.json bower_json = JSON.parse(bower_file) main_files = bower_json['main'] next unless main_files # handle singular or multiple files main_files = [main_files] unless main_files.is_a?(Array) # Remove "./" relative path from main file strings main_files.map! { |file| File.join(component_dir, file.gsub(/^\.\//, '')) } # delete all files that are not in main Find.find(component_dir).reverse_each do |file_or_dir| next if main_files.include?(file_or_dir) if File.directory?(file_or_dir) Dir.rmdir(file_or_dir) if (Dir.entries(file_or_dir) - %w[ . .. ]).empty? else FileUtils.rm(file_or_dir) end end end end # http://stackoverflow.com/questions/2108727/which-in-ruby-checking-if-program-exists-in-path-from-ruby def find_command(cmd, paths = []) exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] paths += ENV['PATH'].split(File::PATH_SEPARATOR) paths.each do |path| exts.each do |ext| exe = File.join(path, "#{cmd}#{ext}") return exe if (File.executable?(exe) && File.file?(exe)) end end nil end