func doScan(appDir, path string) (*directory, error) { fullPath := filepath.Join(appDir, path) fi, err := os.Lstat(fullPath) if err != nil { return nil, fmt.Errorf("Scan of %s for path %s failed: %s", appDir, path, err) } if !fi.IsDir() { return nil, fmt.Errorf("Not a directory: %s", path) } dir := directory{ path: path, hash: filehash.Zero(), size: 0, files: make(map[string]*models.AppFileFields, 50), children: make(map[string]*directory, 10), } f, err := os.Open(fullPath) if err != nil { return nil, fmt.Errorf("Scan of %s failed on Open: %s", fullPath, err) } fis, err := f.Readdir(-1) if err != nil { return nil, fmt.Errorf("Scan of %s failed on Readdir: %s", fullPath, err) } for _, fi := range fis { fp := filepath.Join(fullPath, fi.Name()) fpRelative := filepath.Join(path, fi.Name()) if !fi.IsDir() { h := filehash.New(fp) dir.files[fp] = &models.AppFileFields{ Sha1: h.String(), Size: fi.Size(), Path: fpRelative, Mode: fmt.Sprintf("%#o", fi.Mode()), } dir.size += fi.Size() dir.hash.Combine(h) } else { s, err := doScan(appDir, fpRelative) if err != nil { return nil, fmt.Errorf("Scan of %s failed to scan subdirectory %s: %s", fullPath, fp, err) } dir.children[fp] = s } } return &dir, nil }
"github.com/cloudfoundry/cli/cf/models" "github.com/glyn/bloblets/bloblet/filehash" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) var _ = Describe("Scanner", func() { It("should correctly scan an empty directory", func() { d, err := ioutil.TempDir("", "empty") Expect(err).NotTo(HaveOccurred()) dir, err := Scan(d) Expect(err).NotTo(HaveOccurred()) Expect(dir.path).To(Equal(".")) Expect(dir.hash).To(Equal(filehash.Zero())) Expect(dir.size).To(Equal(int64(0))) Expect(dir.files).To(BeEmpty()) Expect(dir.children).To(BeEmpty()) Expect(dir.bloblet).To(BeNil()) }) It("should correctly scan a directory with no children", func() { dir, err := Scan("./test/nochildren") Expect(err).NotTo(HaveOccurred()) Expect(dir.path).To(Equal(".")) Expect(dir.hash.String()).To(Equal("6fbf71631414af6ab45c4508bc4bc030ae12f891")) Expect(dir.size).To(Equal(int64(3218))) Expect(hashes(dir.files)).To(Equal(map[string]string{"test/nochildren/file1": filehash.New("./test/nochildren/file1").String(), "test/nochildren/file2": filehash.New("./test/nochildren/file2").String()})) Expect(dir.children).To(BeEmpty())
"strings" "github.com/cloudfoundry/cli/cf/models" "github.com/glyn/bloblets/bloblet/filehash" ) type Condensate interface { Bloblets([]models.AppFileFields) ([]Bloblet, []models.AppFileFields) } const BlobletFileName = "com-github-glyn-bloblet.zip" var BlobletFileNamePathTerminator = filepath.Join("", BlobletFileName) var noFiles = make(map[string]*models.AppFileFields) var zeroHash = filehash.Zero() // Condenses the files in the given directory and returns details of (a) files which // are already larger than minCompressedBlobletSize, and (b) bloblets. func (dir *directory) Condense(minBlobletSize, minCompressedBlobletSize int64) []models.AppFileFields { affs := make([]models.AppFileFields, 0, 100) for _, child := range dir.children { caffs := child.Condense(minBlobletSize, minCompressedBlobletSize) affs = appendAll(affs, caffs) // If the child has not been condensed, copy its files to its parent (this directory). if child.bloblet == nil { addAll(dir.files, child.files) dir.size += child.size dir.hash.Combine(child.hash) // Show child has been condensed into parent - only for use in testing.