mirror of
https://github.com/anchore/syft.git
synced 2026-10-12 22:27:22 +02:00
Compare commits
7
Commits
v1.1.1
...
plugin-system
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
206fd8b7d3 | ||
|
|
c348d97fe0 | ||
|
|
30bb7cf992 | ||
|
|
54e0ee4c47 | ||
|
|
c231a9d7cb | ||
|
|
3e27b6e93f | ||
|
|
63ee5ba098 |
+1
-1
@@ -31,7 +31,6 @@ linters:
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- prealloc
|
||||
- rowserrcheck
|
||||
- scopelint
|
||||
- staticcheck
|
||||
@@ -55,5 +54,6 @@ linters:
|
||||
# - lll # without a way to specify per-line exception cases, this is not usable
|
||||
# - maligned # this is an excellent linter, but tricky to optimize and we are not sensitive to memory layout optimizations
|
||||
# - nestif
|
||||
# - prealloc # this unnecessarily requires preallocations for slices
|
||||
# - testpackage
|
||||
# - wsl
|
||||
@@ -169,6 +169,9 @@ check-pipeline: ## Run local CircleCI pipeline locally (sanity check)
|
||||
circleci local execute -c .tmp/circleci.yml --job "Unit & Integration Tests (go-latest)"
|
||||
@printf '$(SUCCESS)Pipeline checks pass!$(RESET)\n'
|
||||
|
||||
proto:
|
||||
protoc -I syft/plugin/proto/ syft/plugin/proto/cataloger.proto --go_out=plugins=grpc:syft/plugin/proto/
|
||||
|
||||
.PHONY: build
|
||||
build: $(SNAPSHOTDIR) ## Build release snapshot binaries and packages
|
||||
|
||||
|
||||
+17
-1
@@ -3,6 +3,10 @@ package cmd
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/adrg/xdg"
|
||||
"github.com/anchore/syft/internal"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
@@ -78,6 +82,18 @@ func setGlobalCliOptions() {
|
||||
}
|
||||
|
||||
rootCmd.Flags().CountVarP(&cliOpts.Verbosity, "verbose", "v", "increase verbosity (-v = info, -vv = debug)")
|
||||
|
||||
// plugins
|
||||
defaultPluginDir := path.Join(xdg.CacheHome, internal.ApplicationName, "plugins")
|
||||
flag = "plugins.dir"
|
||||
rootCmd.Flags().String(
|
||||
flag, defaultPluginDir,
|
||||
"plugin storage directory",
|
||||
)
|
||||
if err := viper.BindPFlag(flag, rootCmd.Flags().Lookup(flag)); err != nil {
|
||||
fmt.Printf("unable to bind flag '%s': %+v", flag, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func initAppConfig() {
|
||||
@@ -101,7 +117,7 @@ func initLogging() {
|
||||
logWrapper := logger.NewLogrusLogger(cfg)
|
||||
syft.SetLogger(logWrapper)
|
||||
stereoscope.SetLogger(&logger.LogrusNestedLogger{
|
||||
Logger: logWrapper.Logger.WithField("from-lib", "steroscope"),
|
||||
Logger: logWrapper.Logger.WithField("from-lib", "stereoscope"),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
+11
-1
@@ -68,7 +68,17 @@ func startWorker(userInput string) <-chan error {
|
||||
}
|
||||
}
|
||||
|
||||
catalog, scope, distro, err := syft.Catalog(userInput, appConfig.ScopeOpt)
|
||||
config := syft.Config{
|
||||
PluginDirectory: appConfig.Plugins.Directory,
|
||||
}
|
||||
|
||||
client, err := syft.NewClient(config)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("could not initialize syft: %+v", err)
|
||||
return
|
||||
}
|
||||
|
||||
catalog, scope, distro, err := client.Catalog(userInput, appConfig.ScopeOpt)
|
||||
if err != nil {
|
||||
errs <- fmt.Errorf("failed to catalog input: %+v", err)
|
||||
return
|
||||
|
||||
@@ -7,16 +7,19 @@ require (
|
||||
github.com/anchore/go-rpmdb v0.0.0-20200811175839-cbc751c28e8e
|
||||
github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||
github.com/anchore/stereoscope v0.0.0-20200813152757-548b22c8a0b3
|
||||
github.com/anchore/stereoscope v0.0.0-20200903223322-a3806f515470
|
||||
github.com/bmatcuk/doublestar v1.3.1
|
||||
github.com/containerd/continuity v0.0.0-20200710164510-efbc4488d8fe // indirect
|
||||
github.com/dustin/go-humanize v1.0.0
|
||||
github.com/go-test/deep v1.0.6
|
||||
github.com/golang/protobuf v1.4.2
|
||||
github.com/google/go-containerregistry v0.1.1 // indirect
|
||||
github.com/google/uuid v1.1.1
|
||||
github.com/gookit/color v1.2.7
|
||||
github.com/gopherjs/gopherjs v0.0.0-20190910122728-9d188e94fb99 // indirect
|
||||
github.com/hashicorp/go-hclog v0.14.1
|
||||
github.com/hashicorp/go-multierror v1.1.0
|
||||
github.com/hashicorp/go-plugin v1.3.0
|
||||
github.com/hashicorp/go-version v1.2.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/mitchellh/mapstructure v1.3.1
|
||||
@@ -38,6 +41,7 @@ require (
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208 // indirect
|
||||
golang.org/x/sys v0.0.0-20200610111108-226ff32320da // indirect
|
||||
google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7 // indirect
|
||||
google.golang.org/grpc v1.31.1
|
||||
gopkg.in/ini.v1 v1.57.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.3.0
|
||||
)
|
||||
|
||||
@@ -131,8 +131,8 @@ github.com/anchore/go-testutils v0.0.0-20200624184116-66aa578126db/go.mod h1:D3r
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b h1:e1bmaoJfZVsCYMrIZBpFxwV26CbsuoEh5muXD5I1Ods=
|
||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b/go.mod h1:Bkc+JYWjMCF8OyZ340IMSIi2Ebf3uwByOk6ho4wne1E=
|
||||
github.com/anchore/stereoscope v0.0.0-20200520221116-025e07f1c93e/go.mod h1:bkyLl5VITnrmgErv4S1vDfVz/TGAZ5il6161IQo7w2g=
|
||||
github.com/anchore/stereoscope v0.0.0-20200813152757-548b22c8a0b3 h1:pl+txuYlhK8Mmio4d+4zQI/1xg8X6BtNErTASrx23Wk=
|
||||
github.com/anchore/stereoscope v0.0.0-20200813152757-548b22c8a0b3/go.mod h1:WntReQTI/I27FOQ87UgLVVzWgku6+ZsqfOTLxpIZFCs=
|
||||
github.com/anchore/stereoscope v0.0.0-20200903223322-a3806f515470 h1:apXyPyfiaL/YQF7VeXRbDDB9TA7dA9rxdq8YbzPk9ko=
|
||||
github.com/anchore/stereoscope v0.0.0-20200903223322-a3806f515470/go.mod h1:WntReQTI/I27FOQ87UgLVVzWgku6+ZsqfOTLxpIZFCs=
|
||||
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
|
||||
github.com/apex/log v1.1.4/go.mod h1:AlpoD9aScyQfJDVHmLMEcx4oU6LqzkWp4Mg9GdAcEvQ=
|
||||
github.com/apex/log v1.3.0 h1:1fyfbPvUwD10nMoh3hY6MXzvZShJQn9/ck7ATgAt5pA=
|
||||
@@ -474,12 +474,18 @@ github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/U
|
||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1 h1:dH3aiDG9Jvb5r5+bYHsikaOUIpcM0xvgMXVoDkXMzJM=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI=
|
||||
github.com/hashicorp/go-hclog v0.9.2 h1:CG6TE5H9/JXsFWJCfoIVpKFIkFe6ysEuHirp4DxCsHI=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v0.14.1 h1:nQcJDQwIAGnmoUWp8ubocEX40cCml/17YkF6csQLReU=
|
||||
github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ=
|
||||
github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60=
|
||||
github.com/hashicorp/go-msgpack v0.5.3/go.mod h1:ahLV/dePpqEmjfWmKiqvPkv/twdG7iPBM1vqhUKIvfM=
|
||||
github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHhCYQXV3UM06sGGrk=
|
||||
github.com/hashicorp/go-multierror v1.1.0 h1:B9UzwGQJehnUY1yNrnwREHc3fGbC2xefo8g4TbElacI=
|
||||
github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA=
|
||||
github.com/hashicorp/go-plugin v1.3.0 h1:4d/wJojzvHV1I4i/rrjVaeuyxWrLzDE1mDCyDy8fXS8=
|
||||
github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.4/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6 h1:HJunrbHTDDbBb/ay4kxa1n+dLmttUlnP3V9oNE4hmsM=
|
||||
github.com/hashicorp/go-retryablehttp v0.6.6/go.mod h1:vAew36LZh98gCBJNLH42IQ1ER/9wtLZZ8meHqQvEYWY=
|
||||
@@ -500,6 +506,8 @@ github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
|
||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb h1:b5rjCoWHc7eqmAS4/qyk21ZsHyb6Mxv/jykxvNTkU4M=
|
||||
github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
|
||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
@@ -510,6 +518,8 @@ github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJ
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jarcoal/httpmock v1.0.5/go.mod h1:ATjnClrvW/3tijVmpL/va5Z3aAyGvqU3gCT8nX0Txik=
|
||||
github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE=
|
||||
github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74=
|
||||
github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a h1:GmsqmapfzSJkm28dhRoHz2tLRbJmqhU86IPgBtN3mmk=
|
||||
github.com/jingyugao/rowserrcheck v0.0.0-20191204022205-72ab7603b68a/go.mod h1:xRskid8CManxVta/ALEhJha/pweKBaVG6fWgc0yH25s=
|
||||
github.com/jirfag/go-printf-func-name v0.0.0-20191110105641-45db9963cdd3/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
|
||||
@@ -589,6 +599,7 @@ github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNx
|
||||
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.6/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
@@ -611,6 +622,8 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-ps v0.0.0-20190716172923-621e5597135b/go.mod h1:r1VsdOzOPt1ZSrGZWFoNhsAedKnEd6r9Np1+5blZCWk=
|
||||
github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 h1:fzU/JVNcaqHQEcVFAKeR41fkiLdIPrefOvVG1VZ96U0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
@@ -639,6 +652,8 @@ github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d h1:AREM5mwr4u1
|
||||
github.com/nbutton23/zxcvbn-go v0.0.0-20180912185939-ae427f1e4c1d/go.mod h1:o96djdrsSGy3AWPyBgZMAGfxZNfgntdJG+11KU4QvbU=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw=
|
||||
github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/olekukonko/tablewriter v0.0.4 h1:vHD/YYe1Wolo78koG299f7V/VAS08c6IpCLn+Ejf/w8=
|
||||
@@ -923,6 +938,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1012,6 +1028,7 @@ golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191112214154-59a1497f0cea/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
@@ -1148,6 +1165,7 @@ google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
@@ -1181,6 +1199,7 @@ google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb h1:ek2py5bOqzR7MR/
|
||||
google.golang.org/genproto v0.0.0-20200604104852-0b0486081ffb/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7 h1:1N7l1PuXZwEK7OhHdmKQROOM75PnUjABGwvVRbLBgFk=
|
||||
google.golang.org/genproto v0.0.0-20200615140333-fd031eab31e7/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
@@ -1195,6 +1214,8 @@ google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1 h1:EC2SB8S04d2r73uptxphDSUG+kTKVgjRPF+N3xpxRB4=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.31.1 h1:SfXqXS5hkufcdZ/mHtYCh53P2b+92WQq/DZcKLgsFRs=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
|
||||
@@ -28,7 +28,13 @@ type Application struct {
|
||||
Quiet bool `mapstructure:"quiet"`
|
||||
Log Logging `mapstructure:"log"`
|
||||
CliOptions CliOnlyOptions
|
||||
CheckForAppUpdate bool `mapstructure:"check-for-app-update"`
|
||||
CheckForAppUpdate bool `mapstructure:"check-for-app-update"`
|
||||
Plugins Plugins `mapstructure:"plugins"`
|
||||
}
|
||||
|
||||
type Plugins struct {
|
||||
Enabled bool `mapstructure:"enabled"`
|
||||
Directory string `mapstructure:"dir"`
|
||||
}
|
||||
|
||||
type Logging struct {
|
||||
|
||||
+7
-1
@@ -1,6 +1,8 @@
|
||||
package log
|
||||
|
||||
import "github.com/anchore/syft/syft/logger"
|
||||
import (
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
)
|
||||
|
||||
var Log logger.Logger = &nopLogger{}
|
||||
|
||||
@@ -8,6 +10,10 @@ func Errorf(format string, args ...interface{}) {
|
||||
Log.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func Error(args ...interface{}) {
|
||||
Log.Error(args...)
|
||||
}
|
||||
|
||||
func Infof(format string, args ...interface{}) {
|
||||
Log.Infof(format, args...)
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package log
|
||||
type nopLogger struct{}
|
||||
|
||||
func (l *nopLogger) Errorf(format string, args ...interface{}) {}
|
||||
func (l *nopLogger) Error(args ...interface{}) {}
|
||||
func (l *nopLogger) Infof(format string, args ...interface{}) {}
|
||||
func (l *nopLogger) Info(args ...interface{}) {}
|
||||
func (l *nopLogger) Debugf(format string, args ...interface{}) {}
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
// Source: https://github.com/hashicorp/go-hclog/blob/master/stdlog.go (MIT License)
|
||||
|
||||
// Provides a io.Writer to shim the data out of *log.Logger
|
||||
// and back into our Logger. This is basically the only way to
|
||||
// build upon *log.Logger.
|
||||
type HCLogStdlogAdapter struct {
|
||||
log hclog.Logger
|
||||
inferLevels bool
|
||||
forceLevel hclog.Level
|
||||
}
|
||||
|
||||
// Take the data, infer the levels if configured, and send it through
|
||||
// a regular Logger.
|
||||
func (s *HCLogStdlogAdapter) Write(data []byte) (int, error) {
|
||||
str := string(bytes.TrimRight(data, " \t\n"))
|
||||
|
||||
if s.forceLevel != hclog.NoLevel {
|
||||
// Use pickLevel to strip log levels included in the line since we are
|
||||
// forcing the level
|
||||
_, str := s.pickLevel(str)
|
||||
|
||||
// Log at the forced level
|
||||
s.dispatch(str, s.forceLevel)
|
||||
} else if s.inferLevels {
|
||||
level, str := s.pickLevel(str)
|
||||
s.dispatch(str, level)
|
||||
} else {
|
||||
s.log.Info(str)
|
||||
}
|
||||
|
||||
return len(data), nil
|
||||
}
|
||||
|
||||
func (s *HCLogStdlogAdapter) dispatch(str string, level hclog.Level) {
|
||||
switch level {
|
||||
case hclog.Trace:
|
||||
s.log.Trace(str)
|
||||
case hclog.Debug:
|
||||
s.log.Debug(str)
|
||||
case hclog.Info:
|
||||
s.log.Info(str)
|
||||
case hclog.Warn:
|
||||
s.log.Warn(str)
|
||||
case hclog.Error:
|
||||
s.log.Error(str)
|
||||
default:
|
||||
s.log.Info(str)
|
||||
}
|
||||
}
|
||||
|
||||
// Detect, based on conventions, what log level this is.
|
||||
func (s *HCLogStdlogAdapter) pickLevel(str string) (hclog.Level, string) {
|
||||
switch {
|
||||
case strings.HasPrefix(str, "[DEBUG]"):
|
||||
return hclog.Debug, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[TRACE]"):
|
||||
return hclog.Trace, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[INFO]"):
|
||||
return hclog.Info, strings.TrimSpace(str[6:])
|
||||
case strings.HasPrefix(str, "[WARN]"):
|
||||
return hclog.Warn, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[ERROR]"):
|
||||
return hclog.Error, strings.TrimSpace(str[7:])
|
||||
case strings.HasPrefix(str, "[ERR]"):
|
||||
return hclog.Error, strings.TrimSpace(str[5:])
|
||||
default:
|
||||
return hclog.Info, str
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ hclog.Logger = &LoggerHCLogAdapter{}
|
||||
|
||||
// LoggerHCLogAdapter is used to (partially) adapt a syft logger.Logger object to the hclog.Logger interface for syft plugins.
|
||||
// Note: this does not implement all functionality required by the hclog.Logger.
|
||||
type LoggerHCLogAdapter struct {
|
||||
Logger logger.Logger
|
||||
}
|
||||
|
||||
func NewLoggerHCLogAdapter(logger logger.Logger) *LoggerHCLogAdapter {
|
||||
return &LoggerHCLogAdapter{
|
||||
Logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Args are alternating key, val pairs
|
||||
// keys must be strings
|
||||
// vals can be any type, but display is implementation specific
|
||||
// Emit a message and key/value pairs at a provided log level
|
||||
func (l *LoggerHCLogAdapter) Log(level hclog.Level, msg string, args ...interface{}) {
|
||||
l.Logger.Info(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the TRACE level
|
||||
func (l *LoggerHCLogAdapter) Trace(msg string, args ...interface{}) {
|
||||
l.Logger.Debug(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the DEBUG level
|
||||
func (l *LoggerHCLogAdapter) Debug(msg string, args ...interface{}) {
|
||||
l.Logger.Debug(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the INFO level
|
||||
func (l *LoggerHCLogAdapter) Info(msg string, args ...interface{}) {
|
||||
l.Logger.Info(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the WARN level
|
||||
func (l *LoggerHCLogAdapter) Warn(msg string, args ...interface{}) {
|
||||
l.Logger.Error(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the ERROR level
|
||||
func (l *LoggerHCLogAdapter) Error(msg string, args ...interface{}) {
|
||||
l.Logger.Error(append([]interface{}{msg}, args...)...)
|
||||
}
|
||||
|
||||
// Indicate if TRACE logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsTrace() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicate if DEBUG logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsDebug() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicate if INFO logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsInfo() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicate if WARN logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsWarn() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// Indicate if ERROR logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LoggerHCLogAdapter) IsError() bool {
|
||||
// TODO: not implemented
|
||||
return true
|
||||
}
|
||||
|
||||
// ImpliedArgs returns With key/value pairs
|
||||
func (l *LoggerHCLogAdapter) ImpliedArgs() []interface{} {
|
||||
// TODO: not implemented
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates a sublogger that will always have the given key/value pairs
|
||||
func (l *LoggerHCLogAdapter) With(args ...interface{}) hclog.Logger {
|
||||
// TODO: not implemented
|
||||
return l
|
||||
}
|
||||
|
||||
// Returns the Name of the logger
|
||||
func (l *LoggerHCLogAdapter) Name() string {
|
||||
// TODO: not implemented
|
||||
return ""
|
||||
}
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// If the logger already has a name, the new value will be appended to the current
|
||||
// name. That way, a major subsystem can use this to decorate all it's own logs
|
||||
// without losing context.
|
||||
func (l *LoggerHCLogAdapter) Named(name string) hclog.Logger {
|
||||
// TODO: not implemented
|
||||
return l
|
||||
}
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// This sets the name of the logger to the value directly, unlike Named which honor
|
||||
// the current name as well.
|
||||
func (l *LoggerHCLogAdapter) ResetNamed(name string) hclog.Logger {
|
||||
// TODO: not implemented
|
||||
return l
|
||||
}
|
||||
|
||||
// Updates the level. This should affect all sub-loggers as well. If an
|
||||
// implementation cannot update the level on the fly, it should no-op.
|
||||
func (l *LoggerHCLogAdapter) SetLevel(level hclog.Level) {
|
||||
// TODO: not implemented
|
||||
}
|
||||
|
||||
// Return a value that conforms to the stdlib log.Logger interface
|
||||
func (l *LoggerHCLogAdapter) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
|
||||
return log.New(l.StandardWriter(opts), "", log.LstdFlags)
|
||||
}
|
||||
|
||||
// Return a value that conforms to io.Writer, which can be passed into log.SetOutput()
|
||||
func (l *LoggerHCLogAdapter) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer {
|
||||
return &HCLogStdlogAdapter{
|
||||
log: l,
|
||||
inferLevels: opts.InferLevels,
|
||||
forceLevel: opts.ForceLevel,
|
||||
}
|
||||
}
|
||||
+25
-12
@@ -6,10 +6,15 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
"github.com/sirupsen/logrus"
|
||||
prefixed "github.com/x-cray/logrus-prefixed-formatter"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ logger.Logger = &LogrusLogger{}
|
||||
var _ logger.Logger = &LogrusNestedLogger{}
|
||||
|
||||
type LogrusConfig struct {
|
||||
EnableConsole bool
|
||||
EnableFile bool
|
||||
@@ -76,42 +81,50 @@ func NewLogrusLogger(cfg LogrusConfig) *LogrusLogger {
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Debugf(format string, args ...interface{}) {
|
||||
l.Logger.Debugf(format, args...)
|
||||
func (l *LogrusLogger) Errorf(format string, args ...interface{}) {
|
||||
l.Logger.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Infof(format string, args ...interface{}) {
|
||||
l.Logger.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Debug(args ...interface{}) {
|
||||
l.Logger.Debug(args...)
|
||||
func (l *LogrusLogger) Debugf(format string, args ...interface{}) {
|
||||
l.Logger.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Error(args ...interface{}) {
|
||||
l.Logger.Error(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Info(args ...interface{}) {
|
||||
l.Logger.Info(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusLogger) Errorf(format string, args ...interface{}) {
|
||||
l.Logger.Errorf(format, args...)
|
||||
func (l *LogrusLogger) Debug(args ...interface{}) {
|
||||
l.Logger.Debug(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Debugf(format string, args ...interface{}) {
|
||||
l.Logger.Debugf(format, args...)
|
||||
func (l *LogrusNestedLogger) Errorf(format string, args ...interface{}) {
|
||||
l.Logger.Errorf(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Infof(format string, args ...interface{}) {
|
||||
l.Logger.Infof(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Debug(args ...interface{}) {
|
||||
l.Logger.Debug(args...)
|
||||
func (l *LogrusNestedLogger) Debugf(format string, args ...interface{}) {
|
||||
l.Logger.Debugf(format, args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Error(args ...interface{}) {
|
||||
l.Logger.Error(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Info(args ...interface{}) {
|
||||
l.Logger.Info(args...)
|
||||
}
|
||||
|
||||
func (l *LogrusNestedLogger) Errorf(format string, args ...interface{}) {
|
||||
l.Logger.Errorf(format, args...)
|
||||
func (l *LogrusNestedLogger) Debug(args ...interface{}) {
|
||||
l.Logger.Debug(args...)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,181 @@
|
||||
package logger
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ hclog.Logger = &LogrusHCLogAdapter{}
|
||||
|
||||
var levels = map[hclog.Level]logrus.Level{
|
||||
hclog.NoLevel: logrus.PanicLevel,
|
||||
hclog.Error: logrus.ErrorLevel,
|
||||
hclog.Warn: logrus.WarnLevel,
|
||||
hclog.Info: logrus.InfoLevel,
|
||||
hclog.Debug: logrus.DebugLevel,
|
||||
hclog.Trace: logrus.TraceLevel,
|
||||
}
|
||||
|
||||
// LogrusHCLogAdapter is used to adapt a logrus logger object to the hclog.Logger interface for syft plugins.
|
||||
type LogrusHCLogAdapter struct {
|
||||
logger *logrus.Logger
|
||||
entry *logrus.Entry
|
||||
}
|
||||
|
||||
func NewLogrusHCLogAdapter(logger *logrus.Logger, fields map[string]interface{}) *LogrusHCLogAdapter {
|
||||
if fields != nil {
|
||||
return &LogrusHCLogAdapter{
|
||||
logger: logger,
|
||||
entry: logger.WithFields(fields),
|
||||
}
|
||||
}
|
||||
return &LogrusHCLogAdapter{
|
||||
logger: logger,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *LogrusHCLogAdapter) log(level hclog.Level, msg string, args ...interface{}) {
|
||||
if l.entry != nil {
|
||||
l.entry.WithFields(makeArgFields(args...)).Log(levels[level], msg)
|
||||
return
|
||||
}
|
||||
l.logger.WithFields(makeArgFields(args...)).Log(levels[level], msg)
|
||||
}
|
||||
|
||||
// Args are alternating key, val pairs
|
||||
// keys must be strings
|
||||
// vals can be any type, but display is implementation specific
|
||||
// Emit a message and key/value pairs at a provided log level
|
||||
func (l *LogrusHCLogAdapter) Log(level hclog.Level, msg string, args ...interface{}) {
|
||||
l.log(level, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the TRACE level
|
||||
func (l *LogrusHCLogAdapter) Trace(msg string, args ...interface{}) {
|
||||
l.log(hclog.Trace, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the DEBUG level
|
||||
func (l *LogrusHCLogAdapter) Debug(msg string, args ...interface{}) {
|
||||
l.log(hclog.Debug, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the INFO level
|
||||
func (l *LogrusHCLogAdapter) Info(msg string, args ...interface{}) {
|
||||
l.log(hclog.Info, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the WARN level
|
||||
func (l *LogrusHCLogAdapter) Warn(msg string, args ...interface{}) {
|
||||
l.log(hclog.Warn, msg, args...)
|
||||
}
|
||||
|
||||
// Emit a message and key/value pairs at the ERROR level
|
||||
func (l *LogrusHCLogAdapter) Error(msg string, args ...interface{}) {
|
||||
l.log(hclog.Error, msg, args...)
|
||||
}
|
||||
|
||||
// Indicate if TRACE logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsTrace() bool {
|
||||
return l.logger.Level <= logrus.TraceLevel
|
||||
}
|
||||
|
||||
// Indicate if DEBUG logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsDebug() bool {
|
||||
return l.logger.Level <= logrus.DebugLevel
|
||||
}
|
||||
|
||||
// Indicate if INFO logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsInfo() bool {
|
||||
return l.logger.Level <= logrus.InfoLevel
|
||||
}
|
||||
|
||||
// Indicate if WARN logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsWarn() bool {
|
||||
return l.logger.Level <= logrus.WarnLevel
|
||||
}
|
||||
|
||||
// Indicate if ERROR logs would be emitted. This and the other Is* guards
|
||||
// are used to elide expensive logging code based on the current level.
|
||||
func (l *LogrusHCLogAdapter) IsError() bool {
|
||||
return l.logger.Level <= logrus.ErrorLevel
|
||||
}
|
||||
|
||||
// ImpliedArgs returns With key/value pairs
|
||||
func (l *LogrusHCLogAdapter) ImpliedArgs() []interface{} {
|
||||
// TODO: not implemented
|
||||
return nil
|
||||
}
|
||||
|
||||
// Creates a sublogger that will always have the given key/value pairs
|
||||
func (l *LogrusHCLogAdapter) With(args ...interface{}) hclog.Logger {
|
||||
l.entry = l.logger.WithFields(makeArgFields(args...))
|
||||
return l
|
||||
}
|
||||
|
||||
// Returns the Name of the logger
|
||||
func (l *LogrusHCLogAdapter) Name() string {
|
||||
// TODO: not implemented
|
||||
return ""
|
||||
}
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// If the logger already has a name, the new value will be appended to the current
|
||||
// name. That way, a major subsystem can use this to decorate all it's own logs
|
||||
// without losing context.
|
||||
func (l *LogrusHCLogAdapter) Named(name string) hclog.Logger {
|
||||
return NewLogrusHCLogAdapter(l.logger, logrus.Fields{"name": name})
|
||||
}
|
||||
|
||||
// Create a logger that will prepend the name string on the front of all messages.
|
||||
// This sets the name of the logger to the value directly, unlike Named which honor
|
||||
// the current name as well.
|
||||
func (l *LogrusHCLogAdapter) ResetNamed(name string) hclog.Logger {
|
||||
return NewLogrusHCLogAdapter(l.logger, logrus.Fields{"name": name})
|
||||
}
|
||||
|
||||
// Updates the level. This should affect all sub-loggers as well. If an
|
||||
// implementation cannot update the level on the fly, it should no-op.
|
||||
func (l *LogrusHCLogAdapter) SetLevel(level hclog.Level) {
|
||||
l.logger.SetLevel(levels[level])
|
||||
}
|
||||
|
||||
// Return a value that conforms to the stdlib log.Logger interface
|
||||
func (l *LogrusHCLogAdapter) StandardLogger(opts *hclog.StandardLoggerOptions) *log.Logger {
|
||||
return log.New(l.StandardWriter(opts), "", log.LstdFlags)
|
||||
}
|
||||
|
||||
// Return a value that conforms to io.Writer, which can be passed into log.SetOutput()
|
||||
func (l *LogrusHCLogAdapter) StandardWriter(opts *hclog.StandardLoggerOptions) io.Writer {
|
||||
return &HCLogStdlogAdapter{
|
||||
log: l,
|
||||
inferLevels: opts.InferLevels,
|
||||
forceLevel: opts.ForceLevel,
|
||||
}
|
||||
}
|
||||
|
||||
func makeArgFields(args ...interface{}) logrus.Fields {
|
||||
if len(args)%2 != 0 {
|
||||
panic(fmt.Errorf("odd number of logger key-value pairs (%d): %+v", len(args), args))
|
||||
}
|
||||
|
||||
var key string
|
||||
var fields = make(logrus.Fields)
|
||||
for i, arg := range args {
|
||||
if i%2 == 0 {
|
||||
key = arg.(string)
|
||||
} else {
|
||||
fields[key] = arg
|
||||
}
|
||||
}
|
||||
return fields
|
||||
}
|
||||
@@ -4,6 +4,8 @@ Package apkdb provides a concrete Cataloger implementation for Alpine DB files.
|
||||
package apkdb
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -27,16 +29,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (a *Cataloger) Name() string {
|
||||
func (c *Cataloger) Name() string {
|
||||
return "apkdb-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Alpine DB files from the user content source.
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Alpine DB files discovered.
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ Package bundler provides a concrete Cataloger implementation for Ruby Gemfile.lo
|
||||
package bundler
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -27,16 +29,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (a *Cataloger) Name() string {
|
||||
func (c *Cataloger) Name() string {
|
||||
return "bundler-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Gemfile.lock files from the user content source.
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Gemfile.lock files discovered.
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
}
|
||||
|
||||
+55
-52
@@ -12,6 +12,61 @@ import (
|
||||
"github.com/wagoodman/go-progress"
|
||||
)
|
||||
|
||||
// Catalog a given scope (container image or filesystem) with the given catalogers, returning all discovered packages.
|
||||
// In order to efficiently retrieve contents from a underlying container image the content fetch requests are
|
||||
// done in bulk. Specifically, all files of interest are collected from each catalogers and accumulated into a single
|
||||
// request.
|
||||
func Catalog(resolver scope.Resolver, catalogers ...Cataloger) (*pkg.Catalog, error) {
|
||||
catalog := pkg.NewCatalog()
|
||||
fileSelection := make([]file.Reference, 0)
|
||||
|
||||
filesProcessed, packagesDiscovered := newMonitor()
|
||||
|
||||
// ask catalogers for files to extract from the image tar
|
||||
for _, a := range catalogers {
|
||||
catalogerSelection := a.SelectFiles(resolver)
|
||||
fileSelection = append(fileSelection, catalogerSelection...)
|
||||
log.Debugf("cataloger '%s' selected '%d' files", a.Name(), len(catalogerSelection))
|
||||
filesProcessed.N += int64(len(fileSelection))
|
||||
}
|
||||
|
||||
// fetch contents for requested selection by catalogers
|
||||
// TODO: we should consider refactoring to return a set of io.Readers instead of the full contents themselves (allow for optional buffering).
|
||||
contents, err := resolver.MultipleFileContentsByRef(fileSelection...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// perform analysis, accumulating errors for each failed analysis
|
||||
var errs error
|
||||
for _, c := range catalogers {
|
||||
// TODO: check for multiple rounds of analyses by Iterate error
|
||||
packages, err := c.Catalog(contents)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("cataloger '%s' discovered '%d' packages", c.Name(), len(packages))
|
||||
packagesDiscovered.N += int64(len(packages))
|
||||
|
||||
catalogerName := c.Name()
|
||||
for _, p := range packages {
|
||||
p.FoundBy = catalogerName
|
||||
catalog.Add(p)
|
||||
}
|
||||
}
|
||||
|
||||
if errs != nil {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
filesProcessed.SetCompleted()
|
||||
packagesDiscovered.SetCompleted()
|
||||
|
||||
return catalog, nil
|
||||
}
|
||||
|
||||
// Monitor provides progress-related data for observing the progress of a Catalog() call (published on the event bus).
|
||||
type Monitor struct {
|
||||
FilesProcessed progress.Monitorable // the number of files selected and contents analyzed from all registered catalogers
|
||||
@@ -32,55 +87,3 @@ func newMonitor() (*progress.Manual, *progress.Manual) {
|
||||
})
|
||||
return &filesProcessed, &packagesDiscovered
|
||||
}
|
||||
|
||||
// Catalog a given scope (container image or filesystem) with the given catalogers, returning all discovered packages.
|
||||
// In order to efficiently retrieve contents from a underlying container image the content fetch requests are
|
||||
// done in bulk. Specifically, all files of interest are collected from each catalogers and accumulated into a single
|
||||
// request.
|
||||
func Catalog(resolver scope.Resolver, catalogers ...Cataloger) (*pkg.Catalog, error) {
|
||||
catalog := pkg.NewCatalog()
|
||||
fileSelection := make([]file.Reference, 0)
|
||||
|
||||
filesProcessed, packagesDiscovered := newMonitor()
|
||||
|
||||
// ask catalogers for files to extract from the image tar
|
||||
for _, a := range catalogers {
|
||||
fileSelection = append(fileSelection, a.SelectFiles(resolver)...)
|
||||
log.Debugf("cataloger '%s' selected '%d' files", a.Name(), len(fileSelection))
|
||||
filesProcessed.N += int64(len(fileSelection))
|
||||
}
|
||||
|
||||
// fetch contents for requested selection by catalogers
|
||||
// TODO: we should consider refactoring to return a set of io.Readers instead of the full contents themselves (allow for optional buffering).
|
||||
contents, err := resolver.MultipleFileContentsByRef(fileSelection...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// perform analysis, accumulating errors for each failed analysis
|
||||
var errs error
|
||||
for _, a := range catalogers {
|
||||
// TODO: check for multiple rounds of analyses by Iterate error
|
||||
packages, err := a.Catalog(contents)
|
||||
if err != nil {
|
||||
errs = multierror.Append(errs, err)
|
||||
continue
|
||||
}
|
||||
|
||||
log.Debugf("cataloger '%s' discovered '%d' packages", a.Name(), len(packages))
|
||||
packagesDiscovered.N += int64(len(packages))
|
||||
|
||||
for _, p := range packages {
|
||||
catalog.Add(p)
|
||||
}
|
||||
}
|
||||
|
||||
if errs != nil {
|
||||
return nil, errs
|
||||
}
|
||||
|
||||
filesProcessed.SetCompleted()
|
||||
packagesDiscovered.SetCompleted()
|
||||
|
||||
return catalog, nil
|
||||
}
|
||||
|
||||
@@ -6,10 +6,13 @@ catalogers defined in child packages as well as the interface definition to impl
|
||||
package cataloger
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/syft/syft/cataloger/dpkg"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/apkdb"
|
||||
"github.com/anchore/syft/syft/cataloger/bundler"
|
||||
"github.com/anchore/syft/syft/cataloger/dpkg"
|
||||
"github.com/anchore/syft/syft/cataloger/golang"
|
||||
"github.com/anchore/syft/syft/cataloger/java"
|
||||
"github.com/anchore/syft/syft/cataloger/javascript"
|
||||
@@ -28,13 +31,12 @@ type Cataloger interface {
|
||||
// SelectFiles discovers and returns specific files that the cataloger would like to inspect the contents of.
|
||||
SelectFiles(scope.FileResolver) []file.Reference
|
||||
// Catalog is given the file contents and should return any discovered Packages after analyzing the contents.
|
||||
Catalog(map[file.Reference]string) ([]pkg.Package, error)
|
||||
Catalog(map[file.Reference]io.Reader) ([]pkg.Package, error)
|
||||
// TODO: add "IterationNeeded" error to indicate to the driver to continue with another Select/Catalog pass
|
||||
// TODO: we should consider refactoring to return a set of io.Readers instead of the full contents themselves (allow for optional buffering).
|
||||
}
|
||||
|
||||
// All returns a slice of all locally defined catalogers (defined in child packages).
|
||||
func All() []Cataloger {
|
||||
func BuiltIn() []Cataloger {
|
||||
return []Cataloger{
|
||||
dpkg.New(),
|
||||
bundler.New(),
|
||||
|
||||
@@ -4,7 +4,7 @@ Package common provides generic utilities used by multiple catalogers.
|
||||
package common
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
@@ -73,7 +73,7 @@ func (a *GenericCataloger) SelectFiles(resolver scope.FileResolver) []file.Refer
|
||||
}
|
||||
|
||||
// Catalog takes a set of file contents and uses any configured parser functions to resolve and return discovered packages
|
||||
func (a *GenericCataloger) Catalog(contents map[file.Reference]string, upstreamMatcher string) ([]pkg.Package, error) {
|
||||
func (a *GenericCataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
defer a.clear()
|
||||
|
||||
packages := make([]pkg.Package, 0)
|
||||
@@ -81,19 +81,18 @@ func (a *GenericCataloger) Catalog(contents map[file.Reference]string, upstreamM
|
||||
for reference, parser := range a.parsers {
|
||||
content, ok := contents[reference]
|
||||
if !ok {
|
||||
log.Errorf("cataloger '%s' missing file content: %+v", upstreamMatcher, reference)
|
||||
log.Errorf("cataloger missing file content: %+v", reference)
|
||||
continue
|
||||
}
|
||||
|
||||
entries, err := parser(string(reference.Path), strings.NewReader(content))
|
||||
entries, err := parser(string(reference.Path), content)
|
||||
if err != nil {
|
||||
// TODO: should we fail? or only log?
|
||||
log.Errorf("cataloger '%s' failed to parse entries (reference=%+v): %w", upstreamMatcher, reference, err)
|
||||
log.Errorf("cataloger failed to parse entries (reference=%+v): %w", reference, err)
|
||||
continue
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
entry.FoundBy = upstreamMatcher
|
||||
entry.Source = []file.Reference{reference}
|
||||
|
||||
packages = append(packages, entry)
|
||||
|
||||
@@ -79,17 +79,15 @@ func TestGenericCataloger(t *testing.T) {
|
||||
selectionByPath[string(s.Path)] = s
|
||||
}
|
||||
|
||||
upstream := "some-other-cataloger"
|
||||
expectedPkgs := make(map[file.Reference]pkg.Package)
|
||||
for path, ref := range selectionByPath {
|
||||
expectedPkgs[ref] = pkg.Package{
|
||||
FoundBy: upstream,
|
||||
Source: []file.Reference{ref},
|
||||
Name: fmt.Sprintf("%s file contents!", path),
|
||||
Source: []file.Reference{ref},
|
||||
Name: fmt.Sprintf("%s file contents!", path),
|
||||
}
|
||||
}
|
||||
|
||||
actualPkgs, err := cataloger.Catalog(resolver.contents, upstream)
|
||||
actualPkgs, err := cataloger.Catalog(resolver.contents)
|
||||
if err != nil {
|
||||
t.Fatalf("cataloger catalog action failed: %+v", err)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ Package dpkg provides a concrete Cataloger implementation for Debian package DB
|
||||
package dpkg
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -27,16 +29,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (a *Cataloger) Name() string {
|
||||
func (c *Cataloger) Name() string {
|
||||
return "dpkg-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered DPKG status files from the user content source.
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all DPKG status files discovered.
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ Package golang provides a concrete Cataloger implementation for go.mod files.
|
||||
package golang
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -27,16 +29,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (a *Cataloger) Name() string {
|
||||
func (c *Cataloger) Name() string {
|
||||
return "go-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered go.mod files from the user content source.
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all go.mod files discovered.
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ Package java provides a concrete Cataloger implementation for Java archives (jar
|
||||
package java
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -28,16 +30,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (a *Cataloger) Name() string {
|
||||
func (c *Cataloger) Name() string {
|
||||
return "java-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Java archive files from the user content source.
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Java archive files discovered.
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ Package javascript provides a concrete Cataloger implementation for JavaScript e
|
||||
package javascript
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -28,16 +30,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (a *Cataloger) Name() string {
|
||||
func (c *Cataloger) Name() string {
|
||||
return "javascript-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Javascript ecosystem files from the user content source.
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Javascript ecosystem files discovered.
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ Package python provides a concrete Cataloger implementation for Python ecosystem
|
||||
package python
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -31,16 +33,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (a *Cataloger) Name() string {
|
||||
func (c *Cataloger) Name() string {
|
||||
return "python-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered Python ecosystem files from the user content source.
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all Python ecosystem files discovered.
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ Package rpmdb provides a concrete Cataloger implementation for RPM "Package" DB
|
||||
package rpmdb
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/common"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
@@ -27,16 +29,16 @@ func New() *Cataloger {
|
||||
}
|
||||
|
||||
// Name returns a string that uniquely describes this cataloger.
|
||||
func (a *Cataloger) Name() string {
|
||||
func (c *Cataloger) Name() string {
|
||||
return "rpmdb-cataloger"
|
||||
}
|
||||
|
||||
// SelectFiles returns a set of discovered RPM DB files from the user content source.
|
||||
func (a *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return a.cataloger.SelectFiles(resolver)
|
||||
func (c *Cataloger) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
return c.cataloger.SelectFiles(resolver)
|
||||
}
|
||||
|
||||
// Catalog returns the Packages indexed from all RPM DB files discovered.
|
||||
func (a *Cataloger) Catalog(contents map[file.Reference]string) ([]pkg.Package, error) {
|
||||
return a.cataloger.Catalog(contents, a.Name())
|
||||
func (c *Cataloger) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
return c.cataloger.Catalog(contents)
|
||||
}
|
||||
|
||||
@@ -10,13 +10,35 @@ import (
|
||||
"github.com/anchore/syft/syft/distro"
|
||||
"github.com/anchore/syft/syft/logger"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/plugin"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/wagoodman/go-partybus"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
PluginDirectory string
|
||||
}
|
||||
|
||||
type Client struct {
|
||||
config Config
|
||||
plugins *plugin.Repository
|
||||
}
|
||||
|
||||
func NewClient(config Config) (Client, error) {
|
||||
plugins, err := plugin.NewRepositoryFromDirectory(config.PluginDirectory)
|
||||
if err != nil {
|
||||
return Client{}, err
|
||||
}
|
||||
|
||||
return Client{
|
||||
config: config,
|
||||
plugins: plugins,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Catalog the given image from a particular perspective (e.g. squashed scope, all-layers scope). Returns the discovered
|
||||
// set of packages, the identified Linux distribution, and the scope object used to wrap the data source.
|
||||
func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scope, *distro.Distro, error) {
|
||||
func (c *Client) Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scope, *distro.Distro, error) {
|
||||
log.Info("cataloging image")
|
||||
s, cleanup, err := scope.NewScope(userInput, scoptOpt)
|
||||
defer cleanup()
|
||||
@@ -24,9 +46,9 @@ func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scop
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
|
||||
d := IdentifyDistro(s)
|
||||
d := c.IdentifyDistro(s)
|
||||
|
||||
catalog, err := CatalogFromScope(s)
|
||||
catalog, err := c.CatalogFromScope(s)
|
||||
if err != nil {
|
||||
return nil, nil, nil, err
|
||||
}
|
||||
@@ -36,7 +58,7 @@ func Catalog(userInput string, scoptOpt scope.Option) (*pkg.Catalog, *scope.Scop
|
||||
|
||||
// IdentifyDistro attempts to discover what the underlying Linux distribution may be from the available flat files
|
||||
// provided by the given scope object. If results are inconclusive a "UnknownDistro" Type is returned.
|
||||
func IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
func (c *Client) IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
d := distro.Identify(s.Resolver)
|
||||
if d.Type != distro.UnknownDistroType {
|
||||
log.Infof("identified distro: %s", d.String())
|
||||
@@ -47,9 +69,15 @@ func IdentifyDistro(s scope.Scope) distro.Distro {
|
||||
}
|
||||
|
||||
// Catalog the given scope, which may represent a container image or filesystem. Returns the discovered set of packages.
|
||||
func CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {
|
||||
func (c *Client) CatalogFromScope(s scope.Scope) (*pkg.Catalog, error) {
|
||||
log.Info("building the catalog")
|
||||
return cataloger.Catalog(s.Resolver, cataloger.All()...)
|
||||
pluginCatalogers, deactivatePluginsFn, err := c.plugins.ActivateCatalogers()
|
||||
defer deactivatePluginsFn()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return cataloger.Catalog(s.Resolver, append(pluginCatalogers, cataloger.BuiltIn()...)...)
|
||||
}
|
||||
|
||||
// SetLogger sets the logger object used for all syft logging calls.
|
||||
+13
-2
@@ -1,6 +1,7 @@
|
||||
package distro
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// returns a distro or nil
|
||||
// TODO: refactor to io.Reader
|
||||
type parseFunc func(string) *Distro
|
||||
|
||||
type parseEntry struct {
|
||||
@@ -17,6 +19,7 @@ type parseEntry struct {
|
||||
fn parseFunc
|
||||
}
|
||||
|
||||
// nolint: funlen
|
||||
// Identify parses distro-specific files to determine distro metadata like version and release.
|
||||
func Identify(resolver scope.Resolver) Distro {
|
||||
distro := NewUnknownDistro()
|
||||
@@ -52,8 +55,8 @@ identifyLoop:
|
||||
}
|
||||
|
||||
for _, ref := range refs {
|
||||
contents, err := resolver.MultipleFileContentsByRef(ref)
|
||||
content, ok := contents[ref]
|
||||
contentReaders, err := resolver.MultipleFileContentsByRef(ref)
|
||||
contentReader, ok := contentReaders[ref]
|
||||
|
||||
if !ok {
|
||||
log.Infof("no content present for ref: %s", ref)
|
||||
@@ -65,6 +68,14 @@ identifyLoop:
|
||||
continue
|
||||
}
|
||||
|
||||
bytes, err := ioutil.ReadAll(contentReader)
|
||||
if err != nil {
|
||||
log.Debugf("unable to read contents from %s: %s", entry.path, err)
|
||||
continue
|
||||
}
|
||||
|
||||
content := string(bytes)
|
||||
|
||||
if content == "" {
|
||||
log.Debugf("no contents in file, skipping: %s", entry.path)
|
||||
continue
|
||||
|
||||
@@ -5,6 +5,7 @@ package logger
|
||||
|
||||
type Logger interface {
|
||||
Errorf(format string, args ...interface{})
|
||||
Error(args ...interface{})
|
||||
Infof(format string, args ...interface{})
|
||||
Info(args ...interface{})
|
||||
Debugf(format string, args ...interface{})
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/syft/cataloger"
|
||||
syftPluginGrpc "github.com/anchore/syft/syft/plugin/grpc"
|
||||
"github.com/anchore/syft/syft/plugin/proto"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// integrity check
|
||||
var _ plugin.GRPCPlugin = &CatalogerPlugin{}
|
||||
|
||||
// CatalogerPlugin is the implementation of plugin.Plugin that is served/consumed.
|
||||
type CatalogerPlugin struct {
|
||||
plugin.NetRPCUnsupportedPlugin
|
||||
Impl cataloger.Cataloger
|
||||
}
|
||||
|
||||
func (p *CatalogerPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error {
|
||||
proto.RegisterCatalogerServer(s, syftPluginGrpc.NewCatalogServer(p.Impl, broker))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *CatalogerPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error) {
|
||||
return syftPluginGrpc.NewCatalogerClient(proto.NewCatalogerClient(c), broker), nil
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package plugin
|
||||
|
||||
type Config struct {
|
||||
Name string
|
||||
Type Type
|
||||
Command string
|
||||
Args []string
|
||||
Env []string
|
||||
Sha256 []byte
|
||||
}
|
||||
@@ -0,0 +1,117 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/anchore/syft/syft/cataloger"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/plugin/proto"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var _ cataloger.Cataloger = &CatalogerClient{}
|
||||
|
||||
type CatalogerClient struct {
|
||||
broker *plugin.GRPCBroker
|
||||
client proto.CatalogerClient
|
||||
}
|
||||
|
||||
func NewCatalogerClient(client proto.CatalogerClient, broker *plugin.GRPCBroker) *CatalogerClient {
|
||||
return &CatalogerClient{
|
||||
broker: broker,
|
||||
client: client,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *CatalogerClient) Name() string {
|
||||
resp, err := c.client.Name(context.Background(), &proto.Empty{})
|
||||
if err != nil {
|
||||
return fmt.Sprintf("error (%s)", err.Error())
|
||||
}
|
||||
|
||||
return resp.Name
|
||||
}
|
||||
|
||||
func (c *CatalogerClient) SelectFiles(resolver scope.FileResolver) []file.Reference {
|
||||
fileResolverServer := &FileResolverServer{Impl: resolver}
|
||||
|
||||
var s *grpc.Server
|
||||
serverFunc := func(opts []grpc.ServerOption) *grpc.Server {
|
||||
s = grpc.NewServer(opts...)
|
||||
proto.RegisterFileResolverServer(s, fileResolverServer)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
brokerID := c.broker.NextId()
|
||||
go c.broker.AcceptAndServe(brokerID, serverFunc)
|
||||
|
||||
resp, err := c.client.SelectFiles(context.Background(), &proto.SelectFilesRequest{
|
||||
FileResolverBrokerId: brokerID,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
// TODO: nope
|
||||
panic(err)
|
||||
}
|
||||
|
||||
s.Stop()
|
||||
|
||||
var result []file.Reference
|
||||
for _, f := range resp.Files {
|
||||
result = append(result, file.NewFileReferenceWithID(file.Path(f.Path), uint64(f.Id)))
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func (c *CatalogerClient) Catalog(contents map[file.Reference]io.Reader) ([]pkg.Package, error) {
|
||||
var fileRefContents []*proto.FileReferenceContents
|
||||
for ref, reader := range contents {
|
||||
readerContents, err := ioutil.ReadAll(reader)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not read %+v contents: %+v", ref, err)
|
||||
}
|
||||
fileRefContents = append(fileRefContents, &proto.FileReferenceContents{
|
||||
Id: int64(ref.ID()),
|
||||
Path: string(ref.Path),
|
||||
Contents: string(readerContents),
|
||||
})
|
||||
}
|
||||
resp, err := c.client.Catalog(context.Background(), &proto.CatalogRequest{
|
||||
Contents: fileRefContents,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []pkg.Package
|
||||
for _, p := range resp.Package {
|
||||
if p != nil {
|
||||
var sources []file.Reference
|
||||
for _, s := range p.Source {
|
||||
sources = append(sources, file.NewFileReferenceWithID(file.Path(s.Path), uint64(s.Id)))
|
||||
}
|
||||
// TODO: this is potentially brittle
|
||||
result = append(result, pkg.Package{
|
||||
Name: p.Name,
|
||||
Version: p.Version,
|
||||
FoundBy: p.FoundBy,
|
||||
Source: sources,
|
||||
Licenses: p.Licenses,
|
||||
Language: pkg.Language(p.Language),
|
||||
Type: pkg.Type(p.Type),
|
||||
Metadata: p.Metadata,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger"
|
||||
"github.com/anchore/syft/syft/plugin/proto"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
type CatalogerServer struct {
|
||||
Impl cataloger.Cataloger
|
||||
broker *plugin.GRPCBroker
|
||||
}
|
||||
|
||||
func NewCatalogServer(impl cataloger.Cataloger, broker *plugin.GRPCBroker) *CatalogerServer {
|
||||
return &CatalogerServer{
|
||||
Impl: impl,
|
||||
broker: broker,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *CatalogerServer) Name(ctx context.Context, req *proto.Empty) (*proto.NameResponse, error) {
|
||||
name := s.Impl.Name()
|
||||
return &proto.NameResponse{
|
||||
Name: name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *CatalogerServer) SelectFiles(ctx context.Context, req *proto.SelectFilesRequest) (*proto.SelectFilesResponse, error) {
|
||||
conn, err := s.broker.Dial(req.FileResolverBrokerId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
fileResolverClient := &FileResolverClient{proto.NewFileResolverClient(conn)}
|
||||
|
||||
fileRefs := s.Impl.SelectFiles(fileResolverClient)
|
||||
|
||||
var refs []*proto.FileReference
|
||||
for _, ref := range fileRefs {
|
||||
refs = append(refs, &proto.FileReference{
|
||||
Id: int64(ref.ID()),
|
||||
Path: string(ref.Path),
|
||||
})
|
||||
}
|
||||
|
||||
return &proto.SelectFilesResponse{
|
||||
Files: refs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *CatalogerServer) Catalog(ctx context.Context, req *proto.CatalogRequest) (*proto.CatalogResponse, error) {
|
||||
contents := make(map[file.Reference]io.Reader)
|
||||
for _, f := range req.Contents {
|
||||
contents[file.NewFileReferenceWithID(file.Path(f.Path), uint64(f.Id))] = strings.NewReader(f.Contents)
|
||||
}
|
||||
packages, err := s.Impl.Catalog(contents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var results []*proto.Package
|
||||
for _, p := range packages {
|
||||
var sources []*proto.FileReference
|
||||
for _, s := range p.Source {
|
||||
sources = append(sources, &proto.FileReference{
|
||||
Id: int64(s.ID()),
|
||||
Path: string(s.Path),
|
||||
})
|
||||
}
|
||||
|
||||
var metadata map[string]string
|
||||
if v, ok := p.Metadata.(map[string]string); ok {
|
||||
metadata = v
|
||||
}
|
||||
|
||||
// TODO: this is potentially brittle
|
||||
results = append(results, &proto.Package{
|
||||
Name: p.Name,
|
||||
Version: p.Version,
|
||||
FoundBy: p.FoundBy,
|
||||
Source: sources,
|
||||
Licenses: p.Licenses,
|
||||
Language: uint64(p.Language),
|
||||
Type: string(p.Type),
|
||||
// TODO: metadata needs to be more thoroughly thought through
|
||||
Metadata: metadata,
|
||||
})
|
||||
}
|
||||
|
||||
return &proto.CatalogResponse{
|
||||
Package: results,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/plugin/proto"
|
||||
)
|
||||
|
||||
type FileResolverClient struct{ client proto.FileResolverClient }
|
||||
|
||||
func (m *FileResolverClient) FilesByPath(paths ...file.Path) ([]file.Reference, error) {
|
||||
var pathStrs []string
|
||||
for _, p := range paths {
|
||||
pathStrs = append(pathStrs, string(p))
|
||||
}
|
||||
resp, err := m.client.FilesByPath(context.Background(), &proto.FileResolverRequest{
|
||||
Paths: pathStrs,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result []file.Reference
|
||||
for _, ref := range resp.Files {
|
||||
result = append(result, file.NewFileReferenceWithID(file.Path(ref.Path), uint64(ref.Id)))
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
func (m *FileResolverClient) FilesByGlob(patterns ...string) ([]file.Reference, error) {
|
||||
resp, err := m.client.FilesByGlob(context.Background(), &proto.FileResolverRequest{
|
||||
Paths: patterns,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
log.Debugf("FilesByGlob Response: %+v", resp)
|
||||
|
||||
var result []file.Reference
|
||||
for _, ref := range resp.Files {
|
||||
result = append(result, file.NewFileReferenceWithID(file.Path(ref.Path), uint64(ref.Id)))
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/plugin/proto"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
)
|
||||
|
||||
type FileResolverServer struct {
|
||||
Impl scope.FileResolver
|
||||
}
|
||||
|
||||
func (m *FileResolverServer) FilesByPath(ctx context.Context, req *proto.FileResolverRequest) (resp *proto.FileResolverResponse, err error) {
|
||||
var paths []file.Path
|
||||
for _, p := range req.Paths {
|
||||
paths = append(paths, file.Path(p))
|
||||
}
|
||||
r, err := m.Impl.FilesByPath(paths...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var refs []*proto.FileReference
|
||||
for _, ref := range r {
|
||||
refs = append(refs, &proto.FileReference{
|
||||
Id: int64(ref.ID()),
|
||||
Path: string(ref.Path),
|
||||
})
|
||||
}
|
||||
|
||||
return &proto.FileResolverResponse{
|
||||
Files: refs,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *FileResolverServer) FilesByGlob(ctx context.Context, req *proto.FileResolverRequest) (resp *proto.FileResolverResponse, err error) {
|
||||
r, err := m.Impl.FilesByGlob(req.Paths...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var refs []*proto.FileReference
|
||||
for _, ref := range r {
|
||||
refs = append(refs, &proto.FileReference{
|
||||
Id: int64(ref.ID()),
|
||||
Path: string(ref.Path),
|
||||
})
|
||||
}
|
||||
|
||||
return &proto.FileResolverResponse{
|
||||
Files: refs,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/internal/logger"
|
||||
"github.com/hashicorp/go-hclog"
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
var versionedPlugins = map[int]plugin.PluginSet{
|
||||
1: {
|
||||
TypeCataloger.String(): &CatalogerPlugin{},
|
||||
},
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
Config Config
|
||||
clientConfig plugin.ClientConfig
|
||||
client *plugin.Client
|
||||
}
|
||||
|
||||
// TODO: type should be in the name like with terraform "terraform-<TYPE>-<NAME>"
|
||||
|
||||
func NewPlugin(config Config) Plugin {
|
||||
//cmd := exec.Command("sh", "-c", config.Command) //, config.Args...)
|
||||
cmd := exec.Command(config.Command)
|
||||
cmd.Env = append(cmd.Env, config.Env...)
|
||||
|
||||
var secureConfig *plugin.SecureConfig
|
||||
if len(config.Sha256) > 0 {
|
||||
secureConfig = &plugin.SecureConfig{
|
||||
Checksum: config.Sha256,
|
||||
Hash: sha256.New(),
|
||||
}
|
||||
}
|
||||
|
||||
var pluginLogger hclog.Logger
|
||||
if logrusLogger, ok := log.Log.(*logger.LogrusLogger); ok {
|
||||
pluginLogger = logger.NewLogrusHCLogAdapter(logrusLogger.Logger, map[string]interface{}{"plugin": config.Name})
|
||||
} else {
|
||||
// TODO: this does not fully map features, thus logging will be awkward
|
||||
// TODO: find a better way to map loggers (expand our interface?)
|
||||
pluginLogger = logger.NewLoggerHCLogAdapter(log.Log)
|
||||
}
|
||||
|
||||
clientConfig := plugin.ClientConfig{
|
||||
HandshakeConfig: config.Type.HandshakeConfig(),
|
||||
VersionedPlugins: versionedPlugins,
|
||||
SecureConfig: secureConfig,
|
||||
Cmd: cmd,
|
||||
Logger: pluginLogger,
|
||||
AllowedProtocols: []plugin.Protocol{
|
||||
plugin.ProtocolGRPC,
|
||||
},
|
||||
}
|
||||
|
||||
return Plugin{
|
||||
Config: config,
|
||||
clientConfig: clientConfig,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Plugin) Start() (interface{}, error) {
|
||||
if p.client != nil {
|
||||
return nil, fmt.Errorf("plugin already started")
|
||||
}
|
||||
|
||||
// start the plugin in a sub process
|
||||
p.client = plugin.NewClient(&p.clientConfig)
|
||||
|
||||
// connect to the sub process via RPC
|
||||
rpcClient, err := p.client.Client()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// fetch the plugin object meeting the requested interface
|
||||
raw, err := rpcClient.Dispense(p.Config.Type.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (p *Plugin) Stop() error {
|
||||
if p.client == nil {
|
||||
return fmt.Errorf("plugin has not been started")
|
||||
}
|
||||
p.client.Kill()
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,841 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// source: cataloger.proto
|
||||
|
||||
package proto
|
||||
|
||||
import (
|
||||
context "context"
|
||||
fmt "fmt"
|
||||
proto "github.com/golang/protobuf/proto"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.ProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
type FileReference struct {
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *FileReference) Reset() { *m = FileReference{} }
|
||||
func (m *FileReference) String() string { return proto.CompactTextString(m) }
|
||||
func (*FileReference) ProtoMessage() {}
|
||||
func (*FileReference) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{0}
|
||||
}
|
||||
|
||||
func (m *FileReference) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_FileReference.Unmarshal(m, b)
|
||||
}
|
||||
func (m *FileReference) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_FileReference.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *FileReference) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_FileReference.Merge(m, src)
|
||||
}
|
||||
func (m *FileReference) XXX_Size() int {
|
||||
return xxx_messageInfo_FileReference.Size(m)
|
||||
}
|
||||
func (m *FileReference) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_FileReference.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_FileReference proto.InternalMessageInfo
|
||||
|
||||
func (m *FileReference) GetId() int64 {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *FileReference) GetPath() string {
|
||||
if m != nil {
|
||||
return m.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type FileReferenceContents struct {
|
||||
Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
Path string `protobuf:"bytes,2,opt,name=path,proto3" json:"path,omitempty"`
|
||||
Contents string `protobuf:"bytes,3,opt,name=contents,proto3" json:"contents,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *FileReferenceContents) Reset() { *m = FileReferenceContents{} }
|
||||
func (m *FileReferenceContents) String() string { return proto.CompactTextString(m) }
|
||||
func (*FileReferenceContents) ProtoMessage() {}
|
||||
func (*FileReferenceContents) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{1}
|
||||
}
|
||||
|
||||
func (m *FileReferenceContents) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_FileReferenceContents.Unmarshal(m, b)
|
||||
}
|
||||
func (m *FileReferenceContents) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_FileReferenceContents.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *FileReferenceContents) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_FileReferenceContents.Merge(m, src)
|
||||
}
|
||||
func (m *FileReferenceContents) XXX_Size() int {
|
||||
return xxx_messageInfo_FileReferenceContents.Size(m)
|
||||
}
|
||||
func (m *FileReferenceContents) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_FileReferenceContents.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_FileReferenceContents proto.InternalMessageInfo
|
||||
|
||||
func (m *FileReferenceContents) GetId() int64 {
|
||||
if m != nil {
|
||||
return m.Id
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *FileReferenceContents) GetPath() string {
|
||||
if m != nil {
|
||||
return m.Path
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *FileReferenceContents) GetContents() string {
|
||||
if m != nil {
|
||||
return m.Contents
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Empty struct {
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Empty) Reset() { *m = Empty{} }
|
||||
func (m *Empty) String() string { return proto.CompactTextString(m) }
|
||||
func (*Empty) ProtoMessage() {}
|
||||
func (*Empty) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{2}
|
||||
}
|
||||
|
||||
func (m *Empty) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Empty.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Empty) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Empty.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Empty) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Empty.Merge(m, src)
|
||||
}
|
||||
func (m *Empty) XXX_Size() int {
|
||||
return xxx_messageInfo_Empty.Size(m)
|
||||
}
|
||||
func (m *Empty) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Empty.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Empty proto.InternalMessageInfo
|
||||
|
||||
type FileResolverRequest struct {
|
||||
Paths []string `protobuf:"bytes,1,rep,name=paths,proto3" json:"paths,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *FileResolverRequest) Reset() { *m = FileResolverRequest{} }
|
||||
func (m *FileResolverRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*FileResolverRequest) ProtoMessage() {}
|
||||
func (*FileResolverRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{3}
|
||||
}
|
||||
|
||||
func (m *FileResolverRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_FileResolverRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *FileResolverRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_FileResolverRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *FileResolverRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_FileResolverRequest.Merge(m, src)
|
||||
}
|
||||
func (m *FileResolverRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_FileResolverRequest.Size(m)
|
||||
}
|
||||
func (m *FileResolverRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_FileResolverRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_FileResolverRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *FileResolverRequest) GetPaths() []string {
|
||||
if m != nil {
|
||||
return m.Paths
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type FileResolverResponse struct {
|
||||
Files []*FileReference `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *FileResolverResponse) Reset() { *m = FileResolverResponse{} }
|
||||
func (m *FileResolverResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*FileResolverResponse) ProtoMessage() {}
|
||||
func (*FileResolverResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{4}
|
||||
}
|
||||
|
||||
func (m *FileResolverResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_FileResolverResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *FileResolverResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_FileResolverResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *FileResolverResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_FileResolverResponse.Merge(m, src)
|
||||
}
|
||||
func (m *FileResolverResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_FileResolverResponse.Size(m)
|
||||
}
|
||||
func (m *FileResolverResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_FileResolverResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_FileResolverResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *FileResolverResponse) GetFiles() []*FileReference {
|
||||
if m != nil {
|
||||
return m.Files
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type NameResponse struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *NameResponse) Reset() { *m = NameResponse{} }
|
||||
func (m *NameResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*NameResponse) ProtoMessage() {}
|
||||
func (*NameResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{5}
|
||||
}
|
||||
|
||||
func (m *NameResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_NameResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *NameResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_NameResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *NameResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_NameResponse.Merge(m, src)
|
||||
}
|
||||
func (m *NameResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_NameResponse.Size(m)
|
||||
}
|
||||
func (m *NameResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_NameResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_NameResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *NameResponse) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SelectFilesRequest struct {
|
||||
FileResolverBrokerId uint32 `protobuf:"varint,1,opt,name=fileResolverBrokerId,proto3" json:"fileResolverBrokerId,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *SelectFilesRequest) Reset() { *m = SelectFilesRequest{} }
|
||||
func (m *SelectFilesRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*SelectFilesRequest) ProtoMessage() {}
|
||||
func (*SelectFilesRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{6}
|
||||
}
|
||||
|
||||
func (m *SelectFilesRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SelectFilesRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *SelectFilesRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_SelectFilesRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *SelectFilesRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SelectFilesRequest.Merge(m, src)
|
||||
}
|
||||
func (m *SelectFilesRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_SelectFilesRequest.Size(m)
|
||||
}
|
||||
func (m *SelectFilesRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SelectFilesRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SelectFilesRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *SelectFilesRequest) GetFileResolverBrokerId() uint32 {
|
||||
if m != nil {
|
||||
return m.FileResolverBrokerId
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type SelectFilesResponse struct {
|
||||
Files []*FileReference `protobuf:"bytes,1,rep,name=files,proto3" json:"files,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *SelectFilesResponse) Reset() { *m = SelectFilesResponse{} }
|
||||
func (m *SelectFilesResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*SelectFilesResponse) ProtoMessage() {}
|
||||
func (*SelectFilesResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{7}
|
||||
}
|
||||
|
||||
func (m *SelectFilesResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_SelectFilesResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *SelectFilesResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_SelectFilesResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *SelectFilesResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_SelectFilesResponse.Merge(m, src)
|
||||
}
|
||||
func (m *SelectFilesResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_SelectFilesResponse.Size(m)
|
||||
}
|
||||
func (m *SelectFilesResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_SelectFilesResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_SelectFilesResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *SelectFilesResponse) GetFiles() []*FileReference {
|
||||
if m != nil {
|
||||
return m.Files
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Package struct {
|
||||
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Version string `protobuf:"bytes,2,opt,name=version,proto3" json:"version,omitempty"`
|
||||
FoundBy string `protobuf:"bytes,3,opt,name=foundBy,proto3" json:"foundBy,omitempty"`
|
||||
Source []*FileReference `protobuf:"bytes,4,rep,name=source,proto3" json:"source,omitempty"`
|
||||
Licenses []string `protobuf:"bytes,5,rep,name=licenses,proto3" json:"licenses,omitempty"`
|
||||
Language uint64 `protobuf:"varint,6,opt,name=language,proto3" json:"language,omitempty"`
|
||||
Type string `protobuf:"bytes,7,opt,name=type,proto3" json:"type,omitempty"`
|
||||
Metadata map[string]string `protobuf:"bytes,8,rep,name=metadata,proto3" json:"metadata,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *Package) Reset() { *m = Package{} }
|
||||
func (m *Package) String() string { return proto.CompactTextString(m) }
|
||||
func (*Package) ProtoMessage() {}
|
||||
func (*Package) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{8}
|
||||
}
|
||||
|
||||
func (m *Package) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_Package.Unmarshal(m, b)
|
||||
}
|
||||
func (m *Package) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_Package.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *Package) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_Package.Merge(m, src)
|
||||
}
|
||||
func (m *Package) XXX_Size() int {
|
||||
return xxx_messageInfo_Package.Size(m)
|
||||
}
|
||||
func (m *Package) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_Package.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_Package proto.InternalMessageInfo
|
||||
|
||||
func (m *Package) GetName() string {
|
||||
if m != nil {
|
||||
return m.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetVersion() string {
|
||||
if m != nil {
|
||||
return m.Version
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetFoundBy() string {
|
||||
if m != nil {
|
||||
return m.FoundBy
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetSource() []*FileReference {
|
||||
if m != nil {
|
||||
return m.Source
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Package) GetLicenses() []string {
|
||||
if m != nil {
|
||||
return m.Licenses
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Package) GetLanguage() uint64 {
|
||||
if m != nil {
|
||||
return m.Language
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *Package) GetType() string {
|
||||
if m != nil {
|
||||
return m.Type
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (m *Package) GetMetadata() map[string]string {
|
||||
if m != nil {
|
||||
return m.Metadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CatalogRequest struct {
|
||||
Contents []*FileReferenceContents `protobuf:"bytes,1,rep,name=contents,proto3" json:"contents,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CatalogRequest) Reset() { *m = CatalogRequest{} }
|
||||
func (m *CatalogRequest) String() string { return proto.CompactTextString(m) }
|
||||
func (*CatalogRequest) ProtoMessage() {}
|
||||
func (*CatalogRequest) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{9}
|
||||
}
|
||||
|
||||
func (m *CatalogRequest) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CatalogRequest.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CatalogRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CatalogRequest.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CatalogRequest) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CatalogRequest.Merge(m, src)
|
||||
}
|
||||
func (m *CatalogRequest) XXX_Size() int {
|
||||
return xxx_messageInfo_CatalogRequest.Size(m)
|
||||
}
|
||||
func (m *CatalogRequest) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CatalogRequest.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CatalogRequest proto.InternalMessageInfo
|
||||
|
||||
func (m *CatalogRequest) GetContents() []*FileReferenceContents {
|
||||
if m != nil {
|
||||
return m.Contents
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type CatalogResponse struct {
|
||||
Package []*Package `protobuf:"bytes,1,rep,name=package,proto3" json:"package,omitempty"`
|
||||
XXX_NoUnkeyedLiteral struct{} `json:"-"`
|
||||
XXX_unrecognized []byte `json:"-"`
|
||||
XXX_sizecache int32 `json:"-"`
|
||||
}
|
||||
|
||||
func (m *CatalogResponse) Reset() { *m = CatalogResponse{} }
|
||||
func (m *CatalogResponse) String() string { return proto.CompactTextString(m) }
|
||||
func (*CatalogResponse) ProtoMessage() {}
|
||||
func (*CatalogResponse) Descriptor() ([]byte, []int) {
|
||||
return fileDescriptor_346aaad5d7f2c092, []int{10}
|
||||
}
|
||||
|
||||
func (m *CatalogResponse) XXX_Unmarshal(b []byte) error {
|
||||
return xxx_messageInfo_CatalogResponse.Unmarshal(m, b)
|
||||
}
|
||||
func (m *CatalogResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
|
||||
return xxx_messageInfo_CatalogResponse.Marshal(b, m, deterministic)
|
||||
}
|
||||
func (m *CatalogResponse) XXX_Merge(src proto.Message) {
|
||||
xxx_messageInfo_CatalogResponse.Merge(m, src)
|
||||
}
|
||||
func (m *CatalogResponse) XXX_Size() int {
|
||||
return xxx_messageInfo_CatalogResponse.Size(m)
|
||||
}
|
||||
func (m *CatalogResponse) XXX_DiscardUnknown() {
|
||||
xxx_messageInfo_CatalogResponse.DiscardUnknown(m)
|
||||
}
|
||||
|
||||
var xxx_messageInfo_CatalogResponse proto.InternalMessageInfo
|
||||
|
||||
func (m *CatalogResponse) GetPackage() []*Package {
|
||||
if m != nil {
|
||||
return m.Package
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterType((*FileReference)(nil), "proto.FileReference")
|
||||
proto.RegisterType((*FileReferenceContents)(nil), "proto.FileReferenceContents")
|
||||
proto.RegisterType((*Empty)(nil), "proto.Empty")
|
||||
proto.RegisterType((*FileResolverRequest)(nil), "proto.FileResolverRequest")
|
||||
proto.RegisterType((*FileResolverResponse)(nil), "proto.FileResolverResponse")
|
||||
proto.RegisterType((*NameResponse)(nil), "proto.NameResponse")
|
||||
proto.RegisterType((*SelectFilesRequest)(nil), "proto.SelectFilesRequest")
|
||||
proto.RegisterType((*SelectFilesResponse)(nil), "proto.SelectFilesResponse")
|
||||
proto.RegisterType((*Package)(nil), "proto.Package")
|
||||
proto.RegisterMapType((map[string]string)(nil), "proto.Package.MetadataEntry")
|
||||
proto.RegisterType((*CatalogRequest)(nil), "proto.CatalogRequest")
|
||||
proto.RegisterType((*CatalogResponse)(nil), "proto.CatalogResponse")
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("cataloger.proto", fileDescriptor_346aaad5d7f2c092) }
|
||||
|
||||
var fileDescriptor_346aaad5d7f2c092 = []byte{
|
||||
// 541 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x9c, 0x53, 0xcb, 0x8e, 0xd3, 0x3c,
|
||||
0x14, 0x56, 0x7a, 0x4b, 0x7b, 0x7a, 0x99, 0x5f, 0x6e, 0xe7, 0x57, 0x08, 0x2c, 0xaa, 0xac, 0xca,
|
||||
0x45, 0x5d, 0x74, 0x36, 0x15, 0xb3, 0xa2, 0x65, 0x86, 0x8b, 0x04, 0x1a, 0x99, 0x05, 0x6b, 0x4f,
|
||||
0x7a, 0x5a, 0xa2, 0xa6, 0x71, 0x88, 0xdd, 0x4a, 0x79, 0x19, 0x1e, 0x83, 0x07, 0xe0, 0xc9, 0x50,
|
||||
0x6c, 0x27, 0xd4, 0x10, 0x21, 0x34, 0xab, 0xf8, 0xe4, 0xfb, 0xfc, 0x9d, 0xcf, 0xe7, 0x02, 0x17,
|
||||
0x21, 0x93, 0x2c, 0xe6, 0x3b, 0xcc, 0xe6, 0x69, 0xc6, 0x25, 0x27, 0x6d, 0xf5, 0x09, 0xae, 0x60,
|
||||
0x78, 0x1b, 0xc5, 0x48, 0x71, 0x8b, 0x19, 0x26, 0x21, 0x92, 0x11, 0x34, 0xa2, 0x8d, 0xe7, 0x4c,
|
||||
0x9d, 0x59, 0x93, 0x36, 0xa2, 0x0d, 0x21, 0xd0, 0x4a, 0x99, 0xfc, 0xe2, 0x35, 0xa6, 0xce, 0xac,
|
||||
0x47, 0xd5, 0x39, 0xf8, 0x0c, 0x97, 0xd6, 0xa5, 0x35, 0x4f, 0x24, 0x26, 0x52, 0xfc, 0xcb, 0x65,
|
||||
0xe2, 0x43, 0x37, 0x34, 0x7c, 0xaf, 0xa9, 0xfe, 0x57, 0x71, 0xe0, 0x42, 0xfb, 0xe6, 0x90, 0xca,
|
||||
0x3c, 0x78, 0x0e, 0x63, 0x9d, 0x41, 0xf0, 0xf8, 0x84, 0x19, 0xc5, 0xaf, 0x47, 0x14, 0x92, 0x4c,
|
||||
0xa0, 0x5d, 0x68, 0x08, 0xcf, 0x99, 0x36, 0x67, 0x3d, 0xaa, 0x83, 0x60, 0x05, 0x13, 0x9b, 0x2c,
|
||||
0x52, 0x9e, 0x08, 0x24, 0xcf, 0xa0, 0xbd, 0x8d, 0x62, 0xd4, 0xec, 0xfe, 0x62, 0xa2, 0x5f, 0x3e,
|
||||
0xb7, 0xac, 0x53, 0x4d, 0x09, 0x02, 0x18, 0x7c, 0x64, 0x07, 0xac, 0xee, 0x12, 0x68, 0x25, 0xec,
|
||||
0x80, 0xea, 0x2d, 0x3d, 0xaa, 0xce, 0xc1, 0x5b, 0x20, 0x9f, 0x30, 0xc6, 0x50, 0x16, 0x0a, 0xa2,
|
||||
0xf4, 0xb4, 0x80, 0xc9, 0xf6, 0x2c, 0xfb, 0x2a, 0xe3, 0x7b, 0xcc, 0xde, 0xe9, 0x2a, 0x0c, 0x69,
|
||||
0x2d, 0x16, 0xbc, 0x82, 0xb1, 0xa5, 0xf4, 0x00, 0xc3, 0x3f, 0x1a, 0xe0, 0xde, 0xb1, 0x70, 0xcf,
|
||||
0x76, 0xb5, 0x66, 0x89, 0x07, 0xee, 0x09, 0x33, 0x11, 0xf1, 0xc4, 0x54, 0xbf, 0x0c, 0x0b, 0x64,
|
||||
0xcb, 0x8f, 0xc9, 0x66, 0x95, 0x9b, 0xfa, 0x97, 0x21, 0x79, 0x01, 0x1d, 0xc1, 0x8f, 0x59, 0x88,
|
||||
0x5e, 0xeb, 0x2f, 0x06, 0x0c, 0xa7, 0x68, 0x64, 0x1c, 0x85, 0x98, 0x08, 0x14, 0x5e, 0x5b, 0xf5,
|
||||
0xa3, 0x8a, 0x15, 0xc6, 0x92, 0xdd, 0x91, 0xed, 0xd0, 0xeb, 0x4c, 0x9d, 0x59, 0x8b, 0x56, 0x71,
|
||||
0xe1, 0x56, 0xe6, 0x29, 0x7a, 0xae, 0x76, 0x5b, 0x9c, 0xc9, 0x12, 0xba, 0x07, 0x94, 0x6c, 0xc3,
|
||||
0x24, 0xf3, 0xba, 0x2a, 0xf7, 0x13, 0x93, 0xdb, 0xbc, 0x71, 0xfe, 0xc1, 0xc0, 0x37, 0x89, 0xcc,
|
||||
0x72, 0x5a, 0xb1, 0xfd, 0x6b, 0x18, 0x5a, 0x10, 0xf9, 0x0f, 0x9a, 0x7b, 0xcc, 0x4d, 0x2d, 0x8a,
|
||||
0x63, 0x31, 0x35, 0x27, 0x16, 0x1f, 0xd1, 0x14, 0x42, 0x07, 0x2f, 0x1b, 0x4b, 0x27, 0x78, 0x0f,
|
||||
0xa3, 0xb5, 0xde, 0x8b, 0xb2, 0x9b, 0xcb, 0xb3, 0xe9, 0x74, 0x2c, 0x23, 0xb5, 0x13, 0x7f, 0x36,
|
||||
0xbb, 0xd7, 0x70, 0x51, 0x69, 0x99, 0x7e, 0xce, 0xc0, 0x4d, 0xb5, 0x7d, 0xa3, 0x35, 0xb2, 0x1f,
|
||||
0x45, 0x4b, 0x78, 0xf1, 0xdd, 0x81, 0xde, 0xba, 0xdc, 0x50, 0xf2, 0x14, 0x5a, 0xc5, 0x30, 0x92,
|
||||
0x81, 0xa1, 0xab, 0x9d, 0xf0, 0xc7, 0x26, 0xb2, 0xe6, 0xf4, 0x35, 0xf4, 0xcf, 0x26, 0x89, 0x3c,
|
||||
0x32, 0x9c, 0x3f, 0xe7, 0xd4, 0xf7, 0xeb, 0x20, 0xa3, 0xb2, 0x04, 0xd7, 0x64, 0x27, 0x97, 0x86,
|
||||
0x66, 0xd7, 0xc5, 0xff, 0xff, 0xf7, 0xdf, 0xfa, 0xe6, 0xe2, 0x9b, 0x03, 0x83, 0xf3, 0xe5, 0x23,
|
||||
0xb7, 0xd0, 0x57, 0xda, 0xab, 0xfc, 0x4e, 0x6d, 0xbb, 0x55, 0x3d, 0x6b, 0x9b, 0xfd, 0xc7, 0xb5,
|
||||
0x98, 0xb1, 0xf4, 0x4b, 0xe7, 0x4d, 0xcc, 0xef, 0x1f, 0xac, 0x73, 0xdf, 0x51, 0xd8, 0xd5, 0xcf,
|
||||
0x00, 0x00, 0x00, 0xff, 0xff, 0x6e, 0xfe, 0x04, 0x3e, 0x01, 0x05, 0x00, 0x00,
|
||||
}
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ context.Context
|
||||
var _ grpc.ClientConnInterface
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
const _ = grpc.SupportPackageIsVersion6
|
||||
|
||||
// CatalogerClient is the client API for Cataloger service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type CatalogerClient interface {
|
||||
Name(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*NameResponse, error)
|
||||
SelectFiles(ctx context.Context, in *SelectFilesRequest, opts ...grpc.CallOption) (*SelectFilesResponse, error)
|
||||
Catalog(ctx context.Context, in *CatalogRequest, opts ...grpc.CallOption) (*CatalogResponse, error)
|
||||
}
|
||||
|
||||
type catalogerClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewCatalogerClient(cc grpc.ClientConnInterface) CatalogerClient {
|
||||
return &catalogerClient{cc}
|
||||
}
|
||||
|
||||
func (c *catalogerClient) Name(ctx context.Context, in *Empty, opts ...grpc.CallOption) (*NameResponse, error) {
|
||||
out := new(NameResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.Cataloger/Name", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *catalogerClient) SelectFiles(ctx context.Context, in *SelectFilesRequest, opts ...grpc.CallOption) (*SelectFilesResponse, error) {
|
||||
out := new(SelectFilesResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.Cataloger/SelectFiles", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *catalogerClient) Catalog(ctx context.Context, in *CatalogRequest, opts ...grpc.CallOption) (*CatalogResponse, error) {
|
||||
out := new(CatalogResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.Cataloger/Catalog", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CatalogerServer is the server API for Cataloger service.
|
||||
type CatalogerServer interface {
|
||||
Name(context.Context, *Empty) (*NameResponse, error)
|
||||
SelectFiles(context.Context, *SelectFilesRequest) (*SelectFilesResponse, error)
|
||||
Catalog(context.Context, *CatalogRequest) (*CatalogResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedCatalogerServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedCatalogerServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedCatalogerServer) Name(ctx context.Context, req *Empty) (*NameResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Name not implemented")
|
||||
}
|
||||
func (*UnimplementedCatalogerServer) SelectFiles(ctx context.Context, req *SelectFilesRequest) (*SelectFilesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method SelectFiles not implemented")
|
||||
}
|
||||
func (*UnimplementedCatalogerServer) Catalog(ctx context.Context, req *CatalogRequest) (*CatalogResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method Catalog not implemented")
|
||||
}
|
||||
|
||||
func RegisterCatalogerServer(s *grpc.Server, srv CatalogerServer) {
|
||||
s.RegisterService(&_Cataloger_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _Cataloger_Name_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CatalogerServer).Name(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Cataloger/Name",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CatalogerServer).Name(ctx, req.(*Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Cataloger_SelectFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(SelectFilesRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CatalogerServer).SelectFiles(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Cataloger/SelectFiles",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CatalogerServer).SelectFiles(ctx, req.(*SelectFilesRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Cataloger_Catalog_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(CatalogRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CatalogerServer).Catalog(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.Cataloger/Catalog",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CatalogerServer).Catalog(ctx, req.(*CatalogRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _Cataloger_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "proto.Cataloger",
|
||||
HandlerType: (*CatalogerServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "Name",
|
||||
Handler: _Cataloger_Name_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "SelectFiles",
|
||||
Handler: _Cataloger_SelectFiles_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "Catalog",
|
||||
Handler: _Cataloger_Catalog_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "cataloger.proto",
|
||||
}
|
||||
|
||||
// FileResolverClient is the client API for FileResolver service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
|
||||
type FileResolverClient interface {
|
||||
FilesByPath(ctx context.Context, in *FileResolverRequest, opts ...grpc.CallOption) (*FileResolverResponse, error)
|
||||
FilesByGlob(ctx context.Context, in *FileResolverRequest, opts ...grpc.CallOption) (*FileResolverResponse, error)
|
||||
}
|
||||
|
||||
type fileResolverClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewFileResolverClient(cc grpc.ClientConnInterface) FileResolverClient {
|
||||
return &fileResolverClient{cc}
|
||||
}
|
||||
|
||||
func (c *fileResolverClient) FilesByPath(ctx context.Context, in *FileResolverRequest, opts ...grpc.CallOption) (*FileResolverResponse, error) {
|
||||
out := new(FileResolverResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.FileResolver/FilesByPath", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *fileResolverClient) FilesByGlob(ctx context.Context, in *FileResolverRequest, opts ...grpc.CallOption) (*FileResolverResponse, error) {
|
||||
out := new(FileResolverResponse)
|
||||
err := c.cc.Invoke(ctx, "/proto.FileResolver/FilesByGlob", in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// FileResolverServer is the server API for FileResolver service.
|
||||
type FileResolverServer interface {
|
||||
FilesByPath(context.Context, *FileResolverRequest) (*FileResolverResponse, error)
|
||||
FilesByGlob(context.Context, *FileResolverRequest) (*FileResolverResponse, error)
|
||||
}
|
||||
|
||||
// UnimplementedFileResolverServer can be embedded to have forward compatible implementations.
|
||||
type UnimplementedFileResolverServer struct {
|
||||
}
|
||||
|
||||
func (*UnimplementedFileResolverServer) FilesByPath(ctx context.Context, req *FileResolverRequest) (*FileResolverResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method FilesByPath not implemented")
|
||||
}
|
||||
func (*UnimplementedFileResolverServer) FilesByGlob(ctx context.Context, req *FileResolverRequest) (*FileResolverResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method FilesByGlob not implemented")
|
||||
}
|
||||
|
||||
func RegisterFileResolverServer(s *grpc.Server, srv FileResolverServer) {
|
||||
s.RegisterService(&_FileResolver_serviceDesc, srv)
|
||||
}
|
||||
|
||||
func _FileResolver_FilesByPath_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(FileResolverRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(FileResolverServer).FilesByPath(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.FileResolver/FilesByPath",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(FileResolverServer).FilesByPath(ctx, req.(*FileResolverRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _FileResolver_FilesByGlob_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(FileResolverRequest)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(FileResolverServer).FilesByGlob(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: "/proto.FileResolver/FilesByGlob",
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(FileResolverServer).FilesByGlob(ctx, req.(*FileResolverRequest))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
var _FileResolver_serviceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "proto.FileResolver",
|
||||
HandlerType: (*FileResolverServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "FilesByPath",
|
||||
Handler: _FileResolver_FilesByPath_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "FilesByGlob",
|
||||
Handler: _FileResolver_FilesByGlob_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "cataloger.proto",
|
||||
}
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
syntax = "proto3";
|
||||
package proto;
|
||||
|
||||
message FileReference {
|
||||
int64 id = 1;
|
||||
string path = 2;
|
||||
}
|
||||
|
||||
message FileReferenceContents {
|
||||
int64 id = 1;
|
||||
string path = 2;
|
||||
string contents = 3;
|
||||
}
|
||||
|
||||
message Empty {
|
||||
}
|
||||
|
||||
message FileResolverRequest {
|
||||
repeated string paths = 1;
|
||||
}
|
||||
|
||||
message FileResolverResponse {
|
||||
repeated FileReference files = 1;
|
||||
}
|
||||
|
||||
message NameResponse {
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
message SelectFilesRequest {
|
||||
uint32 fileResolverBrokerId = 1;
|
||||
}
|
||||
|
||||
message SelectFilesResponse {
|
||||
repeated FileReference files = 1;
|
||||
}
|
||||
|
||||
message Package {
|
||||
string name = 1;
|
||||
string version = 2;
|
||||
string foundBy = 3;
|
||||
repeated FileReference source = 4;
|
||||
repeated string licenses = 5;
|
||||
uint64 language = 6;
|
||||
string type = 7;
|
||||
map<string, string> metadata = 8;
|
||||
}
|
||||
|
||||
message CatalogRequest {
|
||||
repeated FileReferenceContents contents = 1;
|
||||
}
|
||||
|
||||
message CatalogResponse {
|
||||
repeated Package package = 1;
|
||||
}
|
||||
|
||||
service Cataloger {
|
||||
rpc Name(Empty) returns (NameResponse);
|
||||
rpc SelectFiles(SelectFilesRequest) returns (SelectFilesResponse);
|
||||
rpc Catalog(CatalogRequest) returns (CatalogResponse);
|
||||
}
|
||||
|
||||
service FileResolver {
|
||||
rpc FilesByPath(FileResolverRequest) returns (FileResolverResponse);
|
||||
rpc FilesByGlob(FileResolverRequest) returns (FileResolverResponse);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,119 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/cataloger"
|
||||
)
|
||||
|
||||
type Repository struct {
|
||||
byType map[Type][]Plugin
|
||||
}
|
||||
|
||||
func NewRepository() *Repository {
|
||||
return &Repository{
|
||||
byType: make(map[Type][]Plugin),
|
||||
}
|
||||
}
|
||||
|
||||
func NewRepositoryFromDirectory(dir string) (*Repository, error) {
|
||||
repo := NewRepository()
|
||||
if dir == "" {
|
||||
return repo, nil
|
||||
}
|
||||
|
||||
return repo, repo.AddFromDirectory(dir)
|
||||
}
|
||||
|
||||
func (c *Repository) Add(plugin Plugin) {
|
||||
c.byType[plugin.Config.Type] = append(c.byType[plugin.Config.Type], plugin)
|
||||
}
|
||||
|
||||
func (c *Repository) AddFromDirectory(dir string, pluginTypes ...Type) error {
|
||||
plugins, err := Discover(dir, pluginTypes...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, plugin := range plugins {
|
||||
log.Debugf("added plugin: %q", plugin.Config.Name)
|
||||
c.Add(plugin)
|
||||
}
|
||||
log.Debugf("%d plugins added", len(plugins))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Repository) Get(pluginType Type) []Plugin {
|
||||
return c.byType[pluginType]
|
||||
}
|
||||
|
||||
func (c *Repository) ActivateCatalogers() ([]cataloger.Cataloger, func(), error) {
|
||||
var result []cataloger.Cataloger
|
||||
var plugins []Plugin
|
||||
var deactivateFn = func() {
|
||||
for _, plugin := range plugins {
|
||||
if err := plugin.Stop(); err != nil {
|
||||
log.Errorf("failed to stop plugin: %w", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, plugin := range c.Get(TypeCataloger) {
|
||||
raw, err := plugin.Start()
|
||||
if err != nil {
|
||||
return nil, deactivateFn, err
|
||||
}
|
||||
plugins = append(plugins, plugin)
|
||||
|
||||
theCataloger, ok := raw.(cataloger.Cataloger)
|
||||
if !ok {
|
||||
return nil, deactivateFn, fmt.Errorf("activation of cataloger did not return a cataloger object (name=%s type=%T)", plugin.Config.Name, theCataloger)
|
||||
}
|
||||
|
||||
result = append(result, theCataloger)
|
||||
}
|
||||
return result, deactivateFn, nil
|
||||
}
|
||||
|
||||
func Discover(dir string, pluginTypes ...Type) ([]Plugin, error) {
|
||||
var err error
|
||||
|
||||
if len(pluginTypes) == 0 {
|
||||
pluginTypes = AllTypes
|
||||
}
|
||||
|
||||
if !filepath.IsAbs(dir) {
|
||||
dir, err = filepath.Abs(dir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var plugins []Plugin
|
||||
|
||||
for _, pluginType := range pluginTypes {
|
||||
pluginPrefix := pluginType.String()
|
||||
pluginGlob := fmt.Sprintf("%s-*", pluginPrefix)
|
||||
paths, err := filepath.Glob(filepath.Join(dir, pluginGlob))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, path := range paths {
|
||||
// TODO: should we use a config for some of this?
|
||||
plugins = append(plugins, NewPlugin(Config{
|
||||
// TODO: should the name be org/name instead of just name? this implies changing the dir storage too
|
||||
Name: strings.TrimPrefix(filepath.Base(path), pluginPrefix+"-"),
|
||||
Type: pluginType,
|
||||
Command: path,
|
||||
Args: nil, // TODO
|
||||
Env: nil, // TODO
|
||||
}))
|
||||
}
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
var AllTypes = []Type{
|
||||
TypeCataloger,
|
||||
}
|
||||
|
||||
type Type uint64
|
||||
|
||||
const (
|
||||
TypeUnknown Type = iota
|
||||
TypeCataloger
|
||||
)
|
||||
|
||||
func (p Type) String() string {
|
||||
switch p {
|
||||
case TypeCataloger:
|
||||
return "cataloger"
|
||||
default:
|
||||
return "unknown"
|
||||
}
|
||||
}
|
||||
|
||||
func (p Type) HandshakeConfig() plugin.HandshakeConfig {
|
||||
switch p {
|
||||
case TypeCataloger:
|
||||
return plugin.HandshakeConfig{
|
||||
ProtocolVersion: 1,
|
||||
MagicCookieKey: "SYFT_PLUGIN_MAGIC_COOKIE",
|
||||
MagicCookieValue: "0f86cc7f-6f97-410e-a844-087cd12e36e3",
|
||||
}
|
||||
default:
|
||||
panic(fmt.Errorf("plugin type unsupported"))
|
||||
}
|
||||
}
|
||||
|
||||
func ParseType(pluginType string) Type {
|
||||
switch pluginType {
|
||||
case "cataloger":
|
||||
return TypeCataloger
|
||||
default:
|
||||
return TypeUnknown
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package scope
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
@@ -16,7 +17,7 @@ type Resolver interface {
|
||||
|
||||
// ContentResolver knows how to get file content for given file.References
|
||||
type ContentResolver interface {
|
||||
MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]string, error)
|
||||
MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]io.Reader, error)
|
||||
}
|
||||
|
||||
// FileResolver knows how to get file.References for given string paths and globs
|
||||
|
||||
@@ -3,6 +3,7 @@ package resolvers
|
||||
import (
|
||||
"archive/tar"
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
@@ -111,6 +112,6 @@ func (r *AllLayersResolver) FilesByGlob(patterns ...string) ([]file.Reference, e
|
||||
|
||||
// MultipleFileContentsByRef returns the file contents for all file.References relative to the image. Note that a
|
||||
// file.Reference is a path relative to a particular layer.
|
||||
func (r *AllLayersResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]string, error) {
|
||||
func (r *AllLayersResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]io.Reader, error) {
|
||||
return r.img.MultipleFileContentsByRef(f...)
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ package resolvers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
@@ -40,15 +40,6 @@ func (s DirectoryResolver) FilesByPath(userPaths ...file.Path) ([]file.Reference
|
||||
return references, nil
|
||||
}
|
||||
|
||||
func fileContents(path file.Path) ([]byte, error) {
|
||||
contents, err := ioutil.ReadFile(string(path))
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return contents, nil
|
||||
}
|
||||
|
||||
// FilesByGlob returns all file.References that match the given path glob pattern from any layer in the image.
|
||||
func (s DirectoryResolver) FilesByGlob(patterns ...string) ([]file.Reference, error) {
|
||||
result := make([]file.Reference, 0)
|
||||
@@ -76,15 +67,15 @@ func (s DirectoryResolver) FilesByGlob(patterns ...string) ([]file.Reference, er
|
||||
}
|
||||
|
||||
// MultipleFileContentsByRef returns the file contents for all file.References relative a directory.
|
||||
func (s DirectoryResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]string, error) {
|
||||
refContents := make(map[file.Reference]string)
|
||||
func (s DirectoryResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]io.Reader, error) {
|
||||
refContents := make(map[file.Reference]io.Reader)
|
||||
for _, fileRef := range f {
|
||||
contents, err := fileContents(fileRef.Path)
|
||||
|
||||
targetFile, err := os.Open(string(fileRef.Path))
|
||||
if err != nil {
|
||||
return refContents, fmt.Errorf("could not read contents of file: %s", fileRef.Path)
|
||||
return refContents, fmt.Errorf("could not open file=%q: %w", fileRef.Path, err)
|
||||
}
|
||||
refContents[fileRef] = string(contents)
|
||||
|
||||
refContents[fileRef] = targetFile
|
||||
}
|
||||
return refContents, nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package resolvers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/stereoscope/pkg/image"
|
||||
@@ -75,6 +76,6 @@ func (r *ImageSquashResolver) FilesByGlob(patterns ...string) ([]file.Reference,
|
||||
|
||||
// MultipleFileContentsByRef returns the file contents for all file.References relative to the image. Note that a
|
||||
// file.Reference is a path relative to a particular layer, in this case only from the squashed representation.
|
||||
func (r *ImageSquashResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]string, error) {
|
||||
func (r *ImageSquashResolver) MultipleFileContentsByRef(f ...file.Reference) (map[file.Reference]io.Reader, error) {
|
||||
return r.img.MultipleFileContentsByRef(f...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user