github.com/kovansky/hugo@v0.92.3-0.20220224232819-63076e4ff19f/common/paths/url.go (about)

     1  // Copyright 2021 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package paths
    15  
    16  import (
    17  	"fmt"
    18  	"net/url"
    19  	"path"
    20  	"strings"
    21  )
    22  
    23  type pathBridge struct{}
    24  
    25  func (pathBridge) Base(in string) string {
    26  	return path.Base(in)
    27  }
    28  
    29  func (pathBridge) Clean(in string) string {
    30  	return path.Clean(in)
    31  }
    32  
    33  func (pathBridge) Dir(in string) string {
    34  	return path.Dir(in)
    35  }
    36  
    37  func (pathBridge) Ext(in string) string {
    38  	return path.Ext(in)
    39  }
    40  
    41  func (pathBridge) Join(elem ...string) string {
    42  	return path.Join(elem...)
    43  }
    44  
    45  func (pathBridge) Separator() string {
    46  	return "/"
    47  }
    48  
    49  var pb pathBridge
    50  
    51  // MakePermalink combines base URL with content path to create full URL paths.
    52  // Example
    53  //    base:   http://spf13.com/
    54  //    path:   post/how-i-blog
    55  //    result: http://spf13.com/post/how-i-blog
    56  func MakePermalink(host, plink string) *url.URL {
    57  	base, err := url.Parse(host)
    58  	if err != nil {
    59  		panic(err)
    60  	}
    61  
    62  	p, err := url.Parse(plink)
    63  	if err != nil {
    64  		panic(err)
    65  	}
    66  
    67  	if p.Host != "" {
    68  		panic(fmt.Errorf("can't make permalink from absolute link %q", plink))
    69  	}
    70  
    71  	base.Path = path.Join(base.Path, p.Path)
    72  
    73  	// path.Join will strip off the last /, so put it back if it was there.
    74  	hadTrailingSlash := (plink == "" && strings.HasSuffix(host, "/")) || strings.HasSuffix(p.Path, "/")
    75  	if hadTrailingSlash && !strings.HasSuffix(base.Path, "/") {
    76  		base.Path = base.Path + "/"
    77  	}
    78  
    79  	return base
    80  }
    81  
    82  // AddContextRoot adds the context root to an URL if it's not already set.
    83  // For relative URL entries on sites with a base url with a context root set (i.e. http://example.com/mysite),
    84  // relative URLs must not include the context root if canonifyURLs is enabled. But if it's disabled, it must be set.
    85  func AddContextRoot(baseURL, relativePath string) string {
    86  	url, err := url.Parse(baseURL)
    87  	if err != nil {
    88  		panic(err)
    89  	}
    90  
    91  	newPath := path.Join(url.Path, relativePath)
    92  
    93  	// path strips trailing slash, ignore root path.
    94  	if newPath != "/" && strings.HasSuffix(relativePath, "/") {
    95  		newPath += "/"
    96  	}
    97  	return newPath
    98  }
    99  
   100  // URLizeAn
   101  
   102  // PrettifyURL takes a URL string and returns a semantic, clean URL.
   103  func PrettifyURL(in string) string {
   104  	x := PrettifyURLPath(in)
   105  
   106  	if path.Base(x) == "index.html" {
   107  		return path.Dir(x)
   108  	}
   109  
   110  	if in == "" {
   111  		return "/"
   112  	}
   113  
   114  	return x
   115  }
   116  
   117  // PrettifyURLPath takes a URL path to a content and converts it
   118  // to enable pretty URLs.
   119  //     /section/name.html       becomes /section/name/index.html
   120  //     /section/name/           becomes /section/name/index.html
   121  //     /section/name/index.html becomes /section/name/index.html
   122  func PrettifyURLPath(in string) string {
   123  	return prettifyPath(in, pb)
   124  }
   125  
   126  // Uglify does the opposite of PrettifyURLPath().
   127  //     /section/name/index.html becomes /section/name.html
   128  //     /section/name/           becomes /section/name.html
   129  //     /section/name.html       becomes /section/name.html
   130  func Uglify(in string) string {
   131  	if path.Ext(in) == "" {
   132  		if len(in) < 2 {
   133  			return "/"
   134  		}
   135  		// /section/name/  -> /section/name.html
   136  		return path.Clean(in) + ".html"
   137  	}
   138  
   139  	name, ext := fileAndExt(in, pb)
   140  	if name == "index" {
   141  		// /section/name/index.html -> /section/name.html
   142  		d := path.Dir(in)
   143  		if len(d) > 1 {
   144  			return d + ext
   145  		}
   146  		return in
   147  	}
   148  	// /.xml -> /index.xml
   149  	if name == "" {
   150  		return path.Dir(in) + "index" + ext
   151  	}
   152  	// /section/name.html -> /section/name.html
   153  	return path.Clean(in)
   154  }