mirror of
https://github.com/anchore/syft
synced 2024-11-10 06:14:16 +00:00
Merge pull request #53 from anchore/add-python-wheel-egg-analyzers
Add python wheel and egg analyzer support
This commit is contained in:
commit
64a9125895
18 changed files with 622 additions and 15 deletions
|
@ -13,7 +13,7 @@ type Analyzer struct {
|
||||||
|
|
||||||
func NewAnalyzer() *Analyzer {
|
func NewAnalyzer() *Analyzer {
|
||||||
globParserDispatch := map[string]common.ParserFn{
|
globParserDispatch := map[string]common.ParserFn{
|
||||||
"*/Gemfile.lock": ParseGemfileLockEntries,
|
"*/Gemfile.lock": parseGemfileLockEntries,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Analyzer{
|
return &Analyzer{
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
|
|
||||||
var sectionsOfInterest = internal.NewStringSetFromSlice([]string{"GEM"})
|
var sectionsOfInterest = internal.NewStringSetFromSlice([]string{"GEM"})
|
||||||
|
|
||||||
func ParseGemfileLockEntries(reader io.Reader) ([]pkg.Package, error) {
|
func parseGemfileLockEntries(reader io.Reader) ([]pkg.Package, error) {
|
||||||
pkgs := make([]pkg.Package, 0)
|
pkgs := make([]pkg.Package, 0)
|
||||||
scanner := bufio.NewScanner(reader)
|
scanner := bufio.NewScanner(reader)
|
||||||
|
|
||||||
|
|
|
@ -67,7 +67,7 @@ func TestParseGemfileLockEntries(t *testing.T) {
|
||||||
t.Fatalf("failed to open fixture: %+v", err)
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
actual, err := ParseGemfileLockEntries(fixture)
|
actual, err := parseGemfileLockEntries(fixture)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("failed to parse gemfile lock: %+v", err)
|
t.Fatalf("failed to parse gemfile lock: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ import (
|
||||||
"github.com/anchore/stereoscope/pkg/tree"
|
"github.com/anchore/stereoscope/pkg/tree"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// TODO: put under test...
|
||||||
|
|
||||||
type GenericAnalyzer struct {
|
type GenericAnalyzer struct {
|
||||||
globParserDispatch map[string]ParserFn
|
globParserDispatch map[string]ParserFn
|
||||||
pathParserDispatch map[string]ParserFn
|
pathParserDispatch map[string]ParserFn
|
||||||
|
|
|
@ -3,6 +3,7 @@ package analyzer
|
||||||
import (
|
import (
|
||||||
"github.com/anchore/imgbom/imgbom/analyzer/bundler"
|
"github.com/anchore/imgbom/imgbom/analyzer/bundler"
|
||||||
"github.com/anchore/imgbom/imgbom/analyzer/dpkg"
|
"github.com/anchore/imgbom/imgbom/analyzer/dpkg"
|
||||||
|
"github.com/anchore/imgbom/imgbom/analyzer/python"
|
||||||
"github.com/anchore/imgbom/imgbom/pkg"
|
"github.com/anchore/imgbom/imgbom/pkg"
|
||||||
"github.com/anchore/imgbom/imgbom/scope"
|
"github.com/anchore/imgbom/imgbom/scope"
|
||||||
"github.com/anchore/imgbom/internal/log"
|
"github.com/anchore/imgbom/internal/log"
|
||||||
|
@ -30,6 +31,7 @@ func newController() controller {
|
||||||
}
|
}
|
||||||
ctrlr.add(dpkg.NewAnalyzer())
|
ctrlr.add(dpkg.NewAnalyzer())
|
||||||
ctrlr.add(bundler.NewAnalyzer())
|
ctrlr.add(bundler.NewAnalyzer())
|
||||||
|
ctrlr.add(python.NewAnalyzer())
|
||||||
return ctrlr
|
return ctrlr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ type Analyzer struct {
|
||||||
|
|
||||||
func NewAnalyzer() *Analyzer {
|
func NewAnalyzer() *Analyzer {
|
||||||
pathParserDispatch := map[string]common.ParserFn{
|
pathParserDispatch := map[string]common.ParserFn{
|
||||||
"/var/lib/dpkg/status": ParseDpkgStatus,
|
"/var/lib/dpkg/status": parseDpkgStatus,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &Analyzer{
|
return &Analyzer{
|
||||||
|
|
|
@ -12,7 +12,7 @@ import (
|
||||||
|
|
||||||
var errEndOfPackages = fmt.Errorf("no more packages to read")
|
var errEndOfPackages = fmt.Errorf("no more packages to read")
|
||||||
|
|
||||||
func ParseDpkgStatus(reader io.Reader) ([]pkg.Package, error) {
|
func parseDpkgStatus(reader io.Reader) ([]pkg.Package, error) {
|
||||||
buffedReader := bufio.NewReader(reader)
|
buffedReader := bufio.NewReader(reader)
|
||||||
var packages = make([]pkg.Package, 0)
|
var packages = make([]pkg.Package, 0)
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ func TestMultiplePackages(t *testing.T) {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
pkgs, err := ParseDpkgStatus(file)
|
pkgs, err := parseDpkgStatus(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal("Unable to read file contents: ", err)
|
t.Fatal("Unable to read file contents: ", err)
|
||||||
}
|
}
|
||||||
|
|
35
imgbom/analyzer/python/analyzer.go
Normal file
35
imgbom/analyzer/python/analyzer.go
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
package python
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/anchore/imgbom/imgbom/analyzer/common"
|
||||||
|
"github.com/anchore/imgbom/imgbom/pkg"
|
||||||
|
"github.com/anchore/stereoscope/pkg/file"
|
||||||
|
"github.com/anchore/stereoscope/pkg/tree"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Analyzer struct {
|
||||||
|
analyzer common.GenericAnalyzer
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewAnalyzer() *Analyzer {
|
||||||
|
globParserDispatch := map[string]common.ParserFn{
|
||||||
|
"*egg-info/PKG-INFO": parseEggMetadata,
|
||||||
|
"*dist-info/METADATA": parseWheelMetadata,
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Analyzer{
|
||||||
|
analyzer: common.NewGenericAnalyzer(nil, globParserDispatch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Analyzer) Name() string {
|
||||||
|
return "python-analyzer"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Analyzer) SelectFiles(trees []tree.FileTreeReader) []file.Reference {
|
||||||
|
return a.analyzer.SelectFiles(trees)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *Analyzer) Analyze(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||||
|
return a.analyzer.Analyze(contents, a.Name())
|
||||||
|
}
|
90
imgbom/analyzer/python/parse_wheel_egg.go
Normal file
90
imgbom/analyzer/python/parse_wheel_egg.go
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
package python
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/anchore/imgbom/imgbom/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseWheelMetadata(reader io.Reader) ([]pkg.Package, error) {
|
||||||
|
packages, err := parseWheelOrEggMetadata(reader)
|
||||||
|
for idx := range packages {
|
||||||
|
packages[idx].Type = pkg.WheelPkg
|
||||||
|
}
|
||||||
|
return packages, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEggMetadata(reader io.Reader) ([]pkg.Package, error) {
|
||||||
|
packages, err := parseWheelOrEggMetadata(reader)
|
||||||
|
for idx := range packages {
|
||||||
|
packages[idx].Type = pkg.EggPkg
|
||||||
|
}
|
||||||
|
return packages, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseWheelOrEggMetadata(reader io.Reader) ([]pkg.Package, error) {
|
||||||
|
fields := make(map[string]string)
|
||||||
|
var key string
|
||||||
|
|
||||||
|
scanner := bufio.NewScanner(reader)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
|
||||||
|
line = strings.TrimRight(line, "\n")
|
||||||
|
|
||||||
|
// empty line indicates end of entry
|
||||||
|
if len(line) == 0 {
|
||||||
|
// if the entry has not started, keep parsing lines
|
||||||
|
if len(fields) == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
switch {
|
||||||
|
case strings.HasPrefix(line, " "):
|
||||||
|
// a field-body continuation
|
||||||
|
if len(key) == 0 {
|
||||||
|
return nil, fmt.Errorf("no match for continuation: line: '%s'", line)
|
||||||
|
}
|
||||||
|
|
||||||
|
val, ok := fields[key]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("no previous key exists, expecting: %s", key)
|
||||||
|
}
|
||||||
|
// concatenate onto previous value
|
||||||
|
val = fmt.Sprintf("%s\n %s", val, strings.TrimSpace(line))
|
||||||
|
fields[key] = val
|
||||||
|
default:
|
||||||
|
// parse a new key (note, duplicate keys are overridden)
|
||||||
|
if i := strings.Index(line, ":"); i > 0 {
|
||||||
|
key = strings.TrimSpace(line[0:i])
|
||||||
|
val := strings.TrimSpace(line[i+1:])
|
||||||
|
|
||||||
|
fields[key] = val
|
||||||
|
} else {
|
||||||
|
return nil, fmt.Errorf("cannot parse field from line: '%s'", line)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse python wheel/egg: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
p := pkg.Package{
|
||||||
|
Name: fields["Name"],
|
||||||
|
Version: fields["Version"],
|
||||||
|
Language: pkg.Python,
|
||||||
|
}
|
||||||
|
|
||||||
|
if license, ok := fields["License"]; ok && license != "" {
|
||||||
|
p.Licenses = []string{license}
|
||||||
|
}
|
||||||
|
|
||||||
|
return []pkg.Package{p}, nil
|
||||||
|
}
|
91
imgbom/analyzer/python/parse_wheel_egg_test.go
Normal file
91
imgbom/analyzer/python/parse_wheel_egg_test.go
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
package python
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/anchore/imgbom/imgbom/pkg"
|
||||||
|
)
|
||||||
|
|
||||||
|
func assertPkgsEqual(t *testing.T, actual []pkg.Package, expected map[string]pkg.Package) {
|
||||||
|
t.Helper()
|
||||||
|
if len(actual) != 1 {
|
||||||
|
for _, a := range actual {
|
||||||
|
t.Log(" ", a)
|
||||||
|
}
|
||||||
|
t.Fatalf("unexpected package count: %d!=%d", len(actual), 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, a := range actual {
|
||||||
|
expectedPkg, ok := expected[a.Name]
|
||||||
|
if !ok {
|
||||||
|
t.Errorf("unexpected package found: '%s'", a.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if expectedPkg.Version != a.Version {
|
||||||
|
t.Errorf("unexpected package version: '%s'", a.Version)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Language != expectedPkg.Language {
|
||||||
|
t.Errorf("bad language: '%+v'", a.Language)
|
||||||
|
}
|
||||||
|
|
||||||
|
if a.Type != expectedPkg.Type {
|
||||||
|
t.Errorf("bad package type: %+v", a.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(a.Licenses) < 1 {
|
||||||
|
t.Errorf("bad package licenses count: '%+v'", a.Licenses)
|
||||||
|
} else if a.Licenses[0] != expectedPkg.Licenses[0] {
|
||||||
|
t.Errorf("bad package licenses: '%+v'", a.Licenses)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestParseEggMetadata(t *testing.T) {
|
||||||
|
expected := map[string]pkg.Package{
|
||||||
|
"requests": {
|
||||||
|
Name: "requests",
|
||||||
|
Version: "2.22.0",
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.EggPkg,
|
||||||
|
Licenses: []string{"Apache 2.0"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
fixture, err := os.Open("test-fixtures/egg-info/PKG-INFO")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := parseEggMetadata(fixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to parse egg-info: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertPkgsEqual(t, actual, expected)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseWheelMetadata(t *testing.T) {
|
||||||
|
expected := map[string]pkg.Package{
|
||||||
|
"Pygments": {
|
||||||
|
Name: "Pygments",
|
||||||
|
Version: "2.6.1",
|
||||||
|
Language: pkg.Python,
|
||||||
|
Type: pkg.WheelPkg,
|
||||||
|
Licenses: []string{"BSD License"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
fixture, err := os.Open("test-fixtures/dist-info/METADATA")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to open fixture: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
actual, err := parseWheelMetadata(fixture)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("failed to parse dist-info: %+v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertPkgsEqual(t, actual, expected)
|
||||||
|
|
||||||
|
}
|
47
imgbom/analyzer/python/test-fixtures/dist-info/METADATA
Normal file
47
imgbom/analyzer/python/test-fixtures/dist-info/METADATA
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
Metadata-Version: 2.1
|
||||||
|
Name: Pygments
|
||||||
|
Version: 2.6.1
|
||||||
|
Summary: Pygments is a syntax highlighting package written in Python.
|
||||||
|
Home-page: https://pygments.org/
|
||||||
|
Author: Georg Brandl
|
||||||
|
Author-email: georg@python.org
|
||||||
|
License: BSD License
|
||||||
|
Keywords: syntax highlighting
|
||||||
|
Platform: any
|
||||||
|
Classifier: License :: OSI Approved :: BSD License
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: Intended Audience :: End Users/Desktop
|
||||||
|
Classifier: Intended Audience :: System Administrators
|
||||||
|
Classifier: Development Status :: 6 - Mature
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Programming Language :: Python :: 3.7
|
||||||
|
Classifier: Programming Language :: Python :: 3.8
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||||
|
Classifier: Operating System :: OS Independent
|
||||||
|
Classifier: Topic :: Text Processing :: Filters
|
||||||
|
Classifier: Topic :: Utilities
|
||||||
|
Requires-Python: >=3.5
|
||||||
|
|
||||||
|
|
||||||
|
Pygments
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Pygments is a syntax highlighting package written in Python.
|
||||||
|
|
||||||
|
It is a generic syntax highlighter suitable for use in code hosting, forums,
|
||||||
|
wikis or other applications that need to prettify source code. Highlights
|
||||||
|
are:
|
||||||
|
|
||||||
|
* a wide range of over 500 languages and other text formats is supported
|
||||||
|
* special attention is paid to details, increasing quality by a fair amount
|
||||||
|
* support for new languages and formats are added easily
|
||||||
|
* a number of output formats, presently HTML, LaTeX, RTF, SVG, all image formats that PIL supports and ANSI sequences
|
||||||
|
* it is usable as a command-line tool and as a library
|
||||||
|
|
||||||
|
:copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
|
134
imgbom/analyzer/python/test-fixtures/egg-info/PKG-INFO
Normal file
134
imgbom/analyzer/python/test-fixtures/egg-info/PKG-INFO
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
Metadata-Version: 2.1
|
||||||
|
Name: requests
|
||||||
|
Version: 2.22.0
|
||||||
|
Summary: Python HTTP for Humans.
|
||||||
|
Home-page: http://python-requests.org
|
||||||
|
Author: Kenneth Reitz
|
||||||
|
Author-email: me@kennethreitz.org
|
||||||
|
License: Apache 2.0
|
||||||
|
Description: Requests: HTTP for Humans™
|
||||||
|
==========================
|
||||||
|
|
||||||
|
[![image](https://img.shields.io/pypi/v/requests.svg)](https://pypi.org/project/requests/)
|
||||||
|
[![image](https://img.shields.io/pypi/l/requests.svg)](https://pypi.org/project/requests/)
|
||||||
|
[![image](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests/)
|
||||||
|
[![codecov.io](https://codecov.io/github/requests/requests/coverage.svg?branch=master)](https://codecov.io/github/requests/requests)
|
||||||
|
[![image](https://img.shields.io/github/contributors/requests/requests.svg)](https://github.com/requests/requests/graphs/contributors)
|
||||||
|
[![image](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/kennethreitz)
|
||||||
|
|
||||||
|
Requests is the only *Non-GMO* HTTP library for Python, safe for human
|
||||||
|
consumption.
|
||||||
|
|
||||||
|
![image](https://farm5.staticflickr.com/4317/35198386374_1939af3de6_k_d.jpg)
|
||||||
|
|
||||||
|
Behold, the power of Requests:
|
||||||
|
|
||||||
|
``` {.sourceCode .python}
|
||||||
|
>>> import requests
|
||||||
|
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
|
||||||
|
>>> r.status_code
|
||||||
|
200
|
||||||
|
>>> r.headers['content-type']
|
||||||
|
'application/json; charset=utf8'
|
||||||
|
>>> r.encoding
|
||||||
|
'utf-8'
|
||||||
|
>>> r.text
|
||||||
|
u'{"type":"User"...'
|
||||||
|
>>> r.json()
|
||||||
|
{u'disk_usage': 368627, u'private_gists': 484, ...}
|
||||||
|
```
|
||||||
|
|
||||||
|
See [the similar code, sans Requests](https://gist.github.com/973705).
|
||||||
|
|
||||||
|
[![image](https://raw.githubusercontent.com/requests/requests/master/docs/_static/requests-logo-small.png)](http://docs.python-requests.org/)
|
||||||
|
|
||||||
|
Requests allows you to send *organic, grass-fed* HTTP/1.1 requests,
|
||||||
|
without the need for manual labor. There's no need to manually add query
|
||||||
|
strings to your URLs, or to form-encode your POST data. Keep-alive and
|
||||||
|
HTTP connection pooling are 100% automatic, thanks to
|
||||||
|
[urllib3](https://github.com/shazow/urllib3).
|
||||||
|
|
||||||
|
Besides, all the cool kids are doing it. Requests is one of the most
|
||||||
|
downloaded Python packages of all time, pulling in over 11,000,000
|
||||||
|
downloads every month. You don't want to be left out!
|
||||||
|
|
||||||
|
Feature Support
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Requests is ready for today's web.
|
||||||
|
|
||||||
|
- International Domains and URLs
|
||||||
|
- Keep-Alive & Connection Pooling
|
||||||
|
- Sessions with Cookie Persistence
|
||||||
|
- Browser-style SSL Verification
|
||||||
|
- Basic/Digest Authentication
|
||||||
|
- Elegant Key/Value Cookies
|
||||||
|
- Automatic Decompression
|
||||||
|
- Automatic Content Decoding
|
||||||
|
- Unicode Response Bodies
|
||||||
|
- Multipart File Uploads
|
||||||
|
- HTTP(S) Proxy Support
|
||||||
|
- Connection Timeouts
|
||||||
|
- Streaming Downloads
|
||||||
|
- `.netrc` Support
|
||||||
|
- Chunked Requests
|
||||||
|
|
||||||
|
Requests officially supports Python 2.7 & 3.4–3.7, and runs great on
|
||||||
|
PyPy.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
To install Requests, simply use [pipenv](http://pipenv.org/) (or pip, of
|
||||||
|
course):
|
||||||
|
|
||||||
|
``` {.sourceCode .bash}
|
||||||
|
$ pipenv install requests
|
||||||
|
✨🍰✨
|
||||||
|
```
|
||||||
|
|
||||||
|
Satisfaction guaranteed.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Fantastic documentation is available at
|
||||||
|
<http://docs.python-requests.org/>, for a limited time only.
|
||||||
|
|
||||||
|
How to Contribute
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
1. Become more familiar with the project by reading our [Contributor's Guide](http://docs.python-requests.org/en/latest/dev/contributing/) and our [development philosophy](http://docs.python-requests.org/en/latest/dev/philosophy/).
|
||||||
|
2. Check for open issues or open a fresh issue to start a discussion
|
||||||
|
around a feature idea or a bug. There is a [Contributor
|
||||||
|
Friendly](https://github.com/requests/requests/issues?direction=desc&labels=Contributor+Friendly&page=1&sort=updated&state=open)
|
||||||
|
tag for issues that should be ideal for people who are not very
|
||||||
|
familiar with the codebase yet.
|
||||||
|
3. Fork [the repository](https://github.com/requests/requests) on
|
||||||
|
GitHub to start making your changes to the **master** branch (or
|
||||||
|
branch off of it).
|
||||||
|
4. Write a test which shows that the bug was fixed or that the feature
|
||||||
|
works as expected.
|
||||||
|
5. Send a pull request and bug the maintainer until it gets merged and
|
||||||
|
published. :) Make sure to add yourself to
|
||||||
|
[AUTHORS](https://github.com/requests/requests/blob/master/AUTHORS.rst).
|
||||||
|
|
||||||
|
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: Natural Language :: English
|
||||||
|
Classifier: License :: OSI Approved :: Apache Software License
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 2
|
||||||
|
Classifier: Programming Language :: Python :: 2.7
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Programming Language :: Python :: 3.7
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||||
|
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
|
||||||
|
Description-Content-Type: text/markdown
|
||||||
|
Provides-Extra: security
|
||||||
|
Provides-Extra: socks
|
|
@ -5,8 +5,10 @@ const (
|
||||||
ApkPkg
|
ApkPkg
|
||||||
BundlerPkg
|
BundlerPkg
|
||||||
DebPkg
|
DebPkg
|
||||||
|
EggPkg
|
||||||
PacmanPkg
|
PacmanPkg
|
||||||
RpmPkg
|
RpmPkg
|
||||||
|
WheelPkg
|
||||||
)
|
)
|
||||||
|
|
||||||
type Type uint
|
type Type uint
|
||||||
|
@ -14,18 +16,22 @@ type Type uint
|
||||||
var typeStr = []string{
|
var typeStr = []string{
|
||||||
"UnknownPackage",
|
"UnknownPackage",
|
||||||
"apk",
|
"apk",
|
||||||
"bundler",
|
"bundle",
|
||||||
"deb",
|
"deb",
|
||||||
|
"egg",
|
||||||
"pacman",
|
"pacman",
|
||||||
"rpm",
|
"rpm",
|
||||||
|
"wheel",
|
||||||
}
|
}
|
||||||
|
|
||||||
var AllPkgs = []Type{
|
var AllPkgs = []Type{
|
||||||
ApkPkg,
|
ApkPkg,
|
||||||
BundlerPkg,
|
BundlerPkg,
|
||||||
DebPkg,
|
DebPkg,
|
||||||
|
EggPkg,
|
||||||
PacmanPkg,
|
PacmanPkg,
|
||||||
RpmPkg,
|
RpmPkg,
|
||||||
|
WheelPkg,
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Type) String() string {
|
func (t Type) String() string {
|
||||||
|
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"github.com/anchore/imgbom/imgbom/scope"
|
"github.com/anchore/imgbom/imgbom/scope"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBundlerImage(t *testing.T) {
|
func TestLanguageImage(t *testing.T) {
|
||||||
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-language-pkgs")
|
img, cleanup := testutils.GetFixtureImage(t, "docker-archive", "image-language-pkgs")
|
||||||
defer cleanup()
|
defer cleanup()
|
||||||
|
|
||||||
|
@ -26,6 +26,22 @@ func TestBundlerImage(t *testing.T) {
|
||||||
pkgLanguage pkg.Language
|
pkgLanguage pkg.Language
|
||||||
pkgInfo map[string]string
|
pkgInfo map[string]string
|
||||||
}{
|
}{
|
||||||
|
{
|
||||||
|
name: "find python wheel packages",
|
||||||
|
pkgType: pkg.WheelPkg,
|
||||||
|
pkgLanguage: pkg.Python,
|
||||||
|
pkgInfo: map[string]string{
|
||||||
|
"Pygments": "2.6.1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "find python egg packages",
|
||||||
|
pkgType: pkg.EggPkg,
|
||||||
|
pkgLanguage: pkg.Python,
|
||||||
|
pkgInfo: map[string]string{
|
||||||
|
"requests": "2.22.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "find bundler packages",
|
name: "find bundler packages",
|
||||||
pkgType: pkg.BundlerPkg,
|
pkgType: pkg.BundlerPkg,
|
||||||
|
@ -88,12 +104,7 @@ func TestBundlerImage(t *testing.T) {
|
||||||
for _, c := range cases {
|
for _, c := range cases {
|
||||||
t.Run(c.name, func(t *testing.T) {
|
t.Run(c.name, func(t *testing.T) {
|
||||||
|
|
||||||
if catalog.PackageCount() != len(c.pkgInfo) {
|
pkgCount := 0
|
||||||
for a := range catalog.Enumerate(c.pkgType) {
|
|
||||||
t.Log(" ", a)
|
|
||||||
}
|
|
||||||
t.Fatalf("unexpected package count: %d!=%d", catalog.PackageCount(), len(c.pkgInfo))
|
|
||||||
}
|
|
||||||
|
|
||||||
for a := range catalog.Enumerate(c.pkgType) {
|
for a := range catalog.Enumerate(c.pkgType) {
|
||||||
|
|
||||||
|
@ -113,6 +124,14 @@ func TestBundlerImage(t *testing.T) {
|
||||||
if a.Type != c.pkgType {
|
if a.Type != c.pkgType {
|
||||||
t.Errorf("bad package type (pkg=%+v): %+v", a.Name, a.Type)
|
t.Errorf("bad package type (pkg=%+v): %+v", a.Name, a.Type)
|
||||||
}
|
}
|
||||||
|
pkgCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
if pkgCount != len(c.pkgInfo) {
|
||||||
|
for a := range catalog.Enumerate(c.pkgType) {
|
||||||
|
t.Log(" ", a)
|
||||||
|
}
|
||||||
|
t.Fatalf("unexpected package count: %d!=%d", pkgCount, len(c.pkgInfo))
|
||||||
}
|
}
|
||||||
|
|
||||||
})
|
})
|
|
@ -1,2 +1,2 @@
|
||||||
FROM scratch
|
FROM scratch
|
||||||
COPY Gemfile.lock .
|
COPY . .
|
|
@ -0,0 +1,47 @@
|
||||||
|
Metadata-Version: 2.1
|
||||||
|
Name: Pygments
|
||||||
|
Version: 2.6.1
|
||||||
|
Summary: Pygments is a syntax highlighting package written in Python.
|
||||||
|
Home-page: https://pygments.org/
|
||||||
|
Author: Georg Brandl
|
||||||
|
Author-email: georg@python.org
|
||||||
|
License: BSD License
|
||||||
|
Keywords: syntax highlighting
|
||||||
|
Platform: any
|
||||||
|
Classifier: License :: OSI Approved :: BSD License
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: Intended Audience :: End Users/Desktop
|
||||||
|
Classifier: Intended Audience :: System Administrators
|
||||||
|
Classifier: Development Status :: 6 - Mature
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Programming Language :: Python :: 3.7
|
||||||
|
Classifier: Programming Language :: Python :: 3.8
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||||
|
Classifier: Operating System :: OS Independent
|
||||||
|
Classifier: Topic :: Text Processing :: Filters
|
||||||
|
Classifier: Topic :: Utilities
|
||||||
|
Requires-Python: >=3.5
|
||||||
|
|
||||||
|
|
||||||
|
Pygments
|
||||||
|
~~~~~~~~
|
||||||
|
|
||||||
|
Pygments is a syntax highlighting package written in Python.
|
||||||
|
|
||||||
|
It is a generic syntax highlighter suitable for use in code hosting, forums,
|
||||||
|
wikis or other applications that need to prettify source code. Highlights
|
||||||
|
are:
|
||||||
|
|
||||||
|
* a wide range of over 500 languages and other text formats is supported
|
||||||
|
* special attention is paid to details, increasing quality by a fair amount
|
||||||
|
* support for new languages and formats are added easily
|
||||||
|
* a number of output formats, presently HTML, LaTeX, RTF, SVG, all image formats that PIL supports and ANSI sequences
|
||||||
|
* it is usable as a command-line tool and as a library
|
||||||
|
|
||||||
|
:copyright: Copyright 2006-2019 by the Pygments team, see AUTHORS.
|
||||||
|
:license: BSD, see LICENSE for details.
|
||||||
|
|
134
integration/test-fixtures/image-language-pkgs/egg-info/PKG-INFO
Normal file
134
integration/test-fixtures/image-language-pkgs/egg-info/PKG-INFO
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
Metadata-Version: 2.1
|
||||||
|
Name: requests
|
||||||
|
Version: 2.22.0
|
||||||
|
Summary: Python HTTP for Humans.
|
||||||
|
Home-page: http://python-requests.org
|
||||||
|
Author: Kenneth Reitz
|
||||||
|
Author-email: me@kennethreitz.org
|
||||||
|
License: Apache 2.0
|
||||||
|
Description: Requests: HTTP for Humans™
|
||||||
|
==========================
|
||||||
|
|
||||||
|
[![image](https://img.shields.io/pypi/v/requests.svg)](https://pypi.org/project/requests/)
|
||||||
|
[![image](https://img.shields.io/pypi/l/requests.svg)](https://pypi.org/project/requests/)
|
||||||
|
[![image](https://img.shields.io/pypi/pyversions/requests.svg)](https://pypi.org/project/requests/)
|
||||||
|
[![codecov.io](https://codecov.io/github/requests/requests/coverage.svg?branch=master)](https://codecov.io/github/requests/requests)
|
||||||
|
[![image](https://img.shields.io/github/contributors/requests/requests.svg)](https://github.com/requests/requests/graphs/contributors)
|
||||||
|
[![image](https://img.shields.io/badge/Say%20Thanks-!-1EAEDB.svg)](https://saythanks.io/to/kennethreitz)
|
||||||
|
|
||||||
|
Requests is the only *Non-GMO* HTTP library for Python, safe for human
|
||||||
|
consumption.
|
||||||
|
|
||||||
|
![image](https://farm5.staticflickr.com/4317/35198386374_1939af3de6_k_d.jpg)
|
||||||
|
|
||||||
|
Behold, the power of Requests:
|
||||||
|
|
||||||
|
``` {.sourceCode .python}
|
||||||
|
>>> import requests
|
||||||
|
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass'))
|
||||||
|
>>> r.status_code
|
||||||
|
200
|
||||||
|
>>> r.headers['content-type']
|
||||||
|
'application/json; charset=utf8'
|
||||||
|
>>> r.encoding
|
||||||
|
'utf-8'
|
||||||
|
>>> r.text
|
||||||
|
u'{"type":"User"...'
|
||||||
|
>>> r.json()
|
||||||
|
{u'disk_usage': 368627, u'private_gists': 484, ...}
|
||||||
|
```
|
||||||
|
|
||||||
|
See [the similar code, sans Requests](https://gist.github.com/973705).
|
||||||
|
|
||||||
|
[![image](https://raw.githubusercontent.com/requests/requests/master/docs/_static/requests-logo-small.png)](http://docs.python-requests.org/)
|
||||||
|
|
||||||
|
Requests allows you to send *organic, grass-fed* HTTP/1.1 requests,
|
||||||
|
without the need for manual labor. There's no need to manually add query
|
||||||
|
strings to your URLs, or to form-encode your POST data. Keep-alive and
|
||||||
|
HTTP connection pooling are 100% automatic, thanks to
|
||||||
|
[urllib3](https://github.com/shazow/urllib3).
|
||||||
|
|
||||||
|
Besides, all the cool kids are doing it. Requests is one of the most
|
||||||
|
downloaded Python packages of all time, pulling in over 11,000,000
|
||||||
|
downloads every month. You don't want to be left out!
|
||||||
|
|
||||||
|
Feature Support
|
||||||
|
---------------
|
||||||
|
|
||||||
|
Requests is ready for today's web.
|
||||||
|
|
||||||
|
- International Domains and URLs
|
||||||
|
- Keep-Alive & Connection Pooling
|
||||||
|
- Sessions with Cookie Persistence
|
||||||
|
- Browser-style SSL Verification
|
||||||
|
- Basic/Digest Authentication
|
||||||
|
- Elegant Key/Value Cookies
|
||||||
|
- Automatic Decompression
|
||||||
|
- Automatic Content Decoding
|
||||||
|
- Unicode Response Bodies
|
||||||
|
- Multipart File Uploads
|
||||||
|
- HTTP(S) Proxy Support
|
||||||
|
- Connection Timeouts
|
||||||
|
- Streaming Downloads
|
||||||
|
- `.netrc` Support
|
||||||
|
- Chunked Requests
|
||||||
|
|
||||||
|
Requests officially supports Python 2.7 & 3.4–3.7, and runs great on
|
||||||
|
PyPy.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
|
||||||
|
To install Requests, simply use [pipenv](http://pipenv.org/) (or pip, of
|
||||||
|
course):
|
||||||
|
|
||||||
|
``` {.sourceCode .bash}
|
||||||
|
$ pipenv install requests
|
||||||
|
✨🍰✨
|
||||||
|
```
|
||||||
|
|
||||||
|
Satisfaction guaranteed.
|
||||||
|
|
||||||
|
Documentation
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Fantastic documentation is available at
|
||||||
|
<http://docs.python-requests.org/>, for a limited time only.
|
||||||
|
|
||||||
|
How to Contribute
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
1. Become more familiar with the project by reading our [Contributor's Guide](http://docs.python-requests.org/en/latest/dev/contributing/) and our [development philosophy](http://docs.python-requests.org/en/latest/dev/philosophy/).
|
||||||
|
2. Check for open issues or open a fresh issue to start a discussion
|
||||||
|
around a feature idea or a bug. There is a [Contributor
|
||||||
|
Friendly](https://github.com/requests/requests/issues?direction=desc&labels=Contributor+Friendly&page=1&sort=updated&state=open)
|
||||||
|
tag for issues that should be ideal for people who are not very
|
||||||
|
familiar with the codebase yet.
|
||||||
|
3. Fork [the repository](https://github.com/requests/requests) on
|
||||||
|
GitHub to start making your changes to the **master** branch (or
|
||||||
|
branch off of it).
|
||||||
|
4. Write a test which shows that the bug was fixed or that the feature
|
||||||
|
works as expected.
|
||||||
|
5. Send a pull request and bug the maintainer until it gets merged and
|
||||||
|
published. :) Make sure to add yourself to
|
||||||
|
[AUTHORS](https://github.com/requests/requests/blob/master/AUTHORS.rst).
|
||||||
|
|
||||||
|
|
||||||
|
Platform: UNKNOWN
|
||||||
|
Classifier: Development Status :: 5 - Production/Stable
|
||||||
|
Classifier: Intended Audience :: Developers
|
||||||
|
Classifier: Natural Language :: English
|
||||||
|
Classifier: License :: OSI Approved :: Apache Software License
|
||||||
|
Classifier: Programming Language :: Python
|
||||||
|
Classifier: Programming Language :: Python :: 2
|
||||||
|
Classifier: Programming Language :: Python :: 2.7
|
||||||
|
Classifier: Programming Language :: Python :: 3
|
||||||
|
Classifier: Programming Language :: Python :: 3.5
|
||||||
|
Classifier: Programming Language :: Python :: 3.6
|
||||||
|
Classifier: Programming Language :: Python :: 3.7
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||||
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||||
|
Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*
|
||||||
|
Description-Content-Type: text/markdown
|
||||||
|
Provides-Extra: security
|
||||||
|
Provides-Extra: socks
|
Loading…
Reference in a new issue