diff --git a/go.mod b/go.mod
index f697426bf11..06bb72fde5e 100644
--- a/go.mod
+++ b/go.mod
@@ -36,6 +36,7 @@ require (
github.com/aws/aws-sdk-go v1.25.33 // indirect
github.com/blang/semver v3.5.1+incompatible
github.com/bmatcuk/doublestar v1.2.2
+ github.com/buildpacks/pack v0.6.0
github.com/creack/pty v1.1.9 // indirect
github.com/docker/cli v0.0.0-20191212191748-ebca1413117a
github.com/docker/distribution v2.7.1+incompatible
@@ -69,8 +70,6 @@ require (
github.com/krishicks/yaml-patch v0.0.10
github.com/markbates/inflect v1.0.4 // indirect
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a // indirect
- github.com/mattn/go-colorable v0.1.4 // indirect
- github.com/mattn/go-isatty v0.0.10 // indirect
github.com/mitchellh/go-homedir v1.1.0
github.com/moby/buildkit v0.6.3
github.com/onsi/ginkgo v1.10.3 // indirect
diff --git a/go.sum b/go.sum
index 96314957d36..1efcede9ce1 100644
--- a/go.sum
+++ b/go.sum
@@ -13,22 +13,16 @@ cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg
cloud.google.com/go v0.49.0 h1:CH+lkubJzcPYB1Ggupcq0+k8Ni2ILdG2lYjDIgavDBQ=
cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
-cloud.google.com/go/bigquery v1.2.0 h1:5wdyDJgqmqlAqzIhN6hY9E2vqE9M545UVLU1rrSr/x4=
cloud.google.com/go/bigquery v1.2.0/go.mod h1:Cqg1qaK3wRdys8sKlow0jIBVFwSTiHoFx5um4ujCpyE=
-cloud.google.com/go/datastore v1.0.0 h1:Kt+gOPPp2LEPWp8CSfxhsM8ik9CcyE/gYu+0r+RnZvM=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
-cloud.google.com/go/pubsub v1.0.1 h1:W9tAK3E57P75u0XLLR82LZyw8VpAnhmyTOxW9qzmyj8=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.4.0 h1:KDdqY5VTXBTqpSbctVTt0mVvfanP6JZzNzLE0qNY100=
cloud.google.com/go/storage v1.4.0/go.mod h1:ZusYJWlOshgSBGbt6K3GnB3MT3H1xs2id9+TCl4fDBA=
-contrib.go.opencensus.io/exporter/prometheus v0.1.0 h1:SByaIoWwNgMdPSgl5sMqM2KDE5H/ukPWBRo314xiDvg=
contrib.go.opencensus.io/exporter/prometheus v0.1.0/go.mod h1:cGFniUXGZlKRjzOyuZJ6mgB+PgBcCIa79kEKR8YCW+A=
-contrib.go.opencensus.io/exporter/stackdriver v0.12.8 h1:iXI5hr7pUwMx0IwMphpKz5Q3If/G5JiWFVZ5MPPxP9E=
contrib.go.opencensus.io/exporter/stackdriver v0.12.8/go.mod h1:XyyafDnFOsqoxHJgTFycKZMrRUrPThLh2iYTJF6uoO0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/azure-sdk-for-go v19.1.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
-github.com/Azure/azure-sdk-for-go v36.1.0+incompatible h1:smHlbChr/JDmsyUqELZXLs0YIgpXecIGdUibuc2983s=
github.com/Azure/azure-sdk-for-go v36.1.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
@@ -41,11 +35,8 @@ github.com/Azure/go-autorest/autorest/adal v0.6.1-0.20190906230412-69b4126ece6b
github.com/Azure/go-autorest/autorest/adal v0.6.1-0.20190906230412-69b4126ece6b/go.mod h1:Z6vX6WXXuyieHAXwMj0S6HY6e6wcHn37qQMBQlvY3lc=
github.com/Azure/go-autorest/autorest/date v0.2.1-0.20190906230412-69b4126ece6b h1:ZlCWQMu0oy+olcLYnRGErn1opwgFgh5vyL0K65oXKiA=
github.com/Azure/go-autorest/autorest/date v0.2.1-0.20190906230412-69b4126ece6b/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g=
-github.com/Azure/go-autorest/autorest/mocks v0.3.1-0.20190906230412-69b4126ece6b h1:vLvMiJlO7uZ3Kr0LM4WtT37CbeCgX1Nu0PS6hdqvS9w=
github.com/Azure/go-autorest/autorest/mocks v0.3.1-0.20190906230412-69b4126ece6b/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM=
-github.com/Azure/go-autorest/autorest/to v0.3.0 h1:zebkZaadz7+wIQYgC7GXaz3Wb28yKYfVkkBKwc38VF8=
github.com/Azure/go-autorest/autorest/to v0.3.0/go.mod h1:MgwOyqaIuKdG4TL/2ywSsIWKAfJfgHDo8ObuUk3t5sA=
-github.com/Azure/go-autorest/autorest/validation v0.2.0 h1:15vMO4y76dehZSq7pAaOLQxC6dZYsSrj2GQpflyM/L4=
github.com/Azure/go-autorest/autorest/validation v0.2.0/go.mod h1:3EEqHnBxQGHXRYq3HT1WyXAvT7LLY3tl70hw6tQIbjI=
github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY=
github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc=
@@ -57,6 +48,8 @@ github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
+github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
+github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.13-0.20190408173621-84b4ab48a507/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
@@ -64,29 +57,31 @@ github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jB
github.com/Microsoft/hcsshim v0.8.5/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/Netflix/go-expect v0.0.0-20180615182759-c93bf25de8e8/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
-github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667 h1:l2RCK7mjLhjfZRIcCXTVHI34l67IRtKASBjusViLzQ0=
github.com/Netflix/go-expect v0.0.0-20190729225929-0e00d9168667/go.mod h1:oX5x61PbNXchhh0oikYAH+4Pcfw5LKv21+Jnpr6r6Pc=
+github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/PuerkitoBio/purell v1.0.0/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20160726150825-5bd2802263f2/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
-github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs=
github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q=
github.com/apache/thrift v0.0.0-20161221203622-b2a4d4ae21c7/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012 h1:r9k3B0K539tmbDOdyCIuz/6qtn8q+lp+qvEStcFUIdM=
+github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012/go.mod h1:Ls949n1HFtXfbDcjiTTFQqkVUrte0puoIBfO3SVgwOA=
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
+github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
-github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio=
github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs=
github.com/aws/aws-sdk-go v1.15.90/go.mod h1:es1KtYUFs7le0xQ3rOihkuoVD90z7D0fR2Qm4S00/gU=
+github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
-github.com/aws/aws-sdk-go v1.25.33 h1:8muvpP+Bq5e0CDkM9PDZ6tN74fVUq5v3zSCRaZ93ykM=
github.com/aws/aws-sdk-go v1.25.33/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
@@ -96,7 +91,12 @@ github.com/blang/semver v3.5.1+incompatible h1:cQNTCjp13qL8KC3Nbxr/y2Bqb63oX6wdn
github.com/blang/semver v3.5.1+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk=
github.com/bmatcuk/doublestar v1.2.2 h1:oC24CykoSAB8zd7XgruHo33E0cHJf/WhQA/7BeXj+x0=
github.com/bmatcuk/doublestar v1.2.2/go.mod h1:wiQtGV+rzVYxB7WIlirSN++5HPtPlXEo9MEoZQC/PmE=
-github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
+github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b h1:SDsB0hJtURA+5i5vIjLntzRNPEqdoz6q+0MShCWdctw=
+github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b/go.mod h1:E3lXJcNXcRefJQAHW5rqboonet+jtOml4qImbJhYGAo=
+github.com/buildpacks/lifecycle v0.5.1-0.20191217221752-3b74c943b7b3 h1:15zYyFmNbrtx5MmyVEKVgY2/eearqEqGJXLCjmvUo58=
+github.com/buildpacks/lifecycle v0.5.1-0.20191217221752-3b74c943b7b3/go.mod h1:ZIuIs9B6tjAW4dthhltKVyEUlhRfFWWix9eqoInMGX4=
+github.com/buildpacks/pack v0.6.0 h1:hOnUrwmFQp5OxxrEp6qIxWVtqjXypJ0g31JuKRUGrLU=
+github.com/buildpacks/pack v0.6.0/go.mod h1:5YXVrPFdS9CAQWS5iOcMhk3ul5YCMw4EvZr2pIecO7A=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/cespare/xxhash/v2 v2.1.0 h1:yTUvW7Vhb89inJ+8irsUqiWjh8iT6sQPZiQzI6ReGkA=
github.com/cespare/xxhash/v2 v2.1.0/go.mod h1:dgIUBU3pDso/gPgZ1osOZ0iQf77oPR28Tjxl5dIMyVM=
@@ -121,13 +121,14 @@ github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3Ee
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
-github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v0.0.0-20151105211317-5215b55f46b2/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
+github.com/dgodd/dockerdial v1.0.1 h1:6XixGQxeytsIdVsbI4y+EHuv8QcxxH6ySJZLkm3jk5o=
+github.com/dgodd/dockerdial v1.0.1/go.mod h1:MJmK56eTylC3KU7DR6bc3k9jmbpURO8rDOsGbfj+c6o=
github.com/dgrijalva/jwt-go v0.0.0-20160705203006-01aeca54ebda/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
@@ -135,6 +136,7 @@ github.com/docker/cli v0.0.0-20190321234815-f40f9c240ab0/go.mod h1:JLrzqnKDaYBop
github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/cli v0.0.0-20191212191748-ebca1413117a h1:rgpgmLocRiSIM3zdtVgJcyvH7S2cSiIPtL7LvFY8K/0=
github.com/docker/cli v0.0.0-20191212191748-ebca1413117a/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v0.0.0-20180327202408-83389a148052/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1-0.20190205005809-0d3efadf0154+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
@@ -151,20 +153,18 @@ github.com/docker/go-events v0.0.0-20170721190031-9461782956ad/go.mod h1:Uw6Uezg
github.com/docker/go-metrics v0.0.1 h1:AgB/0SvBxihN0X8OR4SjsblXkbMvalQ8cjmtKQ2rQV8=
github.com/docker/go-metrics v0.0.1/go.mod h1:cG1hvH2utMXtqgqqYE9plW6lDxS3/5ayHzueweSI3Vw=
github.com/docker/go-units v0.3.1/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docker/libnetwork v0.8.0-dev.2.0.20190604151032-3c26b4e7495e/go.mod h1:93m0aTqz6z+g32wla4l4WxTrdtvBRmVzYRkYvasA5Z8=
-github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7 h1:UhxFibDNY/bfvqU5CAUmr9zpesgbU6SWc8/B4mflAE4=
github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNEkKy96OOhEzfZl+yxihPEzKnqJwvfuSUqbZE=
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s=
github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
-github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484 h1:pEtiCjIXx3RvGjlUJuCNxNOw0MNblyR9Wi+vJGBFh+8=
github.com/elazarl/goproxy v0.0.0-20191011121108-aa519ddbe484/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
-github.com/elazarl/goproxy/ext v0.0.0-20191011121108-aa519ddbe484 h1:aBgSK7SOjFeL1wfzfbIb/pkPpfRr6EP7b1Af4o/xkpU=
github.com/elazarl/goproxy/ext v0.0.0-20191011121108-aa519ddbe484/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
@@ -178,15 +178,13 @@ github.com/evanphx/json-patch v4.5.0+incompatible h1:ouOWdg56aJriqS0huScTkVXPC5I
github.com/evanphx/json-patch v4.5.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
-github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -209,7 +207,6 @@ github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/gobuffalo/envy v1.6.5/go.mod h1:N+GkhhZ/93bGZc6ZKhJLP6+m+tCNPKwgSpH9kaifseQ=
-github.com/gobuffalo/envy v1.7.1 h1:OQl5ys5MBea7OGCdvPbBJWRgnhC/fGona6QKfvFeau8=
github.com/gobuffalo/envy v1.7.1/go.mod h1:FurDp9+EDPE4aIUS3ZLyD+7/9fpx7YRt/ukY6jIHf0w=
github.com/godbus/dbus v4.1.0+incompatible/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw=
github.com/gofrs/flock v0.7.0/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU=
@@ -218,6 +215,7 @@ github.com/gogo/protobuf v0.0.0-20171007142547-342cbe0a0415/go.mod h1:r8qH/GZQm5
github.com/gogo/protobuf v1.0.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
github.com/gogo/protobuf v1.3.1 h1:DqDEcV5aeaTmdFBePNpYsp3FlcVH/2ISVVM9Qf8PSls=
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
@@ -227,8 +225,10 @@ github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4er
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9 h1:uHTyIjqVhYRhLbJ8nIiOJHkEZZ+5YoOsAbD3sk82NiE=
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
+github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/protobuf v0.0.0-20161109072736-4bd1920723d7/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
@@ -246,6 +246,7 @@ github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5a
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1 h1:Xye71clBPdm5HgqGwUkwhbynsUJZhDbS20FvLhQ2izg=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af/go.mod h1:9kIomAeXUmwhqeYS2zoEuQ0sc2GOVmNW7t3y9aNQL1o=
github.com/google/go-containerregistry v0.0.0-20191218175032-34fb8ff33bed h1:0AwV9UBwwKPKrfpTYLOKr8ymevanUxrsSEkAo0uU9aA=
github.com/google/go-containerregistry v0.0.0-20191218175032-34fb8ff33bed/go.mod h1:rodaC7jYStJ2mjR8Y+5a/jCzcRPFRH74KmqSnJC88co=
github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
@@ -256,7 +257,6 @@ github.com/google/gofuzz v0.0.0-20161122191042-44d81051d367/go.mod h1:HP5RmnzzSN
github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
github.com/google/gofuzz v1.0.0 h1:A8PeW59pxE9IoFRqBp37U+mSNaQoZ46F1f0f863XSXw=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
-github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
@@ -275,6 +275,8 @@ github.com/googleapis/gnostic v0.3.1/go.mod h1:on+2t9HRStVgn95RSsFWFz+6Q0Snyqv1a
github.com/gophercloud/gophercloud v0.0.0-20190126172459-c818fa66e4c8/go.mod h1:3WdhXV3rUYy9p6AUW8d94kr+HS62Y4VL9mBnFxsD8q4=
github.com/gophercloud/gophercloud v0.6.0 h1:Xb2lcqZtml1XjgYZxbeayEemq7ASbeTp09m36gQFpEU=
github.com/gophercloud/gophercloud v0.6.0/go.mod h1:GICNByuaEBibcjmjvI7QvYJSZEbGkcYwAR7EZK2WMqM=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
github.com/gotestyourself/gotestyourself v2.2.0+incompatible/go.mod h1:zZKM6oeNM8k+FRljX1mnzVYeS8wiGgQyvST1/GafPbY=
@@ -292,10 +294,12 @@ github.com/hashicorp/golang-lru v0.5.3 h1:YPkqC67at8FYaadspW/6uE0COsBxS2656RLEr8
github.com/hashicorp/golang-lru v0.5.3/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/uuid v0.0.0-20160311170451-ebb0a03e909c/go.mod h1:fHzc09UnyJyqyW+bFuq864eh+wC7dj65aXmXLRe5to0=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0=
+github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi1wLU=
github.com/hinshun/vt10x v0.0.0-20180616224451-1954e6464174/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
-github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c h1:kp3AxgXgDOmIJFR7bIwqFhwJ2qWar8tEQSE5XXhCfVk=
github.com/hinshun/vt10x v0.0.0-20180809195222-d55458df857c/go.mod h1:DqJ97dSdRW1W22yXSB90986pcOyQ7r45iio1KN2ez1A=
-github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ=
@@ -308,12 +312,11 @@ github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOl
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
-github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
github.com/joefitzgerald/rainbow-reporter v0.1.0/go.mod h1:481CNgqmVHQZzdIbN52CupLJyoVwB10FQ/IQlF1pdL8=
-github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
github.com/json-iterator/go v0.0.0-20180612202835-f2b4162afba3/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
@@ -330,19 +333,18 @@ github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNU
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd h1:Coekwdh0v2wtGp9Gmz1Ze3eVRAWJMLokvN3QjdzCHLY=
github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
-github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
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/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
-github.com/kr/pty v1.1.8 h1:AkaSdXYQOWeaO3neb8EM634ahkXXe3jYbVh/F9lq+GI=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
-github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/krishicks/yaml-patch v0.0.10 h1:H4FcHpnNwVmw8u0MjPRjWyIXtco6zM2F78t+57oNM3E=
github.com/krishicks/yaml-patch v0.0.10/go.mod h1:Sm5TchwZS6sm7RJoyg87tzxm2ZcKzdRE4Q7TjNhPrME=
@@ -353,14 +355,16 @@ github.com/mailru/easyjson v0.0.0-20160728113105-d5b7844b561a/go.mod h1:C1wdFJiN
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.7.0/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs=
-github.com/markbates/inflect v1.0.4 h1:5fh1gzTFhfae06u3hzHYO9xe3l3v3nW5Pwt3naLTP5g=
github.com/markbates/inflect v1.0.4/go.mod h1:1fR9+pO2KHEO9ZRtto13gDwwZaAKstQzferVeWqbgNs=
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a h1:+J2gw7Bw77w/fbK7wnNJJDKmw1IbWft2Ul5BzrG1Qm8=
github.com/mattbaird/jsonpatch v0.0.0-20171005235357-81af80346b1a/go.mod h1:M1qoD/MqPgTZIk0EWKB38wE28ACRfVcn+cU08jyArI0=
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
+github.com/mattn/go-isatty v0.0.5/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 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
@@ -374,6 +378,8 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ=
+github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e h1:Qa6dnn8DlasdXRnacluu8HzPts0S1I9zvvUPDbBnXFI=
+github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/buildkit v0.6.3 h1:2eFVHDz1E9uyMsbquywvjPIZ0yHT58HWCcn0K9qavWM=
github.com/moby/buildkit v0.6.3/go.mod h1:JKVImCzxztxvULr5P6ZiBfA/B2P+ZpR6UHxOXQn4KiU=
@@ -395,7 +401,6 @@ github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+W
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
-github.com/onsi/ginkgo v1.10.3 h1:OoxbjfXVZyod1fmWYhI7SEyaD8B00ynP3T+D5GiyHOY=
github.com/onsi/ginkgo v1.10.3/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
@@ -452,16 +457,19 @@ github.com/rakyll/statik v0.1.6/go.mod h1:OEi9wJV/fMUAGx1eNjq75DKDsJVuEv1U0oYdX6
github.com/remyoudompheng/bigfft v0.0.0-20170806203942-52369c62f446/go.mod h1:uYEyJGbgTkfkS4+E/PavXkNJcbFIpEtjt2B0KDQ5+9M=
github.com/rjeczalik/notify v0.9.2 h1:MiTWrPj55mNDHEiIX5YUSKefw/+lCQVoAFmD6oQm5w8=
github.com/rjeczalik/notify v0.9.2/go.mod h1:aErll2f0sUX9PXZnVNyeiObbmTlk5jnMoCa4QEjJeqM=
+github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
-github.com/rogpeppe/go-internal v1.3.2 h1:XU784Pr0wdahMY2bYcyK6N1KuaRAdLtqD4qd8D18Bfs=
github.com/rogpeppe/go-internal v1.3.2/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
+github.com/sclevine/spec v1.0.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
github.com/sclevine/spec v1.2.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
+github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
+github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
github.com/segmentio/textio v1.2.0 h1:Ug4IkV3kh72juJbG8azoSBlgebIbUUxVNrfFcKHfTSQ=
github.com/segmentio/textio v1.2.0/go.mod h1:+Rb7v0YVODP+tK5F7FD9TCkV7gOYx9IgLHWiqtvY8ag=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
@@ -470,11 +478,15 @@ github.com/serialx/hashring v0.0.0-20190422032157-8b2912629002/go.mod h1:/yeG0My
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.0.3/go.mod h1:pMByvHTf9Beacp5x1UXfOR9xyW/9antXMhjMPG0dEzc=
+github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.3.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
@@ -501,6 +513,10 @@ github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81P
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tektoncd/pipeline v0.5.1-0.20190731183258-9d7e37e85bf8 h1:NftWnvqs4oGBatJExafxwZ/GzQa2+U3CZU4QKEcmWKA=
github.com/tektoncd/pipeline v0.5.1-0.20190731183258-9d7e37e85bf8/go.mod h1:IZzJdiX9EqEMuUcgdnElozdYYRh0/ZRC+NKMLj1K3Yw=
+github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
+github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
github.com/tonistiigi/fsutil v0.0.0-20190819224149-3d2716dd0a4d/go.mod h1:pzh7kdwkDRh+Bx8J30uqaKJ1M4QrSH/um8fcIXeM8rc=
github.com/tonistiigi/units v0.0.0-20180711220420-6950e57a87ea/go.mod h1:WPnis/6cRcDZSUvVmezrxJPkiO87ThFYsoUiMwWNDJk=
github.com/uber/jaeger-client-go v0.0.0-20180103221425-e02c85f9069e/go.mod h1:WVhlPFC8FDjOFMMWRy2pZqQJSXxYSwNYOkTr/Z6d3Kk=
@@ -518,14 +534,10 @@ go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.1/go.mod h1:Ap50jQcDJrx6rB6VgeeFPtuPIf3wMRvRfrfYDO6+BmA=
go.opencensus.io v0.22.2 h1:75k/FF0Q2YM8QYo07VPddOLBslDt1MZOdEslOHvmzAs=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
-go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY=
go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ=
go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
-go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E=
go.uber.org/multierr v1.4.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4=
-go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4=
go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA=
-go.uber.org/zap v1.12.0 h1:dySoUQPFBGj6xwjmBzageVL8jGi8uxc6bEmJQjA06bw=
go.uber.org/zap v1.12.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181025213731-e84da0312774/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
@@ -533,6 +545,7 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf
golang.org/x/crypto v0.0.0-20190123085648-057139ce5d2b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -551,6 +564,7 @@ golang.org/x/exp v0.0.0-20191127035308-9964a5a80460 h1:zNL062UG4d0GC48Bhm+lEI9lT
golang.org/x/exp v0.0.0-20191127035308-9964a5a80460/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
+golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -568,6 +582,7 @@ golang.org/x/net v0.0.0-20170114055629-f2499483f923/go.mod h1:mL1N/T3taQHkDXs73r
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=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -608,6 +623,7 @@ golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5h
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180926160741-c2ed4eda69e7/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -642,6 +658,8 @@ golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxb
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0 h1:/5xXl8Y5W96D+TtHSlonuFqGHIWVuyCkGJLwGh9JJFs=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181011042414-1f849cf54d09/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -664,6 +682,7 @@ golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190920225731-5eefd052ad72/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.0.0-20191017205301-920acffc3e65/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191028194131-d78a1f2664a0/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
@@ -699,6 +718,7 @@ google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRn
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
@@ -707,6 +727,7 @@ google.golang.org/genproto v0.0.0-20191028173616-919d9bdd9fe6/go.mod h1:n3cpQtvx
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216205247-b31c10ee225f h1:0RYv5T9ZdroAqqfM2taEB0nJrArv0X1JpIdgUmY4xg8=
google.golang.org/genproto v0.0.0-20191216205247-b31c10ee225f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
+google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
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.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
@@ -721,10 +742,8 @@ gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4
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/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
-gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
gopkg.in/inf.v0 v0.9.0/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
@@ -732,11 +751,9 @@ gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/src-d/go-billy.v4 v4.3.2 h1:0SQA1pRztfTFx2miS8sA97XvooFeNOmvUenF4o0EcVg=
gopkg.in/src-d/go-billy.v4 v4.3.2/go.mod h1:nDjArDMp+XMs1aFAESLRjfGSgfvoYN0hDfzEk0GjC98=
-gopkg.in/src-d/go-git-fixtures.v3 v3.5.0 h1:ivZFOIltbce2Mo8IjzUHAFoq/IylO9WHhNOAJK+LsJg=
gopkg.in/src-d/go-git-fixtures.v3 v3.5.0/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g=
gopkg.in/src-d/go-git.v4 v4.13.1 h1:SRtFyV8Kxc0UP7aCHcijOMQGPxHSmMOPrzulQWolkYE=
gopkg.in/src-d/go-git.v4 v4.13.1/go.mod h1:nx5NYcxdKxq5fpltdHnPa2Exj4Sx0EclMWZQbYDu2z8=
-gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME=
gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI=
@@ -747,8 +764,8 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.7 h1:VUgggvou5XRW9mHwD/yXxIYSMtY0zoKQf/v226p2nyo=
gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
-gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
@@ -773,13 +790,13 @@ k8s.io/klog v0.3.1/go.mod h1:Gq+BEi5rUBO/HRz0bTSXDUcqjScdoY3a9IHpCEIOOfk=
k8s.io/klog v0.4.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8=
k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I=
+k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/kube-openapi v0.0.0-20190228160746-b3a7cee44a30/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
k8s.io/kube-openapi v0.0.0-20190816220812-743ec37842bf/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a h1:UcxjrRMyNx/i/y8G7kPvLyy7rfbeuf1PYyBf973pgyU=
k8s.io/kube-openapi v0.0.0-20191107075043-30be4d16710a/go.mod h1:1TqjTSzOxsLGIKfj0lK8EeCP7K1iUG65v09OM0/WG5E=
k8s.io/kubectl v0.0.0-20190831163037-3b58a944563f h1:rngzSSBHZ0ofTBvPu8HT9R+EMc3PKE9XUD9DrK+QdAM=
k8s.io/kubectl v0.0.0-20190831163037-3b58a944563f/go.mod h1:/TM8X12sDkA1rdjpK4qMqSYiDZbicsgYIGjicJ6P4EU=
-k8s.io/kubernetes v1.12.10 h1:Ev14jntgqMAlW1Dyk++0dU76+Wb2FJ9VwopYK1R78m4=
k8s.io/kubernetes v1.12.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
k8s.io/metrics v0.0.0-20190831080339-bd7772846802/go.mod h1:98g4ghmWXz8M0qrhPme3ZnY3E/zPsSSbLlqOsw7WVa4=
k8s.io/utils v0.0.0-20190221042446-c2654d5206da/go.mod h1:8k8uAuAQ0rXslZKaEWd0c3oVhZz7sSzSiPnVZayjIX0=
diff --git a/pkg/skaffold/build/buildpacks/build_test.go b/pkg/skaffold/build/buildpacks/build_test.go
index 4f437031e78..3f519c02463 100644
--- a/pkg/skaffold/build/buildpacks/build_test.go
+++ b/pkg/skaffold/build/buildpacks/build_test.go
@@ -18,22 +18,35 @@ package buildpacks
import (
"context"
+ "io"
"io/ioutil"
"testing"
+ "github.com/buildpacks/pack"
+
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
"github.com/GoogleContainerTools/skaffold/testutil"
)
+type fakePack struct {
+ Opts pack.BuildOptions
+}
+
+func (f *fakePack) runPack(_ context.Context, _ io.Writer, opts pack.BuildOptions) error {
+ f.Opts = opts
+ return nil
+}
+
func TestBuild(t *testing.T) {
tests := []struct {
- description string
- artifact *latest.BuildpackArtifact
- tag string
- api *testutil.FakeAPIClient
- pushImages bool
- shouldErr bool
+ description string
+ artifact *latest.BuildpackArtifact
+ tag string
+ api *testutil.FakeAPIClient
+ pushImages bool
+ shouldErr bool
+ expectedOptions *pack.BuildOptions
}{
{
description: "success",
@@ -44,6 +57,14 @@ func TestBuild(t *testing.T) {
},
tag: "img:tag",
api: &testutil.FakeAPIClient{},
+ expectedOptions: &pack.BuildOptions{
+ AppPath: ".",
+ Builder: "my/builder",
+ RunImage: "my/run",
+ Env: map[string]string{},
+ Image: "img:latest",
+ NoPull: true,
+ },
},
{
description: "invalid ref",
@@ -66,20 +87,14 @@ func TestBuild(t *testing.T) {
},
tag: "img:tag",
api: &testutil.FakeAPIClient{},
- },
- {
- description: "force pull error",
- artifact: &latest.BuildpackArtifact{
- Builder: "my/builder",
- RunImage: "my/run",
- ForcePull: true,
- Dependencies: defaultBuildpackDependencies(),
+ expectedOptions: &pack.BuildOptions{
+ AppPath: ".",
+ Builder: "my/builder",
+ RunImage: "my/run",
+ Env: map[string]string{},
+ Image: "img:latest",
+ NoPull: false,
},
- tag: "img:tag",
- api: &testutil.FakeAPIClient{
- ErrImagePull: true,
- },
- shouldErr: true,
},
{
description: "push error",
@@ -111,6 +126,9 @@ func TestBuild(t *testing.T) {
for _, test := range tests {
testutil.Run(t, test.description, func(t *testutil.T) {
t.NewTempDir().Touch("file").Chdir()
+ pack := &fakePack{}
+ t.Override(&runPackFunc, pack.runPack)
+
test.api.
Add(test.artifact.Builder, "builderImageID").
Add(test.artifact.RunImage, "runImageID").
@@ -126,6 +144,9 @@ func TestBuild(t *testing.T) {
}, test.tag)
t.CheckError(test.shouldErr, err)
+ if test.expectedOptions != nil {
+ t.CheckDeepEqual(*test.expectedOptions, pack.Opts)
+ }
})
}
}
diff --git a/pkg/skaffold/build/buildpacks/lifecycle.go b/pkg/skaffold/build/buildpacks/lifecycle.go
index 9d1d4aa8d2b..15b4d3b641d 100644
--- a/pkg/skaffold/build/buildpacks/lifecycle.go
+++ b/pkg/skaffold/build/buildpacks/lifecycle.go
@@ -18,19 +18,21 @@ package buildpacks
import (
"context"
- "fmt"
"io"
- "path/filepath"
- "time"
+ "strings"
- "github.com/docker/docker/api/types/mount"
+ "github.com/buildpacks/pack"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/build/misc"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/docker"
"github.com/GoogleContainerTools/skaffold/pkg/skaffold/schema/latest"
- "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
+)
+
+// For testing
+var (
+ runPackFunc = runPack
)
func (b *Builder) build(ctx context.Context, out io.Writer, a *latest.Artifact, tag string) (string, error) {
@@ -48,17 +50,25 @@ func (b *Builder) build(ctx context.Context, out io.Writer, a *latest.Artifact,
builderImage := artifact.Builder
logrus.Debugln("Builder image", builderImage)
- if err := b.pull(ctx, out, builderImage, artifact.ForcePull); err != nil {
- return "", err
+ if !artifact.ForcePull {
+ if err := b.pull(ctx, out, builderImage); err != nil {
+ return "", err
+ }
}
- runImage, err := b.findRunImage(ctx, artifact, builderImage)
- if err != nil {
- return "", err
- }
- logrus.Debugln("Run image", runImage)
- if err := b.pull(ctx, out, runImage, artifact.ForcePull); err != nil {
- return "", err
+ runImage := artifact.RunImage
+ if !artifact.ForcePull {
+ // If ForcePull is true, we let pack find and pull the run image
+ var err error
+ runImage, err = b.findRunImage(ctx, artifact, builderImage)
+ if err != nil {
+ return "", err
+ }
+ logrus.Debugln("Run image", runImage)
+
+ if err := b.pull(ctx, out, runImage); err != nil {
+ return "", err
+ }
}
logrus.Debugln("Evaluate env variables")
@@ -67,89 +77,44 @@ func (b *Builder) build(ctx context.Context, out io.Writer, a *latest.Artifact,
return "", errors.Wrap(err, "unable to evaluate env variables")
}
- logrus.Debugln("Get dependencies")
- deps, err := GetDependencies(ctx, workspace, artifact)
- if err != nil {
+ if err := runPackFunc(ctx, out, pack.BuildOptions{
+ AppPath: workspace,
+ Builder: builderImage,
+ RunImage: runImage,
+ Env: envMap(env),
+ Image: latest,
+ NoPull: !artifact.ForcePull,
+ }); err != nil {
return "", err
}
- var paths []string
- for _, dep := range deps {
- paths = append(paths, filepath.Join(workspace, dep))
- }
-
- copyWorkspace := func(ctx context.Context, container string) error {
- uid := 1000
- gid := 1000
- modTime := time.Date(1980, time.January, 1, 0, 0, 1, 0, time.UTC)
+ return latest, nil
+}
- return b.localDocker.CopyToContainer(ctx, container, "/workspace", workspace, paths, uid, gid, modTime)
+func runPack(ctx context.Context, out io.Writer, opts pack.BuildOptions) error {
+ packClient, err := pack.NewClient(pack.WithLogger(NewLogger(out)))
+ if err != nil {
+ return errors.Wrap(err, "unable to create pack client")
}
- // These volumes store the state shared between build steps.
- // After the build, they are deleted.
- cacheID := util.RandomID()
- packWorkspace := volume(mount.TypeVolume, fmt.Sprintf("pack-%s.workspace", cacheID), "/workspace")
- layers := volume(mount.TypeVolume, fmt.Sprintf("pack-%s.layers", cacheID), "/layers")
-
- // These volumes are kept after the build and shared with all the builds.
- // They handle the caching of layer both for build time and run time.
- buildCache := volume(mount.TypeVolume, "pack-cache-skaffold.build", "/cache")
- launchCache := volume(mount.TypeVolume, "pack-cache-skaffold.launch", "/launch-cache")
+ return packClient.Build(ctx, opts)
+}
- // Some steps need access to the Docker socket to load/save images.
- dockerSocket := volume(mount.TypeBind, "/var/run/docker.sock", "/var/run/docker.sock")
+func envMap(env []string) map[string]string {
+ kv := make(map[string]string)
- defer func() {
- // Don't use ctx. It might have been cancelled by Ctrl-C
- if err := b.localDocker.VolumeRemove(context.Background(), packWorkspace.Source, true); err != nil {
- logrus.Warnf("unable to delete the docker volume [%s]", packWorkspace.Source)
- }
- if err := b.localDocker.VolumeRemove(context.Background(), layers.Source, true); err != nil {
- logrus.Warnf("unable to delete the docker volume [%s]", layers.Source)
- }
- }()
-
- if err := b.localDocker.ContainerRun(ctx, out,
- docker.ContainerRun{
- Image: builderImage,
- Command: []string{"/lifecycle/detector"},
- BeforeStart: copyWorkspace,
- Mounts: []mount.Mount{packWorkspace, layers},
- Env: env,
- }, docker.ContainerRun{
- Image: builderImage,
- Command: []string{"sh", "-c", "/lifecycle/restorer -path /cache && /lifecycle/analyzer -daemon " + latest},
- User: "root",
- Mounts: []mount.Mount{packWorkspace, layers, buildCache, dockerSocket},
- }, docker.ContainerRun{
- Image: builderImage,
- Command: []string{"/lifecycle/builder"},
- Mounts: []mount.Mount{packWorkspace, layers},
- Env: env,
- }, docker.ContainerRun{
- Image: builderImage,
- Command: []string{"sh", "-c", "/lifecycle/exporter -daemon -image " + runImage + " -launch-cache /launch-cache " + latest + " && /lifecycle/cacher -path /cache"},
- User: "root",
- Mounts: []mount.Mount{packWorkspace, layers, launchCache, buildCache, dockerSocket},
- },
- ); err != nil {
- return "", err
+ for _, e := range env {
+ parts := strings.SplitN(e, "=", 2)
+ kv[parts[0]] = parts[1]
}
- return latest, nil
-}
-
-func volume(mountType mount.Type, source, target string) mount.Mount {
- return mount.Mount{Type: mountType, Source: source, Target: target}
+ return kv
}
// pull makes sure the given image is pre-pulled.
-func (b *Builder) pull(ctx context.Context, out io.Writer, image string, force bool) error {
- if force || !b.localDocker.ImageExists(ctx, image) {
- if err := b.localDocker.Pull(ctx, out, image); err != nil {
- return err
- }
+func (b *Builder) pull(ctx context.Context, out io.Writer, image string) error {
+ if b.localDocker.ImageExists(ctx, image) {
+ return nil
}
- return nil
+ return b.localDocker.Pull(ctx, out, image)
}
diff --git a/pkg/skaffold/build/buildpacks/logger.go b/pkg/skaffold/build/buildpacks/logger.go
new file mode 100644
index 00000000000..f75dfdb136e
--- /dev/null
+++ b/pkg/skaffold/build/buildpacks/logger.go
@@ -0,0 +1,61 @@
+/*
+Copyright 2019 The Skaffold Authors
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package buildpacks
+
+import (
+ "io"
+
+ "github.com/sirupsen/logrus"
+
+ "github.com/buildpacks/pack/logging"
+)
+
+type logger struct {
+ *logrus.Logger
+ out io.Writer
+}
+
+func NewLogger(out io.Writer) logging.Logger {
+ return &logger{
+ Logger: logrus.StandardLogger(),
+ out: out,
+ }
+}
+
+func (l *logger) Debug(msg string) {
+ l.Logger.Debug(msg)
+}
+
+func (l *logger) Info(msg string) {
+ l.Logger.Info(msg)
+}
+
+func (l *logger) Warn(msg string) {
+ l.Logger.Warn(msg)
+}
+
+func (l *logger) Error(msg string) {
+ l.Logger.Error(msg)
+}
+
+func (l *logger) Writer() io.Writer {
+ return l.out
+}
+
+func (l *logger) IsVerbose() bool {
+ return false
+}
diff --git a/pkg/skaffold/docker/containers.go b/pkg/skaffold/docker/containers.go
deleted file mode 100644
index 9254d23ff42..00000000000
--- a/pkg/skaffold/docker/containers.go
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
-Copyright 2019 The Skaffold Authors
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package docker
-
-import (
- "context"
- "io"
- "time"
-
- "github.com/docker/docker/api/types"
- "github.com/docker/docker/api/types/container"
- "github.com/docker/docker/pkg/stdcopy"
-
- "github.com/GoogleContainerTools/skaffold/pkg/skaffold/util"
-)
-
-// ContainerRun runs a list of containers in sequence, stopping on the first error.
-// TODO: by properly interleaving calls to the Docker API, we could speed
-// things up by roughly 700ms.
-func (l *localDaemon) ContainerRun(ctx context.Context, out io.Writer, runs ...ContainerRun) error {
- for _, run := range runs {
- container, err := l.apiClient.ContainerCreate(ctx, &container.Config{
- Image: run.Image,
- Cmd: run.Command,
- User: run.User,
- Env: run.Env,
- }, &container.HostConfig{
- Mounts: run.Mounts,
- }, nil, "")
- if err != nil {
- return err
- }
-
- if run.BeforeStart != nil {
- run.BeforeStart(ctx, container.ID)
- }
-
- errRun := l.runAndLog(ctx, out, container.ID)
-
- // Don't use ctx. It might have been cancelled by Ctrl-C
- if err := l.apiClient.ContainerRemove(context.Background(), container.ID, types.ContainerRemoveOptions{Force: true}); err != nil {
- return err
- }
-
- if errRun != nil {
- return errRun
- }
- }
-
- return nil
-}
-
-func (l *localDaemon) runAndLog(ctx context.Context, out io.Writer, containerID string) error {
- if err := l.apiClient.ContainerStart(ctx, containerID, types.ContainerStartOptions{}); err != nil {
- return err
- }
-
- logs, err := l.apiClient.ContainerLogs(ctx, containerID, types.ContainerLogsOptions{
- ShowStdout: true,
- ShowStderr: true,
- Follow: true,
- })
- if err != nil {
- return err
- }
- defer logs.Close()
-
- _, err = stdcopy.StdCopy(out, out, logs)
- return err
-}
-
-// CopyToContainer copies files to a running container.
-func (l *localDaemon) CopyToContainer(ctx context.Context, container string, dest string, root string, paths []string, uid, gid int, modTime time.Time) error {
- r, w := io.Pipe()
- go func() {
- if err := util.CreateTarWithParents(w, root, paths, uid, gid, modTime); err != nil {
- w.CloseWithError(err)
- } else {
- w.Close()
- }
- }()
-
- return l.apiClient.CopyToContainer(ctx, container, dest, r, types.CopyToContainerOptions{})
-}
-
-// VolumeRemove removes a volume.
-func (l *localDaemon) VolumeRemove(ctx context.Context, volumeID string, force bool) error {
- return l.apiClient.VolumeRemove(ctx, volumeID, force)
-}
diff --git a/pkg/skaffold/docker/image.go b/pkg/skaffold/docker/image.go
index 7986c561174..21524756a40 100644
--- a/pkg/skaffold/docker/image.go
+++ b/pkg/skaffold/docker/image.go
@@ -24,7 +24,6 @@ import (
"sort"
"strings"
"sync"
- "time"
"github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/mount"
@@ -67,9 +66,6 @@ type LocalDaemon interface {
ImageRemove(ctx context.Context, image string, opts types.ImageRemoveOptions) ([]types.ImageDeleteResponseItem, error)
ImageExists(ctx context.Context, ref string) bool
Prune(ctx context.Context, out io.Writer, images []string, pruneChildren bool) error
- ContainerRun(ctx context.Context, out io.Writer, runs ...ContainerRun) error
- CopyToContainer(ctx context.Context, container string, dest string, root string, paths []string, uid, gid int, modTime time.Time) error
- VolumeRemove(ctx context.Context, volumeID string, force bool) error
}
type localDaemon struct {
diff --git a/pkg/skaffold/util/tar.go b/pkg/skaffold/util/tar.go
index 8df455319e0..bf14c8ede20 100644
--- a/pkg/skaffold/util/tar.go
+++ b/pkg/skaffold/util/tar.go
@@ -23,7 +23,6 @@ import (
"os"
"path/filepath"
"runtime"
- "time"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
@@ -59,40 +58,6 @@ func CreateTar(w io.Writer, root string, paths []string) error {
return nil
}
-func CreateTarWithParents(w io.Writer, root string, paths []string, uid, gid int, modTime time.Time) error {
- headerModifier := func(header *tar.Header) {
- header.ModTime = modTime
- header.Uid = uid
- header.Gid = gid
- header.Uname = ""
- header.Gname = ""
- }
-
- tw := tar.NewWriter(w)
- defer tw.Close()
-
- // Make sure parent folders are added before files
- // TODO(dgageot): this should probably also be done in CreateTar
- // but I'd rather not break things that people didn't complain about!
- added := map[string]bool{}
-
- for _, path := range paths {
- var parentsFirst []string
- for p := path; p != "." && !added[p]; p = filepath.Dir(p) {
- parentsFirst = append(parentsFirst, p)
- added[p] = true
- }
-
- for i := len(parentsFirst) - 1; i >= 0; i-- {
- if err := addFileToTar(root, parentsFirst[i], "", tw, headerModifier); err != nil {
- return err
- }
- }
- }
-
- return nil
-}
-
func CreateTarGz(w io.Writer, root string, paths []string) error {
gw := gzip.NewWriter(w)
defer gw.Close()
diff --git a/pkg/skaffold/util/tar_test.go b/pkg/skaffold/util/tar_test.go
index 668f53e2317..948de738b28 100644
--- a/pkg/skaffold/util/tar_test.go
+++ b/pkg/skaffold/util/tar_test.go
@@ -24,7 +24,6 @@ import (
"io/ioutil"
"runtime"
"testing"
- "time"
"github.com/GoogleContainerTools/skaffold/testutil"
)
@@ -62,46 +61,6 @@ func TestCreateTar(t *testing.T) {
})
}
-func TestCreateTarWithParents(t *testing.T) {
- testutil.Run(t, "", func(t *testutil.T) {
- files := map[string]string{
- "foo": "baz1",
- "bar/bat": "baz2",
- "bar/baz": "baz3",
- }
- _, paths := prepareFiles(t, files)
-
- var b bytes.Buffer
- err := CreateTarWithParents(&b, ".", paths, 10, 100, time.Now())
- t.CheckNoError(err)
-
- // Make sure the contents match.
- tarFiles := make(map[string]string)
- tr := tar.NewReader(&b)
- for {
- hdr, err := tr.Next()
- if err == io.EOF {
- break
- }
- t.CheckNoError(err)
- t.CheckDeepEqual(10, hdr.Uid)
- t.CheckDeepEqual(100, hdr.Gid)
-
- content, err := ioutil.ReadAll(tr)
- t.CheckNoError(err)
-
- tarFiles[hdr.Name] = string(content)
- }
-
- t.CheckDeepEqual(map[string]string{
- "foo": "baz1",
- "bar": "",
- "bar/bat": "baz2",
- "bar/baz": "baz3",
- }, tarFiles)
- })
-}
-
func TestCreateTarGz(t *testing.T) {
testutil.Run(t, "", func(t *testutil.T) {
files := map[string]string{
diff --git a/testutil/fake_image_api.go b/testutil/fake_image_api.go
index 56244fc6e4f..8926a805fbd 100644
--- a/testutil/fake_image_api.go
+++ b/testutil/fake_image_api.go
@@ -23,19 +23,14 @@ import (
"io"
"io/ioutil"
"os"
- "strconv"
"strings"
- "sync"
"github.com/docker/docker/api/types"
- containertypes "github.com/docker/docker/api/types/container"
- networktypes "github.com/docker/docker/api/types/network"
"github.com/docker/docker/api/types/registry"
"github.com/docker/docker/client"
reg "github.com/docker/docker/registry"
digest "github.com/opencontainers/go-digest"
v1 "github.com/opencontainers/image-spec/specs-go/v1"
- "github.com/pkg/errors"
)
type ContainerState int
@@ -58,10 +53,6 @@ type FakeAPIClient struct {
nextImageID int
Pushed map[string]string
Built []types.ImageBuildOptions
-
- nextContainerID int
- containerStates map[string]ContainerState
- containerLock sync.Mutex
}
func (f *FakeAPIClient) Add(tag, imageID string) *FakeAPIClient {
@@ -210,93 +201,6 @@ func (f *FakeAPIClient) ImageLoad(ctx context.Context, input io.Reader, quiet bo
}, nil
}
-func (f *FakeAPIClient) ContainerCreate(ctx context.Context, config *containertypes.Config, hostConfig *containertypes.HostConfig, networkingConfig *networktypes.NetworkingConfig, containerName string) (containertypes.ContainerCreateCreatedBody, error) {
- f.containerLock.Lock()
- defer f.containerLock.Unlock()
-
- f.nextContainerID++
- containerID := strconv.Itoa(f.nextContainerID)
-
- if f.containerStates == nil {
- f.containerStates = make(map[string]ContainerState)
- }
- f.containerStates[containerID] = Created
-
- return containertypes.ContainerCreateCreatedBody{
- ID: containerID,
- }, nil
-}
-
-func (f *FakeAPIClient) ContainerStart(ctx context.Context, container string, options types.ContainerStartOptions) error {
- f.containerLock.Lock()
- defer f.containerLock.Unlock()
-
- state, present := f.containerStates[container]
- if !present {
- return errors.New("not found")
- }
-
- if state == Started {
- return errors.New("already started")
- }
-
- f.containerStates[container] = Started
- return nil
-}
-
-func (f *FakeAPIClient) CopyToContainer(ctx context.Context, container, path string, content io.Reader, options types.CopyToContainerOptions) error {
- f.containerLock.Lock()
- defer f.containerLock.Unlock()
-
- state, present := f.containerStates[container]
- if !present {
- return errors.New("not found")
- }
-
- if state != Started {
- return errors.New("not started")
- }
-
- return nil
-}
-
-func (f *FakeAPIClient) ContainerLogs(ctx context.Context, container string, config types.ContainerLogsOptions) (io.ReadCloser, error) {
- f.containerLock.Lock()
- defer f.containerLock.Unlock()
-
- state, present := f.containerStates[container]
- if !present {
- return nil, errors.New("not found")
- }
-
- if state != Started {
- return nil, errors.New("not started")
- }
-
- return ioutil.NopCloser(strings.NewReader("")), nil
-}
-
-func (f *FakeAPIClient) ContainerRemove(ctx context.Context, container string, options types.ContainerRemoveOptions) error {
- f.containerLock.Lock()
- defer f.containerLock.Unlock()
-
- state, present := f.containerStates[container]
- if !present {
- return errors.New("not found")
- }
-
- if state != Started {
- return errors.New("not started")
- }
-
- delete(f.containerStates, container)
- return nil
-}
-
-func (f *FakeAPIClient) VolumeRemove(ctx context.Context, volumeID string, force bool) error {
- return nil
-}
-
func (f *FakeAPIClient) Close() error { return nil }
// TODO(dgageot): create something that looks more like an actual tar file.
diff --git a/vendor/github.com/Masterminds/semver/.travis.yml b/vendor/github.com/Masterminds/semver/.travis.yml
new file mode 100644
index 00000000000..3d9ebadb933
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/.travis.yml
@@ -0,0 +1,27 @@
+language: go
+
+go:
+ - 1.6.x
+ - 1.7.x
+ - 1.8.x
+ - 1.9.x
+ - 1.10.x
+ - tip
+
+# Setting sudo access to false will let Travis CI use containers rather than
+# VMs to run the tests. For more details see:
+# - http://docs.travis-ci.com/user/workers/container-based-infrastructure/
+# - http://docs.travis-ci.com/user/workers/standard-infrastructure/
+sudo: false
+
+script:
+ - make setup
+ - make test
+
+notifications:
+ webhooks:
+ urls:
+ - https://webhooks.gitter.im/e/06e3328629952dabe3e0
+ on_success: change # options: [always|never|change] default: always
+ on_failure: always # options: [always|never|change] default: always
+ on_start: never # options: [always|never|change] default: always
diff --git a/vendor/github.com/Masterminds/semver/CHANGELOG.md b/vendor/github.com/Masterminds/semver/CHANGELOG.md
new file mode 100644
index 00000000000..b888e20abaa
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/CHANGELOG.md
@@ -0,0 +1,86 @@
+# 1.4.2 (2018-04-10)
+
+## Changed
+- #72: Updated the docs to point to vert for a console appliaction
+- #71: Update the docs on pre-release comparator handling
+
+## Fixed
+- #70: Fix the handling of pre-releases and the 0.0.0 release edge case
+
+# 1.4.1 (2018-04-02)
+
+## Fixed
+- Fixed #64: Fix pre-release precedence issue (thanks @uudashr)
+
+# 1.4.0 (2017-10-04)
+
+## Changed
+- #61: Update NewVersion to parse ints with a 64bit int size (thanks @zknill)
+
+# 1.3.1 (2017-07-10)
+
+## Fixed
+- Fixed #57: number comparisons in prerelease sometimes inaccurate
+
+# 1.3.0 (2017-05-02)
+
+## Added
+- #45: Added json (un)marshaling support (thanks @mh-cbon)
+- Stability marker. See https://masterminds.github.io/stability/
+
+## Fixed
+- #51: Fix handling of single digit tilde constraint (thanks @dgodd)
+
+## Changed
+- #55: The godoc icon moved from png to svg
+
+# 1.2.3 (2017-04-03)
+
+## Fixed
+- #46: Fixed 0.x.x and 0.0.x in constraints being treated as *
+
+# Release 1.2.2 (2016-12-13)
+
+## Fixed
+- #34: Fixed issue where hyphen range was not working with pre-release parsing.
+
+# Release 1.2.1 (2016-11-28)
+
+## Fixed
+- #24: Fixed edge case issue where constraint "> 0" does not handle "0.0.1-alpha"
+ properly.
+
+# Release 1.2.0 (2016-11-04)
+
+## Added
+- #20: Added MustParse function for versions (thanks @adamreese)
+- #15: Added increment methods on versions (thanks @mh-cbon)
+
+## Fixed
+- Issue #21: Per the SemVer spec (section 9) a pre-release is unstable and
+ might not satisfy the intended compatibility. The change here ignores pre-releases
+ on constraint checks (e.g., ~ or ^) when a pre-release is not part of the
+ constraint. For example, `^1.2.3` will ignore pre-releases while
+ `^1.2.3-alpha` will include them.
+
+# Release 1.1.1 (2016-06-30)
+
+## Changed
+- Issue #9: Speed up version comparison performance (thanks @sdboyer)
+- Issue #8: Added benchmarks (thanks @sdboyer)
+- Updated Go Report Card URL to new location
+- Updated Readme to add code snippet formatting (thanks @mh-cbon)
+- Updating tagging to v[SemVer] structure for compatibility with other tools.
+
+# Release 1.1.0 (2016-03-11)
+
+- Issue #2: Implemented validation to provide reasons a versions failed a
+ constraint.
+
+# Release 1.0.1 (2015-12-31)
+
+- Fixed #1: * constraint failing on valid versions.
+
+# Release 1.0.0 (2015-10-20)
+
+- Initial release
diff --git a/vendor/github.com/Masterminds/semver/LICENSE.txt b/vendor/github.com/Masterminds/semver/LICENSE.txt
new file mode 100644
index 00000000000..0da4aeadb09
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/LICENSE.txt
@@ -0,0 +1,20 @@
+The Masterminds
+Copyright (C) 2014-2015, Matt Butcher and Matt Farina
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/Masterminds/semver/Makefile b/vendor/github.com/Masterminds/semver/Makefile
new file mode 100644
index 00000000000..a7a1b4e36de
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/Makefile
@@ -0,0 +1,36 @@
+.PHONY: setup
+setup:
+ go get -u gopkg.in/alecthomas/gometalinter.v1
+ gometalinter.v1 --install
+
+.PHONY: test
+test: validate lint
+ @echo "==> Running tests"
+ go test -v
+
+.PHONY: validate
+validate:
+ @echo "==> Running static validations"
+ @gometalinter.v1 \
+ --disable-all \
+ --enable deadcode \
+ --severity deadcode:error \
+ --enable gofmt \
+ --enable gosimple \
+ --enable ineffassign \
+ --enable misspell \
+ --enable vet \
+ --tests \
+ --vendor \
+ --deadline 60s \
+ ./... || exit_code=1
+
+.PHONY: lint
+lint:
+ @echo "==> Running linters"
+ @gometalinter.v1 \
+ --disable-all \
+ --enable golint \
+ --vendor \
+ --deadline 60s \
+ ./... || :
diff --git a/vendor/github.com/Masterminds/semver/README.md b/vendor/github.com/Masterminds/semver/README.md
new file mode 100644
index 00000000000..3e934ed71ec
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/README.md
@@ -0,0 +1,165 @@
+# SemVer
+
+The `semver` package provides the ability to work with [Semantic Versions](http://semver.org) in Go. Specifically it provides the ability to:
+
+* Parse semantic versions
+* Sort semantic versions
+* Check if a semantic version fits within a set of constraints
+* Optionally work with a `v` prefix
+
+[![Stability:
+Active](https://masterminds.github.io/stability/active.svg)](https://masterminds.github.io/stability/active.html)
+[![Build Status](https://travis-ci.org/Masterminds/semver.svg)](https://travis-ci.org/Masterminds/semver) [![Build status](https://ci.appveyor.com/api/projects/status/jfk66lib7hb985k8/branch/master?svg=true&passingText=windows%20build%20passing&failingText=windows%20build%20failing)](https://ci.appveyor.com/project/mattfarina/semver/branch/master) [![GoDoc](https://godoc.org/github.com/Masterminds/semver?status.svg)](https://godoc.org/github.com/Masterminds/semver) [![Go Report Card](https://goreportcard.com/badge/github.com/Masterminds/semver)](https://goreportcard.com/report/github.com/Masterminds/semver)
+
+## Parsing Semantic Versions
+
+To parse a semantic version use the `NewVersion` function. For example,
+
+```go
+ v, err := semver.NewVersion("1.2.3-beta.1+build345")
+```
+
+If there is an error the version wasn't parseable. The version object has methods
+to get the parts of the version, compare it to other versions, convert the
+version back into a string, and get the original string. For more details
+please see the [documentation](https://godoc.org/github.com/Masterminds/semver).
+
+## Sorting Semantic Versions
+
+A set of versions can be sorted using the [`sort`](https://golang.org/pkg/sort/)
+package from the standard library. For example,
+
+```go
+ raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
+ vs := make([]*semver.Version, len(raw))
+ for i, r := range raw {
+ v, err := semver.NewVersion(r)
+ if err != nil {
+ t.Errorf("Error parsing version: %s", err)
+ }
+
+ vs[i] = v
+ }
+
+ sort.Sort(semver.Collection(vs))
+```
+
+## Checking Version Constraints
+
+Checking a version against version constraints is one of the most featureful
+parts of the package.
+
+```go
+ c, err := semver.NewConstraint(">= 1.2.3")
+ if err != nil {
+ // Handle constraint not being parseable.
+ }
+
+ v, _ := semver.NewVersion("1.3")
+ if err != nil {
+ // Handle version not being parseable.
+ }
+ // Check if the version meets the constraints. The a variable will be true.
+ a := c.Check(v)
+```
+
+## Basic Comparisons
+
+There are two elements to the comparisons. First, a comparison string is a list
+of comma separated and comparisons. These are then separated by || separated or
+comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a
+comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
+greater than or equal to 4.2.3.
+
+The basic comparisons are:
+
+* `=`: equal (aliased to no operator)
+* `!=`: not equal
+* `>`: greater than
+* `<`: less than
+* `>=`: greater than or equal to
+* `<=`: less than or equal to
+
+_Note, according to the Semantic Version specification pre-releases may not be
+API compliant with their release counterpart. It says,_
+
+> _A pre-release version indicates that the version is unstable and might not satisfy the intended compatibility requirements as denoted by its associated normal version._
+
+_SemVer comparisons without a pre-release value will skip pre-release versions.
+For example, `>1.2.3` will skip pre-releases when looking at a list of values
+while `>1.2.3-alpha.1` will evaluate pre-releases._
+
+## Hyphen Range Comparisons
+
+There are multiple methods to handle ranges and the first is hyphens ranges.
+These look like:
+
+* `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
+* `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5`
+
+## Wildcards In Comparisons
+
+The `x`, `X`, and `*` characters can be used as a wildcard character. This works
+for all comparison operators. When used on the `=` operator it falls
+back to the pack level comparison (see tilde below). For example,
+
+* `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
+* `>= 1.2.x` is equivalent to `>= 1.2.0`
+* `<= 2.x` is equivalent to `<= 3`
+* `*` is equivalent to `>= 0.0.0`
+
+## Tilde Range Comparisons (Patch)
+
+The tilde (`~`) comparison operator is for patch level ranges when a minor
+version is specified and major level changes when the minor number is missing.
+For example,
+
+* `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
+* `~1` is equivalent to `>= 1, < 2`
+* `~2.3` is equivalent to `>= 2.3, < 2.4`
+* `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
+* `~1.x` is equivalent to `>= 1, < 2`
+
+## Caret Range Comparisons (Major)
+
+The caret (`^`) comparison operator is for major level changes. This is useful
+when comparisons of API versions as a major change is API breaking. For example,
+
+* `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
+* `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
+* `^2.3` is equivalent to `>= 2.3, < 3`
+* `^2.x` is equivalent to `>= 2.0.0, < 3`
+
+# Validation
+
+In addition to testing a version against a constraint, a version can be validated
+against a constraint. When validation fails a slice of errors containing why a
+version didn't meet the constraint is returned. For example,
+
+```go
+ c, err := semver.NewConstraint("<= 1.2.3, >= 1.4")
+ if err != nil {
+ // Handle constraint not being parseable.
+ }
+
+ v, _ := semver.NewVersion("1.3")
+ if err != nil {
+ // Handle version not being parseable.
+ }
+
+ // Validate a version against a constraint.
+ a, msgs := c.Validate(v)
+ // a is false
+ for _, m := range msgs {
+ fmt.Println(m)
+
+ // Loops over the errors which would read
+ // "1.3 is greater than 1.2.3"
+ // "1.3 is less than 1.4"
+ }
+```
+
+# Contribute
+
+If you find an issue or want to contribute please file an [issue](https://github.com/Masterminds/semver/issues)
+or [create a pull request](https://github.com/Masterminds/semver/pulls).
diff --git a/vendor/github.com/Masterminds/semver/appveyor.yml b/vendor/github.com/Masterminds/semver/appveyor.yml
new file mode 100644
index 00000000000..b2778df15a4
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/appveyor.yml
@@ -0,0 +1,44 @@
+version: build-{build}.{branch}
+
+clone_folder: C:\gopath\src\github.com\Masterminds\semver
+shallow_clone: true
+
+environment:
+ GOPATH: C:\gopath
+
+platform:
+ - x64
+
+install:
+ - go version
+ - go env
+ - go get -u gopkg.in/alecthomas/gometalinter.v1
+ - set PATH=%PATH%;%GOPATH%\bin
+ - gometalinter.v1.exe --install
+
+build_script:
+ - go install -v ./...
+
+test_script:
+ - "gometalinter.v1 \
+ --disable-all \
+ --enable deadcode \
+ --severity deadcode:error \
+ --enable gofmt \
+ --enable gosimple \
+ --enable ineffassign \
+ --enable misspell \
+ --enable vet \
+ --tests \
+ --vendor \
+ --deadline 60s \
+ ./... || exit_code=1"
+ - "gometalinter.v1 \
+ --disable-all \
+ --enable golint \
+ --vendor \
+ --deadline 60s \
+ ./... || :"
+ - go test -v
+
+deploy: off
diff --git a/vendor/github.com/Masterminds/semver/collection.go b/vendor/github.com/Masterminds/semver/collection.go
new file mode 100644
index 00000000000..a78235895fd
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/collection.go
@@ -0,0 +1,24 @@
+package semver
+
+// Collection is a collection of Version instances and implements the sort
+// interface. See the sort package for more details.
+// https://golang.org/pkg/sort/
+type Collection []*Version
+
+// Len returns the length of a collection. The number of Version instances
+// on the slice.
+func (c Collection) Len() int {
+ return len(c)
+}
+
+// Less is needed for the sort interface to compare two Version objects on the
+// slice. If checks if one is less than the other.
+func (c Collection) Less(i, j int) bool {
+ return c[i].LessThan(c[j])
+}
+
+// Swap is needed for the sort interface to replace the Version objects
+// at two different positions in the slice.
+func (c Collection) Swap(i, j int) {
+ c[i], c[j] = c[j], c[i]
+}
diff --git a/vendor/github.com/Masterminds/semver/constraints.go b/vendor/github.com/Masterminds/semver/constraints.go
new file mode 100644
index 00000000000..a41a6a7a4a8
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/constraints.go
@@ -0,0 +1,426 @@
+package semver
+
+import (
+ "errors"
+ "fmt"
+ "regexp"
+ "strings"
+)
+
+// Constraints is one or more constraint that a semantic version can be
+// checked against.
+type Constraints struct {
+ constraints [][]*constraint
+}
+
+// NewConstraint returns a Constraints instance that a Version instance can
+// be checked against. If there is a parse error it will be returned.
+func NewConstraint(c string) (*Constraints, error) {
+
+ // Rewrite - ranges into a comparison operation.
+ c = rewriteRange(c)
+
+ ors := strings.Split(c, "||")
+ or := make([][]*constraint, len(ors))
+ for k, v := range ors {
+ cs := strings.Split(v, ",")
+ result := make([]*constraint, len(cs))
+ for i, s := range cs {
+ pc, err := parseConstraint(s)
+ if err != nil {
+ return nil, err
+ }
+
+ result[i] = pc
+ }
+ or[k] = result
+ }
+
+ o := &Constraints{constraints: or}
+ return o, nil
+}
+
+// Check tests if a version satisfies the constraints.
+func (cs Constraints) Check(v *Version) bool {
+ // loop over the ORs and check the inner ANDs
+ for _, o := range cs.constraints {
+ joy := true
+ for _, c := range o {
+ if !c.check(v) {
+ joy = false
+ break
+ }
+ }
+
+ if joy {
+ return true
+ }
+ }
+
+ return false
+}
+
+// Validate checks if a version satisfies a constraint. If not a slice of
+// reasons for the failure are returned in addition to a bool.
+func (cs Constraints) Validate(v *Version) (bool, []error) {
+ // loop over the ORs and check the inner ANDs
+ var e []error
+ for _, o := range cs.constraints {
+ joy := true
+ for _, c := range o {
+ if !c.check(v) {
+ em := fmt.Errorf(c.msg, v, c.orig)
+ e = append(e, em)
+ joy = false
+ }
+ }
+
+ if joy {
+ return true, []error{}
+ }
+ }
+
+ return false, e
+}
+
+var constraintOps map[string]cfunc
+var constraintMsg map[string]string
+var constraintRegex *regexp.Regexp
+
+func init() {
+ constraintOps = map[string]cfunc{
+ "": constraintTildeOrEqual,
+ "=": constraintTildeOrEqual,
+ "!=": constraintNotEqual,
+ ">": constraintGreaterThan,
+ "<": constraintLessThan,
+ ">=": constraintGreaterThanEqual,
+ "=>": constraintGreaterThanEqual,
+ "<=": constraintLessThanEqual,
+ "=<": constraintLessThanEqual,
+ "~": constraintTilde,
+ "~>": constraintTilde,
+ "^": constraintCaret,
+ }
+
+ constraintMsg = map[string]string{
+ "": "%s is not equal to %s",
+ "=": "%s is not equal to %s",
+ "!=": "%s is equal to %s",
+ ">": "%s is less than or equal to %s",
+ "<": "%s is greater than or equal to %s",
+ ">=": "%s is less than %s",
+ "=>": "%s is less than %s",
+ "<=": "%s is greater than %s",
+ "=<": "%s is greater than %s",
+ "~": "%s does not have same major and minor version as %s",
+ "~>": "%s does not have same major and minor version as %s",
+ "^": "%s does not have same major version as %s",
+ }
+
+ ops := make([]string, 0, len(constraintOps))
+ for k := range constraintOps {
+ ops = append(ops, regexp.QuoteMeta(k))
+ }
+
+ constraintRegex = regexp.MustCompile(fmt.Sprintf(
+ `^\s*(%s)\s*(%s)\s*$`,
+ strings.Join(ops, "|"),
+ cvRegex))
+
+ constraintRangeRegex = regexp.MustCompile(fmt.Sprintf(
+ `\s*(%s)\s+-\s+(%s)\s*`,
+ cvRegex, cvRegex))
+}
+
+// An individual constraint
+type constraint struct {
+ // The callback function for the restraint. It performs the logic for
+ // the constraint.
+ function cfunc
+
+ msg string
+
+ // The version used in the constraint check. For example, if a constraint
+ // is '<= 2.0.0' the con a version instance representing 2.0.0.
+ con *Version
+
+ // The original parsed version (e.g., 4.x from != 4.x)
+ orig string
+
+ // When an x is used as part of the version (e.g., 1.x)
+ minorDirty bool
+ dirty bool
+ patchDirty bool
+}
+
+// Check if a version meets the constraint
+func (c *constraint) check(v *Version) bool {
+ return c.function(v, c)
+}
+
+type cfunc func(v *Version, c *constraint) bool
+
+func parseConstraint(c string) (*constraint, error) {
+ m := constraintRegex.FindStringSubmatch(c)
+ if m == nil {
+ return nil, fmt.Errorf("improper constraint: %s", c)
+ }
+
+ ver := m[2]
+ orig := ver
+ minorDirty := false
+ patchDirty := false
+ dirty := false
+ if isX(m[3]) {
+ ver = "0.0.0"
+ dirty = true
+ } else if isX(strings.TrimPrefix(m[4], ".")) || m[4] == "" {
+ minorDirty = true
+ dirty = true
+ ver = fmt.Sprintf("%s.0.0%s", m[3], m[6])
+ } else if isX(strings.TrimPrefix(m[5], ".")) {
+ dirty = true
+ patchDirty = true
+ ver = fmt.Sprintf("%s%s.0%s", m[3], m[4], m[6])
+ }
+
+ con, err := NewVersion(ver)
+ if err != nil {
+
+ // The constraintRegex should catch any regex parsing errors. So,
+ // we should never get here.
+ return nil, errors.New("constraint Parser Error")
+ }
+
+ cs := &constraint{
+ function: constraintOps[m[1]],
+ msg: constraintMsg[m[1]],
+ con: con,
+ orig: orig,
+ minorDirty: minorDirty,
+ patchDirty: patchDirty,
+ dirty: dirty,
+ }
+ return cs, nil
+}
+
+// Constraint functions
+func constraintNotEqual(v *Version, c *constraint) bool {
+ if c.dirty {
+
+ // If there is a pre-release on the version but the constraint isn't looking
+ // for them assume that pre-releases are not compatible. See issue 21 for
+ // more details.
+ if v.Prerelease() != "" && c.con.Prerelease() == "" {
+ return false
+ }
+
+ if c.con.Major() != v.Major() {
+ return true
+ }
+ if c.con.Minor() != v.Minor() && !c.minorDirty {
+ return true
+ } else if c.minorDirty {
+ return false
+ }
+
+ return false
+ }
+
+ return !v.Equal(c.con)
+}
+
+func constraintGreaterThan(v *Version, c *constraint) bool {
+
+ // An edge case the constraint is 0.0.0 and the version is 0.0.0-someprerelease
+ // exists. This that case.
+ if !isNonZero(c.con) && isNonZero(v) {
+ return true
+ }
+
+ // If there is a pre-release on the version but the constraint isn't looking
+ // for them assume that pre-releases are not compatible. See issue 21 for
+ // more details.
+ if v.Prerelease() != "" && c.con.Prerelease() == "" {
+ return false
+ }
+
+ return v.Compare(c.con) == 1
+}
+
+func constraintLessThan(v *Version, c *constraint) bool {
+ // If there is a pre-release on the version but the constraint isn't looking
+ // for them assume that pre-releases are not compatible. See issue 21 for
+ // more details.
+ if v.Prerelease() != "" && c.con.Prerelease() == "" {
+ return false
+ }
+
+ if !c.dirty {
+ return v.Compare(c.con) < 0
+ }
+
+ if v.Major() > c.con.Major() {
+ return false
+ } else if v.Minor() > c.con.Minor() && !c.minorDirty {
+ return false
+ }
+
+ return true
+}
+
+func constraintGreaterThanEqual(v *Version, c *constraint) bool {
+ // An edge case the constraint is 0.0.0 and the version is 0.0.0-someprerelease
+ // exists. This that case.
+ if !isNonZero(c.con) && isNonZero(v) {
+ return true
+ }
+
+ // If there is a pre-release on the version but the constraint isn't looking
+ // for them assume that pre-releases are not compatible. See issue 21 for
+ // more details.
+ if v.Prerelease() != "" && c.con.Prerelease() == "" {
+ return false
+ }
+
+ return v.Compare(c.con) >= 0
+}
+
+func constraintLessThanEqual(v *Version, c *constraint) bool {
+ // If there is a pre-release on the version but the constraint isn't looking
+ // for them assume that pre-releases are not compatible. See issue 21 for
+ // more details.
+ if v.Prerelease() != "" && c.con.Prerelease() == "" {
+ return false
+ }
+
+ if !c.dirty {
+ return v.Compare(c.con) <= 0
+ }
+
+ if v.Major() > c.con.Major() {
+ return false
+ } else if v.Minor() > c.con.Minor() && !c.minorDirty {
+ return false
+ }
+
+ return true
+}
+
+// ~*, ~>* --> >= 0.0.0 (any)
+// ~2, ~2.x, ~2.x.x, ~>2, ~>2.x ~>2.x.x --> >=2.0.0, <3.0.0
+// ~2.0, ~2.0.x, ~>2.0, ~>2.0.x --> >=2.0.0, <2.1.0
+// ~1.2, ~1.2.x, ~>1.2, ~>1.2.x --> >=1.2.0, <1.3.0
+// ~1.2.3, ~>1.2.3 --> >=1.2.3, <1.3.0
+// ~1.2.0, ~>1.2.0 --> >=1.2.0, <1.3.0
+func constraintTilde(v *Version, c *constraint) bool {
+ // If there is a pre-release on the version but the constraint isn't looking
+ // for them assume that pre-releases are not compatible. See issue 21 for
+ // more details.
+ if v.Prerelease() != "" && c.con.Prerelease() == "" {
+ return false
+ }
+
+ if v.LessThan(c.con) {
+ return false
+ }
+
+ // ~0.0.0 is a special case where all constraints are accepted. It's
+ // equivalent to >= 0.0.0.
+ if c.con.Major() == 0 && c.con.Minor() == 0 && c.con.Patch() == 0 &&
+ !c.minorDirty && !c.patchDirty {
+ return true
+ }
+
+ if v.Major() != c.con.Major() {
+ return false
+ }
+
+ if v.Minor() != c.con.Minor() && !c.minorDirty {
+ return false
+ }
+
+ return true
+}
+
+// When there is a .x (dirty) status it automatically opts in to ~. Otherwise
+// it's a straight =
+func constraintTildeOrEqual(v *Version, c *constraint) bool {
+ // If there is a pre-release on the version but the constraint isn't looking
+ // for them assume that pre-releases are not compatible. See issue 21 for
+ // more details.
+ if v.Prerelease() != "" && c.con.Prerelease() == "" {
+ return false
+ }
+
+ if c.dirty {
+ c.msg = constraintMsg["~"]
+ return constraintTilde(v, c)
+ }
+
+ return v.Equal(c.con)
+}
+
+// ^* --> (any)
+// ^2, ^2.x, ^2.x.x --> >=2.0.0, <3.0.0
+// ^2.0, ^2.0.x --> >=2.0.0, <3.0.0
+// ^1.2, ^1.2.x --> >=1.2.0, <2.0.0
+// ^1.2.3 --> >=1.2.3, <2.0.0
+// ^1.2.0 --> >=1.2.0, <2.0.0
+func constraintCaret(v *Version, c *constraint) bool {
+ // If there is a pre-release on the version but the constraint isn't looking
+ // for them assume that pre-releases are not compatible. See issue 21 for
+ // more details.
+ if v.Prerelease() != "" && c.con.Prerelease() == "" {
+ return false
+ }
+
+ if v.LessThan(c.con) {
+ return false
+ }
+
+ if v.Major() != c.con.Major() {
+ return false
+ }
+
+ return true
+}
+
+var constraintRangeRegex *regexp.Regexp
+
+const cvRegex string = `v?([0-9|x|X|\*]+)(\.[0-9|x|X|\*]+)?(\.[0-9|x|X|\*]+)?` +
+ `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
+ `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
+
+func isX(x string) bool {
+ switch x {
+ case "x", "*", "X":
+ return true
+ default:
+ return false
+ }
+}
+
+func rewriteRange(i string) string {
+ m := constraintRangeRegex.FindAllStringSubmatch(i, -1)
+ if m == nil {
+ return i
+ }
+ o := i
+ for _, v := range m {
+ t := fmt.Sprintf(">= %s, <= %s", v[1], v[11])
+ o = strings.Replace(o, v[0], t, 1)
+ }
+
+ return o
+}
+
+// Detect if a version is not zero (0.0.0)
+func isNonZero(v *Version) bool {
+ if v.Major() != 0 || v.Minor() != 0 || v.Patch() != 0 || v.Prerelease() != "" {
+ return true
+ }
+
+ return false
+}
diff --git a/vendor/github.com/Masterminds/semver/doc.go b/vendor/github.com/Masterminds/semver/doc.go
new file mode 100644
index 00000000000..e00f65eb73c
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/doc.go
@@ -0,0 +1,115 @@
+/*
+Package semver provides the ability to work with Semantic Versions (http://semver.org) in Go.
+
+Specifically it provides the ability to:
+
+ * Parse semantic versions
+ * Sort semantic versions
+ * Check if a semantic version fits within a set of constraints
+ * Optionally work with a `v` prefix
+
+Parsing Semantic Versions
+
+To parse a semantic version use the `NewVersion` function. For example,
+
+ v, err := semver.NewVersion("1.2.3-beta.1+build345")
+
+If there is an error the version wasn't parseable. The version object has methods
+to get the parts of the version, compare it to other versions, convert the
+version back into a string, and get the original string. For more details
+please see the documentation at https://godoc.org/github.com/Masterminds/semver.
+
+Sorting Semantic Versions
+
+A set of versions can be sorted using the `sort` package from the standard library.
+For example,
+
+ raw := []string{"1.2.3", "1.0", "1.3", "2", "0.4.2",}
+ vs := make([]*semver.Version, len(raw))
+ for i, r := range raw {
+ v, err := semver.NewVersion(r)
+ if err != nil {
+ t.Errorf("Error parsing version: %s", err)
+ }
+
+ vs[i] = v
+ }
+
+ sort.Sort(semver.Collection(vs))
+
+Checking Version Constraints
+
+Checking a version against version constraints is one of the most featureful
+parts of the package.
+
+ c, err := semver.NewConstraint(">= 1.2.3")
+ if err != nil {
+ // Handle constraint not being parseable.
+ }
+
+ v, _ := semver.NewVersion("1.3")
+ if err != nil {
+ // Handle version not being parseable.
+ }
+ // Check if the version meets the constraints. The a variable will be true.
+ a := c.Check(v)
+
+Basic Comparisons
+
+There are two elements to the comparisons. First, a comparison string is a list
+of comma separated and comparisons. These are then separated by || separated or
+comparisons. For example, `">= 1.2, < 3.0.0 || >= 4.2.3"` is looking for a
+comparison that's greater than or equal to 1.2 and less than 3.0.0 or is
+greater than or equal to 4.2.3.
+
+The basic comparisons are:
+
+ * `=`: equal (aliased to no operator)
+ * `!=`: not equal
+ * `>`: greater than
+ * `<`: less than
+ * `>=`: greater than or equal to
+ * `<=`: less than or equal to
+
+Hyphen Range Comparisons
+
+There are multiple methods to handle ranges and the first is hyphens ranges.
+These look like:
+
+ * `1.2 - 1.4.5` which is equivalent to `>= 1.2, <= 1.4.5`
+ * `2.3.4 - 4.5` which is equivalent to `>= 2.3.4, <= 4.5`
+
+Wildcards In Comparisons
+
+The `x`, `X`, and `*` characters can be used as a wildcard character. This works
+for all comparison operators. When used on the `=` operator it falls
+back to the pack level comparison (see tilde below). For example,
+
+ * `1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
+ * `>= 1.2.x` is equivalent to `>= 1.2.0`
+ * `<= 2.x` is equivalent to `<= 3`
+ * `*` is equivalent to `>= 0.0.0`
+
+Tilde Range Comparisons (Patch)
+
+The tilde (`~`) comparison operator is for patch level ranges when a minor
+version is specified and major level changes when the minor number is missing.
+For example,
+
+ * `~1.2.3` is equivalent to `>= 1.2.3, < 1.3.0`
+ * `~1` is equivalent to `>= 1, < 2`
+ * `~2.3` is equivalent to `>= 2.3, < 2.4`
+ * `~1.2.x` is equivalent to `>= 1.2.0, < 1.3.0`
+ * `~1.x` is equivalent to `>= 1, < 2`
+
+Caret Range Comparisons (Major)
+
+The caret (`^`) comparison operator is for major level changes. This is useful
+when comparisons of API versions as a major change is API breaking. For example,
+
+ * `^1.2.3` is equivalent to `>= 1.2.3, < 2.0.0`
+ * `^1.2.x` is equivalent to `>= 1.2.0, < 2.0.0`
+ * `^2.3` is equivalent to `>= 2.3, < 3`
+ * `^2.x` is equivalent to `>= 2.0.0, < 3`
+*/
+package semver
diff --git a/vendor/github.com/Masterminds/semver/version.go b/vendor/github.com/Masterminds/semver/version.go
new file mode 100644
index 00000000000..9d22ea6308d
--- /dev/null
+++ b/vendor/github.com/Masterminds/semver/version.go
@@ -0,0 +1,421 @@
+package semver
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+// The compiled version of the regex created at init() is cached here so it
+// only needs to be created once.
+var versionRegex *regexp.Regexp
+var validPrereleaseRegex *regexp.Regexp
+
+var (
+ // ErrInvalidSemVer is returned a version is found to be invalid when
+ // being parsed.
+ ErrInvalidSemVer = errors.New("Invalid Semantic Version")
+
+ // ErrInvalidMetadata is returned when the metadata is an invalid format
+ ErrInvalidMetadata = errors.New("Invalid Metadata string")
+
+ // ErrInvalidPrerelease is returned when the pre-release is an invalid format
+ ErrInvalidPrerelease = errors.New("Invalid Prerelease string")
+)
+
+// SemVerRegex is the regular expression used to parse a semantic version.
+const SemVerRegex string = `v?([0-9]+)(\.[0-9]+)?(\.[0-9]+)?` +
+ `(-([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?` +
+ `(\+([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*))?`
+
+// ValidPrerelease is the regular expression which validates
+// both prerelease and metadata values.
+const ValidPrerelease string = `^([0-9A-Za-z\-]+(\.[0-9A-Za-z\-]+)*)`
+
+// Version represents a single semantic version.
+type Version struct {
+ major, minor, patch int64
+ pre string
+ metadata string
+ original string
+}
+
+func init() {
+ versionRegex = regexp.MustCompile("^" + SemVerRegex + "$")
+ validPrereleaseRegex = regexp.MustCompile(ValidPrerelease)
+}
+
+// NewVersion parses a given version and returns an instance of Version or
+// an error if unable to parse the version.
+func NewVersion(v string) (*Version, error) {
+ m := versionRegex.FindStringSubmatch(v)
+ if m == nil {
+ return nil, ErrInvalidSemVer
+ }
+
+ sv := &Version{
+ metadata: m[8],
+ pre: m[5],
+ original: v,
+ }
+
+ var temp int64
+ temp, err := strconv.ParseInt(m[1], 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("Error parsing version segment: %s", err)
+ }
+ sv.major = temp
+
+ if m[2] != "" {
+ temp, err = strconv.ParseInt(strings.TrimPrefix(m[2], "."), 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("Error parsing version segment: %s", err)
+ }
+ sv.minor = temp
+ } else {
+ sv.minor = 0
+ }
+
+ if m[3] != "" {
+ temp, err = strconv.ParseInt(strings.TrimPrefix(m[3], "."), 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("Error parsing version segment: %s", err)
+ }
+ sv.patch = temp
+ } else {
+ sv.patch = 0
+ }
+
+ return sv, nil
+}
+
+// MustParse parses a given version and panics on error.
+func MustParse(v string) *Version {
+ sv, err := NewVersion(v)
+ if err != nil {
+ panic(err)
+ }
+ return sv
+}
+
+// String converts a Version object to a string.
+// Note, if the original version contained a leading v this version will not.
+// See the Original() method to retrieve the original value. Semantic Versions
+// don't contain a leading v per the spec. Instead it's optional on
+// impelementation.
+func (v *Version) String() string {
+ var buf bytes.Buffer
+
+ fmt.Fprintf(&buf, "%d.%d.%d", v.major, v.minor, v.patch)
+ if v.pre != "" {
+ fmt.Fprintf(&buf, "-%s", v.pre)
+ }
+ if v.metadata != "" {
+ fmt.Fprintf(&buf, "+%s", v.metadata)
+ }
+
+ return buf.String()
+}
+
+// Original returns the original value passed in to be parsed.
+func (v *Version) Original() string {
+ return v.original
+}
+
+// Major returns the major version.
+func (v *Version) Major() int64 {
+ return v.major
+}
+
+// Minor returns the minor version.
+func (v *Version) Minor() int64 {
+ return v.minor
+}
+
+// Patch returns the patch version.
+func (v *Version) Patch() int64 {
+ return v.patch
+}
+
+// Prerelease returns the pre-release version.
+func (v *Version) Prerelease() string {
+ return v.pre
+}
+
+// Metadata returns the metadata on the version.
+func (v *Version) Metadata() string {
+ return v.metadata
+}
+
+// originalVPrefix returns the original 'v' prefix if any.
+func (v *Version) originalVPrefix() string {
+
+ // Note, only lowercase v is supported as a prefix by the parser.
+ if v.original != "" && v.original[:1] == "v" {
+ return v.original[:1]
+ }
+ return ""
+}
+
+// IncPatch produces the next patch version.
+// If the current version does not have prerelease/metadata information,
+// it unsets metadata and prerelease values, increments patch number.
+// If the current version has any of prerelease or metadata information,
+// it unsets both values and keeps curent patch value
+func (v Version) IncPatch() Version {
+ vNext := v
+ // according to http://semver.org/#spec-item-9
+ // Pre-release versions have a lower precedence than the associated normal version.
+ // according to http://semver.org/#spec-item-10
+ // Build metadata SHOULD be ignored when determining version precedence.
+ if v.pre != "" {
+ vNext.metadata = ""
+ vNext.pre = ""
+ } else {
+ vNext.metadata = ""
+ vNext.pre = ""
+ vNext.patch = v.patch + 1
+ }
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext
+}
+
+// IncMinor produces the next minor version.
+// Sets patch to 0.
+// Increments minor number.
+// Unsets metadata.
+// Unsets prerelease status.
+func (v Version) IncMinor() Version {
+ vNext := v
+ vNext.metadata = ""
+ vNext.pre = ""
+ vNext.patch = 0
+ vNext.minor = v.minor + 1
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext
+}
+
+// IncMajor produces the next major version.
+// Sets patch to 0.
+// Sets minor to 0.
+// Increments major number.
+// Unsets metadata.
+// Unsets prerelease status.
+func (v Version) IncMajor() Version {
+ vNext := v
+ vNext.metadata = ""
+ vNext.pre = ""
+ vNext.patch = 0
+ vNext.minor = 0
+ vNext.major = v.major + 1
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext
+}
+
+// SetPrerelease defines the prerelease value.
+// Value must not include the required 'hypen' prefix.
+func (v Version) SetPrerelease(prerelease string) (Version, error) {
+ vNext := v
+ if len(prerelease) > 0 && !validPrereleaseRegex.MatchString(prerelease) {
+ return vNext, ErrInvalidPrerelease
+ }
+ vNext.pre = prerelease
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext, nil
+}
+
+// SetMetadata defines metadata value.
+// Value must not include the required 'plus' prefix.
+func (v Version) SetMetadata(metadata string) (Version, error) {
+ vNext := v
+ if len(metadata) > 0 && !validPrereleaseRegex.MatchString(metadata) {
+ return vNext, ErrInvalidMetadata
+ }
+ vNext.metadata = metadata
+ vNext.original = v.originalVPrefix() + "" + vNext.String()
+ return vNext, nil
+}
+
+// LessThan tests if one version is less than another one.
+func (v *Version) LessThan(o *Version) bool {
+ return v.Compare(o) < 0
+}
+
+// GreaterThan tests if one version is greater than another one.
+func (v *Version) GreaterThan(o *Version) bool {
+ return v.Compare(o) > 0
+}
+
+// Equal tests if two versions are equal to each other.
+// Note, versions can be equal with different metadata since metadata
+// is not considered part of the comparable version.
+func (v *Version) Equal(o *Version) bool {
+ return v.Compare(o) == 0
+}
+
+// Compare compares this version to another one. It returns -1, 0, or 1 if
+// the version smaller, equal, or larger than the other version.
+//
+// Versions are compared by X.Y.Z. Build metadata is ignored. Prerelease is
+// lower than the version without a prerelease.
+func (v *Version) Compare(o *Version) int {
+ // Compare the major, minor, and patch version for differences. If a
+ // difference is found return the comparison.
+ if d := compareSegment(v.Major(), o.Major()); d != 0 {
+ return d
+ }
+ if d := compareSegment(v.Minor(), o.Minor()); d != 0 {
+ return d
+ }
+ if d := compareSegment(v.Patch(), o.Patch()); d != 0 {
+ return d
+ }
+
+ // At this point the major, minor, and patch versions are the same.
+ ps := v.pre
+ po := o.Prerelease()
+
+ if ps == "" && po == "" {
+ return 0
+ }
+ if ps == "" {
+ return 1
+ }
+ if po == "" {
+ return -1
+ }
+
+ return comparePrerelease(ps, po)
+}
+
+// UnmarshalJSON implements JSON.Unmarshaler interface.
+func (v *Version) UnmarshalJSON(b []byte) error {
+ var s string
+ if err := json.Unmarshal(b, &s); err != nil {
+ return err
+ }
+ temp, err := NewVersion(s)
+ if err != nil {
+ return err
+ }
+ v.major = temp.major
+ v.minor = temp.minor
+ v.patch = temp.patch
+ v.pre = temp.pre
+ v.metadata = temp.metadata
+ v.original = temp.original
+ temp = nil
+ return nil
+}
+
+// MarshalJSON implements JSON.Marshaler interface.
+func (v *Version) MarshalJSON() ([]byte, error) {
+ return json.Marshal(v.String())
+}
+
+func compareSegment(v, o int64) int {
+ if v < o {
+ return -1
+ }
+ if v > o {
+ return 1
+ }
+
+ return 0
+}
+
+func comparePrerelease(v, o string) int {
+
+ // split the prelease versions by their part. The separator, per the spec,
+ // is a .
+ sparts := strings.Split(v, ".")
+ oparts := strings.Split(o, ".")
+
+ // Find the longer length of the parts to know how many loop iterations to
+ // go through.
+ slen := len(sparts)
+ olen := len(oparts)
+
+ l := slen
+ if olen > slen {
+ l = olen
+ }
+
+ // Iterate over each part of the prereleases to compare the differences.
+ for i := 0; i < l; i++ {
+ // Since the lentgh of the parts can be different we need to create
+ // a placeholder. This is to avoid out of bounds issues.
+ stemp := ""
+ if i < slen {
+ stemp = sparts[i]
+ }
+
+ otemp := ""
+ if i < olen {
+ otemp = oparts[i]
+ }
+
+ d := comparePrePart(stemp, otemp)
+ if d != 0 {
+ return d
+ }
+ }
+
+ // Reaching here means two versions are of equal value but have different
+ // metadata (the part following a +). They are not identical in string form
+ // but the version comparison finds them to be equal.
+ return 0
+}
+
+func comparePrePart(s, o string) int {
+ // Fastpath if they are equal
+ if s == o {
+ return 0
+ }
+
+ // When s or o are empty we can use the other in an attempt to determine
+ // the response.
+ if s == "" {
+ if o != "" {
+ return -1
+ }
+ return 1
+ }
+
+ if o == "" {
+ if s != "" {
+ return 1
+ }
+ return -1
+ }
+
+ // When comparing strings "99" is greater than "103". To handle
+ // cases like this we need to detect numbers and compare them.
+
+ oi, n1 := strconv.ParseInt(o, 10, 64)
+ si, n2 := strconv.ParseInt(s, 10, 64)
+
+ // The case where both are strings compare the strings
+ if n1 != nil && n2 != nil {
+ if s > o {
+ return 1
+ }
+ return -1
+ } else if n1 != nil {
+ // o is a string and s is a number
+ return -1
+ } else if n2 != nil {
+ // s is a string and o is a number
+ return 1
+ }
+ // Both are numbers
+ if si > oi {
+ return 1
+ }
+ return -1
+
+}
diff --git a/vendor/github.com/apex/log/.gitignore b/vendor/github.com/apex/log/.gitignore
new file mode 100644
index 00000000000..7a6353d6737
--- /dev/null
+++ b/vendor/github.com/apex/log/.gitignore
@@ -0,0 +1 @@
+.envrc
diff --git a/vendor/github.com/apex/log/History.md b/vendor/github.com/apex/log/History.md
new file mode 100644
index 00000000000..c88be39eb97
--- /dev/null
+++ b/vendor/github.com/apex/log/History.md
@@ -0,0 +1,12 @@
+
+v1.1.1 / 2019-06-24
+===================
+
+ * add go.mod
+ * add rough pass at apexlogs handler
+
+v1.1.0 / 2018-10-11
+===================
+
+ * fix: cli handler to show non-string fields appropriately
+ * fix: cli using fatih/color to better support windows
diff --git a/vendor/github.com/apex/log/LICENSE b/vendor/github.com/apex/log/LICENSE
new file mode 100644
index 00000000000..af718006842
--- /dev/null
+++ b/vendor/github.com/apex/log/LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2015 TJ Holowaychuk tj@tjholowaychuk.com
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/github.com/apex/log/Makefile b/vendor/github.com/apex/log/Makefile
new file mode 100644
index 00000000000..f948e88ec12
--- /dev/null
+++ b/vendor/github.com/apex/log/Makefile
@@ -0,0 +1,2 @@
+
+include github.com/tj/make/golang
diff --git a/vendor/github.com/apex/log/Readme.md b/vendor/github.com/apex/log/Readme.md
new file mode 100644
index 00000000000..4a48b6710dd
--- /dev/null
+++ b/vendor/github.com/apex/log/Readme.md
@@ -0,0 +1,29 @@
+
+![Structured logging for golang](assets/title.png)
+
+Package log implements a simple structured logging API inspired by Logrus, designed with centralization in mind. Read more on [Medium](https://medium.com/@tjholowaychuk/apex-log-e8d9627f4a9a#.rav8yhkud).
+
+## Handlers
+
+- __cli__ – human-friendly CLI output
+- __discard__ – discards all logs
+- __es__ – Elasticsearch handler
+- __graylog__ – Graylog handler
+- __json__ – JSON output handler
+- __kinesis__ – AWS Kinesis handler
+- __level__ – level filter handler
+- __logfmt__ – logfmt plain-text formatter
+- __memory__ – in-memory handler for tests
+- __multi__ – fan-out to multiple handlers
+- __papertrail__ – Papertrail handler
+- __text__ – human-friendly colored output
+- __delta__ – outputs the delta between log calls and spinner
+
+---
+
+[![Build Status](https://semaphoreci.com/api/v1/projects/d8a8b1c0-45b0-4b89-b066-99d788d0b94c/642077/badge.svg)](https://semaphoreci.com/tj/log)
+[![GoDoc](https://godoc.org/github.com/apex/log?status.svg)](https://godoc.org/github.com/apex/log)
+![](https://img.shields.io/badge/license-MIT-blue.svg)
+![](https://img.shields.io/badge/status-stable-green.svg)
+
+
diff --git a/vendor/github.com/apex/log/default.go b/vendor/github.com/apex/log/default.go
new file mode 100644
index 00000000000..22134862381
--- /dev/null
+++ b/vendor/github.com/apex/log/default.go
@@ -0,0 +1,45 @@
+package log
+
+import (
+ "bytes"
+ "fmt"
+ "log"
+ "sort"
+)
+
+// field used for sorting.
+type field struct {
+ Name string
+ Value interface{}
+}
+
+// by sorts fields by name.
+type byName []field
+
+func (a byName) Len() int { return len(a) }
+func (a byName) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a byName) Less(i, j int) bool { return a[i].Name < a[j].Name }
+
+// handleStdLog outpouts to the stlib log.
+func handleStdLog(e *Entry) error {
+ level := levelNames[e.Level]
+
+ var fields []field
+
+ for k, v := range e.Fields {
+ fields = append(fields, field{k, v})
+ }
+
+ sort.Sort(byName(fields))
+
+ var b bytes.Buffer
+ fmt.Fprintf(&b, "%5s %-25s", level, e.Message)
+
+ for _, f := range fields {
+ fmt.Fprintf(&b, " %s=%v", f.Name, f.Value)
+ }
+
+ log.Println(b.String())
+
+ return nil
+}
diff --git a/vendor/github.com/apex/log/doc.go b/vendor/github.com/apex/log/doc.go
new file mode 100644
index 00000000000..0331e8e163e
--- /dev/null
+++ b/vendor/github.com/apex/log/doc.go
@@ -0,0 +1,10 @@
+/*
+Package log implements a simple structured logging API designed with few assumptions. Designed for
+centralized logging solutions such as Kinesis which require encoding and decoding before fanning-out
+to handlers.
+
+You may use this package with inline handlers, much like Logrus, however a centralized solution
+is recommended so that apps do not need to be re-deployed to add or remove logging service
+providers.
+*/
+package log
diff --git a/vendor/github.com/apex/log/entry.go b/vendor/github.com/apex/log/entry.go
new file mode 100644
index 00000000000..9f0a5e1fdaf
--- /dev/null
+++ b/vendor/github.com/apex/log/entry.go
@@ -0,0 +1,172 @@
+package log
+
+import (
+ "fmt"
+ "os"
+ "strings"
+ "time"
+)
+
+// assert interface compliance.
+var _ Interface = (*Entry)(nil)
+
+// Now returns the current time.
+var Now = time.Now
+
+// Entry represents a single log entry.
+type Entry struct {
+ Logger *Logger `json:"-"`
+ Fields Fields `json:"fields"`
+ Level Level `json:"level"`
+ Timestamp time.Time `json:"timestamp"`
+ Message string `json:"message"`
+ start time.Time
+ fields []Fields
+}
+
+// NewEntry returns a new entry for `log`.
+func NewEntry(log *Logger) *Entry {
+ return &Entry{
+ Logger: log,
+ }
+}
+
+// WithFields returns a new entry with `fields` set.
+func (e *Entry) WithFields(fields Fielder) *Entry {
+ f := []Fields{}
+ f = append(f, e.fields...)
+ f = append(f, fields.Fields())
+ return &Entry{
+ Logger: e.Logger,
+ fields: f,
+ }
+}
+
+// WithField returns a new entry with the `key` and `value` set.
+func (e *Entry) WithField(key string, value interface{}) *Entry {
+ return e.WithFields(Fields{key: value})
+}
+
+// WithError returns a new entry with the "error" set to `err`.
+//
+// The given error may implement .Fielder, if it does the method
+// will add all its `.Fields()` into the returned entry.
+func (e *Entry) WithError(err error) *Entry {
+ ctx := e.WithField("error", err.Error())
+
+ if s, ok := err.(stackTracer); ok {
+ frame := s.StackTrace()[0]
+
+ name := fmt.Sprintf("%n", frame)
+ file := fmt.Sprintf("%+s", frame)
+ line := fmt.Sprintf("%d", frame)
+
+ parts := strings.Split(file, "\n\t")
+ if len(parts) > 1 {
+ file = parts[1]
+ }
+
+ ctx = ctx.WithField("source", fmt.Sprintf("%s: %s:%s", name, file, line))
+ }
+
+ if f, ok := err.(Fielder); ok {
+ ctx = ctx.WithFields(f.Fields())
+ }
+
+ return ctx
+}
+
+// Debug level message.
+func (e *Entry) Debug(msg string) {
+ e.Logger.log(DebugLevel, e, msg)
+}
+
+// Info level message.
+func (e *Entry) Info(msg string) {
+ e.Logger.log(InfoLevel, e, msg)
+}
+
+// Warn level message.
+func (e *Entry) Warn(msg string) {
+ e.Logger.log(WarnLevel, e, msg)
+}
+
+// Error level message.
+func (e *Entry) Error(msg string) {
+ e.Logger.log(ErrorLevel, e, msg)
+}
+
+// Fatal level message, followed by an exit.
+func (e *Entry) Fatal(msg string) {
+ e.Logger.log(FatalLevel, e, msg)
+ os.Exit(1)
+}
+
+// Debugf level formatted message.
+func (e *Entry) Debugf(msg string, v ...interface{}) {
+ e.Debug(fmt.Sprintf(msg, v...))
+}
+
+// Infof level formatted message.
+func (e *Entry) Infof(msg string, v ...interface{}) {
+ e.Info(fmt.Sprintf(msg, v...))
+}
+
+// Warnf level formatted message.
+func (e *Entry) Warnf(msg string, v ...interface{}) {
+ e.Warn(fmt.Sprintf(msg, v...))
+}
+
+// Errorf level formatted message.
+func (e *Entry) Errorf(msg string, v ...interface{}) {
+ e.Error(fmt.Sprintf(msg, v...))
+}
+
+// Fatalf level formatted message, followed by an exit.
+func (e *Entry) Fatalf(msg string, v ...interface{}) {
+ e.Fatal(fmt.Sprintf(msg, v...))
+}
+
+// Trace returns a new entry with a Stop method to fire off
+// a corresponding completion log, useful with defer.
+func (e *Entry) Trace(msg string) *Entry {
+ e.Info(msg)
+ v := e.WithFields(e.Fields)
+ v.Message = msg
+ v.start = time.Now()
+ return v
+}
+
+// Stop should be used with Trace, to fire off the completion message. When
+// an `err` is passed the "error" field is set, and the log level is error.
+func (e *Entry) Stop(err *error) {
+ if err == nil || *err == nil {
+ e.WithField("duration", time.Since(e.start)).Info(e.Message)
+ } else {
+ e.WithField("duration", time.Since(e.start)).WithError(*err).Error(e.Message)
+ }
+}
+
+// mergedFields returns the fields list collapsed into a single map.
+func (e *Entry) mergedFields() Fields {
+ f := Fields{}
+
+ for _, fields := range e.fields {
+ for k, v := range fields {
+ f[k] = v
+ }
+ }
+
+ return f
+}
+
+// finalize returns a copy of the Entry with Fields merged.
+func (e *Entry) finalize(level Level, msg string) *Entry {
+ return &Entry{
+ Logger: e.Logger,
+ Fields: e.mergedFields(),
+ Level: level,
+ Message: msg,
+ Timestamp: Now(),
+ }
+}
diff --git a/vendor/github.com/apex/log/go.mod b/vendor/github.com/apex/log/go.mod
new file mode 100644
index 00000000000..efc674b8cdf
--- /dev/null
+++ b/vendor/github.com/apex/log/go.mod
@@ -0,0 +1,25 @@
+module github.com/apex/log
+
+go 1.12
+
+require (
+ github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a
+ github.com/aphistic/sweet v0.2.0 // indirect
+ github.com/aws/aws-sdk-go v1.20.6
+ github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59
+ github.com/fatih/color v1.7.0
+ github.com/go-logfmt/logfmt v0.4.0
+ github.com/google/uuid v1.1.1 // indirect
+ github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 // indirect
+ github.com/mattn/go-colorable v0.1.2
+ github.com/pkg/errors v0.8.1
+ github.com/rogpeppe/fastuuid v1.1.0
+ github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 // indirect
+ github.com/smartystreets/gunit v1.0.0 // indirect
+ github.com/stretchr/testify v1.3.0
+ github.com/tj/assert v0.0.0-20171129193455-018094318fb0
+ github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2
+ github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b
+ github.com/tj/go-spin v1.1.0
+ golang.org/x/net v0.0.0-20190620200207-3b0461eec859 // indirect
+)
diff --git a/vendor/github.com/apex/log/go.sum b/vendor/github.com/apex/log/go.sum
new file mode 100644
index 00000000000..972a66dbcba
--- /dev/null
+++ b/vendor/github.com/apex/log/go.sum
@@ -0,0 +1,90 @@
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a h1:2KLQMJ8msqoPHIPDufkxVcoTtcmE5+1sL9950m4R9Pk=
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
+github.com/aphistic/sweet v0.2.0 h1:I4z+fAUqvKfvZV/CHi5dV0QuwbmIvYYFDjG0Ss5QpAs=
+github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
+github.com/aws/aws-sdk-go v1.20.6 h1:kmy4Gvdlyez1fV4kw5RYxZzWKVyuHZHgPWeU/YvRsV4=
+github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
+github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 h1:K//n/AqR5HjG3qxbrBCL4vJPW0MVFSs9CPK1OOJdRME=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/onsi/ginkgo v1.6.0 h1:Ix8l273rp3QzYgXSR+c8d1fTG7UPgYkOSELPhiY/YGw=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/fastuuid v1.1.0 h1:INyGLmTCMGFr6OVIb977ghJvABML2CMVjPoRfNDdYDo=
+github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/smartystreets/assertions v1.0.0 h1:UVQPSSmc3qtTi+zPPkCXvZX9VvW/xT/NsRvKfwY81a8=
+github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9 h1:hp2CYQUINdZMHdvTdXtPOY2ainKl4IoMcpAXEf2xj3Q=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+github.com/smartystreets/gunit v1.0.0 h1:RyPDUFcJbvtXlhJPk7v+wnxZRY2EUokhEYl2EJOPToI=
+github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/tj/assert v0.0.0-20171129193455-018094318fb0 h1:Rw8kxzWo1mr6FSaYXjQELRe88y2KdfynXdnK72rdjtA=
+github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2 h1:eGaGNxrtoZf/mBURsnNQKDR7u50Klgcf2eFDQEnc8Bc=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b h1:m74UWYy+HBs+jMFR9mdZU6shPewugMyH5+GV6LNgW8w=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
+github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
+github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734 h1:p/H982KKEjUnLJkM3tt/LemDnOc1GiZL5FCVlORJ5zo=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d h1:+R4KGOnez64A81RvjARKc4UT5/tI9ujCIVX+P5KiHuI=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+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=
diff --git a/vendor/github.com/apex/log/interface.go b/vendor/github.com/apex/log/interface.go
new file mode 100644
index 00000000000..c92ebea75ba
--- /dev/null
+++ b/vendor/github.com/apex/log/interface.go
@@ -0,0 +1,19 @@
+package log
+
+// Interface represents the API of both Logger and Entry.
+type Interface interface {
+ WithFields(fields Fielder) *Entry
+ WithField(key string, value interface{}) *Entry
+ WithError(err error) *Entry
+ Debug(msg string)
+ Info(msg string)
+ Warn(msg string)
+ Error(msg string)
+ Fatal(msg string)
+ Debugf(msg string, v ...interface{})
+ Infof(msg string, v ...interface{})
+ Warnf(msg string, v ...interface{})
+ Errorf(msg string, v ...interface{})
+ Fatalf(msg string, v ...interface{})
+ Trace(msg string) *Entry
+}
diff --git a/vendor/github.com/apex/log/levels.go b/vendor/github.com/apex/log/levels.go
new file mode 100644
index 00000000000..7d43a43609f
--- /dev/null
+++ b/vendor/github.com/apex/log/levels.go
@@ -0,0 +1,81 @@
+package log
+
+import (
+ "bytes"
+ "errors"
+ "strings"
+)
+
+// ErrInvalidLevel is returned if the severity level is invalid.
+var ErrInvalidLevel = errors.New("invalid level")
+
+// Level of severity.
+type Level int
+
+// Log levels.
+const (
+ InvalidLevel Level = iota - 1
+ DebugLevel
+ InfoLevel
+ WarnLevel
+ ErrorLevel
+ FatalLevel
+)
+
+var levelNames = [...]string{
+ DebugLevel: "debug",
+ InfoLevel: "info",
+ WarnLevel: "warn",
+ ErrorLevel: "error",
+ FatalLevel: "fatal",
+}
+
+var levelStrings = map[string]Level{
+ "debug": DebugLevel,
+ "info": InfoLevel,
+ "warn": WarnLevel,
+ "warning": WarnLevel,
+ "error": ErrorLevel,
+ "fatal": FatalLevel,
+}
+
+// String implementation.
+func (l Level) String() string {
+ return levelNames[l]
+}
+
+// MarshalJSON implementation.
+func (l Level) MarshalJSON() ([]byte, error) {
+ return []byte(`"` + l.String() + `"`), nil
+}
+
+// UnmarshalJSON implementation.
+func (l *Level) UnmarshalJSON(b []byte) error {
+ v, err := ParseLevel(string(bytes.Trim(b, `"`)))
+ if err != nil {
+ return err
+ }
+
+ *l = v
+ return nil
+}
+
+// ParseLevel parses level string.
+func ParseLevel(s string) (Level, error) {
+ l, ok := levelStrings[strings.ToLower(s)]
+ if !ok {
+ return InvalidLevel, ErrInvalidLevel
+ }
+
+ return l, nil
+}
+
+// MustParseLevel parses level string or panics.
+func MustParseLevel(s string) Level {
+ l, err := ParseLevel(s)
+ if err != nil {
+ panic("invalid log level")
+ }
+
+ return l
+}
diff --git a/vendor/github.com/apex/log/logger.go b/vendor/github.com/apex/log/logger.go
new file mode 100644
index 00000000000..1755747c912
--- /dev/null
+++ b/vendor/github.com/apex/log/logger.go
@@ -0,0 +1,149 @@
+package log
+
+import (
+ stdlog "log"
+ "sort"
+)
+
+// assert interface compliance.
+var _ Interface = (*Logger)(nil)
+
+// Fielder is an interface for providing fields to custom types.
+type Fielder interface {
+ Fields() Fields
+}
+
+// Fields represents a map of entry level data used for structured logging.
+type Fields map[string]interface{}
+
+// Fields implements Fielder.
+func (f Fields) Fields() Fields {
+ return f
+}
+
+// Get field value by name.
+func (f Fields) Get(name string) interface{} {
+ return f[name]
+}
+
+// Names returns field names sorted.
+func (f Fields) Names() (v []string) {
+ for k := range f {
+ v = append(v, k)
+ }
+
+ sort.Strings(v)
+ return
+}
+
+// The HandlerFunc type is an adapter to allow the use of ordinary functions as
+// log handlers. If f is a function with the appropriate signature,
+// HandlerFunc(f) is a Handler object that calls f.
+type HandlerFunc func(*Entry) error
+
+// HandleLog calls f(e).
+func (f HandlerFunc) HandleLog(e *Entry) error {
+ return f(e)
+}
+
+// Handler is used to handle log events, outputting them to
+// stdio or sending them to remote services. See the "handlers"
+// directory for implementations.
+//
+// It is left up to Handlers to implement thread-safety.
+type Handler interface {
+ HandleLog(*Entry) error
+}
+
+// Logger represents a logger with configurable Level and Handler.
+type Logger struct {
+ Handler Handler
+ Level Level
+}
+
+// WithFields returns a new entry with `fields` set.
+func (l *Logger) WithFields(fields Fielder) *Entry {
+ return NewEntry(l).WithFields(fields.Fields())
+}
+
+// WithField returns a new entry with the `key` and `value` set.
+//
+// Note that the `key` should not have spaces in it - use camel
+// case or underscores
+func (l *Logger) WithField(key string, value interface{}) *Entry {
+ return NewEntry(l).WithField(key, value)
+}
+
+// WithError returns a new entry with the "error" set to `err`.
+func (l *Logger) WithError(err error) *Entry {
+ return NewEntry(l).WithError(err)
+}
+
+// Debug level message.
+func (l *Logger) Debug(msg string) {
+ NewEntry(l).Debug(msg)
+}
+
+// Info level message.
+func (l *Logger) Info(msg string) {
+ NewEntry(l).Info(msg)
+}
+
+// Warn level message.
+func (l *Logger) Warn(msg string) {
+ NewEntry(l).Warn(msg)
+}
+
+// Error level message.
+func (l *Logger) Error(msg string) {
+ NewEntry(l).Error(msg)
+}
+
+// Fatal level message, followed by an exit.
+func (l *Logger) Fatal(msg string) {
+ NewEntry(l).Fatal(msg)
+}
+
+// Debugf level formatted message.
+func (l *Logger) Debugf(msg string, v ...interface{}) {
+ NewEntry(l).Debugf(msg, v...)
+}
+
+// Infof level formatted message.
+func (l *Logger) Infof(msg string, v ...interface{}) {
+ NewEntry(l).Infof(msg, v...)
+}
+
+// Warnf level formatted message.
+func (l *Logger) Warnf(msg string, v ...interface{}) {
+ NewEntry(l).Warnf(msg, v...)
+}
+
+// Errorf level formatted message.
+func (l *Logger) Errorf(msg string, v ...interface{}) {
+ NewEntry(l).Errorf(msg, v...)
+}
+
+// Fatalf level formatted message, followed by an exit.
+func (l *Logger) Fatalf(msg string, v ...interface{}) {
+ NewEntry(l).Fatalf(msg, v...)
+}
+
+// Trace returns a new entry with a Stop method to fire off
+// a corresponding completion log, useful with defer.
+func (l *Logger) Trace(msg string) *Entry {
+ return NewEntry(l).Trace(msg)
+}
+
+// log the message, invoking the handler. We clone the entry here
+// to bypass the overhead in Entry methods when the level is not
+// met.
+func (l *Logger) log(level Level, e *Entry, msg string) {
+ if level < l.Level {
+ return
+ }
+
+ if err := l.Handler.HandleLog(e.finalize(level, msg)); err != nil {
+ stdlog.Printf("error logging: %s", err)
+ }
+}
diff --git a/vendor/github.com/apex/log/pkg.go b/vendor/github.com/apex/log/pkg.go
new file mode 100644
index 00000000000..9bf51dc8e5d
--- /dev/null
+++ b/vendor/github.com/apex/log/pkg.go
@@ -0,0 +1,100 @@
+package log
+
+// singletons ftw?
+var Log Interface = &Logger{
+ Handler: HandlerFunc(handleStdLog),
+ Level: InfoLevel,
+}
+
+// SetHandler sets the handler. This is not thread-safe.
+// The default handler outputs to the stdlib log.
+func SetHandler(h Handler) {
+ if logger, ok := Log.(*Logger); ok {
+ logger.Handler = h
+ }
+}
+
+// SetLevel sets the log level. This is not thread-safe.
+func SetLevel(l Level) {
+ if logger, ok := Log.(*Logger); ok {
+ logger.Level = l
+ }
+}
+
+// SetLevelFromString sets the log level from a string, panicing when invalid. This is not thread-safe.
+func SetLevelFromString(s string) {
+ if logger, ok := Log.(*Logger); ok {
+ logger.Level = MustParseLevel(s)
+ }
+}
+
+// WithFields returns a new entry with `fields` set.
+func WithFields(fields Fielder) *Entry {
+ return Log.WithFields(fields)
+}
+
+// WithField returns a new entry with the `key` and `value` set.
+func WithField(key string, value interface{}) *Entry {
+ return Log.WithField(key, value)
+}
+
+// WithError returns a new entry with the "error" set to `err`.
+func WithError(err error) *Entry {
+ return Log.WithError(err)
+}
+
+// Debug level message.
+func Debug(msg string) {
+ Log.Debug(msg)
+}
+
+// Info level message.
+func Info(msg string) {
+ Log.Info(msg)
+}
+
+// Warn level message.
+func Warn(msg string) {
+ Log.Warn(msg)
+}
+
+// Error level message.
+func Error(msg string) {
+ Log.Error(msg)
+}
+
+// Fatal level message, followed by an exit.
+func Fatal(msg string) {
+ Log.Fatal(msg)
+}
+
+// Debugf level formatted message.
+func Debugf(msg string, v ...interface{}) {
+ Log.Debugf(msg, v...)
+}
+
+// Infof level formatted message.
+func Infof(msg string, v ...interface{}) {
+ Log.Infof(msg, v...)
+}
+
+// Warnf level formatted message.
+func Warnf(msg string, v ...interface{}) {
+ Log.Warnf(msg, v...)
+}
+
+// Errorf level formatted message.
+func Errorf(msg string, v ...interface{}) {
+ Log.Errorf(msg, v...)
+}
+
+// Fatalf level formatted message, followed by an exit.
+func Fatalf(msg string, v ...interface{}) {
+ Log.Fatalf(msg, v...)
+}
+
+// Trace returns a new entry with a Stop method to fire off
+// a corresponding completion log, useful with defer.
+func Trace(msg string) *Entry {
+ return Log.Trace(msg)
+}
diff --git a/vendor/github.com/apex/log/stack.go b/vendor/github.com/apex/log/stack.go
new file mode 100644
index 00000000000..57efe3262e1
--- /dev/null
+++ b/vendor/github.com/apex/log/stack.go
@@ -0,0 +1,8 @@
+package log
+
+import "github.com/pkg/errors"
+
+// stackTracer interface.
+type stackTracer interface {
+ StackTrace() errors.StackTrace
+}
diff --git a/vendor/github.com/buildpacks/imgutil/.gitignore b/vendor/github.com/buildpacks/imgutil/.gitignore
new file mode 100644
index 00000000000..3a30eb64468
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/.gitignore
@@ -0,0 +1,15 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+
+# IDEs
+.idea/
diff --git a/vendor/github.com/buildpacks/imgutil/.travis.yml b/vendor/github.com/buildpacks/imgutil/.travis.yml
new file mode 100644
index 00000000000..8eb081b7b57
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/.travis.yml
@@ -0,0 +1,18 @@
+language: go
+go: 1.12.x
+dist: trusty
+
+env:
+ global:
+ - GO111MODULE=on
+
+jobs:
+ include:
+ - os: linux
+ script:
+ - docker info
+ - make
+
+branches:
+ only:
+ - master
diff --git a/vendor/github.com/buildpacks/imgutil/LICENSE b/vendor/github.com/buildpacks/imgutil/LICENSE
new file mode 100644
index 00000000000..261eeb9e9f8
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/buildpacks/imgutil/Makefile b/vendor/github.com/buildpacks/imgutil/Makefile
new file mode 100644
index 00000000000..68cf56c8bbb
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/Makefile
@@ -0,0 +1,23 @@
+# Go parameters
+GOCMD?=go
+GOTEST=$(GOCMD) test -mod=vendor
+PACKAGE_BASE=github.com/buildpacks/imgutil
+PACKAGES:=$(shell $(GOCMD) list -mod=vendor ./... | grep -v /testdata/)
+SRC:=$(shell find . -type f -name '*.go' -not -path "*/vendor/*")
+
+all: test
+
+install-goimports:
+ @echo "> Installing goimports..."
+ cd tools; $(GOCMD) install -mod=vendor golang.org/x/tools/cmd/goimports
+
+format: install-goimports
+ @echo "> Formating code..."
+ @goimports -l -w -local ${PACKAGE_BASE} ${SRC}
+
+vet:
+ @echo "> Vetting code..."
+ @$(GOCMD) vet -mod=vendor ${PACKAGES}
+
+test: format vet
+ $(GOTEST) -parallel=1 -count=1 -v ./...
diff --git a/vendor/github.com/buildpacks/imgutil/README.md b/vendor/github.com/buildpacks/imgutil/README.md
new file mode 100644
index 00000000000..2caa4b9dfc4
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/README.md
@@ -0,0 +1,19 @@
+# imgutil
+
+[![Build Status](https://travis-ci.org/buildpack/imgutil.svg?branch=master)](https://travis-ci.org/buildpack/imgutil)
+
+Helpful utilities for working with images
+
+## Development
+
+To format:
+
+```bash
+$ make format
+```
+
+To run tests:
+
+```bash
+$ make test
+```
\ No newline at end of file
diff --git a/vendor/github.com/buildpacks/imgutil/go.mod b/vendor/github.com/buildpacks/imgutil/go.mod
new file mode 100644
index 00000000000..84d8ba92aee
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/go.mod
@@ -0,0 +1,16 @@
+module github.com/buildpacks/imgutil
+
+require (
+ github.com/docker/distribution v2.7.1+incompatible // indirect
+ github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7
+ github.com/docker/go-connections v0.4.0
+ github.com/gogo/protobuf v1.2.1 // indirect
+ github.com/google/go-cmp v0.2.0
+ github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af
+ github.com/pkg/errors v0.8.1
+ github.com/sclevine/spec v1.0.0
+ golang.org/x/sync v0.0.0-20190423024810-112230192c58
+ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 // indirect
+)
+
+go 1.13
diff --git a/vendor/github.com/buildpacks/imgutil/go.sum b/vendor/github.com/buildpacks/imgutil/go.sum
new file mode 100644
index 00000000000..ae725d322dc
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/go.sum
@@ -0,0 +1,166 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/Azure/azure-sdk-for-go v19.1.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-autorest v10.15.5+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/aws/aws-sdk-go v1.15.90/go.mod h1:es1KtYUFs7le0xQ3rOihkuoVD90z7D0fR2Qm4S00/gU=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 h1:Cvj7S8I4Xpx78KAl6TwTmMHuHlZ/0SM60NUneGJQ7IE=
+github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
+github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/protobuf v1.2.0 h1:P3YflyNX/ehuJFLhxviNdFxQPkGK5cDcApsge1SqnvM=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af h1:gCcst+zXdvatJYFDtPd3C3VNEGcoFOOMwFydnFIfnF0=
+github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af/go.mod h1:9kIomAeXUmwhqeYS2zoEuQ0sc2GOVmNW7t3y9aNQL1o=
+github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+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/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/sclevine/spec v1.0.0 h1:ILQ08A/CHCz8GGqivOvI54Hy1U40wwcpkf7WtB1MQfY=
+github.com/sclevine/spec v1.0.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
+github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2 h1:bSDNvY7ZPG5RlJ8otE/7V6gMiyenm9RtJ7IUVIAoJ1w=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+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/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191017205301-920acffc3e65/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8 h1:Nw54tB0rB7hY/N0NQvRW8DG4Yk3Q6T9cu9RcFQDu1tc=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
+k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
+k8s.io/client-go v0.0.0-20180910083459-2cefa64ff137/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
+k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
+k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
diff --git a/vendor/github.com/buildpacks/imgutil/image.go b/vendor/github.com/buildpacks/imgutil/image.go
new file mode 100644
index 00000000000..84e1af6a09d
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/image.go
@@ -0,0 +1,53 @@
+package imgutil
+
+import (
+ "fmt"
+ "io"
+ "strings"
+ "time"
+)
+
+type SaveDiagnostic struct {
+ ImageName string
+ Cause error
+}
+
+type SaveError struct {
+ Errors []SaveDiagnostic
+}
+
+func (e SaveError) Error() string {
+ var errors []string
+ for _, d := range e.Errors {
+ errors = append(errors, fmt.Sprintf("[%s: %s]", d.ImageName, d.Cause.Error()))
+ }
+ return fmt.Sprintf("failed to write image to the following tags: %s", strings.Join(errors, ","))
+}
+
+type Image interface {
+ Name() string
+ Rename(name string)
+ Label(string) (string, error)
+ SetLabel(string, string) error
+ Env(key string) (string, error)
+ SetEnv(string, string) error
+ SetEntrypoint(...string) error
+ SetWorkingDir(string) error
+ SetCmd(...string) error
+ Rebase(string, Image) error
+ AddLayer(path string) error
+ ReuseLayer(diffID string) error
+ // TopLayer returns the diff id for the top layer
+ TopLayer() (string, error)
+ // Save saves the image as `Name()` and any additional names provided to this method.
+ Save(additionalNames ...string) error
+ // Found tells whether the image exists in the repository by `Name()`.
+ Found() bool
+ // GetLayer retrieves layer by diff id. Returns a reader of the uncompressed contents of the layer.
+ GetLayer(diffID string) (io.ReadCloser, error)
+ Delete() error
+ CreatedAt() (time.Time, error)
+ Identifier() (Identifier, error)
+}
+
+type Identifier fmt.Stringer
diff --git a/vendor/github.com/buildpacks/imgutil/local/identifier.go b/vendor/github.com/buildpacks/imgutil/local/identifier.go
new file mode 100644
index 00000000000..dd24fba1bb1
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/local/identifier.go
@@ -0,0 +1,9 @@
+package local
+
+type IDIdentifier struct {
+ ImageID string
+}
+
+func (i IDIdentifier) String() string {
+ return i.ImageID
+}
diff --git a/vendor/github.com/buildpacks/imgutil/local/local.go b/vendor/github.com/buildpacks/imgutil/local/local.go
new file mode 100644
index 00000000000..42b2a74287e
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/local/local.go
@@ -0,0 +1,616 @@
+package local
+
+import (
+ "archive/tar"
+ "context"
+ "crypto/sha256"
+ "encoding/hex"
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "github.com/docker/docker/api/types"
+ "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/client"
+ "github.com/google/go-containerregistry/pkg/name"
+ "github.com/pkg/errors"
+ "golang.org/x/sync/singleflight"
+
+ "github.com/buildpacks/imgutil"
+)
+
+type Image struct {
+ repoName string
+ docker *client.Client
+ inspect types.ImageInspect
+ layerPaths []string
+ currentTempImage string
+ requestGroup singleflight.Group
+ prevName string
+ easyAddLayers []string
+}
+
+type FileSystemLocalImage struct {
+ dir string
+ layersMap map[string]string
+}
+
+type ImageOption func(image *Image) (*Image, error)
+
+func WithPreviousImage(imageName string) ImageOption {
+ return func(i *Image) (*Image, error) {
+ if _, err := inspectOptionalImage(i.docker, imageName); err != nil {
+ return i, err
+ }
+
+ i.prevName = imageName
+
+ return i, nil
+ }
+}
+
+func FromBaseImage(imageName string) ImageOption {
+ return func(i *Image) (*Image, error) {
+ var (
+ err error
+ inspect types.ImageInspect
+ )
+
+ if inspect, err = inspectOptionalImage(i.docker, imageName); err != nil {
+ return i, err
+ }
+
+ i.inspect = inspect
+ i.layerPaths = make([]string, len(i.inspect.RootFS.Layers))
+
+ return i, nil
+ }
+}
+
+func NewImage(repoName string, dockerClient *client.Client, ops ...ImageOption) (imgutil.Image, error) {
+ inspect := defaultInspect()
+
+ image := &Image{
+ docker: dockerClient,
+ repoName: repoName,
+ inspect: inspect,
+ layerPaths: make([]string, len(inspect.RootFS.Layers)),
+ }
+
+ var err error
+ for _, v := range ops {
+ image, err = v(image)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return image, nil
+}
+
+func (i *Image) Label(key string) (string, error) {
+ labels := i.inspect.Config.Labels
+ return labels[key], nil
+}
+
+func (i *Image) Env(key string) (string, error) {
+ for _, envVar := range i.inspect.Config.Env {
+ parts := strings.Split(envVar, "=")
+ if parts[0] == key {
+ return parts[1], nil
+ }
+ }
+ return "", nil
+}
+
+func (i *Image) Rename(name string) {
+ i.easyAddLayers = nil
+ if prevInspect, _, err := i.docker.ImageInspectWithRaw(context.TODO(), name); err == nil {
+ if i.sameBase(prevInspect) {
+ i.easyAddLayers = prevInspect.RootFS.Layers[len(i.inspect.RootFS.Layers):]
+ }
+ }
+
+ i.repoName = name
+}
+
+func (i *Image) sameBase(prevInspect types.ImageInspect) bool {
+ if len(prevInspect.RootFS.Layers) < len(i.inspect.RootFS.Layers) {
+ return false
+ }
+ for i, baseLayer := range i.inspect.RootFS.Layers {
+ if baseLayer != prevInspect.RootFS.Layers[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func (i *Image) Name() string {
+ return i.repoName
+}
+
+func (i *Image) Found() bool {
+ return i.inspect.ID != ""
+}
+
+func (i *Image) Identifier() (imgutil.Identifier, error) {
+ return IDIdentifier{
+ ImageID: strings.TrimPrefix(i.inspect.ID, "sha256:"),
+ }, nil
+}
+
+func (i *Image) CreatedAt() (time.Time, error) {
+ createdAtTime := i.inspect.Created
+ createdTime, err := time.Parse(time.RFC3339Nano, createdAtTime)
+
+ if err != nil {
+ return time.Time{}, err
+ }
+ return createdTime, nil
+}
+
+func (i *Image) Rebase(baseTopLayer string, newBase imgutil.Image) error {
+ ctx := context.Background()
+
+ // FIND TOP LAYER
+ keepLayers := -1
+ for idx, diffID := range i.inspect.RootFS.Layers {
+ if diffID == baseTopLayer {
+ keepLayers = len(i.inspect.RootFS.Layers) - idx - 1
+ break
+ }
+ }
+ if keepLayers == -1 {
+ return fmt.Errorf("'%s' not found in '%s' during rebase", baseTopLayer, i.repoName)
+ }
+
+ // SWITCH BASE LAYERS
+ newBaseInspect, _, err := i.docker.ImageInspectWithRaw(ctx, newBase.Name())
+ if err != nil {
+ return errors.Wrap(err, "analyze read previous image config")
+ }
+ i.inspect.RootFS.Layers = newBaseInspect.RootFS.Layers
+ i.layerPaths = make([]string, len(i.inspect.RootFS.Layers))
+
+ // DOWNLOAD IMAGE
+ fsImage, err := i.downloadImageOnce(i.repoName)
+ if err != nil {
+ return err
+ }
+
+ // READ MANIFEST.JSON
+ b, err := ioutil.ReadFile(filepath.Join(fsImage.dir, "manifest.json"))
+ if err != nil {
+ return err
+ }
+ var manifest []struct{ Layers []string }
+ if err := json.Unmarshal(b, &manifest); err != nil {
+ return err
+ }
+ if len(manifest) != 1 {
+ return fmt.Errorf("expected 1 image received %d", len(manifest))
+ }
+
+ // ADD EXISTING LAYERS
+ for _, filename := range manifest[0].Layers[(len(manifest[0].Layers) - keepLayers):] {
+ if err := i.AddLayer(filepath.Join(fsImage.dir, filename)); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (i *Image) SetLabel(key, val string) error {
+ if i.inspect.Config.Labels == nil {
+ i.inspect.Config.Labels = map[string]string{}
+ }
+
+ i.inspect.Config.Labels[key] = val
+ return nil
+}
+
+func (i *Image) SetEnv(key, val string) error {
+ i.inspect.Config.Env = append(i.inspect.Config.Env, fmt.Sprintf("%s=%s", key, val))
+ return nil
+}
+
+func (i *Image) SetWorkingDir(dir string) error {
+ i.inspect.Config.WorkingDir = dir
+ return nil
+}
+
+func (i *Image) SetEntrypoint(ep ...string) error {
+ i.inspect.Config.Entrypoint = ep
+ return nil
+}
+
+func (i *Image) SetCmd(cmd ...string) error {
+ i.inspect.Config.Cmd = cmd
+ return nil
+}
+
+func (i *Image) TopLayer() (string, error) {
+ all := i.inspect.RootFS.Layers
+
+ if len(all) == 0 {
+ return "", fmt.Errorf("image '%s' has no layers", i.repoName)
+ }
+
+ topLayer := all[len(all)-1]
+ return topLayer, nil
+}
+
+func (i *Image) GetLayer(diffID string) (io.ReadCloser, error) {
+ fsImage, err := i.downloadImageOnce(i.repoName)
+ if err != nil {
+ return nil, err
+ }
+
+ layerID, ok := fsImage.layersMap[diffID]
+ if !ok {
+ return nil, fmt.Errorf("image '%s' does not contain layer with diff ID '%s'", i.repoName, diffID)
+ }
+ return os.Open(filepath.Join(fsImage.dir, layerID))
+}
+
+func (i *Image) AddLayer(path string) error {
+ f, err := os.Open(path)
+ if err != nil {
+ return errors.Wrapf(err, "AddLayer: open layer: %s", path)
+ }
+ defer f.Close()
+ hasher := sha256.New()
+ if _, err := io.Copy(hasher, f); err != nil {
+ return errors.Wrapf(err, "AddLayer: calculate checksum: %s", path)
+ }
+ sha := hex.EncodeToString(hasher.Sum(make([]byte, 0, hasher.Size())))
+
+ i.inspect.RootFS.Layers = append(i.inspect.RootFS.Layers, "sha256:"+sha)
+ i.layerPaths = append(i.layerPaths, path)
+ i.easyAddLayers = nil
+
+ return nil
+}
+
+func (i *Image) ReuseLayer(diffID string) error {
+ if len(i.easyAddLayers) > 0 && i.easyAddLayers[0] == diffID {
+ i.inspect.RootFS.Layers = append(i.inspect.RootFS.Layers, diffID)
+ i.layerPaths = append(i.layerPaths, "")
+ i.easyAddLayers = i.easyAddLayers[1:]
+ return nil
+ }
+
+ if i.prevName == "" {
+ return errors.New("no previous image provided to reuse layers from")
+ }
+
+ fsImage, err := i.downloadImageOnce(i.prevName)
+ if err != nil {
+ return err
+ }
+
+ reuseLayer, ok := fsImage.layersMap[diffID]
+ if !ok {
+ return fmt.Errorf("SHA %s was not found in %s", diffID, i.repoName)
+ }
+
+ return i.AddLayer(filepath.Join(fsImage.dir, reuseLayer))
+}
+
+func (i *Image) Save(additionalNames ...string) error {
+ inspect, err := i.doSave()
+ if err != nil {
+ saveErr := imgutil.SaveError{}
+ for _, n := range append([]string{i.Name()}, additionalNames...) {
+ saveErr.Errors = append(saveErr.Errors, imgutil.SaveDiagnostic{ImageName: n, Cause: err})
+ }
+ return saveErr
+ }
+ i.inspect = inspect
+
+ var errs []imgutil.SaveDiagnostic
+ for _, n := range append([]string{i.Name()}, additionalNames...) {
+ if err := i.docker.ImageTag(context.Background(), i.inspect.ID, n); err != nil {
+ errs = append(errs, imgutil.SaveDiagnostic{ImageName: n, Cause: err})
+ }
+ }
+
+ if len(errs) > 0 {
+ return imgutil.SaveError{Errors: errs}
+ }
+
+ return nil
+}
+
+func (i *Image) doSave() (types.ImageInspect, error) {
+ ctx := context.Background()
+ done := make(chan error)
+
+ t, err := name.NewTag(i.repoName, name.WeakValidation)
+ if err != nil {
+ return types.ImageInspect{}, err
+ }
+ repoName := t.String()
+
+ pr, pw := io.Pipe()
+ defer pw.Close()
+ go func() {
+ res, err := i.docker.ImageLoad(ctx, pr, true)
+ if err != nil {
+ done <- err
+ return
+ }
+ defer res.Body.Close()
+ io.Copy(ioutil.Discard, res.Body)
+
+ done <- nil
+ }()
+
+ tw := tar.NewWriter(pw)
+ defer tw.Close()
+
+ configFile, err := i.newConfigFile()
+ if err != nil {
+ return types.ImageInspect{}, errors.Wrap(err, "generate config file")
+ }
+
+ id := fmt.Sprintf("%x", sha256.Sum256(configFile))
+ if err := addTextToTar(tw, id+".json", configFile); err != nil {
+ return types.ImageInspect{}, err
+ }
+
+ var layerPaths []string
+ for _, path := range i.layerPaths {
+ if path == "" {
+ layerPaths = append(layerPaths, "")
+ continue
+ }
+ layerName := fmt.Sprintf("/%x.tar", sha256.Sum256([]byte(path)))
+ f, err := os.Open(path)
+ if err != nil {
+ return types.ImageInspect{}, err
+ }
+ defer f.Close()
+ if err := addFileToTar(tw, layerName, f); err != nil {
+ return types.ImageInspect{}, err
+ }
+ f.Close()
+ layerPaths = append(layerPaths, layerName)
+
+ }
+
+ manifest, err := json.Marshal([]map[string]interface{}{
+ {
+ "Config": id + ".json",
+ "RepoTags": []string{repoName},
+ "Layers": layerPaths,
+ },
+ })
+ if err != nil {
+ return types.ImageInspect{}, err
+ }
+
+ if err := addTextToTar(tw, "manifest.json", manifest); err != nil {
+ return types.ImageInspect{}, err
+ }
+
+ tw.Close()
+ pw.Close()
+ err = <-done
+
+ i.requestGroup.Forget(i.repoName)
+
+ inspect, _, err := i.docker.ImageInspectWithRaw(context.Background(), id)
+ if err != nil {
+ if client.IsErrNotFound(err) {
+ return types.ImageInspect{}, errors.Wrapf(err, "save image '%s'", i.repoName)
+ }
+ return types.ImageInspect{}, err
+ }
+
+ return inspect, nil
+}
+
+func (i *Image) newConfigFile() ([]byte, error) {
+ imgConfig := map[string]interface{}{
+ "os": "linux",
+ "created": time.Now().Format(time.RFC3339),
+ "config": i.inspect.Config,
+ "rootfs": map[string][]string{
+ "diff_ids": i.inspect.RootFS.Layers,
+ },
+ "history": make([]struct{}, len(i.inspect.RootFS.Layers)),
+ }
+ return json.Marshal(imgConfig)
+}
+
+func (i *Image) Delete() error {
+ if !i.Found() {
+ return nil
+ }
+ options := types.ImageRemoveOptions{
+ Force: true,
+ PruneChildren: true,
+ }
+ _, err := i.docker.ImageRemove(context.Background(), i.inspect.ID, options)
+ return err
+}
+
+func (i *Image) downloadImageOnce(imageName string) (*FileSystemLocalImage, error) {
+ v, err, _ := i.requestGroup.Do(imageName, func() (details interface{}, err error) {
+ return downloadImage(i.docker, imageName)
+ })
+
+ if err != nil {
+ return nil, err
+ }
+
+ return v.(*FileSystemLocalImage), nil
+}
+
+func downloadImage(docker *client.Client, imageName string) (*FileSystemLocalImage, error) {
+ ctx := context.Background()
+
+ tarFile, err := docker.ImageSave(ctx, []string{imageName})
+ if err != nil {
+ return nil, err
+ }
+ defer tarFile.Close()
+
+ tmpDir, err := ioutil.TempDir("", "imgutil.local.image.")
+ if err != nil {
+ return nil, errors.Wrap(err, "local reuse-layer create temp dir")
+ }
+
+ err = untar(tarFile, tmpDir)
+ if err != nil {
+ return nil, err
+ }
+
+ mf, err := os.Open(filepath.Join(tmpDir, "manifest.json"))
+ if err != nil {
+ return nil, err
+ }
+ defer mf.Close()
+
+ var manifest []struct {
+ Config string
+ Layers []string
+ }
+ if err := json.NewDecoder(mf).Decode(&manifest); err != nil {
+ return nil, err
+ }
+
+ if len(manifest) != 1 {
+ return nil, fmt.Errorf("manifest.json had unexpected number of entries: %d", len(manifest))
+ }
+
+ df, err := os.Open(filepath.Join(tmpDir, manifest[0].Config))
+ if err != nil {
+ return nil, err
+ }
+ defer df.Close()
+
+ var details struct {
+ RootFS struct {
+ DiffIDs []string `json:"diff_ids"`
+ } `json:"rootfs"`
+ }
+
+ if err = json.NewDecoder(df).Decode(&details); err != nil {
+ return nil, err
+ }
+
+ if len(manifest[0].Layers) != len(details.RootFS.DiffIDs) {
+ return nil, fmt.Errorf("layers and diff IDs do not match, there are %d layers and %d diffIDs", len(manifest[0].Layers), len(details.RootFS.DiffIDs))
+ }
+
+ layersMap := make(map[string]string, len(manifest[0].Layers))
+ for i, diffID := range details.RootFS.DiffIDs {
+ layerID := manifest[0].Layers[i]
+ layersMap[diffID] = layerID
+ }
+
+ return &FileSystemLocalImage{
+ dir: tmpDir,
+ layersMap: layersMap,
+ }, nil
+}
+
+func addTextToTar(tw *tar.Writer, name string, contents []byte) error {
+ hdr := &tar.Header{Name: name, Mode: 0644, Size: int64(len(contents))}
+ if err := tw.WriteHeader(hdr); err != nil {
+ return err
+ }
+ _, err := tw.Write(contents)
+ return err
+}
+
+func addFileToTar(tw *tar.Writer, name string, contents *os.File) error {
+ fi, err := contents.Stat()
+ if err != nil {
+ return err
+ }
+ hdr := &tar.Header{Name: name, Mode: 0644, Size: int64(fi.Size())}
+ if err := tw.WriteHeader(hdr); err != nil {
+ return err
+ }
+ _, err = io.Copy(tw, contents)
+ return err
+}
+
+func untar(r io.Reader, dest string) error {
+ tr := tar.NewReader(r)
+ for {
+ hdr, err := tr.Next()
+ if err == io.EOF {
+ // end of tar archive
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+
+ path := filepath.Join(dest, hdr.Name)
+
+ switch hdr.Typeflag {
+ case tar.TypeDir:
+ if err := os.MkdirAll(path, hdr.FileInfo().Mode()); err != nil {
+ return err
+ }
+ case tar.TypeReg, tar.TypeRegA:
+ _, err := os.Stat(filepath.Dir(path))
+ if os.IsNotExist(err) {
+ if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+ return err
+ }
+ }
+
+ fh, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY, hdr.FileInfo().Mode())
+ if err != nil {
+ return err
+ }
+ if _, err := io.Copy(fh, tr); err != nil {
+ fh.Close()
+ return err
+ }
+ fh.Close()
+ case tar.TypeSymlink:
+ if err := os.Symlink(hdr.Linkname, path); err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("unknown file type in tar %d", hdr.Typeflag)
+ }
+ }
+}
+
+func inspectOptionalImage(docker *client.Client, imageName string) (types.ImageInspect, error) {
+ var (
+ err error
+ inspect types.ImageInspect
+ )
+
+ if inspect, _, err = docker.ImageInspectWithRaw(context.Background(), imageName); err != nil {
+ if client.IsErrNotFound(err) {
+ return defaultInspect(), nil
+ }
+
+ return types.ImageInspect{}, errors.Wrapf(err, "verifying image '%s'", imageName)
+ }
+
+ return inspect, nil
+}
+
+func defaultInspect() types.ImageInspect {
+ return types.ImageInspect{
+ Config: &container.Config{},
+ }
+}
diff --git a/vendor/github.com/buildpacks/imgutil/remote/identifier.go b/vendor/github.com/buildpacks/imgutil/remote/identifier.go
new file mode 100644
index 00000000000..56389053577
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/remote/identifier.go
@@ -0,0 +1,13 @@
+package remote
+
+import (
+ "github.com/google/go-containerregistry/pkg/name"
+)
+
+type DigestIdentifier struct {
+ Digest name.Digest
+}
+
+func (d DigestIdentifier) String() string {
+ return d.Digest.String()
+}
diff --git a/vendor/github.com/buildpacks/imgutil/remote/remote.go b/vendor/github.com/buildpacks/imgutil/remote/remote.go
new file mode 100644
index 00000000000..6a619a92d27
--- /dev/null
+++ b/vendor/github.com/buildpacks/imgutil/remote/remote.go
@@ -0,0 +1,432 @@
+package remote
+
+import (
+ "compress/gzip"
+ "fmt"
+ "io"
+ "net/http"
+ "strings"
+ "time"
+
+ "github.com/google/go-containerregistry/pkg/authn"
+ "github.com/google/go-containerregistry/pkg/name"
+ v1 "github.com/google/go-containerregistry/pkg/v1"
+ "github.com/google/go-containerregistry/pkg/v1/mutate"
+ "github.com/google/go-containerregistry/pkg/v1/random"
+ "github.com/google/go-containerregistry/pkg/v1/remote"
+ "github.com/google/go-containerregistry/pkg/v1/remote/transport"
+ "github.com/google/go-containerregistry/pkg/v1/tarball"
+ "github.com/google/go-containerregistry/pkg/v1/types"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/imgutil"
+)
+
+type Image struct {
+ keychain authn.Keychain
+ repoName string
+ image v1.Image
+ prevLayers []v1.Layer
+}
+
+type ImageOption func(*Image) (*Image, error)
+
+func WithPreviousImage(imageName string) ImageOption {
+ return func(r *Image) (*Image, error) {
+ var err error
+
+ prevImage, err := newV1Image(r.keychain, imageName)
+ if err != nil {
+ return nil, err
+ }
+
+ prevLayers, err := prevImage.Layers()
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to get layers for previous image with repo name '%s'", imageName)
+ }
+
+ r.prevLayers = prevLayers
+ return r, nil
+ }
+}
+
+func FromBaseImage(imageName string) ImageOption {
+ return func(r *Image) (*Image, error) {
+ var err error
+ r.image, err = newV1Image(r.keychain, imageName)
+ if err != nil {
+ return nil, err
+ }
+ return r, nil
+ }
+}
+
+func NewImage(repoName string, keychain authn.Keychain, ops ...ImageOption) (imgutil.Image, error) {
+ image, err := emptyImage()
+ if err != nil {
+ return nil, err
+ }
+
+ ri := &Image{
+ keychain: keychain,
+ repoName: repoName,
+ image: image,
+ }
+
+ for _, op := range ops {
+ ri, err = op(ri)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ return ri, nil
+}
+
+func newV1Image(keychain authn.Keychain, repoName string) (v1.Image, error) {
+ ref, auth, err := referenceForRepoName(keychain, repoName)
+ if err != nil {
+ return nil, err
+ }
+ image, err := remote.Image(ref, remote.WithAuth(auth), remote.WithTransport(http.DefaultTransport))
+ if err != nil {
+ if transportErr, ok := err.(*transport.Error); ok && len(transportErr.Errors) > 0 {
+ switch transportErr.Errors[0].Code {
+ case transport.UnauthorizedErrorCode, transport.ManifestUnknownErrorCode:
+ return emptyImage()
+ }
+ }
+ return nil, fmt.Errorf("connect to repo store '%s': %s", repoName, err.Error())
+ }
+ return image, nil
+}
+
+func emptyImage() (v1.Image, error) {
+ return random.Image(0, 0)
+}
+
+func referenceForRepoName(keychain authn.Keychain, ref string) (name.Reference, authn.Authenticator, error) {
+ var auth authn.Authenticator
+ r, err := name.ParseReference(ref, name.WeakValidation)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ auth, err = keychain.Resolve(r.Context().Registry)
+ if err != nil {
+ return nil, nil, err
+ }
+ return r, auth, nil
+}
+
+func (i *Image) Label(key string) (string, error) {
+ cfg, err := i.image.ConfigFile()
+ if err != nil || cfg == nil {
+ return "", fmt.Errorf("failed to get config file for image '%s'", i.repoName)
+ }
+ labels := cfg.Config.Labels
+ return labels[key], nil
+
+}
+
+func (i *Image) Env(key string) (string, error) {
+ cfg, err := i.image.ConfigFile()
+ if err != nil || cfg == nil {
+ return "", fmt.Errorf("failed to get config file for image '%s'", i.repoName)
+ }
+ for _, envVar := range cfg.Config.Env {
+ parts := strings.Split(envVar, "=")
+ if parts[0] == key {
+ return parts[1], nil
+ }
+ }
+ return "", nil
+}
+
+func (i *Image) Rename(name string) {
+ i.repoName = name
+}
+
+func (i *Image) Name() string {
+ return i.repoName
+}
+
+func (i *Image) Found() bool {
+ ref, auth, err := referenceForRepoName(i.keychain, i.repoName)
+ if err != nil {
+ return false
+ }
+ _, err = remote.Image(ref, remote.WithAuth(auth), remote.WithTransport(http.DefaultTransport))
+ if err != nil {
+ return false
+ }
+ return true
+}
+
+func (i *Image) Identifier() (imgutil.Identifier, error) {
+ ref, err := name.ParseReference(i.repoName, name.WeakValidation)
+ if err != nil {
+ return nil, fmt.Errorf("failed to parse reference for image '%s': %s", i.repoName, err)
+ }
+
+ hash, err := i.image.Digest()
+ if err != nil {
+ return nil, fmt.Errorf("failed to get digest for image '%s': %s", i.repoName, err)
+ }
+
+ digestRef, err := name.NewDigest(fmt.Sprintf("%s@%s", ref.Context().Name(), hash.String()), name.WeakValidation)
+ if err != nil {
+ return nil, errors.Wrap(err, "creating digest reference")
+ }
+
+ return DigestIdentifier{
+ Digest: digestRef,
+ }, nil
+}
+
+func (i *Image) CreatedAt() (time.Time, error) {
+ configFile, err := i.image.ConfigFile()
+ if err != nil {
+ return time.Time{}, fmt.Errorf("failed to get createdAt time for image '%s': %s", i.repoName, err)
+ }
+ return configFile.Created.UTC(), nil
+}
+
+func (i *Image) Rebase(baseTopLayer string, newBase imgutil.Image) error {
+ newBaseRemote, ok := newBase.(*Image)
+ if !ok {
+ return errors.New("expected new base to be a remote image")
+ }
+
+ newImage, err := mutate.Rebase(i.image, &subImage{img: i.image, topDiffID: baseTopLayer}, newBaseRemote.image)
+ if err != nil {
+ return errors.Wrap(err, "rebase")
+ }
+ i.image = newImage
+ return nil
+}
+
+func (i *Image) SetLabel(key, val string) error {
+ configFile, err := i.image.ConfigFile()
+ if err != nil {
+ return err
+ }
+ config := *configFile.Config.DeepCopy()
+ if config.Labels == nil {
+ config.Labels = map[string]string{}
+ }
+ config.Labels[key] = val
+ i.image, err = mutate.Config(i.image, config)
+ return err
+}
+
+func (i *Image) SetEnv(key, val string) error {
+ configFile, err := i.image.ConfigFile()
+ if err != nil {
+ return err
+ }
+ config := *configFile.Config.DeepCopy()
+ for idx, e := range config.Env {
+ parts := strings.Split(e, "=")
+ if parts[0] == key {
+ config.Env[idx] = fmt.Sprintf("%s=%s", key, val)
+ i.image, err = mutate.Config(i.image, config)
+ if err != nil {
+ return err
+ }
+ return nil
+ }
+ }
+ config.Env = append(config.Env, fmt.Sprintf("%s=%s", key, val))
+ i.image, err = mutate.Config(i.image, config)
+ return err
+}
+
+func (i *Image) SetWorkingDir(dir string) error {
+ configFile, err := i.image.ConfigFile()
+ if err != nil {
+ return err
+ }
+ config := *configFile.Config.DeepCopy()
+ config.WorkingDir = dir
+ i.image, err = mutate.Config(i.image, config)
+ return err
+}
+
+func (i *Image) SetEntrypoint(ep ...string) error {
+ configFile, err := i.image.ConfigFile()
+ if err != nil {
+ return err
+ }
+ config := *configFile.Config.DeepCopy()
+ config.Entrypoint = ep
+ i.image, err = mutate.Config(i.image, config)
+ return err
+}
+
+func (i *Image) SetCmd(cmd ...string) error {
+ configFile, err := i.image.ConfigFile()
+ if err != nil {
+ return err
+ }
+ config := *configFile.Config.DeepCopy()
+ config.Cmd = cmd
+ i.image, err = mutate.Config(i.image, config)
+ return err
+}
+
+func (i *Image) TopLayer() (string, error) {
+ all, err := i.image.Layers()
+ if err != nil {
+ return "", err
+ }
+ if len(all) == 0 {
+ return "", fmt.Errorf("image %s has no layers", i.Name())
+ }
+ topLayer := all[len(all)-1]
+ hex, err := topLayer.DiffID()
+ if err != nil {
+ return "", err
+ }
+ return hex.String(), nil
+}
+
+func (i *Image) GetLayer(sha string) (io.ReadCloser, error) {
+ layers, err := i.image.Layers()
+ if err != nil {
+ return nil, err
+ }
+
+ layer, err := findLayerWithSha(layers, sha)
+ if err != nil {
+ return nil, err
+ }
+
+ return layer.Uncompressed()
+}
+
+func (i *Image) AddLayer(path string) error {
+ layer, err := tarball.LayerFromFile(path, tarball.WithCompressionLevel(gzip.DefaultCompression))
+ if err != nil {
+ return err
+ }
+ i.image, err = mutate.AppendLayers(i.image, layer)
+ if err != nil {
+ return errors.Wrap(err, "add layer")
+ }
+ return nil
+}
+
+func (i *Image) ReuseLayer(sha string) error {
+ layer, err := findLayerWithSha(i.prevLayers, sha)
+ if err != nil {
+ return err
+ }
+ i.image, err = mutate.AppendLayers(i.image, layer)
+ return err
+}
+
+func findLayerWithSha(layers []v1.Layer, diffID string) (v1.Layer, error) {
+ for _, layer := range layers {
+ dID, err := layer.DiffID()
+ if err != nil {
+ return nil, errors.Wrap(err, "get diff ID for previous image layer")
+ }
+ if diffID == dID.String() {
+ return layer, nil
+ }
+ }
+ return nil, fmt.Errorf(`previous image did not have layer with diff id '%s'`, diffID)
+}
+
+func (i *Image) Save(additionalNames ...string) error {
+ var err error
+
+ allNames := append([]string{i.repoName}, additionalNames...)
+
+ i.image, err = mutate.CreatedAt(i.image, v1.Time{Time: time.Now()})
+ if err != nil {
+ return errors.Wrap(err, "set creation time")
+ }
+
+ cfg, err := i.image.ConfigFile()
+ if err != nil {
+ return errors.Wrap(err, "get image config")
+ }
+
+ layers, err := i.image.Layers()
+ if err != nil {
+ return errors.Wrap(err, "get image layers")
+ }
+
+ cfg.History = make([]v1.History, len(layers))
+ i.image, err = mutate.ConfigFile(i.image, cfg)
+ if err != nil {
+ return errors.Wrap(err, "zeroing history")
+ }
+
+ var diagnostics []imgutil.SaveDiagnostic
+ for _, n := range allNames {
+ if err := i.doSave(n); err != nil {
+ diagnostics = append(diagnostics, imgutil.SaveDiagnostic{ImageName: n, Cause: err})
+ }
+ }
+ if len(diagnostics) > 0 {
+ return imgutil.SaveError{Errors: diagnostics}
+ }
+
+ return nil
+}
+
+func (i *Image) doSave(imageName string) error {
+ ref, auth, err := referenceForRepoName(i.keychain, imageName)
+ if err != nil {
+ return err
+ }
+ return remote.Write(ref, i.image, remote.WithAuth(auth))
+}
+
+func (i *Image) Delete() error {
+ id, err := i.Identifier()
+ if err != nil {
+ return err
+ }
+ ref, auth, err := referenceForRepoName(i.keychain, id.String())
+ if err != nil {
+ return err
+ }
+ return remote.Delete(ref, remote.WithAuth(auth))
+}
+
+type subImage struct {
+ img v1.Image
+ topDiffID string
+}
+
+func (si *subImage) Layers() ([]v1.Layer, error) {
+ all, err := si.img.Layers()
+ if err != nil {
+ return nil, err
+ }
+ for i, l := range all {
+ d, err := l.DiffID()
+ if err != nil {
+ return nil, err
+ }
+ if d.String() == si.topDiffID {
+ return all[0 : i+1], nil
+ }
+ }
+ return nil, errors.New("could not find base layer in image")
+}
+func (si *subImage) BlobSet() (map[v1.Hash]struct{}, error) { panic("Not Implemented") }
+func (si *subImage) MediaType() (types.MediaType, error) { panic("Not Implemented") }
+func (si *subImage) ConfigName() (v1.Hash, error) { panic("Not Implemented") }
+func (si *subImage) ConfigFile() (*v1.ConfigFile, error) { panic("Not Implemented") }
+func (si *subImage) RawConfigFile() ([]byte, error) { panic("Not Implemented") }
+func (si *subImage) Digest() (v1.Hash, error) { panic("Not Implemented") }
+func (si *subImage) Manifest() (*v1.Manifest, error) { panic("Not Implemented") }
+func (si *subImage) RawManifest() ([]byte, error) { panic("Not Implemented") }
+func (si *subImage) LayerByDigest(v1.Hash) (v1.Layer, error) { panic("Not Implemented") }
+func (si *subImage) LayerByDiffID(v1.Hash) (v1.Layer, error) { panic("Not Implemented") }
+func (si *subImage) Size() (int64, error) { panic("Not Implemented") }
diff --git a/vendor/github.com/buildpacks/lifecycle/.gitignore b/vendor/github.com/buildpacks/lifecycle/.gitignore
new file mode 100644
index 00000000000..1ae2ae2df48
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/.gitignore
@@ -0,0 +1,6 @@
+.DS_Store
+.idea
+*.coverprofile
+*.test
+*~
+/out
diff --git a/vendor/github.com/buildpacks/lifecycle/.travis.yml b/vendor/github.com/buildpacks/lifecycle/.travis.yml
new file mode 100644
index 00000000000..3cef38717ed
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/.travis.yml
@@ -0,0 +1,8 @@
+language: go
+go:
+- 1.13.x
+script:
+- make test
+branches:
+ only:
+ - master
diff --git a/vendor/github.com/buildpacks/lifecycle/LICENSE b/vendor/github.com/buildpacks/lifecycle/LICENSE
new file mode 100644
index 00000000000..a83b6322182
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2018 Stephen Levine
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/buildpacks/lifecycle/Makefile b/vendor/github.com/buildpacks/lifecycle/Makefile
new file mode 100644
index 00000000000..6ddad5990db
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/Makefile
@@ -0,0 +1,90 @@
+GOCMD?=go
+GOENV=GOARCH=amd64 CGO_ENABLED=0
+GOBUILD=$(GOCMD) build -mod=vendor -ldflags "-s -w -X 'github.com/buildpacks/lifecycle/cmd.Version=$(LIFECYCLE_VERSION)' -X 'github.com/buildpacks/lifecycle/cmd.SCMRepository=$(SCM_REPO)' -X 'github.com/buildpacks/lifecycle/cmd.SCMCommit=$(SCM_COMMIT)'"
+GOTEST=$(GOCMD) test -mod=vendor
+LIFECYCLE_VERSION?=0.0.0
+PLATFORM_API=0.2
+BUILDPACK_API=0.2
+SCM_REPO?=
+SCM_COMMIT=$$(git rev-parse --short HEAD)
+ARCHIVE_NAME=lifecycle-v$(LIFECYCLE_VERSION)+linux.x86-64
+
+define LIFECYCLE_DESCRIPTOR
+[api]
+ platform = "$(PLATFORM_API)"
+ buildpack = "$(BUILDPACK_API)"
+
+[lifecycle]
+ version = "$(LIFECYCLE_VERSION)"
+endef
+
+all: test build package
+
+build: build-linux
+
+build-macos:
+ @echo "> Building for macos..."
+ mkdir -p ./out/lifecycle
+ GOOS=darwin $(GOENV) $(GOBUILD) -o ./out/lifecycle -a ./cmd/...
+
+build-linux:
+ @echo "> Building for linux..."
+ mkdir -p ./out/lifecycle
+ GOOS=linux $(GOENV) $(GOBUILD) -o ./out/lifecycle -a ./cmd/...
+
+build-windows:
+ @echo "> Building for windows..."
+ mkdir -p ./out/lifecycle
+ GOOS=windows $(GOENV) $(GOBUILD) -o ./out/lifecycle -a ./cmd/...
+
+descriptor: export LIFECYCLE_DESCRIPTOR:=$(LIFECYCLE_DESCRIPTOR)
+descriptor:
+ @echo "> Writing descriptor file..."
+ mkdir -p ./out
+ echo "$${LIFECYCLE_DESCRIPTOR}" > ./out/lifecycle.toml
+
+install-goimports:
+ @echo "> Installing goimports..."
+ cd tools; $(GOCMD) install -mod=vendor golang.org/x/tools/cmd/goimports
+
+install-yj:
+ @echo "> Installing yj..."
+ cd tools; $(GOCMD) install -mod=vendor github.com/sclevine/yj
+
+install-mockgen:
+ @echo "> Installing mockgen..."
+ cd tools; $(GOCMD) install -mod=vendor github.com/golang/mock/mockgen
+
+install-golangci-lint:
+ @echo "> Installing golangci-lint..."
+ cd tools; $(GOCMD) install -mod=vendor github.com/golangci/golangci-lint/cmd/golangci-lint
+
+lint: install-golangci-lint
+ @echo "> Linting code..."
+ @golangci-lint run -c golangci.yaml
+
+generate: install-mockgen
+ @echo "> Generating..."
+ $(GOCMD) generate
+
+format: install-goimports
+ @echo "> Formating code..."
+ test -z $$(goimports -l -w -local github.com/buildpacks/lifecycle $$(find . -type f -name '*.go' -not -path "*/vendor/*"))
+
+test: unit acceptance
+
+unit: format lint install-yj
+ @echo "> Running unit tests..."
+ $(GOTEST) -v -count=1 ./...
+
+acceptance: format lint
+ @echo "> Running acceptance tests..."
+ $(GOTEST) -v -count=1 -tags=acceptance ./acceptance/...
+
+clean:
+ @echo "> Cleaning workspace..."
+ rm -rf ./out
+
+package: descriptor
+ @echo "> Packaging lifecycle..."
+ tar czf ./out/$(ARCHIVE_NAME).tgz -C out lifecycle.toml lifecycle
diff --git a/vendor/github.com/buildpacks/lifecycle/README.md b/vendor/github.com/buildpacks/lifecycle/README.md
new file mode 100644
index 00000000000..92b8fa8f5f1
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/README.md
@@ -0,0 +1,80 @@
+# Lifecycle
+
+[![Build Status](https://travis-ci.org/buildpacks/lifecycle.svg?branch=master)](https://travis-ci.org/buildpack/lifecycle)
+[![GoDoc](https://godoc.org/github.com/buildpacks/lifecycle?status.svg)](https://godoc.org/github.com/buildpacks/lifecycle)
+
+A reference implementation of [Buildpack API v3](https://github.com/buildpacks/spec).
+
+## Commands
+
+### Build
+
+* `detector` - chooses buildpacks (via `/bin/detect`)
+* `analyzer` - restores launch layer metadata from the previous build
+* `builder` - executes buildpacks (via `/bin/build`)
+* `exporter` - remotely patches images with new layers (via rebase & append)
+* `launcher` - invokes choice of process
+
+### Develop
+
+* `detector` - chooses buildpacks (via `/bin/detect`)
+* `developer` - executes buildpacks (via `/bin/develop`)
+* `launcher` - invokes choice of process
+
+### Cache
+
+* `restorer` - restores cache
+* `cacher` - updates cache
+
+### Rebase
+
+* `rebaser` - remotely patches images with new base image
+
+## Notes
+
+Cache implementations (`restorer` and `cacher`) are intended to be interchangeable and platform-specific.
+A platform may choose not to deduplicate cache layers.
+
+## Development
+To test, build, and package binaries into an archive, simply run:
+
+```bash
+$ make all
+```
+This will create an archive at `out/lifecycle-+linux.x86-64.tgz`.
+
+By default, `LIFECYCLE_VERSION` is `0.0.0`. It can be changed by prepending `LIFECYCLE_VERSION=` to the
+`make` command. For example:
+
+```bash
+$ LIFECYCLE_VERSION=1.2.3 make all
+```
+
+Steps can also be run individually as shown below.
+
+### Test
+
+Formats, vets, and tests the code.
+
+```bash
+$ make test
+```
+
+### Build
+
+Builds binaries to `out/lifecycle/`.
+
+```bash
+$ make build
+```
+
+> To clean the `out/` directory, run `make clean`.
+
+### Package
+
+Creates an archive at `out/lifecycle-+linux.x86-64.tgz`, using the contents of the
+`out/lifecycle/` directory, for the given (or default) `LIFECYCLE_VERSION`.
+
+```bash
+$ make package
+```
diff --git a/vendor/github.com/buildpacks/lifecycle/analyzer.go b/vendor/github.com/buildpacks/lifecycle/analyzer.go
new file mode 100644
index 00000000000..5b258e6aeb7
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/analyzer.go
@@ -0,0 +1,136 @@
+package lifecycle
+
+import (
+ "fmt"
+ "os"
+
+ "github.com/buildpacks/imgutil"
+ "github.com/pkg/errors"
+)
+
+type Analyzer struct {
+ AnalyzedPath string
+ AppDir string
+ Buildpacks []Buildpack
+ GID, UID int
+ LayersDir string
+ Logger Logger
+ SkipLayers bool
+}
+
+// Analyze restores metadata for launch and cache layers into the layers directory.
+// If a usable cache is not provided, Analyze will not restore any cache=true layer metadata.
+func (a *Analyzer) Analyze(image imgutil.Image, cache Cache) (*AnalyzedMetadata, error) {
+ imageID, err := a.getImageIdentifier(image)
+ if err != nil {
+ return nil, errors.Wrap(err, "retrieving image identifier")
+ }
+
+ var appMeta LayersMetadata
+ // continue even if the label cannot be decoded
+ if err := DecodeLabel(image, LayerMetadataLabel, &appMeta); err != nil {
+ appMeta = LayersMetadata{}
+ }
+
+ if a.SkipLayers {
+ a.Logger.Infof("Skipping buildpack layer analysis")
+ return &AnalyzedMetadata{
+ Image: imageID,
+ Metadata: appMeta,
+ }, nil
+ }
+
+ // Create empty cache metadata in case a usable cache is not provided.
+ var cacheMeta CacheMetadata
+ if cache != nil {
+ var err error
+ cacheMeta, err = cache.RetrieveMetadata()
+ if err != nil {
+ return nil, errors.Wrap(err, "retrieving cache metadata")
+ }
+ } else {
+ a.Logger.Debug("Usable cache not provided, using empty cache metadata.")
+ }
+
+ for _, buildpack := range a.Buildpacks {
+ buildpackDir, err := readBuildpackLayersDir(a.LayersDir, buildpack)
+ if err != nil {
+ return nil, errors.Wrap(err, "reading buildpack layer directory")
+ }
+
+ // Restore metadata for launch=true layers.
+ // The restorer step will restore the layer data for cache=true layers if possible or delete the layer.
+ appLayers := appMeta.MetadataForBuildpack(buildpack.ID).Layers
+ for name, layer := range appLayers {
+ identifier := fmt.Sprintf("%s:%s", buildpack.ID, name)
+ if !layer.Launch {
+ a.Logger.Debugf("Not restoring metadata for %q, marked as launch=false", identifier)
+ continue
+ }
+ if layer.Build && !layer.Cache {
+ a.Logger.Debugf("Not restoring metadata for %q, marked as build=true, cache=false", identifier)
+ continue
+ }
+ a.Logger.Infof("Restoring metadata for %q from app image", identifier)
+ if err := a.writeLayerMetadata(buildpackDir, name, layer); err != nil {
+ return nil, err
+ }
+ }
+
+ // Restore metadata for cache=true layers.
+ // The restorer step will restore the layer data if possible or delete the layer.
+ cachedLayers := cacheMeta.MetadataForBuildpack(buildpack.ID).Layers
+ for name, layer := range cachedLayers {
+ identifier := fmt.Sprintf("%s:%s", buildpack.ID, name)
+ if !layer.Cache {
+ a.Logger.Debugf("Not restoring %q from cache, marked as cache=false", identifier)
+ continue
+ }
+ // If launch=true, the metadata was restored from the app image or the layer is stale.
+ if layer.Launch {
+ a.Logger.Debugf("Not restoring %q from cache, marked as launch=true", identifier)
+ continue
+ }
+ a.Logger.Infof("Restoring metadata for %q from cache", identifier)
+ if err := a.writeLayerMetadata(buildpackDir, name, layer); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ // if analyzer is running as root it needs to fix the ownership of the layers dir
+ if current := os.Getuid(); current == 0 {
+ if err := recursiveChown(a.LayersDir, a.UID, a.GID); err != nil {
+ return nil, errors.Wrapf(err, "chowning layers dir to '%d/%d'", a.UID, a.GID)
+ }
+ }
+
+ return &AnalyzedMetadata{
+ Image: imageID,
+ Metadata: appMeta,
+ }, nil
+}
+
+func (a *Analyzer) getImageIdentifier(image imgutil.Image) (*ImageIdentifier, error) {
+ if !image.Found() {
+ a.Logger.Warnf("Image %q not found", image.Name())
+ return nil, nil
+ }
+ identifier, err := image.Identifier()
+ if err != nil {
+ return nil, err
+ }
+ a.Logger.Debugf("Analyzing image %q", identifier.String())
+ return &ImageIdentifier{
+ Reference: identifier.String(),
+ }, nil
+}
+
+func (a *Analyzer) writeLayerMetadata(buildpackDir bpLayersDir, name string, metadata BuildpackLayerMetadata) error {
+ layer := buildpackDir.newBPLayer(name)
+ a.Logger.Debugf("Writing layer metadata for %q", layer.Identifier())
+ if err := layer.writeMetadata(metadata); err != nil {
+ return err
+ }
+ return layer.writeSha(metadata.SHA)
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/archive/tar.go b/vendor/github.com/buildpacks/lifecycle/archive/tar.go
new file mode 100644
index 00000000000..452a9c7eb12
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/archive/tar.go
@@ -0,0 +1,280 @@
+package archive
+
+import (
+ "archive/tar"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "time"
+)
+
+func WriteFilesToTar(dest string, uid, gid int, files ...string) (string, map[string]struct{}, error) {
+ hasher := sha256.New()
+ f, err := os.Create(dest)
+ if err != nil {
+ return "", nil, err
+ }
+ defer f.Close()
+
+ w := io.MultiWriter(hasher, f)
+ tw := tar.NewWriter(w)
+
+ fileSet := map[string]struct{}{}
+ for _, file := range files {
+ if AddFileToArchive(tw, file, uid, gid, fileSet) != nil {
+ return "", nil, err
+ }
+ }
+ _ = tw.Close()
+
+ sha := hex.EncodeToString(hasher.Sum(make([]byte, 0, hasher.Size())))
+ return "sha256:" + sha, fileSet, nil
+}
+
+func AddFileToArchive(tw *tar.Writer, srcDir string, uid, gid int, fileSet map[string]struct{}) error {
+ err := addParentDirsUnique(srcDir, tw, uid, gid, fileSet)
+ if err != nil {
+ return err
+ }
+
+ return filepath.Walk(srcDir, func(file string, fi os.FileInfo, err error) error {
+ if _, ok := fileSet[file]; ok {
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ if fi.Mode()&os.ModeSocket != 0 {
+ return nil
+ }
+ var header *tar.Header
+ var target string
+ if fi.Mode()&os.ModeSymlink != 0 {
+ target, err = os.Readlink(file)
+ if err != nil {
+ return err
+ }
+ }
+ header, err = tar.FileInfoHeader(fi, target)
+ if err != nil {
+ return err
+ }
+ header.Name = file
+ header.ModTime = time.Date(1980, time.January, 1, 0, 0, 1, 0, time.UTC)
+ header.Uid = uid
+ header.Gid = gid
+ header.Uname = ""
+ header.Gname = ""
+
+ if err := tw.WriteHeader(header); err != nil {
+ return err
+ }
+ if fi.Mode().IsRegular() {
+ f, err := os.Open(file)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ if _, err := io.Copy(tw, f); err != nil {
+ return err
+ }
+ }
+
+ fileSet[file] = struct{}{}
+ return nil
+ })
+}
+
+func WriteTarFile(sourceDir, dest string, uid, gid int) (string, error) {
+ hasher := sha256.New()
+ f, err := os.Create(dest)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+ w := io.MultiWriter(hasher, f)
+
+ if err := WriteTarArchive(w, sourceDir, uid, gid); err != nil {
+ return "", err
+ }
+ sha := hex.EncodeToString(hasher.Sum(make([]byte, 0, hasher.Size())))
+ return "sha256:" + sha, nil
+}
+
+func WriteTarArchive(w io.Writer, srcDir string, uid, gid int) error {
+ tw := tar.NewWriter(w)
+ defer tw.Close()
+
+ err := addParentDirs(srcDir, tw, uid, gid)
+ if err != nil {
+ return err
+ }
+
+ return filepath.Walk(srcDir, func(file string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if fi.Mode()&os.ModeSocket != 0 {
+ return nil
+ }
+ var header *tar.Header
+ var target string
+ if fi.Mode()&os.ModeSymlink != 0 {
+ target, err = os.Readlink(file)
+ if err != nil {
+ return err
+ }
+ }
+ header, err = tar.FileInfoHeader(fi, target)
+ if err != nil {
+ return err
+ }
+ header.Name = file
+ header.ModTime = time.Date(1980, time.January, 1, 0, 0, 1, 0, time.UTC)
+ header.Uid = uid
+ header.Gid = gid
+ header.Uname = ""
+ header.Gname = ""
+
+ if err := tw.WriteHeader(header); err != nil {
+ return err
+ }
+ if fi.Mode().IsRegular() {
+ f, err := os.Open(file)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ if _, err := io.Copy(tw, f); err != nil {
+ return err
+ }
+ }
+ return nil
+ })
+}
+
+func addParentDirsUnique(tarDir string, tw *tar.Writer, uid, gid int, parentDirs map[string]struct{}) error {
+ parent := filepath.Dir(tarDir)
+ if parent == "." || parent == "/" {
+ return nil
+ }
+
+ if _, ok := parentDirs[parent]; ok {
+ return nil
+ }
+
+ if err := addParentDirsUnique(parent, tw, uid, gid, parentDirs); err != nil {
+ return err
+ }
+
+ info, err := os.Stat(parent)
+ if err != nil {
+ return err
+ }
+
+ header, err := tar.FileInfoHeader(info, parent)
+ if err != nil {
+ return err
+ }
+ header.Name = parent
+ header.ModTime = time.Date(1980, time.January, 1, 0, 0, 1, 0, time.UTC)
+
+ parentDirs[parent] = struct{}{}
+
+ return tw.WriteHeader(header)
+}
+
+func addParentDirs(tarDir string, tw *tar.Writer, uid, gid int) error {
+ parent := filepath.Dir(tarDir)
+ if parent == "." || parent == "/" {
+ return nil
+ }
+
+ if err := addParentDirs(parent, tw, uid, gid); err != nil {
+ return err
+ }
+
+ info, err := os.Stat(parent)
+ if err != nil {
+ return err
+ }
+
+ header, err := tar.FileInfoHeader(info, parent)
+ if err != nil {
+ return err
+ }
+ header.Name = parent
+ header.ModTime = time.Date(1980, time.January, 1, 0, 0, 1, 0, time.UTC)
+
+ return tw.WriteHeader(header)
+}
+
+type PathMode struct {
+ Path string
+ Mode os.FileMode
+}
+
+func Untar(r io.Reader, dest string) error {
+ tr := tar.NewReader(r)
+ var pathModes []PathMode
+ for {
+ hdr, err := tr.Next()
+ if err == io.EOF {
+ for _, pathMode := range pathModes {
+ if err := os.Chmod(pathMode.Path, pathMode.Mode); err != nil {
+ return err
+ }
+ }
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+
+ path := filepath.Join(dest, hdr.Name)
+
+ switch hdr.Typeflag {
+ case tar.TypeDir:
+ if _, err := os.Stat(path); os.IsNotExist(err) {
+ pathMode := PathMode{path, hdr.FileInfo().Mode()}
+ pathModes = append(pathModes, pathMode)
+ }
+ if err := os.MkdirAll(path, os.ModePerm); err != nil {
+ return err
+ }
+ case tar.TypeReg, tar.TypeRegA:
+ _, err := os.Stat(filepath.Dir(path))
+ if os.IsNotExist(err) {
+ if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil {
+ return err
+ }
+ }
+ if err := writeFile(tr, path, hdr.FileInfo().Mode()); err != nil {
+ return err
+ }
+ // Update permissions in case umask was applied.
+ if err := os.Chmod(path, hdr.FileInfo().Mode()); err != nil {
+ return err
+ }
+ case tar.TypeSymlink:
+ if err := os.Symlink(hdr.Linkname, path); err != nil {
+ return err
+ }
+ default:
+ return fmt.Errorf("unknown file type in tar %d", hdr.Typeflag)
+ }
+ }
+}
+
+func writeFile(in io.Reader, path string, mode os.FileMode) error {
+ fh, err := os.OpenFile(path, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, mode)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ _, err = io.Copy(fh, in)
+ return err
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/auth/env_keychain.go b/vendor/github.com/buildpacks/lifecycle/auth/env_keychain.go
new file mode 100644
index 00000000000..55ac4f21e31
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/auth/env_keychain.go
@@ -0,0 +1,161 @@
+package auth
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "os"
+ "regexp"
+
+ "github.com/google/go-containerregistry/pkg/authn"
+ "github.com/google/go-containerregistry/pkg/name"
+ "github.com/pkg/errors"
+)
+
+// EnvKeychain creates a keychain augmenting the default keychain with information from an environment variable.
+//
+// See `ReadEnvVar`.
+func EnvKeychain(envVar string) authn.Keychain {
+ return authn.NewMultiKeychain(&envKeychain{envVar: envVar}, authn.DefaultKeychain)
+}
+
+type envKeychain struct {
+ envVar string
+}
+
+func (k *envKeychain) Resolve(resource authn.Resource) (authn.Authenticator, error) {
+ authHeaders, err := ReadEnvVar(k.envVar)
+ if err != nil {
+ return nil, errors.Wrap(err, "reading auth env var")
+ }
+
+ header, ok := authHeaders[resource.RegistryStr()]
+ if ok {
+ authConfig, err := authHeaderToConfig(header)
+ if err != nil {
+ return nil, errors.Wrapf(err, "parsing auth header '%s'", header)
+ }
+
+ return &providedAuth{config: authConfig}, nil
+ }
+
+ return authn.Anonymous, nil
+}
+
+type providedAuth struct {
+ config *authn.AuthConfig
+}
+
+func (p *providedAuth) Authorization() (*authn.AuthConfig, error) {
+ return p.config, nil
+}
+
+// ReadEnvVar parses an environment variable to produce a map of 'registry url' to 'authorization header'.
+//
+// Complementary to `BuildEnvVar`.
+//
+// Example Input:
+// {"gcr.io": "Bearer asdf=", "docker.io": "Basic qwerty="}
+//
+// Example Output:
+// gcr.io -> Bearer asdf=
+// docker.io -> Basic qwerty=
+func ReadEnvVar(envVar string) (map[string]string, error) {
+ authMap := map[string]string{}
+
+ env := os.Getenv(envVar)
+ if env != "" {
+ err := json.Unmarshal([]byte(env), &authMap)
+ if err != nil {
+ return nil, errors.Wrapf(err, "failed to parse %s value", envVar)
+ }
+ }
+
+ return authMap, nil
+}
+
+// BuildEnvVar creates the contents to use for authentication environment variable.
+//
+// Complementary to `ReadEnvVar`.
+func BuildEnvVar(keychain authn.Keychain, images ...string) (string, error) {
+ registryAuths := map[string]string{}
+
+ for _, image := range images {
+ reference, authenticator, err := ReferenceForRepoName(keychain, image)
+ if err != nil {
+ return "", nil
+ }
+ if authenticator == authn.Anonymous {
+ continue
+ }
+
+ authConfig, err := authenticator.Authorization()
+ if err != nil {
+ return "", nil
+ }
+
+ registryAuths[reference.Context().Registry.Name()], err = authConfigToHeader(authConfig)
+ if err != nil {
+ return "", nil
+ }
+ }
+
+ authData, err := json.Marshal(registryAuths)
+ if err != nil {
+ return "", err
+ }
+ return string(authData), nil
+}
+
+func authConfigToHeader(config *authn.AuthConfig) (string, error) {
+ if config.Auth != "" {
+ return fmt.Sprintf("Basic %s", config.Auth), nil
+ }
+
+ if config.RegistryToken != "" {
+ return fmt.Sprintf("Bearer %s", config.RegistryToken), nil
+ }
+
+ if config.Username != "" && config.Password != "" {
+ delimited := fmt.Sprintf("%s:%s", config.Username, config.Password)
+ encoded := base64.StdEncoding.EncodeToString([]byte(delimited))
+ return fmt.Sprintf("Basic %s", encoded), nil
+ }
+
+ return "", nil
+}
+
+var (
+ basicAuthRegExp = regexp.MustCompile("(?i)^basic (.*)$")
+ bearerAuthRegExp = regexp.MustCompile("(?i)^bearer (.*)$")
+)
+
+func authHeaderToConfig(header string) (*authn.AuthConfig, error) {
+ if matches := basicAuthRegExp.FindAllStringSubmatch(header, -1); len(matches) != 0 {
+ return &authn.AuthConfig{
+ Auth: matches[0][1],
+ }, nil
+ }
+
+ if matches := bearerAuthRegExp.FindAllStringSubmatch(header, -1); len(matches) != 0 {
+ return &authn.AuthConfig{
+ RegistryToken: matches[0][1],
+ }, nil
+ }
+
+ return nil, errors.Errorf("unknown auth type from header: %s", header)
+}
+
+func ReferenceForRepoName(keychain authn.Keychain, ref string) (name.Reference, authn.Authenticator, error) {
+ var auth authn.Authenticator
+ r, err := name.ParseReference(ref, name.WeakValidation)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ auth, err = keychain.Resolve(r.Context().Registry)
+ if err != nil {
+ return nil, nil, err
+ }
+ return r, auth, nil
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/builder.go b/vendor/github.com/buildpacks/lifecycle/builder.go
new file mode 100644
index 00000000000..8c1be5dc58e
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/builder.go
@@ -0,0 +1,232 @@
+package lifecycle
+
+import (
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sort"
+
+ "github.com/BurntSushi/toml"
+)
+
+type Builder struct {
+ AppDir string
+ LayersDir string
+ PlatformDir string
+ BuildpacksDir string
+ Env BuildEnv
+ Group BuildpackGroup
+ Plan BuildPlan
+ Out, Err *log.Logger
+}
+
+type BuildEnv interface {
+ AddRootDir(baseDir string) error
+ AddEnvDir(envDir string) error
+ WithPlatform(platformDir string) ([]string, error)
+ List() []string
+}
+
+type Process struct {
+ Type string `toml:"type" json:"type"`
+ Command string `toml:"command" json:"command"`
+ Args []string `toml:"args" json:"args"`
+ Direct bool `toml:"direct" json:"direct"`
+}
+
+type Slice struct {
+ Paths []string `tom:"paths"`
+}
+
+type LaunchTOML struct {
+ Processes []Process `toml:"processes"`
+ Slices []Slice `toml:"slices"`
+}
+
+type BOMEntry struct {
+ Require
+ Buildpack Buildpack `toml:"buildpack" json:"buildpack"`
+}
+
+type buildpackPlan struct {
+ Entries []Require `toml:"entries"`
+}
+
+func (b *Builder) Build() (*BuildMetadata, error) {
+ platformDir, err := filepath.Abs(b.PlatformDir)
+ if err != nil {
+ return nil, err
+ }
+ layersDir, err := filepath.Abs(b.LayersDir)
+ if err != nil {
+ return nil, err
+ }
+ appDir, err := filepath.Abs(b.AppDir)
+ if err != nil {
+ return nil, err
+ }
+ planDir, err := ioutil.TempDir("", "plan.")
+ if err != nil {
+ return nil, err
+ }
+ defer os.RemoveAll(planDir)
+
+ procMap := processMap{}
+ plan := b.Plan
+ var bom []BOMEntry
+ var slices []Slice
+
+ for _, bp := range b.Group.Group {
+ bpInfo, err := bp.lookup(b.BuildpacksDir)
+ if err != nil {
+ return nil, err
+ }
+ bpDirName := bp.dir()
+ bpLayersDir := filepath.Join(layersDir, bpDirName)
+ bpPlanDir := filepath.Join(planDir, bpDirName)
+ if err := os.MkdirAll(bpLayersDir, 0777); err != nil {
+ return nil, err
+ }
+
+ if err := os.MkdirAll(bpPlanDir, 0777); err != nil {
+ return nil, err
+ }
+ bpPlanPath := filepath.Join(bpPlanDir, "plan.toml")
+ if err := WriteTOML(bpPlanPath, plan.find(bp)); err != nil {
+ return nil, err
+ }
+ cmd := exec.Command(filepath.Join(bpInfo.Path, "bin", "build"), bpLayersDir, platformDir, bpPlanPath)
+ cmd.Dir = appDir
+ cmd.Stdout = b.Out.Writer()
+ cmd.Stderr = b.Err.Writer()
+ if bpInfo.Buildpack.ClearEnv {
+ cmd.Env = b.Env.List()
+ } else {
+ cmd.Env, err = b.Env.WithPlatform(platformDir)
+ if err != nil {
+ return nil, err
+ }
+ }
+ if err := cmd.Run(); err != nil {
+ return nil, err
+ }
+ if err := setupEnv(b.Env, bpLayersDir); err != nil {
+ return nil, err
+ }
+ var bpPlanOut buildpackPlan
+ if _, err := toml.DecodeFile(bpPlanPath, &bpPlanOut); err != nil {
+ return nil, err
+ }
+ var bpBOM []BOMEntry
+ plan, bpBOM = plan.filter(bp, bpPlanOut)
+ bom = append(bom, bpBOM...)
+
+ var launch LaunchTOML
+ tomlPath := filepath.Join(bpLayersDir, "launch.toml")
+ if _, err := toml.DecodeFile(tomlPath, &launch); os.IsNotExist(err) {
+ continue
+ } else if err != nil {
+ return nil, err
+ }
+ procMap.add(launch.Processes)
+ slices = append(slices, launch.Slices...)
+ }
+
+ return &BuildMetadata{
+ Processes: procMap.list(),
+ Buildpacks: b.Group.Group,
+ BOM: bom,
+ Slices: slices,
+ }, nil
+}
+
+func (p BuildPlan) find(bp Buildpack) buildpackPlan {
+ var out []Require
+ for _, entry := range p.Entries {
+ for _, provider := range entry.Providers {
+ if provider == bp {
+ out = append(out, entry.Requires...)
+ break
+ }
+ }
+ }
+ return buildpackPlan{Entries: out}
+}
+
+// TODO: ensure at least one claimed entry of each name is provided by the BP
+func (p BuildPlan) filter(bp Buildpack, plan buildpackPlan) (BuildPlan, []BOMEntry) {
+ var out []BuildPlanEntry
+ for _, entry := range p.Entries {
+ if !plan.has(entry) {
+ out = append(out, entry)
+ }
+ }
+ var bom []BOMEntry
+ for _, entry := range plan.Entries {
+ bom = append(bom, BOMEntry{Require: entry, Buildpack: bp})
+ }
+ return BuildPlan{Entries: out}, bom
+}
+
+func (p buildpackPlan) has(entry BuildPlanEntry) bool {
+ for _, buildEntry := range p.Entries {
+ for _, req := range entry.Requires {
+ if req.Name == buildEntry.Name {
+ return true
+ }
+ }
+ }
+ return false
+}
+
+func setupEnv(env BuildEnv, layersDir string) error {
+ if err := eachDir(layersDir, func(path string) error {
+ if !isBuild(path + ".toml") {
+ return nil
+ }
+ return env.AddRootDir(path)
+ }); err != nil {
+ return err
+ }
+
+ return eachDir(layersDir, func(path string) error {
+ if !isBuild(path + ".toml") {
+ return nil
+ }
+ if err := env.AddEnvDir(filepath.Join(path, "env")); err != nil {
+ return err
+ }
+ return env.AddEnvDir(filepath.Join(path, "env.build"))
+ })
+}
+
+func isBuild(path string) bool {
+ var layerTOML struct {
+ Build bool `toml:"build"`
+ }
+ _, err := toml.DecodeFile(path, &layerTOML)
+ return err == nil && layerTOML.Build
+}
+
+type processMap map[string]Process
+
+func (m processMap) add(l []Process) {
+ for _, proc := range l {
+ m[proc.Type] = proc
+ }
+}
+
+func (m processMap) list() []Process {
+ var keys []string
+ for key := range m {
+ keys = append(keys, key)
+ }
+ sort.Strings(keys)
+ procs := []Process{}
+ for _, key := range keys {
+ procs = append(procs, m[key])
+ }
+ return procs
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/cmd/exit.go b/vendor/github.com/buildpacks/lifecycle/cmd/exit.go
new file mode 100644
index 00000000000..d2971f69b92
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/cmd/exit.go
@@ -0,0 +1,66 @@
+package cmd
+
+import (
+ "fmt"
+ "os"
+ "strings"
+)
+
+const (
+ CodeFailed = 1
+ // 2: reserved
+ CodeInvalidArgs = 3
+ // 4: CodeInvalidEnv
+ // 5: CodeNotFound
+ CodeFailedDetect = 6
+ CodeFailedBuild = 7
+ CodeFailedLaunch = 8
+ // 9: CodeFailedUpdate
+ CodeFailedSave = 10
+)
+
+type ErrorFail struct {
+ Err error
+ Code int
+ Action []string
+}
+
+func (e *ErrorFail) Error() string {
+ message := "failed to " + strings.Join(e.Action, " ")
+ if e.Err == nil {
+ return message
+ }
+ return fmt.Sprintf("%s: %s", message, e.Err)
+}
+
+func FailCode(code int, action ...string) *ErrorFail {
+ return FailErrCode(nil, code, action...)
+}
+
+func FailErr(err error, action ...string) *ErrorFail {
+ code := CodeFailed
+ if err, ok := err.(*ErrorFail); ok {
+ code = err.Code
+ }
+ return FailErrCode(err, code, action...)
+}
+
+func FailErrCode(err error, code int, action ...string) *ErrorFail {
+ return &ErrorFail{Err: err, Code: code, Action: action}
+}
+
+func Exit(err error) {
+ if err == nil {
+ os.Exit(0)
+ }
+ Logger.Errorf("%s\n", err)
+ if err, ok := err.(*ErrorFail); ok {
+ os.Exit(err.Code)
+ }
+ os.Exit(CodeFailed)
+}
+
+func ExitWithVersion() {
+ Logger.Infof(buildVersion())
+ os.Exit(0)
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/cmd/flags.go b/vendor/github.com/buildpacks/lifecycle/cmd/flags.go
new file mode 100644
index 00000000000..e1defe2b187
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/cmd/flags.go
@@ -0,0 +1,185 @@
+package cmd
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "strconv"
+
+ "github.com/docker/docker/client"
+ "github.com/pkg/errors"
+)
+
+const (
+ DefaultLayersDir = "/layers"
+ DefaultAppDir = "/workspace"
+ DefaultBuildpacksDir = "/cnb/buildpacks"
+ DefaultPlatformDir = "/platform"
+ DefaultOrderPath = "/cnb/order.toml"
+ DefaultGroupPath = "./group.toml"
+ DefaultStackPath = "/cnb/stack.toml"
+ DefaultAnalyzedPath = "./analyzed.toml"
+ DefaultPlanPath = "./plan.toml"
+ DefaultProcessType = "web"
+ DefaultLauncherPath = "/cnb/lifecycle/launcher"
+ DefaultLogLevel = "info"
+
+ EnvLayersDir = "CNB_LAYERS_DIR"
+ EnvAppDir = "CNB_APP_DIR"
+ EnvBuildpacksDir = "CNB_BUILDPACKS_DIR"
+ EnvPlatformDir = "CNB_PLATFORM_DIR"
+ EnvAnalyzedPath = "CNB_ANALYZED_PATH"
+ EnvOrderPath = "CNB_ORDER_PATH"
+ EnvGroupPath = "CNB_GROUP_PATH"
+ EnvStackPath = "CNB_STACK_PATH"
+ EnvPlanPath = "CNB_PLAN_PATH"
+ EnvUseDaemon = "CNB_USE_DAEMON" // defaults to false
+ EnvUseHelpers = "CNB_USE_CRED_HELPERS" // defaults to false
+ EnvRunImage = "CNB_RUN_IMAGE"
+ EnvCacheImage = "CNB_CACHE_IMAGE"
+ EnvCacheDir = "CNB_CACHE_DIR"
+ EnvLaunchCacheDir = "CNB_LAUNCH_CACHE_DIR"
+ EnvUID = "CNB_USER_ID"
+ EnvGID = "CNB_GROUP_ID"
+ EnvRegistryAuth = "CNB_REGISTRY_AUTH"
+ EnvSkipLayers = "CNB_ANALYZE_SKIP_LAYERS" // defaults to false
+ EnvProcessType = "CNB_PROCESS_TYPE"
+ EnvProcessTypeLegacy = "PACK_PROCESS_TYPE" // deprecated
+ EnvLogLevel = "CNB_LOG_LEVEL"
+)
+
+func FlagAnalyzedPath(dir *string) {
+ flag.StringVar(dir, "analyzed", envOrDefault(EnvAnalyzedPath, DefaultAnalyzedPath), "path to analyzed.toml")
+}
+
+func FlagAppDir(dir *string) {
+ flag.StringVar(dir, "app", envOrDefault(EnvAppDir, DefaultAppDir), "path to app directory")
+}
+
+func FlagBuildpacksDir(dir *string) {
+ flag.StringVar(dir, "buildpacks", envOrDefault(EnvBuildpacksDir, DefaultBuildpacksDir), "path to buildpacks directory")
+}
+
+func FlagCacheDir(dir *string) {
+ flag.StringVar(dir, "cache-dir", os.Getenv(EnvCacheDir), "path to cache directory")
+}
+
+func FlagCacheImage(image *string) {
+ flag.StringVar(image, "cache-image", os.Getenv(EnvCacheImage), "cache image tag name")
+}
+
+func FlagGID(gid *int) {
+ flag.IntVar(gid, "gid", intEnv(EnvGID), "GID of user's group in the stack's build and run images")
+}
+
+func FlagGroupPath(path *string) {
+ flag.StringVar(path, "group", envOrDefault(EnvGroupPath, DefaultGroupPath), "path to group.toml")
+}
+
+func FlagLaunchCacheDir(dir *string) {
+ flag.StringVar(dir, "launch-cache", os.Getenv(EnvLaunchCacheDir), "path to launch cache directory")
+}
+
+func FlagLauncherPath(path *string) {
+ flag.StringVar(path, "launcher", DefaultLauncherPath, "path to launcher binary")
+}
+
+func FlagLayersDir(dir *string) {
+ flag.StringVar(dir, "layers", envOrDefault(EnvLayersDir, DefaultLayersDir), "path to layers directory")
+}
+
+func FlagOrderPath(path *string) {
+ flag.StringVar(path, "order", envOrDefault(EnvOrderPath, DefaultOrderPath), "path to order.toml")
+}
+
+func FlagPlanPath(path *string) {
+ flag.StringVar(path, "plan", envOrDefault(EnvPlanPath, DefaultPlanPath), "path to plan.toml")
+}
+
+func FlagPlatformDir(dir *string) {
+ flag.StringVar(dir, "platform", envOrDefault(EnvPlatformDir, DefaultPlatformDir), "path to platform directory")
+}
+
+func FlagRunImage(image *string) {
+ flag.StringVar(image, "image", os.Getenv(EnvRunImage), "reference to run image")
+}
+
+func FlagStackPath(path *string) {
+ flag.StringVar(path, "stack", envOrDefault(EnvStackPath, DefaultStackPath), "path to stack.toml")
+}
+
+func FlagUID(uid *int) {
+ flag.IntVar(uid, "uid", intEnv(EnvUID), "UID of user in the stack's build and run images")
+}
+
+func FlagUseCredHelpers(use *bool) {
+ flag.BoolVar(use, "helpers", boolEnv(EnvUseHelpers), "use credential helpers")
+}
+
+func FlagUseDaemon(use *bool) {
+ flag.BoolVar(use, "daemon", boolEnv(EnvUseDaemon), "export to docker daemon")
+}
+
+func FlagSkipLayers(skip *bool) {
+ flag.BoolVar(skip, "skip-layers", boolEnv(EnvSkipLayers), "do not provide layer metadata to buildpacks")
+}
+
+func FlagVersion(version *bool) {
+ flag.BoolVar(version, "version", false, "show version")
+}
+
+func FlagLogLevel(level *string) {
+ flag.StringVar(level, "log-level", envOrDefault(EnvLogLevel, DefaultLogLevel), "logging level")
+}
+
+var (
+ // Version is the version of the lifecycle and all produced binaries. It is injected at compile time.
+ Version = "0.0.0"
+ // SCMCommit is the commit information provided by SCM. It is injected at compile time.
+ SCMCommit = ""
+ // SCMRepository is the source repository. It is injected at compile time.
+ SCMRepository = ""
+)
+
+// buildVersion is a display format of the version and build metadata in compliance with semver.
+func buildVersion() string {
+ // noinspection GoBoolExpressions
+ if SCMCommit == "" {
+ return Version
+ }
+
+ return fmt.Sprintf("%s+%s", Version, SCMCommit)
+}
+
+func intEnv(k string) int {
+ v := os.Getenv(k)
+ d, err := strconv.Atoi(v)
+ if err != nil {
+ return 0
+ }
+ return d
+}
+
+func boolEnv(k string) bool {
+ v := os.Getenv(k)
+ b, err := strconv.ParseBool(v)
+ if err != nil {
+ return false
+ }
+ return b
+}
+
+func envOrDefault(key string, defaultVal string) string {
+ if envVal := os.Getenv(key); envVal != "" {
+ return envVal
+ }
+ return defaultVal
+}
+
+func DockerClient() (*client.Client, error) {
+ docker, err := client.NewClientWithOpts(client.FromEnv, client.WithVersion("1.38"))
+ if err != nil {
+ return nil, errors.Wrap(err, "new docker client")
+ }
+ return docker, nil
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/cmd/logs.go b/vendor/github.com/buildpacks/lifecycle/cmd/logs.go
new file mode 100644
index 00000000000..e4b7ea0b65e
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/cmd/logs.go
@@ -0,0 +1,65 @@
+package cmd
+
+import (
+ "io"
+ "os"
+ "sync"
+
+ "github.com/apex/log"
+ "github.com/heroku/color"
+)
+
+const (
+ errorLevelText = "ERROR: "
+ warnLevelText = "Warning: "
+)
+
+// Default logger
+var (
+ Logger = &log.Logger{
+ Handler: &handler{
+ writer: os.Stdout,
+ },
+ }
+ warnStyle = color.New(color.FgYellow, color.Bold).SprintfFunc()
+ errorStyle = color.New(color.FgRed, color.Bold).SprintfFunc()
+)
+
+func SetLogLevel(level string) *ErrorFail {
+ var err error
+ Logger.Level, err = log.ParseLevel(level)
+ if err != nil {
+ return FailErrCode(err, CodeInvalidArgs, "parse log level")
+ }
+
+ return nil
+}
+
+type handler struct {
+ mu sync.Mutex
+ writer io.Writer
+}
+
+func (h *handler) HandleLog(entry *log.Entry) error {
+ h.mu.Lock()
+ defer h.mu.Unlock()
+
+ var err error
+ switch entry.Level {
+ case log.WarnLevel:
+ _, err = h.writer.Write([]byte(warnStyle(warnLevelText) + appendMissingLineFeed(entry.Message)))
+ case log.ErrorLevel:
+ _, err = h.writer.Write([]byte(errorStyle(errorLevelText) + appendMissingLineFeed(entry.Message)))
+ default:
+ _, err = h.writer.Write([]byte(appendMissingLineFeed(entry.Message)))
+ }
+ return err
+}
+
+func appendMissingLineFeed(msg string) string {
+ buff := []byte(msg)
+ if buff[len(buff)-1] != '\n' {
+ buff = append(buff, '\n')
+ }
+ return string(buff)
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/cred_helpers.go b/vendor/github.com/buildpacks/lifecycle/cred_helpers.go
new file mode 100644
index 00000000000..bf10ebc5fc6
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/cred_helpers.go
@@ -0,0 +1,80 @@
+package lifecycle
+
+import (
+ "encoding/json"
+ "errors"
+ "os"
+ "path/filepath"
+ "regexp"
+
+ "github.com/google/go-containerregistry/pkg/name"
+)
+
+func SetupCredHelpers(dockerPath string, refs ...string) error {
+ configPath := filepath.Join(dockerPath, "config.json")
+
+ config := map[string]interface{}{}
+ if f, err := os.Open(configPath); err == nil {
+ err := json.NewDecoder(f).Decode(&config)
+ if f.Close(); err != nil {
+ return err
+ }
+ } else if !os.IsNotExist(err) {
+ return err
+ }
+
+ if _, ok := config["credHelpers"]; !ok {
+ config["credHelpers"] = make(map[string]interface{})
+ }
+
+ credHelpers := make(map[string]string)
+ for _, refStr := range refs {
+ ref, err := name.ParseReference(refStr, name.WeakValidation)
+ if err != nil {
+ return err
+ }
+
+ registry := ref.Context().RegistryStr()
+ for _, ch := range []struct {
+ domain string
+ helper string
+ }{
+ {"([.]|^)gcr[.]io$", "gcr"},
+ {"[.]amazonaws[.]", "ecr-login"},
+ {"([.]|^)azurecr[.]io$", "acr"},
+ } {
+ match, err := regexp.MatchString("(?i)"+ch.domain, registry)
+ if err != nil || !match {
+ continue
+ }
+ credHelpers[registry] = ch.helper
+ }
+ }
+
+ if len(credHelpers) == 0 {
+ return nil
+ }
+
+ ch, ok := config["credHelpers"].(map[string]interface{})
+ if !ok {
+ return errors.New("failed to parse docker config 'credHelpers'")
+ }
+
+ for k, v := range credHelpers {
+ if _, ok := ch[k]; !ok {
+ ch[k] = v
+ }
+ }
+
+ if err := os.MkdirAll(dockerPath, 0777); err != nil {
+ return err
+ }
+
+ f, err := os.Create(configPath)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ return json.NewEncoder(f).Encode(config)
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/detector.go b/vendor/github.com/buildpacks/lifecycle/detector.go
new file mode 100644
index 00000000000..82964bade91
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/detector.go
@@ -0,0 +1,486 @@
+package lifecycle
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "sync"
+ "syscall"
+
+ "github.com/BurntSushi/toml"
+ "github.com/pkg/errors"
+)
+
+const (
+ CodeDetectPass = 0
+ CodeDetectFail = 100
+)
+
+var ErrFail = errors.New("no buildpacks participating")
+
+type Buildpack struct {
+ ID string `toml:"id" json:"id"`
+ Version string `toml:"version" json:"version"`
+ Optional bool `toml:"optional,omitempty" json:"optional,omitempty"`
+}
+
+func (bp Buildpack) dir() string {
+ return escapeID(bp.ID)
+}
+
+func (bp Buildpack) String() string {
+ return bp.ID + "@" + bp.Version
+}
+
+func (bp Buildpack) noOpt() Buildpack {
+ bp.Optional = false
+ return bp
+}
+
+type BuildPlan struct {
+ Entries []BuildPlanEntry `toml:"entries"`
+}
+
+type BuildPlanEntry struct {
+ Providers []Buildpack `toml:"providers"`
+ Requires []Require `toml:"requires"`
+}
+
+func (be BuildPlanEntry) noOpt() BuildPlanEntry {
+ var out []Buildpack
+ for _, p := range be.Providers {
+ out = append(out, p.noOpt())
+ }
+ be.Providers = out
+ return be
+}
+
+type Require struct {
+ Name string `toml:"name" json:"name"`
+ Version string `toml:"version" json:"version"`
+ Metadata map[string]interface{} `toml:"metadata" json:"metadata"`
+}
+
+type Provide struct {
+ Name string `toml:"name"`
+}
+
+type DetectConfig struct {
+ FullEnv []string
+ ClearEnv []string
+ AppDir string
+ PlatformDir string
+ BuildpacksDir string
+ Logger Logger
+ runs *sync.Map
+}
+
+func (bp Buildpack) lookup(buildpacksDir string) (*buildpackTOML, error) {
+ bpTOML := buildpackTOML{}
+ bpPath, err := filepath.Abs(filepath.Join(buildpacksDir, bp.dir(), bp.Version))
+ if err != nil {
+ return nil, err
+ }
+ tomlPath := filepath.Join(bpPath, "buildpack.toml")
+ if _, err := toml.DecodeFile(tomlPath, &bpTOML); err != nil {
+ return nil, err
+ }
+ bpTOML.Path = bpPath
+ return &bpTOML, nil
+}
+
+func (c *DetectConfig) process(done []Buildpack) ([]Buildpack, []BuildPlanEntry, error) {
+ var runs []detectRun
+ for _, bp := range done {
+ t, ok := c.runs.Load(bp.String())
+ if !ok {
+ return nil, nil, errors.Errorf("missing detection of '%s'", bp)
+ }
+ run := t.(detectRun)
+ if len(run.Output) > 0 {
+ c.Logger.Debugf("======== Output: %s ========", bp)
+ c.Logger.Debug(string(run.Output))
+ }
+ if run.Err != nil {
+ c.Logger.Debugf("======== Error: %s ========", bp)
+ c.Logger.Debug(run.Err.Error())
+ }
+ runs = append(runs, run)
+ }
+
+ c.Logger.Debugf("======== Results ========")
+
+ results := detectResults{}
+ detected := true
+ for i, bp := range done {
+ run := runs[i]
+ switch run.Code {
+ case CodeDetectPass:
+ c.Logger.Debugf("pass: %s", bp)
+ results = append(results, detectResult{bp, run})
+ case CodeDetectFail:
+ if bp.Optional {
+ c.Logger.Debugf("skip: %s", bp)
+ } else {
+ c.Logger.Debugf("fail: %s", bp)
+ }
+ detected = detected && bp.Optional
+ case -1:
+ c.Logger.Debugf("err: %s", bp)
+ detected = detected && bp.Optional
+ default:
+ c.Logger.Debugf("err: %s (%d)", bp, run.Code)
+ detected = detected && bp.Optional
+ }
+ }
+ if !detected {
+ return nil, nil, ErrFail
+ }
+
+ i := 0
+ deps, trial, err := results.runTrials(func(trial detectTrial) (depMap, detectTrial, error) {
+ i++
+ return c.runTrial(i, trial)
+ })
+ if err != nil {
+ return nil, nil, err
+ }
+
+ if len(done) != len(trial) {
+ c.Logger.Infof("%d of %d buildpacks participating", len(trial), len(done))
+ }
+
+ maxLength := 0
+ for _, t := range trial {
+ l := len(t.ID)
+ if l > maxLength {
+ maxLength = l
+ }
+ }
+
+ f := fmt.Sprintf("%%-%ds %%s", maxLength)
+
+ for _, t := range trial {
+ c.Logger.Infof(f, t.ID, t.Version)
+ }
+
+ var found []Buildpack
+ for _, r := range trial {
+ found = append(found, r.Buildpack.noOpt())
+ }
+ var plan []BuildPlanEntry
+ for _, dep := range deps {
+ plan = append(plan, dep.BuildPlanEntry.noOpt())
+ }
+ return found, plan, nil
+}
+
+func (c *DetectConfig) runTrial(i int, trial detectTrial) (depMap, detectTrial, error) {
+ c.Logger.Debugf("Resolving plan... (try #%d)", i)
+
+ var deps depMap
+ retry := true
+ for retry {
+ retry = false
+ deps = newDepMap(trial)
+
+ if err := deps.eachUnmetRequire(func(name string, bp Buildpack) error {
+ retry = true
+ if !bp.Optional {
+ c.Logger.Debugf("fail: %s requires %s", bp, name)
+ return ErrFail
+ }
+ c.Logger.Debugf("skip: %s requires %s", bp, name)
+ trial = trial.remove(bp)
+ return nil
+ }); err != nil {
+ return nil, nil, err
+ }
+
+ if err := deps.eachUnmetProvide(func(name string, bp Buildpack) error {
+ retry = true
+ if !bp.Optional {
+ c.Logger.Debugf("fail: %s provides unused %s", bp, name)
+ return ErrFail
+ }
+ c.Logger.Debugf("skip: %s provides unused %s", bp, name)
+ trial = trial.remove(bp)
+ return nil
+ }); err != nil {
+ return nil, nil, err
+ }
+ }
+
+ if len(trial) == 0 {
+ c.Logger.Debugf("fail: no viable buildpacks in group")
+ return nil, nil, ErrFail
+ }
+ return deps, trial, nil
+}
+
+func (bp *buildpackTOML) Detect(c *DetectConfig) detectRun {
+ appDir, err := filepath.Abs(c.AppDir)
+ if err != nil {
+ return detectRun{Code: -1, Err: err}
+ }
+ platformDir, err := filepath.Abs(c.PlatformDir)
+ if err != nil {
+ return detectRun{Code: -1, Err: err}
+ }
+ planDir, err := ioutil.TempDir("", "plan.")
+ if err != nil {
+ return detectRun{Code: -1, Err: err}
+ }
+ defer os.RemoveAll(planDir)
+ planPath := filepath.Join(planDir, "plan.toml")
+ if err := ioutil.WriteFile(planPath, nil, 0777); err != nil {
+ return detectRun{Code: -1, Err: err}
+ }
+ out := &bytes.Buffer{}
+ cmd := exec.Command(filepath.Join(bp.Path, "bin", "detect"), platformDir, planPath)
+ cmd.Dir = appDir
+ cmd.Stdout = out
+ cmd.Stderr = out
+ cmd.Env = c.FullEnv
+ if bp.Buildpack.ClearEnv {
+ cmd.Env = c.ClearEnv
+ }
+
+ if err := cmd.Run(); err != nil {
+ if err, ok := err.(*exec.ExitError); ok {
+ if status, ok := err.Sys().(syscall.WaitStatus); ok {
+ return detectRun{Code: status.ExitStatus(), Output: out.Bytes()}
+ }
+ }
+ return detectRun{Code: -1, Err: err, Output: out.Bytes()}
+ }
+ var t detectRun
+ if _, err := toml.DecodeFile(planPath, &t); err != nil {
+ return detectRun{Code: -1, Err: err}
+ }
+ t.Output = out.Bytes()
+ return t
+}
+
+type BuildpackGroup struct {
+ Group []Buildpack `toml:"group"`
+}
+
+func (bg BuildpackGroup) Detect(c *DetectConfig) (BuildpackGroup, BuildPlan, error) {
+ if c.runs == nil {
+ c.runs = &sync.Map{}
+ }
+ bps, entries, err := bg.detect(nil, &sync.WaitGroup{}, c)
+ return BuildpackGroup{Group: bps}, BuildPlan{Entries: entries}, err
+}
+
+func (bg BuildpackGroup) detect(done []Buildpack, wg *sync.WaitGroup, c *DetectConfig) ([]Buildpack, []BuildPlanEntry, error) {
+ for i, bp := range bg.Group {
+ key := bp.String()
+ if hasID(done, bp.ID) {
+ continue
+ }
+ info, err := bp.lookup(c.BuildpacksDir)
+ if err != nil {
+ return nil, nil, err
+ }
+ if info.Order != nil {
+ // TODO: double-check slice safety here
+ // FIXME: cyclical references lead to infinite recursion
+ return info.Order.detect(done, bg.Group[i+1:], bp.Optional, wg, c)
+ }
+ done = append(done, bp)
+ wg.Add(1)
+ go func() {
+ if _, ok := c.runs.Load(key); !ok {
+ c.runs.Store(key, info.Detect(c))
+ }
+ wg.Done()
+ }()
+ }
+
+ wg.Wait()
+
+ return c.process(done)
+}
+
+func (bg BuildpackGroup) append(group ...BuildpackGroup) BuildpackGroup {
+ for _, g := range group {
+ bg.Group = append(bg.Group, g.Group...)
+ }
+ return bg
+}
+
+type BuildpackOrder []BuildpackGroup
+
+func (bo BuildpackOrder) Detect(c *DetectConfig) (BuildpackGroup, BuildPlan, error) {
+ if c.runs == nil {
+ c.runs = &sync.Map{}
+ }
+ bps, entries, err := bo.detect(nil, nil, false, &sync.WaitGroup{}, c)
+ return BuildpackGroup{Group: bps}, BuildPlan{Entries: entries}, err
+}
+
+func (bo BuildpackOrder) detect(done, next []Buildpack, optional bool, wg *sync.WaitGroup, c *DetectConfig) ([]Buildpack, []BuildPlanEntry, error) {
+ ngroup := BuildpackGroup{Group: next}
+ for _, group := range bo {
+ // FIXME: double-check slice safety here
+ found, plan, err := group.append(ngroup).detect(done, wg, c)
+ if err == ErrFail {
+ wg = &sync.WaitGroup{}
+ continue
+ }
+ return found, plan, err
+ }
+ if optional {
+ return ngroup.detect(done, wg, c)
+ }
+ return nil, nil, ErrFail
+}
+
+func hasID(bps []Buildpack, id string) bool {
+ for _, bp := range bps {
+ if bp.ID == id {
+ return true
+ }
+ }
+ return false
+}
+
+type detectRun struct {
+ planSections
+ Or []planSections `toml:"or"`
+ Output []byte `toml:"-"`
+ Code int `toml:"-"`
+ Err error `toml:"-"`
+}
+
+type planSections struct {
+ Requires []Require `toml:"requires"`
+ Provides []Provide `toml:"provides"`
+}
+
+type detectResult struct {
+ Buildpack
+ detectRun
+}
+
+func (r *detectResult) options() []detectOption {
+ var out []detectOption
+ for i, sections := range append([]planSections{r.planSections}, r.Or...) {
+ bp := r.Buildpack
+ bp.Optional = bp.Optional && i == len(r.Or)
+ out = append(out, detectOption{bp, sections})
+ }
+ return out
+}
+
+type detectResults []detectResult
+type trialFunc func(detectTrial) (depMap, detectTrial, error)
+
+func (rs detectResults) runTrials(f trialFunc) (depMap, detectTrial, error) {
+ return rs.runTrialsFrom(nil, f)
+}
+
+func (rs detectResults) runTrialsFrom(prefix detectTrial, f trialFunc) (depMap, detectTrial, error) {
+ if len(rs) == 0 {
+ deps, trial, err := f(prefix)
+ return deps, trial, err
+ }
+
+ var lastErr error
+ for _, option := range rs[0].options() {
+ deps, trial, err := rs[1:].runTrialsFrom(append(prefix, option), f)
+ if err == nil {
+ return deps, trial, nil
+ }
+ lastErr = err
+ }
+ return nil, nil, lastErr
+}
+
+type detectOption struct {
+ Buildpack
+ planSections
+}
+
+type detectTrial []detectOption
+
+func (ts detectTrial) remove(bp Buildpack) detectTrial {
+ var out detectTrial
+ for _, t := range ts {
+ if t.Buildpack != bp {
+ out = append(out, t)
+ }
+ }
+ return out
+}
+
+type depEntry struct {
+ BuildPlanEntry
+ earlyRequires []Buildpack
+ extraProvides []Buildpack
+}
+
+type depMap map[string]depEntry
+
+func newDepMap(trial detectTrial) depMap {
+ m := depMap{}
+ for _, option := range trial {
+ for _, p := range option.Provides {
+ m.provide(option.Buildpack, p)
+ }
+ for _, r := range option.Requires {
+ m.require(option.Buildpack, r)
+ }
+ }
+ return m
+}
+
+func (m depMap) provide(bp Buildpack, provide Provide) {
+ entry := m[provide.Name]
+ entry.extraProvides = append(entry.extraProvides, bp)
+ m[provide.Name] = entry
+}
+
+func (m depMap) require(bp Buildpack, require Require) {
+ entry := m[require.Name]
+ entry.Providers = append(entry.Providers, entry.extraProvides...)
+ entry.extraProvides = nil
+
+ if len(entry.Providers) == 0 {
+ entry.earlyRequires = append(entry.earlyRequires, bp)
+ } else {
+ entry.Requires = append(entry.Requires, require)
+ }
+ m[require.Name] = entry
+}
+
+func (m depMap) eachUnmetProvide(f func(name string, bp Buildpack) error) error {
+ for name, entry := range m {
+ if len(entry.extraProvides) != 0 {
+ for _, bp := range entry.extraProvides {
+ if err := f(name, bp); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
+
+func (m depMap) eachUnmetRequire(f func(name string, bp Buildpack) error) error {
+ for name, entry := range m {
+ if len(entry.earlyRequires) != 0 {
+ for _, bp := range entry.earlyRequires {
+ if err := f(name, bp); err != nil {
+ return err
+ }
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/env.go b/vendor/github.com/buildpacks/lifecycle/env.go
new file mode 100644
index 00000000000..6ca4d11ca22
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/env.go
@@ -0,0 +1,156 @@
+package lifecycle
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+type Env struct {
+ LookupEnv func(key string) (string, bool)
+ Getenv func(key string) string
+ Setenv func(key, value string) error
+ Unsetenv func(key string) error
+ Environ func() []string
+ Map map[string][]string
+}
+
+func (p *Env) AddRootDir(baseDir string) error {
+ absBaseDir, err := filepath.Abs(baseDir)
+ if err != nil {
+ return err
+ }
+ for dir, vars := range p.Map {
+ newDir := filepath.Join(absBaseDir, dir)
+ if _, err := os.Stat(newDir); os.IsNotExist(err) {
+ continue
+ } else if err != nil {
+ return err
+ }
+ for _, key := range vars {
+ value := newDir + prefix(p.Getenv(key), os.PathListSeparator)
+ if err := p.Setenv(key, value); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (p *Env) AddEnvDir(envDir string) error {
+ return eachEnvFile(envDir, func(k, v string) error {
+ parts := strings.SplitN(k, ".", 2)
+ name := parts[0]
+ var action string
+ if len(parts) > 1 {
+ action = parts[1]
+ }
+ switch action {
+ case "prepend":
+ return p.Setenv(name, v+prefix(p.Getenv(name), delim(envDir, name)...))
+ case "append":
+ return p.Setenv(name, suffix(p.Getenv(name), delim(envDir, name)...)+v)
+ case "override":
+ return p.Setenv(name, v)
+ case "default":
+ if p.Getenv(name) != "" {
+ return nil
+ }
+ return p.Setenv(name, v)
+ case "":
+ return p.Setenv(name, v+prefix(p.Getenv(name), delim(envDir, name, os.PathListSeparator)...))
+ default:
+ return nil
+ }
+ })
+}
+
+func (p *Env) WithPlatform(platformDir string) (out []string, err error) {
+ restore := map[string]*string{}
+ defer func() {
+ for k, v := range restore {
+ var rErr error
+ if v == nil {
+ rErr = p.Unsetenv(k)
+ } else {
+ rErr = p.Setenv(k, *v)
+ }
+ if err == nil {
+ err = rErr
+ }
+ }
+ }()
+ if err := eachEnvFile(filepath.Join(platformDir, "env"), func(k, v string) error {
+ restore[k] = nil
+ if old, ok := p.LookupEnv(k); ok {
+ restore[k] = &old
+ }
+ if p.isRootEnv(k) {
+ return p.Setenv(k, v+prefix(p.Getenv(k), os.PathListSeparator))
+ }
+ return p.Setenv(k, v)
+ }); err != nil {
+ return nil, err
+ }
+ return p.List(), nil
+}
+
+func (p *Env) List() []string {
+ return p.Environ()
+}
+
+func prefix(s string, prefix ...byte) string {
+ if s == "" {
+ return ""
+ }
+ return string(prefix) + s
+}
+
+func suffix(s string, suffix ...byte) string {
+ if s == "" {
+ return ""
+ }
+ return s + string(suffix)
+}
+
+func delim(dir, name string, def ...byte) []byte {
+ value, err := ioutil.ReadFile(filepath.Join(dir, name+".delim"))
+ if err != nil {
+ return def
+ }
+ return value
+}
+
+func eachEnvFile(dir string, fn func(k, v string) error) error {
+ files, err := ioutil.ReadDir(dir)
+ if os.IsNotExist(err) {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ for _, f := range files {
+ if f.IsDir() {
+ continue
+ }
+ value, err := ioutil.ReadFile(filepath.Join(dir, f.Name()))
+ if err != nil {
+ return err
+ }
+ if err := fn(f.Name(), string(value)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (p *Env) isRootEnv(name string) bool {
+ for _, m := range p.Map {
+ for _, k := range m {
+ if k == name {
+ return true
+ }
+ }
+ }
+ return false
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/exporter.go b/vendor/github.com/buildpacks/lifecycle/exporter.go
new file mode 100644
index 00000000000..ba140ccc3fa
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/exporter.go
@@ -0,0 +1,425 @@
+package lifecycle
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "github.com/BurntSushi/toml"
+ "github.com/buildpacks/imgutil"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/lifecycle/archive"
+ "github.com/buildpacks/lifecycle/cmd"
+)
+
+//go:generate mockgen -package testmock -destination testmock/cache.go github.com/buildpacks/lifecycle Cache
+type Cache interface {
+ Name() string
+ SetMetadata(metadata CacheMetadata) error
+ RetrieveMetadata() (CacheMetadata, error)
+ AddLayerFile(sha string, tarPath string) error
+ ReuseLayer(sha string) error
+ RetrieveLayer(sha string) (io.ReadCloser, error)
+ Commit() error
+}
+
+type Exporter struct {
+ Buildpacks []Buildpack
+ ArtifactsDir string
+ Logger Logger
+ UID, GID int
+ tarHashes map[string]string // Stores hashes of layer tarballs for reuse between the export and cache steps.
+}
+
+type LauncherConfig struct {
+ Path string
+ Metadata LauncherMetadata
+}
+
+type SliceLayer struct {
+ ID string
+ TarPath string
+ SHA string
+}
+
+func (e *Exporter) Export(
+ layersDir,
+ appDir string,
+ workingImage imgutil.Image,
+ runImageRef string,
+ origMetadata LayersMetadata,
+ additionalNames []string,
+ launcherConfig LauncherConfig,
+ stack StackMetadata,
+) error {
+ var err error
+
+ meta := LayersMetadata{}
+ meta.RunImage.TopLayer, err = workingImage.TopLayer()
+ if err != nil {
+ return errors.Wrap(err, "get run image top layer SHA")
+ }
+
+ meta.RunImage.Reference = runImageRef
+ meta.Stack = stack
+
+ buildMD := &BuildMetadata{}
+ if _, err := toml.DecodeFile(MetadataFilePath(layersDir), buildMD); err != nil {
+ return errors.Wrap(err, "read build metadata")
+ }
+
+ // creating app layers (slices + app dir)
+ appSlices, err := e.createAppSliceLayers(workingImage, &layer{path: appDir, identifier: "app"}, buildMD.Slices)
+ if err != nil {
+ return errors.Wrap(err, "creating app layers")
+ }
+
+ // launcher
+ meta.Launcher.SHA, err = e.addOrReuseLayer(workingImage, &layer{path: launcherConfig.Path, identifier: "launcher"}, origMetadata.Launcher.SHA)
+ if err != nil {
+ return errors.Wrap(err, "exporting launcher layer")
+ }
+
+ // layers
+ for _, bp := range e.Buildpacks {
+ bpDir, err := readBuildpackLayersDir(layersDir, bp)
+ if err != nil {
+ return errors.Wrapf(err, "reading layers for buildpack '%s'", bp.ID)
+ }
+ bpMD := BuildpackLayersMetadata{
+ ID: bp.ID,
+ Version: bp.Version,
+ Layers: map[string]BuildpackLayerMetadata{},
+ }
+ for _, layer := range bpDir.findLayers(launch) {
+ layer := layer
+ lmd, err := layer.read()
+ if err != nil {
+ return errors.Wrapf(err, "reading '%s' metadata", layer.Identifier())
+ }
+
+ if layer.hasLocalContents() {
+ origLayerMetadata := origMetadata.MetadataForBuildpack(bp.ID).Layers[layer.name()]
+ lmd.SHA, err = e.addOrReuseLayer(workingImage, &layer, origLayerMetadata.SHA)
+ if err != nil {
+ return err
+ }
+ } else {
+ if lmd.Cache {
+ return fmt.Errorf("layer '%s' is cache=true but has no contents", layer.Identifier())
+ }
+ origLayerMetadata, ok := origMetadata.MetadataForBuildpack(bp.ID).Layers[layer.name()]
+ if !ok {
+ return fmt.Errorf("cannot reuse '%s', previous image has no metadata for layer '%s'", layer.Identifier(), layer.Identifier())
+ }
+
+ e.Logger.Infof("Reusing layer '%s'\n", layer.Identifier())
+ e.Logger.Debugf("Layer '%s' SHA: %s\n", layer.Identifier(), origLayerMetadata.SHA)
+ if err := workingImage.ReuseLayer(origLayerMetadata.SHA); err != nil {
+ return errors.Wrapf(err, "reusing layer: '%s'", layer.Identifier())
+ }
+ lmd.SHA = origLayerMetadata.SHA
+ }
+ bpMD.Layers[layer.name()] = lmd
+ }
+ meta.Buildpacks = append(meta.Buildpacks, bpMD)
+
+ if malformedLayers := bpDir.findLayers(malformed); len(malformedLayers) > 0 {
+ ids := make([]string, 0, len(malformedLayers))
+ for _, ml := range malformedLayers {
+ ids = append(ids, ml.Identifier())
+ }
+ return fmt.Errorf("failed to parse metadata for layers '%s'", ids)
+ }
+ }
+
+ // app
+ meta.App, err = e.addSliceLayers(workingImage, appSlices, origMetadata.App)
+ if err != nil {
+ return errors.Wrap(err, "exporting slice layers")
+ }
+
+ // config
+ meta.Config.SHA, err = e.addOrReuseLayer(workingImage, &layer{path: filepath.Join(layersDir, "config"), identifier: "config"}, origMetadata.Config.SHA)
+ if err != nil {
+ return errors.Wrap(err, "exporting config layer")
+ }
+
+ data, err := json.Marshal(meta)
+ if err != nil {
+ return errors.Wrap(err, "marshall metadata")
+ }
+
+ if err = workingImage.SetLabel(LayerMetadataLabel, string(data)); err != nil {
+ return errors.Wrap(err, "set app image metadata label")
+ }
+
+ buildMD.Launcher = launcherConfig.Metadata
+ buildJSON, err := json.Marshal(buildMD)
+ if err != nil {
+ return errors.Wrap(err, "parse build metadata")
+ }
+ if err := workingImage.SetLabel(BuildMetadataLabel, string(buildJSON)); err != nil {
+ return errors.Wrap(err, "set build image metadata label")
+ }
+
+ if err = workingImage.SetEnv(cmd.EnvLayersDir, layersDir); err != nil {
+ return errors.Wrapf(err, "set app image env %s", cmd.EnvLayersDir)
+ }
+
+ if err = workingImage.SetEnv(cmd.EnvAppDir, appDir); err != nil {
+ return errors.Wrapf(err, "set app image env %s", cmd.EnvAppDir)
+ }
+
+ if err = workingImage.SetEntrypoint(launcherConfig.Path); err != nil {
+ return errors.Wrap(err, "setting entrypoint")
+ }
+
+ if err = workingImage.SetCmd(); err != nil { // Note: Command intentionally empty
+ return errors.Wrap(err, "setting cmd")
+ }
+
+ return saveImage(workingImage, additionalNames, e.Logger)
+}
+
+func (e *Exporter) Cache(layersDir string, cacheStore Cache) error {
+ var err error
+ origMeta, err := cacheStore.RetrieveMetadata()
+ if err != nil {
+ return errors.Wrap(err, "metadata for previous cache")
+ }
+ meta := CacheMetadata{}
+
+ for _, bp := range e.Buildpacks {
+ bpDir, err := readBuildpackLayersDir(layersDir, bp)
+ if err != nil {
+ return errors.Wrapf(err, "reading layers for buildpack '%s'", bp.ID)
+ }
+
+ bpMD := BuildpackLayersMetadata{
+ ID: bp.ID,
+ Version: bp.Version,
+ Layers: map[string]BuildpackLayerMetadata{},
+ }
+ for _, layer := range bpDir.findLayers(cached) {
+ layer := layer
+ if !layer.hasLocalContents() {
+ return fmt.Errorf("failed to cache layer '%s' because it has no contents", layer.Identifier())
+ }
+ lmd, err := layer.read()
+ if err != nil {
+ return errors.Wrapf(err, "reading %q metadata", layer.Identifier())
+ }
+ origLayerMetadata := origMeta.MetadataForBuildpack(bp.ID).Layers[layer.name()]
+ if lmd.SHA, err = e.addOrReuseCacheLayer(cacheStore, &layer, origLayerMetadata.SHA); err != nil {
+ return err
+ }
+ bpMD.Layers[layer.name()] = lmd
+ }
+ meta.Buildpacks = append(meta.Buildpacks, bpMD)
+ }
+
+ if err := cacheStore.SetMetadata(meta); err != nil {
+ return errors.Wrap(err, "setting cache metadata")
+ }
+ if err := cacheStore.Commit(); err != nil {
+ return errors.Wrap(err, "committing cache")
+ }
+
+ return nil
+}
+
+func (e *Exporter) tarLayer(layer identifiableLayer) (string, string, error) {
+ tarPath := filepath.Join(e.ArtifactsDir, escapeID(layer.Identifier())+".tar")
+ if e.tarHashes == nil {
+ e.tarHashes = make(map[string]string)
+ }
+ if sha, ok := e.tarHashes[tarPath]; ok {
+ e.Logger.Debugf("Reusing tarball for layer %q with SHA: %s\n", layer.Identifier(), sha)
+ return tarPath, sha, nil
+ }
+ e.Logger.Debugf("Writing tarball for layer %q\n", layer.Identifier())
+ sha, err := archive.WriteTarFile(layer.Path(), tarPath, e.UID, e.GID)
+ if err != nil {
+ return "", "", err
+ }
+ e.tarHashes[tarPath] = sha
+ return tarPath, sha, nil
+}
+
+func (e *Exporter) addOrReuseLayer(image imgutil.Image, layer identifiableLayer, previousSHA string) (string, error) {
+ tarPath, sha, err := e.tarLayer(layer)
+ if err != nil {
+ return "", errors.Wrapf(err, "tarring layer '%s'", layer.Identifier())
+ }
+ if sha == previousSHA {
+ e.Logger.Infof("Reusing layer '%s'\n", layer.Identifier())
+ e.Logger.Debugf("Layer '%s' SHA: %s\n", layer.Identifier(), sha)
+ return sha, image.ReuseLayer(previousSHA)
+ }
+ e.Logger.Infof("Adding layer '%s'\n", layer.Identifier())
+ e.Logger.Debugf("Layer '%s' SHA: %s\n", layer.Identifier(), sha)
+ return sha, image.AddLayer(tarPath)
+}
+
+func (e *Exporter) addOrReuseCacheLayer(cache Cache, layer identifiableLayer, previousSHA string) (string, error) {
+ tarPath, sha, err := e.tarLayer(layer)
+ if err != nil {
+ return "", errors.Wrapf(err, "tarring layer %q", layer.Identifier())
+ }
+ if sha == previousSHA {
+ e.Logger.Infof("Reusing cache layer '%s'\n", layer.Identifier())
+ e.Logger.Debugf("Layer '%s' SHA: %s\n", layer.Identifier(), sha)
+ return sha, cache.ReuseLayer(previousSHA)
+ }
+ e.Logger.Infof("Adding cache layer '%s'\n", layer.Identifier())
+ e.Logger.Debugf("Layer '%s' SHA: %s\n", layer.Identifier(), sha)
+ return sha, cache.AddLayerFile(sha, tarPath)
+}
+
+func (e *Exporter) createAppSliceLayers(image imgutil.Image, appLayer identifiableLayer, slices []Slice) ([]SliceLayer, error) {
+ var appSlices []SliceLayer
+
+ for index, slice := range slices {
+ var allGlobMatches []string
+ for _, path := range slice.Paths {
+ globMatches, err := filepath.Glob(e.toAbs(appLayer.Path(), path))
+ if err != nil {
+ return nil, errors.Wrap(err, "bad pattern for glob path")
+ }
+ allGlobMatches = append(allGlobMatches, globMatches...)
+ }
+ sliceLayerID := fmt.Sprintf("slice-%d", index+1)
+ sliceLayer, err := e.createSliceLayer(image, sliceLayerID, allGlobMatches)
+ if err != nil {
+ return nil, errors.Wrap(err, "creating slice layer")
+ }
+ appSlices = append(appSlices, sliceLayer)
+ }
+
+ // finish-up by creating the actual app dir layer and place it at the end of the app slices
+ // -------------
+ // | slice 1 |
+ // -------------
+ // | slice 2 |
+ // -------------
+ // | slice N |
+ // -------------
+ // | app dir |
+ // -------------
+ tarPath := filepath.Join(e.ArtifactsDir, escapeID(appLayer.Identifier())+".tar")
+ sha, err := archive.WriteTarFile(appLayer.Path(), tarPath, e.UID, e.GID)
+ if err != nil {
+ return nil, errors.Wrapf(err, "exporting layer '%s'", appLayer.Identifier())
+ }
+
+ return append(appSlices, SliceLayer{
+ ID: appLayer.Identifier(),
+ SHA: sha,
+ TarPath: tarPath,
+ }), nil
+}
+
+func (e *Exporter) createSliceLayer(image imgutil.Image, layerID string, files []string) (SliceLayer, error) {
+ tarPath := filepath.Join(e.ArtifactsDir, escapeID(layerID)+".tar")
+ sha, fileSet, err := archive.WriteFilesToTar(tarPath, e.UID, e.GID, files...)
+ if err != nil {
+ return SliceLayer{}, errors.Wrapf(err, "exporting slice layer '%s'", layerID)
+ }
+
+ // for this first iteration, just delete the actual files then revisit
+ // the directories and delete if empty as a result of previous removal
+ var dirs []string
+ for file := range fileSet {
+ stat, _ := os.Stat(file)
+ if !stat.IsDir() {
+ err = os.Remove(file)
+ if err != nil {
+ e.Logger.Errorf("failed to delete file %v", err)
+ }
+ } else {
+ dirs = append(dirs, file)
+ }
+ }
+ // sort the dirs by their path depth (deepest -> most shallow) to avoid NOT being able to delete a high level dir
+ // that nested empty dirs.
+ sort.SliceStable(dirs, func(i, j int) bool {
+ return len(strings.Split(dirs[i], string(os.PathSeparator))) > len(strings.Split(dirs[j], string(os.PathSeparator)))
+ })
+ for _, dir := range dirs {
+ if ok, err := isEmptyDir(dir); ok {
+ if err != nil {
+ e.Logger.Errorf("failed to check if directory is empty %v", err)
+ }
+ err = os.Remove(dir)
+ if err != nil {
+ e.Logger.Errorf("failed to delete directory %v", err)
+ }
+ }
+ }
+
+ return SliceLayer{
+ ID: layerID,
+ SHA: sha,
+ TarPath: tarPath,
+ }, nil
+}
+
+func (e *Exporter) addSliceLayers(image imgutil.Image, sliceLayers []SliceLayer, previousAppMD []LayerMetadata) ([]LayerMetadata, error) {
+ var numberOfReusedLayers int
+ var appMD []LayerMetadata
+
+ for _, slice := range sliceLayers {
+ var err error
+
+ found := false
+ for _, previous := range previousAppMD {
+ if slice.SHA == previous.SHA {
+ found = true
+ break
+ }
+ }
+ if found {
+ err = image.ReuseLayer(slice.SHA)
+ numberOfReusedLayers++
+ } else {
+ err = image.AddLayer(slice.TarPath)
+ }
+ if err != nil {
+ return nil, err
+ }
+ e.Logger.Debugf("Layer '%s' SHA: %s\n", slice.ID, slice.SHA)
+ appMD = append(appMD, LayerMetadata{SHA: slice.SHA})
+ }
+
+ delta := len(sliceLayers) - numberOfReusedLayers
+ if numberOfReusedLayers > 0 {
+ e.Logger.Infof("Reusing %d/%d app layer(s)\n", numberOfReusedLayers, len(sliceLayers))
+ }
+ if delta != 0 {
+ e.Logger.Infof("Adding %d/%d app layer(s)\n", delta, len(sliceLayers))
+ }
+
+ return appMD, nil
+}
+
+func (e *Exporter) toAbs(baseDir, path string) string {
+ path = filepath.Clean(path)
+
+ // force relative path to be absolute from the base dir
+ if !filepath.IsAbs(path) {
+ path = filepath.Join(baseDir, path)
+ }
+ // force an absolute path to be absolute from base dir
+ if len(path) > len(baseDir) && path[:len(baseDir)] != baseDir {
+ path = filepath.Join(baseDir, path)
+ e.Logger.Warnf("found absolute path %s outside of %s", path, baseDir)
+ }
+
+ return path
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/go.mod b/vendor/github.com/buildpacks/lifecycle/go.mod
new file mode 100644
index 00000000000..74555205c53
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/go.mod
@@ -0,0 +1,22 @@
+module github.com/buildpacks/lifecycle
+
+require (
+ github.com/BurntSushi/toml v0.3.1
+ github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012
+ github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b
+ github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7
+ github.com/docker/go-connections v0.4.0
+ github.com/golang/mock v1.3.1
+ github.com/google/go-cmp v0.3.0
+ github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af
+ github.com/heroku/color v0.0.6
+ github.com/mattn/go-colorable v0.1.4 // indirect
+ github.com/mattn/go-isatty v0.0.10 // indirect
+ github.com/pkg/errors v0.8.1
+ github.com/sclevine/spec v1.4.0
+ golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 // indirect
+ golang.org/x/sync v0.0.0-20190423024810-112230192c58
+ google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8 // indirect
+)
+
+go 1.13
diff --git a/vendor/github.com/buildpacks/lifecycle/go.sum b/vendor/github.com/buildpacks/lifecycle/go.sum
new file mode 100644
index 00000000000..eec52a8a26f
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/go.sum
@@ -0,0 +1,250 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/Azure/azure-sdk-for-go v19.1.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-autorest v10.15.5+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012 h1:r9k3B0K539tmbDOdyCIuz/6qtn8q+lp+qvEStcFUIdM=
+github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012/go.mod h1:Ls949n1HFtXfbDcjiTTFQqkVUrte0puoIBfO3SVgwOA=
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a h1:2KLQMJ8msqoPHIPDufkxVcoTtcmE5+1sL9950m4R9Pk=
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
+github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/aws/aws-sdk-go v1.15.90/go.mod h1:es1KtYUFs7le0xQ3rOihkuoVD90z7D0fR2Qm4S00/gU=
+github.com/aws/aws-sdk-go v1.20.6 h1:kmy4Gvdlyez1fV4kw5RYxZzWKVyuHZHgPWeU/YvRsV4=
+github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59 h1:WWB576BN5zNSZc/M9d/10pqEx5VHNhaQ/yOVAkmj5Yo=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
+github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b h1:SDsB0hJtURA+5i5vIjLntzRNPEqdoz6q+0MShCWdctw=
+github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b/go.mod h1:E3lXJcNXcRefJQAHW5rqboonet+jtOml4qImbJhYGAo=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 h1:Cvj7S8I4Xpx78KAl6TwTmMHuHlZ/0SM60NUneGJQ7IE=
+github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
+github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
+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/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-logfmt/logfmt v0.4.0 h1:MP4Eh7ZCb31lleYCFuwm0oe4/YGak+5l1vA2NOE80nA=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af h1:gCcst+zXdvatJYFDtPd3C3VNEGcoFOOMwFydnFIfnF0=
+github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af/go.mod h1:9kIomAeXUmwhqeYS2zoEuQ0sc2GOVmNW7t3y9aNQL1o=
+github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0=
+github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi1wLU=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7 h1:K//n/AqR5HjG3qxbrBCL4vJPW0MVFSs9CPK1OOJdRME=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
+github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515 h1:T+h1c/A9Gawja4Y9mFVWj2vyii2bbUNDw3kt9VxK2EY=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-isatty v0.0.5/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 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/fastuuid v1.1.0 h1:INyGLmTCMGFr6OVIb977ghJvABML2CMVjPoRfNDdYDo=
+github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/sclevine/spec v1.0.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
+github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
+github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/sirupsen/logrus v1.4.1 h1:GL2rEmy6nsikmW0r8opw9JIRScdMF5hA8cOYLH7In1k=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2 h1:eGaGNxrtoZf/mBURsnNQKDR7u50Klgcf2eFDQEnc8Bc=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b h1:m74UWYy+HBs+jMFR9mdZU6shPewugMyH5+GV6LNgW8w=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
+github.com/tj/go-spin v1.1.0 h1:lhdWZsvImxvZ3q1C5OIB7d72DuOwP4O2NdBg9PyzNds=
+github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+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=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/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 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191017205301-920acffc3e65/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8 h1:x913Lq/RebkvUmRSdQ8MNb0GZKn+SR1ESfoetcQSeak=
+google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
+k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
+k8s.io/client-go v0.0.0-20180910083459-2cefa64ff137/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
+k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
+k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
diff --git a/vendor/github.com/buildpacks/lifecycle/golangci.yaml b/vendor/github.com/buildpacks/lifecycle/golangci.yaml
new file mode 100644
index 00000000000..93a050c6c62
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/golangci.yaml
@@ -0,0 +1,33 @@
+run:
+ timeout: 6m
+ modules-download-mode: vendor
+
+linters:
+ disable-all: true
+ enable:
+ - bodyclose
+ - deadcode
+ - dogsled
+ - gocritic
+ - goimports
+ - golint
+ - gosimple
+ - govet
+ - ineffassign
+ - maligned
+ - misspell
+ - nakedret
+ - scopelint
+ - staticcheck
+ - structcheck
+ - stylecheck
+ - typecheck
+ - unconvert
+ - unused
+ - varcheck
+ - whitespace
+
+
+linters-settings:
+ goimports:
+ local-prefixes: github.com/buildpacks/lifecycle
diff --git a/vendor/github.com/buildpacks/lifecycle/launcher.go b/vendor/github.com/buildpacks/lifecycle/launcher.go
new file mode 100644
index 00000000000..9964154ff20
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/launcher.go
@@ -0,0 +1,192 @@
+package lifecycle
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+
+ "github.com/pkg/errors"
+)
+
+type Launcher struct {
+ DefaultProcessType string
+ LayersDir string
+ AppDir string
+ Processes []Process
+ Buildpacks []Buildpack
+ Env BuildEnv
+ Exec func(argv0 string, argv []string, envv []string) error
+}
+
+func (l *Launcher) Launch(self string, cmd []string) error {
+ if err := l.env(); err != nil {
+ return errors.Wrap(err, "modify env")
+ }
+ process, err := l.processFor(cmd)
+ if err != nil {
+ return errors.Wrap(err, "determine start command")
+ }
+ if err := os.Chdir(l.AppDir); err != nil {
+ return errors.Wrap(err, "change to app directory")
+ }
+ if process.Direct {
+ binary, err := exec.LookPath(process.Command)
+ if err != nil {
+ return errors.Wrap(err, "path lookup")
+ }
+
+ if err := l.Exec(binary,
+ append([]string{process.Command}, process.Args...),
+ l.Env.List(),
+ ); err != nil {
+ return errors.Wrap(err, "direct exec")
+ }
+ return nil
+ }
+ launcher, err := l.profileD()
+ if err != nil {
+ return errors.Wrap(err, "determine profile")
+ }
+ if err := l.Exec("/bin/bash", append([]string{
+ "bash", "-c",
+ launcher, self, process.Command,
+ }, process.Args...), l.Env.List()); err != nil {
+ return errors.Wrap(err, "bash exec")
+ }
+ return nil
+}
+
+func (l *Launcher) env() error {
+ appInfo, err := os.Stat(l.AppDir)
+ if err != nil {
+ return errors.Wrap(err, "find app directory")
+ }
+ return l.eachBuildpack(l.LayersDir, func(path string) error {
+ bpInfo, err := os.Stat(path)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return nil
+ }
+ return errors.Wrap(err, "find buildpack directory")
+ }
+ if os.SameFile(appInfo, bpInfo) {
+ return nil
+ }
+ if err := eachDir(path, func(path string) error {
+ return l.Env.AddRootDir(path)
+ }); err != nil {
+ return errors.Wrap(err, "add layer root")
+ }
+ if err := eachDir(path, func(path string) error {
+ if err := l.Env.AddEnvDir(filepath.Join(path, "env")); err != nil {
+ return err
+ }
+ return l.Env.AddEnvDir(filepath.Join(path, "env.launch"))
+ }); err != nil {
+ return errors.Wrap(err, "add layer env")
+ }
+ return nil
+ })
+}
+
+func (l *Launcher) profileD() (string, error) {
+ var out []string
+
+ appendIfFile := func(path string) error {
+ fi, err := os.Stat(path)
+ if os.IsNotExist(err) {
+ return nil
+ }
+ if err != nil {
+ return err
+ }
+ if !fi.IsDir() {
+ out = append(out, fmt.Sprintf(`source "%s"`, path))
+ }
+ return nil
+ }
+ layersDir, err := filepath.Abs(l.LayersDir)
+ if err != nil {
+ return "", err
+ }
+ for _, bp := range l.Buildpacks {
+ scripts, err := filepath.Glob(filepath.Join(layersDir, bp.dir(), "*", "profile.d", "*"))
+ if err != nil {
+ return "", err
+ }
+ for _, script := range scripts {
+ if err := appendIfFile(script); err != nil {
+ return "", err
+ }
+ }
+ }
+
+ if err := appendIfFile(filepath.Join(l.AppDir, ".profile")); err != nil {
+ return "", err
+ }
+
+ out = append(out, `exec bash -c "$@"`)
+ return strings.Join(out, "\n"), nil
+}
+
+func (l *Launcher) processFor(cmd []string) (Process, error) {
+ if len(cmd) == 0 {
+ if process, ok := l.findProcessType(l.DefaultProcessType); ok {
+ return process, nil
+ }
+
+ return Process{}, fmt.Errorf("process type %s was not found", l.DefaultProcessType)
+ }
+
+ if len(cmd) == 1 {
+ if process, ok := l.findProcessType(cmd[0]); ok {
+ return process, nil
+ }
+ }
+
+ if len(cmd) > 1 && cmd[0] == "--" {
+ return Process{Command: cmd[1], Args: cmd[2:], Direct: true}, nil
+ }
+
+ return Process{Command: cmd[0], Args: cmd[1:]}, nil
+}
+
+func (l *Launcher) findProcessType(kind string) (Process, bool) {
+ for _, p := range l.Processes {
+ if p.Type == kind {
+ return p, true
+ }
+ }
+
+ return Process{}, false
+}
+
+func eachDir(dir string, fn func(path string) error) error {
+ files, err := ioutil.ReadDir(dir)
+ if os.IsNotExist(err) {
+ return nil
+ } else if err != nil {
+ return err
+ }
+ for _, f := range files {
+ if !f.IsDir() {
+ continue
+ }
+ if err := fn(filepath.Join(dir, f.Name())); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func (l *Launcher) eachBuildpack(dir string, fn func(path string) error) error {
+ for _, bp := range l.Buildpacks {
+ if err := fn(filepath.Join(l.LayersDir, bp.dir())); err != nil {
+ return err
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/layers.go b/vendor/github.com/buildpacks/lifecycle/layers.go
new file mode 100644
index 00000000000..a3d1a54365b
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/layers.go
@@ -0,0 +1,199 @@
+package lifecycle
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/BurntSushi/toml"
+)
+
+type bpLayersDir struct {
+ path string
+ layers []bpLayer
+ name string
+ buildpack Buildpack
+}
+
+func readBuildpackLayersDir(layersDir string, buildpack Buildpack) (bpLayersDir, error) {
+ path := filepath.Join(layersDir, buildpack.dir())
+ bpDir := bpLayersDir{
+ name: buildpack.ID,
+ path: path,
+ layers: []bpLayer{},
+ buildpack: buildpack,
+ }
+
+ fis, err := ioutil.ReadDir(path)
+ if err != nil && !os.IsNotExist(err) {
+ return bpLayersDir{}, err
+ }
+
+ names := map[string]struct{}{}
+ for _, fi := range fis {
+ if fi.IsDir() {
+ bpDir.layers = append(bpDir.layers, *bpDir.newBPLayer(fi.Name()))
+ names[fi.Name()] = struct{}{}
+ }
+ }
+
+ tomls, err := filepath.Glob(filepath.Join(path, "*.toml"))
+ if err != nil {
+ return bpLayersDir{}, err
+ }
+ for _, toml := range tomls {
+ name := strings.TrimSuffix(filepath.Base(toml), ".toml")
+ if _, ok := names[name]; !ok {
+ bpDir.layers = append(bpDir.layers, *bpDir.newBPLayer(name))
+ }
+ }
+ return bpDir, nil
+}
+
+func launch(l bpLayer) bool {
+ md, err := l.read()
+ return err == nil && md.Launch
+}
+
+func malformed(l bpLayer) bool {
+ _, err := l.read()
+ return err != nil
+}
+
+func cached(l bpLayer) bool {
+ md, err := l.read()
+ return err == nil && md.Cache
+}
+
+func (bd *bpLayersDir) findLayers(f func(layer bpLayer) bool) []bpLayer {
+ var selectedLayers []bpLayer
+ for _, l := range bd.layers {
+ if f(l) {
+ selectedLayers = append(selectedLayers, l)
+ }
+ }
+ return selectedLayers
+}
+
+func (bd *bpLayersDir) newBPLayer(name string) *bpLayer {
+ return &bpLayer{
+ layer{
+ path: filepath.Join(bd.path, name),
+ identifier: fmt.Sprintf("%s:%s", bd.buildpack.ID, name),
+ },
+ }
+}
+
+type bpLayer struct {
+ layer
+}
+
+func (bp *bpLayer) read() (BuildpackLayerMetadata, error) {
+ var data BuildpackLayerMetadata
+ tomlPath := bp.path + ".toml"
+ fh, err := os.Open(tomlPath)
+ if os.IsNotExist(err) {
+ return BuildpackLayerMetadata{}, nil
+ } else if err != nil {
+ return BuildpackLayerMetadata{}, err
+ }
+ defer fh.Close()
+ if _, err := toml.DecodeFile(tomlPath, &data); err != nil {
+ return BuildpackLayerMetadata{}, err
+ }
+ sha, err := ioutil.ReadFile(bp.path + ".sha")
+ if err != nil {
+ if os.IsNotExist(err) {
+ return data, nil
+ }
+ return BuildpackLayerMetadata{}, err
+ }
+ data.SHA = string(sha)
+ return data, nil
+}
+
+func (bp *bpLayer) remove() error {
+ if err := os.RemoveAll(bp.path); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ if err := os.Remove(bp.path + ".sha"); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ if err := os.Remove(bp.path + ".toml"); err != nil && !os.IsNotExist(err) {
+ return err
+ }
+ return nil
+}
+
+func (bp *bpLayer) writeMetadata(metadata BuildpackLayerMetadata) error {
+ path := filepath.Join(bp.path + ".toml")
+ if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
+ return err
+ }
+ fh, err := os.Create(path)
+ if err != nil {
+ return err
+ }
+ defer fh.Close()
+ return toml.NewEncoder(fh).Encode(metadata.BuildpackLayerMetadataFile)
+}
+
+func (bp *bpLayer) hasLocalContents() bool {
+ _, err := ioutil.ReadDir(bp.path)
+
+ return !os.IsNotExist(err)
+}
+
+func (bp *bpLayer) writeSha(sha string) error {
+ if err := ioutil.WriteFile(bp.path+".sha", []byte(sha), 0777); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (bp *bpLayer) name() string {
+ return filepath.Base(bp.path)
+}
+
+type layer struct {
+ path string
+ identifier string
+}
+
+func (l *layer) Identifier() string {
+ return l.identifier
+}
+
+func (l *layer) Path() string {
+ return l.path
+}
+
+type identifiableLayer interface {
+ Identifier() string
+ Path() string
+}
+
+func recursiveChown(path string, uid, gid int) error {
+ fis, err := ioutil.ReadDir(path)
+ if err != nil {
+ return err
+ }
+ if err := os.Chown(path, uid, gid); err != nil {
+ return err
+ }
+ for _, fi := range fis {
+ filePath := filepath.Join(path, fi.Name())
+ if fi.IsDir() {
+ if err := recursiveChown(filePath, uid, gid); err != nil {
+ return err
+ }
+ } else {
+ if err := os.Lchown(filePath, uid, gid); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/lifecycle.go b/vendor/github.com/buildpacks/lifecycle/lifecycle.go
new file mode 100644
index 00000000000..f13158a2447
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/lifecycle.go
@@ -0,0 +1,39 @@
+package lifecycle
+
+var POSIXBuildEnv = map[string][]string{
+ "bin": {
+ "PATH",
+ },
+ "lib": {
+ "LD_LIBRARY_PATH",
+ "LIBRARY_PATH",
+ },
+ "include": {
+ "CPATH",
+ },
+ "pkgconfig": {
+ "PKG_CONFIG_PATH",
+ },
+}
+
+var POSIXLaunchEnv = map[string][]string{
+ "bin": {"PATH"},
+ "lib": {"LD_LIBRARY_PATH"},
+}
+
+type buildpackTOML struct {
+ Buildpack buildpackInfo `toml:"buildpack"`
+ Order BuildpackOrder `toml:"order"`
+ Path string `toml:"-"`
+}
+
+type buildpackInfo struct {
+ ID string `toml:"id"`
+ Version string `toml:"version"`
+ Name string `toml:"name"`
+ ClearEnv bool `toml:"clear-env,omitempty"`
+}
+
+func (bp buildpackTOML) String() string {
+ return bp.Buildpack.Name + " " + bp.Buildpack.Version
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/logger.go b/vendor/github.com/buildpacks/lifecycle/logger.go
new file mode 100644
index 00000000000..6daaf019022
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/logger.go
@@ -0,0 +1,15 @@
+package lifecycle
+
+type Logger interface {
+ Debug(msg string)
+ Debugf(fmt string, v ...interface{})
+
+ Info(msg string)
+ Infof(fmt string, v ...interface{})
+
+ Warn(msg string)
+ Warnf(fmt string, v ...interface{})
+
+ Error(msg string)
+ Errorf(fmt string, v ...interface{})
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/metadata.go b/vendor/github.com/buildpacks/lifecycle/metadata.go
new file mode 100644
index 00000000000..0f392ff616c
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/metadata.go
@@ -0,0 +1,160 @@
+package lifecycle
+
+import (
+ "path"
+
+ "github.com/google/go-containerregistry/pkg/name"
+ "github.com/pkg/errors"
+)
+
+const (
+ BuildMetadataLabel = "io.buildpacks.build.metadata"
+ LayerMetadataLabel = "io.buildpacks.lifecycle.metadata"
+ StackIDLabel = "io.buildpacks.stack.id"
+)
+
+type BuildMetadata struct {
+ Processes []Process `toml:"processes" json:"processes"`
+ Buildpacks []Buildpack `toml:"buildpacks" json:"buildpacks"`
+ BOM []BOMEntry `toml:"bom" json:"bom"`
+ Launcher LauncherMetadata `toml:"-" json:"launcher"`
+ Slices []Slice `toml:"slices" json:"-"`
+}
+
+type LauncherMetadata struct {
+ Version string `json:"version"`
+ Source SourceMetadata `json:"source"`
+}
+
+type SourceMetadata struct {
+ Git GitMetadata `json:"git"`
+}
+
+type GitMetadata struct {
+ Repository string `json:"repository"`
+ Commit string `json:"commit"`
+}
+
+func MetadataFilePath(layersDir string) string {
+ return path.Join(layersDir, "config", "metadata.toml")
+}
+
+type CacheMetadata struct {
+ Buildpacks []BuildpackLayersMetadata `json:"buildpacks"`
+}
+
+func (cm *CacheMetadata) MetadataForBuildpack(id string) BuildpackLayersMetadata {
+ for _, bpMd := range cm.Buildpacks {
+ if bpMd.ID == id {
+ return bpMd
+ }
+ }
+ return BuildpackLayersMetadata{}
+}
+
+// NOTE: This struct MUST be kept in sync with `LayersMetadataCompat`
+type LayersMetadata struct {
+ App []LayerMetadata `json:"app" toml:"app"`
+ Config LayerMetadata `json:"config" toml:"config"`
+ Launcher LayerMetadata `json:"launcher" toml:"launcher"`
+ Buildpacks []BuildpackLayersMetadata `json:"buildpacks" toml:"buildpacks"`
+ RunImage RunImageMetadata `json:"runImage" toml:"run-image"`
+ Stack StackMetadata `json:"stack" toml:"stack"`
+}
+
+// NOTE: This struct MUST be kept in sync with `LayersMetadata`.
+// It exists for situations where the `App` field type cannot be
+// guaranteed, yet the original struct data must be maintained.
+type LayersMetadataCompat struct {
+ App interface{} `json:"app" toml:"app"`
+ Config LayerMetadata `json:"config" toml:"config"`
+ Launcher LayerMetadata `json:"launcher" toml:"launcher"`
+ Buildpacks []BuildpackLayersMetadata `json:"buildpacks" toml:"buildpacks"`
+ RunImage RunImageMetadata `json:"runImage" toml:"run-image"`
+ Stack StackMetadata `json:"stack" toml:"stack"`
+}
+
+type AnalyzedMetadata struct {
+ Image *ImageIdentifier `toml:"image"`
+ Metadata LayersMetadata `toml:"metadata"`
+}
+
+// FIXME: fix key names to be accurate in the daemon case
+type ImageIdentifier struct {
+ Reference string `toml:"reference"`
+}
+
+type LayerMetadata struct {
+ SHA string `json:"sha" toml:"sha"`
+}
+
+type BuildpackLayersMetadata struct {
+ ID string `json:"key" toml:"key"`
+ Version string `json:"version" toml:"version"`
+ Layers map[string]BuildpackLayerMetadata `json:"layers" toml:"layers"`
+}
+
+type BuildpackLayerMetadata struct {
+ LayerMetadata
+ BuildpackLayerMetadataFile
+}
+
+type BuildpackLayerMetadataFile struct {
+ Data interface{} `json:"data" toml:"metadata"`
+ Build bool `json:"build" toml:"build"`
+ Launch bool `json:"launch" toml:"launch"`
+ Cache bool `json:"cache" toml:"cache"`
+}
+
+type RunImageMetadata struct {
+ TopLayer string `json:"topLayer" toml:"top-layer"`
+ Reference string `json:"reference" toml:"reference"`
+}
+
+type StackMetadata struct {
+ RunImage StackRunImageMetadata `json:"runImage" toml:"run-image"`
+}
+
+type StackRunImageMetadata struct {
+ Image string `toml:"image" json:"image"`
+ Mirrors []string `toml:"mirrors" json:"mirrors,omitempty"`
+}
+
+func (sm *StackMetadata) BestRunImageMirror(registry string) (string, error) {
+ if sm.RunImage.Image == "" {
+ return "", errors.New("missing run-image metadata")
+ }
+ runImageMirrors := []string{sm.RunImage.Image}
+ runImageMirrors = append(runImageMirrors, sm.RunImage.Mirrors...)
+ runImageRef, err := byRegistry(registry, runImageMirrors)
+ if err != nil {
+ return "", errors.Wrap(err, "failed to find run-image")
+ }
+ return runImageRef, nil
+}
+
+func (m *LayersMetadata) MetadataForBuildpack(id string) BuildpackLayersMetadata {
+ for _, bpMd := range m.Buildpacks {
+ if bpMd.ID == id {
+ return bpMd
+ }
+ }
+ return BuildpackLayersMetadata{}
+}
+
+func byRegistry(reg string, imgs []string) (string, error) {
+ if len(imgs) < 1 {
+ return "", errors.New("no images provided to search")
+ }
+
+ for _, img := range imgs {
+ ref, err := name.ParseReference(img, name.WeakValidation)
+ if err != nil {
+ continue
+ }
+ if reg == ref.Context().RegistryStr() {
+ return img, nil
+ }
+ }
+ return imgs[0], nil
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/rebaser.go b/vendor/github.com/buildpacks/lifecycle/rebaser.go
new file mode 100644
index 00000000000..acbb3a0d642
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/rebaser.go
@@ -0,0 +1,73 @@
+package lifecycle
+
+import (
+ "encoding/json"
+ "fmt"
+
+ "github.com/buildpacks/imgutil"
+ "github.com/pkg/errors"
+)
+
+type Rebaser struct {
+ Logger Logger
+}
+
+func (r *Rebaser) Rebase(
+ workingImage imgutil.Image,
+ newBaseImage imgutil.Image,
+ additionalNames []string,
+) error {
+ var origMetadata LayersMetadataCompat
+ if err := DecodeLabel(workingImage, LayerMetadataLabel, &origMetadata); err != nil {
+ return errors.Wrap(err, "get image metadata")
+ }
+
+ workingStackID, err := workingImage.Label(StackIDLabel)
+ if err != nil {
+ return errors.Wrap(err, "get working image stack")
+ }
+
+ newBaseStackID, err := newBaseImage.Label(StackIDLabel)
+ if err != nil {
+ return errors.Wrap(err, "get new base image stack")
+ }
+
+ if workingStackID == "" {
+ return errors.New("stack not defined on working image")
+ }
+
+ if newBaseStackID == "" {
+ return errors.New("stack not defined on new base image")
+ }
+
+ if workingStackID != newBaseStackID {
+ return errors.New(fmt.Sprintf("incompatible stack: '%s' is not compatible with '%s'", newBaseStackID, workingStackID))
+ }
+
+ err = workingImage.Rebase(origMetadata.RunImage.TopLayer, newBaseImage)
+ if err != nil {
+ return errors.Wrap(err, "rebase working image")
+ }
+
+ origMetadata.RunImage.TopLayer, err = newBaseImage.TopLayer()
+ if err != nil {
+ return errors.Wrap(err, "get rebase run image top layer SHA")
+ }
+
+ identifier, err := newBaseImage.Identifier()
+ if err != nil {
+ return errors.Wrap(err, "get run image id or digest")
+ }
+ origMetadata.RunImage.Reference = identifier.String()
+
+ data, err := json.Marshal(origMetadata)
+ if err != nil {
+ return errors.Wrap(err, "marshall metadata")
+ }
+
+ if err := workingImage.SetLabel(LayerMetadataLabel, string(data)); err != nil {
+ return errors.Wrap(err, "set app image metadata label")
+ }
+
+ return saveImage(workingImage, additionalNames, r.Logger)
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/restorer.go b/vendor/github.com/buildpacks/lifecycle/restorer.go
new file mode 100644
index 00000000000..c281564ea24
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/restorer.go
@@ -0,0 +1,99 @@
+package lifecycle
+
+import (
+ "os"
+
+ "github.com/pkg/errors"
+ "golang.org/x/sync/errgroup"
+
+ "github.com/buildpacks/lifecycle/archive"
+)
+
+type Restorer struct {
+ LayersDir string
+ Buildpacks []Buildpack
+ Logger Logger
+ UID int
+ GID int
+}
+
+// Restore attempts to restore layer data for cache=true layers, removing the layer when unsuccessful.
+// If a usable cache is not provided, Restore will remove all cache=true layer metadata.
+func (r *Restorer) Restore(cache Cache) error {
+ // Create empty cache metadata in case a usable cache is not provided.
+ var meta CacheMetadata
+ if cache != nil {
+ var err error
+ meta, err = cache.RetrieveMetadata()
+ if err != nil {
+ return errors.Wrapf(err, "retrieving cache metadata")
+ }
+ } else {
+ r.Logger.Debug("Usable cache not provided, using empty cache metadata.")
+ }
+
+ var g errgroup.Group
+ for _, buildpack := range r.Buildpacks {
+ buildpackDir, err := readBuildpackLayersDir(r.LayersDir, buildpack)
+ if err != nil {
+ return errors.Wrapf(err, "reading buildpack layer directory")
+ }
+
+ cachedLayers := meta.MetadataForBuildpack(buildpack.ID).Layers
+ for _, bpLayer := range buildpackDir.findLayers(cached) {
+ name := bpLayer.name()
+ cachedLayer, exists := cachedLayers[name]
+ if !exists {
+ r.Logger.Infof("Removing %q, not in cache", bpLayer.Identifier())
+ if err := bpLayer.remove(); err != nil {
+ return errors.Wrapf(err, "removing layer")
+ }
+ continue
+ }
+ data, err := bpLayer.read()
+ if err != nil {
+ return errors.Wrapf(err, "reading layer")
+ }
+ if data.SHA != cachedLayer.SHA {
+ r.Logger.Infof("Removing %q, wrong sha", bpLayer.Identifier())
+ r.Logger.Debugf("Layer sha: %q, cache sha: %q", data.SHA, cachedLayer.SHA)
+ if err := bpLayer.remove(); err != nil {
+ return errors.Wrapf(err, "removing layer")
+ }
+ } else {
+ r.Logger.Infof("Restoring data for %q from cache", bpLayer.Identifier())
+ g.Go(func() error {
+ return r.restoreLayer(cache, cachedLayer.SHA)
+ })
+ }
+ }
+ }
+ if err := g.Wait(); err != nil {
+ return errors.Wrap(err, "restoring data")
+ }
+
+ // if restorer is running as root it needs to fix the ownership of the layers dir
+ if current := os.Getuid(); current == -1 {
+ return errors.New("cannot determine UID")
+ } else if current == 0 {
+ if err := recursiveChown(r.LayersDir, r.UID, r.GID); err != nil {
+ return errors.Wrapf(err, "chowning layers dir to '%d/%d'", r.UID, r.GID)
+ }
+ }
+ return nil
+}
+
+func (r *Restorer) restoreLayer(cache Cache, sha string) error {
+ // Sanity check to prevent panic.
+ if cache == nil {
+ return errors.New("restoring layer: cache not provided")
+ }
+ r.Logger.Debugf("Retrieving data for %q", sha)
+ rc, err := cache.RetrieveLayer(sha)
+ if err != nil {
+ return err
+ }
+ defer rc.Close()
+
+ return archive.Untar(rc, "/")
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/save.go b/vendor/github.com/buildpacks/lifecycle/save.go
new file mode 100644
index 00000000000..3b4702a5e50
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/save.go
@@ -0,0 +1,73 @@
+package lifecycle
+
+import (
+ "fmt"
+
+ "github.com/buildpacks/imgutil"
+ "github.com/buildpacks/imgutil/local"
+ "github.com/buildpacks/imgutil/remote"
+ "github.com/pkg/errors"
+)
+
+func saveImage(image imgutil.Image, additionalNames []string, logger Logger) error {
+ var saveErr error
+ if err := image.Save(additionalNames...); err != nil {
+ var ok bool
+ if saveErr, ok = err.(imgutil.SaveError); !ok {
+ return errors.Wrap(err, "saving image")
+ }
+ }
+
+ id, idErr := image.Identifier()
+ if idErr != nil {
+ if saveErr != nil {
+ return &MultiError{Errors: []error{idErr, saveErr}}
+ }
+ return idErr
+ }
+
+ refType, ref, shortRef := getReference(id)
+ logger.Infof("*** Images (%s):\n", shortRef)
+ for _, n := range append([]string{image.Name()}, additionalNames...) {
+ if ok, message := getSaveStatus(saveErr, n); !ok {
+ logger.Infof(" %s - %s\n", n, message)
+ } else {
+ logger.Infof(" %s\n", n)
+ }
+ }
+
+ logger.Debugf("\n*** %s: %s\n", refType, ref)
+ return saveErr
+}
+
+type MultiError struct {
+ Errors []error
+}
+
+func (me *MultiError) Error() string {
+ return fmt.Sprintf("failed with multiple errors %+v", me.Errors)
+}
+
+func getReference(identifier imgutil.Identifier) (string, string, string) {
+ switch v := identifier.(type) {
+ case local.IDIdentifier:
+ return "Image ID", v.String(), TruncateSha(v.String())
+ case remote.DigestIdentifier:
+ return "Digest", v.Digest.DigestStr(), v.Digest.DigestStr()
+ default:
+ return "Reference", v.String(), v.String()
+ }
+}
+
+func getSaveStatus(err error, imageName string) (bool, string) {
+ if err != nil {
+ if saveErr, ok := err.(imgutil.SaveError); ok {
+ for _, d := range saveErr.Errors {
+ if d.ImageName == imageName {
+ return false, d.Cause.Error()
+ }
+ }
+ }
+ }
+ return true, ""
+}
diff --git a/vendor/github.com/buildpacks/lifecycle/utils.go b/vendor/github.com/buildpacks/lifecycle/utils.go
new file mode 100644
index 00000000000..243fcba1ef6
--- /dev/null
+++ b/vendor/github.com/buildpacks/lifecycle/utils.go
@@ -0,0 +1,76 @@
+package lifecycle
+
+import (
+ "encoding/json"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "github.com/BurntSushi/toml"
+ "github.com/buildpacks/imgutil"
+ "github.com/pkg/errors"
+)
+
+func WriteTOML(path string, data interface{}) error {
+ if err := os.MkdirAll(filepath.Dir(path), 0777); err != nil {
+ return err
+ }
+ f, err := os.Create(path)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ return toml.NewEncoder(f).Encode(data)
+}
+
+func ReadGroup(path string) (BuildpackGroup, error) {
+ var group BuildpackGroup
+ _, err := toml.DecodeFile(path, &group)
+ return group, err
+}
+
+func ReadOrder(path string) (BuildpackOrder, error) {
+ var order struct {
+ Order BuildpackOrder `toml:"order"`
+ }
+ _, err := toml.DecodeFile(path, &order)
+ return order.Order, err
+}
+
+func TruncateSha(sha string) string {
+ rawSha := strings.TrimPrefix(sha, "sha256:")
+ if len(sha) > 12 {
+ return rawSha[0:12]
+ }
+ return rawSha
+}
+
+func DecodeLabel(image imgutil.Image, label string, v interface{}) error {
+ if !image.Found() {
+ return nil
+ }
+ contents, err := image.Label(label)
+ if err != nil {
+ return errors.Wrapf(err, "retrieving label '%s' for image '%s'", label, image.Name())
+ }
+ if contents == "" {
+ return nil
+ }
+ if err := json.Unmarshal([]byte(contents), v); err != nil {
+ return errors.Wrapf(err, "failed to unmarshal context of label '%s'", label)
+ }
+ return nil
+}
+
+func escapeID(id string) string {
+ return strings.Replace(id, "/", "_", -1)
+}
+
+func isEmptyDir(name string) (bool, error) {
+ entries, err := ioutil.ReadDir(name)
+ if err != nil {
+ return false, err
+ }
+ return len(entries) == 0, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/.gitignore b/vendor/github.com/buildpacks/pack/.gitignore
new file mode 100644
index 00000000000..c3cc6a71c46
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/.gitignore
@@ -0,0 +1,13 @@
+.pack/
+/pack
+out/
+
+# Jetbrains Goland
+.idea/
+
+# Build outputs
+artifacts/
+.DS_Store
+
+# Travis unencrypted file
+.travis/key.pem
\ No newline at end of file
diff --git a/vendor/github.com/buildpacks/pack/.travis.yml b/vendor/github.com/buildpacks/pack/.travis.yml
new file mode 100644
index 00000000000..2c86f897b95
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/.travis.yml
@@ -0,0 +1,24 @@
+language: go
+go: 1.12.x
+
+env:
+ global:
+ - GO111MODULE=on
+
+jobs:
+ include:
+ - os: linux
+ script: make
+ - os: osx
+ script: make
+ env:
+ - NO_DOCKER=true
+ - os: windows
+ script: go test -mod=vendor -parallel=1 -v ./...
+ after_success: go build -mod=vendor -o pack ./cmd/pack
+ env:
+ - NO_DOCKER=true
+
+branches:
+ only:
+ - master
\ No newline at end of file
diff --git a/vendor/github.com/buildpacks/pack/CODEOWNERS b/vendor/github.com/buildpacks/pack/CODEOWNERS
new file mode 100644
index 00000000000..e9a137de3ef
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/CODEOWNERS
@@ -0,0 +1 @@
+* @buildpack/platform-maintainers
diff --git a/vendor/github.com/buildpacks/pack/CONTRIBUTING.md b/vendor/github.com/buildpacks/pack/CONTRIBUTING.md
new file mode 100644
index 00000000000..9f9b7ced1ed
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/CONTRIBUTING.md
@@ -0,0 +1,102 @@
+We're glad you are interested in contributing to this project. We hope that this
+document helps you get started.
+
+If something is missing, incorrect, or made irrelevant please feel free to make
+a PR to keep it up-to-date.
+
+## Prerequisites
+
+- [Go](https://golang.org/dl/)
+ - including [Git](https://git-scm.com/)
+- [Docker](https://www.docker.com/)
+
+## Development
+
+### Building
+
+To build pack:
+```
+make build
+```
+
+This will output the binary to the directory `out/`.
+
+Options:
+
+| ENV_VAR | Description | Default |
+|--------------|------------------------------------------------------------------------|---------|
+| GOCMD | Change the `go` executable. For example, [richgo][rgo] for testing. | go |
+| PACK_BIN | Change the name or location of the binary relative to `out/`. | pack |
+| PACK_VERSION | Tell `pack` what version to consider itself | `dev` |
+
+[rgo]: https://github.com/kyoh86/richgo
+
+_NOTE: This project uses [go modules](https://github.com/golang/go/wiki/Modules) for dependency management._
+
+### Testing
+
+To run unit and integration tests:
+
+```bash
+make unit
+```
+
+To run acceptance tests:
+```bash
+make acceptance
+```
+
+Alternately, to run all tests:
+```bash
+make test
+```
+
+### Formatting
+
+To format the code:
+
+```bash
+make format
+```
+
+### Verification
+
+To verify formatting and vet:
+```bash
+make verify
+```
+
+## Pull Requests
+
+1. **[Fork]((https://help.github.com/en/articles/fork-a-repo)) the repo**
+2. **Code, Test, Commit...**
+
+ _Don't forget utilize the convenient make functions above._
+
+3. **Preparing a Branch**
+
+ We prefer to have PRs that are encompassed in a single commit. This might
+ require that you execute some of these commands:
+
+ If you are no up-to-date with master:
+ ```bash
+ # rebase from master (applies your changes on top of master)
+ git pull -r origin master
+ ```
+
+ If you made more than one commit:
+ ```bash
+ # squash multiple commits, if applicable
+ # set the top most commit to `pick` and all subsequent to `squash`
+ git rebase -i origin/master
+ ```
+
+ Another requirement is that you sign your work. See [DCO](https://probot.github.io/apps/dco/) for more details.
+ ```bash
+ git commit --amend --signoff
+ ```
+
+4. **Submit a Pull Request**
+
+ Submitting the pull request is done in [GitHub](https://github.com/buildpacks/pack/compare/) by selecting
+ your branch as the `compare` branch.
\ No newline at end of file
diff --git a/vendor/github.com/buildpacks/pack/LICENSE b/vendor/github.com/buildpacks/pack/LICENSE
new file mode 100644
index 00000000000..261eeb9e9f8
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/LICENSE
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/vendor/github.com/buildpacks/pack/Makefile b/vendor/github.com/buildpacks/pack/Makefile
new file mode 100644
index 00000000000..682137abd46
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/Makefile
@@ -0,0 +1,75 @@
+GOCMD?=go
+GOENV=CGO_ENABLED=0
+GOFLAGS?=-mod=vendor
+PACK_VERSION?=dev-$(shell date +%Y-%m-%d-%H:%M:%S)
+PACK_BIN?=pack
+PACKAGE_BASE=github.com/buildpacks/pack
+PACKAGES:=$(shell $(GOCMD) list ./... | grep -v /testdata/)
+SRC:=$(shell find . -type f -name '*.go' -not -path "*/vendor/*")
+ARCHIVE_NAME=pack-$(PACK_VERSION)
+
+export GOFLAGS:=$(GOFLAGS)
+
+all: clean verify test build
+
+build:
+ @echo "> Building..."
+ mkdir -p ./out
+ $(GOENV) $(GOCMD) build -ldflags "-X 'github.com/buildpacks/pack/cmd.Version=${PACK_VERSION}'" -o ./out/$(PACK_BIN) -a ./cmd/pack
+
+package:
+ tar czf ./out/$(ARCHIVE_NAME).tgz -C out/ pack
+
+install-mockgen:
+ @echo "> Installing mockgen..."
+ cd tools; $(GOCMD) install github.com/golang/mock/mockgen
+
+install-goimports:
+ @echo "> Installing goimports..."
+ cd tools; $(GOCMD) install golang.org/x/tools/cmd/goimports
+
+format: install-goimports
+ @echo "> Formating code..."
+ @goimports -l -w -local ${PACKAGE_BASE} ${SRC}
+
+install-golangci-lint:
+ @echo "> Installing golangci-lint..."
+ cd tools; $(GOCMD) install github.com/golangci/golangci-lint/cmd/golangci-lint
+
+lint: install-golangci-lint
+ @echo "> Linting code..."
+ @golangci-lint run -c golangci.yaml
+
+test: unit acceptance
+
+unit: format lint
+ @echo "> Running unit/integration tests..."
+ $(GOCMD) test -v -count=1 -parallel=1 -timeout=0 ./...
+
+acceptance: format lint
+ @echo "> Running acceptance tests..."
+ $(GOCMD) test -v -count=1 -parallel=1 -timeout=0 -tags=acceptance ./acceptance
+
+acceptance-all: format lint
+ @echo "> Running acceptance tests..."
+ ACCEPTANCE_SUITE_CONFIG=$$(cat ./acceptance/testconfig/all.json) $(GOCMD) test -v -count=1 -parallel=1 -timeout=0 -tags=acceptance ./acceptance
+
+clean:
+ @echo "> Cleaning workspace..."
+ rm -rf ./out
+
+verify: verify-format lint
+
+generate: install-mockgen
+ @echo "> Generating mocks..."
+ $(GOCMD) generate ./...
+
+verify-format: install-goimports
+ @echo "> Verifying format..."
+ @test -z "$(shell goimports -l -local ${PACKAGE_BASE} ${SRC})";\
+ _err=$$?;\
+ [ $$_err -ne 0 ] && echo "ERROR: Format verification failed!\n" &&\
+ goimports -d -local ${PACKAGE_BASE} ${SRC} && exit $$_err;\
+ exit 0;
+
+.PHONY: clean build format imports lint test unit acceptance verify verify-format
\ No newline at end of file
diff --git a/vendor/github.com/buildpacks/pack/README.md b/vendor/github.com/buildpacks/pack/README.md
new file mode 100644
index 00000000000..1f091ebc300
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/README.md
@@ -0,0 +1,33 @@
+# pack - Buildpack CLI
+
+[![Travis Build Status](https://travis-ci.org/buildpacks/pack.svg?branch=master)](https://travis-ci.org/buildpacks/pack/branches)
+[![Go Report Card](https://goreportcard.com/badge/github.com/buildpacks/pack)](https://goreportcard.com/report/github.com/buildpacks/pack)
+[![GoDoc](https://godoc.org/github.com/buildpacks/pack?status.svg)](https://godoc.org/github.com/buildpacks/pack)
+[![GitHub license](https://img.shields.io/github/license/buildpacks/pack)](https://github.com/buildpacks/pack/blob/master/LICENSE)
+[![Slack](https://slack.buildpacks.io/badge.svg)](https://slack.buildpacks.io/)
+
+`pack` makes it easy for...
+- **App Developers** to use buildpacks to convert code into runnable images.
+- **Buildpack Authors** to develop and package buildpacks for distribution.
+- **Operators** to package buildpacks for distribution and maintain applications.
+
+`pack` is a CLI implementation of the [Platform Interface Specification][platform-spec] for [Cloud Native Buildpacks][buildpacks.io].
+
+## Usage
+
+- [Installing][install-pack]
+- [Getting Started][getting-started]
+
+## Contributing
+
+For information on how to contribute to this project including its development
+process see [CONTRIBUTING.md](CONTRIBUTING.md).
+
+## Resources
+- [Buildpack Specification](https://github.com/buildpacks/spec/blob/master/buildpack.md)
+- [Platform Specification][platform-spec]
+
+[buildpacks.io]: https://buildpacks.io/
+[install-pack]: https://buildpacks.io/docs/install-pack/
+[getting-started]: https://buildpacks.io/docs/app-journey
+[platform-spec]: https://github.com/buildpacks/spec/blob/master/platform.md
diff --git a/vendor/github.com/buildpacks/pack/build.go b/vendor/github.com/buildpacks/pack/build.go
new file mode 100644
index 00000000000..33ef755bcfc
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/build.go
@@ -0,0 +1,441 @@
+package pack
+
+import (
+ "context"
+ "fmt"
+ "math/rand"
+ "net/url"
+ "os"
+ "path/filepath"
+ "runtime"
+ "strings"
+
+ "github.com/buildpacks/imgutil"
+ "github.com/docker/docker/api/types"
+ "github.com/google/go-containerregistry/pkg/name"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/cmd"
+ "github.com/buildpacks/pack/internal/api"
+ "github.com/buildpacks/pack/internal/archive"
+ "github.com/buildpacks/pack/internal/build"
+ "github.com/buildpacks/pack/internal/builder"
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/paths"
+ "github.com/buildpacks/pack/internal/stack"
+ "github.com/buildpacks/pack/internal/stringset"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type Lifecycle interface {
+ Execute(ctx context.Context, opts build.LifecycleOptions) error
+}
+
+type BuildOptions struct {
+ Image string // required
+ Builder string // required
+ AppPath string // defaults to current working directory
+ RunImage string // defaults to the best mirror from the builder metadata or AdditionalMirrors
+ AdditionalMirrors map[string][]string // only considered if RunImage is not provided
+ Env map[string]string
+ Publish bool
+ NoPull bool
+ ClearCache bool
+ Buildpacks []string
+ ProxyConfig *ProxyConfig // defaults to environment proxy vars
+ ContainerConfig ContainerConfig
+}
+
+type ProxyConfig struct {
+ HTTPProxy string
+ HTTPSProxy string
+ NoProxy string
+}
+
+type ContainerConfig struct {
+ Network string
+}
+
+func (c *Client) Build(ctx context.Context, opts BuildOptions) error {
+ imageRef, err := c.parseTagReference(opts.Image)
+ if err != nil {
+ return errors.Wrapf(err, "invalid image name '%s'", opts.Image)
+ }
+
+ appPath, err := c.processAppPath(opts.AppPath)
+ if err != nil {
+ return errors.Wrapf(err, "invalid app path '%s'", opts.AppPath)
+ }
+
+ proxyConfig := c.processProxyConfig(opts.ProxyConfig)
+
+ builderRef, err := c.processBuilderName(opts.Builder)
+ if err != nil {
+ return errors.Wrapf(err, "invalid builder '%s'", opts.Builder)
+ }
+
+ rawBuilderImage, err := c.imageFetcher.Fetch(ctx, builderRef.Name(), true, !opts.NoPull)
+ if err != nil {
+ return errors.Wrapf(err, "failed to fetch builder image '%s'", builderRef.Name())
+ }
+
+ bldr, err := c.getBuilder(rawBuilderImage)
+ if err != nil {
+ return errors.Wrapf(err, "invalid builder '%s'", opts.Builder)
+ }
+
+ runImageName := c.resolveRunImage(opts.RunImage, imageRef.Context().RegistryStr(), bldr.Stack(), opts.AdditionalMirrors)
+ runImage, err := c.validateRunImage(ctx, runImageName, opts.NoPull, opts.Publish, bldr.StackID)
+ if err != nil {
+ return errors.Wrapf(err, "invalid run-image '%s'", runImageName)
+ }
+
+ var runMixins []string
+ if _, err := dist.GetLabel(runImage, stack.MixinsLabel, &runMixins); err != nil {
+ return err
+ }
+
+ fetchedBPs, group, err := c.processBuildpacks(ctx, opts.Buildpacks)
+ if err != nil {
+ return err
+ }
+
+ if err := c.validateMixins(fetchedBPs, bldr, runImageName, runMixins); err != nil {
+ return errors.Wrap(err, "validating stack mixins")
+ }
+
+ ephemeralBuilder, err := c.createEphemeralBuilder(rawBuilderImage, opts.Env, group, fetchedBPs)
+ if err != nil {
+ return err
+ }
+ defer c.docker.ImageRemove(context.Background(), ephemeralBuilder.Name(), types.ImageRemoveOptions{Force: true})
+
+ lcPlatformAPIVersion := ephemeralBuilder.LifecycleDescriptor().API.PlatformVersion
+ supportsPlatform := false
+ for _, v := range build.SupportedPlatformAPIVersions {
+ if api.MustParse(v).SupportsVersion(lcPlatformAPIVersion) {
+ supportsPlatform = true
+ break
+ }
+ }
+ if !supportsPlatform {
+ c.logger.Debugf("pack %s supports Platform API version(s): %s", cmd.Version, strings.Join(build.SupportedPlatformAPIVersions, ", "))
+ c.logger.Debugf("Builder %s has Platform API version: %s", style.Symbol(opts.Builder), lcPlatformAPIVersion)
+ return errors.Errorf("Builder %s is incompatible with this version of pack", style.Symbol(opts.Builder))
+ }
+
+ return c.lifecycle.Execute(ctx, build.LifecycleOptions{
+ AppPath: appPath,
+ Image: imageRef,
+ Builder: ephemeralBuilder,
+ RunImage: runImageName,
+ ClearCache: opts.ClearCache,
+ Publish: opts.Publish,
+ HTTPProxy: proxyConfig.HTTPProxy,
+ HTTPSProxy: proxyConfig.HTTPSProxy,
+ NoProxy: proxyConfig.NoProxy,
+ Network: opts.ContainerConfig.Network,
+ })
+}
+
+func (c *Client) processBuilderName(builderName string) (name.Reference, error) {
+ if builderName == "" {
+ return nil, errors.New("builder is a required parameter if the client has no default builder")
+ }
+ return name.ParseReference(builderName, name.WeakValidation)
+}
+
+func (c *Client) getBuilder(img imgutil.Image) (*builder.Builder, error) {
+ bldr, err := builder.FromImage(img)
+ if err != nil {
+ return nil, err
+ }
+ if bldr.Stack().RunImage.Image == "" {
+ return nil, errors.New("builder metadata is missing runImage")
+ }
+ return bldr, nil
+}
+
+func (c *Client) validateRunImage(context context.Context, name string, noPull bool, publish bool, expectedStack string) (imgutil.Image, error) {
+ if name == "" {
+ return nil, errors.New("run image must be specified")
+ }
+ img, err := c.imageFetcher.Fetch(context, name, !publish, !noPull)
+ if err != nil {
+ return nil, err
+ }
+ stackID, err := img.Label("io.buildpacks.stack.id")
+ if err != nil {
+ return nil, err
+ }
+ if stackID != expectedStack {
+ return nil, fmt.Errorf("run-image stack id '%s' does not match builder stack '%s'", stackID, expectedStack)
+ }
+ return img, nil
+}
+
+func (c *Client) validateMixins(additionalBuildpacks []dist.Buildpack, bldr *builder.Builder, runImageName string, runMixins []string) error {
+ if err := stack.ValidateMixins(bldr.Image().Name(), bldr.Mixins(), runImageName, runMixins); err != nil {
+ return err
+ }
+
+ bps, err := allBuildpacks(bldr.Image(), additionalBuildpacks)
+ if err != nil {
+ return err
+ }
+ mixins := assembleAvailableMixins(bldr.Mixins(), runMixins)
+
+ for _, bp := range bps {
+ if err := bp.EnsureStackSupport(bldr.StackID, mixins, true); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// assembleAvailableMixins returns the set of mixins that are common between the two provided sets, plus build-only mixins and run-only mixins.
+func assembleAvailableMixins(buildMixins, runMixins []string) []string {
+ // NOTE: We cannot simply union the two mixin sets, as this could introduce a mixin that is only present on one stack
+ // image but not the other. A buildpack that happens to require the mixin would fail to run properly, even though validation
+ // would pass.
+ //
+ // For example:
+ //
+ // Incorrect:
+ // Run image mixins: [A, B]
+ // Build image mixins: [A]
+ // Merged: [A, B]
+ // Buildpack requires: [A, B]
+ // Match? Yes
+ //
+ // Correct:
+ // Run image mixins: [A, B]
+ // Build image mixins: [A]
+ // Merged: [A]
+ // Buildpack requires: [A, B]
+ // Match? No
+
+ buildOnly := stack.FindStageMixins(buildMixins, "build")
+ runOnly := stack.FindStageMixins(runMixins, "run")
+ _, _, common := stringset.Compare(buildMixins, runMixins)
+
+ return append(common, append(buildOnly, runOnly...)...)
+}
+
+func allBuildpacks(builderImage imgutil.Image, additionalBuildpacks []dist.Buildpack) ([]dist.BuildpackDescriptor, error) {
+ var all []dist.BuildpackDescriptor
+ var bpLayers dist.BuildpackLayers
+ if _, err := dist.GetLabel(builderImage, dist.BuildpackLayersLabel, &bpLayers); err != nil {
+ return nil, err
+ }
+ for id, bps := range bpLayers {
+ for ver, bp := range bps {
+ desc := dist.BuildpackDescriptor{
+ Info: dist.BuildpackInfo{
+ ID: id,
+ Version: ver,
+ },
+ Stacks: bp.Stacks,
+ Order: bp.Order,
+ }
+ all = append(all, desc)
+ }
+ }
+ for _, bp := range additionalBuildpacks {
+ all = append(all, bp.Descriptor())
+ }
+ return all, nil
+}
+
+func (c *Client) processAppPath(appPath string) (string, error) {
+ var (
+ resolvedAppPath string
+ err error
+ )
+
+ if appPath == "" {
+ if appPath, err = os.Getwd(); err != nil {
+ return "", errors.Wrap(err, "get working dir")
+ }
+ }
+
+ if resolvedAppPath, err = filepath.EvalSymlinks(appPath); err != nil {
+ return "", errors.Wrap(err, "evaluate symlink")
+ }
+
+ if resolvedAppPath, err = filepath.Abs(resolvedAppPath); err != nil {
+ return "", errors.Wrap(err, "resolve absolute path")
+ }
+
+ fi, err := os.Stat(resolvedAppPath)
+ if err != nil {
+ return "", errors.Wrap(err, "stat file")
+ }
+
+ if !fi.IsDir() {
+ fh, err := os.Open(resolvedAppPath)
+ if err != nil {
+ return "", errors.Wrap(err, "read file")
+ }
+ defer fh.Close()
+
+ isZip, err := archive.IsZip(fh)
+ if err != nil {
+ return "", errors.Wrap(err, "check zip")
+ }
+
+ if !isZip {
+ return "", errors.New("app path must be a directory or zip")
+ }
+ }
+
+ return resolvedAppPath, nil
+}
+
+func (c *Client) processProxyConfig(config *ProxyConfig) ProxyConfig {
+ var (
+ httpProxy, httpsProxy, noProxy string
+ ok bool
+ )
+ if config != nil {
+ return *config
+ }
+ if httpProxy, ok = os.LookupEnv("HTTP_PROXY"); !ok {
+ httpProxy = os.Getenv("http_proxy")
+ }
+ if httpsProxy, ok = os.LookupEnv("HTTPS_PROXY"); !ok {
+ httpsProxy = os.Getenv("https_proxy")
+ }
+ if noProxy, ok = os.LookupEnv("NO_PROXY"); !ok {
+ noProxy = os.Getenv("no_proxy")
+ }
+ return ProxyConfig{
+ HTTPProxy: httpProxy,
+ HTTPSProxy: httpsProxy,
+ NoProxy: noProxy,
+ }
+}
+
+func (c *Client) processBuildpacks(ctx context.Context, buildpacks []string) ([]dist.Buildpack, dist.OrderEntry, error) {
+ group := dist.OrderEntry{Group: []dist.BuildpackRef{}}
+ var bps []dist.Buildpack
+ for _, bp := range buildpacks {
+ if isBuildpackID(bp) {
+ id, version := c.parseBuildpack(bp)
+ group.Group = append(group.Group, dist.BuildpackRef{
+ BuildpackInfo: dist.BuildpackInfo{
+ ID: id,
+ Version: version,
+ },
+ })
+ } else {
+ err := ensureBPSupport(bp)
+ if err != nil {
+ return nil, dist.OrderEntry{}, errors.Wrapf(err, "checking buildpack path")
+ }
+
+ blob, err := c.downloader.Download(ctx, bp)
+ if err != nil {
+ return nil, dist.OrderEntry{}, errors.Wrapf(err, "downloading buildpack from %s", style.Symbol(bp))
+ }
+
+ fetchedBP, err := dist.BuildpackFromRootBlob(blob)
+ if err != nil {
+ return nil, dist.OrderEntry{}, errors.Wrapf(err, "creating buildpack from %s", style.Symbol(bp))
+ }
+
+ bps = append(bps, fetchedBP)
+
+ group.Group = append(group.Group, dist.BuildpackRef{
+ BuildpackInfo: fetchedBP.Descriptor().Info,
+ })
+ }
+ }
+ return bps, group, nil
+}
+
+func isBuildpackID(bp string) bool {
+ if !paths.IsURI(bp) {
+ if _, err := os.Stat(bp); err != nil {
+ return true
+ }
+ }
+ return false
+}
+
+func ensureBPSupport(bpPath string) (err error) {
+ p := bpPath
+ if paths.IsURI(bpPath) {
+ var u *url.URL
+ u, err = url.Parse(bpPath)
+ if err != nil {
+ return err
+ }
+
+ if u.Scheme == "file" {
+ p, err = paths.URIToFilePath(bpPath)
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ if runtime.GOOS == "windows" && !paths.IsURI(p) {
+ isDir, err := paths.IsDir(p)
+ if err != nil {
+ return err
+ }
+
+ if isDir {
+ return fmt.Errorf("buildpack %s: directory-based buildpacks are not currently supported on Windows", style.Symbol(bpPath))
+ }
+ }
+
+ return nil
+}
+
+func (c *Client) parseBuildpack(bp string) (string, string) {
+ parts := strings.Split(bp, "@")
+ if len(parts) == 2 {
+ if parts[1] == "latest" {
+ c.logger.Warn("@latest syntax is deprecated, will not work in future releases")
+ return parts[0], ""
+ }
+
+ return parts[0], parts[1]
+ }
+
+ return parts[0], ""
+}
+
+func (c *Client) createEphemeralBuilder(rawBuilderImage imgutil.Image, env map[string]string, group dist.OrderEntry, buildpacks []dist.Buildpack) (*builder.Builder, error) {
+ origBuilderName := rawBuilderImage.Name()
+ bldr, err := builder.New(rawBuilderImage, fmt.Sprintf("pack.local/builder/%x:latest", randString(10)))
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid builder %s", style.Symbol(origBuilderName))
+ }
+
+ bldr.SetEnv(env)
+ for _, bp := range buildpacks {
+ bpInfo := bp.Descriptor().Info
+ c.logger.Debugf("Adding buildpack %s version %s to builder", style.Symbol(bpInfo.ID), style.Symbol(bpInfo.Version))
+ bldr.AddBuildpack(bp)
+ }
+ if len(group.Group) > 0 {
+ c.logger.Debug("Setting custom order")
+ bldr.SetOrder([]dist.OrderEntry{group})
+ }
+
+ if err := bldr.Save(c.logger); err != nil {
+ return nil, err
+ }
+ return bldr, nil
+}
+
+func randString(n int) string {
+ b := make([]byte, n)
+ for i := range b {
+ b[i] = 'a' + byte(rand.Intn(26))
+ }
+ return string(b)
+}
diff --git a/vendor/github.com/buildpacks/pack/builder/config.go b/vendor/github.com/buildpacks/pack/builder/config.go
new file mode 100644
index 00000000000..387e3a61199
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/builder/config.go
@@ -0,0 +1,136 @@
+package builder
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+
+ "github.com/BurntSushi/toml"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/paths"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type Config struct {
+ Description string `toml:"description"`
+ Buildpacks []BuildpackConfig `toml:"buildpacks"`
+ Packages []PackageConfig `toml:"packages"`
+ Order dist.Order `toml:"order"`
+ Stack StackConfig `toml:"stack"`
+ Lifecycle LifecycleConfig `toml:"lifecycle"`
+}
+
+type BuildpackConfig struct {
+ dist.BuildpackInfo
+ URI string `toml:"uri"`
+}
+
+type PackageConfig struct {
+ Image string `toml:"image"`
+}
+
+type StackConfig struct {
+ ID string `toml:"id"`
+ BuildImage string `toml:"build-image"`
+ RunImage string `toml:"run-image"`
+ RunImageMirrors []string `toml:"run-image-mirrors,omitempty"`
+}
+
+type LifecycleConfig struct {
+ URI string `toml:"uri"`
+ Version string `toml:"version"`
+}
+
+// ReadConfig reads a builder configuration from the file path provided and returns the
+// configuration along with any warnings encountered while parsing
+func ReadConfig(path string) (config Config, warnings []string, err error) {
+ builderDir, err := filepath.Abs(filepath.Dir(path))
+ if err != nil {
+ return Config{}, nil, err
+ }
+
+ file, err := os.Open(path)
+ if err != nil {
+ return Config{}, nil, errors.Wrap(err, "opening config file")
+ }
+ defer file.Close()
+
+ warnings, err = getWarningsForObsoleteFields(file)
+ if err != nil {
+ return Config{}, nil, errors.Wrapf(err, "check warnings for file '%s'", path)
+ }
+ if _, err := file.Seek(0, io.SeekStart); err != nil {
+ return Config{}, nil, errors.Wrap(err, "reset config file pointer")
+ }
+
+ config, err = parseConfig(file, builderDir)
+ if err != nil {
+ return Config{}, nil, errors.Wrapf(err, "parse contents of '%s'", path)
+ }
+
+ if len(config.Order) == 0 {
+ warnings = append(warnings, fmt.Sprintf("empty %s definition", style.Symbol("order")))
+ }
+
+ return config, warnings, nil
+}
+
+func getWarningsForObsoleteFields(reader io.Reader) ([]string, error) {
+ var warnings []string
+
+ var obsoleteConfig = struct {
+ Buildpacks []struct {
+ Latest bool
+ }
+ Groups []interface{}
+ }{}
+
+ if _, err := toml.DecodeReader(reader, &obsoleteConfig); err != nil {
+ return nil, err
+ }
+
+ latestUsed := false
+
+ for _, bp := range obsoleteConfig.Buildpacks {
+ latestUsed = bp.Latest
+ }
+
+ if latestUsed {
+ warnings = append(warnings, fmt.Sprintf("%s field on a buildpack is obsolete and will be ignored", style.Symbol("latest")))
+ }
+
+ if len(obsoleteConfig.Groups) > 0 {
+ warnings = append(warnings, fmt.Sprintf("%s field is obsolete in favor of %s", style.Symbol("groups"), style.Symbol("order")))
+ }
+
+ return warnings, nil
+}
+
+// parseConfig reads a builder configuration from reader and resolves relative buildpack paths using `relativeToDir`
+func parseConfig(reader io.Reader, relativeToDir string) (Config, error) {
+ var builderConfig Config
+ if _, err := toml.DecodeReader(reader, &builderConfig); err != nil {
+ return Config{}, errors.Wrap(err, "decoding toml contents")
+ }
+
+ for i, bp := range builderConfig.Buildpacks {
+ uri, err := paths.ToAbsolute(bp.URI, relativeToDir)
+ if err != nil {
+ return Config{}, errors.Wrap(err, "transforming buildpack URI")
+ }
+ builderConfig.Buildpacks[i].URI = uri
+ }
+
+ if builderConfig.Lifecycle.URI != "" {
+ uri, err := paths.ToAbsolute(builderConfig.Lifecycle.URI, relativeToDir)
+ if err != nil {
+ return Config{}, errors.Wrap(err, "transforming lifecycle URI")
+ }
+ builderConfig.Lifecycle.URI = uri
+ }
+
+ return builderConfig, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/client.go b/vendor/github.com/buildpacks/pack/client.go
new file mode 100644
index 00000000000..ad5ee068d4e
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/client.go
@@ -0,0 +1,131 @@
+package pack
+
+import (
+ "context"
+ "os"
+ "path/filepath"
+
+ "github.com/buildpacks/imgutil"
+ dockerClient "github.com/docker/docker/client"
+ "github.com/google/go-containerregistry/pkg/authn"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/blob"
+ "github.com/buildpacks/pack/internal/build"
+ "github.com/buildpacks/pack/internal/config"
+ "github.com/buildpacks/pack/internal/image"
+ "github.com/buildpacks/pack/logging"
+)
+
+//go:generate mockgen -package testmocks -destination testmocks/mock_image_fetcher.go github.com/buildpacks/pack ImageFetcher
+type ImageFetcher interface {
+ // Fetch fetches an image by resolving it both remotely and locally depending on provided parameters.
+ // If daemon is true, it will look return a `local.Image`. Pull, applicable only when daemon is true, will
+ // attempt to pull a remote image first.
+ Fetch(ctx context.Context, name string, daemon, pull bool) (imgutil.Image, error)
+}
+
+//go:generate mockgen -package testmocks -destination testmocks/mock_downloader.go github.com/buildpacks/pack Downloader
+type Downloader interface {
+ Download(ctx context.Context, pathOrURI string) (blob.Blob, error)
+}
+
+//go:generate mockgen -package testmocks -destination testmocks/mock_image_factory.go github.com/buildpacks/pack ImageFactory
+type ImageFactory interface {
+ NewImage(repoName string, local bool) (imgutil.Image, error)
+}
+
+type Client struct {
+ logger logging.Logger
+ imageFetcher ImageFetcher
+ downloader Downloader
+ lifecycle Lifecycle
+ docker *dockerClient.Client
+ imageFactory ImageFactory
+}
+
+type ClientOption func(c *Client)
+
+// WithLogger supply your own logger.
+func WithLogger(l logging.Logger) ClientOption {
+ return func(c *Client) {
+ c.logger = l
+ }
+}
+
+// WithImageFactory supply your own image factory.
+func WithImageFactory(f ImageFactory) ClientOption {
+ return func(c *Client) {
+ c.imageFactory = f
+ }
+}
+
+// WithFetcher supply your own fetcher.
+func WithFetcher(f ImageFetcher) ClientOption {
+ return func(c *Client) {
+ c.imageFetcher = f
+ }
+}
+
+// WithDownloader supply your own downloader.
+func WithDownloader(d Downloader) ClientOption {
+ return func(c *Client) {
+ c.downloader = d
+ }
+}
+
+// WithCacheDir supply your own cache directory.
+//
+// Deprecated: use WithDownloader instead.
+func WithCacheDir(path string) ClientOption {
+ return func(c *Client) {
+ c.downloader = blob.NewDownloader(c.logger, path)
+ }
+}
+
+// WithDockerClient supply your own docker client.
+func WithDockerClient(docker *dockerClient.Client) ClientOption {
+ return func(c *Client) {
+ c.docker = docker
+ }
+}
+
+func NewClient(opts ...ClientOption) (*Client, error) {
+ var client Client
+
+ for _, opt := range opts {
+ opt(&client)
+ }
+
+ if client.logger == nil {
+ client.logger = logging.New(os.Stderr)
+ }
+
+ if client.docker == nil {
+ var err error
+ client.docker, err = dockerClient.NewClientWithOpts(dockerClient.FromEnv, dockerClient.WithVersion("1.38"))
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if client.downloader == nil {
+ packHome, err := config.PackHome()
+ if err != nil {
+ return nil, errors.Wrap(err, "getting pack home")
+ }
+ client.downloader = blob.NewDownloader(client.logger, filepath.Join(packHome, "download-cache"))
+ }
+
+ if client.imageFetcher == nil {
+ client.imageFetcher = image.NewFetcher(client.logger, client.docker)
+ }
+
+ if client.imageFactory == nil {
+ client.imageFactory = image.NewFactory(client.docker, authn.DefaultKeychain)
+ }
+
+ client.lifecycle = build.NewLifecycle(client.docker, client.logger)
+
+ return &client, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/cmd/cmd.go b/vendor/github.com/buildpacks/pack/cmd/cmd.go
new file mode 100644
index 00000000000..3a347a3cf9f
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/cmd/cmd.go
@@ -0,0 +1,6 @@
+package cmd
+
+var (
+ // Version is the version of `pack`. It is injected at compile time.
+ Version = "0.0.0"
+)
diff --git a/vendor/github.com/buildpacks/pack/common.go b/vendor/github.com/buildpacks/pack/common.go
new file mode 100644
index 00000000000..8a477d2a67e
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/common.go
@@ -0,0 +1,77 @@
+package pack
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/google/go-containerregistry/pkg/name"
+
+ "github.com/buildpacks/pack/internal/builder"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+func (c *Client) parseTagReference(imageName string) (name.Reference, error) {
+ if imageName == "" {
+ return nil, errors.New("image is a required parameter")
+ }
+ if _, err := name.ParseReference(imageName, name.WeakValidation); err != nil {
+ return nil, err
+ }
+ ref, err := name.NewTag(imageName, name.WeakValidation)
+ if err != nil {
+ return nil, fmt.Errorf("'%s' is not a tag reference", imageName)
+ }
+
+ return ref, nil
+}
+
+func (c *Client) resolveRunImage(runImage, targetRegistry string, stackInfo builder.StackMetadata, additionalMirrors map[string][]string) string {
+ if runImage != "" {
+ c.logger.Debugf("Using provided run-image %s", style.Symbol(runImage))
+ return runImage
+ }
+ runImageName := getBestRunMirror(
+ targetRegistry,
+ stackInfo.RunImage.Image,
+ stackInfo.RunImage.Mirrors,
+ additionalMirrors[stackInfo.RunImage.Image],
+ )
+
+ switch {
+ case runImageName == stackInfo.RunImage.Image:
+ c.logger.Debugf("Selected run image %s", style.Symbol(runImageName))
+ case contains(stackInfo.RunImage.Mirrors, runImageName):
+ c.logger.Debugf("Selected run image mirror %s", style.Symbol(runImageName))
+ default:
+ c.logger.Debugf("Selected run image mirror %s from local config", style.Symbol(runImageName))
+ }
+ return runImageName
+}
+
+func contains(slc []string, v string) bool {
+ for _, s := range slc {
+ if s == v {
+ return true
+ }
+ }
+ return false
+}
+
+func getBestRunMirror(registry string, runImage string, mirrors []string, preferredMirrors []string) string {
+ runImageList := append(preferredMirrors, append([]string{runImage}, mirrors...)...)
+ for _, img := range runImageList {
+ ref, err := name.ParseReference(img, name.WeakValidation)
+ if err != nil {
+ continue
+ }
+ if ref.Context().RegistryStr() == registry {
+ return img
+ }
+ }
+
+ if len(preferredMirrors) > 0 {
+ return preferredMirrors[0]
+ }
+
+ return runImage
+}
diff --git a/vendor/github.com/buildpacks/pack/create_builder.go b/vendor/github.com/buildpacks/pack/create_builder.go
new file mode 100644
index 00000000000..41b2e3458ad
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/create_builder.go
@@ -0,0 +1,226 @@
+package pack
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/Masterminds/semver"
+ "github.com/buildpacks/imgutil"
+ "github.com/pkg/errors"
+
+ pubbldr "github.com/buildpacks/pack/builder"
+ "github.com/buildpacks/pack/internal/builder"
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/image"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type CreateBuilderOptions struct {
+ BuilderName string
+ Config pubbldr.Config
+ Publish bool
+ NoPull bool
+}
+
+func (c *Client) CreateBuilder(ctx context.Context, opts CreateBuilderOptions) error {
+ if err := validateBuilderConfig(opts.Config); err != nil {
+ return errors.Wrap(err, "invalid builder config")
+ }
+
+ if err := c.validateRunImageConfig(ctx, opts); err != nil {
+ return err
+ }
+
+ baseImage, err := c.imageFetcher.Fetch(ctx, opts.Config.Stack.BuildImage, !opts.Publish, !opts.NoPull)
+ if err != nil {
+ return errors.Wrap(err, "fetch build image")
+ }
+
+ c.logger.Debugf("Creating builder %s from build-image %s", style.Symbol(opts.BuilderName), style.Symbol(baseImage.Name()))
+ bldr, err := builder.New(baseImage, opts.BuilderName)
+ if err != nil {
+ return errors.Wrap(err, "invalid build-image")
+ }
+
+ bldr.SetDescription(opts.Config.Description)
+
+ if bldr.StackID != opts.Config.Stack.ID {
+ return fmt.Errorf(
+ "stack %s from builder config is incompatible with stack %s from build image",
+ style.Symbol(opts.Config.Stack.ID),
+ style.Symbol(bldr.StackID),
+ )
+ }
+
+ lifecycle, err := c.fetchLifecycle(ctx, opts.Config.Lifecycle)
+ if err != nil {
+ return errors.Wrap(err, "fetch lifecycle")
+ }
+
+ if err := bldr.SetLifecycle(lifecycle); err != nil {
+ return errors.Wrap(err, "setting lifecycle")
+ }
+
+ for _, b := range opts.Config.Buildpacks {
+ err := ensureBPSupport(b.URI)
+ if err != nil {
+ return err
+ }
+
+ blob, err := c.downloader.Download(ctx, b.URI)
+ if err != nil {
+ return errors.Wrapf(err, "downloading buildpack from %s", style.Symbol(b.URI))
+ }
+
+ fetchedBp, err := dist.BuildpackFromRootBlob(blob)
+ if err != nil {
+ return errors.Wrapf(err, "creating buildpack from %s", style.Symbol(b.URI))
+ }
+
+ err = validateBuildpack(fetchedBp, b.URI, b.ID, b.Version)
+ if err != nil {
+ return errors.Wrap(err, "invalid buildpack")
+ }
+
+ bldr.AddBuildpack(fetchedBp)
+ }
+
+ for _, pkg := range opts.Config.Packages {
+ bps, err := extractPackagedBuildpacks(ctx, pkg.Image, c.imageFetcher, opts.Publish, opts.NoPull)
+ if err != nil {
+ return err
+ }
+
+ for _, bp := range bps {
+ bldr.AddBuildpack(bp)
+ }
+ }
+
+ bldr.SetOrder(opts.Config.Order)
+ bldr.SetStack(opts.Config.Stack)
+
+ return bldr.Save(c.logger)
+}
+
+func validateBuildpack(bp dist.Buildpack, source, expectedID, expectedBPVersion string) error {
+ if expectedID != "" && bp.Descriptor().Info.ID != expectedID {
+ return fmt.Errorf(
+ "buildpack from URI %s has ID %s which does not match ID %s from builder config",
+ style.Symbol(source),
+ style.Symbol(bp.Descriptor().Info.ID),
+ style.Symbol(expectedID),
+ )
+ }
+
+ if expectedBPVersion != "" && bp.Descriptor().Info.Version != expectedBPVersion {
+ return fmt.Errorf(
+ "buildpack from URI %s has version %s which does not match version %s from builder config",
+ style.Symbol(source),
+ style.Symbol(bp.Descriptor().Info.Version),
+ style.Symbol(expectedBPVersion),
+ )
+ }
+
+ return nil
+}
+
+func (c *Client) fetchLifecycle(ctx context.Context, config pubbldr.LifecycleConfig) (builder.Lifecycle, error) {
+ if config.Version != "" && config.URI != "" {
+ return nil, errors.Errorf(
+ "%s can only declare %s or %s, not both",
+ style.Symbol("lifecycle"), style.Symbol("version"), style.Symbol("uri"),
+ )
+ }
+
+ var uri string
+ switch {
+ case config.Version != "":
+ v, err := semver.NewVersion(config.Version)
+ if err != nil {
+ return nil, errors.Wrapf(err, "%s must be a valid semver", style.Symbol("lifecycle.version"))
+ }
+
+ uri = uriFromLifecycleVersion(*v)
+ case config.URI != "":
+ uri = config.URI
+ default:
+ uri = uriFromLifecycleVersion(*semver.MustParse(builder.DefaultLifecycleVersion))
+ }
+
+ b, err := c.downloader.Download(ctx, uri)
+ if err != nil {
+ return nil, errors.Wrap(err, "downloading lifecycle")
+ }
+
+ lifecycle, err := builder.NewLifecycle(b)
+ if err != nil {
+ return nil, errors.Wrap(err, "invalid lifecycle")
+ }
+
+ return lifecycle, nil
+}
+
+func uriFromLifecycleVersion(version semver.Version) string {
+ return fmt.Sprintf("https://github.com/buildpacks/lifecycle/releases/download/v%s/lifecycle-v%s+linux.x86-64.tgz", version.String(), version.String())
+}
+
+func validateBuilderConfig(conf pubbldr.Config) error {
+ if conf.Stack.ID == "" {
+ return errors.New("stack.id is required")
+ }
+
+ if conf.Stack.BuildImage == "" {
+ return errors.New("stack.build-image is required")
+ }
+
+ if conf.Stack.RunImage == "" {
+ return errors.New("stack.run-image is required")
+ }
+
+ return nil
+}
+
+func (c *Client) validateRunImageConfig(ctx context.Context, opts CreateBuilderOptions) error {
+ var runImages []imgutil.Image
+ for _, i := range append([]string{opts.Config.Stack.RunImage}, opts.Config.Stack.RunImageMirrors...) {
+ if !opts.Publish {
+ img, err := c.imageFetcher.Fetch(ctx, i, true, false)
+ if err != nil {
+ if errors.Cause(err) != image.ErrNotFound {
+ return err
+ }
+ } else {
+ runImages = append(runImages, img)
+ continue
+ }
+ }
+
+ img, err := c.imageFetcher.Fetch(ctx, i, false, false)
+ if err != nil {
+ if errors.Cause(err) != image.ErrNotFound {
+ return err
+ }
+ c.logger.Warnf("run image %s is not accessible", style.Symbol(i))
+ } else {
+ runImages = append(runImages, img)
+ }
+ }
+
+ for _, img := range runImages {
+ stackID, err := img.Label("io.buildpacks.stack.id")
+ if err != nil {
+ return err
+ }
+
+ if stackID != opts.Config.Stack.ID {
+ return fmt.Errorf(
+ "stack %s from builder config is incompatible with stack %s from run image %s",
+ style.Symbol(opts.Config.Stack.ID),
+ style.Symbol(stackID),
+ style.Symbol(img.Name()),
+ )
+ }
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/pack/create_buildpackage.go b/vendor/github.com/buildpacks/pack/create_buildpackage.go
new file mode 100644
index 00000000000..d16c24fb97e
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/create_buildpackage.go
@@ -0,0 +1,71 @@
+package pack
+
+import (
+ "context"
+
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/buildpackage"
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type CreatePackageOptions struct {
+ Name string
+ Config buildpackage.Config
+ Publish bool
+ NoPull bool
+}
+
+func (c *Client) CreatePackage(ctx context.Context, opts CreatePackageOptions) error {
+ packageBuilder := buildpackage.NewBuilder(c.imageFactory)
+
+ bpURI := opts.Config.Buildpack.URI
+ if bpURI == "" {
+ return errors.New("buildpack URI must be provided")
+ }
+
+ blob, err := c.downloader.Download(ctx, bpURI)
+ if err != nil {
+ return errors.Wrapf(err, "downloading buildpack from %s", style.Symbol(bpURI))
+ }
+
+ bp, err := dist.BuildpackFromRootBlob(blob)
+ if err != nil {
+ return errors.Wrapf(err, "creating buildpack from %s", style.Symbol(bpURI))
+ }
+
+ packageBuilder.SetBuildpack(bp)
+
+ for _, dep := range opts.Config.Dependencies {
+ if dep.URI != "" {
+ blob, err := c.downloader.Download(ctx, dep.URI)
+ if err != nil {
+ return errors.Wrapf(err, "downloading buildpack from %s", style.Symbol(dep.URI))
+ }
+
+ depBP, err := dist.BuildpackFromRootBlob(blob)
+ if err != nil {
+ return errors.Wrapf(err, "creating buildpack from %s", style.Symbol(dep.URI))
+ }
+
+ packageBuilder.AddDependency(depBP)
+ } else if dep.ImageName != "" {
+ bps, err := extractPackagedBuildpacks(ctx, dep.ImageName, c.imageFetcher, opts.Publish, opts.NoPull)
+ if err != nil {
+ return err
+ }
+
+ for _, depBP := range bps {
+ packageBuilder.AddDependency(depBP)
+ }
+ }
+ }
+
+ _, err = packageBuilder.Save(opts.Name, opts.Publish)
+ if err != nil {
+ return errors.Wrapf(err, "saving image")
+ }
+
+ return err
+}
diff --git a/vendor/github.com/buildpacks/pack/go.mod b/vendor/github.com/buildpacks/pack/go.mod
new file mode 100644
index 00000000000..ea14c860339
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/go.mod
@@ -0,0 +1,23 @@
+module github.com/buildpacks/pack
+
+require (
+ github.com/BurntSushi/toml v0.3.1
+ github.com/Masterminds/semver v1.4.2
+ github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012
+ github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b
+ github.com/buildpacks/lifecycle v0.5.1-0.20191217221752-3b74c943b7b3
+ github.com/dgodd/dockerdial v1.0.1
+ github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7
+ github.com/docker/go-connections v0.4.0
+ github.com/golang/mock v1.3.1
+ github.com/google/go-cmp v0.3.0
+ github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af
+ github.com/heroku/color v0.0.6
+ github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e
+ github.com/onsi/gomega v1.7.0
+ github.com/pkg/errors v0.8.1
+ github.com/sclevine/spec v1.4.0
+ github.com/spf13/cobra v0.0.5
+)
+
+go 1.13
diff --git a/vendor/github.com/buildpacks/pack/go.sum b/vendor/github.com/buildpacks/pack/go.sum
new file mode 100644
index 00000000000..4b745f3203d
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/go.sum
@@ -0,0 +1,273 @@
+cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
+github.com/Azure/azure-sdk-for-go v19.1.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
+github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
+github.com/Azure/go-autorest v10.15.5+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
+github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
+github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
+github.com/Masterminds/semver v1.4.2 h1:WBLTQ37jOCzSLtXNdoo8bNM8876KhNqOKvrlGITgsTc=
+github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
+github.com/Microsoft/go-winio v0.4.11/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA=
+github.com/Microsoft/go-winio v0.4.14 h1:+hMXMk01us9KgxGb7ftKQt2Xpf5hH/yky+TDA+qxleU=
+github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
+github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
+github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012 h1:r9k3B0K539tmbDOdyCIuz/6qtn8q+lp+qvEStcFUIdM=
+github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012/go.mod h1:Ls949n1HFtXfbDcjiTTFQqkVUrte0puoIBfO3SVgwOA=
+github.com/aphistic/golf v0.0.0-20180712155816-02c07f170c5a/go.mod h1:3NqKYiepwy8kCu4PNA+aP7WUV72eXWJeP9/r3/K9aLE=
+github.com/aphistic/sweet v0.2.0/go.mod h1:fWDlIh/isSE9n6EPsRmC0det+whmX6dJid3stzu0Xys=
+github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
+github.com/aws/aws-sdk-go v1.15.90/go.mod h1:es1KtYUFs7le0xQ3rOihkuoVD90z7D0fR2Qm4S00/gU=
+github.com/aws/aws-sdk-go v1.20.6/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
+github.com/aybabtme/rgbterm v0.0.0-20170906152045-cc83f3b3ce59/go.mod h1:q/89r3U2H7sSsE2t6Kca0lfwTK8JdoNGS/yzM/4iH5I=
+github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b h1:SDsB0hJtURA+5i5vIjLntzRNPEqdoz6q+0MShCWdctw=
+github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b/go.mod h1:E3lXJcNXcRefJQAHW5rqboonet+jtOml4qImbJhYGAo=
+github.com/buildpacks/lifecycle v0.5.1-0.20191217221752-3b74c943b7b3 h1:15zYyFmNbrtx5MmyVEKVgY2/eearqEqGJXLCjmvUo58=
+github.com/buildpacks/lifecycle v0.5.1-0.20191217221752-3b74c943b7b3/go.mod h1:ZIuIs9B6tjAW4dthhltKVyEUlhRfFWWix9eqoInMGX4=
+github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/containerd/containerd v1.3.0 h1:xjvXQWABwS2uiv3TWgQt5Uth60Gu86LTGZXMJkjc7rY=
+github.com/containerd/containerd v1.3.0/go.mod h1:bC6axHOhabU15QhwfG7w5PipXdVtMXFTttgp+kVtyUA=
+github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
+github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
+github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
+github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/dgodd/dockerdial v1.0.1 h1:6XixGQxeytsIdVsbI4y+EHuv8QcxxH6ySJZLkm3jk5o=
+github.com/dgodd/dockerdial v1.0.1/go.mod h1:MJmK56eTylC3KU7DR6bc3k9jmbpURO8rDOsGbfj+c6o=
+github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017 h1:2HQmlpI3yI9deH18Q6xiSOIjXD4sLI55Y/gfpa8/558=
+github.com/docker/cli v0.0.0-20191017083524-a8ff7f821017/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
+github.com/docker/distribution v0.0.0-20180327202408-83389a148052/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.6.0-rc.1.0.20180327202408-83389a148052+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BUmsJpcB+cRlLU7cSug=
+github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
+github.com/docker/docker v0.7.3-0.20181027010111-b8e87cfdad8d/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7 h1:Cvj7S8I4Xpx78KAl6TwTmMHuHlZ/0SM60NUneGJQ7IE=
+github.com/docker/docker v1.4.2-0.20190924003213-a8608b5b67c7/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
+github.com/docker/docker-credential-helpers v0.6.3 h1:zI2p9+1NQYdnG6sMU26EX4aVGlqbInSQxQXLvzJ4RPQ=
+github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
+github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
+github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
+github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
+github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
+github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
+github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
+github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
+github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
+github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/gogo/protobuf v1.2.1 h1:/s5zKNz0uPFCZ5hddgPdo2TK2TVrUNMn0OOX8/aZMTE=
+github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
+github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
+github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E=
+github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
+github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s=
+github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
+github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs=
+github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
+github.com/google/btree v0.0.0-20180124185431-e89373fe6b4a/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
+github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
+github.com/google/go-cmp v0.3.0 h1:crn/baboCvb5fXaQ0IJ1SGTsTVrWpDsCWC8EGETZijY=
+github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
+github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af h1:gCcst+zXdvatJYFDtPd3C3VNEGcoFOOMwFydnFIfnF0=
+github.com/google/go-containerregistry v0.0.0-20191018211754-b77a90c667af/go.mod h1:9kIomAeXUmwhqeYS2zoEuQ0sc2GOVmNW7t3y9aNQL1o=
+github.com/google/gofuzz v0.0.0-20170612174753-24818f796faf/go.mod h1:HP5RmnzzSNb993RKQDq4+1A4ia9nllfqcQFTQJedwGI=
+github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
+github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
+github.com/googleapis/gnostic v0.2.2/go.mod h1:sJBsCZ4ayReDTBIg8b9dl28c5xFWyhBTVRp3pOg5EKY=
+github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
+github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw=
+github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
+github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
+github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d h1:kJCB4vdITiW1eC1vq2e6IsrXKrZit1bv/TDYFGMp4BQ=
+github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM=
+github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0=
+github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi1wLU=
+github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
+github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
+github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
+github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
+github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
+github.com/jpillora/backoff v0.0.0-20180909062703-3050d21c67d7/go.mod h1:2iMrUgbbvHEiQClaW2NsSzMyGHqN+rDFqY705q49KG0=
+github.com/json-iterator/go v0.0.0-20180701071628-ab8a2e0c74be/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
+github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
+github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s=
+github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
+github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
+github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
+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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
+github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-colorable v0.1.4 h1:snbPLB8fVfU9iwbbo30TPtbLRzwWu6aJS6Xh4eaaviA=
+github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-isatty v0.0.5/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 h1:qxFzApOv4WsAL965uUPIsXzAKCZxN2p9UqdhFS4ZW10=
+github.com/mattn/go-isatty v0.0.10/go.mod h1:qgIWMr58cqv1PHHyhnkY9lrL7etaEgOFcMEpPG5Rm84=
+github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
+github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
+github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e h1:Qa6dnn8DlasdXRnacluu8HzPts0S1I9zvvUPDbBnXFI=
+github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e/go.mod h1:waEya8ee1Ro/lgxpVhkJI4BVASzkm3UZqkx/cFJiYHM=
+github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
+github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
+github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
+github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
+github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
+github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/ginkgo v1.10.1 h1:q/mM8GF/n0shIN8SaAZ0V+jnLPzen6WIVZdiwrRlMlo=
+github.com/onsi/ginkgo v1.10.1/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
+github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
+github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
+github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ=
+github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s=
+github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI=
+github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
+github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
+github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
+github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I=
+github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
+github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
+github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
+github.com/sclevine/spec v1.0.0/go.mod h1:W4J29eT/Kzv7/b9IWLB055Z+qvVC9vt0Arko24q7p+U=
+github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8=
+github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM=
+github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
+github.com/sirupsen/logrus v1.1.1/go.mod h1:zrgwTnHtNr00buQ1vSptGe8m1f/BbgsPukg8qsT7A+A=
+github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
+github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4=
+github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
+github.com/smartystreets/assertions v1.0.0/go.mod h1:kHHU4qYBaI3q23Pp3VPrmWhuIUrLW/7eUrw0BU5VaoM=
+github.com/smartystreets/go-aws-auth v0.0.0-20180515143844-0c1422d1fdb9/go.mod h1:SnhjPscd9TpLiy1LpzGSKh3bXCfxxXuqd9xmQJy3slM=
+github.com/smartystreets/gunit v1.0.0/go.mod h1:qwPWnhz6pn0NnRBP++URONOVyNkPyr4SauJk4cUOwJs=
+github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
+github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
+github.com/spf13/cobra v0.0.5 h1:f0B+LkLX6DtmRH1isoNA9VTtNUK9K8xYd28JNNfOv/s=
+github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU=
+github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
+github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
+github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
+github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
+github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk=
+github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
+github.com/tj/assert v0.0.0-20171129193455-018094318fb0/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
+github.com/tj/go-elastic v0.0.0-20171221160941-36157cbbebc2/go.mod h1:WjeM0Oo1eNAjXGDx2yma7uG2XoyRZTq1uv3M/o7imD0=
+github.com/tj/go-kinesis v0.0.0-20171128231115-08b17f58cb1b/go.mod h1:/yhzCV0xPfx6jb1bBgRFjl5lytqVqZXEaeqWP8lTEao=
+github.com/tj/go-spin v1.1.0/go.mod h1:Mg1mzmePZm4dva8Qz60H2lHwmJ2loum4VIrLgVnKwh4=
+github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
+github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
+golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20190426145343-a29dc8fdc734/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
+golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
+golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
+golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
+golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
+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=
+golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
+golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80 h1:Ao/3l156eZf2AW5wK8a7/smtodRU+gha3+BeqJ69lRk=
+golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
+golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181025063200-d989b31c8746/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/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 h1:/XfQ9z7ib8eEJX2hdgFTZJ/ntt0swNk5oYBziWeTCvY=
+golang.org/x/sys v0.0.0-20191010194322-b09406accb47/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs=
+golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
+golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ=
+golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
+golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
+golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
+golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
+golang.org/x/tools v0.0.0-20191017205301-920acffc3e65/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
+google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
+google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
+google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8 h1:x913Lq/RebkvUmRSdQ8MNb0GZKn+SR1ESfoetcQSeak=
+google.golang.org/genproto v0.0.0-20190508193815-b515fa19cec8/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
+google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio=
+google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
+google.golang.org/grpc v1.24.0 h1:vb/1TCsVn3DcJlQ0Gs1yB1pKI6Do2/QNwxdKqmc/b0s=
+google.golang.org/grpc v1.24.0/go.mod h1:XDChyiUovWa60DnaeDeZmSW86xtLtjtZbwvSiRnRtcA=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY=
+gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
+gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
+gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
+gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
+gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
+gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
+gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
+gotest.tools v2.1.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo=
+gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw=
+honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
+k8s.io/api v0.0.0-20180904230853-4e7be11eab3f/go.mod h1:iuAfoD4hCxJ8Onx9kaTIt30j7jUFS00AXQi6QMi99vA=
+k8s.io/apimachinery v0.0.0-20180904193909-def12e63c512/go.mod h1:ccL7Eh7zubPUSh9A3USN90/OzHNSVN6zxzde07TDCL0=
+k8s.io/client-go v0.0.0-20180910083459-2cefa64ff137/go.mod h1:7vJpHMYJwNQCWgzmNV+VYUl1zCObLyodBc8nIyt8L5s=
+k8s.io/kube-openapi v0.0.0-20180731170545-e3762e86a74c/go.mod h1:BXM9ceUBTj2QnfH2MK1odQs778ajze1RxcmP6S8RVVc=
+k8s.io/kubernetes v1.11.10/go.mod h1:ocZa8+6APFNC2tX1DZASIbocyYT5jHzqFVsY5aoB7Jk=
diff --git a/vendor/github.com/buildpacks/pack/golangci.yaml b/vendor/github.com/buildpacks/pack/golangci.yaml
new file mode 100644
index 00000000000..22e69ce5df6
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/golangci.yaml
@@ -0,0 +1,32 @@
+run:
+ timeout: 6m
+ modules-download-mode: vendor
+
+linters:
+ disable-all: true
+ enable:
+ - bodyclose
+ - deadcode
+ - dogsled
+ - gocritic
+ - goimports
+ - golint
+ - gosimple
+ - govet
+ - ineffassign
+ - maligned
+ - misspell
+ - nakedret
+ - scopelint
+ - staticcheck
+ - structcheck
+ - stylecheck
+ - typecheck
+ - unconvert
+ - unused
+ - varcheck
+ - whitespace
+
+linters-settings:
+ goimports:
+ local-prefixes: github.com/buildpacks/pack
\ No newline at end of file
diff --git a/vendor/github.com/buildpacks/pack/inspect_builder.go b/vendor/github.com/buildpacks/pack/inspect_builder.go
new file mode 100644
index 00000000000..ba228e2064c
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/inspect_builder.go
@@ -0,0 +1,67 @@
+package pack
+
+import (
+ "context"
+ "strings"
+
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/builder"
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/image"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type BuilderInfo struct {
+ Description string
+ Stack string
+ Mixins []string
+ RunImage string
+ RunImageMirrors []string
+ Buildpacks []builder.BuildpackMetadata
+ Order dist.Order
+ Lifecycle builder.LifecycleDescriptor
+ CreatedBy builder.CreatorMetadata
+}
+
+type BuildpackInfo struct {
+ ID string
+ Version string
+}
+
+func (c *Client) InspectBuilder(name string, daemon bool) (*BuilderInfo, error) {
+ img, err := c.imageFetcher.Fetch(context.Background(), name, daemon, false)
+ if err != nil {
+ if errors.Cause(err) == image.ErrNotFound {
+ return nil, nil
+ }
+ return nil, err
+ }
+
+ bldr, err := builder.FromImage(img)
+ if err != nil {
+ return nil, errors.Wrapf(err, "invalid builder %s", style.Symbol(name))
+ }
+
+ var commonMixins, buildMixins []string
+ commonMixins = []string{}
+ for _, mixin := range bldr.Mixins() {
+ if strings.HasPrefix(mixin, "build:") {
+ buildMixins = append(buildMixins, mixin)
+ } else {
+ commonMixins = append(commonMixins, mixin)
+ }
+ }
+
+ return &BuilderInfo{
+ Description: bldr.Description(),
+ Stack: bldr.StackID,
+ Mixins: append(commonMixins, buildMixins...),
+ RunImage: bldr.Stack().RunImage.Image,
+ RunImageMirrors: bldr.Stack().RunImage.Mirrors,
+ Buildpacks: bldr.Buildpacks(),
+ Order: bldr.Order(),
+ Lifecycle: bldr.LifecycleDescriptor(),
+ CreatedBy: bldr.CreatedBy(),
+ }, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/inspect_image.go b/vendor/github.com/buildpacks/pack/inspect_image.go
new file mode 100644
index 00000000000..20db4d1f064
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/inspect_image.go
@@ -0,0 +1,88 @@
+package pack
+
+import (
+ "context"
+
+ "github.com/Masterminds/semver"
+ "github.com/buildpacks/lifecycle"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/image"
+)
+
+type ImageInfo struct {
+ StackID string
+ Buildpacks []lifecycle.Buildpack
+ Base lifecycle.RunImageMetadata
+ BOM []lifecycle.BOMEntry
+ Stack lifecycle.StackMetadata
+ Processes ProcessDetails
+}
+
+type ProcessDetails struct {
+ DefaultProcess *lifecycle.Process
+ OtherProcesses []lifecycle.Process
+}
+
+// Deserialize just the subset of fields we need to avoid breaking changes
+type layersMetadata struct {
+ RunImage lifecycle.RunImageMetadata `json:"runImage" toml:"run-image"`
+ Stack lifecycle.StackMetadata `json:"stack" toml:"stack"`
+}
+
+func (c *Client) InspectImage(name string, daemon bool) (*ImageInfo, error) {
+ img, err := c.imageFetcher.Fetch(context.Background(), name, daemon, false)
+ if err != nil {
+ if errors.Cause(err) == image.ErrNotFound {
+ return nil, nil
+ }
+ return nil, err
+ }
+
+ var layersMd layersMetadata
+ if _, err := dist.GetLabel(img, lifecycle.LayerMetadataLabel, &layersMd); err != nil {
+ return nil, err
+ }
+
+ var buildMD lifecycle.BuildMetadata
+ if _, err := dist.GetLabel(img, lifecycle.BuildMetadataLabel, &buildMD); err != nil {
+ return nil, err
+ }
+
+ minimumBaseImageReferenceVersion := semver.MustParse("0.5.0")
+ actualLauncherVersion, err := semver.NewVersion(buildMD.Launcher.Version)
+
+ if err == nil && actualLauncherVersion.LessThan(minimumBaseImageReferenceVersion) {
+ layersMd.RunImage.Reference = ""
+ }
+
+ stackID, err := img.Label(lifecycle.StackIDLabel)
+ if err != nil {
+ return nil, err
+ }
+
+ defaultProcessType, err := img.Env("CNB_PROCESS_TYPE")
+ if err != nil || defaultProcessType == "" {
+ defaultProcessType = "web"
+ }
+
+ var processDetails ProcessDetails
+ for _, proc := range buildMD.Processes {
+ proc := proc
+ if proc.Type == defaultProcessType {
+ processDetails.DefaultProcess = &proc
+ continue
+ }
+ processDetails.OtherProcesses = append(processDetails.OtherProcesses, proc)
+ }
+
+ return &ImageInfo{
+ StackID: stackID,
+ Stack: layersMd.Stack,
+ Base: layersMd.RunImage,
+ BOM: buildMD.BOM,
+ Buildpacks: buildMD.Buildpacks,
+ Processes: processDetails,
+ }, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/api/version.go b/vendor/github.com/buildpacks/pack/internal/api/version.go
new file mode 100644
index 00000000000..eaafafa9e79
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/api/version.go
@@ -0,0 +1,121 @@
+package api
+
+import (
+ "fmt"
+ "regexp"
+ "strconv"
+
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/style"
+)
+
+var regex = regexp.MustCompile(`^v?(\d+)\.(\d*)$`)
+
+type Version struct {
+ major,
+ minor uint64
+}
+
+func MustParse(v string) *Version {
+ version, err := NewVersion(v)
+ if err != nil {
+ panic(err)
+ }
+
+ return version
+}
+
+func NewVersion(v string) (*Version, error) {
+ matches := regex.FindAllStringSubmatch(v, -1)
+ if len(matches) == 0 {
+ return nil, errors.Errorf("could not parse %s as version", style.Symbol(v))
+ }
+
+ var (
+ major, minor uint64
+ err error
+ )
+ if len(matches[0]) == 3 {
+ major, err = strconv.ParseUint(matches[0][1], 10, 64)
+ if err != nil {
+ return nil, errors.Wrapf(err, "parsing major %s", style.Symbol(matches[0][1]))
+ }
+
+ minor, err = strconv.ParseUint(matches[0][2], 10, 64)
+ if err != nil {
+ return nil, errors.Wrapf(err, "parsing minor %s", style.Symbol(matches[0][2]))
+ }
+ } else {
+ return nil, errors.Errorf("could not parse version %s", style.Symbol(v))
+ }
+
+ return &Version{major: major, minor: minor}, nil
+}
+
+func (v *Version) String() string {
+ return fmt.Sprintf("%d.%d", v.major, v.minor)
+}
+
+// MarshalText makes Version satisfy the encoding.TextMarshaler interface.
+func (v *Version) MarshalText() ([]byte, error) {
+ return []byte(v.String()), nil
+}
+
+// UnmarshalText makes Version satisfy the encoding.TextUnmarshaler interface.
+func (v *Version) UnmarshalText(text []byte) error {
+ s := string(text)
+
+ parsedVersion, err := NewVersion(s)
+ if err != nil {
+ return errors.Wrapf(err, "invalid api version %s", s)
+ }
+
+ v.major = parsedVersion.major
+ v.minor = parsedVersion.minor
+
+ return nil
+}
+
+// SupportsVersion determines whether this version supports a given version. If comparing two pre-stable (major == 0)
+// versions, minors must match exactly. Otherwise, this minor must be greater than or equal to the given minor. Majors
+// must always match.
+func (v *Version) SupportsVersion(o *Version) bool {
+ if v.Equal(o) {
+ return true
+ }
+
+ if v.major != 0 {
+ return v.major == o.major && v.minor >= o.minor
+ }
+
+ return false
+}
+
+func (v *Version) Equal(o *Version) bool {
+ return v.Compare(o) == 0
+}
+
+func (v *Version) Compare(o *Version) int {
+ if v.major != o.major {
+ if v.major < o.major {
+ return -1
+ }
+
+ if v.major > o.major {
+ return 1
+ }
+ }
+
+ if v.minor != o.minor {
+ if v.minor < o.minor {
+ return -1
+ }
+
+ if v.minor > o.minor {
+ return 1
+ }
+ }
+
+ return 0
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/app/image.go b/vendor/github.com/buildpacks/pack/internal/app/image.go
new file mode 100644
index 00000000000..787beeac086
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/app/image.go
@@ -0,0 +1,8 @@
+package app
+
+import "github.com/buildpacks/pack/logging"
+
+type Image struct {
+ RepoName string
+ Logger logging.Logger
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/app/run.go b/vendor/github.com/buildpacks/pack/internal/app/run.go
new file mode 100644
index 00000000000..03b4453cf45
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/app/run.go
@@ -0,0 +1,104 @@
+package app
+
+import (
+ "context"
+ "fmt"
+ "strconv"
+ "strings"
+
+ "github.com/docker/docker/api/types"
+ dcontainer "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/client"
+ "github.com/docker/go-connections/nat"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/container"
+ "github.com/buildpacks/pack/logging"
+)
+
+func (i *Image) Run(ctx context.Context, docker *client.Client, ports []string) error {
+ if ports == nil {
+ var err error
+ ports, err = exposedPorts(ctx, docker, i.RepoName)
+ if err != nil {
+ return err
+ }
+ }
+
+ parsedPorts, portBindings, err := parsePorts(ports)
+ if err != nil {
+ return err
+ }
+
+ ctr, err := docker.ContainerCreate(ctx, &dcontainer.Config{
+ Image: i.RepoName,
+ AttachStdout: true,
+ AttachStderr: true,
+ ExposedPorts: parsedPorts,
+ Labels: map[string]string{"author": "pack"},
+ }, &dcontainer.HostConfig{
+ AutoRemove: true,
+ PortBindings: portBindings,
+ }, nil, "")
+ if err != nil {
+ return err
+ }
+ defer docker.ContainerRemove(context.Background(), ctr.ID, types.ContainerRemoveOptions{Force: true})
+
+ logContainerListening(i.Logger, portBindings)
+ if err = container.Run(
+ ctx,
+ docker,
+ ctr.ID,
+ logging.GetInfoWriter(i.Logger),
+ logging.GetInfoErrorWriter(i.Logger),
+ ); err != nil {
+ return errors.Wrap(err, "run container")
+ }
+
+ return nil
+}
+
+func exposedPorts(ctx context.Context, docker *client.Client, imageID string) ([]string, error) {
+ i, _, err := docker.ImageInspectWithRaw(ctx, imageID)
+ if err != nil {
+ return nil, err
+ }
+ var ports []string
+ for port := range i.Config.ExposedPorts {
+ ports = append(ports, port.Port())
+ }
+ return ports, nil
+}
+
+func parsePorts(ports []string) (nat.PortSet, nat.PortMap, error) {
+ for i, p := range ports {
+ p = strings.TrimSpace(p)
+ if _, err := strconv.Atoi(p); err == nil {
+ // default simple port to localhost and inside the container
+ p = fmt.Sprintf("127.0.0.1:%s:%s/tcp", p, p)
+ }
+ ports[i] = p
+ }
+
+ return nat.ParsePortSpecs(ports)
+}
+
+func logContainerListening(logger logging.Logger, portBindings nat.PortMap) {
+ // TODO handle case with multiple ports, for now when there is more than
+ // one port we assume you know what you're doing and don't need guidance
+ if len(portBindings) == 1 {
+ for _, bindings := range portBindings {
+ if len(bindings) == 1 {
+ binding := bindings[0]
+ host := binding.HostIP
+ port := binding.HostPort
+ if host == "127.0.0.1" {
+ host = "localhost"
+ }
+ // TODO the service may not be http based
+ logger.Infof("Starting container listening at http://%s:%s/\n", host, port)
+ }
+ }
+ }
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/archive/archive.go b/vendor/github.com/buildpacks/pack/internal/archive/archive.go
new file mode 100644
index 00000000000..c040590fedf
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/archive/archive.go
@@ -0,0 +1,311 @@
+package archive
+
+import (
+ "archive/tar"
+ "archive/zip"
+ "bytes"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "time"
+
+ "github.com/docker/docker/pkg/ioutils"
+ "github.com/pkg/errors"
+)
+
+var NormalizedDateTime time.Time
+
+func init() {
+ NormalizedDateTime = time.Date(1980, time.January, 1, 0, 0, 1, 0, time.UTC)
+}
+
+func ReadDirAsTar(srcDir, basePath string, uid, gid int, mode int64) io.ReadCloser {
+ return GenerateTar(func(tw *tar.Writer) error {
+ return WriteDirToTar(tw, srcDir, basePath, uid, gid, mode)
+ })
+}
+
+func ReadZipAsTar(srcPath, basePath string, uid, gid int, mode int64) io.ReadCloser {
+ return GenerateTar(func(tw *tar.Writer) error {
+ return WriteZipToTar(tw, srcPath, basePath, uid, gid, mode)
+ })
+}
+
+// GenerateTar returns a reader to a tar from a generator function. Note that the
+// generator will not fully execute until the reader is fully read from. Any errors
+// returned by the generator will be returned when reading the reader.
+func GenerateTar(gen func(*tar.Writer) error) io.ReadCloser {
+ errChan := make(chan error)
+ pr, pw := io.Pipe()
+
+ go func() {
+ tw := tar.NewWriter(pw)
+ defer func() {
+ if r := recover(); r != nil {
+ tw.Close()
+ pw.CloseWithError(errors.Errorf("panic: %v", r))
+ }
+ }()
+
+ err := gen(tw)
+
+ closeErr := tw.Close()
+ closeErr = aggregateError(closeErr, pw.CloseWithError(err))
+
+ errChan <- closeErr
+ }()
+
+ return ioutils.NewReadCloserWrapper(pr, func() error {
+ var completeErr error
+
+ // closing the reader ensures that if anything attempts
+ // further reading it doesn't block waiting for content
+ if err := pr.Close(); err != nil {
+ completeErr = aggregateError(completeErr, err)
+ }
+
+ // wait until everything closes properly
+ if err := <-errChan; err != nil {
+ completeErr = aggregateError(completeErr, err)
+ }
+
+ return completeErr
+ })
+}
+
+func aggregateError(base, addition error) error {
+ if addition == nil {
+ return base
+ }
+
+ if base == nil {
+ return addition
+ }
+
+ return errors.Wrap(addition, base.Error())
+}
+
+func CreateSingleFileTarReader(path, txt string) (io.Reader, error) {
+ var buf bytes.Buffer
+ tarBuilder := TarBuilder{}
+ tarBuilder.AddFile(path, 0644, NormalizedDateTime, []byte(txt))
+ _, err := tarBuilder.WriteTo(&buf)
+ if err != nil {
+ return nil, err
+ }
+
+ return bytes.NewReader(buf.Bytes()), nil
+}
+
+func CreateSingleFileTar(tarFile, path, txt string) error {
+ tarBuilder := TarBuilder{}
+ tarBuilder.AddFile(path, 0644, NormalizedDateTime, []byte(txt))
+ return tarBuilder.WriteToPath(tarFile)
+}
+
+func AddFileToTar(tw *tar.Writer, path string, txt string) error {
+ if err := tw.WriteHeader(&tar.Header{
+ Name: path,
+ Size: int64(len(txt)),
+ Mode: 0644,
+ ModTime: NormalizedDateTime,
+ }); err != nil {
+ return err
+ }
+ if _, err := tw.Write([]byte(txt)); err != nil {
+ return err
+ }
+ return nil
+}
+
+var ErrEntryNotExist = errors.New("not exist")
+
+func ReadTarEntry(rc io.Reader, entryPath string) (*tar.Header, []byte, error) {
+ tr := tar.NewReader(rc)
+ for {
+ header, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return nil, nil, errors.Wrap(err, "failed to get next tar entry")
+ }
+
+ if path.Clean(header.Name) == entryPath {
+ buf, err := ioutil.ReadAll(tr)
+ if err != nil {
+ return nil, nil, errors.Wrapf(err, "failed to read contents of '%s'", entryPath)
+ }
+
+ return header, buf, nil
+ }
+ }
+
+ return nil, nil, errors.Wrapf(ErrEntryNotExist, "could not find entry path '%s'", entryPath)
+}
+
+func WriteDirToTar(tw *tar.Writer, srcDir, basePath string, uid, gid int, mode int64) error {
+ return filepath.Walk(srcDir, func(file string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+
+ if fi.Mode()&os.ModeSocket != 0 {
+ return nil
+ }
+
+ var header *tar.Header
+ if fi.Mode()&os.ModeSymlink != 0 {
+ target, err := os.Readlink(file)
+ if err != nil {
+ return err
+ }
+
+ header, err = tar.FileInfoHeader(fi, target)
+ if err != nil {
+ return err
+ }
+ } else {
+ header, err = tar.FileInfoHeader(fi, fi.Name())
+ if err != nil {
+ return err
+ }
+ }
+
+ relPath, err := filepath.Rel(srcDir, file)
+ if err != nil {
+ return err
+ } else if relPath == "." {
+ return nil
+ }
+
+ header.Name = filepath.ToSlash(filepath.Join(basePath, relPath))
+ finalizeHeader(header, uid, gid, mode)
+
+ if err := tw.WriteHeader(header); err != nil {
+ return err
+ }
+
+ if fi.Mode().IsRegular() {
+ f, err := os.Open(file)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+
+ if _, err := io.Copy(tw, f); err != nil {
+ return err
+ }
+ }
+
+ return nil
+ })
+}
+
+func WriteZipToTar(tw *tar.Writer, srcZip, basePath string, uid, gid int, mode int64) error {
+ zipReader, err := zip.OpenReader(srcZip)
+ if err != nil {
+ return err
+ }
+ defer zipReader.Close()
+
+ for _, f := range zipReader.File {
+ var header *tar.Header
+ if f.Mode()&os.ModeSymlink != 0 {
+ target, err := func() (string, error) {
+ r, err := f.Open()
+ if err != nil {
+ return "", nil
+ }
+ defer r.Close()
+
+ // contents is the target of the symlink
+ target, err := ioutil.ReadAll(r)
+ if err != nil {
+ return "", err
+ }
+
+ return string(target), nil
+ }()
+
+ if err != nil {
+ return err
+ }
+
+ header, err = tar.FileInfoHeader(f.FileInfo(), target)
+ if err != nil {
+ return err
+ }
+ } else {
+ header, err = tar.FileInfoHeader(f.FileInfo(), f.Name)
+ if err != nil {
+ return err
+ }
+ }
+
+ header.Name = filepath.ToSlash(filepath.Join(basePath, f.Name))
+ finalizeHeader(header, uid, gid, mode)
+
+ if err := tw.WriteHeader(header); err != nil {
+ return err
+ }
+
+ if f.Mode().IsRegular() {
+ err := func() error {
+ fi, err := f.Open()
+ if err != nil {
+ return err
+ }
+ defer fi.Close()
+
+ _, err = io.Copy(tw, fi)
+ return err
+ }()
+
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ return nil
+}
+
+func finalizeHeader(header *tar.Header, uid, gid int, mode int64) {
+ NormalizeHeader(header)
+ if mode != -1 {
+ header.Mode = mode
+ }
+ header.Uid = uid
+ header.Gid = gid
+}
+
+// NormalizeHeader normalizes a tar.Header
+//
+// Normalizes the following:
+// - ModTime
+// - GID
+// - UID
+// - User Name
+// - Group Name
+func NormalizeHeader(header *tar.Header) {
+ header.ModTime = NormalizedDateTime
+ header.Uid = 0
+ header.Gid = 0
+ header.Uname = ""
+ header.Gname = ""
+}
+
+func IsZip(file io.Reader) (bool, error) {
+ b := make([]byte, 4)
+ _, err := file.Read(b)
+ if err != nil && err != io.EOF {
+ return false, err
+ } else if err == io.EOF {
+ return false, nil
+ }
+
+ return bytes.Equal(b, []byte("\x50\x4B\x03\x04")), nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/archive/tar_builder.go b/vendor/github.com/buildpacks/pack/internal/archive/tar_builder.go
new file mode 100644
index 00000000000..a2bfd96237e
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/archive/tar_builder.go
@@ -0,0 +1,94 @@
+package archive
+
+import (
+ "archive/tar"
+ "io"
+ "os"
+ "time"
+
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type TarBuilder struct {
+ files []fileEntry
+}
+
+type fileEntry struct {
+ typeFlag byte
+ path string
+ mode int64
+ modTime time.Time
+ contents []byte
+}
+
+func (t *TarBuilder) AddFile(path string, mode int64, modTime time.Time, contents []byte) {
+ t.files = append(t.files, fileEntry{
+ typeFlag: tar.TypeReg,
+ path: path,
+ mode: mode,
+ modTime: modTime,
+ contents: contents,
+ })
+}
+
+func (t *TarBuilder) AddDir(path string, mode int64, modTime time.Time) {
+ t.files = append(t.files, fileEntry{
+ typeFlag: tar.TypeDir,
+ path: path,
+ mode: mode,
+ modTime: modTime,
+ })
+}
+
+func (t *TarBuilder) Reader() io.ReadCloser {
+ pr, pw := io.Pipe()
+ go func() {
+ var err error
+ defer func() {
+ pw.CloseWithError(err)
+ }()
+ _, err = t.WriteTo(pw)
+ }()
+
+ return pr
+}
+
+func (t *TarBuilder) WriteToPath(path string) error {
+ fh, err := os.Create(path)
+ if err != nil {
+ return errors.Wrapf(err, "create file for tar: %s", style.Symbol(path))
+ }
+ defer fh.Close()
+
+ _, err = t.WriteTo(fh)
+ return err
+}
+
+func (t *TarBuilder) WriteTo(writer io.Writer) (int64, error) {
+ tw := tar.NewWriter(writer)
+ defer tw.Close()
+
+ var written int64
+ for _, f := range t.files {
+ if err := tw.WriteHeader(&tar.Header{
+ Typeflag: f.typeFlag,
+ Name: f.path,
+ Size: int64(len(f.contents)),
+ Mode: f.mode,
+ ModTime: f.modTime,
+ }); err != nil {
+ return written, err
+ }
+
+ n, err := tw.Write(f.contents)
+ if err != nil {
+ return written, err
+ }
+
+ written += int64(n)
+ }
+
+ return written, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/blob/blob.go b/vendor/github.com/buildpacks/pack/internal/blob/blob.go
new file mode 100644
index 00000000000..80c407ecae2
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/blob/blob.go
@@ -0,0 +1,80 @@
+package blob
+
+import (
+ "bytes"
+ "compress/gzip"
+ "io"
+ "os"
+
+ "github.com/docker/docker/pkg/ioutils"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/archive"
+)
+
+type Blob interface {
+ Open() (io.ReadCloser, error)
+}
+
+type blob struct {
+ path string
+}
+
+func NewBlob(path string) Blob {
+ return &blob{path: path}
+}
+
+// Open returns an io.ReadCloser whose contents are in tar archive format
+func (b blob) Open() (r io.ReadCloser, err error) {
+ fi, err := os.Stat(b.path)
+ if err != nil {
+ return nil, errors.Wrapf(err, "read blob at path '%s'", b.path)
+ }
+ if fi.IsDir() {
+ return archive.ReadDirAsTar(b.path, ".", 0, 0, -1), nil
+ }
+
+ fh, err := os.Open(b.path)
+ if err != nil {
+ return nil, errors.Wrap(err, "open buildpack archive")
+ }
+ defer func() {
+ if err != nil {
+ fh.Close()
+ }
+ }()
+
+ if ok, err := isGZip(fh); err != nil {
+ return nil, errors.Wrap(err, "check header")
+ } else if !ok {
+ return fh, nil
+ }
+ gzr, err := gzip.NewReader(fh)
+ if err != nil {
+ return nil, errors.Wrap(err, "create gzip reader")
+ }
+
+ rc := ioutils.NewReadCloserWrapper(gzr, func() error {
+ defer fh.Close()
+ return gzr.Close()
+ })
+
+ return rc, nil
+}
+
+func isGZip(file io.ReadSeeker) (bool, error) {
+ b := make([]byte, 3)
+ if _, err := file.Seek(0, 0); err != nil {
+ return false, err
+ }
+ _, err := file.Read(b)
+ if err != nil && err != io.EOF {
+ return false, err
+ } else if err == io.EOF {
+ return false, nil
+ }
+ if _, err := file.Seek(0, 0); err != nil {
+ return false, err
+ }
+ return bytes.Equal(b, []byte("\x1f\x8b\x08")), nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/blob/downloader.go b/vendor/github.com/buildpacks/pack/internal/blob/downloader.go
new file mode 100644
index 00000000000..30b97724943
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/blob/downloader.go
@@ -0,0 +1,187 @@
+package blob
+
+import (
+ "context"
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "net/url"
+ "os"
+ "path/filepath"
+
+ "github.com/mitchellh/ioprogress"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/paths"
+ "github.com/buildpacks/pack/internal/style"
+ "github.com/buildpacks/pack/logging"
+)
+
+const (
+ cacheDirPrefix = "c"
+ cacheVersion = "2"
+)
+
+type downloader struct {
+ logger logging.Logger
+ baseCacheDir string
+}
+
+func NewDownloader(logger logging.Logger, baseCacheDir string) *downloader { //nolint:golint,gosimple
+ return &downloader{
+ logger: logger,
+ baseCacheDir: baseCacheDir,
+ }
+}
+
+func (d *downloader) Download(ctx context.Context, pathOrURI string) (Blob, error) {
+ if paths.IsURI(pathOrURI) {
+ parsedURL, err := url.Parse(pathOrURI)
+ if err != nil {
+ return nil, errors.Wrapf(err, "parsing path/uri %s", style.Symbol(pathOrURI))
+ }
+
+ var path string
+ switch parsedURL.Scheme {
+ case "file":
+ path, err = paths.URIToFilePath(pathOrURI)
+ case "http", "https":
+ path, err = d.handleHTTP(ctx, pathOrURI)
+ default:
+ err = fmt.Errorf("unsupported protocol %s in URI %s", style.Symbol(parsedURL.Scheme), style.Symbol(pathOrURI))
+ }
+ if err != nil {
+ return nil, err
+ }
+
+ return &blob{path: path}, nil
+ }
+
+ path := d.handleFile(pathOrURI)
+
+ return &blob{path: path}, nil
+}
+
+func (d *downloader) handleFile(path string) string {
+ path, err := filepath.Abs(path)
+ if err != nil {
+ return ""
+ }
+
+ return path
+}
+
+func (d *downloader) handleHTTP(ctx context.Context, uri string) (string, error) {
+ cacheDir := d.versionedCacheDir()
+
+ if err := os.MkdirAll(cacheDir, 0755); err != nil {
+ return "", err
+ }
+
+ cachePath := filepath.Join(cacheDir, fmt.Sprintf("%x", sha256.Sum256([]byte(uri))))
+
+ etagFile := cachePath + ".etag"
+ etagExists, err := fileExists(etagFile)
+ if err != nil {
+ return "", err
+ }
+
+ etag := ""
+ if etagExists {
+ bytes, err := ioutil.ReadFile(etagFile)
+ if err != nil {
+ return "", err
+ }
+ etag = string(bytes)
+ }
+
+ reader, etag, err := d.downloadAsStream(ctx, uri, etag)
+ if err != nil {
+ return "", err
+ } else if reader == nil {
+ return cachePath, nil
+ }
+ defer reader.Close()
+
+ fh, err := os.Create(cachePath)
+ if err != nil {
+ return "", errors.Wrapf(err, "create cache path %s", style.Symbol(cachePath))
+ }
+ defer fh.Close()
+
+ _, err = io.Copy(fh, reader)
+ if err != nil {
+ return "", errors.Wrap(err, "writing cache")
+ }
+
+ if err = ioutil.WriteFile(etagFile, []byte(etag), 0744); err != nil {
+ return "", errors.Wrap(err, "writing etag")
+ }
+
+ return cachePath, nil
+}
+
+func (d *downloader) downloadAsStream(ctx context.Context, uri string, etag string) (io.ReadCloser, string, error) {
+ req, err := http.NewRequest("GET", uri, nil)
+ if err != nil {
+ return nil, "", err
+ }
+ req = req.WithContext(ctx)
+
+ if etag != "" {
+ req.Header.Set("If-None-Match", etag)
+ }
+
+ resp, err := (&http.Client{}).Do(req) //nolint:bodyclose
+ if err != nil {
+ return nil, "", err
+ }
+
+ if resp.StatusCode >= 200 && resp.StatusCode < 300 {
+ d.logger.Infof("Downloading from %s", style.Symbol(uri))
+ return withProgress(logging.GetInfoWriter(d.logger), resp.Body, resp.ContentLength), resp.Header.Get("Etag"), nil
+ }
+
+ if resp.StatusCode == 304 {
+ d.logger.Debugf("Using cached version of %s", style.Symbol(uri))
+ return nil, etag, nil
+ }
+
+ return nil, "", fmt.Errorf(
+ "could not download from %s, code http status %s",
+ style.Symbol(uri), style.Symbol("%d", resp.StatusCode),
+ )
+}
+
+func withProgress(writer io.Writer, rc io.ReadCloser, length int64) io.ReadCloser {
+ return &progressReader{
+ Closer: rc,
+ Reader: &ioprogress.Reader{
+ Reader: rc,
+ Size: length,
+ DrawFunc: ioprogress.DrawTerminalf(writer, ioprogress.DrawTextFormatBytes),
+ },
+ }
+}
+
+type progressReader struct {
+ *ioprogress.Reader
+ io.Closer
+}
+
+func (d *downloader) versionedCacheDir() string {
+ return filepath.Join(d.baseCacheDir, cacheDirPrefix+cacheVersion)
+}
+
+func fileExists(file string) (bool, error) {
+ _, err := os.Stat(file)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return false, nil
+ }
+ return false, err
+ }
+ return true, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/build/build.go b/vendor/github.com/buildpacks/pack/internal/build/build.go
new file mode 100644
index 00000000000..713b0c8f559
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/build/build.go
@@ -0,0 +1,167 @@
+package build
+
+import (
+ "context"
+ "math/rand"
+ "sync"
+ "time"
+
+ "github.com/docker/docker/client"
+ "github.com/google/go-containerregistry/pkg/name"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/api"
+ "github.com/buildpacks/pack/internal/builder"
+ "github.com/buildpacks/pack/internal/cache"
+ "github.com/buildpacks/pack/internal/style"
+ "github.com/buildpacks/pack/logging"
+)
+
+var (
+ // SupportedPlatformAPIVersions lists the Platform API versions pack supports.
+ SupportedPlatformAPIVersions = []string{"0.1", "0.2"}
+)
+
+type Lifecycle struct {
+ builder *builder.Builder
+ logger logging.Logger
+ docker *client.Client
+ appPath string
+ appOnce *sync.Once
+ httpProxy string
+ httpsProxy string
+ noProxy string
+ version string
+ platformAPIVersion string
+ LayersVolume string
+ AppVolume string
+}
+
+type Cache interface {
+ Name() string
+ Clear(context.Context) error
+}
+
+func init() {
+ rand.Seed(time.Now().UTC().UnixNano())
+}
+
+func NewLifecycle(docker *client.Client, logger logging.Logger) *Lifecycle {
+ return &Lifecycle{logger: logger, docker: docker}
+}
+
+type LifecycleOptions struct {
+ AppPath string
+ Image name.Reference
+ Builder *builder.Builder
+ RunImage string
+ ClearCache bool
+ Publish bool
+ HTTPProxy string
+ HTTPSProxy string
+ NoProxy string
+ Network string
+}
+
+// CombinedExporterCacher returns true if the lifecycle contains combined exporter/cacher phases and reversed analyzer/restorer phases.
+func (l *Lifecycle) CombinedExporterCacher() bool {
+ return api.MustParse(l.platformAPIVersion).Compare(api.MustParse("0.2")) >= 0
+}
+
+func (l *Lifecycle) Execute(ctx context.Context, opts LifecycleOptions) error {
+ l.Setup(opts)
+ defer l.Cleanup()
+
+ buildCache := cache.NewVolumeCache(opts.Image, "build", l.docker)
+ launchCache := cache.NewVolumeCache(opts.Image, "launch", l.docker)
+ l.logger.Debugf("Using build cache volume %s", style.Symbol(buildCache.Name()))
+
+ if opts.ClearCache {
+ if err := buildCache.Clear(ctx); err != nil {
+ return errors.Wrap(err, "clearing build cache")
+ }
+ l.logger.Debugf("Build cache %s cleared", style.Symbol(buildCache.Name()))
+ }
+
+ l.logger.Info(style.Step("DETECTING"))
+ if err := l.Detect(ctx, opts.Network); err != nil {
+ return err
+ }
+
+ if l.CombinedExporterCacher() {
+ l.logger.Info(style.Step("ANALYZING"))
+ if err := l.Analyze(ctx, opts.Image.Name(), buildCache.Name(), opts.Publish, opts.ClearCache); err != nil {
+ return err
+ }
+
+ l.logger.Info(style.Step("RESTORING"))
+ if opts.ClearCache {
+ l.logger.Info("Skipping 'restore' due to clearing cache")
+ } else if err := l.Restore(ctx, buildCache.Name()); err != nil {
+ return err
+ }
+ } else {
+ l.logger.Info(style.Step("RESTORING"))
+ if opts.ClearCache {
+ l.logger.Info("Skipping 'restore' due to clearing cache")
+ } else if err := l.Restore(ctx, buildCache.Name()); err != nil {
+ return err
+ }
+
+ l.logger.Info(style.Step("ANALYZING"))
+ if err := l.Analyze(ctx, opts.Image.Name(), buildCache.Name(), opts.Publish, opts.ClearCache); err != nil {
+ return err
+ }
+ }
+
+ l.logger.Info(style.Step("BUILDING"))
+ if err := l.Build(ctx, opts.Network); err != nil {
+ return err
+ }
+
+ l.logger.Info(style.Step("EXPORTING"))
+ if err := l.Export(ctx, opts.Image.Name(), opts.RunImage, opts.Publish, launchCache.Name(), buildCache.Name()); err != nil {
+ return err
+ }
+
+ if !l.CombinedExporterCacher() {
+ l.logger.Info(style.Step("CACHING"))
+ if err := l.Cache(ctx, buildCache.Name()); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (l *Lifecycle) Setup(opts LifecycleOptions) {
+ l.LayersVolume = "pack-layers-" + randString(10)
+ l.AppVolume = "pack-app-" + randString(10)
+ l.appPath = opts.AppPath
+ l.appOnce = &sync.Once{}
+ l.builder = opts.Builder
+ l.httpProxy = opts.HTTPProxy
+ l.httpsProxy = opts.HTTPSProxy
+ l.noProxy = opts.NoProxy
+ l.version = opts.Builder.LifecycleDescriptor().Info.Version.String()
+ l.platformAPIVersion = opts.Builder.LifecycleDescriptor().API.PlatformVersion.String()
+}
+
+func (l *Lifecycle) Cleanup() error {
+ var reterr error
+ if err := l.docker.VolumeRemove(context.Background(), l.LayersVolume, true); err != nil {
+ reterr = errors.Wrapf(err, "failed to clean up layers volume %s", l.LayersVolume)
+ }
+ if err := l.docker.VolumeRemove(context.Background(), l.AppVolume, true); err != nil {
+ reterr = errors.Wrapf(err, "failed to clean up app volume %s", l.AppVolume)
+ }
+ return reterr
+}
+
+func randString(n int) string {
+ b := make([]byte, n)
+ for i := range b {
+ b[i] = 'a' + byte(rand.Intn(26))
+ }
+ return string(b)
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/build/phase.go b/vendor/github.com/buildpacks/pack/internal/build/phase.go
new file mode 100644
index 00000000000..54b22d55783
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/build/phase.go
@@ -0,0 +1,200 @@
+package build
+
+import (
+ "context"
+ "fmt"
+ "io"
+ "os"
+ "runtime"
+ "sync"
+
+ "github.com/buildpacks/lifecycle/auth"
+ "github.com/docker/docker/api/types"
+ dcontainer "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/client"
+ "github.com/google/go-containerregistry/pkg/authn"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/archive"
+ "github.com/buildpacks/pack/internal/container"
+ "github.com/buildpacks/pack/logging"
+)
+
+type Phase struct {
+ name string
+ logger logging.Logger
+ docker *client.Client
+ ctrConf *dcontainer.Config
+ hostConf *dcontainer.HostConfig
+ ctr dcontainer.ContainerCreateCreatedBody
+ uid, gid int
+ appPath string
+ appOnce *sync.Once
+}
+
+func (l *Lifecycle) NewPhase(name string, ops ...func(*Phase) (*Phase, error)) (*Phase, error) {
+ ctrConf := &dcontainer.Config{
+ Image: l.builder.Name(),
+ Labels: map[string]string{"author": "pack"},
+ }
+ hostConf := &dcontainer.HostConfig{
+ Binds: []string{
+ fmt.Sprintf("%s:%s", l.LayersVolume, layersDir),
+ fmt.Sprintf("%s:%s", l.AppVolume, appDir),
+ },
+ }
+ ctrConf.Cmd = []string{"/lifecycle/" + name}
+ phase := &Phase{
+ ctrConf: ctrConf,
+ hostConf: hostConf,
+ name: name,
+ docker: l.docker,
+ logger: l.logger,
+ uid: l.builder.UID,
+ gid: l.builder.GID,
+ appPath: l.appPath,
+ appOnce: l.appOnce,
+ }
+
+ if l.httpProxy != "" {
+ phase.ctrConf.Env = append(phase.ctrConf.Env, "HTTP_PROXY="+l.httpProxy)
+ phase.ctrConf.Env = append(phase.ctrConf.Env, "http_proxy="+l.httpProxy)
+ }
+ if l.httpsProxy != "" {
+ phase.ctrConf.Env = append(phase.ctrConf.Env, "HTTPS_PROXY="+l.httpsProxy)
+ phase.ctrConf.Env = append(phase.ctrConf.Env, "https_proxy="+l.httpsProxy)
+ }
+ if l.noProxy != "" {
+ phase.ctrConf.Env = append(phase.ctrConf.Env, "NO_PROXY="+l.noProxy)
+ phase.ctrConf.Env = append(phase.ctrConf.Env, "no_proxy="+l.noProxy)
+ }
+
+ var err error
+ for _, op := range ops {
+ phase, err = op(phase)
+ if err != nil {
+ return nil, errors.Wrapf(err, "create %s phase", name)
+ }
+ }
+ return phase, nil
+}
+
+func WithArgs(args ...string) func(*Phase) (*Phase, error) {
+ return func(phase *Phase) (*Phase, error) {
+ phase.ctrConf.Cmd = append(phase.ctrConf.Cmd, args...)
+ return phase, nil
+ }
+}
+
+func WithDaemonAccess() func(*Phase) (*Phase, error) {
+ return func(phase *Phase) (*Phase, error) {
+ phase.ctrConf.User = "root"
+ phase.hostConf.Binds = append(phase.hostConf.Binds, "/var/run/docker.sock:/var/run/docker.sock")
+ return phase, nil
+ }
+}
+
+func WithRoot() func(*Phase) (*Phase, error) {
+ return func(phase *Phase) (*Phase, error) {
+ phase.ctrConf.User = "root"
+ return phase, nil
+ }
+}
+
+func WithBinds(binds ...string) func(*Phase) (*Phase, error) {
+ return func(phase *Phase) (*Phase, error) {
+ phase.hostConf.Binds = append(phase.hostConf.Binds, binds...)
+ return phase, nil
+ }
+}
+
+func WithRegistryAccess(repos ...string) func(*Phase) (*Phase, error) {
+ return func(phase *Phase) (*Phase, error) {
+ authConfig, err := auth.BuildEnvVar(authn.DefaultKeychain, repos...)
+ if err != nil {
+ return nil, err
+ }
+ phase.ctrConf.Env = append(phase.ctrConf.Env, fmt.Sprintf(`CNB_REGISTRY_AUTH=%s`, authConfig))
+ phase.hostConf.NetworkMode = "host"
+ return phase, nil
+ }
+}
+
+func WithNetwork(networkMode string) func(*Phase) (*Phase, error) {
+ return func(phase *Phase) (*Phase, error) {
+ phase.hostConf.NetworkMode = dcontainer.NetworkMode(networkMode)
+ return phase, nil
+ }
+}
+
+func (p *Phase) Run(ctx context.Context) error {
+ var err error
+
+ p.ctr, err = p.docker.ContainerCreate(ctx, p.ctrConf, p.hostConf, nil, "")
+ if err != nil {
+ return errors.Wrapf(err, "failed to create '%s' container", p.name)
+ }
+
+ p.appOnce.Do(func() {
+ var (
+ appReader io.ReadCloser
+ clientErr error
+ )
+ appReader, err = p.createAppReader()
+ if err != nil {
+ err = errors.Wrapf(err, "create tar archive from '%s'", p.appPath)
+ return
+ }
+ defer appReader.Close()
+
+ doneChan := make(chan interface{})
+ pr, pw := io.Pipe()
+ go func() {
+ clientErr = p.docker.CopyToContainer(ctx, p.ctr.ID, "/", pr, types.CopyToContainerOptions{})
+ close(doneChan)
+ }()
+ func() {
+ defer pw.Close()
+ _, err = io.Copy(pw, appReader)
+ }()
+
+ <-doneChan
+ if err == nil {
+ err = clientErr
+ }
+ })
+
+ if err != nil {
+ return errors.Wrapf(err, "failed to copy files to '%s' container", p.name)
+ }
+
+ return container.Run(
+ ctx,
+ p.docker,
+ p.ctr.ID,
+ logging.NewPrefixWriter(logging.GetInfoWriter(p.logger), p.name),
+ logging.NewPrefixWriter(logging.GetInfoErrorWriter(p.logger), p.name),
+ )
+}
+
+func (p *Phase) Cleanup() error {
+ return p.docker.ContainerRemove(context.Background(), p.ctr.ID, types.ContainerRemoveOptions{Force: true})
+}
+
+func (p *Phase) createAppReader() (io.ReadCloser, error) {
+ fi, err := os.Stat(p.appPath)
+ if err != nil {
+ return nil, err
+ }
+
+ if fi.IsDir() {
+ var mode int64 = -1
+ if runtime.GOOS == "windows" {
+ mode = 0777
+ }
+
+ return archive.ReadDirAsTar(p.appPath, appDir, p.uid, p.gid, mode), nil
+ }
+
+ return archive.ReadZipAsTar(p.appPath, appDir, p.uid, p.gid, -1), nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/build/phases.go b/vendor/github.com/buildpacks/pack/internal/build/phases.go
new file mode 100644
index 00000000000..41936caa211
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/build/phases.go
@@ -0,0 +1,201 @@
+package build
+
+import (
+ "context"
+ "fmt"
+
+ "github.com/Masterminds/semver"
+)
+
+const (
+ layersDir = "/layers"
+ appDir = "/workspace"
+ cacheDir = "/cache"
+ launchCacheDir = "/launch-cache"
+ platformDir = "/platform"
+)
+
+func (l *Lifecycle) Detect(ctx context.Context, networkMode string) error {
+ detect, err := l.NewPhase(
+ "detector",
+ WithArgs(
+ l.withLogLevel(
+ "-app", appDir,
+ "-platform", platformDir,
+ )...,
+ ),
+ WithNetwork(networkMode),
+ )
+ if err != nil {
+ return err
+ }
+ defer detect.Cleanup()
+ return detect.Run(ctx)
+}
+
+func (l *Lifecycle) Restore(ctx context.Context, cacheName string) error {
+ cacheFlag := "-path"
+ if l.CombinedExporterCacher() {
+ cacheFlag = "-cache-dir"
+ }
+
+ restore, err := l.NewPhase(
+ "restorer",
+ WithDaemonAccess(),
+ WithArgs(
+ l.withLogLevel(
+ cacheFlag, cacheDir,
+ "-layers", layersDir,
+ )...,
+ ),
+ WithBinds(fmt.Sprintf("%s:%s", cacheName, cacheDir)),
+ )
+ if err != nil {
+ return err
+ }
+ defer restore.Cleanup()
+ return restore.Run(ctx)
+}
+
+func (l *Lifecycle) Analyze(ctx context.Context, repoName, cacheName string, publish, clearCache bool) error {
+ analyze, err := l.newAnalyze(repoName, cacheName, publish, clearCache)
+ if err != nil {
+ return err
+ }
+ defer analyze.Cleanup()
+ return analyze.Run(ctx)
+}
+
+func (l *Lifecycle) newAnalyze(repoName, cacheName string, publish, clearCache bool) (*Phase, error) {
+ args := []string{
+ "-layers", layersDir,
+ repoName,
+ }
+ if clearCache {
+ args = prependArg("-skip-layers", args)
+ } else if l.CombinedExporterCacher() {
+ args = append([]string{"-cache-dir", cacheDir}, args...)
+ }
+
+ if publish {
+ return l.NewPhase(
+ "analyzer",
+ WithRegistryAccess(repoName),
+ WithRoot(),
+ WithArgs(args...),
+ WithBinds(fmt.Sprintf("%s:%s", cacheName, cacheDir)),
+ )
+ }
+ return l.NewPhase(
+ "analyzer",
+ WithDaemonAccess(),
+ WithArgs(
+ l.withLogLevel(
+ prependArg(
+ "-daemon",
+ args,
+ )...,
+ )...,
+ ),
+ WithBinds(fmt.Sprintf("%s:%s", cacheName, cacheDir)),
+ )
+}
+
+func prependArg(arg string, args []string) []string {
+ return append([]string{arg}, args...)
+}
+
+func (l *Lifecycle) Build(ctx context.Context, networkMode string) error {
+ build, err := l.NewPhase(
+ "builder",
+ WithArgs(
+ "-layers", layersDir,
+ "-app", appDir,
+ "-platform", platformDir,
+ ),
+ WithNetwork(networkMode),
+ )
+ if err != nil {
+ return err
+ }
+ defer build.Cleanup()
+ return build.Run(ctx)
+}
+
+func (l *Lifecycle) Export(ctx context.Context, repoName string, runImage string, publish bool, launchCacheName, cacheName string) error {
+ export, err := l.newExport(repoName, runImage, publish, launchCacheName, cacheName)
+ if err != nil {
+ return err
+ }
+ defer export.Cleanup()
+ return export.Run(ctx)
+}
+
+func (l *Lifecycle) newExport(repoName, runImage string, publish bool, launchCacheName, cacheName string) (*Phase, error) {
+ if publish {
+ return l.NewPhase(
+ "exporter",
+ WithRegistryAccess(repoName, runImage),
+ WithArgs(
+ l.withLogLevel(
+ "-image", runImage,
+ "-layers", layersDir,
+ "-app", appDir,
+ repoName,
+ )...,
+ ),
+ )
+ }
+
+ args := []string{
+ "-image", runImage,
+ "-layers", layersDir,
+ "-app", appDir,
+ "-daemon",
+ "-launch-cache", launchCacheDir,
+ repoName,
+ }
+ if l.CombinedExporterCacher() {
+ args = append([]string{"-cache-dir", cacheDir}, args...)
+ }
+
+ return l.NewPhase(
+ "exporter",
+ WithDaemonAccess(),
+ WithArgs(
+ l.withLogLevel(args...)...,
+ ),
+ WithBinds(fmt.Sprintf("%s:%s", launchCacheName, launchCacheDir)),
+ WithBinds(fmt.Sprintf("%s:%s", cacheName, cacheDir)),
+ )
+}
+
+// The cache phase is obsolete with Platform API 0.2 and will be removed in the future.
+func (l *Lifecycle) Cache(ctx context.Context, cacheName string) error {
+ cache, err := l.NewPhase(
+ "cacher",
+ WithDaemonAccess(),
+ WithArgs(
+ l.withLogLevel(
+ "-path", cacheDir,
+ "-layers", layersDir,
+ )...,
+ ),
+ WithBinds(fmt.Sprintf("%s:%s", cacheName, cacheDir)),
+ )
+ if err != nil {
+ return err
+ }
+ defer cache.Cleanup()
+ return cache.Run(ctx)
+}
+
+func (l *Lifecycle) withLogLevel(args ...string) []string {
+ version := semver.MustParse(l.version)
+ if semver.MustParse("0.4.0").LessThan(version) {
+ if l.logger.IsVerbose() {
+ return append([]string{"-log-level", "debug"}, args...)
+ }
+ }
+ return args
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/builder/builder.go b/vendor/github.com/buildpacks/pack/internal/builder/builder.go
new file mode 100644
index 00000000000..34168c437de
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/builder/builder.go
@@ -0,0 +1,676 @@
+package builder
+
+import (
+ "archive/tar"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "time"
+
+ "github.com/BurntSushi/toml"
+ "github.com/buildpacks/imgutil"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/builder"
+ "github.com/buildpacks/pack/cmd"
+ "github.com/buildpacks/pack/internal/api"
+ "github.com/buildpacks/pack/internal/archive"
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/stack"
+ "github.com/buildpacks/pack/internal/style"
+ "github.com/buildpacks/pack/logging"
+)
+
+const (
+ packName = "Pack CLI"
+
+ cnbDir = "/cnb"
+
+ orderPath = "/cnb/order.toml"
+ stackPath = "/cnb/stack.toml"
+ platformDir = "/platform"
+ lifecycleDir = "/cnb/lifecycle"
+ workspaceDir = "/workspace"
+ layersDir = "/layers"
+
+ metadataLabel = "io.buildpacks.builder.metadata"
+ stackLabel = "io.buildpacks.stack.id"
+
+ envUID = "CNB_USER_ID"
+ envGID = "CNB_GROUP_ID"
+)
+
+type Builder struct {
+ baseImageName string
+ image imgutil.Image
+ lifecycle Lifecycle
+ lifecycleDescriptor LifecycleDescriptor
+ additionalBuildpacks []dist.Buildpack
+ metadata Metadata
+ mixins []string
+ env map[string]string
+ UID, GID int
+ StackID string
+ replaceOrder bool
+ order dist.Order
+}
+
+type orderTOML struct {
+ Order dist.Order `toml:"order"`
+}
+
+// FromImage constructs a builder from a builder image
+func FromImage(img imgutil.Image) (*Builder, error) {
+ var metadata Metadata
+ if ok, err := dist.GetLabel(img, metadataLabel, &metadata); err != nil {
+ return nil, err
+ } else if !ok {
+ return nil, fmt.Errorf("builder %s missing label %s -- try recreating builder", style.Symbol(img.Name()), style.Symbol(metadataLabel))
+ }
+ return constructBuilder(img, "", metadata)
+}
+
+// New constructs a new builder from base image
+func New(baseImage imgutil.Image, name string) (*Builder, error) {
+ var metadata Metadata
+ if _, err := dist.GetLabel(baseImage, metadataLabel, &metadata); err != nil {
+ return nil, err
+ }
+ return constructBuilder(baseImage, name, metadata)
+}
+
+func constructBuilder(img imgutil.Image, newName string, metadata Metadata) (*Builder, error) {
+ uid, gid, err := userAndGroupIDs(img)
+ if err != nil {
+ return nil, err
+ }
+
+ stackID, err := img.Label(stackLabel)
+ if err != nil {
+ return nil, errors.Wrapf(err, "get label %s from image %s", style.Symbol(stackLabel), style.Symbol(img.Name()))
+ }
+ if stackID == "" {
+ return nil, fmt.Errorf("image %s missing label %s", style.Symbol(img.Name()), style.Symbol(stackLabel))
+ }
+
+ var mixins []string
+ if _, err := dist.GetLabel(img, stack.MixinsLabel, &mixins); err != nil {
+ return nil, err
+ }
+
+ baseName := img.Name()
+ if newName != "" && baseName != newName {
+ img.Rename(newName)
+ }
+
+ lifecycleVersion := VersionMustParse(AssumedLifecycleVersion)
+ if metadata.Lifecycle.Version != nil {
+ lifecycleVersion = metadata.Lifecycle.Version
+ }
+
+ buildpackAPIVersion := api.MustParse(dist.AssumedBuildpackAPIVersion)
+ if metadata.Lifecycle.API.BuildpackVersion != nil {
+ buildpackAPIVersion = metadata.Lifecycle.API.BuildpackVersion
+ }
+
+ platformAPIVersion := api.MustParse(AssumedPlatformAPIVersion)
+ if metadata.Lifecycle.API.PlatformVersion != nil {
+ platformAPIVersion = metadata.Lifecycle.API.PlatformVersion
+ }
+
+ var order dist.Order
+ if ok, err := dist.GetLabel(img, OrderLabel, &order); err != nil {
+ return nil, err
+ } else if !ok {
+ order = metadata.Groups.ToOrder()
+ }
+
+ return &Builder{
+ baseImageName: baseName,
+ image: img,
+ metadata: metadata,
+ mixins: mixins,
+ order: order,
+ UID: uid,
+ GID: gid,
+ StackID: stackID,
+ lifecycleDescriptor: LifecycleDescriptor{
+ Info: LifecycleInfo{
+ Version: lifecycleVersion,
+ },
+ API: LifecycleAPI{
+ PlatformVersion: platformAPIVersion,
+ BuildpackVersion: buildpackAPIVersion,
+ },
+ },
+ env: map[string]string{},
+ }, nil
+}
+
+func (b *Builder) Description() string {
+ return b.metadata.Description
+}
+
+func (b *Builder) LifecycleDescriptor() LifecycleDescriptor {
+ return b.lifecycleDescriptor
+}
+
+func (b *Builder) Buildpacks() []BuildpackMetadata {
+ return b.metadata.Buildpacks
+}
+
+func (b *Builder) CreatedBy() CreatorMetadata {
+ return b.metadata.CreatedBy
+}
+
+func (b *Builder) Order() dist.Order {
+ return b.order
+}
+
+func (b *Builder) Name() string {
+ return b.image.Name()
+}
+
+func (b *Builder) Image() imgutil.Image {
+ return b.image
+}
+
+func (b *Builder) Stack() StackMetadata {
+ return b.metadata.Stack
+}
+func (b *Builder) Mixins() []string {
+ return b.mixins
+}
+
+func (b *Builder) AddBuildpack(bp dist.Buildpack) {
+ b.additionalBuildpacks = append(b.additionalBuildpacks, bp)
+ b.metadata.Buildpacks = append(b.metadata.Buildpacks, BuildpackMetadata{
+ BuildpackInfo: bp.Descriptor().Info,
+ })
+}
+
+func (b *Builder) SetLifecycle(lifecycle Lifecycle) error {
+ b.lifecycle = lifecycle
+ b.lifecycleDescriptor = lifecycle.Descriptor()
+ return nil
+}
+
+func (b *Builder) SetEnv(env map[string]string) {
+ b.env = env
+}
+
+func (b *Builder) SetOrder(order dist.Order) {
+ b.order = order
+ b.replaceOrder = true
+}
+
+func (b *Builder) SetDescription(description string) {
+ b.metadata.Description = description
+}
+
+func (b *Builder) SetStack(stackConfig builder.StackConfig) {
+ b.metadata.Stack = StackMetadata{
+ RunImage: RunImageMetadata{
+ Image: stackConfig.RunImage,
+ Mirrors: stackConfig.RunImageMirrors,
+ },
+ }
+}
+
+func (b *Builder) Save(logger logging.Logger) error {
+ resolvedOrder, err := processOrder(b.metadata.Buildpacks, b.order)
+ if err != nil {
+ return errors.Wrap(err, "processing order")
+ }
+
+ b.metadata.Groups = orderToV1Order(resolvedOrder)
+ processMetadata(&b.metadata)
+
+ tmpDir, err := ioutil.TempDir("", "create-builder-scratch")
+ if err != nil {
+ return err
+ }
+ defer os.RemoveAll(tmpDir)
+
+ dirsTar, err := b.defaultDirsLayer(tmpDir)
+ if err != nil {
+ return err
+ }
+ if err := b.image.AddLayer(dirsTar); err != nil {
+ return errors.Wrap(err, "adding default dirs layer")
+ }
+
+ if b.lifecycle != nil {
+ b.metadata.Lifecycle.LifecycleInfo = b.lifecycle.Descriptor().Info
+ b.metadata.Lifecycle.API = b.lifecycle.Descriptor().API
+ lifecycleTar, err := b.lifecycleLayer(tmpDir)
+ if err != nil {
+ return err
+ }
+ if err := b.image.AddLayer(lifecycleTar); err != nil {
+ return errors.Wrap(err, "adding lifecycle layer")
+ }
+ }
+
+ if err := validateBuildpacks(b.StackID, b.Mixins(), b.LifecycleDescriptor(), b.additionalBuildpacks); err != nil {
+ return errors.Wrap(err, "validating buildpacks")
+ }
+
+ bpLayers := dist.BuildpackLayers{}
+ if _, err := dist.GetLabel(b.image, dist.BuildpackLayersLabel, &bpLayers); err != nil {
+ return err
+ }
+
+ for _, bp := range b.additionalBuildpacks {
+ bpLayerTar, err := dist.BuildpackToLayerTar(tmpDir, bp)
+ if err != nil {
+ return err
+ }
+
+ if err := b.image.AddLayer(bpLayerTar); err != nil {
+ return errors.Wrapf(err,
+ "adding layer tar for buildpack %s",
+ style.Symbol(bp.Descriptor().Info.FullName()),
+ )
+ }
+
+ diffID, err := dist.LayerDiffID(bpLayerTar)
+ if err != nil {
+ return errors.Wrapf(err,
+ "getting content hashes for buildpack %s",
+ style.Symbol(bp.Descriptor().Info.FullName()),
+ )
+ }
+
+ bpInfo := bp.Descriptor().Info
+ if _, ok := bpLayers[bpInfo.ID][bpInfo.Version]; ok {
+ logger.Warnf(
+ "buildpack %s already exists on builder and will be overwritten",
+ style.Symbol(bpInfo.FullName()),
+ )
+ }
+
+ dist.AddBuildpackToLayersMD(bpLayers, bp.Descriptor(), diffID.String())
+ }
+
+ if err := dist.SetLabel(b.image, dist.BuildpackLayersLabel, bpLayers); err != nil {
+ return err
+ }
+
+ if b.replaceOrder {
+ orderTar, err := b.orderLayer(resolvedOrder, tmpDir)
+ if err != nil {
+ return err
+ }
+ if err := b.image.AddLayer(orderTar); err != nil {
+ return errors.Wrap(err, "adding order.tar layer")
+ }
+
+ if err := dist.SetLabel(b.image, OrderLabel, b.order); err != nil {
+ return err
+ }
+ }
+
+ stackTar, err := b.stackLayer(tmpDir)
+ if err != nil {
+ return err
+ }
+ if err := b.image.AddLayer(stackTar); err != nil {
+ return errors.Wrap(err, "adding stack.tar layer")
+ }
+
+ compatTar, err := b.compatLayer(resolvedOrder, tmpDir)
+ if err != nil {
+ return err
+ }
+
+ if err := b.image.AddLayer(compatTar); err != nil {
+ return errors.Wrap(err, "adding compat.tar layer")
+ }
+
+ envTar, err := b.envLayer(tmpDir, b.env)
+ if err != nil {
+ return err
+ }
+ if err := b.image.AddLayer(envTar); err != nil {
+ return errors.Wrap(err, "adding env layer")
+ }
+
+ b.metadata.CreatedBy = CreatorMetadata{
+ Name: packName,
+ Version: cmd.Version,
+ }
+
+ if err := dist.SetLabel(b.image, metadataLabel, b.metadata); err != nil {
+ return err
+ }
+
+ if err := dist.SetLabel(b.image, stack.MixinsLabel, b.mixins); err != nil {
+ return err
+ }
+
+ if err := b.image.SetWorkingDir(layersDir); err != nil {
+ return errors.Wrap(err, "failed to set working dir")
+ }
+
+ return b.image.Save()
+}
+
+func processOrder(buildpacks []BuildpackMetadata, order dist.Order) (dist.Order, error) {
+ resolvedOrder := dist.Order{}
+
+ for gi, g := range order {
+ resolvedOrder = append(resolvedOrder, dist.OrderEntry{})
+
+ for _, bpRef := range g.Group {
+ var matchingBps []dist.BuildpackInfo
+ for _, bp := range buildpacks {
+ if bpRef.ID == bp.ID {
+ matchingBps = append(matchingBps, bp.BuildpackInfo)
+ }
+ }
+
+ if len(matchingBps) == 0 {
+ return dist.Order{}, fmt.Errorf("no versions of buildpack %s were found on the builder", style.Symbol(bpRef.ID))
+ }
+
+ if bpRef.Version == "" {
+ if len(matchingBps) > 1 {
+ return dist.Order{}, fmt.Errorf("unable to resolve version: multiple versions of %s - must specify an explicit version", style.Symbol(bpRef.ID))
+ }
+
+ bpRef.Version = matchingBps[0].Version
+ }
+
+ if !hasBuildpackWithVersion(matchingBps, bpRef.Version) {
+ return dist.Order{}, fmt.Errorf("buildpack %s with version %s was not found on the builder", style.Symbol(bpRef.ID), style.Symbol(bpRef.Version))
+ }
+
+ resolvedOrder[gi].Group = append(resolvedOrder[gi].Group, bpRef)
+ }
+ }
+
+ return resolvedOrder, nil
+}
+
+func hasBuildpackWithVersion(bps []dist.BuildpackInfo, version string) bool {
+ for _, bp := range bps {
+ if bp.Version == version {
+ return true
+ }
+ }
+ return false
+}
+
+func validateBuildpacks(stackID string, mixins []string, lifecycleDescriptor LifecycleDescriptor, bps []dist.Buildpack) error {
+ bpLookup := map[string]interface{}{}
+
+ for _, bp := range bps {
+ bpLookup[bp.Descriptor().Info.FullName()] = nil
+ }
+
+ for _, bp := range bps {
+ bpd := bp.Descriptor()
+
+ if !bpd.API.SupportsVersion(lifecycleDescriptor.API.BuildpackVersion) {
+ return fmt.Errorf(
+ "buildpack %s (Buildpack API version %s) is incompatible with lifecycle %s (Buildpack API version %s)",
+ style.Symbol(bpd.Info.FullName()),
+ bpd.API.String(),
+ style.Symbol(lifecycleDescriptor.Info.Version.String()),
+ lifecycleDescriptor.API.BuildpackVersion.String(),
+ )
+ }
+
+ if len(bpd.Stacks) >= 1 { // standard buildpack
+ if err := bpd.EnsureStackSupport(stackID, mixins, false); err != nil {
+ return err
+ }
+ } else { // order buildpack
+ for _, g := range bpd.Order {
+ for _, r := range g.Group {
+ if _, ok := bpLookup[r.FullName()]; !ok {
+ return fmt.Errorf(
+ "buildpack %s not found on the builder",
+ style.Symbol(r.FullName()),
+ )
+ }
+ }
+ }
+ }
+ }
+
+ return nil
+}
+
+func userAndGroupIDs(img imgutil.Image) (int, int, error) {
+ sUID, err := img.Env(envUID)
+ if err != nil {
+ return 0, 0, errors.Wrap(err, "reading builder env variables")
+ } else if sUID == "" {
+ return 0, 0, fmt.Errorf("image %s missing required env var %s", style.Symbol(img.Name()), style.Symbol(envUID))
+ }
+
+ sGID, err := img.Env(envGID)
+ if err != nil {
+ return 0, 0, errors.Wrap(err, "reading builder env variables")
+ } else if sGID == "" {
+ return 0, 0, fmt.Errorf("image %s missing required env var %s", style.Symbol(img.Name()), style.Symbol(envGID))
+ }
+
+ var uid, gid int
+ uid, err = strconv.Atoi(sUID)
+ if err != nil {
+ return 0, 0, fmt.Errorf("failed to parse %s, value %s should be an integer", style.Symbol(envUID), style.Symbol(sUID))
+ }
+
+ gid, err = strconv.Atoi(sGID)
+ if err != nil {
+ return 0, 0, fmt.Errorf("failed to parse %s, value %s should be an integer", style.Symbol(envGID), style.Symbol(sGID))
+ }
+
+ return uid, gid, nil
+}
+
+func (b *Builder) defaultDirsLayer(dest string) (string, error) {
+ fh, err := os.Create(filepath.Join(dest, "dirs.tar"))
+ if err != nil {
+ return "", err
+ }
+ defer fh.Close()
+
+ tw := tar.NewWriter(fh)
+ defer tw.Close()
+
+ ts := archive.NormalizedDateTime
+
+ if err := tw.WriteHeader(b.packOwnedDir(workspaceDir, ts)); err != nil {
+ return "", errors.Wrapf(err, "creating %s dir in layer", style.Symbol(workspaceDir))
+ }
+
+ if err := tw.WriteHeader(b.packOwnedDir(layersDir, ts)); err != nil {
+ return "", errors.Wrapf(err, "creating %s dir in layer", style.Symbol(layersDir))
+ }
+
+ if err := tw.WriteHeader(b.rootOwnedDir(cnbDir, ts)); err != nil {
+ return "", errors.Wrapf(err, "creating %s dir in layer", style.Symbol(cnbDir))
+ }
+
+ if err := tw.WriteHeader(b.rootOwnedDir(dist.BuildpacksDir, ts)); err != nil {
+ return "", errors.Wrapf(err, "creating %s dir in layer", style.Symbol(dist.BuildpacksDir))
+ }
+
+ if err := tw.WriteHeader(b.rootOwnedDir(platformDir, ts)); err != nil {
+ return "", errors.Wrapf(err, "creating %s dir in layer", style.Symbol(platformDir))
+ }
+
+ if err := tw.WriteHeader(b.rootOwnedDir(platformDir+"/env", ts)); err != nil {
+ return "", errors.Wrapf(err, "creating %s dir in layer", style.Symbol(platformDir+"/env"))
+ }
+
+ return fh.Name(), nil
+}
+
+func (b *Builder) packOwnedDir(path string, time time.Time) *tar.Header {
+ return &tar.Header{
+ Typeflag: tar.TypeDir,
+ Name: path,
+ Mode: 0755,
+ ModTime: time,
+ Uid: b.UID,
+ Gid: b.GID,
+ }
+}
+
+func (b *Builder) rootOwnedDir(path string, time time.Time) *tar.Header {
+ return &tar.Header{
+ Typeflag: tar.TypeDir,
+ Name: path,
+ Mode: 0755,
+ ModTime: time,
+ }
+}
+
+func (b *Builder) orderLayer(order dist.Order, dest string) (string, error) {
+ contents, err := orderFileContents(order)
+ if err != nil {
+ return "", err
+ }
+
+ layerTar := filepath.Join(dest, "order.tar")
+ err = archive.CreateSingleFileTar(layerTar, orderPath, contents)
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to create order.toml layer tar")
+ }
+
+ return layerTar, nil
+}
+
+func orderFileContents(order dist.Order) (string, error) {
+ buf := &bytes.Buffer{}
+
+ tomlData := orderTOML{Order: order}
+ if err := toml.NewEncoder(buf).Encode(tomlData); err != nil {
+ return "", errors.Wrapf(err, "failed to marshal order.toml")
+ }
+ return buf.String(), nil
+}
+
+func (b *Builder) stackLayer(dest string) (string, error) {
+ buf := &bytes.Buffer{}
+ err := toml.NewEncoder(buf).Encode(b.metadata.Stack)
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to marshal stack.toml")
+ }
+
+ layerTar := filepath.Join(dest, "stack.tar")
+ err = archive.CreateSingleFileTar(layerTar, stackPath, buf.String())
+ if err != nil {
+ return "", errors.Wrapf(err, "failed to create stack.toml layer tar")
+ }
+
+ return layerTar, nil
+}
+
+func (b *Builder) embedLifecycleTar(tw *tar.Writer) error {
+ var regex = regexp.MustCompile(`^[^/]+/([^/]+)$`)
+
+ lr, err := b.lifecycle.Open()
+ if err != nil {
+ return errors.Wrap(err, "failed to open lifecycle")
+ }
+ defer lr.Close()
+ tr := tar.NewReader(lr)
+ for {
+ header, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return errors.Wrap(err, "failed to get next tar entry")
+ }
+
+ pathMatches := regex.FindStringSubmatch(path.Clean(header.Name))
+ if pathMatches != nil {
+ binaryName := pathMatches[1]
+
+ header.Name = lifecycleDir + "/" + binaryName
+ err = tw.WriteHeader(header)
+ if err != nil {
+ return errors.Wrapf(err, "failed to write header for '%s'", header.Name)
+ }
+
+ buf, err := ioutil.ReadAll(tr)
+ if err != nil {
+ return errors.Wrapf(err, "failed to read contents of '%s'", header.Name)
+ }
+
+ _, err = tw.Write(buf)
+ if err != nil {
+ return errors.Wrapf(err, "failed to write contents to '%s'", header.Name)
+ }
+ }
+ }
+
+ return nil
+}
+
+func (b *Builder) envLayer(dest string, env map[string]string) (string, error) {
+ fh, err := os.Create(filepath.Join(dest, "env.tar"))
+ if err != nil {
+ return "", err
+ }
+ defer fh.Close()
+
+ tw := tar.NewWriter(fh)
+ defer tw.Close()
+
+ for k, v := range env {
+ if err := tw.WriteHeader(&tar.Header{
+ Name: path.Join(platformDir, "env", k),
+ Size: int64(len(v)),
+ Mode: 0644,
+ ModTime: archive.NormalizedDateTime,
+ }); err != nil {
+ return "", err
+ }
+ if _, err := tw.Write([]byte(v)); err != nil {
+ return "", err
+ }
+ }
+
+ return fh.Name(), nil
+}
+
+func (b *Builder) lifecycleLayer(dest string) (string, error) {
+ fh, err := os.Create(filepath.Join(dest, "lifecycle.tar"))
+ if err != nil {
+ return "", err
+ }
+ defer fh.Close()
+
+ tw := tar.NewWriter(fh)
+ defer tw.Close()
+
+ if err := tw.WriteHeader(&tar.Header{
+ Typeflag: tar.TypeDir,
+ Name: lifecycleDir,
+ Mode: 0755,
+ ModTime: archive.NormalizedDateTime,
+ }); err != nil {
+ return "", err
+ }
+
+ err = b.embedLifecycleTar(tw)
+ if err != nil {
+ return "", errors.Wrap(err, "embedding lifecycle tar")
+ }
+
+ return fh.Name(), nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/builder/compat.go b/vendor/github.com/buildpacks/pack/internal/builder/compat.go
new file mode 100644
index 00000000000..2a93fbb2137
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/builder/compat.go
@@ -0,0 +1,152 @@
+package builder
+
+import (
+ "archive/tar"
+ "bytes"
+ "fmt"
+ "os"
+ "path"
+
+ "github.com/BurntSushi/toml"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/api"
+ "github.com/buildpacks/pack/internal/archive"
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+const (
+ compatBuildpacksDir = "/buildpacks"
+ compatLifecycleDir = "/lifecycle"
+ compatStackPath = "/buildpacks/stack.toml"
+)
+
+type V1Order []V1Group
+
+type V1Group struct {
+ Buildpacks []dist.BuildpackRef `toml:"buildpacks" json:"buildpacks"`
+}
+
+func (o V1Order) ToOrder() dist.Order {
+ var order dist.Order
+ for _, gp := range o {
+ var buildpacks []dist.BuildpackRef
+ buildpacks = append(buildpacks, gp.Buildpacks...)
+
+ order = append(order, dist.OrderEntry{
+ Group: buildpacks,
+ })
+ }
+ return order
+}
+
+func orderToV1Order(o dist.Order) V1Order {
+ var order V1Order //nolint:prealloc
+ for _, gp := range o {
+ var buildpacks []dist.BuildpackRef
+ buildpacks = append(buildpacks, gp.Group...)
+
+ order = append(order, V1Group{
+ Buildpacks: buildpacks,
+ })
+ }
+
+ return order
+}
+
+func (b *Builder) compatLayer(order dist.Order, dest string) (string, error) {
+ compatTar := path.Join(dest, "compat.tar")
+ fh, err := os.Create(compatTar)
+ if err != nil {
+ return "", err
+ }
+ defer fh.Close()
+
+ tw := tar.NewWriter(fh)
+ defer tw.Close()
+
+ if b.lifecycle != nil {
+ if err := compatLifecycle(tw); err != nil {
+ return "", err
+ }
+ }
+
+ if err := b.compatBuildpacks(tw); err != nil {
+ return "", err
+ }
+
+ if err := b.compatStack(tw); err != nil {
+ return "", errors.Wrapf(err, "failed to add %s to compat layer", style.Symbol(compatStackPath))
+ }
+
+ return compatTar, nil
+}
+
+func compatLifecycle(tw *tar.Writer) error {
+ return addSymlink(tw, compatLifecycleDir, lifecycleDir)
+}
+
+func (b *Builder) compatBuildpacks(tw *tar.Writer) error {
+ ts := archive.NormalizedDateTime
+ if err := tw.WriteHeader(b.rootOwnedDir(compatBuildpacksDir, ts)); err != nil {
+ return errors.Wrapf(err, "creating %s dir in layer", style.Symbol(dist.BuildpacksDir))
+ }
+ for _, bp := range b.additionalBuildpacks {
+ descriptor := bp.Descriptor()
+
+ compatDir := path.Join(compatBuildpacksDir, descriptor.EscapedID())
+ if err := tw.WriteHeader(b.rootOwnedDir(compatDir, ts)); err != nil {
+ return errors.Wrapf(err, "creating %s dir in layer", style.Symbol(compatDir))
+ }
+ compatLink := path.Join(compatDir, descriptor.Info.Version)
+ bpDir := path.Join(dist.BuildpacksDir, descriptor.EscapedID(), descriptor.Info.Version)
+ if err := addSymlink(tw, compatLink, bpDir); err != nil {
+ return err
+ }
+
+ bpAPIVersion := b.lifecycleDescriptor.API.BuildpackVersion
+ if bpAPIVersion != nil && bpAPIVersion.Equal(api.MustParse("0.1")) {
+ if err := symlinkLatest(tw, bpDir, descriptor, b.metadata); err != nil {
+ return err
+ }
+ }
+ }
+ return nil
+}
+
+func (b *Builder) compatStack(tw *tar.Writer) error {
+ stackBuf := &bytes.Buffer{}
+ if err := toml.NewEncoder(stackBuf).Encode(b.metadata.Stack); err != nil {
+ return errors.Wrapf(err, "failed to marshal stack.toml")
+ }
+ return archive.AddFileToTar(tw, compatStackPath, stackBuf.String())
+}
+
+func addSymlink(tw *tar.Writer, name, linkName string) error {
+ if err := tw.WriteHeader(&tar.Header{
+ Name: name,
+ Linkname: linkName,
+ Typeflag: tar.TypeSymlink,
+ Mode: 0644,
+ ModTime: archive.NormalizedDateTime,
+ }); err != nil {
+ return errors.Wrapf(err, "creating %s symlink", style.Symbol(name))
+ }
+ return nil
+}
+
+// Deprecated: The 'latest' symlink is in place for backwards compatibility only. This should be removed as soon
+// as we no longer support older releases that rely on it.
+func symlinkLatest(tw *tar.Writer, baseTarDir string, bp dist.BuildpackDescriptor, metadata Metadata) error {
+ for _, b := range metadata.Buildpacks {
+ if b.ID == bp.Info.ID && b.Version == bp.Info.Version && b.Latest {
+ name := fmt.Sprintf("%s/%s/%s", compatBuildpacksDir, bp.EscapedID(), "latest")
+ if err := addSymlink(tw, name, baseTarDir); err != nil {
+ return errors.Wrapf(err, "creating latest symlink for buildpack '%s:%s'", bp.Info.ID, bp.Info.Version)
+ }
+ break
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/builder/lifecycle.go b/vendor/github.com/buildpacks/pack/internal/builder/lifecycle.go
new file mode 100644
index 00000000000..92f00345045
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/builder/lifecycle.go
@@ -0,0 +1,149 @@
+package builder
+
+import (
+ "archive/tar"
+ "fmt"
+ "io"
+ "path"
+ "regexp"
+
+ "github.com/BurntSushi/toml"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/api"
+ "github.com/buildpacks/pack/internal/archive"
+ "github.com/buildpacks/pack/internal/dist"
+)
+
+const (
+ AssumedLifecycleVersion = "0.3.0"
+ AssumedPlatformAPIVersion = "0.1"
+
+ DefaultLifecycleVersion = "0.5.0"
+ DefaultBuildpackAPIVersion = "0.2"
+ DefaultPlatformAPIVersion = "0.1"
+)
+
+type Blob interface {
+ Open() (io.ReadCloser, error)
+}
+
+//go:generate mockgen -package testmocks -destination testmocks/mock_lifecycle.go github.com/buildpacks/pack/internal/builder Lifecycle
+type Lifecycle interface {
+ Blob
+ Descriptor() LifecycleDescriptor
+}
+
+type LifecycleDescriptor struct {
+ Info LifecycleInfo `toml:"lifecycle"`
+ API LifecycleAPI `toml:"api"`
+}
+
+type LifecycleInfo struct {
+ Version *Version `toml:"version" json:"version"`
+}
+
+type LifecycleAPI struct {
+ BuildpackVersion *api.Version `toml:"buildpack" json:"buildpack"`
+ PlatformVersion *api.Version `toml:"platform" json:"platform"`
+}
+
+type lifecycle struct {
+ descriptor LifecycleDescriptor
+ Blob
+}
+
+func NewLifecycle(blob Blob) (Lifecycle, error) {
+ var err error
+
+ br, err := blob.Open()
+ if err != nil {
+ return nil, errors.Wrap(err, "open lifecycle blob")
+ }
+ defer br.Close()
+
+ var descriptor LifecycleDescriptor
+ _, buf, err := archive.ReadTarEntry(br, "lifecycle.toml")
+
+ //TODO: make lifecycle descriptor required after v0.4.0 release [https://github.com/buildpacks/pack/issues/267]
+ if err != nil && errors.Cause(err) == archive.ErrEntryNotExist {
+ return &lifecycle{
+ Blob: blob,
+ descriptor: LifecycleDescriptor{
+ Info: LifecycleInfo{
+ Version: VersionMustParse(AssumedLifecycleVersion),
+ },
+ API: LifecycleAPI{
+ BuildpackVersion: api.MustParse(dist.AssumedBuildpackAPIVersion),
+ PlatformVersion: api.MustParse(AssumedPlatformAPIVersion),
+ },
+ },
+ }, nil
+ } else if err != nil {
+ return nil, errors.Wrap(err, "decode lifecycle descriptor")
+ }
+ _, err = toml.Decode(string(buf), &descriptor)
+ if err != nil {
+ return nil, errors.Wrap(err, "decoding descriptor")
+ }
+
+ lifecycle := &lifecycle{Blob: blob, descriptor: descriptor}
+
+ if err = lifecycle.validateBinaries(); err != nil {
+ return nil, errors.Wrap(err, "validating binaries")
+ }
+
+ return lifecycle, nil
+}
+
+func (l *lifecycle) Descriptor() LifecycleDescriptor {
+ return l.descriptor
+}
+
+// Binaries returns a list of all binaries contained in the lifecycle.
+func (l *lifecycle) binaries() []string {
+ binaries := []string{
+ "detector",
+ "restorer",
+ "analyzer",
+ "builder",
+ "exporter",
+ "launcher",
+ }
+ if l.Descriptor().API.PlatformVersion.Compare(api.MustParse("0.2")) < 0 {
+ binaries = append(binaries, "cacher")
+ }
+ return binaries
+}
+
+func (l *lifecycle) validateBinaries() error {
+ rc, err := l.Open()
+ if err != nil {
+ return errors.Wrap(err, "create lifecycle blob reader")
+ }
+ defer rc.Close()
+ regex := regexp.MustCompile(`^[^/]+/([^/]+)$`)
+ headers := map[string]bool{}
+ tr := tar.NewReader(rc)
+ for {
+ header, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return errors.Wrap(err, "failed to get next tar entry")
+ }
+
+ pathMatches := regex.FindStringSubmatch(path.Clean(header.Name))
+ if pathMatches != nil {
+ headers[pathMatches[1]] = true
+ }
+ }
+ for _, p := range l.binaries() {
+ _, found := headers[p]
+ if !found {
+ return fmt.Errorf("did not find '%s' in tar", p)
+ }
+ }
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/builder/metadata.go b/vendor/github.com/buildpacks/pack/internal/builder/metadata.go
new file mode 100644
index 00000000000..939a2a2b7cf
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/builder/metadata.go
@@ -0,0 +1,55 @@
+package builder
+
+import "github.com/buildpacks/pack/internal/dist"
+
+const (
+ OrderLabel = "io.buildpacks.buildpack.order"
+)
+
+type Metadata struct {
+ Description string `json:"description"`
+ Buildpacks []BuildpackMetadata `json:"buildpacks"`
+ Groups V1Order `json:"groups"` // deprecated
+ Stack StackMetadata `json:"stack"`
+ Lifecycle LifecycleMetadata `json:"lifecycle"`
+ CreatedBy CreatorMetadata `json:"createdBy"`
+}
+
+type CreatorMetadata struct {
+ Name string `json:"name"`
+ Version string `json:"version"`
+}
+
+type BuildpackMetadata struct {
+ dist.BuildpackInfo
+ Latest bool `json:"latest"` // deprecated
+}
+
+type LifecycleMetadata struct {
+ LifecycleInfo
+ API LifecycleAPI `json:"api"`
+}
+
+type StackMetadata struct {
+ RunImage RunImageMetadata `json:"runImage" toml:"run-image"`
+}
+
+type RunImageMetadata struct {
+ Image string `json:"image" toml:"image"`
+ Mirrors []string `json:"mirrors" toml:"mirrors"`
+}
+
+func processMetadata(md *Metadata) {
+ for i, bp := range md.Buildpacks {
+ var matchingBps []dist.BuildpackInfo
+ for _, bp2 := range md.Buildpacks {
+ if bp.ID == bp2.ID {
+ matchingBps = append(matchingBps, bp.BuildpackInfo)
+ }
+ }
+
+ if len(matchingBps) == 1 {
+ md.Buildpacks[i].Latest = true
+ }
+ }
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/builder/version.go b/vendor/github.com/buildpacks/pack/internal/builder/version.go
new file mode 100644
index 00000000000..50131ad3ae9
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/builder/version.go
@@ -0,0 +1,36 @@
+package builder
+
+import (
+ "github.com/Masterminds/semver"
+ "github.com/pkg/errors"
+)
+
+// Version is an extension to semver.Version to make it marshalable.
+type Version struct {
+ semver.Version
+}
+
+func VersionMustParse(v string) *Version {
+ return &Version{Version: *semver.MustParse(v)}
+}
+
+func (v *Version) String() string {
+ return v.Version.String()
+}
+
+// MarshalText makes Version satisfy the encoding.TextMarshaler interface.
+func (v *Version) MarshalText() ([]byte, error) {
+ return []byte(v.Version.Original()), nil
+}
+
+// UnmarshalText makes Version satisfy the encoding.TextUnmarshaler interface.
+func (v *Version) UnmarshalText(text []byte) error {
+ s := string(text)
+ w, err := semver.NewVersion(s)
+ if err != nil {
+ return errors.Wrapf(err, "invalid semantic version %s", s)
+ }
+
+ v.Version = *w
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/buildpackage/builder.go b/vendor/github.com/buildpacks/pack/internal/buildpackage/builder.go
new file mode 100644
index 00000000000..5acc1203491
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/buildpackage/builder.go
@@ -0,0 +1,115 @@
+package buildpackage
+
+import (
+ "io/ioutil"
+ "os"
+
+ "github.com/buildpacks/imgutil"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/stack"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type ImageFactory interface {
+ NewImage(repoName string, local bool) (imgutil.Image, error)
+}
+
+type PackageBuilder struct {
+ buildpack dist.Buildpack
+ dependencies []dist.Buildpack
+ imageFactory ImageFactory
+}
+
+func NewBuilder(imageFactory ImageFactory) *PackageBuilder {
+ return &PackageBuilder{
+ imageFactory: imageFactory,
+ }
+}
+
+func (p *PackageBuilder) SetBuildpack(buildpack dist.Buildpack) {
+ p.buildpack = buildpack
+}
+
+func (p *PackageBuilder) AddDependency(buildpack dist.Buildpack) {
+ p.dependencies = append(p.dependencies, buildpack)
+}
+
+func (p *PackageBuilder) Save(repoName string, publish bool) (imgutil.Image, error) {
+ if p.buildpack == nil {
+ return nil, errors.New("buildpack must be set")
+ }
+
+ stacks := p.buildpack.Descriptor().Stacks
+ for _, bp := range p.dependencies {
+ bpd := bp.Descriptor()
+
+ if len(stacks) == 0 {
+ stacks = bpd.Stacks
+ } else if len(bpd.Stacks) > 0 { // skip over "meta-buildpacks"
+ stacks = stack.MergeCompatible(stacks, bpd.Stacks)
+ if len(stacks) == 0 {
+ return nil, errors.Errorf(
+ "buildpack %s does not support any stacks from %s",
+ style.Symbol(p.buildpack.Descriptor().Info.FullName()),
+ style.Symbol(bpd.Info.FullName()),
+ )
+ }
+ }
+ }
+
+ if len(stacks) == 0 {
+ return nil, errors.Errorf("no compatible stacks among provided buildpacks")
+ }
+
+ image, err := p.imageFactory.NewImage(repoName, !publish)
+ if err != nil {
+ return nil, errors.Wrapf(err, "creating image")
+ }
+
+ if err := dist.SetLabel(image, MetadataLabel, &Metadata{
+ BuildpackInfo: p.buildpack.Descriptor().Info,
+ Stacks: stacks,
+ }); err != nil {
+ return nil, err
+ }
+
+ tmpDir, err := ioutil.TempDir("", "create-package")
+ if err != nil {
+ return nil, err
+ }
+ defer os.RemoveAll(tmpDir)
+
+ bpLayers := dist.BuildpackLayers{}
+ for _, bp := range append(p.dependencies, p.buildpack) {
+ bpLayerTar, err := dist.BuildpackToLayerTar(tmpDir, bp)
+ if err != nil {
+ return nil, err
+ }
+
+ if err := image.AddLayer(bpLayerTar); err != nil {
+ return nil, errors.Wrapf(err, "adding layer tar for buildpack %s", style.Symbol(bp.Descriptor().Info.FullName()))
+ }
+
+ diffID, err := dist.LayerDiffID(bpLayerTar)
+ if err != nil {
+ return nil, errors.Wrapf(err,
+ "getting content hashes for buildpack %s",
+ style.Symbol(bp.Descriptor().Info.FullName()),
+ )
+ }
+
+ dist.AddBuildpackToLayersMD(bpLayers, bp.Descriptor(), diffID.String())
+ }
+
+ if err := dist.SetLabel(image, dist.BuildpackLayersLabel, bpLayers); err != nil {
+ return nil, err
+ }
+
+ if err := image.Save(); err != nil {
+ return nil, err
+ }
+
+ return image, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/buildpackage/buildpackage.go b/vendor/github.com/buildpacks/pack/internal/buildpackage/buildpackage.go
new file mode 100644
index 00000000000..845d7f00ee5
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/buildpackage/buildpackage.go
@@ -0,0 +1,17 @@
+package buildpackage
+
+import (
+ "github.com/buildpacks/pack/internal/dist"
+)
+
+const MetadataLabel = "io.buildpacks.buildpackage.metadata"
+
+type Config struct {
+ Buildpack dist.BuildpackURI `toml:"buildpack"`
+ Dependencies []dist.ImageOrURI `toml:"dependencies"`
+}
+
+type Metadata struct {
+ dist.BuildpackInfo
+ Stacks []dist.Stack `toml:"stacks" json:"stacks"`
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/cache/image_cache.go b/vendor/github.com/buildpacks/pack/internal/cache/image_cache.go
new file mode 100644
index 00000000000..ec85baab3a6
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/cache/image_cache.go
@@ -0,0 +1,38 @@
+package cache
+
+import (
+ "context"
+ "crypto/sha256"
+ "fmt"
+
+ "github.com/docker/docker/api/types"
+ "github.com/docker/docker/client"
+ "github.com/google/go-containerregistry/pkg/name"
+)
+
+type ImageCache struct {
+ docker *client.Client
+ image string
+}
+
+func NewImageCache(imageRef name.Reference, dockerClient *client.Client) *ImageCache {
+ sum := sha256.Sum256([]byte(imageRef.Name()))
+ return &ImageCache{
+ image: fmt.Sprintf("pack-cache-%x", sum[:6]),
+ docker: dockerClient,
+ }
+}
+
+func (c *ImageCache) Name() string {
+ return c.image
+}
+
+func (c *ImageCache) Clear(ctx context.Context) error {
+ _, err := c.docker.ImageRemove(ctx, c.Name(), types.ImageRemoveOptions{
+ Force: true,
+ })
+ if err != nil && !client.IsErrNotFound(err) {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/cache/volume_cache.go b/vendor/github.com/buildpacks/pack/internal/cache/volume_cache.go
new file mode 100644
index 00000000000..f12391f7082
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/cache/volume_cache.go
@@ -0,0 +1,35 @@
+package cache
+
+import (
+ "context"
+ "crypto/sha256"
+ "fmt"
+
+ "github.com/docker/docker/client"
+ "github.com/google/go-containerregistry/pkg/name"
+)
+
+type VolumeCache struct {
+ docker *client.Client
+ volume string
+}
+
+func NewVolumeCache(imageRef name.Reference, suffix string, dockerClient *client.Client) *VolumeCache {
+ sum := sha256.Sum256([]byte(imageRef.Name()))
+ return &VolumeCache{
+ volume: fmt.Sprintf("pack-cache-%x.%s", sum[:6], suffix),
+ docker: dockerClient,
+ }
+}
+
+func (c *VolumeCache) Name() string {
+ return c.volume
+}
+
+func (c *VolumeCache) Clear(ctx context.Context) error {
+ err := c.docker.VolumeRemove(ctx, c.Name(), true)
+ if err != nil && !client.IsErrNotFound(err) {
+ return err
+ }
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/config/config.go b/vendor/github.com/buildpacks/pack/internal/config/config.go
new file mode 100644
index 00000000000..86c8478d375
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/config/config.go
@@ -0,0 +1,77 @@
+package config
+
+import (
+ "os"
+ "path/filepath"
+
+ "github.com/BurntSushi/toml"
+ "github.com/pkg/errors"
+)
+
+type Config struct {
+ RunImages []RunImage `toml:"run-images"`
+ DefaultBuilder string `toml:"default-builder-image,omitempty"`
+}
+
+type RunImage struct {
+ Image string `toml:"image"`
+ Mirrors []string `toml:"mirrors"`
+}
+
+func DefaultConfigPath() (string, error) {
+ home, err := PackHome()
+ if err != nil {
+ return "", errors.Wrap(err, "getting pack home")
+ }
+ return filepath.Join(home, "config.toml"), nil
+}
+
+func PackHome() (string, error) {
+ packHome := os.Getenv("PACK_HOME")
+ if packHome == "" {
+ home, err := os.UserHomeDir()
+ if err != nil {
+ return "", errors.Wrap(err, "getting user home")
+ }
+ packHome = filepath.Join(home, ".pack")
+ }
+ return packHome, nil
+}
+
+func Read(path string) (Config, error) {
+ cfg := Config{}
+ _, err := toml.DecodeFile(path, &cfg)
+ if err != nil && !os.IsNotExist(err) {
+ return Config{}, errors.Wrapf(err, "failed to read config file at path %s", path)
+ }
+
+ return cfg, nil
+}
+
+func Write(cfg Config, path string) error {
+ if err := MkdirAll(filepath.Dir(path)); err != nil {
+ return err
+ }
+ w, err := os.Create(path)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+
+ return toml.NewEncoder(w).Encode(cfg)
+}
+
+func MkdirAll(path string) error {
+ return os.MkdirAll(path, 0777)
+}
+
+func SetRunImageMirrors(cfg Config, image string, mirrors []string) Config {
+ for i := range cfg.RunImages {
+ if cfg.RunImages[i].Image == image {
+ cfg.RunImages[i].Mirrors = mirrors
+ return cfg
+ }
+ }
+ cfg.RunImages = append(cfg.RunImages, RunImage{Image: image, Mirrors: mirrors})
+ return cfg
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/container/run.go b/vendor/github.com/buildpacks/pack/internal/container/run.go
new file mode 100644
index 00000000000..e615f04bab9
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/container/run.go
@@ -0,0 +1,45 @@
+package container
+
+import (
+ "context"
+ "fmt"
+ "io"
+
+ "github.com/docker/docker/api/types"
+ dcontainer "github.com/docker/docker/api/types/container"
+ "github.com/docker/docker/client"
+ "github.com/docker/docker/pkg/stdcopy"
+ "github.com/pkg/errors"
+)
+
+func Run(ctx context.Context, docker *client.Client, ctrID string, out, errOut io.Writer) error {
+ bodyChan, errChan := docker.ContainerWait(ctx, ctrID, dcontainer.WaitConditionNextExit)
+
+ if err := docker.ContainerStart(ctx, ctrID, types.ContainerStartOptions{}); err != nil {
+ return errors.Wrap(err, "container start")
+ }
+ logs, err := docker.ContainerLogs(ctx, ctrID, types.ContainerLogsOptions{
+ ShowStdout: true,
+ ShowStderr: true,
+ Follow: true,
+ })
+ if err != nil {
+ return errors.Wrap(err, "container logs stdout")
+ }
+
+ copyErr := make(chan error)
+ go func() {
+ _, err := stdcopy.StdCopy(out, errOut, logs)
+ copyErr <- err
+ }()
+
+ select {
+ case body := <-bodyChan:
+ if body.StatusCode != 0 {
+ return fmt.Errorf("failed with status code: %d", body.StatusCode)
+ }
+ case err := <-errChan:
+ return err
+ }
+ return <-copyErr
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/dist/buildpack.go b/vendor/github.com/buildpacks/pack/internal/dist/buildpack.go
new file mode 100644
index 00000000000..183c6f3ff91
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/dist/buildpack.go
@@ -0,0 +1,233 @@
+package dist
+
+import (
+ "archive/tar"
+ "io"
+ "path"
+
+ "github.com/BurntSushi/toml"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/api"
+ "github.com/buildpacks/pack/internal/archive"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+const AssumedBuildpackAPIVersion = "0.1"
+const BuildpacksDir = "/cnb/buildpacks"
+
+type Blob interface {
+ Open() (io.ReadCloser, error)
+}
+
+type buildpack struct {
+ descriptor BuildpackDescriptor
+ Blob `toml:"-"`
+}
+
+func (b *buildpack) Descriptor() BuildpackDescriptor {
+ return b.descriptor
+}
+
+//go:generate mockgen -package testmocks -destination testmocks/mock_buildpack.go github.com/buildpacks/pack/internal/dist Buildpack
+type Buildpack interface {
+ // Open returns a reader to a tar with contents structured as per the distribution spec
+ // (currently '/cnbs/buildpacks/{ID}/{version}/*', all entries with a zeroed-out
+ // timestamp and root UID/GID).
+ Open() (io.ReadCloser, error)
+ Descriptor() BuildpackDescriptor
+}
+
+type BuildpackInfo struct {
+ ID string `toml:"id" json:"id"`
+ Version string `toml:"version" json:"version,omitempty"`
+}
+
+func (b BuildpackInfo) FullName() string {
+ if b.Version != "" {
+ return b.ID + "@" + b.Version
+ }
+ return b.ID
+}
+
+type Stack struct {
+ ID string `json:"id"`
+ Mixins []string `json:"mixins,omitempty"`
+}
+
+// BuildpackFromRootBlob constructs a buildpack from a blob. It is assumed that the buildpack contents reside at the root of the
+// blob. The constructed buildpack contents will be structured as per the distribution spec (currently
+// a tar with contents under '/cnbs/buildpacks/{ID}/{version}/*').
+func BuildpackFromRootBlob(blob Blob) (Buildpack, error) {
+ bpd := BuildpackDescriptor{}
+ rc, err := blob.Open()
+ if err != nil {
+ return nil, errors.Wrap(err, "open buildpack")
+ }
+ defer rc.Close()
+
+ _, buf, err := archive.ReadTarEntry(rc, "buildpack.toml")
+ if err != nil {
+ return nil, errors.Wrap(err, "reading buildpack.toml")
+ }
+
+ bpd.API = api.MustParse(AssumedBuildpackAPIVersion)
+ _, err = toml.Decode(string(buf), &bpd)
+ if err != nil {
+ return nil, errors.Wrap(err, "decoding buildpack.toml")
+ }
+
+ err = validateDescriptor(bpd)
+ if err != nil {
+ return nil, errors.Wrap(err, "invalid buildpack.toml")
+ }
+
+ db := &distBlob{
+ openFn: func() io.ReadCloser {
+ return archive.GenerateTar(func(tw *tar.Writer) error {
+ return toDistTar(tw, bpd, blob)
+ })
+ },
+ }
+
+ return &buildpack{
+ descriptor: bpd,
+ Blob: db,
+ }, nil
+}
+
+// BuildpackFromTarBlob constructs a buildpack from a ReadCloser to a tar. It is assumed that the buildpack
+// contents are structured as per the distribution spec (currently '/cnbs/buildpacks/{ID}/{version}/*').
+func BuildpackFromTarBlob(bpd BuildpackDescriptor, blob Blob) Buildpack {
+ return &buildpack{
+ Blob: blob,
+ descriptor: bpd,
+ }
+}
+
+type distBlob struct {
+ openFn func() io.ReadCloser
+}
+
+func (b *distBlob) Open() (io.ReadCloser, error) {
+ return b.openFn(), nil
+}
+
+func toDistTar(tw *tar.Writer, bpd BuildpackDescriptor, blob Blob) error {
+ ts := archive.NormalizedDateTime
+
+ if err := tw.WriteHeader(&tar.Header{
+ Typeflag: tar.TypeDir,
+ Name: path.Join(BuildpacksDir, bpd.EscapedID()),
+ Mode: 0755,
+ ModTime: ts,
+ }); err != nil {
+ return errors.Wrapf(err, "writing buildpack id dir header")
+ }
+
+ baseTarDir := path.Join(BuildpacksDir, bpd.EscapedID(), bpd.Info.Version)
+ if err := tw.WriteHeader(&tar.Header{
+ Typeflag: tar.TypeDir,
+ Name: baseTarDir,
+ Mode: 0755,
+ ModTime: ts,
+ }); err != nil {
+ return errors.Wrapf(err, "writing buildpack version dir header")
+ }
+
+ rc, err := blob.Open()
+ if err != nil {
+ return errors.Wrap(err, "reading buildpack blob")
+ }
+ defer rc.Close()
+
+ tr := tar.NewReader(rc)
+ for {
+ header, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ return errors.Wrap(err, "failed to get next tar entry")
+ }
+
+ archive.NormalizeHeader(header)
+ header.Name = path.Clean(header.Name)
+ if header.Name == "." || header.Name == "/" {
+ continue
+ }
+
+ header.Mode = calcFileMode(header)
+ header.Name = path.Join(baseTarDir, header.Name)
+ err = tw.WriteHeader(header)
+ if err != nil {
+ return errors.Wrapf(err, "failed to write header for '%s'", header.Name)
+ }
+
+ _, err = io.Copy(tw, tr)
+ if err != nil {
+ return errors.Wrapf(err, "failed to write contents to '%s'", header.Name)
+ }
+ }
+
+ return nil
+}
+
+func calcFileMode(header *tar.Header) int64 {
+ switch {
+ case header.Typeflag == tar.TypeDir:
+ return 0755
+ case nameOneOf(header.Name,
+ path.Join("bin", "detect"),
+ path.Join("bin", "build"),
+ ):
+ return 0755
+ case anyExecBit(header.Mode):
+ return 0755
+ }
+
+ return 0644
+}
+
+func nameOneOf(name string, paths ...string) bool {
+ for _, p := range paths {
+ if name == p {
+ return true
+ }
+ }
+ return false
+}
+
+func anyExecBit(mode int64) bool {
+ return mode&0111 != 0
+}
+
+func validateDescriptor(bpd BuildpackDescriptor) error {
+ if bpd.Info.ID == "" {
+ return errors.Errorf("%s is required", style.Symbol("buildpack.id"))
+ }
+
+ if bpd.Info.Version == "" {
+ return errors.Errorf("%s is required", style.Symbol("buildpack.version"))
+ }
+
+ if len(bpd.Order) == 0 && len(bpd.Stacks) == 0 {
+ return errors.Errorf(
+ "buildpack %s: must have either %s or an %s defined",
+ style.Symbol(bpd.Info.FullName()),
+ style.Symbol("stacks"),
+ style.Symbol("order"),
+ )
+ }
+
+ if len(bpd.Order) >= 1 && len(bpd.Stacks) >= 1 {
+ return errors.Errorf(
+ "buildpack %s: cannot have both %s and an %s defined",
+ style.Symbol(bpd.Info.FullName()),
+ style.Symbol("stacks"),
+ style.Symbol("order"),
+ )
+ }
+
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/dist/buildpack_descriptor.go b/vendor/github.com/buildpacks/pack/internal/dist/buildpack_descriptor.go
new file mode 100644
index 00000000000..6a57a1a7ac2
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/dist/buildpack_descriptor.go
@@ -0,0 +1,59 @@
+package dist
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/buildpacks/pack/internal/api"
+ "github.com/buildpacks/pack/internal/stringset"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type BuildpackDescriptor struct {
+ API *api.Version `toml:"api"`
+ Info BuildpackInfo `toml:"buildpack"`
+ Stacks []Stack `toml:"stacks"`
+ Order Order `toml:"order"`
+}
+
+func (b *BuildpackDescriptor) EscapedID() string {
+ return strings.Replace(b.Info.ID, "/", "_", -1)
+}
+
+func (b *BuildpackDescriptor) EnsureStackSupport(stackID string, providedMixins []string, validateRunStageMixins bool) error {
+ if len(b.Stacks) == 0 {
+ return nil // Order buildpack, no validation required
+ }
+
+ bpMixins, err := b.findMixinsForStack(stackID)
+ if err != nil {
+ return err
+ }
+
+ if !validateRunStageMixins {
+ var filtered []string
+ for _, m := range bpMixins {
+ if !strings.HasPrefix(m, "run:") {
+ filtered = append(filtered, m)
+ }
+ }
+ bpMixins = filtered
+ }
+
+ _, missing, _ := stringset.Compare(providedMixins, bpMixins)
+ if len(missing) > 0 {
+ sort.Strings(missing)
+ return fmt.Errorf("buildpack %s requires missing mixin(s): %s", style.Symbol(b.Info.FullName()), strings.Join(missing, ", "))
+ }
+ return nil
+}
+
+func (b *BuildpackDescriptor) findMixinsForStack(stackID string) ([]string, error) {
+ for _, s := range b.Stacks {
+ if s.ID == stackID {
+ return s.Mixins, nil
+ }
+ }
+ return nil, fmt.Errorf("buildpack %s does not support stack %s", style.Symbol(b.Info.FullName()), style.Symbol(stackID))
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/dist/dist.go b/vendor/github.com/buildpacks/pack/internal/dist/dist.go
new file mode 100644
index 00000000000..3b8b9f4dd6d
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/dist/dist.go
@@ -0,0 +1,51 @@
+package dist
+
+import "github.com/buildpacks/pack/internal/api"
+
+const BuildpackLayersLabel = "io.buildpacks.buildpack.layers"
+
+type BuildpackURI struct {
+ URI string `toml:"uri"`
+}
+
+type ImageRef struct {
+ ImageName string `toml:"image"`
+}
+
+type ImageOrURI struct {
+ BuildpackURI
+ ImageRef
+}
+
+type Order []OrderEntry
+
+type OrderEntry struct {
+ Group []BuildpackRef `toml:"group" json:"group"`
+}
+
+type BuildpackRef struct {
+ BuildpackInfo
+ Optional bool `toml:"optional,omitempty" json:"optional,omitempty"`
+}
+
+type BuildpackLayers map[string]map[string]BuildpackLayerInfo
+
+type BuildpackLayerInfo struct {
+ API *api.Version `json:"api"`
+ Stacks []Stack `json:"stacks"`
+ Order Order `json:"order,omitempty"`
+ LayerDiffID string `json:"layerDiffID"`
+}
+
+func AddBuildpackToLayersMD(layerMD BuildpackLayers, descriptor BuildpackDescriptor, diffID string) {
+ bpInfo := descriptor.Info
+ if _, ok := layerMD[bpInfo.ID]; !ok {
+ layerMD[bpInfo.ID] = map[string]BuildpackLayerInfo{}
+ }
+ layerMD[bpInfo.ID][bpInfo.Version] = BuildpackLayerInfo{
+ API: descriptor.API,
+ Stacks: descriptor.Stacks,
+ Order: descriptor.Order,
+ LayerDiffID: diffID,
+ }
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/dist/image.go b/vendor/github.com/buildpacks/pack/internal/dist/image.go
new file mode 100644
index 00000000000..6bbc2d6c57f
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/dist/image.go
@@ -0,0 +1,43 @@
+package dist
+
+import (
+ "encoding/json"
+
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type Labeled interface {
+ Name() string
+ Label(name string) (value string, err error)
+}
+
+type Labelable interface {
+ SetLabel(name string, value string) error
+}
+
+func SetLabel(labelable Labelable, label string, data interface{}) error {
+ dataBytes, err := json.Marshal(data)
+ if err != nil {
+ return errors.Wrapf(err, "marshalling data to JSON for label %s", style.Symbol(label))
+ }
+ if err := labelable.SetLabel(label, string(dataBytes)); err != nil {
+ return errors.Wrapf(err, "setting label %s", style.Symbol(label))
+ }
+ return nil
+}
+
+func GetLabel(labeled Labeled, label string, obj interface{}) (ok bool, err error) {
+ labelData, err := labeled.Label(label)
+ if err != nil {
+ return false, errors.Wrapf(err, "retrieving label %s", style.Symbol(label))
+ }
+ if labelData != "" {
+ if err := json.Unmarshal([]byte(labelData), obj); err != nil {
+ return false, errors.Wrapf(err, "unmarshalling label %s", style.Symbol(label))
+ }
+ return true, nil
+ }
+ return false, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/dist/layers.go b/vendor/github.com/buildpacks/pack/internal/dist/layers.go
new file mode 100644
index 00000000000..514b748d064
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/dist/layers.go
@@ -0,0 +1,54 @@
+package dist
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+
+ v1 "github.com/google/go-containerregistry/pkg/v1"
+ "github.com/google/go-containerregistry/pkg/v1/tarball"
+ "github.com/pkg/errors"
+)
+
+func BuildpackToLayerTar(dest string, bp Buildpack) (string, error) {
+ bpd := bp.Descriptor()
+ bpReader, err := bp.Open()
+ if err != nil {
+ return "", errors.Wrap(err, "opening buildpack blob")
+ }
+ defer bpReader.Close()
+
+ layerTar := filepath.Join(dest, fmt.Sprintf("%s.%s.tar", bpd.EscapedID(), bpd.Info.Version))
+ fh, err := os.Create(layerTar)
+ if err != nil {
+ return "", errors.Wrap(err, "create file for tar")
+ }
+ defer fh.Close()
+
+ if _, err := io.Copy(fh, bpReader); err != nil {
+ return "", errors.Wrap(err, "writing buildpack blob to tar")
+ }
+
+ return layerTar, nil
+}
+
+func LayerDiffID(layerTarPath string) (v1.Hash, error) {
+ fh, err := os.Open(layerTarPath)
+ if err != nil {
+ return v1.Hash{}, errors.Wrap(err, "opening tar file")
+ }
+ defer fh.Close()
+
+ layer, err := tarball.LayerFromFile(layerTarPath)
+ if err != nil {
+ return v1.Hash{}, errors.Wrap(err, "reading layer tar")
+ }
+
+ hash, err := layer.DiffID()
+ if err != nil {
+ return v1.Hash{}, errors.Wrap(err, "generating diff id")
+ }
+
+ return hash, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/image/factory.go b/vendor/github.com/buildpacks/pack/internal/image/factory.go
new file mode 100644
index 00000000000..dbf3b377c54
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/image/factory.go
@@ -0,0 +1,29 @@
+package image
+
+import (
+ "github.com/buildpacks/imgutil"
+ "github.com/buildpacks/imgutil/local"
+ "github.com/buildpacks/imgutil/remote"
+ "github.com/docker/docker/client"
+ "github.com/google/go-containerregistry/pkg/authn"
+)
+
+type DefaultImageFactory struct {
+ dockerClient *client.Client
+ keychain authn.Keychain
+}
+
+func NewFactory(dockerClient *client.Client, keychain authn.Keychain) *DefaultImageFactory {
+ return &DefaultImageFactory{
+ dockerClient: dockerClient,
+ keychain: keychain,
+ }
+}
+
+func (f *DefaultImageFactory) NewImage(repoName string, daemon bool) (imgutil.Image, error) {
+ if daemon {
+ return local.NewImage(repoName, f.dockerClient)
+ }
+
+ return remote.NewImage(repoName, f.keychain)
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/image/fetcher.go b/vendor/github.com/buildpacks/pack/internal/image/fetcher.go
new file mode 100644
index 00000000000..3d62b3f0c4a
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/image/fetcher.go
@@ -0,0 +1,149 @@
+package image
+
+import (
+ "context"
+ "encoding/base64"
+ "encoding/json"
+ "io"
+ "strings"
+
+ "github.com/buildpacks/imgutil"
+ "github.com/buildpacks/imgutil/local"
+ "github.com/buildpacks/imgutil/remote"
+ "github.com/buildpacks/lifecycle/auth"
+ "github.com/docker/docker/api/types"
+ "github.com/docker/docker/client"
+ "github.com/docker/docker/pkg/jsonmessage"
+ "github.com/google/go-containerregistry/pkg/authn"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/style"
+ "github.com/buildpacks/pack/logging"
+)
+
+type Fetcher struct {
+ docker *client.Client
+ logger logging.Logger
+}
+
+func NewFetcher(logger logging.Logger, docker *client.Client) *Fetcher {
+ return &Fetcher{
+ logger: logger,
+ docker: docker,
+ }
+}
+
+var ErrNotFound = errors.New("not found")
+
+func (f *Fetcher) Fetch(ctx context.Context, name string, daemon, pull bool) (image imgutil.Image, err error) {
+ if daemon && !pull {
+ return f.fetchDaemonImage(name)
+ }
+
+ image, err = remote.NewImage(name, authn.DefaultKeychain, remote.FromBaseImage(name))
+ if err != nil {
+ return nil, err
+ }
+
+ remoteFound := image.Found()
+
+ if daemon {
+ if remoteFound {
+ f.logger.Debugf("Pulling image %s", style.Symbol(name))
+ if err := f.pullImage(ctx, name); err != nil {
+ return nil, err
+ }
+ }
+ return f.fetchDaemonImage(name)
+ }
+
+ if !remoteFound {
+ return nil, errors.Wrapf(ErrNotFound, "image %s does not exist in registry", style.Symbol(name))
+ }
+
+ return image, nil
+}
+
+func (f *Fetcher) fetchDaemonImage(name string) (imgutil.Image, error) {
+ image, err := local.NewImage(name, f.docker, local.FromBaseImage(name))
+ if err != nil {
+ return nil, err
+ }
+
+ if !image.Found() {
+ return nil, errors.Wrapf(ErrNotFound, "image %s does not exist on the daemon", style.Symbol(name))
+ }
+ return image, nil
+}
+
+func (f *Fetcher) pullImage(ctx context.Context, imageID string) error {
+ regAuth, err := registryAuth(imageID)
+ if err != nil {
+ return err
+ }
+ rc, err := f.docker.ImagePull(ctx, imageID, types.ImagePullOptions{
+ RegistryAuth: regAuth,
+ })
+ if err != nil {
+ return err
+ }
+ writer := logging.GetInfoWriter(f.logger)
+ type descriptor interface {
+ Fd() uintptr
+ }
+ var termFd uintptr
+ isTerm := false
+ if f, ok := writer.(descriptor); ok {
+ isTerm = true
+ termFd = f.Fd()
+ }
+ err = jsonmessage.DisplayJSONMessagesStream(rc, &colorizedWriter{writer}, termFd, isTerm, nil)
+ if err != nil {
+ return err
+ }
+
+ return rc.Close()
+}
+
+func registryAuth(ref string) (string, error) {
+ _, a, err := auth.ReferenceForRepoName(authn.DefaultKeychain, ref)
+ if err != nil {
+ return "", errors.Wrapf(err, "resolve auth for ref %s", ref)
+ }
+ authConfig, err := a.Authorization()
+ if err != nil {
+ return "", err
+ }
+
+ dataJSON, err := json.Marshal(authConfig)
+ if err != nil {
+ return "", err
+ }
+
+ return base64.StdEncoding.EncodeToString(dataJSON), nil
+}
+
+type colorizedWriter struct {
+ writer io.Writer
+}
+
+type colorFunc = func(string, ...interface{}) string
+
+func (w *colorizedWriter) Write(p []byte) (n int, err error) {
+ msg := string(p)
+ colorizers := map[string]colorFunc{
+ "Waiting": style.Waiting,
+ "Pulling fs layer": style.Waiting,
+ "Downloading": style.Working,
+ "Download complete": style.Working,
+ "Extracting": style.Working,
+ "Pull complete": style.Complete,
+ "Already exists": style.Complete,
+ "=": style.ProgressBar,
+ ">": style.ProgressBar,
+ }
+ for pattern, colorize := range colorizers {
+ msg = strings.Replace(msg, pattern, colorize(pattern), -1)
+ }
+ return w.writer.Write([]byte(msg))
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/paths/paths.go b/vendor/github.com/buildpacks/pack/internal/paths/paths.go
new file mode 100644
index 00000000000..b9be2634be9
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/paths/paths.go
@@ -0,0 +1,88 @@
+package paths
+
+import (
+ "net/url"
+ "os"
+ "path/filepath"
+ "regexp"
+ "runtime"
+ "strings"
+)
+
+var schemeRegexp = regexp.MustCompile(`^.+://.*`)
+
+func IsURI(ref string) bool {
+ return schemeRegexp.MatchString(ref)
+}
+
+func IsDir(path string) (bool, error) {
+ fileInfo, err := os.Stat(path)
+ if err != nil {
+ return false, err
+ }
+
+ return fileInfo.IsDir(), nil
+}
+
+func FilePathToURI(path string) (string, error) {
+ var err error
+ if !filepath.IsAbs(path) {
+ path, err = filepath.Abs(path)
+ if err != nil {
+ return "", err
+ }
+ }
+
+ if runtime.GOOS == "windows" {
+ if strings.HasPrefix(path, `\\`) {
+ return "file://" + filepath.ToSlash(strings.TrimPrefix(path, `\\`)), nil
+ }
+ return "file:///" + filepath.ToSlash(path), nil
+ }
+ return "file://" + path, nil
+}
+
+// examples:
+//
+// - unix file: file://laptop/some%20dir/file.tgz
+//
+// - windows drive: file:///C:/Documents%20and%20Settings/file.tgz
+//
+// - windows share: file://laptop/My%20Documents/file.tgz
+//
+func URIToFilePath(uri string) (string, error) {
+ var (
+ osPath string
+ err error
+ )
+
+ osPath = filepath.FromSlash(strings.TrimPrefix(uri, "file://"))
+
+ if osPath, err = url.PathUnescape(osPath); err != nil {
+ return "", nil
+ }
+
+ if runtime.GOOS == "windows" {
+ if strings.HasPrefix(osPath, `\`) {
+ return strings.TrimPrefix(osPath, `\`), nil
+ }
+ return `\\` + osPath, nil
+ }
+ return osPath, nil
+}
+
+func ToAbsolute(uri, relativeTo string) (string, error) {
+ parsed, err := url.Parse(uri)
+ if err != nil {
+ return "", err
+ }
+
+ if parsed.Scheme == "" {
+ if !filepath.IsAbs(parsed.Path) {
+ absPath := filepath.Join(relativeTo, parsed.Path)
+ return FilePathToURI(absPath)
+ }
+ }
+
+ return uri, nil
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/stack/merge.go b/vendor/github.com/buildpacks/pack/internal/stack/merge.go
new file mode 100644
index 00000000000..7eb9b4321fd
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/stack/merge.go
@@ -0,0 +1,62 @@
+package stack
+
+import (
+ "sort"
+
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/stringset"
+)
+
+// MergeCompatible determines the allowable set of stacks that a combination of buildpacks may run on, given each
+// buildpack's set of stacks. Compatibility between the two sets of buildpack stacks is defined by the following rules:
+//
+// 1. The stack must be supported by both buildpacks. That is, any resulting stack ID must appear in both input sets.
+// 2. For each supported stack ID, all required mixins for all buildpacks must be provided by the result. That is,
+// mixins for the stack ID in both input sets are unioned.
+//
+// ---
+//
+// Examples:
+//
+// stacksA = [{ID: "stack1", mixins: ["build:mixinA", "mixinB", "run:mixinC"]}}]
+// stacksB = [{ID: "stack1", mixins: ["build:mixinA", "run:mixinC"]}}]
+// result = [{ID: "stack1", mixins: ["build:mixinA", "mixinB", "run:mixinC"]}}]
+//
+// stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
+// stacksB = [{ID: "stack1", mixins: ["run:mixinC"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
+// result = [{ID: "stack1", mixins: ["build:mixinA", "run:mixinC"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
+//
+// stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}, {ID: "stack2", mixins: ["mixinA"]}}]
+// stacksB = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
+// result = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
+//
+// stacksA = [{ID: "stack1", mixins: ["build:mixinA"]}}]
+// stacksB = [{ID: "stack2", mixins: ["mixinA", "run:mixinB"]}}]
+// result = []
+//
+func MergeCompatible(stacksA []dist.Stack, stacksB []dist.Stack) []dist.Stack {
+ set := map[string][]string{}
+
+ for _, s := range stacksA {
+ set[s.ID] = s.Mixins
+ }
+
+ var results []dist.Stack
+ for _, s := range stacksB {
+ if stackMixins, ok := set[s.ID]; ok {
+ mixinsSet := stringset.FromSlice(append(stackMixins, s.Mixins...))
+ var mixins []string
+ for s := range mixinsSet {
+ mixins = append(mixins, s)
+ }
+ sort.Strings(mixins)
+
+ results = append(results, dist.Stack{
+ ID: s.ID,
+ Mixins: mixins,
+ })
+ }
+ }
+
+ return results
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/stack/mixins.go b/vendor/github.com/buildpacks/pack/internal/stack/mixins.go
new file mode 100644
index 00000000000..b3e77c2827a
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/stack/mixins.go
@@ -0,0 +1,55 @@
+package stack
+
+import (
+ "fmt"
+ "sort"
+ "strings"
+
+ "github.com/buildpacks/pack/internal/stringset"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+const MixinsLabel = "io.buildpacks.stack.mixins"
+
+func ValidateMixins(buildImageName string, buildImageMixins []string, runImageName string, runImageMixins []string) error {
+ if invalid := FindStageMixins(buildImageMixins, "run"); len(invalid) > 0 {
+ sort.Strings(invalid)
+ return fmt.Errorf("%s contains run-only mixin(s): %s", style.Symbol(buildImageName), strings.Join(invalid, ", "))
+ }
+
+ if invalid := FindStageMixins(runImageMixins, "build"); len(invalid) > 0 {
+ sort.Strings(invalid)
+ return fmt.Errorf("%s contains build-only mixin(s): %s", style.Symbol(runImageName), strings.Join(invalid, ", "))
+ }
+
+ buildImageMixins = removeStageMixins(buildImageMixins, "build")
+ runImageMixins = removeStageMixins(runImageMixins, "run")
+
+ _, missing, _ := stringset.Compare(runImageMixins, buildImageMixins)
+
+ if len(missing) > 0 {
+ sort.Strings(missing)
+ return fmt.Errorf("%s missing required mixin(s): %s", style.Symbol(runImageName), strings.Join(missing, ", "))
+ }
+ return nil
+}
+
+func FindStageMixins(mixins []string, stage string) []string {
+ var found []string
+ for _, m := range mixins {
+ if strings.HasPrefix(m, stage+":") {
+ found = append(found, m)
+ }
+ }
+ return found
+}
+
+func removeStageMixins(mixins []string, stage string) []string {
+ var filtered []string
+ for _, m := range mixins {
+ if !strings.HasPrefix(m, stage+":") {
+ filtered = append(filtered, m)
+ }
+ }
+ return filtered
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/stringset/stringset.go b/vendor/github.com/buildpacks/pack/internal/stringset/stringset.go
new file mode 100644
index 00000000000..feb7842e7ae
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/stringset/stringset.go
@@ -0,0 +1,37 @@
+package stringset
+
+// FromSlice converts the given slice to a set in the form of unique keys in a map.
+// The value associated with each key should not be relied upon. A value is present
+// in the set if its key is present in the map, regardless of the key's value.
+func FromSlice(strings []string) map[string]interface{} {
+ set := map[string]interface{}{}
+ for _, s := range strings {
+ set[s] = nil
+ }
+ return set
+}
+
+// Compare performs a set comparison between two slices. `extra` represents elements present in
+// `strings1` but not `strings2`. `missing` represents elements present in `strings2` that are
+// missing from `strings1`. `common` represents elements present in both slices. Since the input
+// slices are treated as sets, duplicates will be removed in any outputs.
+func Compare(strings1, strings2 []string) (extra []string, missing []string, common []string) {
+ set1 := FromSlice(strings1)
+ set2 := FromSlice(strings2)
+
+ for s := range set1 {
+ if _, ok := set2[s]; !ok {
+ extra = append(extra, s)
+ continue
+ }
+ common = append(common, s)
+ }
+
+ for s := range set2 {
+ if _, ok := set1[s]; !ok {
+ missing = append(missing, s)
+ }
+ }
+
+ return extra, missing, common
+}
diff --git a/vendor/github.com/buildpacks/pack/internal/style/style.go b/vendor/github.com/buildpacks/pack/internal/style/style.go
new file mode 100644
index 00000000000..62d75fe7ab7
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/internal/style/style.go
@@ -0,0 +1,39 @@
+package style
+
+import (
+ "fmt"
+
+ "github.com/heroku/color"
+)
+
+var Noop = func(format string, a ...interface{}) string {
+ return color.WhiteString("") + fmt.Sprintf(format, a...)
+}
+
+var Symbol = func(format string, a ...interface{}) string {
+ if color.Enabled() {
+ return Key(format, a...)
+ }
+ return "'" + fmt.Sprintf(format, a...) + "'"
+}
+
+var Key = color.HiBlueString
+
+var Tip = color.New(color.FgGreen, color.Bold).SprintfFunc()
+
+var Warn = color.New(color.FgYellow, color.Bold).SprintfFunc()
+
+var Error = color.New(color.FgRed, color.Bold).SprintfFunc()
+
+var Step = func(format string, a ...interface{}) string {
+ return color.CyanString("===> "+format, a...)
+}
+
+var Prefix = color.CyanString
+
+var TimestampColorCode = color.FgHiBlack
+
+var Waiting = color.HiBlackString
+var Working = color.HiBlueString
+var Complete = color.GreenString
+var ProgressBar = color.HiBlueString
diff --git a/vendor/github.com/buildpacks/pack/logging/default_logger.go b/vendor/github.com/buildpacks/pack/logging/default_logger.go
new file mode 100644
index 00000000000..02684eebaac
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/logging/default_logger.go
@@ -0,0 +1,66 @@
+package logging
+
+import (
+ "fmt"
+ "io"
+ "log"
+)
+
+// New creates a default logger for the pack library. Note that the pack CLI has it's own logger.
+func New(w io.Writer) Logger {
+ return &defaultLogger{
+ out: log.New(w, "", log.LstdFlags|log.Lmicroseconds),
+ }
+}
+
+type defaultLogger struct {
+ out *log.Logger
+}
+
+const (
+ debugPrefix = "DEBUG:"
+ infoPrefix = "INFO:"
+ warnPrefix = "WARN:"
+ errorPrefix = "ERROR:"
+ prefixFmt = "%-7s %s"
+)
+
+func (l *defaultLogger) Debug(msg string) {
+ l.out.Printf(prefixFmt, debugPrefix, msg)
+}
+
+func (l *defaultLogger) Debugf(format string, v ...interface{}) {
+ l.out.Printf(prefixFmt, debugPrefix, fmt.Sprintf(format, v...))
+}
+
+func (l *defaultLogger) Info(msg string) {
+ l.out.Printf(prefixFmt, infoPrefix, msg)
+}
+
+func (l *defaultLogger) Infof(format string, v ...interface{}) {
+ l.out.Printf(prefixFmt, infoPrefix, fmt.Sprintf(format, v...))
+}
+
+func (l *defaultLogger) Warn(msg string) {
+ l.out.Printf(prefixFmt, warnPrefix, msg)
+}
+
+func (l *defaultLogger) Warnf(format string, v ...interface{}) {
+ l.out.Printf(prefixFmt, warnPrefix, fmt.Sprintf(format, v...))
+}
+
+func (l *defaultLogger) Error(msg string) {
+ l.out.Printf(prefixFmt, errorPrefix, msg)
+}
+
+func (l *defaultLogger) Errorf(format string, v ...interface{}) {
+ l.out.Printf(prefixFmt, errorPrefix, fmt.Sprintf(format, v...))
+}
+
+func (l *defaultLogger) Writer() io.Writer {
+ return l.out.Writer()
+}
+
+func (l *defaultLogger) IsVerbose() bool {
+ return false
+}
diff --git a/vendor/github.com/buildpacks/pack/logging/logger.go b/vendor/github.com/buildpacks/pack/logging/logger.go
new file mode 100644
index 00000000000..94212f393f9
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/logging/logger.go
@@ -0,0 +1,82 @@
+// Package logging defines the minimal interface that loggers must support to be used by pack.
+package logging
+
+import (
+ "fmt"
+ "io"
+
+ "github.com/buildpacks/pack/internal/style"
+)
+
+// Logger defines behavior required by a logging package used by pack libraries
+type Logger interface {
+ Debug(msg string)
+ Debugf(fmt string, v ...interface{})
+
+ Info(msg string)
+ Infof(fmt string, v ...interface{})
+
+ Warn(msg string)
+ Warnf(fmt string, v ...interface{})
+
+ Error(msg string)
+ Errorf(fmt string, v ...interface{})
+
+ Writer() io.Writer
+
+ IsVerbose() bool
+}
+
+// WithInfoErrorWriter is an optional interface for loggers that want to support a separate writer for errors and standard logging.
+// the DebugInfoWriter should write to stderr if quiet is false.
+type WithInfoErrorWriter interface {
+ InfoErrorWriter() io.Writer
+}
+
+// WithInfoWriter is an optional interface what will return a writer that will write raw output if quiet is false.
+type WithInfoWriter interface {
+ InfoWriter() io.Writer
+}
+
+// GetInfoErrorWriter will return an ErrorWriter, typically stderr if one exists, otherwise the standard logger writer
+// will be returned.
+func GetInfoErrorWriter(l Logger) io.Writer {
+ if er, ok := l.(WithInfoErrorWriter); ok {
+ return er.InfoErrorWriter()
+ }
+ return l.Writer()
+}
+
+// GetInfoWriter returns a writer
+// See WithInfoWriter
+func GetInfoWriter(l Logger) io.Writer {
+ if ew, ok := l.(WithInfoWriter); ok {
+ return ew.InfoWriter()
+ }
+ return l.Writer()
+}
+
+// PrefixWriter will prefix writes
+type PrefixWriter struct {
+ out io.Writer
+ prefix string
+}
+
+// NewPrefixWriter writes by w will be prefixed
+func NewPrefixWriter(w io.Writer, prefix string) *PrefixWriter {
+ return &PrefixWriter{
+ out: w,
+ prefix: fmt.Sprintf("[%s] ", style.Prefix(prefix)),
+ }
+}
+
+// Writes bytes to the embedded log function
+func (w *PrefixWriter) Write(buf []byte) (int, error) {
+ _, _ = fmt.Fprint(w.out, w.prefix+string(buf))
+ return len(buf), nil
+}
+
+// Tip logs a tip.
+func Tip(l Logger, format string, v ...interface{}) {
+ l.Infof(style.Tip("Tip: ")+format, v...)
+}
diff --git a/vendor/github.com/buildpacks/pack/pack.go b/vendor/github.com/buildpacks/pack/pack.go
new file mode 100644
index 00000000000..9b34f94edf7
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/pack.go
@@ -0,0 +1,74 @@
+package pack
+
+import (
+ "context"
+ "io"
+
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+func extractPackagedBuildpacks(ctx context.Context, pkgImageRef string, fetcher ImageFetcher, publish, noPull bool) ([]dist.Buildpack, error) {
+ pkgImage, err := fetcher.Fetch(ctx, pkgImageRef, !publish, !noPull)
+ if err != nil {
+ return nil, errors.Wrapf(err, "fetching image %s", style.Symbol(pkgImageRef))
+ }
+
+ bpLayers := dist.BuildpackLayers{}
+ ok, err := dist.GetLabel(pkgImage, dist.BuildpackLayersLabel, &bpLayers)
+ if err != nil {
+ return nil, err
+ }
+
+ if !ok {
+ return nil, errors.Errorf(
+ "label %s not present on package %s",
+ style.Symbol(dist.BuildpackLayersLabel),
+ style.Symbol(pkgImageRef),
+ )
+ }
+
+ var bps []dist.Buildpack
+ for bpID, v := range bpLayers {
+ for bpVersion, bpInfo := range v {
+ desc := dist.BuildpackDescriptor{
+ API: bpInfo.API,
+ Info: dist.BuildpackInfo{
+ ID: bpID,
+ Version: bpVersion,
+ },
+ Stacks: bpInfo.Stacks,
+ Order: bpInfo.Order,
+ }
+
+ diffID := bpInfo.LayerDiffID // Allow use in closure
+ b := &openerBlob{
+ opener: func() (io.ReadCloser, error) {
+ rc, err := pkgImage.GetLayer(diffID)
+ if err != nil {
+ return nil, errors.Wrapf(err,
+ "extracting buildpack %s layer (diffID %s) from package %s",
+ style.Symbol(desc.Info.FullName()),
+ style.Symbol(diffID),
+ style.Symbol(pkgImage.Name()),
+ )
+ }
+ return rc, nil
+ },
+ }
+
+ bps = append(bps, dist.BuildpackFromTarBlob(desc, b))
+ }
+ }
+ return bps, nil
+}
+
+type openerBlob struct {
+ opener func() (io.ReadCloser, error)
+}
+
+func (b *openerBlob) Open() (io.ReadCloser, error) {
+ return b.opener()
+}
diff --git a/vendor/github.com/buildpacks/pack/rebase.go b/vendor/github.com/buildpacks/pack/rebase.go
new file mode 100644
index 00000000000..46dd15828f6
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/rebase.go
@@ -0,0 +1,74 @@
+package pack
+
+import (
+ "context"
+
+ "github.com/buildpacks/lifecycle"
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/builder"
+ "github.com/buildpacks/pack/internal/dist"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type RebaseOptions struct {
+ RepoName string
+ Publish bool
+ SkipPull bool
+ RunImage string
+ AdditionalMirrors map[string][]string
+}
+
+func (c *Client) Rebase(ctx context.Context, opts RebaseOptions) error {
+ imageRef, err := c.parseTagReference(opts.RepoName)
+ if err != nil {
+ return errors.Wrapf(err, "invalid image name '%s'", opts.RepoName)
+ }
+
+ appImage, err := c.imageFetcher.Fetch(ctx, opts.RepoName, !opts.Publish, !opts.SkipPull)
+ if err != nil {
+ return err
+ }
+
+ var md lifecycle.LayersMetadataCompat
+ if ok, err := dist.GetLabel(appImage, lifecycle.LayerMetadataLabel, &md); err != nil {
+ return err
+ } else if !ok {
+ return errors.Errorf("could not find label %s on image", style.Symbol(lifecycle.LayerMetadataLabel))
+ }
+
+ runImageName := c.resolveRunImage(
+ opts.RunImage,
+ imageRef.Context().RegistryStr(),
+ builder.StackMetadata{
+ RunImage: builder.RunImageMetadata{
+ Image: md.Stack.RunImage.Image,
+ Mirrors: md.Stack.RunImage.Mirrors,
+ },
+ },
+ opts.AdditionalMirrors)
+
+ if runImageName == "" {
+ return errors.New("run image must be specified")
+ }
+
+ baseImage, err := c.imageFetcher.Fetch(ctx, runImageName, !opts.Publish, !opts.SkipPull)
+ if err != nil {
+ return err
+ }
+
+ c.logger.Infof("Rebasing %s on run image %s", style.Symbol(appImage.Name()), style.Symbol(baseImage.Name()))
+ rebaser := &lifecycle.Rebaser{Logger: c.logger}
+ err = rebaser.Rebase(appImage, baseImage, nil)
+ if err != nil {
+ return err
+ }
+
+ appImageIdentifier, err := appImage.Identifier()
+ if err != nil {
+ return err
+ }
+
+ c.logger.Infof("Rebased Image: %s", style.Symbol(appImageIdentifier.String()))
+ return nil
+}
diff --git a/vendor/github.com/buildpacks/pack/run.go b/vendor/github.com/buildpacks/pack/run.go
new file mode 100644
index 00000000000..d35ed8674d6
--- /dev/null
+++ b/vendor/github.com/buildpacks/pack/run.go
@@ -0,0 +1,48 @@
+package pack
+
+import (
+ "context"
+ "crypto/sha256"
+ "fmt"
+
+ "github.com/pkg/errors"
+
+ "github.com/buildpacks/pack/internal/app"
+ "github.com/buildpacks/pack/internal/style"
+)
+
+type RunOptions struct {
+ AppPath string // defaults to current working directory
+ Builder string // defaults to default builder on the client config
+ RunImage string // defaults to the best mirror from the builder image
+ Env map[string]string
+ NoPull bool
+ ClearCache bool
+ Buildpacks []string
+ Ports []string
+}
+
+func (c *Client) Run(ctx context.Context, opts RunOptions) error {
+ appPath, err := c.processAppPath(opts.AppPath)
+ if err != nil {
+ return errors.Wrapf(err, "invalid app dir '%s'", opts.AppPath)
+ }
+ sum := sha256.Sum256([]byte(appPath))
+ imageName := fmt.Sprintf("pack.local/run/%x", sum[:8])
+ err = c.Build(ctx, BuildOptions{
+ AppPath: appPath,
+ Builder: opts.Builder,
+ RunImage: opts.RunImage,
+ Env: opts.Env,
+ Image: imageName,
+ NoPull: opts.NoPull,
+ ClearCache: opts.ClearCache,
+ Buildpacks: opts.Buildpacks,
+ })
+ if err != nil {
+ return errors.Wrap(err, "build failed")
+ }
+ appImage := &app.Image{RepoName: imageName, Logger: c.logger}
+ c.logger.Debug(style.Step("RUNNING"))
+ return appImage.Run(ctx, c.docker, opts.Ports)
+}
diff --git a/vendor/github.com/heroku/color/.gitignore b/vendor/github.com/heroku/color/.gitignore
new file mode 100644
index 00000000000..ed3ac085ae5
--- /dev/null
+++ b/vendor/github.com/heroku/color/.gitignore
@@ -0,0 +1,16 @@
+# Binaries for programs and plugins
+*.exe
+*.exe~
+*.dll
+*.so
+*.dylib
+
+# Test binary, build with `go test -c`
+*.test
+
+# Output of the go coverage tool, specifically when used with LiteIDE
+*.out
+.idea/
+c.out
+*.test
+*.prof
\ No newline at end of file
diff --git a/vendor/github.com/heroku/color/.golangcli.yml b/vendor/github.com/heroku/color/.golangcli.yml
new file mode 100644
index 00000000000..b9bd6501351
--- /dev/null
+++ b/vendor/github.com/heroku/color/.golangcli.yml
@@ -0,0 +1,26 @@
+run:
+ concurrency: 4
+
+linter-settings:
+ goimports:
+ local-prefixes: github.com/heroku/code
+ lll:
+ line-length: 110
+
+
+linters:
+ enable-all: true
+ disable:
+ - golint
+ - maligned
+ - gochecknoglobals
+
+issues:
+ exclude-rules:
+ - path: _test\.go
+ linters:
+ - scopelint
+ - funlen
+ - path: color\.go
+ linters:
+ - gocritic
diff --git a/vendor/github.com/heroku/color/LICENSE b/vendor/github.com/heroku/color/LICENSE
new file mode 100644
index 00000000000..d23abe74002
--- /dev/null
+++ b/vendor/github.com/heroku/color/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Heroku
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/vendor/github.com/heroku/color/Makefile b/vendor/github.com/heroku/color/Makefile
new file mode 100644
index 00000000000..17c681e420e
--- /dev/null
+++ b/vendor/github.com/heroku/color/Makefile
@@ -0,0 +1,21 @@
+PROJECT_ROOT := $(shell pwd)
+
+.PHONY: test bench fmt lint
+
+test:
+ @go test -race -coverprofile c.out -cpuprofile=cpu2.prof github.com/heroku/color
+
+bench:
+ @go test -bench=. -count=5 -cpu=1,2,4,8 -cpuprofile=cpu.prof github.com/heroku/color
+
+cover: test
+ @go tool cover -html=c.out
+
+lint: $(GOPATH)/bin/golangci-lint
+ @echo "--> Running linter with default config"
+ @golangci-lint run --deadline 3m0s -c $(PROJECT_ROOT)/.golangcli.yml
+
+$(GOPATH)/bin/golangci-lint:
+ @echo "--> Installing linter"
+ curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(shell go env GOPATH)/bin v1.18.0
+
diff --git a/vendor/github.com/heroku/color/README.md b/vendor/github.com/heroku/color/README.md
new file mode 100644
index 00000000000..52c1644bc49
--- /dev/null
+++ b/vendor/github.com/heroku/color/README.md
@@ -0,0 +1,109 @@
+# Color [![GoDoc](https://godoc.org/github.com/heroku/color?status.svg)](https://godoc.org/github.com/heroku/color) [![CircleCI](https://circleci.com/gh/heroku/color.svg?style=svg)](https://circleci.com/gh/heroku/color)
+
+Color is based on the [github.com/fatih/color](https://github.com/fatih/color) package. Unfortunately the original
+color package is archived and is no longer supported. Like the original, this package lets you use colorized outputs in
+terms of [ANSI Escape Codes](http://en.wikipedia.org/wiki/ANSI_escape_code#Colors) in Golang but offers a number of
+improvements from the original. Posix and Windows platforms are supported.
+
+Color seeks to remain *mostly* backward compatible with fatih/color but has a number of changes to support concurrency,
+improved performance and a more idiomatic style.
+
+## Changes And Improvements
+
+The methods of the new `Color` struct do not mutate the sender. This
+results in better concurrency support and improved performance.
+
+You don't need to remember to wrap io.Writer arguments in `colorable.NewColorable` in order to support Windows functionality.
+
+Package public global variables are removed. `color.NoColor` was removed and replaced with the `Disable` function.
+ Colored output can be toggled using the `Disable`. `color.Output` and `color.Error`replaced by `Stdout()` and `Stderr()`
+.
+
+Instances of `Console` can be passed to methods in third party packages that take `io.Writer` as an argument. If the
+ third party package emits ANSI color information the passed in writer will be interpreted correctly on Windows. In
+ addition, color information can be stripped for a console by calling `Console.DisableColors(true)`.
+
+Performance is improved significantly, as much as 400%. Note that some functions that you'd expect to take an
+array of interface{} take an array of strings instead because underlying calls to fmt.SprintXX functions are slow.
+
+`fatih/color` has race conditions. This package was developed with `test.Parallel` and `-race` enabled for tests. Thus
+far no race conditions are known and so this package is suitable for use in a multi goroutine environment.
+
+## Examples
+
+### Standard colors
+
+```go
+// Print with default helper functions
+color.Cyan("Prints text in cyan.")
+
+// A newline will be appended automatically
+color.Blue("Prints %s in blue.", "text")
+```
+
+### Mix and reuse colors
+
+```go
+// Create a new color object
+color.Stdout().Println(color.New(color.FgCyan, color.Underline), "Prints cyan text with an underline.")
+```
+
+### Use your own output (io.Writer)
+
+```go
+// Use your own io.Writer output
+wtr := color.NewConsole(os.Stderr)
+wtr.Println(color.New(color.FgBlue), "Hello! I'm blue.")
+```
+
+### Custom print functions (PrintFunc)
+
+```go
+// Create a custom print function for convenience
+red := color.StdErr().PrintfFunc(color.New(color.FgRed))
+red("Warning")
+red("Error: %s", err)
+
+// Mix up multiple attributes
+notice := color.Stdout().PrintlnFunc(color.New(color.Bold, color.FgGreen))
+notice("Don't forget this...")
+```
+### Insert into noncolor strings (SprintFunc)
+
+```go
+// Create SprintXxx functions to mix strings with other non-colorized strings:
+yellow := color.New(color.FgYellow).SprintFunc()
+red := color.New(color.FgRed).SprintFunc()
+fmt.Printf("This is a %s and this is %s.\n", yellow("warning"), red("error"))
+
+info := color.New(color.FgWhite, color.BgGreen).SprintFunc()
+fmt.Printf("This %s rocks!\n", info("package"))
+
+// Use helper functions
+fmt.Println("This", color.RedString("warning"), "should be not neglected.")
+fmt.Printf("%v %v\n", color.GreenString("Info:"), "an important message.")
+```
+### Disable/Enable color
+
+There might be a case where you want to explicitly disable/enable color output.
+
+`Color` has support to disable/enable colors on a per `Console` basis.
+For example suppose you have a CLI app and a `--no-color` bool flag. You
+can easily disable the color output with:
+
+```go
+
+var flagNoColor = flag.Bool("no-color", false, "Disable color output")
+color.Stdout().DisableColors(*flagNoColor)
+
+```
+## Credits
+
+ * [Fatih Arslan](https://github.com/fatih)
+ * Windows support via @mattn: [colorable](https://github.com/mattn/go-colorable)
+
+## License
+
+The MIT License (MIT) - see [`LICENSE.md`](https://github.com/heroku/color/blob/master/LICENSE) for more details
+
+
diff --git a/vendor/github.com/heroku/color/attributes.go b/vendor/github.com/heroku/color/attributes.go
new file mode 100644
index 00000000000..552b88b6b19
--- /dev/null
+++ b/vendor/github.com/heroku/color/attributes.go
@@ -0,0 +1,175 @@
+package color
+
+import (
+ "fmt"
+)
+
+// Attribute defines a single SGR Code.
+type Attribute uint64
+
+// String returns color code as a string.
+func (a Attribute) String() string {
+ return attributeToSGRCode[a]
+}
+
+// Name returns a human readable name for an Attribute.
+func (a Attribute) Name() string {
+ m := map[Attribute]string{
+ Reset: "Reset",
+ Bold: "Bold",
+ Faint: "Faint",
+ Italic: "Italic",
+ Underline: "Underline",
+ BlinkSlow: "BlinkSlow",
+ BlinkRapid: "BlinkRapid",
+ ReverseVideo: "ReverseVideo",
+ Concealed: "Concealed",
+ CrossedOut: "CrossedOut",
+ FgBlack: "FgBlack",
+ FgRed: "FgRed",
+ FgGreen: "FgGreen",
+ FgYellow: "FgYellow",
+ FgBlue: "FgBlue",
+ FgMagenta: "FgMagenta",
+ FgCyan: "FgCyan",
+ FgWhite: "FgWhite",
+ FgHiBlack: "FgHiBlack",
+ FgHiRed: "FgHiRed",
+ FgHiGreen: "FgHiGreen",
+ FgHiYellow: "FgHiYellow",
+ FgHiBlue: "FgHiBlue",
+ FgHiMagenta: "FgHiMagenta",
+ FgHiCyan: "FgHiCyan",
+ FgHiWhite: "FgHiWhite",
+ BgBlack: "BgBlack",
+ BgRed: "BgRed",
+ BgGreen: "BgGreen",
+ BgYellow: "BgYellow",
+ BgBlue: "BgBlue",
+ BgMagenta: "BgMagenta",
+ BgCyan: "BgCyan",
+ BgWhite: "BgWhite",
+ BgHiBlack: "BgHiBlack",
+ BgHiRed: "BgHiRed",
+ BgHiGreen: "BgHiGreen",
+ BgHiYellow: "BgHiYellow",
+ BgHiBlue: "BgHiBlue",
+ BgHiMagenta: "BgHiMagenta",
+ BgHiCyan: "BgHiCyan",
+ BgHiWhite: "BgHiWhite",
+ }
+ if s, ok := m[a]; ok {
+ return s
+ }
+ return fmt.Sprintf("unknown color %d", a)
+}
+
+const (
+ Reset Attribute = 1 << iota
+ Bold
+ Faint
+ Italic
+ Underline
+ BlinkSlow
+ BlinkRapid
+ ReverseVideo
+ Concealed
+ CrossedOut
+ FgBlack
+ FgRed
+ FgGreen
+ FgYellow
+ FgBlue
+ FgMagenta
+ FgCyan
+ FgWhite
+ FgHiBlack
+ FgHiRed
+ FgHiGreen
+ FgHiYellow
+ FgHiBlue
+ FgHiMagenta
+ FgHiCyan
+ FgHiWhite
+ BgBlack
+ BgRed
+ BgGreen
+ BgYellow
+ BgBlue
+ BgMagenta
+ BgCyan
+ BgWhite
+ BgHiBlack
+ BgHiRed
+ BgHiGreen
+ BgHiYellow
+ BgHiBlue
+ BgHiMagenta
+ BgHiCyan
+ BgHiWhite
+)
+
+var attributeToSGRCode = map[Attribute]string{
+ Reset: "0",
+ Bold: "1",
+ Faint: "2",
+ Italic: "3",
+ Underline: "4",
+ BlinkSlow: "5",
+ BlinkRapid: "6",
+ ReverseVideo: "7",
+ Concealed: "8",
+ CrossedOut: "9",
+ FgBlack: "30",
+ FgRed: "31",
+ FgGreen: "32",
+ FgYellow: "33",
+ FgBlue: "34",
+ FgMagenta: "35",
+ FgCyan: "36",
+ FgWhite: "37",
+ BgBlack: "40",
+ BgRed: "41",
+ BgGreen: "42",
+ BgYellow: "43",
+ BgBlue: "44",
+ BgMagenta: "45",
+ BgCyan: "46",
+ BgWhite: "47",
+ FgHiBlack: "90",
+ FgHiRed: "91",
+ FgHiGreen: "92",
+ FgHiYellow: "93",
+ FgHiBlue: "94",
+ FgHiMagenta: "95",
+ FgHiCyan: "96",
+ FgHiWhite: "97",
+ BgHiBlack: "100",
+ BgHiRed: "101",
+ BgHiGreen: "102",
+ BgHiYellow: "103",
+ BgHiBlue: "104",
+ BgHiMagenta: "105",
+ BgHiCyan: "106",
+ BgHiWhite: "107",
+}
+
+func to_codes(attrs []Attribute) []string {
+ codes := make([]string, len(attrs))
+ for i := 0; i < len(attrs); i++ {
+ code, ok := attributeToSGRCode[attrs[i]]
+ if !ok {
+ return nil
+ }
+ codes[i] = code
+ }
+ return codes
+}
+
+func to_key(attr []Attribute) Attribute {
+ var key Attribute
+ for i := 0; i < len(attr); i++ {
+ key |= attr[i]
+ }
+ return key
+}
diff --git a/vendor/github.com/heroku/color/cache.go b/vendor/github.com/heroku/color/cache.go
new file mode 100644
index 00000000000..60c58f3ae9f
--- /dev/null
+++ b/vendor/github.com/heroku/color/cache.go
@@ -0,0 +1,53 @@
+package color
+
+import "sync"
+
+var cacheSingleton *colorCache
+var cacheOnce sync.Once
+
+func cache() *colorCache {
+ cacheOnce.Do(func() {
+ cacheSingleton = &colorCache{
+ cache: make(colorMap),
+ }
+ })
+ return cacheSingleton
+}
+
+type colorMap map[Attribute]*Color
+
+type colorCache struct {
+ sync.RWMutex
+ cache colorMap
+}
+
+func (cc *colorCache) value(attrs ...Attribute) *Color {
+ key := to_key(attrs)
+ if v := cc.getIfExists(key); v != nil {
+ return v
+ }
+ cc.Lock()
+ v := &Color{
+ colorStart: chainSGRCodes(attrs),
+ }
+ cc.cache[key] = v
+ cc.Unlock()
+ return v
+}
+
+func (vc *colorCache) getIfExists(key Attribute) *Color {
+ vc.RLock()
+ if v, ok := vc.cache[key]; ok {
+ vc.RUnlock()
+ return v
+
+ }
+ vc.RUnlock()
+ return nil
+}
+
+func (vc *colorCache) clear() {
+ vc.Lock()
+ defer vc.Unlock()
+ vc.cache = make(colorMap)
+}
diff --git a/vendor/github.com/heroku/color/color.go b/vendor/github.com/heroku/color/color.go
new file mode 100644
index 00000000000..ca6d5cc2e71
--- /dev/null
+++ b/vendor/github.com/heroku/color/color.go
@@ -0,0 +1,271 @@
+package color
+
+import (
+ "fmt"
+ "strings"
+)
+
+const (
+ escape = "\x1b["
+ endCode = "m"
+ lineFeed = "\n"
+ delimiter = ";"
+ colorReset = "\x1b[0m"
+)
+
+func chainSGRCodes(a []Attribute) string {
+ codes := to_codes(a)
+ if len(codes) == 0 {
+ return colorReset
+ }
+ if len(codes) == 1 {
+ return escape + codes[0] + endCode
+ }
+ var bld strings.Builder
+ bld.Grow((len(codes) * 2) + len(escape) + len(endCode))
+ bld.WriteString(escape)
+ delimsAdded := 0
+ for i := 0; i < len(a); i++ {
+ if delimsAdded > 0 {
+ _, _ = bld.WriteString(delimiter)
+ }
+ bld.WriteString(codes[i])
+ delimsAdded++
+ }
+ bld.WriteString(endCode)
+ return bld.String()
+}
+
+// Color contains methods to create colored strings of text.
+type Color struct {
+ colorStart string
+}
+
+// New creates a Color. It takes a list of Attributes to define
+// the appearance of output.
+func New(attrs ...Attribute) *Color {
+ return cache().value(attrs...)
+}
+
+// Sprint returns text decorated with the display Attributes passed to Color constructor function.
+func (v Color) Sprint(a ...interface{}) string {
+ if Enabled() {
+ return v.wrap(fmt.Sprint(a...))
+ }
+ return fmt.Sprint(a...)
+}
+
+// Sprint formats according to the format specifier and returns text decorated with the display Attributes
+// passed to Color constructor function.
+func (v Color) Sprintf(format string, a ...interface{}) string {
+ if Enabled() {
+ return v.wrap(fmt.Sprintf(format, a...))
+ }
+ return fmt.Sprintf(format, a...)
+}
+
+// Sprint returns text decorated with the display Attributes and terminated by a line feed.
+func (v Color) Sprintln(a ...interface{}) string {
+ var s string
+ if Enabled() {
+ s = v.wrap(fmt.Sprint(a...))
+ } else {
+ s = fmt.Sprint(a...)
+ }
+ if !strings.HasSuffix(s, lineFeed) {
+ s += lineFeed
+ }
+ return s
+}
+
+// SprintFunc returns function that wraps Sprint.
+func (v Color) SprintFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return v.Sprint(a...)
+ }
+}
+
+// SprintfFunc returns function that wraps Sprintf.
+func (v Color) SprintfFunc() func(format string, a ...interface{}) string {
+ return func(format string, a ...interface{}) string {
+ return v.Sprintf(format, a...)
+ }
+}
+
+// SprintlnFunc returns function that wraps Sprintln.
+func (v Color) SprintlnFunc() func(a ...interface{}) string {
+ return func(a ...interface{}) string {
+ return v.Sprintln(a...)
+ }
+}
+
+func (v Color) wrap(s ...string) string {
+ var b strings.Builder
+ b.Grow(len(v.colorStart) + len(s) + len(colorReset))
+ b.WriteString(v.colorStart)
+ for i := 0; i < len(s); i++ {
+ b.WriteString(s[i])
+ }
+ b.WriteString(colorReset)
+ return b.String()
+}
+
+func colorString(format string, attr Attribute, a ...interface{}) string {
+ return cache().value(attr).Sprintf(format, a...)
+}
+
+// Black helper to produce black text to stdout.
+func Black(format string, a ...interface{}) { Stdout().colorPrint(format, FgBlack, a...) }
+
+// BlackE helper to produce black text to stderr.
+func BlackE(format string, a ...interface{}) { Stderr().colorPrint(format, FgBlack, a...) }
+
+// Red helper to produce red text to stdout.
+func Red(format string, a ...interface{}) { Stdout().colorPrint(format, FgRed, a...) }
+
+// RedE helper to produce red text to stderr.
+func RedE(format string, a ...interface{}) { Stderr().colorPrint(format, FgRed, a...) }
+
+// Green helper to produce green text to stdout.
+func Green(format string, a ...interface{}) { Stdout().colorPrint(format, FgGreen, a...) }
+
+// GreenE helper to produce green text to stderr.
+func GreenE(format string, a ...interface{}) { Stderr().colorPrint(format, FgGreen, a...) }
+
+// Yellow helper to produce yellow text to stdout.
+func Yellow(format string, a ...interface{}) { Stdout().colorPrint(format, FgYellow, a...) }
+
+// YellowE helper to produce yellow text to stderr.
+func YellowE(format string, a ...interface{}) { Stderr().colorPrint(format, FgYellow, a...) }
+
+// Blue helper to produce blue text to stdout.
+func Blue(format string, a ...interface{}) { Stdout().colorPrint(format, FgBlue, a...) }
+
+// BlueE helper to produce blue text to stderr.
+func BlueE(format string, a ...interface{}) { Stderr().colorPrint(format, FgBlue, a...) }
+
+// Magenta helper to produce magenta text to stdout.
+func Magenta(format string, a ...interface{}) { Stdout().colorPrint(format, FgMagenta, a...) }
+
+// MagentaE produces magenta text to stderr.
+func MagentaE(format string, a ...interface{}) { Stderr().colorPrint(format, FgMagenta, a...) }
+
+// Cyan helper to produce cyan text to stdout.
+func Cyan(format string, a ...interface{}) { Stdout().colorPrint(format, FgCyan, a...) }
+
+// CyanE helper to produce cyan text to stderr.
+func CyanE(format string, a ...interface{}) { Stderr().colorPrint(format, FgCyan, a...) }
+
+// White helper to produce white text to stdout.
+func White(format string, a ...interface{}) { Stdout().colorPrint(format, FgWhite, a...) }
+
+// WhiteE helper to produce white text to stderr.
+func WhiteE(format string, a ...interface{}) { Stderr().colorPrint(format, FgWhite, a...) }
+
+// BlackString returns a string decorated with black attributes.
+func BlackString(format string, a ...interface{}) string { return colorString(format, FgBlack, a...) }
+
+// RedString returns a string decorated with red attributes.
+func RedString(format string, a ...interface{}) string { return colorString(format, FgRed, a...) }
+
+// GreenString returns a string decorated with green attributes.
+func GreenString(format string, a ...interface{}) string { return colorString(format, FgGreen, a...) }
+
+// YellowString returns a string decorated with yellow attributes.
+func YellowString(format string, a ...interface{}) string { return colorString(format, FgYellow, a...) }
+
+// BlueString returns a string decorated with blue attributes.
+func BlueString(format string, a ...interface{}) string { return colorString(format, FgBlue, a...) }
+
+// MagentaString returns a string decorated with magenta attributes.
+func MagentaString(format string, a ...interface{}) string {
+ return colorString(format, FgMagenta, a...)
+}
+
+// CyanString returns a string decorated with cyan attributes.
+func CyanString(format string, a ...interface{}) string { return colorString(format, FgCyan, a...) }
+
+// WhiteString returns a string decorated with white attributes.
+func WhiteString(format string, a ...interface{}) string { return colorString(format, FgWhite, a...) }
+
+// HiBlack helper to produce black text to stdout.
+func HiBlack(format string, a ...interface{}) { Stdout().colorPrint(format, FgHiBlack, a...) }
+
+// HiBlackE helper to produce black text to stderr.
+func HiBlackE(format string, a ...interface{}) { Stderr().colorPrint(format, FgHiBlack, a...) }
+
+// HiRed helper to write high contrast red text to stdout.
+func HiRed(format string, a ...interface{}) { Stdout().colorPrint(format, FgHiRed, a...) }
+
+// HiRedE helper to write high contrast red text to stderr.
+func HiRedE(format string, a ...interface{}) { Stderr().colorPrint(format, FgHiRed, a...) }
+
+// HiGreen helper writes high contrast green text to stdout.
+func HiGreen(format string, a ...interface{}) { Stdout().colorPrint(format, FgHiGreen, a...) }
+
+// HiGreenE helper writes high contrast green text to stderr.
+func HiGreenE(format string, a ...interface{}) { Stderr().colorPrint(format, FgHiGreen, a...) }
+
+// HiYellow helper writes high contrast yellow text to stdout.
+func HiYellow(format string, a ...interface{}) { Stdout().colorPrint(format, FgHiYellow, a...) }
+
+// HiYellowE helper writes high contrast yellow text to stderr.
+func HiYellowE(format string, a ...interface{}) { Stderr().colorPrint(format, FgHiYellow, a...) }
+
+// HiBlue helper writes high contrast blue text to stdout.
+func HiBlue(format string, a ...interface{}) { Stdout().colorPrint(format, FgHiBlue, a...) }
+
+// HiBlueE helper writes high contrast blue text to stderr.
+func HiBlueE(format string, a ...interface{}) { Stderr().colorPrint(format, FgHiBlue, a...) }
+
+// HiMagenta writes high contrast magenta text to stdout.
+func HiMagenta(format string, a ...interface{}) { Stdout().colorPrint(format, FgHiMagenta, a...) }
+
+// HiMagentaE writes high contrast magenta text to stderr.
+func HiMagentaE(format string, a ...interface{}) { Stderr().colorPrint(format, FgHiMagenta, a...) }
+
+// HiCyan writes high contrast cyan colored text to stdout.
+func HiCyan(format string, a ...interface{}) { Stdout().colorPrint(format, FgHiCyan, a...) }
+
+// HiCyanE writes high contrast contrast cyan colored text to stderr.
+func HiCyanE(format string, a ...interface{}) { Stderr().colorPrint(format, FgHiCyan, a...) }
+
+// HiWhite writes high contrast white colored text to stdout.
+func HiWhite(format string, a ...interface{}) { Stdout().colorPrint(format, FgHiWhite, a...) }
+
+// HiWhiteE writes high contrast white colored text to stderr.
+func HiWhiteE(format string, a ...interface{}) { Stderr().colorPrint(format, FgHiWhite, a...) }
+
+// HiBlackString returns a high contrast black string.
+func HiBlackString(format string, a ...interface{}) string {
+ return colorString(format, FgHiBlack, a...)
+}
+
+// HiRedString returns a high contrast contrast black string.
+func HiRedString(format string, a ...interface{}) string { return colorString(format, FgHiRed, a...) }
+
+// HiGreenString returns a high contrast green string.
+func HiGreenString(format string, a ...interface{}) string {
+ return colorString(format, FgHiGreen, a...)
+}
+
+// HiYellowString returns a high contrast yellow string.
+func HiYellowString(format string, a ...interface{}) string {
+ return colorString(format, FgHiYellow, a...)
+}
+
+// HiBlueString returns a high contrast blue string.
+func HiBlueString(format string, a ...interface{}) string { return colorString(format, FgHiBlue, a...) }
+
+// HiMagentaString returns a high contrast magenta string.
+func HiMagentaString(format string, a ...interface{}) string {
+ return colorString(format, FgHiMagenta, a...)
+}
+
+// HiCyanString returns a high contrast cyan string.
+func HiCyanString(format string, a ...interface{}) string { return colorString(format, FgHiCyan, a...) }
+
+// HiWhiteString returns a high contrast white string.
+func HiWhiteString(format string, a ...interface{}) string {
+ return colorString(format, FgHiWhite, a...)
+}
diff --git a/vendor/github.com/heroku/color/console.go b/vendor/github.com/heroku/color/console.go
new file mode 100644
index 00000000000..031a7442ee0
--- /dev/null
+++ b/vendor/github.com/heroku/color/console.go
@@ -0,0 +1,167 @@
+// Package color produces colored output in terms of ANSI Escape Codes. Posix and Windows platforms are supported.
+package color
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+ "sync"
+
+ "github.com/mattn/go-colorable"
+)
+
+var noColor bool
+var noColorLock sync.RWMutex
+
+// Disable is used to turn color output on and off globally.
+func Disable(flag bool) {
+ noColorLock.Lock()
+ defer noColorLock.Unlock()
+ noColor = flag
+}
+
+// Enabled returns flag indicating whether colors are enabled or not.
+func Enabled() bool {
+ noColorLock.RLock()
+ defer noColorLock.RUnlock()
+ return !noColor
+}
+
+var stdout *Console // Don't use directly use Stdout() instead.
+var stdoutOnce sync.Once
+
+// Stdout returns an io.Writer that writes colored text to standard out.
+func Stdout() *Console {
+ stdoutOnce.Do(func() {
+ stdout = NewConsole(os.Stdout)
+ })
+ return stdout
+}
+
+var stderr *Console // Don't use directly use Stderr() instead.
+var stderrOnce sync.Once
+
+// Stderr returns an io.Writer that writes colored text to standard error.
+func Stderr() *Console {
+ stderrOnce.Do(func() {
+ stderr = NewConsole(os.Stderr)
+ })
+ return stderr
+}
+
+// Console manages state for output, typically stdout or stderr.
+type Console struct {
+ sync.Mutex
+ colored io.Writer
+ noncolored io.Writer
+ current io.Writer
+ fileDescriptor uintptr
+}
+
+// NewConsole creates a wrapper around out which will output platform independent colored text.
+func NewConsole(out *os.File) *Console {
+ c := &Console{
+ colored: colorable.NewColorable(out),
+ noncolored: colorable.NewNonColorable(out),
+ fileDescriptor: out.Fd(),
+ }
+ if Enabled() {
+ c.current = c.colored
+ return c
+ }
+ c.current = c.noncolored
+ return c
+}
+
+func (c *Console) Fd() uintptr {
+ c.Lock()
+ defer c.Unlock()
+ return c.fileDescriptor
+}
+
+// DisableColors if true ANSI color information will be removed for this console object. Passing true will enable
+// colors for this Console, even if colors are disabled globally.
+func (c *Console) DisableColors(strip bool) {
+ c.Lock()
+ defer c.Unlock()
+ if strip {
+ c.current = c.noncolored
+ return
+ }
+ c.current = c.colored
+}
+
+// Set will cause the color passed in as an argument to be written until Unset is called.
+func (c *Console) Set(color *Color) {
+ c.Lock()
+ defer c.Unlock()
+ _, _ = c.current.Write([]byte(color.colorStart))
+}
+
+// Unset will restore console output to default. It will undo colored console output defined from a call to Set.
+func (c *Console) Unset() {
+ c.Lock()
+ defer c.Unlock()
+ _, _ = c.current.Write([]byte(colorReset))
+}
+
+// Write so we can treat a console as a Writer
+func (c *Console) Write(b []byte) (int, error) {
+ c.Lock()
+ n, err := c.current.Write(b)
+ c.Unlock()
+ return n, err
+}
+
+// Print writes colored text to the console. The number of bytes written
+// is returned.
+func (c *Console) Print(col *Color, args ...string) (int, error) {
+ return c.Write([]byte(col.wrap(args...)))
+}
+
+// Printf formats according to a format specifier and writes colored text to the console.
+func (c *Console) Printf(col *Color, format string, args ...interface{}) (int, error) {
+ return c.Write([]byte(col.wrap(fmt.Sprintf(format, args...))))
+}
+
+// Println writes colored text to console, appending input with a line feed.
+// The number of bytes written is returned.
+func (c *Console) Println(col *Color, args ...string) (int, error) {
+ s := col.wrap(args...)
+ if !strings.HasSuffix(s, lineFeed) {
+ s += lineFeed
+ }
+ return c.Write([]byte(s))
+
+}
+
+// PrintFunc returns a wrapper function for Print.
+func (c *Console) PrintFunc(col *Color) func(a ...string) {
+ return func(a ...string) {
+ _, _ = c.Print(col, a...)
+ }
+}
+
+// PrintfFunc returns a wrapper function for Printf.
+func (c *Console) PrintfFunc(col *Color) func(format string, args ...interface{}) {
+ return func(format string, s ...interface{}) {
+ _, _ = c.Printf(col, format, s...)
+ }
+}
+
+// PrintlnFunc returns a wrapper function for Println.
+func (c *Console) PrintlnFunc(col *Color) func(a ...string) {
+ return func(a ...string) {
+ _, _ = c.Println(col, a...)
+ }
+}
+
+func (c *Console) colorPrint(format string, attr Attribute, a ...interface{}) {
+ col := cache().value(attr)
+ if !strings.HasSuffix(format, lineFeed) {
+ _, _ = c.Println(col, fmt.Sprintf(format, a...))
+ return
+ }
+ _, _ = c.Printf(col, format, fmt.Sprint(a...))
+}
diff --git a/vendor/github.com/heroku/color/go.mod b/vendor/github.com/heroku/color/go.mod
new file mode 100644
index 00000000000..d9507de7f80
--- /dev/null
+++ b/vendor/github.com/heroku/color/go.mod
@@ -0,0 +1,5 @@
+module github.com/heroku/color
+
+go 1.13
+
+require github.com/mattn/go-colorable v0.1.2
diff --git a/vendor/github.com/heroku/color/go.sum b/vendor/github.com/heroku/color/go.sum
new file mode 100644
index 00000000000..0a92752b3a7
--- /dev/null
+++ b/vendor/github.com/heroku/color/go.sum
@@ -0,0 +1,6 @@
+github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU=
+github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
+github.com/mattn/go-isatty v0.0.8 h1:HLtExJ+uU2HOZ+wI0Tt5DtUDrx8yhUqDcp7fYERX4CE=
+github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223 h1:DH4skfRX4EBpamg7iV4ZlCpblAHI6s6TDM39bFZumv8=
+golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
diff --git a/vendor/github.com/mitchellh/ioprogress/LICENSE b/vendor/github.com/mitchellh/ioprogress/LICENSE
new file mode 100644
index 00000000000..22985159044
--- /dev/null
+++ b/vendor/github.com/mitchellh/ioprogress/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Mitchell Hashimoto
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/vendor/github.com/mitchellh/ioprogress/README.md b/vendor/github.com/mitchellh/ioprogress/README.md
new file mode 100644
index 00000000000..3d291e9d14e
--- /dev/null
+++ b/vendor/github.com/mitchellh/ioprogress/README.md
@@ -0,0 +1,42 @@
+# ioprogress
+
+ioprogress is a Go (golang) library with implementations of `io.Reader`
+and `io.Writer` that draws progress bars. The primary use case for these
+are for CLI applications but alternate progress bar writers can be supplied
+for alternate environments.
+
+## Example
+
+![Progress](http://g.recordit.co/GO5HxT16QH.gif)
+
+## Installation
+
+Standard `go get`:
+
+```
+$ go get github.com/mitchellh/ioprogress
+```
+
+## Usage
+
+Here is an example of outputting a basic progress bar to the CLI as
+we're "downloading" from some other `io.Reader` (perhaps from a network
+connection):
+
+```go
+// Imagine this came from some external source, such as a network connection,
+// and that we have the full size of it, such as from a Content-Length HTTP
+// header.
+var r io.Reader
+
+// Create the progress reader
+progressR := &ioprogress.Reader{
+ Reader: r,
+ Size: rSize,
+}
+
+// Copy all of the reader to some local file f. As it copies, the
+// progressR will write progress to the terminal on os.Stdout. This is
+// customizable.
+io.Copy(f, progressR)
+```
diff --git a/vendor/github.com/mitchellh/ioprogress/draw.go b/vendor/github.com/mitchellh/ioprogress/draw.go
new file mode 100644
index 00000000000..83b7305a02f
--- /dev/null
+++ b/vendor/github.com/mitchellh/ioprogress/draw.go
@@ -0,0 +1,104 @@
+package ioprogress
+
+import (
+ "fmt"
+ "io"
+ "os"
+ "strings"
+)
+
+// DrawFunc is the callback type for drawing progress.
+type DrawFunc func(int64, int64) error
+
+// DrawTextFormatFunc is a callback used by DrawFuncs that draw text in
+// order to format the text into some more human friendly format.
+type DrawTextFormatFunc func(int64, int64) string
+
+var defaultDrawFunc DrawFunc
+
+func init() {
+ defaultDrawFunc = DrawTerminal(os.Stdout)
+}
+
+// DrawTerminal returns a DrawFunc that draws a progress bar to an io.Writer
+// that is assumed to be a terminal (and therefore respects carriage returns).
+func DrawTerminal(w io.Writer) DrawFunc {
+ return DrawTerminalf(w, func(progress, total int64) string {
+ return fmt.Sprintf("%d/%d", progress, total)
+ })
+}
+
+// DrawTerminalf returns a DrawFunc that draws a progress bar to an io.Writer
+// that is formatted with the given formatting function.
+func DrawTerminalf(w io.Writer, f DrawTextFormatFunc) DrawFunc {
+ var maxLength int
+
+ return func(progress, total int64) error {
+ if progress == -1 && total == -1 {
+ _, err := fmt.Fprintf(w, "\n")
+ return err
+ }
+
+ // Make sure we pad it to the max length we've ever drawn so that
+ // we don't have trailing characters.
+ line := f(progress, total)
+ if len(line) < maxLength {
+ line = fmt.Sprintf(
+ "%s%s",
+ line,
+ strings.Repeat(" ", maxLength-len(line)))
+ }
+ maxLength = len(line)
+
+ _, err := fmt.Fprint(w, line+"\r")
+ return err
+ }
+}
+
+var byteUnits = []string{"B", "KB", "MB", "GB", "TB", "PB"}
+
+// DrawTextFormatBytes is a DrawTextFormatFunc that formats the progress
+// and total into human-friendly byte formats.
+func DrawTextFormatBytes(progress, total int64) string {
+ return fmt.Sprintf("%s/%s", byteUnitStr(progress), byteUnitStr(total))
+}
+
+// DrawTextFormatBar returns a DrawTextFormatFunc that draws a progress
+// bar with the given width (in characters). This can be used in conjunction
+// with another DrawTextFormatFunc to create a progress bar with bytes, for
+// example:
+//
+// bar := DrawTextFormatBar(20)
+// func(progress, total int64) string {
+// return fmt.Sprintf(
+// "%s %s",
+// bar(progress, total),
+// DrawTextFormatBytes(progress, total))
+// }
+//
+func DrawTextFormatBar(width int64) DrawTextFormatFunc {
+ width -= 2
+
+ return func(progress, total int64) string {
+ current := int64((float64(progress) / float64(total)) * float64(width))
+ return fmt.Sprintf(
+ "[%s%s]",
+ strings.Repeat("=", int(current)),
+ strings.Repeat(" ", int(width-current)))
+ }
+}
+
+func byteUnitStr(n int64) string {
+ var unit string
+ size := float64(n)
+ for i := 1; i < len(byteUnits); i++ {
+ if size < 1000 {
+ unit = byteUnits[i-1]
+ break
+ }
+
+ size = size / 1000
+ }
+
+ return fmt.Sprintf("%.3g %s", size, unit)
+}
diff --git a/vendor/github.com/mitchellh/ioprogress/reader.go b/vendor/github.com/mitchellh/ioprogress/reader.go
new file mode 100644
index 00000000000..7d52731e2d2
--- /dev/null
+++ b/vendor/github.com/mitchellh/ioprogress/reader.go
@@ -0,0 +1,107 @@
+package ioprogress
+
+import (
+ "io"
+ "time"
+)
+
+// Reader is an implementation of io.Reader that draws the progress of
+// reading some data.
+type Reader struct {
+ // Reader is the underlying reader to read from
+ Reader io.Reader
+
+ // Size is the total size of the data coming out of the reader.
+ Size int64
+
+ // DrawFunc is the callback to invoke to draw the progress bar. By
+ // default, this will be DrawTerminal(os.Stdout).
+ //
+ // DrawInterval is the minimum time to wait between reads to update the
+ // progress bar.
+ DrawFunc DrawFunc
+ DrawInterval time.Duration
+
+ progress int64
+ lastDraw time.Time
+}
+
+// Read reads from the underlying reader and invokes the DrawFunc if
+// appropriate. The DrawFunc is executed when there is data that is
+// read (progress is made) and at least DrawInterval time has passed.
+func (r *Reader) Read(p []byte) (int, error) {
+ // If we haven't drawn before, initialize the progress bar
+ if r.lastDraw.IsZero() {
+ r.initProgress()
+ }
+
+ // Read from the underlying source
+ n, err := r.Reader.Read(p)
+
+ // Always increment the progress even if there was an error
+ r.progress += int64(n)
+
+ // If we don't have any errors, then draw the progress. If we are
+ // at the end of the data, then finish the progress.
+ if err == nil {
+ // Only draw if we read data or we've never read data before (to
+ // initialize the progress bar).
+ if n > 0 {
+ r.drawProgress()
+ }
+ }
+ if err == io.EOF {
+ r.finishProgress()
+ }
+
+ return n, err
+}
+
+func (r *Reader) drawProgress() {
+ // If we've drawn before, then make sure that the draw interval
+ // has passed before we draw again.
+ interval := r.DrawInterval
+ if interval == 0 {
+ interval = time.Second
+ }
+ if !r.lastDraw.IsZero() {
+ nextDraw := r.lastDraw.Add(interval)
+ if time.Now().Before(nextDraw) {
+ return
+ }
+ }
+
+ // Draw
+ f := r.drawFunc()
+ f(r.progress, r.Size)
+
+ // Record this draw so that we don't draw again really quickly
+ r.lastDraw = time.Now()
+}
+
+func (r *Reader) finishProgress() {
+ f := r.drawFunc()
+ f(r.progress, r.Size)
+
+ // Print a newline
+ f(-1, -1)
+
+ // Reset lastDraw so we don't finish again
+ var zeroDraw time.Time
+ r.lastDraw = zeroDraw
+}
+
+func (r *Reader) initProgress() {
+ var zeroDraw time.Time
+ r.lastDraw = zeroDraw
+ r.drawProgress()
+ r.lastDraw = zeroDraw
+}
+
+func (r *Reader) drawFunc() DrawFunc {
+ if r.DrawFunc == nil {
+ return defaultDrawFunc
+ }
+
+ return r.DrawFunc
+}
diff --git a/vendor/golang.org/x/sync/singleflight/singleflight.go b/vendor/golang.org/x/sync/singleflight/singleflight.go
new file mode 100644
index 00000000000..97a1aa4bb30
--- /dev/null
+++ b/vendor/golang.org/x/sync/singleflight/singleflight.go
@@ -0,0 +1,120 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package singleflight provides a duplicate function call suppression
+// mechanism.
+package singleflight // import "golang.org/x/sync/singleflight"
+
+import "sync"
+
+// call is an in-flight or completed singleflight.Do call
+type call struct {
+ wg sync.WaitGroup
+
+ // These fields are written once before the WaitGroup is done
+ // and are only read after the WaitGroup is done.
+ val interface{}
+ err error
+
+ // forgotten indicates whether Forget was called with this call's key
+ // while the call was still in flight.
+ forgotten bool
+
+ // These fields are read and written with the singleflight
+ // mutex held before the WaitGroup is done, and are read but
+ // not written after the WaitGroup is done.
+ dups int
+ chans []chan<- Result
+}
+
+// Group represents a class of work and forms a namespace in
+// which units of work can be executed with duplicate suppression.
+type Group struct {
+ mu sync.Mutex // protects m
+ m map[string]*call // lazily initialized
+}
+
+// Result holds the results of Do, so they can be passed
+// on a channel.
+type Result struct {
+ Val interface{}
+ Err error
+ Shared bool
+}
+
+// Do executes and returns the results of the given function, making
+// sure that only one execution is in-flight for a given key at a
+// time. If a duplicate comes in, the duplicate caller waits for the
+// original to complete and receives the same results.
+// The return value shared indicates whether v was given to multiple callers.
+func (g *Group) Do(key string, fn func() (interface{}, error)) (v interface{}, err error, shared bool) {
+ g.mu.Lock()
+ if g.m == nil {
+ g.m = make(map[string]*call)
+ }
+ if c, ok := g.m[key]; ok {
+ c.dups++
+ g.mu.Unlock()
+ c.wg.Wait()
+ return c.val, c.err, true
+ }
+ c := new(call)
+ c.wg.Add(1)
+ g.m[key] = c
+ g.mu.Unlock()
+
+ g.doCall(c, key, fn)
+ return c.val, c.err, c.dups > 0
+}
+
+// DoChan is like Do but returns a channel that will receive the
+// results when they are ready.
+func (g *Group) DoChan(key string, fn func() (interface{}, error)) <-chan Result {
+ ch := make(chan Result, 1)
+ g.mu.Lock()
+ if g.m == nil {
+ g.m = make(map[string]*call)
+ }
+ if c, ok := g.m[key]; ok {
+ c.dups++
+ c.chans = append(c.chans, ch)
+ g.mu.Unlock()
+ return ch
+ }
+ c := &call{chans: []chan<- Result{ch}}
+ c.wg.Add(1)
+ g.m[key] = c
+ g.mu.Unlock()
+
+ go g.doCall(c, key, fn)
+
+ return ch
+}
+
+// doCall handles the single call for a key.
+func (g *Group) doCall(c *call, key string, fn func() (interface{}, error)) {
+ c.val, c.err = fn()
+ c.wg.Done()
+
+ g.mu.Lock()
+ if !c.forgotten {
+ delete(g.m, key)
+ }
+ for _, ch := range c.chans {
+ ch <- Result{c.val, c.err, c.dups > 0}
+ }
+ g.mu.Unlock()
+}
+
+// Forget tells the singleflight to forget about a key. Future calls
+// to Do for this key will call the function rather than waiting for
+// an earlier call to complete.
+func (g *Group) Forget(key string) {
+ g.mu.Lock()
+ if c, ok := g.m[key]; ok {
+ c.forgotten = true
+ }
+ delete(g.m, key)
+ g.mu.Unlock()
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index b11afa60151..0146a95f17b 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -30,15 +30,49 @@ github.com/Azure/go-autorest/tracing
github.com/BurntSushi/toml
# github.com/MakeNowJust/heredoc v1.0.0
github.com/MakeNowJust/heredoc
+# github.com/Masterminds/semver v1.4.2
+github.com/Masterminds/semver
# github.com/Microsoft/go-winio v0.4.14
github.com/Microsoft/go-winio
github.com/Microsoft/go-winio/pkg/guid
+# github.com/apex/log v1.1.2-0.20190827100214-baa5455d1012
+github.com/apex/log
# github.com/beorn7/perks v1.0.1
github.com/beorn7/perks/quantile
# github.com/blang/semver v3.5.1+incompatible
github.com/blang/semver
# github.com/bmatcuk/doublestar v1.2.2
github.com/bmatcuk/doublestar
+# github.com/buildpacks/imgutil v0.0.0-20191212154113-dc184e0d403b
+github.com/buildpacks/imgutil
+github.com/buildpacks/imgutil/local
+github.com/buildpacks/imgutil/remote
+# github.com/buildpacks/lifecycle v0.5.1-0.20191217221752-3b74c943b7b3
+github.com/buildpacks/lifecycle
+github.com/buildpacks/lifecycle/archive
+github.com/buildpacks/lifecycle/auth
+github.com/buildpacks/lifecycle/cmd
+# github.com/buildpacks/pack v0.6.0
+github.com/buildpacks/pack
+github.com/buildpacks/pack/builder
+github.com/buildpacks/pack/cmd
+github.com/buildpacks/pack/internal/api
+github.com/buildpacks/pack/internal/app
+github.com/buildpacks/pack/internal/archive
+github.com/buildpacks/pack/internal/blob
+github.com/buildpacks/pack/internal/build
+github.com/buildpacks/pack/internal/builder
+github.com/buildpacks/pack/internal/buildpackage
+github.com/buildpacks/pack/internal/cache
+github.com/buildpacks/pack/internal/config
+github.com/buildpacks/pack/internal/container
+github.com/buildpacks/pack/internal/dist
+github.com/buildpacks/pack/internal/image
+github.com/buildpacks/pack/internal/paths
+github.com/buildpacks/pack/internal/stack
+github.com/buildpacks/pack/internal/stringset
+github.com/buildpacks/pack/internal/style
+github.com/buildpacks/pack/logging
# github.com/cespare/xxhash/v2 v2.1.0
github.com/cespare/xxhash/v2
# github.com/containerd/continuity v0.0.0-20190827140505-75bee3e2ccb6
@@ -207,6 +241,8 @@ github.com/grpc-ecosystem/grpc-gateway/utilities
# github.com/hashicorp/golang-lru v0.5.3
github.com/hashicorp/golang-lru
github.com/hashicorp/golang-lru/simplelru
+# github.com/heroku/color v0.0.6
+github.com/heroku/color
# github.com/imdario/mergo v0.3.8
github.com/imdario/mergo
# github.com/inconshreveable/mousetrap v1.0.0
@@ -243,6 +279,8 @@ github.com/mgutz/ansi
github.com/mitchellh/go-homedir
# github.com/mitchellh/go-wordwrap v1.0.0
github.com/mitchellh/go-wordwrap
+# github.com/mitchellh/ioprogress v0.0.0-20180201004757-6a23b12fa88e
+github.com/mitchellh/ioprogress
# github.com/moby/buildkit v0.6.3
github.com/moby/buildkit/frontend/dockerfile/command
github.com/moby/buildkit/frontend/dockerfile/parser
@@ -372,6 +410,7 @@ golang.org/x/oauth2/jws
golang.org/x/oauth2/jwt
# golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e
golang.org/x/sync/errgroup
+golang.org/x/sync/singleflight
# golang.org/x/sys v0.0.0-20191127021746-63cb32ae39b2
golang.org/x/sys/cpu
golang.org/x/sys/unix