Commit 2bfd8b1f authored by Rene Saarsoo's avatar Rene Saarsoo
Browse files

Initial prototype of caching parsed source code.

At the moment the cache is just saved to .cache/ in current dir.

The parsed data is serialized into binary format using Marshal,
which correctly preserves all the data types and is additionally
really fast.

Refs #446
parent 1cb53766
Loading
Loading
Loading
Loading
+8 −1
Original line number Diff line number Diff line
@@ -3,6 +3,7 @@ require 'jsduck/util/io'
require 'jsduck/parser'
require 'jsduck/source/file'
require 'jsduck/logger'
require 'jsduck/cache'

module JsDuck

@@ -11,11 +12,17 @@ module JsDuck
  class BatchParser

    def self.parse(opts)
      cache = Cache.new(Dir.getwd + "/.cache")

      Util::Parallel.map(opts.input_files) do |fname|
        Logger.log("Parsing", fname)
        begin
          source = Util::IO.read(fname)
          docs = nil
          unless docs = cache.read(source)
            docs = Parser.new.parse(source, fname, opts)
            cache.write(source, docs)
          end
          Source::File.new(source, docs, fname)
        rescue
          Logger.fatal_backtrace("Error while parsing #{fname}", $!)

lib/jsduck/cache.rb

0 → 100644
+43 −0
Original line number Diff line number Diff line
require 'digest/md5'
require 'fileutils'

module JsDuck

  # Reads/writes parsed files in cache.
  class Cache
    def initialize(cache_dir)
      @cache_dir = cache_dir
      FileUtils.mkdir(cache_dir) unless File.exists?(cache_dir)
    end

    # Given contents of a source file, reads the already parsed data
    # structure from cache.  Returns nil when not found.
    def read(file_contents)
      fname = file_name(file_contents)
      if File.exists?(fname)
        File.open(fname, "rb") {|file| Marshal::load(file) }
      else
        nil
      end
    end

    # Writes parse data into cache under a name generated from the
    # contents of a source file.
    def write(file_contents, data)
      fname = file_name(file_contents)
      File.open(fname, "wb") {|file| Marshal::dump(data, file) }
    end

    private

    def file_name(file_contents)
      @cache_dir + "/" + md5(file_contents) + ".dat"
    end

    def md5(string)
      Digest::MD5.hexdigest(string)
    end

  end

end