Initial commit

This commit is contained in:
Ruben Koster 2018-12-04 14:22:49 +01:00
commit c5739f2f5d
10 changed files with 558 additions and 0 deletions

2
.envrc Normal file
View File

@ -0,0 +1,2 @@
export GO111MODULE=on
export PIVNET_API_TOKEN=$(grep token ~/.pivnetrc | cut -d' ' -f4)

50
README.md Normal file
View File

@ -0,0 +1,50 @@
# Pivy - PivNets little helper
A small cli which uses HTTP range Headers and partial unzip to fetch tile metadata directly from Pivotal Network.
## Usage
```
usage: pivy --pivnet-api-token=PIVNET-API-TOKEN [<flags>] <command> [<args> ...]
PivNets little helper
Flags:
--help Show context-sensitive help (also try --help-long
and --help-man).
--accept-eula Automatically accept EULA if necessary (Available
to select users only)
-t, --pivnet-api-token=PIVNET-API-TOKEN
API token for network.pivotal.io (see:
https://network.pivotal.io/users/dashboard/edit-profile)
--include-placeholders replace obscured credentials with interpolatable
placeholders
Commands:
help [<command>...]
Show help.
generate-config-template --product-slug=PRODUCT-SLUG --release-version=RELEASE-VERSION [<flags>]
Generate om cli compatible config template
-p, --product-slug=PRODUCT-SLUG
Product slug e.g. p-mysql
-r, --release-version=RELEASE-VERSION
Release version e.g. 0.1.2-rc1
-g, --glob="*.pivotal" Glob to match product name e.g. *aws* should include
*.pivotal
download-product-template --product-slug=PRODUCT-SLUG --release-version=RELEASE-VERSION [<flags>]
Download raw tile metadata
-p, --product-slug=PRODUCT-SLUG
Product slug e.g. p-mysql
-r, --release-version=RELEASE-VERSION
Release version e.g. 0.1.2-rc1
-g, --glob="*.pivotal" Glob to match product name e.g. *aws* should include
*.pivotal
```

54
commands/commands.go Normal file
View File

@ -0,0 +1,54 @@
package commands
import (
"log"
kingpin "gopkg.in/alecthomas/kingpin.v2"
"github.com/starkandwayne/pivy/pivnet"
)
type register interface {
register(app *kingpin.Application)
}
type global struct {
acceptEULA bool
pivnetToken string
}
// Configure sets up the kingpin commands for the omg-cli.
func Configure(logger *log.Logger, app *kingpin.Application) {
var global global
app.Flag(
"accept-eula",
"Automatically accept EULA if necessary (Available to select users only)",
).Default("false").OverrideDefaultFromEnvar("PIVNET_ACCEPT_EULA").BoolVar(&global.acceptEULA)
app.Flag(
"pivnet-api-token",
"API token for network.pivotal.io (see: https://network.pivotal.io/users/dashboard/edit-profile)",
).Required().OverrideDefaultFromEnvar("PIVNET_API_TOKEN").Short('t').StringVar(&global.pivnetToken)
cmds := []register{
&ConfigTemplateCommand{logger: logger, global: &global},
&DownloadCommand{logger: logger, global: &global},
}
for _, c := range cmds {
c.register(app)
}
}
func registerTileFlags(c *kingpin.CmdClause, tile *pivnet.TileFile) {
c.Flag("product-slug", "Product slug e.g. p-mysql").Required().Short('p').StringVar(&tile.ProductSlug)
c.Flag("release-version", "Release version e.g. 0.1.2-rc1").Required().Short('r').StringVar(&tile.ReleaseVersion)
c.Flag("glob",
"Glob to match product name e.g. *aws* should include *.pivotal",
).Short('g').Default("*.pivotal").StringVar(&tile.Glob)
}
func (g global) NewPivnetSdk(logger *log.Logger) (*pivnet.Sdk, error) {
return pivnet.NewSdk(g.pivnetToken, g.acceptEULA, logger)
}

View File

@ -0,0 +1,53 @@
package commands
import (
"log"
"github.com/starkandwayne/pivy/om"
"github.com/starkandwayne/pivy/pivnet"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
type ConfigTemplateCommand struct {
global *global
logger *log.Logger
tile pivnet.TileFile
placeholders bool
}
const configTemplateName = "generate-config-template"
func (cmd *ConfigTemplateCommand) register(app *kingpin.Application) {
c := app.Command(configTemplateName, "Generate om cli compatible config template").Action(cmd.run)
registerTileFlags(c, &cmd.tile)
app.Flag(
"include-placeholders",
"replace obscured credentials with interpolatable placeholders",
).Default("false").BoolVar(&cmd.placeholders)
}
func (cmd *ConfigTemplateCommand) run(c *kingpin.ParseContext) error {
piv, err := cmd.global.NewPivnetSdk(cmd.logger)
if err != nil {
return err
}
link, err := piv.TileDownloadLink(cmd.tile)
if err != nil {
return err
}
metaData, err := piv.DownloadTileMetaDataFromLink(link)
if err != nil {
return err
}
configTemplate, err := om.TileMetaDataToConfigTemplate(metaData, cmd.placeholders)
if err != nil {
return err
}
cmd.logger.Println(string(configTemplate))
return nil
}

42
commands/download.go Normal file
View File

@ -0,0 +1,42 @@
package commands
import (
"log"
"github.com/starkandwayne/pivy/pivnet"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
type DownloadCommand struct {
global *global
logger *log.Logger
tile pivnet.TileFile
}
const downloadName = "download-product-template"
func (cmd *DownloadCommand) register(app *kingpin.Application) {
c := app.Command(downloadName, "Download raw tile metadata").Action(cmd.run)
registerTileFlags(c, &cmd.tile)
}
func (cmd *DownloadCommand) run(c *kingpin.ParseContext) error {
piv, err := cmd.global.NewPivnetSdk(cmd.logger)
if err != nil {
return err
}
link, err := piv.TileDownloadLink(cmd.tile)
if err != nil {
return err
}
metaData, err := piv.DownloadTileMetaDataFromLink(link)
if err != nil {
return err
}
cmd.logger.Println(string(metaData))
return nil
}

30
go.mod Normal file
View File

@ -0,0 +1,30 @@
module github.com/starkandwayne/pivy
require (
github.com/PuerkitoBio/goquery v1.5.0 // indirect
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc // indirect
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf // indirect
github.com/bmatcuk/doublestar v1.1.1 // indirect
github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1 // indirect
github.com/cloudfoundry/bosh-cli v5.4.0+incompatible // indirect
github.com/cloudfoundry/bosh-utils v0.0.0-20181129005327-aac85884fcb9 // indirect
github.com/cppforlife/go-patch v0.0.0-20171006213518-250da0e0e68c // indirect
github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gobwas/glob v0.2.3
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db // indirect
github.com/google/go-querystring v1.0.0 // indirect
github.com/jeffallen/seekinghttp v0.0.0-20171214161738-f41d11cb25b7
github.com/mholt/archiver v3.1.0+incompatible
github.com/nwaples/rardecode v1.0.0 // indirect
github.com/olekukonko/tablewriter v0.0.1 // indirect
github.com/pierrec/lz4 v2.0.5+incompatible // indirect
github.com/pivotal-cf/go-pivnet v0.0.50
github.com/pivotal-cf/jhanda v0.0.0-20181025233525-e6aa09a032df // indirect
github.com/pivotal-cf/kiln v0.0.0-20181201001855-3e8211a50c91 // indirect
github.com/pivotal-cf/om v0.0.0-20181130184206-81ba5acde680
github.com/pivotal-cf/pivnet-cli v0.0.55
github.com/ulikunitz/xz v0.5.5 // indirect
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect
gopkg.in/alecthomas/kingpin.v2 v2.2.6
)

93
go.sum Normal file
View File

@ -0,0 +1,93 @@
github.com/PuerkitoBio/goquery v1.5.0 h1:uGvmFXOA73IKluu/F84Xd1tt/z07GYm8X49XKHP7EJk=
github.com/PuerkitoBio/goquery v1.5.0/go.mod h1:qD2PgZ9lccMbQlc7eEOjaeRlFQON7xY8kdmcsrnKqMg=
github.com/StackExchange/wmi v0.0.0-20180725035823-b12b22c5341f/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf h1:qet1QNfXsQxTZqLG4oE62mJzwPIB8+Tee4RNCL9ulrY=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o=
github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y=
github.com/bmatcuk/doublestar v1.1.1 h1:YroD6BJCZBYx06yYFEWvUuKVWQn3vLLQAVmDmvTSaiQ=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1 h1:vTlpHKxJqykyKdW9bkrDJNWeKNuSIAJ0TP/K4lRsz/Q=
github.com/charlievieth/fs v0.0.0-20170613215519-7dc373669fa1/go.mod h1:sAoA1zHCH4FJPE2gne5iBiiVG66U7Nyp6JqlOo+FEyg=
github.com/cloudfoundry/bosh-cli v5.4.0+incompatible h1:KpT2PBB7nP1QnK8guXeZ/D2k7FZYAOxcveKgYTDEDBI=
github.com/cloudfoundry/bosh-cli v5.4.0+incompatible/go.mod h1:rzIB+e1sn7wQL/TJ54bl/FemPKRhXby5BIMS3tLuWFM=
github.com/cloudfoundry/bosh-utils v0.0.0-20181129005327-aac85884fcb9 h1:ZZgMA8QKPp3gbJgcDDgC7mlxcjrY3vrbOo3HtMXOPRI=
github.com/cloudfoundry/bosh-utils v0.0.0-20181129005327-aac85884fcb9/go.mod h1:JCrKwetZGjxbfq1U139TZuXDBfdGLtjOEAfxMWKV/QM=
github.com/cppforlife/go-patch v0.0.0-20171006213518-250da0e0e68c h1:L6Qwcfk/qeD05lCaMxjhn8fCKNAVEWOBn1vqU7KJHtk=
github.com/cppforlife/go-patch v0.0.0-20171006213518-250da0e0e68c/go.mod h1:67a7aIi94FHDZdoeGSJRRFDp66l9MhaAG1yGxpUoFD8=
github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76 h1:eX+pdPPlD279OWgdx7f6KqIRSONuK7egk+jDx7OM3Ac=
github.com/dsnet/compress v0.0.0-20171208185109-cc9eb1d7ad76/go.mod h1:KjxHHirfLaw19iGT70HvVjHQsL1vq1SRQB4yOsAfy2s=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-ole/go-ole v0.0.0-20180625085808-7a0fa49edf48/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
github.com/gobwas/glob v0.2.3 h1:A4xDbljILXROh+kObIiy5kIaPYD8e96x1tgBhUI5J+Y=
github.com/gobwas/glob v0.2.3/go.mod h1:d3Ez4x06l9bZtSvzIay5+Yzi0fmZzPgnTbPcKjJAkT8=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db h1:woRePGFeVFfLKN/pOkfl+p/TAqKOfFu+7KPlMVpok/w=
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/jeffallen/seekinghttp v0.0.0-20171214161738-f41d11cb25b7 h1:EPXcO2ZjMGLOutxl1/46KWn0XUP8AKpoWJ5tysr8uDI=
github.com/jeffallen/seekinghttp v0.0.0-20171214161738-f41d11cb25b7/go.mod h1:RjbA1N4AxqQGhffoNx8Pg+yhYMvSkl8r73d+UnaCef4=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
github.com/mattn/go-runewidth v0.0.3 h1:a+kO+98RDGEfo6asOGMmpodZq4FNtnGP54yps8BzLR4=
github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
github.com/mholt/archiver v3.1.0+incompatible h1:S1rFZ7umHtN6cG+6cusrfoXTMPqp6u/R89iKxBYJd4w=
github.com/mholt/archiver v3.1.0+incompatible/go.mod h1:Dh2dOXnSdiLxRiPoVfIr/fI1TwETms9B8CTWfeh7ROU=
github.com/nwaples/rardecode v1.0.0 h1:r7vGuS5akxOnR4JQSkko62RJ1ReCMXxQRPtxsiFMBOs=
github.com/nwaples/rardecode v1.0.0/go.mod h1:5DzqNKiOdpKKBH87u8VlvAnPZMXcGRhxWkRpHbbfGS0=
github.com/olekukonko/tablewriter v0.0.1 h1:b3iUnf1v+ppJiOfNX4yxxqfWKMQPZR5yoh8urCTFX88=
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v1.4.2 h1:3mYCb7aPxS/RU7TI1y4rkEn1oKmPRjNJLNEXgw7MH2I=
github.com/onsi/gomega v1.4.2/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pierrec/lz4 v2.0.5+incompatible h1:2xWsjqPFWcplujydGg4WmhC/6fZqK42wMM8aXeqhl0I=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pivotal-cf/go-pivnet v0.0.50 h1:E7MIsoKyIQcyH6vXd9cWDZRBeDdRhmqEWicZczXVXkk=
github.com/pivotal-cf/go-pivnet v0.0.50/go.mod h1:rvEzWli4NJQhX7Z3z0DiEQXsPwC+uE//eIKcpl7S1as=
github.com/pivotal-cf/jhanda v0.0.0-20181025233525-e6aa09a032df h1:0qMnOwc8HWxJYvsA6jE616dmQcuoJOCOAndIGjsMj3o=
github.com/pivotal-cf/jhanda v0.0.0-20181025233525-e6aa09a032df/go.mod h1:GNr2RBRX0Gs2FaJRi4KUrfQV32EhnjQ3Fj+nw87cx08=
github.com/pivotal-cf/kiln v0.0.0-20181201001855-3e8211a50c91 h1:kietCf8UDrMPGiA1UW6NR6riBLUVQsNaAJ4Xr2NB9kY=
github.com/pivotal-cf/kiln v0.0.0-20181201001855-3e8211a50c91/go.mod h1:dtX102okHXUUdK9XmlK5WYl2lR0VP0OLaYCiIowB17M=
github.com/pivotal-cf/om v0.0.0-20181130184206-81ba5acde680 h1:bQElu4y+5DKjxqDdLN+6RC8bfx2Gs6sFJ4k9j1tKCnM=
github.com/pivotal-cf/om v0.0.0-20181130184206-81ba5acde680/go.mod h1:lvUXUJbWlZpq3odWwJ67T2IbKSNxkvUuLOooTFo98t8=
github.com/pivotal-cf/pivnet-cli v0.0.55 h1:R8mnLHUVb9DWuVqHdmkLCltG7bUTJq9nj5OexPt5Y2s=
github.com/pivotal-cf/pivnet-cli v0.0.55/go.mod h1:GIenTUfi8rXtvDXnOuUMfQ+ZofegQ+7XG2Hby3jB0+4=
github.com/robdimsdale/sanitizer v0.0.0-20160522134901-ab2334cb7539/go.mod h1:tqCODtkKV+9Tfvt9JURvKCTxJ69bA/OU/QhsaQLK/rc=
github.com/shirou/gopsutil v0.0.0-20180927124308-a11c78ba2c13 h1:hzFIj+Ky1KX599VGAVY//20nam1rYKwQwNVix1sYhXo=
github.com/shirou/gopsutil v0.0.0-20180927124308-a11c78ba2c13/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/ulikunitz/xz v0.5.5 h1:pFrO0lVpTBXLpYw+pnLj6TbvHuyjXMfjGeCwSqCVwok=
github.com/ulikunitz/xz v0.5.5/go.mod h1:2bypXElzHzzJZwzH67Y6wb67pO62Rzfn7BSiF4ABRW8=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo=
github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos=
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181017193950-04a2e542c03f h1:4pRM7zYwpBjCnfA1jRmhItLxYJkaEnsmuAcRtA347DA=
golang.org/x/net v0.0.0-20181017193950-04a2e542c03f/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a h1:gOpx8G595UYyvj8UK4+OFyY4rx037g3fmfhe5SasG3U=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f h1:wMNYb4v58l5UBM7MYRLPG6ZhfOqbKu7X5eyFl8ZhKvA=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba h1:nZJIJPGow0Kf9bU9QTc1U6OXbs/7Hu4e+cNv+hxH+Zc=
golang.org/x/sys v0.0.0-20181011152604-fa43e7bc11ba/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
gopkg.in/alecthomas/kingpin.v2 v2.2.6 h1:jMFz6MfLP0/4fUyZle81rXUoxOBFi19VUFKVDOQfozc=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/cheggaaa/pb.v1 v1.0.26 h1:KbH37VyQGNNrLEz+fflXwuLLxnPNoWwUwBF783VJWUg=
gopkg.in/cheggaaa/pb.v1 v1.0.26/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=

17
main.go Normal file
View File

@ -0,0 +1,17 @@
package main
import (
"log"
"os"
"github.com/starkandwayne/pivy/commands"
kingpin "gopkg.in/alecthomas/kingpin.v2"
)
func main() {
logger := log.New(os.Stdout, "", 0)
app := kingpin.New("pivy", "PivNets little helper")
commands.Configure(logger, app)
kingpin.MustParse(app.Parse(os.Args[1:]))
}

32
om/sdk.go Normal file
View File

@ -0,0 +1,32 @@
package om
import (
"bytes"
"log"
"github.com/pivotal-cf/om/commands"
"github.com/pivotal-cf/om/commands/fakes"
"github.com/pivotal-cf/om/extractor"
)
type TileMetaData []byte
type TileConfigTemplate []byte
func TileMetaDataToConfigTemplate(data TileMetaData, placeholders bool) (TileConfigTemplate, error) {
metadataExtractor := &fakes.MetadataExtractor{}
b := &bytes.Buffer{}
logger := log.New(b, "", 0)
command := commands.NewConfigTemplate(metadataExtractor, logger)
metadataExtractor.ExtractMetadataReturns(extractor.Metadata{Raw: data}, nil)
args := []string{
"--product", "/not/used/but/required.pivotal",
}
if placeholders {
args = append(args, "--include-placeholders")
}
err := command.Execute(args)
if err != nil {
return []byte{}, err
}
return b.Bytes(), nil
}

185
pivnet/sdk.go Normal file
View File

@ -0,0 +1,185 @@
package pivnet
import (
"archive/zip"
"bytes"
"fmt"
"io"
"log"
"github.com/gobwas/glob"
"github.com/jeffallen/seekinghttp"
"github.com/mholt/archiver"
gopivnet "github.com/pivotal-cf/go-pivnet"
"github.com/pivotal-cf/go-pivnet/logshim"
"github.com/pivotal-cf/pivnet-cli/filter"
)
const (
retryAttempts = 5 // How many times to retry downloading a tile from PivNet
retryDelay = 5 // How long wait in between download retries
)
// Sdk interacts with the Pivotal Network API.
type Sdk struct {
logger *log.Logger
client gopivnet.Client
filter *filter.Filter
acceptEULA bool
}
// NewSdk creates a new Pivotal Network Sdk.
// It validates that the given apiToken is valid.
func NewSdk(apiToken string, acceptEULA bool, logger *log.Logger) (*Sdk, error) {
sdk := &Sdk{logger: logger, acceptEULA: acceptEULA}
cfg := gopivnet.ClientConfig{
Host: gopivnet.DefaultHost,
Token: apiToken,
}
sdk.client = gopivnet.NewClient(cfg, logshim.NewLogShim(logger, logger, false))
sdk.filter = filter.NewFilter(logshim.NewLogShim(logger, logger, false))
return sdk, sdk.checkCredentials()
}
func (s *Sdk) checkCredentials() error {
ok, err := s.client.Auth.Check()
if !ok {
return fmt.Errorf("authorizing pivnet credentials: %v", err)
}
return nil
}
// TileFile is an PivNet tile
type TileFile struct {
ProductSlug string
ReleaseVersion string
Glob string
}
// TileDownloadLink retrieves expiring download link for given Tile from PivNet.
func (s *Sdk) TileDownloadLink(tile TileFile) (downloadLink string, err error) {
releases, err := s.client.Releases.List(tile.ProductSlug)
if err != nil {
return "", err
}
releases, err = s.filter.ReleasesByVersion(
releases,
tile.ReleaseVersion,
)
if err != nil {
return "", err
}
if len(releases) != 1 {
return "", fmt.Errorf(
"Unable to find version %s for tile %s",
tile.ReleaseVersion,
tile.ProductSlug,
)
}
release := releases[0]
productFiles, err := s.client.ProductFiles.ListForRelease(
tile.ProductSlug,
release.ID,
)
if err != nil {
return "", err
}
productFiles, err = s.filter.ProductFileKeysByGlobs(
productFiles,
[]string{tile.Glob},
)
if err != nil {
return "", err
}
if len(productFiles) == 0 {
return "", fmt.Errorf(
"Unable find file with glob %s for tile %s",
tile.Glob,
tile.ProductSlug,
)
}
if len(productFiles) > 1 {
return "", fmt.Errorf(
"More then one file matched glob %s for tile %s",
tile.Glob,
tile.ProductSlug,
)
}
productFile := productFiles[0]
if s.acceptEULA {
err = s.client.EULA.Accept(tile.ProductSlug, release.ID)
if err != nil {
return "", err
}
}
link, err := productFile.DownloadLink()
if err != nil {
return "", err
}
fetcher := gopivnet.NewProductFileLinkFetcher(link, s.client)
downloadLink, err = fetcher.NewDownloadLink()
if err != nil {
return "", err
}
return downloadLink, nil
}
func (s *Sdk) DownloadTileMetaDataFromLink(link string) ([]byte, error) {
seek := seekinghttp.New(link)
size, err := seek.Size()
if err != nil {
return []byte{}, err
}
var DefaultZip = archiver.NewZip()
err = DefaultZip.Open(seek, size)
if err != nil {
return []byte{}, err
}
defer DefaultZip.Close()
metaData := new(bytes.Buffer)
for {
f, err := DefaultZip.Read()
if err == io.EOF {
break
}
if err != nil {
return []byte{}, err
}
zfh, ok := f.Header.(zip.FileHeader)
if !ok {
return []byte{},
fmt.Errorf("expected header to be zip.FileHeader but was %T", f.Header)
}
if glob.MustCompile("metadata/*.yml").Match(zfh.Name) {
metaData.ReadFrom(f)
break
}
err = f.Close()
if err != nil {
return []byte{}, err
}
}
return metaData.Bytes(), nil
}