mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
rough draft for plugin system
Signed-off-by: Alex Goodman <alex.goodman@anchore.com>
This commit is contained in:
parent
63ee5ba098
commit
3e27b6e93f
@ -31,7 +31,7 @@ linters:
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- prealloc
|
||||
# - prealloc
|
||||
- rowserrcheck
|
||||
- scopelint
|
||||
- staticcheck
|
||||
|
||||
3
Makefile
3
Makefile
@ -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
|
||||
|
||||
|
||||
16
cmd/cmd.go
16
cmd/cmd.go
@ -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.ConfigHome, 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() {
|
||||
|
||||
3
go.mod
3
go.mod
@ -12,11 +12,13 @@ require (
|
||||
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-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
|
||||
@ -39,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
|
||||
)
|
||||
|
||||
16
go.sum
16
go.sum
@ -474,12 +474,16 @@ 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-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 +504,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 +516,7 @@ 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/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=
|
||||
@ -611,6 +618,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 +648,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 +934,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=
|
||||
@ -1148,6 +1160,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 +1194,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 +1209,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 {
|
||||
|
||||
@ -4,11 +4,12 @@ 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"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger catalogs pkg.ApkPkg Package Types defined in Alpine DB files.
|
||||
|
||||
@ -4,11 +4,12 @@ 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"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger catalogs pkg.GemPkg Package Types defined in Bundler Gemfile.lock files.
|
||||
|
||||
@ -6,6 +6,8 @@ catalogers defined in child packages as well as the interface definition to impl
|
||||
package cataloger
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/syft/cataloger/apkdb"
|
||||
"github.com/anchore/syft/syft/cataloger/bundler"
|
||||
@ -17,7 +19,6 @@ import (
|
||||
"github.com/anchore/syft/syft/cataloger/rpmdb"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger describes behavior for an object to participate in parsing container image or file system
|
||||
|
||||
@ -4,11 +4,12 @@ Package common provides generic utilities used by multiple catalogers.
|
||||
package common
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/anchore/syft/syft/pkg"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// GenericCataloger implements the Catalog interface and is responsible for dispatching the proper parser function for
|
||||
|
||||
@ -4,11 +4,12 @@ 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"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger catalogs pkg.DebPkg Package Types defined in DPKG status files.
|
||||
|
||||
@ -4,11 +4,12 @@ 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"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger catalogs pkg.GoModulePkg Package Types defined in go.mod files.
|
||||
|
||||
@ -4,11 +4,12 @@ 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"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger catalogs pkg.JavaPkg and pkg.JenkinsPluginPkg Package Types defined in java archive files.
|
||||
|
||||
@ -4,11 +4,12 @@ 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"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger catalogs pkg.YarnPkg and pkg.NpmPkg Package Types defined in package-lock.json and yarn.lock files.
|
||||
|
||||
@ -4,11 +4,12 @@ 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"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger catalogs pkg.WheelPkg, pkg.EggPkg, and pkg.PythonRequirementsPkg Package Types defined in Python ecosystem files.
|
||||
|
||||
@ -4,11 +4,12 @@ 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"
|
||||
"github.com/anchore/syft/syft/scope"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Cataloger catalogs pkg.RpmPkg Package Types defined in RPM DB files.
|
||||
|
||||
34
syft/plugin/cataloger_plugin.go
Normal file
34
syft/plugin/cataloger_plugin.go
Normal file
@ -0,0 +1,34 @@
|
||||
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{}
|
||||
|
||||
// Cataloger is the interface exposed as a plugin.
|
||||
type Cataloger interface {
|
||||
cataloger.Cataloger
|
||||
}
|
||||
|
||||
// CatalogerPlugin is the implementation of plugin.Plugin that is served/consumed.
|
||||
type CatalogerPlugin struct {
|
||||
plugin.NetRPCUnsupportedPlugin
|
||||
Impl 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
|
||||
}
|
||||
43
syft/plugin/discover.go
Normal file
43
syft/plugin/discover.go
Normal file
@ -0,0 +1,43 @@
|
||||
package plugin
|
||||
|
||||
import "path/filepath"
|
||||
|
||||
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 {
|
||||
// look into a sub dir named by the plugin type
|
||||
searchDir := filepath.Join(dir, pluginType.String())
|
||||
|
||||
paths, err := filepath.Glob(filepath.Join(searchDir, "*"))
|
||||
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: filepath.Base(path),
|
||||
Type: pluginType,
|
||||
Command: path,
|
||||
Args: nil, // TODO
|
||||
Env: nil, // TODO
|
||||
}))
|
||||
}
|
||||
}
|
||||
return plugins, nil
|
||||
}
|
||||
102
syft/plugin/grpc/cataloger_client.go
Normal file
102
syft/plugin/grpc/cataloger_client.go
Normal file
@ -0,0 +1,102 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
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) error {
|
||||
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)
|
||||
|
||||
_, err := c.client.SelectFiles(context.Background(), &proto.SelectFilesRequest{
|
||||
FileResolverBrokerId: brokerID,
|
||||
})
|
||||
|
||||
s.Stop()
|
||||
return err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
99
syft/plugin/grpc/cataloger_server.go
Normal file
99
syft/plugin/grpc/cataloger_server.go
Normal file
@ -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: nil,
|
||||
}, nil
|
||||
}
|
||||
46
syft/plugin/grpc/file_resolver_client.go
Normal file
46
syft/plugin/grpc/file_resolver_client.go
Normal file
@ -0,0 +1,46 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"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
|
||||
}
|
||||
|
||||
var result []file.Reference
|
||||
for _, ref := range resp.Files {
|
||||
result = append(result, file.NewFileReferenceWithID(file.Path(ref.Path), uint64(ref.Id)))
|
||||
}
|
||||
|
||||
return result, err
|
||||
}
|
||||
55
syft/plugin/grpc/file_resolver_server.go
Normal file
55
syft/plugin/grpc/file_resolver_server.go
Normal file
@ -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
|
||||
}
|
||||
85
syft/plugin/plugin.go
Normal file
85
syft/plugin/plugin.go
Normal file
@ -0,0 +1,85 @@
|
||||
package plugin
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
|
||||
"github.com/hashicorp/go-plugin"
|
||||
)
|
||||
|
||||
var plugins = map[int]plugin.PluginSet{
|
||||
1: {
|
||||
TypeCataloger.String(): &CatalogerPlugin{},
|
||||
},
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Name string
|
||||
Type Type
|
||||
Command string
|
||||
Args []string
|
||||
Env []string
|
||||
//Sha256 []byte
|
||||
}
|
||||
|
||||
type Plugin struct {
|
||||
Config Config
|
||||
clientConfig *plugin.ClientConfig
|
||||
client *plugin.Client
|
||||
}
|
||||
|
||||
func NewPlugin(config Config) Plugin {
|
||||
cmd := exec.Command(config.Command, config.Args...)
|
||||
cmd.Env = append(cmd.Env, config.Env...)
|
||||
|
||||
//secureConfig := &plugin.SecureConfig{
|
||||
// Checksum: config.Sha256,
|
||||
// Hash: sha256.New(),
|
||||
//}
|
||||
|
||||
clientConfig := &plugin.ClientConfig{
|
||||
HandshakeConfig: config.Type.HandshakeConfig(),
|
||||
VersionedPlugins: plugins,
|
||||
//SecureConfig: secureConfig,
|
||||
Cmd: cmd,
|
||||
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
|
||||
}
|
||||
841
syft/plugin/proto/cataloger.pb.go
Normal file
841
syft/plugin/proto/cataloger.pb.go
Normal file
@ -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",
|
||||
}
|
||||
67
syft/plugin/proto/cataloger.proto
Executable file
67
syft/plugin/proto/cataloger.proto
Executable file
@ -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);
|
||||
}
|
||||
|
||||
49
syft/plugin/type.go
Normal file
49
syft/plugin/type.go
Normal file
@ -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_CATALOGER_PLUGIN",
|
||||
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,12 +2,13 @@ package resolvers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/bmatcuk/doublestar"
|
||||
"io"
|
||||
"os"
|
||||
"path"
|
||||
|
||||
"github.com/anchore/stereoscope/pkg/file"
|
||||
"github.com/anchore/syft/internal/log"
|
||||
"github.com/bmatcuk/doublestar"
|
||||
)
|
||||
|
||||
// DirectoryResolver implements path and content access for the directory data source.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user