class Licensed::Sources::Manifest

Public Instance Methods

configured_dependencies() click to toggle source

Returns the project dependencies specified from the licensed configuration

# File lib/licensed/sources/manifest.rb, line 129
def configured_dependencies
  @configured_dependencies ||= begin
    dependencies = config.dig("manifest", "dependencies")&.dup || {}

    dependencies.each_with_object({}) do |(name, patterns), hsh|
      # map glob pattern(s) listed for the dependency to a listing
      # of files that match the patterns and are not excluded
      hsh[name] = files_from_pattern_list(patterns) & included_files
    end
  end
end
configured_license_path(package_name) click to toggle source

Returns the license path for a package specified in the configuration.

# File lib/licensed/sources/manifest.rb, line 30
def configured_license_path(package_name)
  license_path = config.dig("manifest", "licenses", package_name)
  return unless license_path

  license_path = config.root.join(license_path)
  return unless license_path.exist?
  license_path
end
enabled?() click to toggle source
# File lib/licensed/sources/manifest.rb, line 10
def enabled?
  File.exist?(manifest_path) || generate_manifest?
end
enumerate_dependencies() click to toggle source
# File lib/licensed/sources/manifest.rb, line 14
def enumerate_dependencies
  Parallel.map(packages) do |package_name, sources|
    Licensed::Sources::Manifest::Dependency.new(
      name: package_name,
      version: contents_version(*sources),
      path: configured_license_path(package_name) || sources_license_path(sources),
      sources: sources,
      metadata: {
        "type"     => Manifest.type,
        "name"     => package_name
      }
    )
  end
end
files_from_pattern_list(patterns) click to toggle source

Finds and returns all files in the project that match the glob pattern arguments.

# File lib/licensed/sources/manifest.rb, line 148
def files_from_pattern_list(patterns)
  return Set.new if patterns.nil? || patterns.empty?

  # evaluate all patterns from the project root
  Array(patterns).each_with_object(Set.new) do |pattern, files|
    if pattern.start_with?("!")
      # if the pattern is an exclusion, remove all matching files
      # from the result
      files.subtract(Dir.glob(pattern[1..-1], File::FNM_DOTMATCH, base: config.root))
    else
      # if the pattern is an inclusion, add all matching files
      # to the result
      files.merge(Dir.glob(pattern, File::FNM_DOTMATCH, base: config.root))
    end
  end
end
generate_manifest() click to toggle source

Returns a manifest of files generated automatically based on patterns set in the licensed configuration file

# File lib/licensed/sources/manifest.rb, line 95
def generate_manifest
  verify_configured_dependencies!
  configured_dependencies.each_with_object({}) do |(name, files), hsh|
    files.each { |f| hsh[f] = name }
  end
end
generate_manifest?() click to toggle source

Returns whether a manifest should be generated automatically

# File lib/licensed/sources/manifest.rb, line 89
def generate_manifest?
  !File.exist?(manifest_path) && !config.dig("manifest", "dependencies").nil?
end
included_files() click to toggle source

Returns the set of project files that are included in dependency evaluation

# File lib/licensed/sources/manifest.rb, line 142
def included_files
  @included_files ||= tracked_files - files_from_pattern_list(config.dig("manifest", "exclude"))
end
manifest() click to toggle source

Returns parsed or generated manifest data for the app

# File lib/licensed/sources/manifest.rb, line 69
def manifest
  return generate_manifest if generate_manifest?

  case manifest_path.extname.downcase.delete "."
  when "json"
    JSON.parse(File.read(manifest_path))
  when "yml", "yaml"
    YAML.load_file(manifest_path)
  end
end
manifest_path() click to toggle source

Returns the manifest location for the app

# File lib/licensed/sources/manifest.rb, line 81
def manifest_path
  path = config.dig("manifest", "path")
  return config.root.join(path) if path

  config.cache_path.join("manifest.json")
end
packages() click to toggle source

Returns a map of package names -> array of full source paths found in the app manifest

# File lib/licensed/sources/manifest.rb, line 60
def packages
  manifest.each_with_object({}) do |(src, package_name), hsh|
    next if src.nil? || src.empty?
    hsh[package_name] ||= []
    hsh[package_name] << File.absolute_path(src, config.root)
  end
end
sources_license_path(sources) click to toggle source

Returns the top-most directory that is common to all paths in ‘sources`

# File lib/licensed/sources/manifest.rb, line 40
def sources_license_path(sources)
  # if there is more than one source, try to find a directory common to
  # all sources
  if sources.size > 1
    common_prefix = Pathname.common_prefix(*sources).to_path

    # don't allow the workspace root to be used as common prefix
    # the project this is run for should be excluded from the manifest,
    # or ignored in the config.  any license in the root should be ignored.
    return common_prefix if common_prefix != config.root
  end

  # use the first (or only) sources directory to find license information
  source = sources.first
  return File.dirname(source) if File.file?(source)
  source
end
tracked_files() click to toggle source

Returns all tracked files in the project as the intersection of what git tracks and the files in the project

# File lib/licensed/sources/manifest.rb, line 166
def tracked_files
  @tracked_files ||= Set.new(Array(Licensed::Git.files)) &
                     Set.new(Dir.glob("**/*", File::FNM_DOTMATCH, base: config.root))
end
verify_configured_dependencies!() click to toggle source

Verify that the licensed configuration file is valid for the current project. Raises errors for issues found with configuration

# File lib/licensed/sources/manifest.rb, line 104
def verify_configured_dependencies!
  # verify that dependencies are configured
  if configured_dependencies.empty?
    raise Source::Error.new("The manifest \"dependencies\" cannot be empty!")
  end

  # verify all included files match a single configured dependency
  errors = included_files.map do |file|
    matches = configured_dependencies.select { |name, files| files.include?(file) }
                                     .map { |name, files| name }
    case matches.size
    when 0
      "#{file} did not match a configured dependency"
    when 1
      nil
    else
      "#{file} matched multiple configured dependencies: #{matches.join(", ")}"
    end
  end

  errors.compact!
  raise Source::Error.new(errors.join($/)) if errors.any?
end