URI: 
       Respect mediatypes for deploy - hugo - [fork] hugo port for 9front
  HTML git clone git@git.drkhsh.at/hugo.git
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
   DIR README
   DIR LICENSE
       ---
   DIR commit 12f6a1cdc0aedf4319367af57bda3c94150d6a84
   DIR parent 2fa851e6500752c0cea1da5cfdfc6d99e0a81a71
  HTML Author: satotake <doublequotation@gmail.com>
       Date:   Tue,  4 Aug 2020 02:06:18 +0900
       
       Respect mediatypes for deploy 
       
       Fixes #6861
       
       Diffstat:
         M deploy/deploy.go                    |      33 ++++++++++++++++++++-----------
         M deploy/deployConfig.go              |      20 ++++++++++++++++++--
         M deploy/deploy_test.go               |      47 +++++++++++++++++++++++++------
       
       3 files changed, 77 insertions(+), 23 deletions(-)
       ---
   DIR diff --git a/deploy/deploy.go b/deploy/deploy.go
       @@ -33,6 +33,7 @@ import (
                "github.com/dustin/go-humanize"
                "github.com/gobwas/glob"
                "github.com/gohugoio/hugo/config"
       +        "github.com/gohugoio/hugo/media"
                "github.com/pkg/errors"
                "github.com/spf13/afero"
                jww "github.com/spf13/jwalterweatherman"
       @@ -51,6 +52,7 @@ type Deployer struct {
        
                target        *target          // the target to deploy to
                matchers      []*matcher       // matchers to apply to uploaded files
       +        mediaTypes    media.Types      // Hugo's MediaType to guess ContentType
                ordering      []*regexp.Regexp // orders uploads
                quiet         bool             // true reduces STDOUT
                confirm       bool             // true enables confirmation before making changes
       @@ -96,11 +98,13 @@ func New(cfg config.Provider, localFs afero.Fs) (*Deployer, error) {
                                return nil, fmt.Errorf("deployment target %q not found", targetName)
                        }
                }
       +
                return &Deployer{
                        localFs:       localFs,
                        target:        tgt,
                        matchers:      dcfg.Matchers,
                        ordering:      dcfg.ordering,
       +                mediaTypes:    dcfg.mediaTypes,
                        quiet:         cfg.GetBool("quiet"),
                        confirm:       cfg.GetBool("confirm"),
                        dryRun:        cfg.GetBool("dryRun"),
       @@ -130,7 +134,7 @@ func (d *Deployer) Deploy(ctx context.Context) error {
                if d.target != nil {
                        include, exclude = d.target.includeGlob, d.target.excludeGlob
                }
       -        local, err := walkLocal(d.localFs, d.matchers, include, exclude)
       +        local, err := walkLocal(d.localFs, d.matchers, include, exclude, d.mediaTypes)
                if err != nil {
                        return err
                }
       @@ -322,14 +326,15 @@ type localFile struct {
                // gzipped before upload.
                UploadSize int64
        
       -        fs      afero.Fs
       -        matcher *matcher
       -        md5     []byte       // cache
       -        gzipped bytes.Buffer // cached of gzipped contents if gzipping
       +        fs         afero.Fs
       +        matcher    *matcher
       +        md5        []byte       // cache
       +        gzipped    bytes.Buffer // cached of gzipped contents if gzipping
       +        mediaTypes media.Types
        }
        
        // newLocalFile initializes a *localFile.
       -func newLocalFile(fs afero.Fs, nativePath, slashpath string, m *matcher) (*localFile, error) {
       +func newLocalFile(fs afero.Fs, nativePath, slashpath string, m *matcher, mt media.Types) (*localFile, error) {
                f, err := fs.Open(nativePath)
                if err != nil {
                        return nil, err
       @@ -340,6 +345,7 @@ func newLocalFile(fs afero.Fs, nativePath, slashpath string, m *matcher) (*local
                        SlashPath:  slashpath,
                        fs:         fs,
                        matcher:    m,
       +                mediaTypes: mt,
                }
                if m != nil && m.Gzip {
                        // We're going to gzip the content. Do it once now, and cache the result
       @@ -410,10 +416,13 @@ func (lf *localFile) ContentType() string {
                if lf.matcher != nil && lf.matcher.ContentType != "" {
                        return lf.matcher.ContentType
                }
       -        // TODO: Hugo has a MediaType and a MediaTypes list and also a concept
       -        // of custom MIME types.
       -        // Use 1) The matcher 2) Hugo's MIME types 3) TypeByExtension.
       -        return mime.TypeByExtension(filepath.Ext(lf.NativePath))
       +
       +        ext := filepath.Ext(lf.NativePath)
       +        if mimeType, found := lf.mediaTypes.GetFirstBySuffix(strings.TrimPrefix(ext, ".")); found {
       +                return mimeType.Type()
       +        }
       +
       +        return mime.TypeByExtension(ext)
        }
        
        // Force returns true if the file should be forced to re-upload based on the
       @@ -457,7 +466,7 @@ func knownHiddenDirectory(name string) bool {
        
        // walkLocal walks the source directory and returns a flat list of files,
        // using localFile.SlashPath as the map keys.
       -func walkLocal(fs afero.Fs, matchers []*matcher, include, exclude glob.Glob) (map[string]*localFile, error) {
       +func walkLocal(fs afero.Fs, matchers []*matcher, include, exclude glob.Glob, mediaTypes media.Types) (map[string]*localFile, error) {
                retval := map[string]*localFile{}
                err := afero.Walk(fs, "", func(path string, info os.FileInfo, err error) error {
                        if err != nil {
       @@ -503,7 +512,7 @@ func walkLocal(fs afero.Fs, matchers []*matcher, include, exclude glob.Glob) (ma
                                        break
                                }
                        }
       -                lf, err := newLocalFile(fs, path, slashpath, m)
       +                lf, err := newLocalFile(fs, path, slashpath, m, mediaTypes)
                        if err != nil {
                                return err
                        }
   DIR diff --git a/deploy/deployConfig.go b/deploy/deployConfig.go
       @@ -20,6 +20,7 @@ import (
                "github.com/gobwas/glob"
                "github.com/gohugoio/hugo/config"
                hglob "github.com/gohugoio/hugo/hugofs/glob"
       +        "github.com/gohugoio/hugo/media"
                "github.com/mitchellh/mapstructure"
        )
        
       @@ -31,7 +32,8 @@ type deployConfig struct {
                Matchers []*matcher
                Order    []string
        
       -        ordering []*regexp.Regexp // compiled Order
       +        ordering   []*regexp.Regexp // compiled Order
       +        mediaTypes media.Types
        }
        
        type target struct {
       @@ -108,7 +110,12 @@ func (m *matcher) Matches(path string) bool {
        
        // decode creates a config from a given Hugo configuration.
        func decodeConfig(cfg config.Provider) (deployConfig, error) {
       -        var dcfg deployConfig
       +
       +        var (
       +                mediaTypesConfig []map[string]interface{}
       +                dcfg             deployConfig
       +        )
       +
                if !cfg.IsSet(deploymentConfigKey) {
                        return dcfg, nil
                }
       @@ -134,5 +141,14 @@ func decodeConfig(cfg config.Provider) (deployConfig, error) {
                        }
                        dcfg.ordering = append(dcfg.ordering, re)
                }
       +
       +        if cfg.IsSet("mediaTypes") {
       +                mediaTypesConfig = append(mediaTypesConfig, cfg.GetStringMap("mediaTypes"))
       +        }
       +
       +        dcfg.mediaTypes, err = media.DecodeTypes(mediaTypesConfig...)
       +        if err != nil {
       +                return dcfg, err
       +        }
                return dcfg, nil
        }
   DIR diff --git a/deploy/deploy_test.go b/deploy/deploy_test.go
       @@ -28,6 +28,7 @@ import (
                "sort"
                "testing"
        
       +        "github.com/gohugoio/hugo/media"
                "github.com/google/go-cmp/cmp"
                "github.com/google/go-cmp/cmp/cmpopts"
                "github.com/spf13/afero"
       @@ -208,6 +209,7 @@ func TestFindDiffs(t *testing.T) {
        }
        
        func TestWalkLocal(t *testing.T) {
       +
                tests := map[string]struct {
                        Given  []string
                        Expect []string
       @@ -246,7 +248,7 @@ func TestWalkLocal(t *testing.T) {
                                                fd.Close()
                                        }
                                }
       -                        if got, err := walkLocal(fs, nil, nil, nil); err != nil {
       +                        if got, err := walkLocal(fs, nil, nil, nil, media.DefaultTypes); err != nil {
                                        t.Fatal(err)
                                } else {
                                        expect := map[string]interface{}{}
       @@ -287,6 +289,7 @@ func TestLocalFile(t *testing.T) {
                        Description         string
                        Path                string
                        Matcher             *matcher
       +                MediaTypesConfig    []map[string]interface{}
                        WantContent         []byte
                        WantSize            int64
                        WantMD5             []byte
       @@ -344,6 +347,18 @@ func TestLocalFile(t *testing.T) {
                                WantMD5:             gzMD5[:],
                                WantContentEncoding: "gzip",
                        },
       +                {
       +                        Description: "Custom MediaType",
       +                        Path:        "foo.hugo",
       +                        MediaTypesConfig: []map[string]interface{}{
       +                                {
       +                                        "hugo/custom": map[string]interface{}{
       +                                                "suffixes": []string{"hugo"}}}},
       +                        WantContent:     contentBytes,
       +                        WantSize:        contentLen,
       +                        WantMD5:         contentMD5[:],
       +                        WantContentType: "hugo/custom",
       +                },
                }
        
                for _, tc := range tests {
       @@ -352,7 +367,15 @@ func TestLocalFile(t *testing.T) {
                                if err := afero.WriteFile(fs, tc.Path, []byte(content), os.ModePerm); err != nil {
                                        t.Fatal(err)
                                }
       -                        lf, err := newLocalFile(fs, tc.Path, filepath.ToSlash(tc.Path), tc.Matcher)
       +                        mediaTypes := media.DefaultTypes
       +                        if len(tc.MediaTypesConfig) > 0 {
       +                                mt, err := media.DecodeTypes(tc.MediaTypesConfig...)
       +                                if err != nil {
       +                                        t.Fatal(err)
       +                                }
       +                                mediaTypes = mt
       +                        }
       +                        lf, err := newLocalFile(fs, tc.Path, filepath.ToSlash(tc.Path), tc.Matcher, mediaTypes)
                                if err != nil {
                                        t.Fatal(err)
                                }
       @@ -543,6 +566,7 @@ func TestEndToEndSync(t *testing.T) {
                                        localFs:    test.fs,
                                        maxDeletes: -1,
                                        bucket:     test.bucket,
       +                                mediaTypes: media.DefaultTypes,
                                }
        
                                // Initial deployment should sync remote with local.
       @@ -629,6 +653,7 @@ func TestMaxDeletes(t *testing.T) {
                                        localFs:    test.fs,
                                        maxDeletes: -1,
                                        bucket:     test.bucket,
       +                                mediaTypes: media.DefaultTypes,
                                }
        
                                // Sync remote with local.
       @@ -702,7 +727,6 @@ func TestMaxDeletes(t *testing.T) {
        // TestIncludeExclude verifies that the include/exclude options for targets work.
        func TestIncludeExclude(t *testing.T) {
                ctx := context.Background()
       -
                tests := []struct {
                        Include string
                        Exclude string
       @@ -766,6 +790,7 @@ func TestIncludeExclude(t *testing.T) {
                                        maxDeletes: -1,
                                        bucket:     fsTest.bucket,
                                        target:     tgt,
       +                                mediaTypes: media.DefaultTypes,
                                }
        
                                // Sync remote with local.
       @@ -826,6 +851,7 @@ func TestIncludeExcludeRemoteDelete(t *testing.T) {
                                        localFs:    fsTest.fs,
                                        maxDeletes: -1,
                                        bucket:     fsTest.bucket,
       +                                mediaTypes: media.DefaultTypes,
                                }
        
                                // Initial sync to get the files on the remote
       @@ -865,6 +891,7 @@ func TestIncludeExcludeRemoteDelete(t *testing.T) {
        // In particular, MD5 hashes must be of the compressed content.
        func TestCompression(t *testing.T) {
                ctx := context.Background()
       +
                tests, cleanup, err := initFsTests()
                if err != nil {
                        t.Fatal(err)
       @@ -877,9 +904,10 @@ func TestCompression(t *testing.T) {
                                        t.Fatal(err)
                                }
                                deployer := &Deployer{
       -                                localFs:  test.fs,
       -                                bucket:   test.bucket,
       -                                matchers: []*matcher{{Pattern: ".*", Gzip: true, re: regexp.MustCompile(".*")}},
       +                                localFs:    test.fs,
       +                                bucket:     test.bucket,
       +                                matchers:   []*matcher{{Pattern: ".*", Gzip: true, re: regexp.MustCompile(".*")}},
       +                                mediaTypes: media.DefaultTypes,
                                }
        
                                // Initial deployment should sync remote with local.
       @@ -935,9 +963,10 @@ func TestMatching(t *testing.T) {
                                        t.Fatal(err)
                                }
                                deployer := &Deployer{
       -                                localFs:  test.fs,
       -                                bucket:   test.bucket,
       -                                matchers: []*matcher{{Pattern: "^subdir/aaa$", Force: true, re: regexp.MustCompile("^subdir/aaa$")}},
       +                                localFs:    test.fs,
       +                                bucket:     test.bucket,
       +                                matchers:   []*matcher{{Pattern: "^subdir/aaa$", Force: true, re: regexp.MustCompile("^subdir/aaa$")}},
       +                                mediaTypes: media.DefaultTypes,
                                }
        
                                // Initial deployment to sync remote with local.