devpack 0.3.3 → 0.4.1
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 +4 -4
- data/.rubocop.yml +4 -0
- data/.ruby-version +1 -1
- data/README.md +26 -1
- data/devpack.gemspec +3 -2
- data/exe/devpack +20 -0
- data/lib/devpack/exec.rb +31 -0
- data/lib/devpack/gem_glob.rb +2 -2
- data/lib/devpack/gem_spec.rb +59 -10
- data/lib/devpack/gems.rb +14 -11
- data/lib/devpack/install.rb +17 -0
- data/lib/devpack/messages.rb +42 -9
- data/lib/devpack/version.rb +1 -1
- data/lib/devpack.rb +17 -1
- metadata +10 -6
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: bc62279883bef6f044e47c419b853c89b33e76f699d7106575cd87869967b36d
         | 
| 4 | 
            +
              data.tar.gz: 48a959cbd1004dce6752b6fb723905ad40f92c02cf73cd8432b969309d94f5a8
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: a473937535208f922c6ceed0e137cfa758bf806bb39516e6f01906d748ef219c0fcb69fba33e195c49e95f045cf335267b7b997f300c30e6311792becba6a4ea
         | 
| 7 | 
            +
              data.tar.gz: 5e4247975b02ec3432344755432bb887ca7036cdb9792a3c8377d3a091dc5c92a464e0e8cf5dcda82248f2039e4c6ca0efedacf4761bec870d0d2fe6101cd254
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/.ruby-version
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            2.5. | 
| 1 | 
            +
            2.5.9
         | 
    
        data/README.md
    CHANGED
    
    | @@ -21,7 +21,7 @@ Add _Devpack_ to any project's `Gemfile`: | |
| 21 21 | 
             
            ```ruby
         | 
| 22 22 | 
             
            # Gemfile
         | 
| 23 23 | 
             
            group :development, :test do
         | 
| 24 | 
            -
              gem 'devpack', '~> 0. | 
| 24 | 
            +
              gem 'devpack', '~> 0.4.0'
         | 
| 25 25 | 
             
            end
         | 
| 26 26 | 
             
            ```
         | 
| 27 27 |  | 
| @@ -45,6 +45,24 @@ It is recommended to use a [global configuration](#global-configuration). | |
| 45 45 |  | 
| 46 46 | 
             
            When using a per-project configuration, `.devpack` files should be added to `.gitignore`.
         | 
| 47 47 |  | 
| 48 | 
            +
            ### Gem Installation
         | 
| 49 | 
            +
             | 
| 50 | 
            +
            A convenience command is provided to install all gems listed in `.devpack` file that are not already installed:
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            ```bash
         | 
| 53 | 
            +
            bundle exec devpack install
         | 
| 54 | 
            +
            ```
         | 
| 55 | 
            +
             | 
| 56 | 
            +
            ### Executing Commands Provided by DevPack Gems
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            Use the `exec` command to run a command provided by a gem installed via _Devpack_.
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            An example use case of this is the [Guard](https://github.com/guard/guard) gem:
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            ```bash
         | 
| 63 | 
            +
            bundle exec devpack exec guard
         | 
| 64 | 
            +
            ```
         | 
| 65 | 
            +
             | 
| 48 66 | 
             
            ### Initializers
         | 
| 49 67 |  | 
| 50 68 | 
             
            Custom initializers can be loaded by creating a directory named `.devpack_initializers` containing a set of `.rb` files.
         | 
| @@ -75,6 +93,13 @@ To configure globally simply save your `.devpack` configuration file to any pare | |
| 75 93 |  | 
| 76 94 | 
             
            This strategy also applies to `.devpack_initializers`.
         | 
| 77 95 |  | 
| 96 | 
            +
            ### Silencing
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            To prevent _Devpack_ from displaying messages on load, set the environment variable `DEVPACK_SILENT=1` to any value:
         | 
| 99 | 
            +
            ```bash
         | 
| 100 | 
            +
            DEVPACK_SILENT=1 bundle exec ruby myapp.rb
         | 
| 101 | 
            +
            ```
         | 
| 102 | 
            +
             | 
| 78 103 | 
             
            ### Disabling
         | 
| 79 104 |  | 
| 80 105 | 
             
            To disable _Devpack_ set the environment variable `DEVPACK_DISABLE` to any value:
         | 
    
        data/devpack.gemspec
    CHANGED
    
    | @@ -17,12 +17,13 @@ Gem::Specification.new do |spec| | |
| 17 17 | 
             
              spec.metadata['homepage_uri'] = spec.homepage
         | 
| 18 18 | 
             
              spec.metadata['source_code_uri'] = spec.homepage
         | 
| 19 19 | 
             
              spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/master/CHANGELOG.md"
         | 
| 20 | 
            +
              spec.metadata['rubygems_mfa_required'] = 'true'
         | 
| 20 21 |  | 
| 21 22 | 
             
              spec.files = Dir.chdir(File.expand_path(__dir__)) do
         | 
| 22 23 | 
             
                `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
         | 
| 23 24 | 
             
              end
         | 
| 24 | 
            -
              spec.bindir        = ' | 
| 25 | 
            -
              spec.executables   = []
         | 
| 25 | 
            +
              spec.bindir        = 'exe'
         | 
| 26 | 
            +
              spec.executables   = ['devpack']
         | 
| 26 27 | 
             
              spec.require_paths = ['lib']
         | 
| 27 28 |  | 
| 28 29 | 
             
              spec.add_development_dependency 'byebug', '~> 11.1'
         | 
    
        data/exe/devpack
    ADDED
    
    | @@ -0,0 +1,20 @@ | |
| 1 | 
            +
            #!/usr/bin/env ruby
         | 
| 2 | 
            +
            # frozen_string_literal: true
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            command = ARGV[0]
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            ENV['DEVPACK_DISABLE'] = '1' if command == 'install'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            require 'open3'
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            require 'devpack'
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            case command
         | 
| 13 | 
            +
            when 'install'
         | 
| 14 | 
            +
              require 'devpack/install'
         | 
| 15 | 
            +
            when 'exec'
         | 
| 16 | 
            +
              require 'devpack/exec'
         | 
| 17 | 
            +
            else
         | 
| 18 | 
            +
              warn "[devpack] Unknown command: #{command}"
         | 
| 19 | 
            +
              exit 1
         | 
| 20 | 
            +
            end
         | 
    
        data/lib/devpack/exec.rb
    ADDED
    
    | @@ -0,0 +1,31 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Gem.module_eval do
         | 
| 4 | 
            +
              def self.devpack_bin_path(gem_name, command, _version = nil)
         | 
| 5 | 
            +
                File.join(Gem.loaded_specs[gem_name].full_gem_path, Gem.loaded_specs[gem_name].bindir, command)
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              class << self
         | 
| 9 | 
            +
                alias_method :_orig_activate_bin_path, :activate_bin_path
         | 
| 10 | 
            +
                alias_method :_orig_bin_path, :bin_path
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                def activate_bin_path(*args)
         | 
| 13 | 
            +
                  _orig_activate_bin_path(*args)
         | 
| 14 | 
            +
                rescue Gem::Exception
         | 
| 15 | 
            +
                  devpack_bin_path(*args)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def bin_path(*args)
         | 
| 19 | 
            +
                  _orig_bin_path(*args)
         | 
| 20 | 
            +
                rescue Gem::Exception
         | 
| 21 | 
            +
                  devpack_bin_path(*args)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            def devpack_exec(args)
         | 
| 27 | 
            +
              options = Bundler::Thor::CoreExt::HashWithIndifferentAccess.new({ 'keep_file_descriptors' => true })
         | 
| 28 | 
            +
              Bundler::CLI::Exec.new(options, args).run
         | 
| 29 | 
            +
            end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            devpack_exec(ARGV[1..-1])
         | 
    
        data/lib/devpack/gem_glob.rb
    CHANGED
    
    | @@ -44,8 +44,8 @@ module Devpack | |
| 44 44 | 
             
                end
         | 
| 45 45 |  | 
| 46 46 | 
             
                def gem_path
         | 
| 47 | 
            -
                  return ENV | 
| 48 | 
            -
                  return ENV | 
| 47 | 
            +
                  return ENV.fetch('GEM_PATH', nil) if ENV.key?('GEM_PATH')
         | 
| 48 | 
            +
                  return ENV.fetch('GEM_HOME', nil) if ENV.key?('GEM_HOME')
         | 
| 49 49 |  | 
| 50 50 | 
             
                  nil
         | 
| 51 51 | 
             
                end
         | 
    
        data/lib/devpack/gem_spec.rb
    CHANGED
    
    | @@ -3,56 +3,104 @@ | |
| 3 3 | 
             
            module Devpack
         | 
| 4 4 | 
             
              # Locates relevant gemspec for a given gem and provides a full list of paths
         | 
| 5 5 | 
             
              # for all `require_paths` listed in gemspec.
         | 
| 6 | 
            +
              # rubocop:disable Metrics/ClassLength
         | 
| 6 7 | 
             
              class GemSpec
         | 
| 7 | 
            -
                 | 
| 8 | 
            +
                attr_reader :name, :root
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def initialize(glob, name, requirement, root: nil)
         | 
| 8 11 | 
             
                  @name = name
         | 
| 9 12 | 
             
                  @glob = glob
         | 
| 10 13 | 
             
                  @requirement = requirement
         | 
| 14 | 
            +
                  @root = root || self
         | 
| 11 15 | 
             
                  @dependency = Gem::Dependency.new(@name, @requirement)
         | 
| 12 16 | 
             
                end
         | 
| 13 17 |  | 
| 14 18 | 
             
                def require_paths(visited = Set.new)
         | 
| 15 | 
            -
                  raise GemNotFoundError | 
| 19 | 
            +
                  raise GemNotFoundError.new("Gem not found: #{required_version}", self) if gemspec.nil?
         | 
| 16 20 |  | 
| 17 21 | 
             
                  (immediate_require_paths + dependency_require_paths(visited)).compact.flatten.uniq
         | 
| 18 22 | 
             
                end
         | 
| 19 23 |  | 
| 20 24 | 
             
                def gemspec
         | 
| 25 | 
            +
                  return Gem.loaded_specs[@name] if compatible?(Gem.loaded_specs[@name])
         | 
| 26 | 
            +
             | 
| 21 27 | 
             
                  @gemspec ||= gemspecs.find do |spec|
         | 
| 22 28 | 
             
                    next false if spec.nil?
         | 
| 23 29 |  | 
| 24 | 
            -
                     | 
| 30 | 
            +
                    raise_incompatible(spec) unless compatible?(spec)
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    @dependency.requirement.satisfied_by?(spec.version)
         | 
| 25 33 | 
             
                  end
         | 
| 26 34 | 
             
                end
         | 
| 27 35 |  | 
| 36 | 
            +
                def pretty_name
         | 
| 37 | 
            +
                  return @name.to_s if @requirement.nil?
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  "#{@name} #{@requirement}"
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def root?
         | 
| 43 | 
            +
                  self == @root
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                def required_version
         | 
| 47 | 
            +
                  return @name.to_s if compatible_spec.nil? && @requirement.nil?
         | 
| 48 | 
            +
                  return "#{@name}:#{compatible_version}" if compatible_spec.nil?
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  "#{@name}:#{compatible_spec.version}"
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 28 53 | 
             
                private
         | 
| 29 54 |  | 
| 30 55 | 
             
                def compatible?(spec)
         | 
| 31 56 | 
             
                  return false if spec.nil?
         | 
| 32 57 | 
             
                  return false if incompatible_version_loaded?(spec)
         | 
| 33 58 |  | 
| 34 | 
            -
                  compatible_specs?( | 
| 59 | 
            +
                  compatible_specs?([@dependency] + spec.runtime_dependencies)
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                def compatible_spec
         | 
| 63 | 
            +
                  @compatible_spec ||= gemspecs.compact
         | 
| 64 | 
            +
                                               .select { |spec| requirements_satisfied_by?(spec.version) }
         | 
| 65 | 
            +
                                               .max_by(&:version)
         | 
| 35 66 | 
             
                end
         | 
| 36 67 |  | 
| 37 68 | 
             
                def incompatible_version_loaded?(spec)
         | 
| 38 69 | 
             
                  matched = Gem.loaded_specs[spec.name]
         | 
| 39 70 | 
             
                  return false if matched.nil?
         | 
| 40 71 |  | 
| 41 | 
            -
                  matched. | 
| 72 | 
            +
                  !matched.satisfies_requirement?(@dependency)
         | 
| 42 73 | 
             
                end
         | 
| 43 74 |  | 
| 44 | 
            -
                def  | 
| 45 | 
            -
                   | 
| 75 | 
            +
                def raise_incompatible(spec)
         | 
| 76 | 
            +
                  raise GemIncompatibilityError.new('Incompatible dependencies', incompatible_dependencies(spec))
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                def compatible_version
         | 
| 80 | 
            +
                  @requirement.requirements.map(&:last).max_by { |version| @requirement.satisfied_by?(version) }
         | 
| 46 81 | 
             
                end
         | 
| 47 82 |  | 
| 48 | 
            -
                def  | 
| 49 | 
            -
                   | 
| 83 | 
            +
                def requirements_satisfied_by?(version)
         | 
| 84 | 
            +
                  @dependency.requirement.satisfied_by?(version)
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                def compatible_specs?(dependencies)
         | 
| 88 | 
            +
                  Gem.loaded_specs.values.all? { |spec| compatible_dependencies?(dependencies, spec) }
         | 
| 50 89 | 
             
                end
         | 
| 51 90 |  | 
| 52 91 | 
             
                def compatible_dependencies?(dependencies, spec)
         | 
| 53 92 | 
             
                  dependencies.all? { |dependency| compatible_dependency?(dependency, spec) }
         | 
| 54 93 | 
             
                end
         | 
| 55 94 |  | 
| 95 | 
            +
                def incompatible_dependencies(spec)
         | 
| 96 | 
            +
                  dependencies = [@dependency] + spec.runtime_dependencies
         | 
| 97 | 
            +
                  Gem.loaded_specs.map do |_name, loaded_spec|
         | 
| 98 | 
            +
                    next nil if compatible_dependencies?(dependencies, loaded_spec)
         | 
| 99 | 
            +
             | 
| 100 | 
            +
                    [@root, dependencies.reject { |dependency| compatible_dependency?(dependency, loaded_spec) }]
         | 
| 101 | 
            +
                  end.compact
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 56 104 | 
             
                def compatible_dependency?(dependency, spec)
         | 
| 57 105 | 
             
                  return false if spec.nil?
         | 
| 58 106 | 
             
                  return true unless dependency.name == spec.name
         | 
| @@ -69,7 +117,7 @@ module Devpack | |
| 69 117 | 
             
                    next nil if visited.include?(dependency)
         | 
| 70 118 |  | 
| 71 119 | 
             
                    visited << dependency
         | 
| 72 | 
            -
                    GemSpec.new(@glob, dependency.name, dependency.requirement).require_paths(visited)
         | 
| 120 | 
            +
                    GemSpec.new(@glob, dependency.name, dependency.requirement, root: @root).require_paths(visited)
         | 
| 73 121 | 
             
                  end
         | 
| 74 122 | 
             
                end
         | 
| 75 123 |  | 
| @@ -101,4 +149,5 @@ module Devpack | |
| 101 149 | 
             
                  @candidates ||= @glob.find(@name)
         | 
| 102 150 | 
             
                end
         | 
| 103 151 | 
             
              end
         | 
| 152 | 
            +
              # rubocop:enable Metrics/ClassLength
         | 
| 104 153 | 
             
            end
         | 
    
        data/lib/devpack/gems.rb
    CHANGED
    
    | @@ -5,36 +5,38 @@ module Devpack | |
| 5 5 | 
             
              class Gems
         | 
| 6 6 | 
             
                include Timeable
         | 
| 7 7 |  | 
| 8 | 
            +
                attr_reader :missing
         | 
| 9 | 
            +
             | 
| 8 10 | 
             
                def initialize(config, glob = GemGlob.new)
         | 
| 9 11 | 
             
                  @config = config
         | 
| 10 12 | 
             
                  @gem_glob = glob
         | 
| 11 13 | 
             
                  @failures = []
         | 
| 12 14 | 
             
                  @missing = []
         | 
| 15 | 
            +
                  @incompatible = []
         | 
| 13 16 | 
             
                end
         | 
| 14 17 |  | 
| 15 | 
            -
                def load
         | 
| 18 | 
            +
                def load(silent: false)
         | 
| 16 19 | 
             
                  return [] if @config.requested_gems.nil?
         | 
| 17 20 |  | 
| 18 21 | 
             
                  gems, time = timed { load_devpack }
         | 
| 19 22 | 
             
                  names = gems.map(&:first)
         | 
| 20 | 
            -
                  summarize(gems, time)
         | 
| 23 | 
            +
                  summarize(gems, time) unless silent
         | 
| 21 24 | 
             
                  names
         | 
| 22 25 | 
             
                end
         | 
| 23 26 |  | 
| 24 27 | 
             
                private
         | 
| 25 28 |  | 
| 26 29 | 
             
                def summarize(gems, time)
         | 
| 27 | 
            -
                  @failures.each  | 
| 28 | 
            -
             | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
                  warn(:success, Messages.loaded(@config.devpack_path, gems, time.round(2)))
         | 
| 30 | 
            +
                  @failures.each { |failure| warn(:error, Messages.failure(failure[:name], failure[:message])) }
         | 
| 31 | 
            +
                  warn(:success, Messages.loaded(@config, gems, time.round(2)))
         | 
| 31 32 | 
             
                  warn(:info, Messages.install_missing(@missing)) unless @missing.empty?
         | 
| 33 | 
            +
                  warn(:info, Messages.alert_incompatible(@incompatible.flatten(1))) unless @incompatible.empty?
         | 
| 32 34 | 
             
                end
         | 
| 33 35 |  | 
| 34 36 | 
             
                def load_devpack
         | 
| 35 37 | 
             
                  @config.requested_gems.map do |requested|
         | 
| 36 38 | 
             
                    name, _, version = requested.partition(':')
         | 
| 37 | 
            -
                    load_gem(name, version.empty? ? nil : Gem::Requirement.new( | 
| 39 | 
            +
                    load_gem(name, version.empty? ? nil : Gem::Requirement.new(version))
         | 
| 38 40 | 
             
                  end.compact
         | 
| 39 41 | 
             
                end
         | 
| 40 42 |  | 
| @@ -42,11 +44,11 @@ module Devpack | |
| 42 44 | 
             
                  [name, activate(name, requirement)]
         | 
| 43 45 | 
             
                rescue LoadError => e
         | 
| 44 46 | 
             
                  deactivate(name)
         | 
| 45 | 
            -
                  @failures << { name: name, message: load_error_message(e) }
         | 
| 46 | 
            -
                  nil
         | 
| 47 | 
            +
                  nil.tap { @failures << { name: name, message: load_error_message(e) } }
         | 
| 47 48 | 
             
                rescue GemNotFoundError => e
         | 
| 48 | 
            -
                  @missing <<  | 
| 49 | 
            -
             | 
| 49 | 
            +
                  nil.tap { @missing << e.meta }
         | 
| 50 | 
            +
                rescue GemIncompatibilityError => e
         | 
| 51 | 
            +
                  nil.tap { @incompatible << e.meta }
         | 
| 50 52 | 
             
                end
         | 
| 51 53 |  | 
| 52 54 | 
             
                def activate(name, version)
         | 
| @@ -77,6 +79,7 @@ module Devpack | |
| 77 79 |  | 
| 78 80 | 
             
                def update_load_path(paths)
         | 
| 79 81 | 
             
                  $LOAD_PATH.concat(paths)
         | 
| 82 | 
            +
                  ENV['RUBYLIB'] = $LOAD_PATH.join(':')
         | 
| 80 83 | 
             
                end
         | 
| 81 84 | 
             
              end
         | 
| 82 85 | 
             
            end
         | 
| @@ -0,0 +1,17 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            missing = Devpack::Gems.new(Devpack.config).tap { |gems| gems.load(silent: true) }.missing
         | 
| 4 | 
            +
            install_command = "bundle exec gem install -V #{missing.map(&:required_version).join(' ')}" unless missing.empty?
         | 
| 5 | 
            +
            if install_command.nil?
         | 
| 6 | 
            +
              Devpack.warn(:info, Devpack::Messages.no_gems_to_install)
         | 
| 7 | 
            +
            else
         | 
| 8 | 
            +
              Devpack.warn(:info, install_command)
         | 
| 9 | 
            +
              output, status = Open3.capture2e(install_command)
         | 
| 10 | 
            +
              if status.success?
         | 
| 11 | 
            +
                Devpack.warn(:success, 'Installation complete.')
         | 
| 12 | 
            +
              else
         | 
| 13 | 
            +
                Devpack.warn(:error, "Installation failed. Manually verify this command: #{install_command}")
         | 
| 14 | 
            +
                puts output
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
            end
         | 
| 17 | 
            +
            exit 0
         | 
    
        data/lib/devpack/messages.rb
    CHANGED
    
    | @@ -13,24 +13,48 @@ module Devpack | |
| 13 13 | 
             
                    "Failed to load initializer `#{path}`: #{error_message}"
         | 
| 14 14 | 
             
                  end
         | 
| 15 15 |  | 
| 16 | 
            -
                   | 
| 17 | 
            -
             | 
| 18 | 
            -
                     | 
| 19 | 
            -
                     | 
| 16 | 
            +
                  # rubocop:disable Metrics/AbcSize
         | 
| 17 | 
            +
                  def loaded(config, gems, time)
         | 
| 18 | 
            +
                    loaded = gems.size - gems.reject { |_, devpack_loaded| devpack_loaded }.size
         | 
| 19 | 
            +
                    of_total = gems.size == config.requested_gems.size ? nil : " of #{color(:cyan) { config.requested_gems.size }}"
         | 
| 20 | 
            +
                    path = color(:cyan) { config.devpack_path }
         | 
| 21 | 
            +
                    base = "Loaded #{color(:green) { loaded }}#{of_total} development gem(s) from #{path} in #{time} seconds"
         | 
| 22 | 
            +
                    return "#{base}." if loaded == gems.size
         | 
| 20 23 |  | 
| 21 | 
            -
                    "#{base} (#{gems.size -  | 
| 24 | 
            +
                    "#{base} (#{color(:cyan) { gems.size - loaded }} gem(s) were already loaded by environment)."
         | 
| 22 25 | 
             
                  end
         | 
| 26 | 
            +
                  # rubocop:enable Metrics/AbcSize
         | 
| 23 27 |  | 
| 24 28 | 
             
                  def loaded_initializers(path, initializers, time)
         | 
| 25 | 
            -
                    "Loaded #{initializers.compact.size} initializer(s) from '#{path}' in #{time} seconds"
         | 
| 29 | 
            +
                    "Loaded #{color(:green) { initializers.compact.size }} initializer(s) from '#{path}' in #{time} seconds"
         | 
| 26 30 | 
             
                  end
         | 
| 27 31 |  | 
| 28 32 | 
             
                  def install_missing(missing)
         | 
| 29 | 
            -
                     | 
| 30 | 
            -
             | 
| 33 | 
            +
                    command = color(:cyan) { 'bundle exec devpack install' }
         | 
| 34 | 
            +
                    grouped_missing = missing
         | 
| 35 | 
            +
                                      .group_by(&:root)
         | 
| 36 | 
            +
                                      .map do |root, dependencies|
         | 
| 37 | 
            +
                      next (color(:cyan) { root.pretty_name }).to_s if dependencies.all?(&:root?)
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                      formatted_dependencies = dependencies.map { |dependency| color(:yellow) { dependency.pretty_name } }
         | 
| 40 | 
            +
                      "#{color(:cyan) { root.pretty_name }}: #{formatted_dependencies.join(', ')}"
         | 
| 41 | 
            +
                    end
         | 
| 42 | 
            +
                    "Install #{missing.size} missing gem(s): #{command} # [#{grouped_missing.join(', ')}]"
         | 
| 43 | 
            +
                  end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                  def alert_incompatible(incompatible)
         | 
| 46 | 
            +
                    grouped_dependencies = {}
         | 
| 47 | 
            +
                    incompatible.each do |spec, dependencies|
         | 
| 48 | 
            +
                      key = spec.root.pretty_name
         | 
| 49 | 
            +
                      grouped_dependencies[key] ||= []
         | 
| 50 | 
            +
                      grouped_dependencies[key] << dependencies
         | 
| 31 51 | 
             
                    end
         | 
| 52 | 
            +
                    alert_incompatible_message(grouped_dependencies)
         | 
| 53 | 
            +
                  end
         | 
| 32 54 |  | 
| 33 | 
            -
             | 
| 55 | 
            +
                  def no_gems_to_install
         | 
| 56 | 
            +
                    "No gems to install: #{Devpack::Messages.color(:green) { Devpack.config.requested_gems.size.to_s }} "\
         | 
| 57 | 
            +
                      "gems already installed from #{Devpack::Messages.color(:cyan) { Devpack.config.devpack_path }}"
         | 
| 34 58 | 
             
                  end
         | 
| 35 59 |  | 
| 36 60 | 
             
                  def test
         | 
| @@ -52,6 +76,15 @@ module Devpack | |
| 52 76 | 
             
                    "bundle exec gem install #{gems.join(' ')}"
         | 
| 53 77 | 
             
                  end
         | 
| 54 78 |  | 
| 79 | 
            +
                  def alert_incompatible_message(grouped_dependencies)
         | 
| 80 | 
            +
                    incompatible_dependencies = grouped_dependencies.sort.map do |name, dependencies|
         | 
| 81 | 
            +
                      "#{color(:cyan) { name }}: "\
         | 
| 82 | 
            +
                        "#{dependencies.flatten.map { |dependency| color(:yellow) { dependency.to_s } }.join(', ')}"
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
                    "Unable to resolve version conflicts for #{color(:yellow) { incompatible_dependencies.size }} "\
         | 
| 85 | 
            +
                      "dependencies: #{incompatible_dependencies.join(', ')}}"
         | 
| 86 | 
            +
                  end
         | 
| 87 | 
            +
             | 
| 55 88 | 
             
                  def palette
         | 
| 56 89 | 
             
                    {
         | 
| 57 90 | 
             
                      reset: "\e[39m",
         | 
    
        data/lib/devpack/version.rb
    CHANGED
    
    
    
        data/lib/devpack.rb
    CHANGED
    
    | @@ -15,12 +15,24 @@ require 'devpack/version' | |
| 15 15 |  | 
| 16 16 | 
             
            # Provides helper method for writing warning messages.
         | 
| 17 17 | 
             
            module Devpack
         | 
| 18 | 
            -
              class  | 
| 18 | 
            +
              # Base class for all Devpack errors. Accepts additional argument `meta` to store object info.
         | 
| 19 | 
            +
              class Error < StandardError
         | 
| 20 | 
            +
                attr_reader :message, :meta
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                def initialize(message = nil, meta = nil)
         | 
| 23 | 
            +
                  @message = message
         | 
| 24 | 
            +
                  @meta = meta
         | 
| 25 | 
            +
                  super(message)
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 19 28 |  | 
| 20 29 | 
             
              class GemNotFoundError < Error; end
         | 
| 30 | 
            +
              class GemIncompatibilityError < Error; end
         | 
| 21 31 |  | 
| 22 32 | 
             
              class << self
         | 
| 23 33 | 
             
                def warn(level, message)
         | 
| 34 | 
            +
                  return if silent?
         | 
| 35 | 
            +
             | 
| 24 36 | 
             
                  prefixed = message.split("\n").map { |line| "#{prefix(level)} #{line}" }.join("\n")
         | 
| 25 37 | 
             
                  Kernel.warn(prefixed)
         | 
| 26 38 | 
             
                end
         | 
| @@ -33,6 +45,10 @@ module Devpack | |
| 33 45 | 
             
                  ENV.key?('DEVPACK_DISABLE')
         | 
| 34 46 | 
             
                end
         | 
| 35 47 |  | 
| 48 | 
            +
                def silent?
         | 
| 49 | 
            +
                  ENV.key?('DEVPACK_SILENT')
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 36 52 | 
             
                def rails?
         | 
| 37 53 | 
             
                  defined?(Rails::Railtie)
         | 
| 38 54 | 
             
                end
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: devpack
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.4.1
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Bob Farrell
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 | 
            -
            bindir:  | 
| 9 | 
            +
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date:  | 
| 11 | 
            +
            date: 2023-01-01 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: byebug
         | 
| @@ -98,7 +98,8 @@ description: Allow developers to optionally include a set of development gems wi | |
| 98 98 | 
             
              adding to the Gemfile.
         | 
| 99 99 | 
             
            email:
         | 
| 100 100 | 
             
            - git@bob.frl
         | 
| 101 | 
            -
            executables: | 
| 101 | 
            +
            executables:
         | 
| 102 | 
            +
            - devpack
         | 
| 102 103 | 
             
            extensions: []
         | 
| 103 104 | 
             
            extra_rdoc_files: []
         | 
| 104 105 | 
             
            files:
         | 
| @@ -115,12 +116,15 @@ files: | |
| 115 116 | 
             
            - bin/console
         | 
| 116 117 | 
             
            - bin/setup
         | 
| 117 118 | 
             
            - devpack.gemspec
         | 
| 119 | 
            +
            - exe/devpack
         | 
| 118 120 | 
             
            - lib/devpack.rb
         | 
| 119 121 | 
             
            - lib/devpack/config.rb
         | 
| 122 | 
            +
            - lib/devpack/exec.rb
         | 
| 120 123 | 
             
            - lib/devpack/gem_glob.rb
         | 
| 121 124 | 
             
            - lib/devpack/gem_spec.rb
         | 
| 122 125 | 
             
            - lib/devpack/gems.rb
         | 
| 123 126 | 
             
            - lib/devpack/initializers.rb
         | 
| 127 | 
            +
            - lib/devpack/install.rb
         | 
| 124 128 | 
             
            - lib/devpack/messages.rb
         | 
| 125 129 | 
             
            - lib/devpack/railtie.rb
         | 
| 126 130 | 
             
            - lib/devpack/timeable.rb
         | 
| @@ -132,6 +136,7 @@ metadata: | |
| 132 136 | 
             
              homepage_uri: https://github.com/bobf/devpack
         | 
| 133 137 | 
             
              source_code_uri: https://github.com/bobf/devpack
         | 
| 134 138 | 
             
              changelog_uri: https://github.com/bobf/devpack/blob/master/CHANGELOG.md
         | 
| 139 | 
            +
              rubygems_mfa_required: 'true'
         | 
| 135 140 | 
             
            post_install_message:
         | 
| 136 141 | 
             
            rdoc_options: []
         | 
| 137 142 | 
             
            require_paths:
         | 
| @@ -147,8 +152,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 147 152 | 
             
                - !ruby/object:Gem::Version
         | 
| 148 153 | 
             
                  version: '0'
         | 
| 149 154 | 
             
            requirements: []
         | 
| 150 | 
            -
             | 
| 151 | 
            -
            rubygems_version: 2.7.6.2
         | 
| 155 | 
            +
            rubygems_version: 3.2.3
         | 
| 152 156 | 
             
            signing_key:
         | 
| 153 157 | 
             
            specification_version: 4
         | 
| 154 158 | 
             
            summary: Conveniently tailor your development environment
         |