Skip to content

Commit

Permalink
Copy cfignore to upload directory to properly ignore files
Browse files Browse the repository at this point in the history
* cfignore needs to be in the upload directory when determining what to zip
  • Loading branch information
Michael Fraenkel committed Aug 2, 2014
1 parent d36cdfa commit ce9e4ee
Show file tree
Hide file tree
Showing 5 changed files with 169 additions and 65 deletions.
6 changes: 6 additions & 0 deletions cf/api/application_bits.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ func (repo CloudControllerApplicationBitsRepository) UploadApp(appGuid string, a
return
}
presentFiles, err = repo.copyUploadableFiles(sourceDir, uploadDir)
if err != nil {
return
}

// copy cfignore if present
fileutils.CopyPathToPath(filepath.Join(sourceDir, ".cfignore"), filepath.Join(uploadDir, ".cfignore"))
})

if err != nil {
Expand Down
224 changes: 159 additions & 65 deletions cf/api/application_bits_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ var _ = Describe("CloudControllerApplicationBitsRepository", func() {
reportedFilePath string
reportedUploadSize uint64
reportedFileCount uint64
reportedZipCount int
)

BeforeEach(func() {
Expand All @@ -45,14 +46,18 @@ var _ = Describe("CloudControllerApplicationBitsRepository", func() {
configRepo.SetApiEndpoint(ts.URL)
gateway := net.NewCloudControllerGateway((configRepo), time.Now)
gateway.PollingThrottle = time.Duration(0)
zipper := app_files.ApplicationZipper{}
zipper := &countingZipper{
z: &app_files.ApplicationZipper{},
}

repo := NewCloudControllerApplicationBitsRepository(configRepo, gateway, zipper)

apiErr = repo.UploadApp("my-cool-app-guid", dir, func(path string, uploadSize, fileCount uint64) {
reportedFilePath = path
reportedUploadSize = uploadSize
reportedFileCount = fileCount
})
reportedZipCount = zipper.size

Expect(handler).To(HaveAllRequestsCalled())
return
Expand All @@ -65,6 +70,7 @@ var _ = Describe("CloudControllerApplicationBitsRepository", func() {
Expect(apiErr).NotTo(HaveOccurred())
Expect(reportedFilePath).To(Equal(appPath))
Expect(reportedFileCount).To(Equal(uint64(len(expectedApplicationContent))))
Expect(reportedZipCount).To(Equal(2))
Expect(reportedUploadSize).To(Equal(uint64(532)))
})

Expand Down Expand Up @@ -110,7 +116,7 @@ var _ = Describe("CloudControllerApplicationBitsRepository", func() {
testapi.NewCloudControllerTestRequest(testnet.TestRequest{
Method: "PUT",
Path: "/v2/apps/my-cool-app-guid/bits",
Matcher: uploadBodyMatcher,
Matcher: uploadBodyMatcher(defaultZipCheck),
Response: testnet.TestResponse{
Status: http.StatusCreated,
Body: `
Expand Down Expand Up @@ -173,10 +179,35 @@ var _ = Describe("CloudControllerApplicationBitsRepository", func() {
Expect(err).NotTo(HaveOccurred())
Expect(reportedFileCount).To(Equal(uint64(0)))
Expect(reportedUploadSize).To(Equal(uint64(0)))
Expect(reportedZipCount).To(Equal(-1))
Expect(reportedFilePath).To(Equal(emptyDir))
})
})
})

Context("when excluding a default ignored item", func() {
var appPath string

BeforeEach(func() {
appPath = filepath.Join(fixturesDir, "exclude-a-default-cfignore")
})

It("includes the ignored item", func() {
err := testUploadApp(appPath,
matchExcludedResourceRequest,
uploadApplicationRequest(func(zipReader *zip.Reader) {
Expect(len(zipReader.File)).To(Equal(3), "Wrong number of files in zip")
}),
createProgressEndpoint("running"),
createProgressEndpoint("finished"),
)

Expect(err).NotTo(HaveOccurred())
Expect(reportedFileCount).To(Equal(uint64(3)))
Expect(reportedUploadSize).To(Equal(uint64(354)))
Expect(reportedZipCount).To(Equal(3))
})
})
})

var matchedResources = testnet.RemoveWhiteSpaceFromBody(`[
Expand All @@ -192,21 +223,23 @@ var matchedResources = testnet.RemoveWhiteSpaceFromBody(`[
}
]`)

var uploadApplicationRequest = testapi.NewCloudControllerTestRequest(testnet.TestRequest{
Method: "PUT",
Path: "/v2/apps/my-cool-app-guid/bits",
Matcher: uploadBodyMatcher,
Response: testnet.TestResponse{
Status: http.StatusCreated,
Body: `
func uploadApplicationRequest(zipCheck func(*zip.Reader)) testnet.TestRequest {
return testapi.NewCloudControllerTestRequest(testnet.TestRequest{
Method: "PUT",
Path: "/v2/apps/my-cool-app-guid/bits",
Matcher: uploadBodyMatcher(zipCheck),
Response: testnet.TestResponse{
Status: http.StatusCreated,
Body: `
{
"metadata":{
"guid": "my-job-guid",
"url": "/v2/jobs/my-job-guid"
}
}
`},
})
})
}

var matchResourceRequest = testnet.TestRequest{
Method: "PUT",
Expand Down Expand Up @@ -239,61 +272,7 @@ var matchResourceRequest = testnet.TestRequest{
},
}

var defaultRequests = []testnet.TestRequest{
matchResourceRequest,
uploadApplicationRequest,
createProgressEndpoint("running"),
createProgressEndpoint("finished"),
}

var expectedApplicationContent = []string{"Gemfile", "Gemfile.lock"}

const maxMultipartResponseSizeInBytes = 4096

var uploadBodyMatcher = func(request *http.Request) {
err := request.ParseMultipartForm(maxMultipartResponseSizeInBytes)
if err != nil {
Fail(fmt.Sprintf("Failed parsing multipart form %v", err))
return
}
defer request.MultipartForm.RemoveAll()

Expect(len(request.MultipartForm.Value)).To(Equal(1), "Should have 1 value")
valuePart, ok := request.MultipartForm.Value["resources"]
Expect(ok).To(BeTrue(), "Resource manifest not present")
Expect(len(valuePart)).To(Equal(1), "Wrong number of values")

resourceManifest := valuePart[0]
chompedResourceManifest := strings.Replace(resourceManifest, "\n", "", -1)
Expect(chompedResourceManifest).To(Equal(matchedResources), "Resources do not match")

Expect(len(request.MultipartForm.File)).To(Equal(1), "Wrong number of files")

fileHeaders, ok := request.MultipartForm.File["application"]
Expect(ok).To(BeTrue(), "Application file part not present")
Expect(len(fileHeaders)).To(Equal(1), "Wrong number of files")

applicationFile := fileHeaders[0]
Expect(applicationFile.Filename).To(Equal("application.zip"), "Wrong file name")

file, err := applicationFile.Open()
if err != nil {
Fail(fmt.Sprintf("Cannot get multipart file %v", err.Error()))
return
}

length, err := strconv.ParseInt(applicationFile.Header.Get("content-length"), 10, 64)
if err != nil {
Fail(fmt.Sprintf("Cannot convert content-length to int %v", err.Error()))
return
}

zipReader, err := zip.NewReader(file, length)
if err != nil {
Fail(fmt.Sprintf("Error reading zip content %v", err.Error()))
return
}

var defaultZipCheck = func(zipReader *zip.Reader) {
Expect(len(zipReader.File)).To(Equal(2), "Wrong number of files in zip")

var expectedPermissionBits os.FileMode
Expand All @@ -317,6 +296,69 @@ nextFile:
}
}

var defaultRequests = []testnet.TestRequest{
matchResourceRequest,
uploadApplicationRequest(defaultZipCheck),
createProgressEndpoint("running"),
createProgressEndpoint("finished"),
}

var expectedApplicationContent = []string{"Gemfile", "Gemfile.lock"}

const maxMultipartResponseSizeInBytes = 4096

func uploadBodyMatcher(zipChecks func(zipReader *zip.Reader)) func(*http.Request) {
return func(request *http.Request) {
defer GinkgoRecover()
err := request.ParseMultipartForm(maxMultipartResponseSizeInBytes)
if err != nil {
Fail(fmt.Sprintf("Failed parsing multipart form %v", err))
return
}
defer request.MultipartForm.RemoveAll()

Expect(len(request.MultipartForm.Value)).To(Equal(1), "Should have 1 value")
valuePart, ok := request.MultipartForm.Value["resources"]
Expect(ok).To(BeTrue(), "Resource manifest not present")
Expect(len(valuePart)).To(Equal(1), "Wrong number of values")

resourceManifest := valuePart[0]
chompedResourceManifest := strings.Replace(resourceManifest, "\n", "", -1)
Expect(chompedResourceManifest).To(Equal(matchedResources), "Resources do not match")

Expect(len(request.MultipartForm.File)).To(Equal(1), "Wrong number of files")

fileHeaders, ok := request.MultipartForm.File["application"]
Expect(ok).To(BeTrue(), "Application file part not present")
Expect(len(fileHeaders)).To(Equal(1), "Wrong number of files")

applicationFile := fileHeaders[0]
Expect(applicationFile.Filename).To(Equal("application.zip"), "Wrong file name")

file, err := applicationFile.Open()
if err != nil {
Fail(fmt.Sprintf("Cannot get multipart file %v", err.Error()))
return
}

length, err := strconv.ParseInt(applicationFile.Header.Get("content-length"), 10, 64)
if err != nil {
Fail(fmt.Sprintf("Cannot convert content-length to int %v", err.Error()))
return
}

if zipChecks != nil {
zipReader, err := zip.NewReader(file, length)
if err != nil {
Fail(fmt.Sprintf("Error reading zip content %v", err.Error()))
return
}

zipChecks(zipReader)
}
}
}

func executableBits(mode os.FileMode) os.FileMode {
return mode & 0111
}
Expand All @@ -338,3 +380,55 @@ func createProgressEndpoint(status string) (req testnet.TestRequest) {

return
}

var matchExcludedResourceRequest = testnet.TestRequest{
Method: "PUT",
Path: "/v2/resource_match",
Matcher: testnet.RequestBodyMatcher(testnet.RemoveWhiteSpaceFromBody(`[
{
"fn": ".svn",
"sha1": "0",
"size": 0
},
{
"fn": ".svn/test",
"sha1": "456b1d3f7cfbadc66d390de79cbbb6e6a10662da",
"size": 12
},
{
"fn": "_darcs",
"sha1": "a94a8fe5ccb19ba61c4c0873d391e987982fbbd3",
"size": 4
}
]`)),
Response: testnet.TestResponse{
Status: http.StatusOK,
Body: matchedResources,
},
}

type countingZipper struct {
z app_files.Zipper
size int
}

func (cz *countingZipper) Zip(dirToZip string, targetFile *os.File) error {
cz.size = -1
err := cz.z.Zip(dirToZip, targetFile)
if err != nil {
return err
}

r, err := zip.OpenReader(targetFile.Name())
if err != nil {
return err
}
defer r.Close()

cz.size = len(r.File)
return nil
}

func (cz *countingZipper) IsZipFile(path string) bool {
return cz.z.IsZipFile(path)
}
2 changes: 2 additions & 0 deletions fixtures/applications/exclude-a-default-cfignore/.cfignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
!.svn
!_darcs
1 change: 1 addition & 0 deletions fixtures/applications/exclude-a-default-cfignore/.svn/test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
a test file
1 change: 1 addition & 0 deletions fixtures/applications/exclude-a-default-cfignore/_darcs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test

0 comments on commit ce9e4ee

Please sign in to comment.