mtwilliams/visual_studio

View on GitHub
lib/visual_studio/environment.rb

Summary

Maintainability
A
35 mins
Test Coverage
module VisualStudio
  module Environment
    SEARCH_DIRECTORIES = ['PATH', 'INCLUDE', 'LIB', 'LIBPATH']

    def self.merge(base, overlay)
      # We merge case insensitively, because Windows. We treat |base| case as canonical
      # unless the variable is only named by |overlay|.
      cased = (overlay.keys + base.keys).uniq.map{|key| [key.upcase, key]}.to_h

      # TODO(mtwilliams): Verify match-up between VCInstallDir and VisualStudioVersion?
      # TODO(mtwilliams): Rederive environment variables based on VCInstallDir and/or WindowsSdkDir.
      env = canonicalize(base).merge(canonicalize(overlay)) do |variable, base, overlay|
        if SEARCH_DIRECTORIES.include? variable.upcase
          # TODO(mtwilliams): Detect new Visual Studio or Windows SDK related
          # paths and replace the old ones based on that.
          base    = base.split(';')
          overlay = overlay.split(';')

          should_include_cwd = base.include?('.') || overlay.include?('.')

          # HACK(mtwilliams): We're using File.expand_path here to "normalize"
          # paths to prevent duplicates, but this could very likely have
          # disastrous effects.
          base = base.reject{|p| p=='.'}.map{|p| File.expand_path(p)}
          overlay = overlay.reject{|p| p=='.'}.map{|p| File.expand_path(p)}

          path = base | overlay
          path = ['.'] + path if should_include_cwd

          path.join(';')
        else
          # Right-hand side takes precedence.
          overlay
        end
      end

      env.map { |canonical, value|
        [cased[canonical], value]
      }.to_h
    end

    private
      def self.canonicalize(environment)
        environment.to_h.map{|key, value| [key.upcase, value]}.to_h
      end
  end
end