Class: Licensed::Sources::NuGet::NuGetDependency

Inherits:
Dependency
  • Object
show all
Defined in:
lib/licensed/sources/nuget.rb

Constant Summary collapse

LICENSE_FILE_REGEX =
/<license\s*type\s*=\s*\"\s*file\s*\"\s*>\s*(.*)\s*<\/license>/ix.freeze
LICENSE_URL_REGEX =
/<licenseUrl>\s*(.*)\s*<\/licenseUrl>/ix.freeze
PROJECT_URL_REGEX =
/<projectUrl>\s*(.*)\s*<\/projectUrl>/ix.freeze
PROJECT_DESC_REGEX =
/<description>\s*(.*)\s*<\/description>/ix.freeze

Constants inherited from Dependency

Dependency::LEGAL_FILES_PATTERN

Instance Attribute Summary

Attributes inherited from Dependency

#additional_terms, #errors, #name, #path, #version

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Dependency

#errors?, #exist?, #initialize, #license_contents, #license_key, #metadata, #notice_contents, #record

Constructor Details

This class inherits a constructor from Licensed::Dependency

Class Method Details

.fetch_content(url, redirect_limit = 5) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
# File 'lib/licensed/sources/nuget.rb', line 140

def fetch_content(url, redirect_limit = 5)
  url = URI.parse(url) if url.instance_of? String
  return @response_by_url[url] if (@response_by_url ||= {}).key?(url)
  return if redirect_limit == 0

  begin
    response = Net::HTTP.get_response(url)
    case response
    when Net::HTTPSuccess     then
      @response_by_url[url] = response.body
    when Net::HTTPRedirection then
      redirect_url = URI.parse(response["location"])
      if redirect_url.relative?
        redirect_url = url + redirect_url
      end
      # The redirect might be to a URL that requires transformation, i.e. a github file
      redirect_url = text_content_url(redirect_url.to_s)
      @response_by_url[url] = fetch_content(redirect_url, redirect_limit - 1)
    end
  rescue
    # Host might no longer exist or some other error, ignore
  end
end

.ignored_url?(url) ⇒ Boolean

Returns:

  • (Boolean)


117
118
119
120
121
# File 'lib/licensed/sources/nuget.rb', line 117

def ignored_url?(url)
  # Many Microsoft packages that now use <license> use this for <licenseUrl>
  # No need to fetch this page - it just contains NuGet documentation
  url == "https://aka.ms/deprecateLicenseUrl"
end

.retrieve_license(url) ⇒ Object



129
130
131
132
133
134
135
136
137
138
# File 'lib/licensed/sources/nuget.rb', line 129

def retrieve_license(url)
  return unless url
  return if ignored_url?(url)

  # Transform URLs that are known to return HTML but have a corresponding text-based URL
  text_url = text_content_url(url)

  raw_content = fetch_content(text_url)
  strip_html(raw_content)
end

.strip_html(html) ⇒ Object



110
111
112
113
114
115
# File 'lib/licensed/sources/nuget.rb', line 110

def strip_html(html)
  return unless html

  return html unless html.downcase.include?("<html")
  ReverseMarkdown.convert(html, unknown_tags: :bypass)
end

.text_content_url(url) ⇒ Object



123
124
125
126
127
# File 'lib/licensed/sources/nuget.rb', line 123

def text_content_url(url)
  # Convert github file URLs to raw URLs
  return url unless match = url.match(/https?:\/\/(?:www\.)?github.com\/([^\/]+)\/([^\/]+)\/blob\/(.*)/i)
  "https://github.com/#{match[1]}/#{match[2]}/raw/#{match[3]}"
end

Instance Method Details

#descriptionObject



51
52
53
54
55
56
57
58
# File 'lib/licensed/sources/nuget.rb', line 51

def description
  return @description if defined?(@description)
  @description = begin
    return unless nuspec_contents
    match = nuspec_contents.match PROJECT_DESC_REGEX
    match[1] if match && match[1]
  end
end

#license_metadataObject

Returns the metadata that represents this dependency. This metadata is written to YAML in the dependencys cached text file



22
23
24
25
26
27
# File 'lib/licensed/sources/nuget.rb', line 22

def 
  super.tap do ||
    ["homepage"] = project_url if project_url
    ["summary"] = description if description
  end
end

#nuspec_contentsObject



34
35
36
37
38
39
40
# File 'lib/licensed/sources/nuget.rb', line 34

def nuspec_contents
  return @nuspec_contents if defined?(@nuspec_contents)
  @nuspec_contents = begin
    return unless nuspec_path && File.exist?(nuspec_path)
    File.read(nuspec_path)
  end
end

#nuspec_local_license_fileObject

Look for a <license type=“file”> element in the nuspec that points to an on-disk license file (which licensee may not find due to a non-standard filename)



81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/licensed/sources/nuget.rb', line 81

def nuspec_local_license_file
  return @nuspec_local_license_file if defined?(@nuspec_local_license_file)
  return unless nuspec_contents

  match = nuspec_contents.match LICENSE_FILE_REGEX
  return unless match && match[1]

  license_path = File.join(File.dirname(nuspec_path), match[1])
  return unless File.exist?(license_path)

  license_data = File.read(license_path)
  @nuspec_local_license_file = Licensee::ProjectFiles::LicenseFile.new(license_data, license_path)
end

#nuspec_pathObject



29
30
31
32
# File 'lib/licensed/sources/nuget.rb', line 29

def nuspec_path
  name = @metadata["name"]
  File.join(self.path, "#{name.downcase}.nuspec")
end

#nuspec_remote_license_fileObject

Look for a <licenseUrl> element in the nuspec that either is known to contain a license identifier in the URL, or points to license text on the internet that can be downloaded.



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/licensed/sources/nuget.rb', line 97

def nuspec_remote_license_file
  return @nuspec_remote_license_file if defined?(@nuspec_remote_license_file)
  return unless nuspec_contents

  match = nuspec_contents.match LICENSE_URL_REGEX
  return unless match && match[1]

  # Attempt to fetch the license content
  license_content = self.class.retrieve_license(match[1])
  @nuspec_remote_license_file = Licensee::ProjectFiles::LicenseFile.new(license_content, { uri: match[1] }) if license_content
end

#project_filesObject



60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/licensed/sources/nuget.rb', line 60

def project_files
  @nuget_project_files ||= begin
    files = super().flatten.compact

    # Only include the local file if it's a file licensee didn't already detect
    nuspec_license_filename = File.basename(nuspec_local_license_file.filename) if nuspec_local_license_file
    if nuspec_license_filename && files.none? { |file| File.basename(file.filename) == nuspec_license_filename }
      files.push(nuspec_local_license_file)
    end

    # Only download licenseUrl if no recognized license was found locally
    if files.none? { |file| file.license && file.license.key != "other" }
      files.push(nuspec_remote_license_file)
    end

    files.compact
  end
end

#project_urlObject



42
43
44
45
46
47
48
49
# File 'lib/licensed/sources/nuget.rb', line 42

def project_url
  return @project_url if defined?(@project_url)
  @project_url = begin
    return unless nuspec_contents
    match = nuspec_contents.match PROJECT_URL_REGEX
    match[1] if match && match[1]
  end
end