diff --git a/Gopkg.lock b/Gopkg.lock index f38e0fc29..c9dca5b53 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -2,94 +2,131 @@ [[projects]] + digest = "1:d043e5ae59276188d876090c261c311e146792c0908e08e67e766b1020a72d00" name = "github.com/PuerkitoBio/goquery" packages = ["."] + pruneopts = "NUT" revision = "a86ea073017a6beddef78c8659e7224e8ca634b0" version = "v1.4.0" [[projects]] + digest = "1:fc86904a62ac4bfff8cfbe94f42231ce3d8cea8fe2506d5293eaef468f8eaecf" name = "github.com/andybalholm/cascadia" packages = ["."] + pruneopts = "NUT" revision = "901648c87902174f774fac311d7f176f8647bdaa" version = "v1.0.0" [[projects]] + digest = "1:0d47d0ff8f835c21bb6119829aab978468b921a57aa49622f7de6a88ae6df10c" name = "github.com/bmatcuk/doublestar" packages = ["."] + pruneopts = "NUT" revision = "b3608229437ba4dc33dae64d56a79a2a73f1f6b2" version = "v1.0.9" [[projects]] branch = "master" + digest = "1:58927c45bfdcd6550e5f1ab008eeeb6951474a232afa1dc690583f26c5f92cbd" name = "github.com/charlievieth/fs" packages = ["."] + pruneopts = "NUT" revision = "7dc373669fa10ddf827c37c595dee30a2f001be9" [[projects]] + digest = "1:34649cbdc8f75148581f0f7398b14c1ce3ac774719694bc4a929e0b2f00b732d" name = "github.com/cloudfoundry/bosh-cli" packages = ["director/template"] + pruneopts = "NUT" revision = "712bfd7271b478ba03c3f604339e2eefbec4647c" version = "v3.0.1" [[projects]] branch = "master" + digest = "1:071f0379869c818446f9d685b132d1a3955ef8487e4aad5f5cf025787e33465c" name = "github.com/cloudfoundry/bosh-utils" packages = [ "errors", "logger", - "system" + "system", ] + pruneopts = "NUT" revision = "fad7a5ad622c066cf1b36eb44b9612cec680e48c" [[projects]] branch = "master" + digest = "1:71570cb9af58f4981cd3b6ac9902b37e978e1f3c34f35a04a3a4837ea542500f" name = "github.com/cppforlife/go-patch" packages = ["patch"] + pruneopts = "NUT" revision = "250da0e0e68ce3367b4302f34218f6c064eb9559" [[projects]] + branch = "threaded" + digest = "1:abe37043b0ba1a2e3a306dcd66e63c822614a0e87a413e224b40e559fcc57c31" + name = "github.com/fredwangwang/formcontent" + packages = ["."] + pruneopts = "NUT" + revision = "693fd491b02cbc57ea30b399611245ff2a5d9c9e" + +[[projects]] + digest = "1:81466b4218bf6adddac2572a30ac733a9255919bc2f470b4827a317bd4ee1756" name = "github.com/ghodss/yaml" packages = ["."] + pruneopts = "NUT" revision = "0ca9ea5df5451ffdf184b4428c902747c2c11cd7" version = "v1.0.0" [[projects]] + digest = "1:9f35c1344b56e5868d511d231f215edd0650aa572664f856444affdd256e43e4" name = "github.com/golang/protobuf" packages = ["proto"] + pruneopts = "NUT" revision = "925541529c1fa6821df4e44ce2723319eb2be768" version = "v1.0.0" [[projects]] branch = "master" + digest = "1:a63cff6b5d8b95638bfe300385d93b2a6d9d687734b863da8e09dc834510a690" name = "github.com/google/go-querystring" packages = ["query"] + pruneopts = "NUT" revision = "53e6ce116135b80d037921a7fdd5138cf32d7a8a" [[projects]] branch = "master" + digest = "1:b87f828d0392f61272dbfd2f5f5d39cdad674a4b604441e3fc4119c2e98ac92d" name = "github.com/gosuri/uilive" packages = ["."] + pruneopts = "NUT" revision = "ac356e6e42cd31fcef8e6aec13ae9ed6fe87713e" [[projects]] + digest = "1:bc4f7eec3b7be8c6cb1f0af6c1e3333d5bb71072951aaaae2f05067b0803f287" name = "github.com/mattn/go-isatty" packages = ["."] + pruneopts = "NUT" revision = "0360b2af4f38e8d38c7fce2a9f4e702702d73a39" version = "v0.0.3" [[projects]] + digest = "1:cb591533458f6eb6e2c1065ff3eac6b50263d7847deb23fc9f79b25bc608970e" name = "github.com/mattn/go-runewidth" packages = ["."] + pruneopts = "NUT" revision = "9e777a8366cce605130a531d2cd6363d07ad7317" version = "v0.0.2" [[projects]] branch = "master" + digest = "1:8ba3f1b3c0cb6d601b3a8d3dfc3a899768614e77ff89a30c6eefdc34f75ff5ee" name = "github.com/olekukonko/tablewriter" packages = ["."] + pruneopts = "NUT" revision = "b8a9be070da40449e501c3c4730a889e42d87a9e" [[projects]] + digest = "1:1db9a4493430dbd0eb8ce02483e7db6a94f80b4c58a7e901e4a9cf2be227b27e" name = "github.com/onsi/ginkgo" packages = [ ".", @@ -110,12 +147,14 @@ "reporters/stenographer", "reporters/stenographer/support/go-colorable", "reporters/stenographer/support/go-isatty", - "types" + "types", ] + pruneopts = "NUT" revision = "9eda700730cba42af70d53180f9dcce9266bc2bc" version = "v1.4.0" [[projects]] + digest = "1:32b6e270bb2709e5dee469d2319b90ee73137eb2b153b33f8093bd170aa1b999" name = "github.com/onsi/gomega" packages = [ ".", @@ -131,55 +170,67 @@ "matchers/support/goraph/edge", "matchers/support/goraph/node", "matchers/support/goraph/util", - "types" + "types", ] + pruneopts = "NUT" revision = "003f63b7f4cff3fc95357005358af2de0f5fe152" version = "v1.3.0" [[projects]] branch = "master" + digest = "1:dafa5a11eca4a8af372af47a61cbb1bd0bc8d5560b4fe5107fd6438f8b92998c" name = "github.com/pivotal-cf/jhanda" packages = [ ".", - "internal/parser" + "internal/parser", ] + pruneopts = "NUT" revision = "1b5ae1681a4554242f0daaea5c97bf1ea80aa761" [[projects]] branch = "master" + digest = "1:0acb8dfe68c725924028244697d888424efb93c83dc4846387c12954dccaa378" name = "github.com/pivotal-cf/kiln" packages = ["proofing"] + pruneopts = "NUT" revision = "9c0f5ac8553d4e981aec5d24d55f14936bfb7d3c" [[projects]] branch = "master" + digest = "1:2db735e26033656283519bf752a6c8b5065c8564952f36c8929a267f06869049" name = "golang.org/x/net" packages = [ "context", "context/ctxhttp", "html", "html/atom", - "html/charset" + "html/charset", ] + pruneopts = "NUT" revision = "6078986fec03a1dcc236c34816c71b0e05018fda" [[projects]] branch = "master" + digest = "1:a3babe25b178a29383a5e0a1d61630815aa7474acaa8f28e254d34376f51afd0" name = "golang.org/x/oauth2" packages = [ ".", "clientcredentials", - "internal" + "internal", ] + pruneopts = "NUT" revision = "fdc9e635145ae97e6c2cb777c48305600cf515cb" [[projects]] branch = "master" + digest = "1:99e2680036a6e92ede18602debb98bb8e620a7d67ca11b3fc21a9c9ab5be3e79" name = "golang.org/x/sys" packages = ["unix"] + pruneopts = "NUT" revision = "378d26f46672a356c46195c28f61bdb4c0a781dd" [[projects]] + digest = "1:f7ca85eff16bc0c23cdbed0f3b5a97cc40a62e167fbf0aab861dfc7600820d2c" name = "golang.org/x/text" packages = [ "encoding", @@ -198,12 +249,14 @@ "language", "runes", "transform", - "unicode/cldr" + "unicode/cldr", ] + pruneopts = "NUT" revision = "f21a4dfb5e38f5895301dc265a8def02365cc3d0" version = "v0.3.0" [[projects]] + digest = "1:c673a656f14b2433d5d9b6e06371073b0066de710a252616bc884db3b6fa51f9" name = "google.golang.org/appengine" packages = [ "internal", @@ -212,26 +265,51 @@ "internal/log", "internal/remote_api", "internal/urlfetch", - "urlfetch" + "urlfetch", ] + pruneopts = "NUT" revision = "150dc57a1b433e64154302bdc40b6bb8aefa313a" version = "v1.0.0" [[projects]] + digest = "1:829600691c61c34b821dd7454dc3e7de5a01a4cecc727ddaa1ae323ef725f614" name = "gopkg.in/cheggaaa/pb.v1" packages = ["."] + pruneopts = "NUT" revision = "72b964305fba1230d3d818711138195f22b9ceea" version = "v1.0.22" [[projects]] + digest = "1:7c95b35057a0ff2e19f707173cc1a947fa43a6eb5c4d300d196ece0334046082" name = "gopkg.in/yaml.v2" packages = ["."] + pruneopts = "NUT" revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" version = "v2.2.1" [solve-meta] analyzer-name = "dep" analyzer-version = 1 - inputs-digest = "c1f9baab291c56f4c7f4aac00844550b2319199d63139d8689f68730f5131e39" + input-imports = [ + "github.com/PuerkitoBio/goquery", + "github.com/cloudfoundry/bosh-cli/director/template", + "github.com/cppforlife/go-patch/patch", + "github.com/fredwangwang/formcontent", + "github.com/ghodss/yaml", + "github.com/google/go-querystring/query", + "github.com/gosuri/uilive", + "github.com/olekukonko/tablewriter", + "github.com/onsi/ginkgo", + "github.com/onsi/ginkgo/extensions/table", + "github.com/onsi/gomega", + "github.com/onsi/gomega/gbytes", + "github.com/onsi/gomega/gexec", + "github.com/pivotal-cf/jhanda", + "github.com/pivotal-cf/kiln/proofing", + "golang.org/x/oauth2", + "golang.org/x/oauth2/clientcredentials", + "gopkg.in/cheggaaa/pb.v1", + "gopkg.in/yaml.v2", + ] solver-name = "gps-cdcl" solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml index 04c2c50ce..018381d61 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -8,3 +8,7 @@ [[constraint]] name = "github.com/pivotal-cf/kiln" branch = "master" + +[[constraint]] + name = "github.com/fredwangwang/formcontent" + branch = "threaded" \ No newline at end of file diff --git a/commands/fakes/multipart.go b/commands/fakes/multipart.go index 60640c41d..783271aac 100644 --- a/commands/fakes/multipart.go +++ b/commands/fakes/multipart.go @@ -4,20 +4,18 @@ package fakes import ( "sync" - "github.com/pivotal-cf/om/formcontent" + "github.com/fredwangwang/formcontent" ) type Multipart struct { - FinalizeStub func() (formcontent.ContentSubmission, error) + FinalizeStub func() formcontent.ContentSubmission finalizeMutex sync.RWMutex finalizeArgsForCall []struct{} finalizeReturns struct { result1 formcontent.ContentSubmission - result2 error } finalizeReturnsOnCall map[int]struct { result1 formcontent.ContentSubmission - result2 error } AddFileStub func(key, path string) error addFileMutex sync.RWMutex @@ -47,7 +45,7 @@ type Multipart struct { invocationsMutex sync.RWMutex } -func (fake *Multipart) Finalize() (formcontent.ContentSubmission, error) { +func (fake *Multipart) Finalize() formcontent.ContentSubmission { fake.finalizeMutex.Lock() ret, specificReturn := fake.finalizeReturnsOnCall[len(fake.finalizeArgsForCall)] fake.finalizeArgsForCall = append(fake.finalizeArgsForCall, struct{}{}) @@ -57,9 +55,9 @@ func (fake *Multipart) Finalize() (formcontent.ContentSubmission, error) { return fake.FinalizeStub() } if specificReturn { - return ret.result1, ret.result2 + return ret.result1 } - return fake.finalizeReturns.result1, fake.finalizeReturns.result2 + return fake.finalizeReturns.result1 } func (fake *Multipart) FinalizeCallCount() int { @@ -68,26 +66,23 @@ func (fake *Multipart) FinalizeCallCount() int { return len(fake.finalizeArgsForCall) } -func (fake *Multipart) FinalizeReturns(result1 formcontent.ContentSubmission, result2 error) { +func (fake *Multipart) FinalizeReturns(result1 formcontent.ContentSubmission) { fake.FinalizeStub = nil fake.finalizeReturns = struct { result1 formcontent.ContentSubmission - result2 error - }{result1, result2} + }{result1} } -func (fake *Multipart) FinalizeReturnsOnCall(i int, result1 formcontent.ContentSubmission, result2 error) { +func (fake *Multipart) FinalizeReturnsOnCall(i int, result1 formcontent.ContentSubmission) { fake.FinalizeStub = nil if fake.finalizeReturnsOnCall == nil { fake.finalizeReturnsOnCall = make(map[int]struct { result1 formcontent.ContentSubmission - result2 error }) } fake.finalizeReturnsOnCall[i] = struct { result1 formcontent.ContentSubmission - result2 error - }{result1, result2} + }{result1} } func (fake *Multipart) AddFile(key string, path string) error { diff --git a/commands/import_installation.go b/commands/import_installation.go index ede5d0d3a..e61818822 100644 --- a/commands/import_installation.go +++ b/commands/import_installation.go @@ -67,7 +67,7 @@ func (ii ImportInstallation) Execute(args []string) error { return fmt.Errorf("failed to insert passphrase: %s", err) } - submission, err := ii.multipart.Finalize() + submission := ii.multipart.Finalize() if err != nil { return fmt.Errorf("failed to create multipart form: %s", err) } @@ -75,9 +75,9 @@ func (ii ImportInstallation) Execute(args []string) error { ii.logger.Printf("beginning installation import to Ops Manager") err = ii.service.UploadInstallationAssetCollection(api.ImportInstallationInput{ - ContentLength: submission.Length, Installation: submission.Content, ContentType: submission.ContentType, + ContentLength: submission.ContentLength, PollingInterval: ii.Options.PollingInterval, }) if err != nil { diff --git a/commands/import_installation_test.go b/commands/import_installation_test.go index 09c95fd8d..84b4aee48 100644 --- a/commands/import_installation_test.go +++ b/commands/import_installation_test.go @@ -10,7 +10,7 @@ import ( "github.com/pivotal-cf/om/api" "github.com/pivotal-cf/om/commands" "github.com/pivotal-cf/om/commands/fakes" - "github.com/pivotal-cf/om/formcontent" + "github.com/fredwangwang/formcontent" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -31,11 +31,11 @@ var _ = Describe("ImportInstallation", func() { It("imports an installation", func() { submission := formcontent.ContentSubmission{ - Length: 10, - Content: ioutil.NopCloser(strings.NewReader("")), - ContentType: "some content-type", + Content: ioutil.NopCloser(strings.NewReader("")), + ContentType: "some content-type", + ContentLength: 10, } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) eaOutputs := []api.EnsureAvailabilityOutput{ {Status: api.EnsureAvailabilityStatusUnstarted}, @@ -91,11 +91,11 @@ var _ = Describe("ImportInstallation", func() { Context("when polling interval is specified", func() { It("passes the value to the installation service", func() { submission := formcontent.ContentSubmission{ - Length: 10, - Content: ioutil.NopCloser(strings.NewReader("")), - ContentType: "some content-type", + Content: ioutil.NopCloser(strings.NewReader("")), + ContentType: "some content-type", + ContentLength: 10, } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) eaOutputs := []api.EnsureAvailabilityOutput{ {Status: api.EnsureAvailabilityStatusUnstarted}, diff --git a/commands/upload_product.go b/commands/upload_product.go index 6a76f6415..5e49f3706 100644 --- a/commands/upload_product.go +++ b/commands/upload_product.go @@ -90,7 +90,7 @@ func (up UploadProduct) Execute(args []string) error { return fmt.Errorf("failed to load product: %s", err) } - submission, err := up.multipart.Finalize() + submission := up.multipart.Finalize() if err != nil { return fmt.Errorf("failed to create multipart form: %s", err) } @@ -98,9 +98,9 @@ func (up UploadProduct) Execute(args []string) error { up.logger.Printf("beginning product upload to Ops Manager") _, err = up.service.UploadAvailableProduct(api.UploadAvailableProductInput{ - ContentLength: submission.Length, Product: submission.Content, ContentType: submission.ContentType, + ContentLength: submission.ContentLength, PollingInterval: up.Options.PollingInterval, }) if err != nil { diff --git a/commands/upload_product_test.go b/commands/upload_product_test.go index d03c6f4df..fc483c86d 100644 --- a/commands/upload_product_test.go +++ b/commands/upload_product_test.go @@ -12,7 +12,7 @@ import ( "github.com/pivotal-cf/om/commands" "github.com/pivotal-cf/om/commands/fakes" "github.com/pivotal-cf/om/extractor" - "github.com/pivotal-cf/om/formcontent" + "github.com/fredwangwang/formcontent" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -35,11 +35,11 @@ var _ = Describe("UploadProduct", func() { It("uploads a product", func() { submission := formcontent.ContentSubmission{ - Length: 10, + ContentLength: 10, Content: ioutil.NopCloser(strings.NewReader("")), ContentType: "some content-type", } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) command := commands.NewUploadProduct(multipart, metadataExtractor, fakeService, logger) diff --git a/commands/upload_stemcell.go b/commands/upload_stemcell.go index e48a493b2..394e65c5a 100644 --- a/commands/upload_stemcell.go +++ b/commands/upload_stemcell.go @@ -6,7 +6,7 @@ import ( "github.com/pivotal-cf/jhanda" "github.com/pivotal-cf/om/api" - "github.com/pivotal-cf/om/formcontent" + "github.com/fredwangwang/formcontent" "github.com/pivotal-cf/om/validator" "strconv" @@ -26,7 +26,7 @@ type UploadStemcell struct { //go:generate counterfeiter -o ./fakes/multipart.go --fake-name Multipart . multipart type multipart interface { - Finalize() (formcontent.ContentSubmission, error) + Finalize() (formcontent.ContentSubmission) AddFile(key, path string) error AddField(key, value string) error } @@ -103,7 +103,7 @@ func (us UploadStemcell) Execute(args []string) error { return fmt.Errorf("failed to load stemcell: %s", err) } - submission, err := us.multipart.Finalize() + submission := us.multipart.Finalize() if err != nil { return fmt.Errorf("failed to create multipart form: %s", err) } @@ -111,9 +111,9 @@ func (us UploadStemcell) Execute(args []string) error { us.logger.Printf("beginning stemcell upload to Ops Manager") _, err = us.service.UploadStemcell(api.StemcellUploadInput{ - ContentLength: submission.Length, Stemcell: submission.Content, ContentType: submission.ContentType, + ContentLength: submission.ContentLength, }) if err != nil { return fmt.Errorf("failed to upload stemcell: %s", err) diff --git a/commands/upload_stemcell_test.go b/commands/upload_stemcell_test.go index 2d4e8f22a..91608e932 100644 --- a/commands/upload_stemcell_test.go +++ b/commands/upload_stemcell_test.go @@ -11,7 +11,7 @@ import ( "github.com/pivotal-cf/om/api" "github.com/pivotal-cf/om/commands" "github.com/pivotal-cf/om/commands/fakes" - "github.com/pivotal-cf/om/formcontent" + "github.com/fredwangwang/formcontent" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -33,11 +33,11 @@ var _ = Describe("UploadStemcell", func() { Context("uploads the stemcell", func() { It("to all compatible products", func() { submission := formcontent.ContentSubmission{ - Length: 10, - Content: ioutil.NopCloser(strings.NewReader("")), - ContentType: "some content-type", + Content: ioutil.NopCloser(strings.NewReader("")), + ContentType: "some content-type", + ContentLength: 10, } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) fakeService.GetDiagnosticReportReturns(api.DiagnosticReport{Stemcells: []string{}}, nil) @@ -76,11 +76,11 @@ var _ = Describe("UploadStemcell", func() { It("disables floating", func() { submission := formcontent.ContentSubmission{ - Length: 10, - Content: ioutil.NopCloser(strings.NewReader("")), - ContentType: "some content-type", + ContentLength: 10, + Content: ioutil.NopCloser(strings.NewReader("")), + ContentType: "some content-type", } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) fakeService.GetDiagnosticReportReturns(api.DiagnosticReport{Stemcells: []string{}}, nil) @@ -123,11 +123,11 @@ var _ = Describe("UploadStemcell", func() { Context("and force is not specified", func() { It("exits successfully without uploading", func() { submission := formcontent.ContentSubmission{ - Length: 10, - Content: ioutil.NopCloser(strings.NewReader("")), - ContentType: "some content-type", + ContentLength: 10, + Content: ioutil.NopCloser(strings.NewReader("")), + ContentType: "some content-type", } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) fakeService.GetDiagnosticReportReturns(api.DiagnosticReport{ Stemcells: []string{"stemcell.tgz"}, @@ -148,11 +148,11 @@ var _ = Describe("UploadStemcell", func() { Context("and force is specified", func() { It("uploads the stemcell", func() { submission := formcontent.ContentSubmission{ - Length: 10, - Content: ioutil.NopCloser(strings.NewReader("")), - ContentType: "some content-type", + Content: ioutil.NopCloser(strings.NewReader("")), + ContentType: "some content-type", + ContentLength: 10, } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) fakeService.GetDiagnosticReportReturns(api.DiagnosticReport{ Stemcells: []string{"stemcell.tgz"}, @@ -197,11 +197,11 @@ var _ = Describe("UploadStemcell", func() { file.WriteString("testing-shasum") submission := formcontent.ContentSubmission{ - Length: 10, - Content: ioutil.NopCloser(strings.NewReader("")), - ContentType: "some content-type", + ContentLength: 10, + Content: ioutil.NopCloser(strings.NewReader("")), + ContentType: "some content-type", } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) fakeService.GetDiagnosticReportReturns(api.DiagnosticReport{Stemcells: []string{}}, nil) @@ -246,11 +246,11 @@ var _ = Describe("UploadStemcell", func() { Context("when the diagnostic report is unavailable", func() { It("uploads the stemcell", func() { submission := formcontent.ContentSubmission{ - Length: 10, - Content: ioutil.NopCloser(strings.NewReader("")), - ContentType: "some content-type", + ContentLength: 10, + Content: ioutil.NopCloser(strings.NewReader("")), + ContentType: "some content-type", } - multipart.FinalizeReturns(submission, nil) + multipart.FinalizeReturns(submission) fakeService.GetDiagnosticReportReturns(api.DiagnosticReport{}, api.DiagnosticReportUnavailable{}) diff --git a/formcontent/formcontent.go b/formcontent/formcontent.go deleted file mode 100644 index 96c61a32b..000000000 --- a/formcontent/formcontent.go +++ /dev/null @@ -1,96 +0,0 @@ -package formcontent - -import ( - "errors" - "io" - "io/ioutil" - "mime/multipart" - "os" - "path/filepath" -) - -type Form struct { - multipartWriter *multipart.Writer - body *os.File -} - -type ContentSubmission struct { - Length int64 - Content io.Reader - ContentType string -} - -func NewForm() (Form, error) { - body, err := ioutil.TempFile("", "") - if err != nil { - return Form{}, err - } - - return Form{ - multipartWriter: multipart.NewWriter(body), - body: body, - }, nil -} - -func (f Form) Finalize() (ContentSubmission, error) { - err := f.multipartWriter.Close() - if err != nil { - return ContentSubmission{}, err - } - - _, err = f.body.Seek(0, 0) - if err != nil { - return ContentSubmission{}, err - } - - stats, err := f.body.Stat() - if err != nil { - return ContentSubmission{}, err - } - - return ContentSubmission{ - Length: stats.Size(), - Content: f.body, - ContentType: f.multipartWriter.FormDataContentType(), - }, nil -} - -func (f Form) AddFile(key, path string) error { - originalContent, err := os.Open(path) - if err != nil { - return err - } - - defer originalContent.Close() - - stats, err := originalContent.Stat() - if err != nil { - return err - } - - if stats.Size() == 0 { - return errors.New("file provided has no content") - } - - formFile, err := f.multipartWriter.CreateFormFile(key, filepath.Base(path)) - if err != nil { - return err - } - - _, err = io.Copy(formFile, originalContent) - if err != nil { - return err - } - - return nil -} - -func (f Form) AddField(key, value string) error { - fieldWriter, err := f.multipartWriter.CreateFormField(key) - if err != nil { - return err - } - - fieldWriter.Write([]byte(value)) - return nil -} diff --git a/formcontent/formcontent_test.go b/formcontent/formcontent_test.go deleted file mode 100644 index b1778ec54..000000000 --- a/formcontent/formcontent_test.go +++ /dev/null @@ -1,145 +0,0 @@ -package formcontent_test - -import ( - "io/ioutil" - "os" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - "github.com/pivotal-cf/om/formcontent" -) - -var _ = Describe("Form", func() { - - Describe("AddFile", func() { - var fileWithContent1 string - var fileWithContent2 string - var form formcontent.Form - - BeforeEach(func() { - handle1, err := ioutil.TempFile("", "") - Expect(err).NotTo(HaveOccurred()) - - _, err = handle1.WriteString("some content") - Expect(err).NotTo(HaveOccurred()) - - fileWithContent1 = handle1.Name() - - handle2, err := ioutil.TempFile("", "") - Expect(err).NotTo(HaveOccurred()) - - _, err = handle2.WriteString("some more content") - Expect(err).NotTo(HaveOccurred()) - - fileWithContent2 = handle2.Name() - - form, err = formcontent.NewForm() - Expect(err).NotTo(HaveOccurred()) - }) - - AfterEach(func() { - os.Remove(fileWithContent1) - os.Remove(fileWithContent2) - }) - - It("writes out the provided file as a multipart form using the writer", func() { - err := form.AddFile("something[file1]", fileWithContent1) - Expect(err).NotTo(HaveOccurred()) - - err = form.AddFile("something[file2]", fileWithContent2) - Expect(err).NotTo(HaveOccurred()) - - submission, err := form.Finalize() - Expect(err).NotTo(HaveOccurred()) - - content, err := ioutil.ReadAll(submission.Content) - Expect(err).NotTo(HaveOccurred()) - - Expect(string(content)).To(ContainSubstring("name=\"something[file1]\"")) - Expect(string(content)).To(ContainSubstring("some content")) - Expect(string(content)).To(ContainSubstring("name=\"something[file2]\"")) - Expect(string(content)).To(ContainSubstring("some more content")) - }) - - Context("when the file provided is empty", func() { - It("returns an error", func() { - emptyFile, err := ioutil.TempFile("", "") - Expect(err).NotTo(HaveOccurred()) - - form, err := formcontent.NewForm() - Expect(err).NotTo(HaveOccurred()) - - err = form.AddFile("foo", emptyFile.Name()) - Expect(err).To(MatchError("file provided has no content")) - }) - }) - - Context("when an error occurs", func() { - Context("when the original file cannot be read", func() { - It("returns an error", func() { - form, err := formcontent.NewForm() - Expect(err).NotTo(HaveOccurred()) - - err = form.AddFile("foo", "/file/does/not/exist") - Expect(err).To(MatchError(ContainSubstring("no such file or directory"))) - }) - }) - }) - }) - - Describe("AddField", func() { - var form formcontent.Form - - BeforeEach(func() { - var err error - form, err = formcontent.NewForm() - Expect(err).NotTo(HaveOccurred()) - }) - - It("writes out the provided fields into the multipart form using the writer", func() { - err := form.AddField("key1", "value1") - Expect(err).NotTo(HaveOccurred()) - - err = form.AddField("key2", "value2") - Expect(err).NotTo(HaveOccurred()) - - err = form.AddField("key3", "value3") - Expect(err).NotTo(HaveOccurred()) - - submission, err := form.Finalize() - Expect(err).NotTo(HaveOccurred()) - - content, err := ioutil.ReadAll(submission.Content) - Expect(err).NotTo(HaveOccurred()) - - Expect(string(content)).To(ContainSubstring("name=\"key1\"")) - Expect(string(content)).To(ContainSubstring("value1")) - Expect(string(content)).To(ContainSubstring("name=\"key2\"")) - Expect(string(content)).To(ContainSubstring("value2")) - Expect(string(content)).To(ContainSubstring("name=\"key3\"")) - Expect(string(content)).To(ContainSubstring("value3")) - }) - }) - - Describe("Finalize", func() { - var form formcontent.Form - - BeforeEach(func() { - var err error - form, err = formcontent.NewForm() - Expect(err).NotTo(HaveOccurred()) - }) - - It("returns a content submission which includes the correct length and content type", func() { - err := form.AddField("key1", "value1") - Expect(err).NotTo(HaveOccurred()) - - submission, err := form.Finalize() - Expect(err).NotTo(HaveOccurred()) - - Expect(submission.Length).To(Equal(int64(185))) - Expect(submission.ContentType).To(ContainSubstring("multipart/form-data")) - }) - - }) -}) diff --git a/formcontent/init_test.go b/formcontent/init_test.go deleted file mode 100644 index 34f364f48..000000000 --- a/formcontent/init_test.go +++ /dev/null @@ -1,13 +0,0 @@ -package formcontent_test - -import ( - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - - "testing" -) - -func TestFormcontent(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "formcontent") -} diff --git a/main.go b/main.go index 12ec6e537..18c4a2821 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,7 @@ import ( "github.com/pivotal-cf/om/api" "github.com/pivotal-cf/om/commands" "github.com/pivotal-cf/om/extractor" - "github.com/pivotal-cf/om/formcontent" + "github.com/fredwangwang/formcontent" "github.com/pivotal-cf/om/network" "github.com/pivotal-cf/om/presenters" "github.com/pivotal-cf/om/progress" @@ -115,7 +115,7 @@ func main() { logWriter := commands.NewLogWriter(os.Stdout) tableWriter := tablewriter.NewWriter(os.Stdout) - form, err := formcontent.NewForm() + form := formcontent.NewForm() if err != nil { stdout.Fatal(err) } diff --git a/vendor/github.com/cloudfoundry/bosh-cli/release/license/license.go b/vendor/github.com/cloudfoundry/bosh-cli/release/license/license.go deleted file mode 100644 index 54c01a72e..000000000 --- a/vendor/github.com/cloudfoundry/bosh-cli/release/license/license.go +++ /dev/null @@ -1,29 +0,0 @@ -package license - -import ( - "github.com/cloudfoundry/bosh-cli/crypto" - . "github.com/cloudfoundry/bosh-cli/release/resource" - crypto2 "github.com/cloudfoundry/bosh-utils/crypto" -) - -type License struct { - resource Resource -} - -func NewLicense(resource Resource) *License { - return &License{resource: resource} -} - -func (l License) Name() string { return l.resource.Name() } -func (l License) Fingerprint() string { return l.resource.Fingerprint() } - -func (l *License) ArchivePath() string { return l.resource.ArchivePath() } -func (l *License) ArchiveDigest() string { return l.resource.ArchiveDigest() } - -func (l *License) Build(dev, final ArchiveIndex) error { return l.resource.Build(dev, final) } -func (l *License) Finalize(final ArchiveIndex) error { return l.resource.Finalize(final) } - -func (l *License) RehashWithCalculator(calculator crypto.DigestCalculator, archiveFileReader crypto2.ArchiveDigestFilePathReader) (*License, error) { - newLicenseResource, err := l.resource.RehashWithCalculator(calculator, archiveFileReader) - return &License{newLicenseResource}, err -} diff --git a/vendor/github.com/fredwangwang/formcontent/formcontent.go b/vendor/github.com/fredwangwang/formcontent/formcontent.go new file mode 100644 index 000000000..f5b3f3060 --- /dev/null +++ b/vendor/github.com/fredwangwang/formcontent/formcontent.go @@ -0,0 +1,189 @@ +package formcontent + +import ( + "bytes" + "errors" + "io" + "mime/multipart" + "os" + "path/filepath" +) + +type Form struct { + contentType string + boundary string + length int64 + pr *io.PipeReader + pw *io.PipeWriter + formFields *bytes.Buffer + formWriter *multipart.Writer + files []string + fileKeys []*bytes.Buffer +} + +type ContentSubmission struct { + Content io.Reader + ContentType string + ContentLength int64 +} + +func NewForm() (*Form) { + buf := &bytes.Buffer{} + + pr, pw := io.Pipe() + + formWriter := multipart.NewWriter(buf) + + return &Form{ + contentType: formWriter.FormDataContentType(), + boundary: formWriter.Boundary(), + pr: pr, + pw: pw, + formFields: buf, + formWriter: formWriter, + } +} + +func (f *Form) AddField(key string, value string) error { + fieldWriter, err := f.formWriter.CreateFormField(key) + if err != nil { + return err + } + + _, err = fieldWriter.Write([]byte(value)) + return err +} + +func (f *Form) AddFile(key string, path string) error { + fileLength, err := verifyFile(path) + if err != nil { + return err + } + + buf := &bytes.Buffer{} + + fileKey := multipart.NewWriter(buf) + fileKey.SetBoundary(f.boundary) + + _, err = fileKey.CreateFormFile(key, filepath.Base(path)) + if err != nil { + return err + } + + // add the length of form fields, including trailing boundary + f.length += fileLength + f.length += int64(buf.Len()) + + f.files = append(f.files, path) + f.fileKeys = append(f.fileKeys, buf) + + return nil +} + +func (f *Form) Finalize() (ContentSubmission) { + f.formWriter.Close() + + // add the length of form fields, including trailing boundary + f.length += int64(f.formFields.Len()) + + // add the length of `\r\n` between fields + if len(f.files) > 0 { + f.length += int64(2 * (len(f.files) - 1)) + if f.formFields.Len() > len(f.boundary)+8 { + f.length += 2 + } + } + + go f.writeToPipe() + + return ContentSubmission{ + ContentLength: f.length, + Content: f.pr, + ContentType: f.contentType, + } +} + +func verifyFile(path string) (int64, error) { + fileContent, err := os.Open(path) + if err != nil { + return 0, err + } + + defer fileContent.Close() + + stats, err := fileContent.Stat() + if err != nil { + return 0, err + } + + if stats.Size() == 0 { + return 0, errors.New("file provided has no content") + } + + return stats.Size(), nil +} + +func (f *Form) writeToPipe() { + var err error + separate := false + + // write files + for i, key := range f.fileKeys { + if separate { + _, err = f.pw.Write([]byte("\r\n")) + if err != nil { + f.pw.CloseWithError(err) + return + } + } + + _, err = io.Copy(f.pw, key) + if err != nil { + f.pw.CloseWithError(err) + return + } + + fileName := f.files[i] + err = writeFileToPipe(fileName, f.pw) + if err != nil { + f.pw.CloseWithError(err) + return + } + + separate = true + } + + // write fields + if separate && f.formFields.Len() > len(f.boundary)+8 { // boundary+8 =>format: \r\n--boundary-words--\r\n + _, err = f.pw.Write([]byte("\r\n")) + if err != nil { + f.pw.CloseWithError(err) + return + } + } + + _, err = io.Copy(f.pw, f.formFields) + if err != nil { + f.pw.CloseWithError(err) + return + } + + f.pw.Close() + return +} + +func writeFileToPipe(fileName string, writer *io.PipeWriter) error { + fileContent, err := os.Open(fileName) + if err != nil { + return err + } + + defer fileContent.Close() + + _, err = io.Copy(writer, fileContent) + if err != nil { + return err + } + + return nil +}