gemstash 1.0.0.pre.1-java
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.
- checksums.yaml +7 -0
- data/CODE_OF_CONDUCT.md +13 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +139 -0
- data/Rakefile +35 -0
- data/bin/console +14 -0
- data/bin/gemstash +3 -0
- data/bin/setup +5 -0
- data/docs/config.md +136 -0
- data/docs/debug.md +24 -0
- data/docs/deploy.md +30 -0
- data/docs/mirror.md +30 -0
- data/docs/multiple_sources.md +68 -0
- data/docs/private_gems.md +140 -0
- data/docs/reference.md +308 -0
- data/exe/gemstash +3 -0
- data/gemstash.gemspec +47 -0
- data/gemstash.png +0 -0
- data/lib/gemstash.rb +26 -0
- data/lib/gemstash/authorization.rb +87 -0
- data/lib/gemstash/cache.rb +79 -0
- data/lib/gemstash/cli.rb +71 -0
- data/lib/gemstash/cli/authorize.rb +69 -0
- data/lib/gemstash/cli/base.rb +46 -0
- data/lib/gemstash/cli/setup.rb +173 -0
- data/lib/gemstash/cli/start.rb +52 -0
- data/lib/gemstash/cli/status.rb +21 -0
- data/lib/gemstash/cli/stop.rb +21 -0
- data/lib/gemstash/config.ru +13 -0
- data/lib/gemstash/configuration.rb +41 -0
- data/lib/gemstash/db.rb +15 -0
- data/lib/gemstash/db/authorization.rb +20 -0
- data/lib/gemstash/db/dependency.rb +50 -0
- data/lib/gemstash/db/rubygem.rb +14 -0
- data/lib/gemstash/db/version.rb +51 -0
- data/lib/gemstash/dependencies.rb +93 -0
- data/lib/gemstash/env.rb +150 -0
- data/lib/gemstash/gem_fetcher.rb +50 -0
- data/lib/gemstash/gem_pusher.rb +125 -0
- data/lib/gemstash/gem_source.rb +37 -0
- data/lib/gemstash/gem_source/dependency_caching.rb +40 -0
- data/lib/gemstash/gem_source/private_source.rb +139 -0
- data/lib/gemstash/gem_source/rack_middleware.rb +22 -0
- data/lib/gemstash/gem_source/upstream_source.rb +183 -0
- data/lib/gemstash/gem_unyanker.rb +61 -0
- data/lib/gemstash/gem_yanker.rb +61 -0
- data/lib/gemstash/http_client.rb +77 -0
- data/lib/gemstash/logging.rb +93 -0
- data/lib/gemstash/migrations/01_gem_dependencies.rb +41 -0
- data/lib/gemstash/migrations/02_authorizations.rb +12 -0
- data/lib/gemstash/puma.rb +6 -0
- data/lib/gemstash/rack_env_rewriter.rb +66 -0
- data/lib/gemstash/specs_builder.rb +93 -0
- data/lib/gemstash/storage.rb +207 -0
- data/lib/gemstash/upstream.rb +65 -0
- data/lib/gemstash/version.rb +4 -0
- data/lib/gemstash/web.rb +97 -0
- metadata +304 -0
| @@ -0,0 +1,52 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
            require "puma/cli"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Gemstash
         | 
| 5 | 
            +
              class CLI
         | 
| 6 | 
            +
                # This implements the command line start task to start the Gemstash server:
         | 
| 7 | 
            +
                #  $ gemstash start
         | 
| 8 | 
            +
                class Start < Gemstash::CLI::Base
         | 
| 9 | 
            +
                  def run
         | 
| 10 | 
            +
                    prepare
         | 
| 11 | 
            +
                    setup_logging
         | 
| 12 | 
            +
                    store_daemonized
         | 
| 13 | 
            +
                    Puma::CLI.new(args, Gemstash::Logging::StreamLogger.puma_events).run
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                private
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def setup_logging
         | 
| 19 | 
            +
                    return unless daemonize?
         | 
| 20 | 
            +
                    Gemstash::Logging.setup_logger(gemstash_env.base_file("server.log"))
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  def store_daemonized
         | 
| 24 | 
            +
                    Gemstash::Env.daemonized = daemonize?
         | 
| 25 | 
            +
                  end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                  def daemonize?
         | 
| 28 | 
            +
                    @cli.options[:daemonize]
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def puma_config
         | 
| 32 | 
            +
                    File.expand_path("../../puma.rb", __FILE__)
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                  def args
         | 
| 36 | 
            +
                    config_args + pidfile_args + daemonize_args
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def config_args
         | 
| 40 | 
            +
                    ["--config", puma_config]
         | 
| 41 | 
            +
                  end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                  def daemonize_args
         | 
| 44 | 
            +
                    if daemonize?
         | 
| 45 | 
            +
                      ["--daemon"]
         | 
| 46 | 
            +
                    else
         | 
| 47 | 
            +
                      []
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
            require "puma/control_cli"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Gemstash
         | 
| 5 | 
            +
              class CLI
         | 
| 6 | 
            +
                # This implements the command line status task to check the server status:
         | 
| 7 | 
            +
                #  $ gemstash status
         | 
| 8 | 
            +
                class Status < Gemstash::CLI::Base
         | 
| 9 | 
            +
                  def run
         | 
| 10 | 
            +
                    prepare
         | 
| 11 | 
            +
                    Puma::ControlCLI.new(args).run
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                private
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def args
         | 
| 17 | 
            +
                    pidfile_args + %w(status)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,21 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
            require "puma/control_cli"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Gemstash
         | 
| 5 | 
            +
              class CLI
         | 
| 6 | 
            +
                # This implements the command line stop task to stop the Gemstash server:
         | 
| 7 | 
            +
                #  $ gemstash stop
         | 
| 8 | 
            +
                class Stop < Gemstash::CLI::Base
         | 
| 9 | 
            +
                  def run
         | 
| 10 | 
            +
                    prepare
         | 
| 11 | 
            +
                    Puma::ControlCLI.new(args).run
         | 
| 12 | 
            +
                  end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                private
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  def args
         | 
| 17 | 
            +
                    pidfile_args + %w(stop)
         | 
| 18 | 
            +
                  end
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
            end
         | 
| @@ -0,0 +1,13 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
            require "puma/commonlogger"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            use Rack::Deflater
         | 
| 5 | 
            +
            use Gemstash::Logging::RackMiddleware
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            if Gemstash::Env.daemonized?
         | 
| 8 | 
            +
              use Puma::CommonLogger, Gemstash::Logging::StreamLogger.for_stdout
         | 
| 9 | 
            +
            end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            use Gemstash::Env::RackMiddleware, Gemstash::Env.current
         | 
| 12 | 
            +
            use Gemstash::GemSource::RackMiddleware
         | 
| 13 | 
            +
            run Gemstash::Web.new(gemstash_env: Gemstash::Env.current)
         | 
| @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            require "yaml"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Gemstash
         | 
| 4 | 
            +
              #:nodoc:
         | 
| 5 | 
            +
              class Configuration
         | 
| 6 | 
            +
                DEFAULTS = {
         | 
| 7 | 
            +
                  :cache_type => "memory",
         | 
| 8 | 
            +
                  :base_path => File.expand_path("~/.gemstash"),
         | 
| 9 | 
            +
                  :db_adapter => "sqlite3",
         | 
| 10 | 
            +
                  :bind => "tcp://0.0.0.0:9292",
         | 
| 11 | 
            +
                  :rubygems_url => "https://www.rubygems.org"
         | 
| 12 | 
            +
                }.freeze
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                DEFAULT_FILE = File.expand_path("~/.gemstash/config.yml").freeze
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def initialize(file: nil, config: nil)
         | 
| 17 | 
            +
                  if config
         | 
| 18 | 
            +
                    @config = DEFAULTS.merge(config).freeze
         | 
| 19 | 
            +
                    return
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  file ||= DEFAULT_FILE
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  if File.exist?(file)
         | 
| 25 | 
            +
                    @config = YAML.load_file(file)
         | 
| 26 | 
            +
                    @config = DEFAULTS.merge(@config)
         | 
| 27 | 
            +
                    @config.freeze
         | 
| 28 | 
            +
                  else
         | 
| 29 | 
            +
                    @config = DEFAULTS
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def default?(key)
         | 
| 34 | 
            +
                  @config[key] == DEFAULTS[key]
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def [](key)
         | 
| 38 | 
            +
                  @config[key]
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
              end
         | 
| 41 | 
            +
            end
         | 
    
        data/lib/gemstash/db.rb
    ADDED
    
    | @@ -0,0 +1,15 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Gemstash
         | 
| 4 | 
            +
              # Module containing the DB models.
         | 
| 5 | 
            +
              module DB
         | 
| 6 | 
            +
                raise "Gemstash::DB cannot be loaded until the Gemstash::Env is available" unless Gemstash::Env.available?
         | 
| 7 | 
            +
                Sequel::Model.db = Gemstash::Env.current.db
         | 
| 8 | 
            +
                Sequel::Model.raise_on_save_failure = true
         | 
| 9 | 
            +
                Sequel::Model.plugin :timestamps, update_on_create: true
         | 
| 10 | 
            +
                autoload :Authorization, "gemstash/db/authorization"
         | 
| 11 | 
            +
                autoload :Dependency,    "gemstash/db/dependency"
         | 
| 12 | 
            +
                autoload :Rubygem,       "gemstash/db/rubygem"
         | 
| 13 | 
            +
                autoload :Version,       "gemstash/db/version"
         | 
| 14 | 
            +
              end
         | 
| 15 | 
            +
            end
         | 
| @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Gemstash
         | 
| 4 | 
            +
              module DB
         | 
| 5 | 
            +
                # Sequel model for authorizations table.
         | 
| 6 | 
            +
                class Authorization < Sequel::Model
         | 
| 7 | 
            +
                  def self.insert_or_update(auth_key, permissions)
         | 
| 8 | 
            +
                    db.transaction do
         | 
| 9 | 
            +
                      record = self[auth_key: auth_key]
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                      if record
         | 
| 12 | 
            +
                        record.update(permissions: permissions)
         | 
| 13 | 
            +
                      else
         | 
| 14 | 
            +
                        create(auth_key: auth_key, permissions: permissions)
         | 
| 15 | 
            +
                      end
         | 
| 16 | 
            +
                    end
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
            end
         | 
| @@ -0,0 +1,50 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Gemstash
         | 
| 4 | 
            +
              module DB
         | 
| 5 | 
            +
                # Sequel model for dependencies table.
         | 
| 6 | 
            +
                class Dependency < Sequel::Model
         | 
| 7 | 
            +
                  def self.insert_by_spec(version_id, spec)
         | 
| 8 | 
            +
                    spec.runtime_dependencies.each do |dep|
         | 
| 9 | 
            +
                      requirements = dep.requirement.requirements
         | 
| 10 | 
            +
                      requirements = requirements.map {|r| "#{r.first} #{r.last}" }
         | 
| 11 | 
            +
                      requirements = requirements.join(", ")
         | 
| 12 | 
            +
                      create(version_id: version_id,
         | 
| 13 | 
            +
                             rubygem_name: dep.name,
         | 
| 14 | 
            +
                             requirements: requirements)
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                  def self.fetch(gems)
         | 
| 19 | 
            +
                    results = db["
         | 
| 20 | 
            +
                      SELECT rubygem.name,
         | 
| 21 | 
            +
                             version.number, version.platform,
         | 
| 22 | 
            +
                             dependency.rubygem_name, dependency.requirements
         | 
| 23 | 
            +
                      FROM rubygems rubygem
         | 
| 24 | 
            +
                      JOIN versions version
         | 
| 25 | 
            +
                        ON version.rubygem_id = rubygem.id
         | 
| 26 | 
            +
                      LEFT JOIN dependencies dependency
         | 
| 27 | 
            +
                        ON dependency.version_id = version.id
         | 
| 28 | 
            +
                      WHERE rubygem.name IN ?
         | 
| 29 | 
            +
                        AND version.indexed = ?", gems.to_a, true].to_a
         | 
| 30 | 
            +
                    results.group_by {|r| r[:name] }.each do |gem, rows|
         | 
| 31 | 
            +
                      requirements = rows.group_by {|r| [r[:number], r[:platform]] }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                      value = requirements.map do |version, r|
         | 
| 34 | 
            +
                        deps = r.map {|x| [x[:rubygem_name], x[:requirements]] }
         | 
| 35 | 
            +
                        deps = [] if deps.size == 1 && deps.first.first.nil?
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                        {
         | 
| 38 | 
            +
                          :name => gem,
         | 
| 39 | 
            +
                          :number => version.first,
         | 
| 40 | 
            +
                          :platform => version.last,
         | 
| 41 | 
            +
                          :dependencies => deps
         | 
| 42 | 
            +
                        }
         | 
| 43 | 
            +
                      end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                      yield(gem, value)
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
                  end
         | 
| 48 | 
            +
                end
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| @@ -0,0 +1,14 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Gemstash
         | 
| 4 | 
            +
              module DB
         | 
| 5 | 
            +
                # Sequel model for rubygems table.
         | 
| 6 | 
            +
                class Rubygem < Sequel::Model
         | 
| 7 | 
            +
                  def self.find_or_insert(spec)
         | 
| 8 | 
            +
                    record = self[name: spec.name]
         | 
| 9 | 
            +
                    return record.id if record
         | 
| 10 | 
            +
                    new(name: spec.name).tap(&:save).id
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
              end
         | 
| 14 | 
            +
            end
         | 
| @@ -0,0 +1,51 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Gemstash
         | 
| 4 | 
            +
              module DB
         | 
| 5 | 
            +
                # Sequel model for versions table.
         | 
| 6 | 
            +
                class Version < Sequel::Model
         | 
| 7 | 
            +
                  many_to_one :rubygem
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def deindex
         | 
| 10 | 
            +
                    update(indexed: false)
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  def reindex
         | 
| 14 | 
            +
                    update(indexed: true)
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  # This converts to the format used by /private/specs.4.8.gz
         | 
| 18 | 
            +
                  def to_spec
         | 
| 19 | 
            +
                    [rubygem.name, Gem::Version.new(number), platform]
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                  def self.for_spec_collection(prerelease: false)
         | 
| 23 | 
            +
                    where(indexed: true, prerelease: prerelease).association_join(:rubygem)
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                  def self.find_by_spec(gem_id, spec)
         | 
| 27 | 
            +
                    self[rubygem_id: gem_id,
         | 
| 28 | 
            +
                         number: spec.version.to_s,
         | 
| 29 | 
            +
                         platform: spec.platform.to_s]
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  def self.find_by_full_name(full_name)
         | 
| 33 | 
            +
                    result = self[full_name: full_name]
         | 
| 34 | 
            +
                    return result if result
         | 
| 35 | 
            +
                    # Try again with the default platform, in case it is implied
         | 
| 36 | 
            +
                    self[full_name: "#{full_name}-ruby"]
         | 
| 37 | 
            +
                  end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  def self.insert_by_spec(gem_id, spec)
         | 
| 40 | 
            +
                    gem_name = Gemstash::DB::Rubygem[gem_id].name
         | 
| 41 | 
            +
                    new(rubygem_id: gem_id,
         | 
| 42 | 
            +
                        number: spec.version.to_s,
         | 
| 43 | 
            +
                        platform: spec.platform.to_s,
         | 
| 44 | 
            +
                        full_name: "#{gem_name}-#{spec.version}-#{spec.platform}",
         | 
| 45 | 
            +
                        storage_id: spec.full_name,
         | 
| 46 | 
            +
                        indexed: true,
         | 
| 47 | 
            +
                        prerelease: spec.version.prerelease?).tap(&:save).id
         | 
| 48 | 
            +
                  end
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
              end
         | 
| 51 | 
            +
            end
         | 
| @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            require "cgi"
         | 
| 2 | 
            +
            require "set"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Gemstash
         | 
| 5 | 
            +
              #:nodoc:
         | 
| 6 | 
            +
              class Dependencies
         | 
| 7 | 
            +
                def self.for_private
         | 
| 8 | 
            +
                  new(scope: "private", db_model: Gemstash::DB::Dependency)
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def self.for_upstream(upstream, http_client)
         | 
| 12 | 
            +
                  new(scope: "upstream/#{upstream}", http_client: http_client)
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                def initialize(scope: nil, http_client: nil, db_model: nil)
         | 
| 16 | 
            +
                  @scope = scope
         | 
| 17 | 
            +
                  @http_client = http_client
         | 
| 18 | 
            +
                  @db_model = db_model
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def fetch(gems)
         | 
| 22 | 
            +
                  Fetcher.new(gems, @scope, @http_client, @db_model).fetch
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                #:nodoc:
         | 
| 26 | 
            +
                class Fetcher
         | 
| 27 | 
            +
                  include Gemstash::Env::Helper
         | 
| 28 | 
            +
                  include Gemstash::Logging
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  def initialize(gems, scope, http_client, db_model)
         | 
| 31 | 
            +
                    @gems = Set.new(gems)
         | 
| 32 | 
            +
                    @scope = scope
         | 
| 33 | 
            +
                    @http_client = http_client
         | 
| 34 | 
            +
                    @db_model = db_model
         | 
| 35 | 
            +
                    @dependencies = []
         | 
| 36 | 
            +
                  end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                  def fetch
         | 
| 39 | 
            +
                    fetch_from_cache
         | 
| 40 | 
            +
                    fetch_from_database
         | 
| 41 | 
            +
                    fetch_from_web
         | 
| 42 | 
            +
                    cache_missing
         | 
| 43 | 
            +
                    @dependencies
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                private
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                  def done?
         | 
| 49 | 
            +
                    @gems.empty?
         | 
| 50 | 
            +
                  end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                  def fetch_from_cache
         | 
| 53 | 
            +
                    gemstash_env.cache.dependencies(@scope, @gems) do |gem, value|
         | 
| 54 | 
            +
                      @gems.delete(gem)
         | 
| 55 | 
            +
                      @dependencies += value
         | 
| 56 | 
            +
                    end
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def fetch_from_database
         | 
| 60 | 
            +
                    return if done?
         | 
| 61 | 
            +
                    return unless @db_model
         | 
| 62 | 
            +
                    log.info "Querying dependencies: #{@gems.to_a.join(", ")}"
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                    @db_model.fetch(@gems) do |gem, value|
         | 
| 65 | 
            +
                      @gems.delete(gem)
         | 
| 66 | 
            +
                      gemstash_env.cache.set_dependency(@scope, gem, value)
         | 
| 67 | 
            +
                      @dependencies += value
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def fetch_from_web
         | 
| 72 | 
            +
                    return if done?
         | 
| 73 | 
            +
                    return unless @http_client
         | 
| 74 | 
            +
                    log.info "Fetching dependencies: #{@gems.to_a.join(", ")}"
         | 
| 75 | 
            +
                    gems_param = @gems.map {|gem| CGI.escape(gem) }.join(",")
         | 
| 76 | 
            +
                    fetched = @http_client.get("api/v1/dependencies?gems=#{gems_param}")
         | 
| 77 | 
            +
                    fetched = Marshal.load(fetched).group_by {|r| r[:name] }
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                    fetched.each do |gem, result|
         | 
| 80 | 
            +
                      @gems.delete(gem)
         | 
| 81 | 
            +
                      gemstash_env.cache.set_dependency(@scope, gem, result)
         | 
| 82 | 
            +
                      @dependencies += result
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  def cache_missing
         | 
| 87 | 
            +
                    @gems.each do |gem|
         | 
| 88 | 
            +
                      gemstash_env.cache.set_dependency(@scope, gem, [])
         | 
| 89 | 
            +
                    end
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
            end
         | 
    
        data/lib/gemstash/env.rb
    ADDED
    
    | @@ -0,0 +1,150 @@ | |
| 1 | 
            +
            require "gemstash"
         | 
| 2 | 
            +
            require "dalli"
         | 
| 3 | 
            +
            require "fileutils"
         | 
| 4 | 
            +
            require "sequel"
         | 
| 5 | 
            +
            require "uri"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Gemstash
         | 
| 8 | 
            +
              # Storage for application-wide variables and configuration.
         | 
| 9 | 
            +
              class Env
         | 
| 10 | 
            +
                # The Gemstash::Env must be set before being retreived via
         | 
| 11 | 
            +
                # Gemstash::Env.current. This error is thrown when that is not honored.
         | 
| 12 | 
            +
                class EnvNotSetError < StandardError
         | 
| 13 | 
            +
                end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                # Little module to provide easy access to the current Gemstash::Env.
         | 
| 16 | 
            +
                module Helper
         | 
| 17 | 
            +
                private
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def gemstash_env
         | 
| 20 | 
            +
                    Gemstash::Env.current
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                # Rack middleware to set the Gemstash::Env for the app.
         | 
| 25 | 
            +
                class RackMiddleware
         | 
| 26 | 
            +
                  def initialize(app, gemstash_env)
         | 
| 27 | 
            +
                    @app = app
         | 
| 28 | 
            +
                    @gemstash_env = gemstash_env
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  def call(env)
         | 
| 32 | 
            +
                    env["gemstash.env"] = @gemstash_env
         | 
| 33 | 
            +
                    @app.call(env)
         | 
| 34 | 
            +
                  end
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def initialize(config = nil, cache: nil, db: nil)
         | 
| 38 | 
            +
                  @config = config
         | 
| 39 | 
            +
                  @cache = cache
         | 
| 40 | 
            +
                  @db = db
         | 
| 41 | 
            +
                end
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                def self.available?
         | 
| 44 | 
            +
                  !Thread.current[:gemstash_env].nil?
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                def self.current
         | 
| 48 | 
            +
                  raise EnvNotSetError unless Thread.current[:gemstash_env]
         | 
| 49 | 
            +
                  Thread.current[:gemstash_env]
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def self.current=(value)
         | 
| 53 | 
            +
                  Thread.current[:gemstash_env] = value
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                def self.daemonized?
         | 
| 57 | 
            +
                  if @daemonized.nil?
         | 
| 58 | 
            +
                    raise "Daemonized hasn't been set yet!"
         | 
| 59 | 
            +
                  else
         | 
| 60 | 
            +
                    @daemonized
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
                end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                def self.daemonized=(value)
         | 
| 65 | 
            +
                  value = false if value.nil?
         | 
| 66 | 
            +
                  @daemonized = value
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                def config
         | 
| 70 | 
            +
                  @config ||= Gemstash::Configuration.new
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                def config=(value)
         | 
| 74 | 
            +
                  reset
         | 
| 75 | 
            +
                  @config = value
         | 
| 76 | 
            +
                end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                def reset
         | 
| 79 | 
            +
                  @config = nil
         | 
| 80 | 
            +
                  @cache = nil
         | 
| 81 | 
            +
                  @cache_client = nil
         | 
| 82 | 
            +
                  @db = nil
         | 
| 83 | 
            +
                end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                def base_path
         | 
| 86 | 
            +
                  dir = config[:base_path]
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                  if config.default?(:base_path)
         | 
| 89 | 
            +
                    FileUtils.mkpath(dir) unless Dir.exist?(dir)
         | 
| 90 | 
            +
                  else
         | 
| 91 | 
            +
                    raise "Base path '#{dir}' is not writable" unless File.writable?(dir)
         | 
| 92 | 
            +
                  end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  dir
         | 
| 95 | 
            +
                end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                def base_file(path)
         | 
| 98 | 
            +
                  File.join(base_path, path)
         | 
| 99 | 
            +
                end
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                def rackup
         | 
| 102 | 
            +
                  File.expand_path("../config.ru", __FILE__)
         | 
| 103 | 
            +
                end
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                def db
         | 
| 106 | 
            +
                  @db ||= begin
         | 
| 107 | 
            +
                    case config[:db_adapter]
         | 
| 108 | 
            +
                    when "sqlite3"
         | 
| 109 | 
            +
                      db_path = base_file("gemstash.db")
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                      if RUBY_PLATFORM == "java"
         | 
| 112 | 
            +
                        db = Sequel.connect("jdbc:sqlite:#{db_path}", max_connections: 1)
         | 
| 113 | 
            +
                      else
         | 
| 114 | 
            +
                        db = Sequel.connect("sqlite://#{URI.escape(db_path)}", max_connections: 1)
         | 
| 115 | 
            +
                      end
         | 
| 116 | 
            +
                    when "postgres"
         | 
| 117 | 
            +
                      db = Sequel.connect(config[:db_url])
         | 
| 118 | 
            +
                    else
         | 
| 119 | 
            +
                      raise "Unsupported DB adapter: '#{config[:db_adapter]}'"
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                    Gemstash::Env.migrate(db)
         | 
| 123 | 
            +
                    db
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                def self.migrate(db)
         | 
| 128 | 
            +
                  Sequel.extension :migration
         | 
| 129 | 
            +
                  migrations_dir = File.expand_path("../migrations", __FILE__)
         | 
| 130 | 
            +
                  Sequel::Migrator.run(db, migrations_dir, :use_transactions => true)
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
                def cache
         | 
| 134 | 
            +
                  @cache ||= Gemstash::Cache.new(cache_client)
         | 
| 135 | 
            +
                end
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                def cache_client
         | 
| 138 | 
            +
                  @cache_client ||= begin
         | 
| 139 | 
            +
                    case config[:cache_type]
         | 
| 140 | 
            +
                    when "memory"
         | 
| 141 | 
            +
                      Gemstash::LruReduxClient.new
         | 
| 142 | 
            +
                    when "memcached"
         | 
| 143 | 
            +
                      Dalli::Client.new(config[:memcached_servers])
         | 
| 144 | 
            +
                    else
         | 
| 145 | 
            +
                      raise "Invalid cache client: '#{config[:cache_type]}'"
         | 
| 146 | 
            +
                    end
         | 
| 147 | 
            +
                  end
         | 
| 148 | 
            +
                end
         | 
| 149 | 
            +
              end
         | 
| 150 | 
            +
            end
         |