mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-11-04 03:27:23 -05:00 
			
		
		
		
	markdown: documentation done. awaiting test
This commit is contained in:
		
							parent
							
								
									2c7de8f328
								
							
						
					
					
						commit
						0fccd3707d
					
				@ -61,10 +61,10 @@ type Config struct {
 | 
				
			|||||||
	// Map of registered templates
 | 
						// Map of registered templates
 | 
				
			||||||
	Templates map[string]string
 | 
						Templates map[string]string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Static files
 | 
						// Map of request URL to static files generated
 | 
				
			||||||
	StaticFiles map[string]string
 | 
						StaticFiles map[string]string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Static files directory
 | 
						// Directory to store static files
 | 
				
			||||||
	StaticDir string
 | 
						StaticDir string
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -17,12 +17,17 @@ var (
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// Metadata stores a page's metadata
 | 
					// Metadata stores a page's metadata
 | 
				
			||||||
type Metadata struct {
 | 
					type Metadata struct {
 | 
				
			||||||
	Title     string
 | 
						// Page title
 | 
				
			||||||
	Template  string
 | 
						Title string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Page template
 | 
				
			||||||
 | 
						Template string
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Variables to be used with Template
 | 
				
			||||||
	Variables map[string]interface{}
 | 
						Variables map[string]interface{}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Load loads parsed metadata into m
 | 
					// load loads parsed values in parsedMap into Metadata
 | 
				
			||||||
func (m *Metadata) load(parsedMap map[string]interface{}) {
 | 
					func (m *Metadata) load(parsedMap map[string]interface{}) {
 | 
				
			||||||
	if template, ok := parsedMap["title"]; ok {
 | 
						if template, ok := parsedMap["title"]; ok {
 | 
				
			||||||
		m.Title, _ = template.(string)
 | 
							m.Title, _ = template.(string)
 | 
				
			||||||
@ -35,14 +40,19 @@ func (m *Metadata) load(parsedMap map[string]interface{}) {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// MetadataParser parses the page metadata
 | 
					// MetadataParser is a an interface that must be satisfied by each parser
 | 
				
			||||||
// into Metadata
 | 
					 | 
				
			||||||
type MetadataParser interface {
 | 
					type MetadataParser interface {
 | 
				
			||||||
	// Identifiers
 | 
						// Opening identifier
 | 
				
			||||||
	Opening() []byte
 | 
						Opening() []byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Closing identifier
 | 
				
			||||||
	Closing() []byte
 | 
						Closing() []byte
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Parse the metadata
 | 
				
			||||||
	Parse([]byte) error
 | 
						Parse([]byte) error
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Parsed metadata.
 | 
				
			||||||
 | 
						// Should be called after a call to Parse returns no error
 | 
				
			||||||
	Metadata() Metadata
 | 
						Metadata() Metadata
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -51,7 +61,7 @@ type JSONMetadataParser struct {
 | 
				
			|||||||
	metadata Metadata
 | 
						metadata Metadata
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Parse parses b into metadata
 | 
					// Parse the metadata
 | 
				
			||||||
func (j *JSONMetadataParser) Parse(b []byte) error {
 | 
					func (j *JSONMetadataParser) Parse(b []byte) error {
 | 
				
			||||||
	m := make(map[string]interface{})
 | 
						m := make(map[string]interface{})
 | 
				
			||||||
	if err := json.Unmarshal(b, &m); err != nil {
 | 
						if err := json.Unmarshal(b, &m); err != nil {
 | 
				
			||||||
@ -61,7 +71,8 @@ func (j *JSONMetadataParser) Parse(b []byte) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Metadata returns the metadata parsed by this parser
 | 
					// Parsed metadata.
 | 
				
			||||||
 | 
					// Should be called after a call to Parse returns no error
 | 
				
			||||||
func (j *JSONMetadataParser) Metadata() Metadata {
 | 
					func (j *JSONMetadataParser) Metadata() Metadata {
 | 
				
			||||||
	return j.metadata
 | 
						return j.metadata
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -81,7 +92,7 @@ type TOMLMetadataParser struct {
 | 
				
			|||||||
	metadata Metadata
 | 
						metadata Metadata
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Parse parses b into metadata
 | 
					// Parse the metadata
 | 
				
			||||||
func (t *TOMLMetadataParser) Parse(b []byte) error {
 | 
					func (t *TOMLMetadataParser) Parse(b []byte) error {
 | 
				
			||||||
	m := make(map[string]interface{})
 | 
						m := make(map[string]interface{})
 | 
				
			||||||
	if err := toml.Unmarshal(b, &m); err != nil {
 | 
						if err := toml.Unmarshal(b, &m); err != nil {
 | 
				
			||||||
@ -91,7 +102,8 @@ func (t *TOMLMetadataParser) Parse(b []byte) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Metadata returns the metadata parsed by this parser
 | 
					// Parsed metadata.
 | 
				
			||||||
 | 
					// Should be called after a call to Parse returns no error
 | 
				
			||||||
func (t *TOMLMetadataParser) Metadata() Metadata {
 | 
					func (t *TOMLMetadataParser) Metadata() Metadata {
 | 
				
			||||||
	return t.metadata
 | 
						return t.metadata
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -106,12 +118,12 @@ func (t *TOMLMetadataParser) Closing() []byte {
 | 
				
			|||||||
	return []byte("+++")
 | 
						return []byte("+++")
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// YAMLMetadataParser is the MetdataParser for YAML
 | 
					// YAMLMetadataParser is the MetadataParser for YAML
 | 
				
			||||||
type YAMLMetadataParser struct {
 | 
					type YAMLMetadataParser struct {
 | 
				
			||||||
	metadata Metadata
 | 
						metadata Metadata
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Parse parses b into metadata
 | 
					// Parse the metadata
 | 
				
			||||||
func (y *YAMLMetadataParser) Parse(b []byte) error {
 | 
					func (y *YAMLMetadataParser) Parse(b []byte) error {
 | 
				
			||||||
	m := make(map[string]interface{})
 | 
						m := make(map[string]interface{})
 | 
				
			||||||
	if err := yaml.Unmarshal(b, &m); err != nil {
 | 
						if err := yaml.Unmarshal(b, &m); err != nil {
 | 
				
			||||||
@ -121,7 +133,8 @@ func (y *YAMLMetadataParser) Parse(b []byte) error {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// Metadata returns the metadata parsed by this parser
 | 
					// Parsed metadata.
 | 
				
			||||||
 | 
					// Should be called after a call to Parse returns no error
 | 
				
			||||||
func (y *YAMLMetadataParser) Metadata() Metadata {
 | 
					func (y *YAMLMetadataParser) Metadata() Metadata {
 | 
				
			||||||
	return y.metadata
 | 
						return y.metadata
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -19,9 +19,9 @@ const (
 | 
				
			|||||||
	StaticDir       = ".caddy_static"
 | 
						StaticDir       = ".caddy_static"
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// process the contents of a page.
 | 
					// process processes the contents of a page.
 | 
				
			||||||
// It parses the metadata if any and uses the template if found
 | 
					// It parses the metadata (if any) and uses the template (if found)
 | 
				
			||||||
func (md Markdown) process(c Config, fpath string, b []byte) ([]byte, error) {
 | 
					func (md Markdown) process(c Config, requestPath string, b []byte) ([]byte, error) {
 | 
				
			||||||
	metadata, markdown, err := extractMetadata(b)
 | 
						metadata, markdown, err := extractMetadata(b)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return nil, err
 | 
							return nil, err
 | 
				
			||||||
@ -46,10 +46,11 @@ func (md Markdown) process(c Config, fpath string, b []byte) ([]byte, error) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	// process markdown
 | 
						// process markdown
 | 
				
			||||||
	markdown = blackfriday.Markdown(markdown, c.Renderer, 0)
 | 
						markdown = blackfriday.Markdown(markdown, c.Renderer, 0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// set it as body for template
 | 
						// set it as body for template
 | 
				
			||||||
	metadata.Variables["body"] = string(markdown)
 | 
						metadata.Variables["body"] = string(markdown)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return md.processTemplate(c, fpath, tmpl, metadata)
 | 
						return md.processTemplate(c, requestPath, tmpl, metadata)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// extractMetadata extracts metadata content from a page.
 | 
					// extractMetadata extracts metadata content from a page.
 | 
				
			||||||
@ -60,12 +61,12 @@ func extractMetadata(b []byte) (metadata Metadata, markdown []byte, err error) {
 | 
				
			|||||||
	reader := bytes.NewBuffer(b)
 | 
						reader := bytes.NewBuffer(b)
 | 
				
			||||||
	scanner := bufio.NewScanner(reader)
 | 
						scanner := bufio.NewScanner(reader)
 | 
				
			||||||
	var parser MetadataParser
 | 
						var parser MetadataParser
 | 
				
			||||||
	//	if scanner.Scan() &&
 | 
					
 | 
				
			||||||
	// Read first line
 | 
						// Read first line
 | 
				
			||||||
	if scanner.Scan() {
 | 
						if scanner.Scan() {
 | 
				
			||||||
		line := scanner.Bytes()
 | 
							line := scanner.Bytes()
 | 
				
			||||||
		parser = findParser(line)
 | 
							parser = findParser(line)
 | 
				
			||||||
		// if no parser found
 | 
							// if no parser found,
 | 
				
			||||||
		// assume metadata not present
 | 
							// assume metadata not present
 | 
				
			||||||
		if parser == nil {
 | 
							if parser == nil {
 | 
				
			||||||
			return metadata, b, nil
 | 
								return metadata, b, nil
 | 
				
			||||||
@ -78,7 +79,8 @@ func extractMetadata(b []byte) (metadata Metadata, markdown []byte, err error) {
 | 
				
			|||||||
	// Read remaining lines until closing identifier is found
 | 
						// Read remaining lines until closing identifier is found
 | 
				
			||||||
	for scanner.Scan() {
 | 
						for scanner.Scan() {
 | 
				
			||||||
		line := scanner.Bytes()
 | 
							line := scanner.Bytes()
 | 
				
			||||||
		// closing identifier found
 | 
					
 | 
				
			||||||
 | 
							// if closing identifier found
 | 
				
			||||||
		if bytes.Equal(bytes.TrimSpace(line), parser.Closing()) {
 | 
							if bytes.Equal(bytes.TrimSpace(line), parser.Closing()) {
 | 
				
			||||||
			// parse the metadata
 | 
								// parse the metadata
 | 
				
			||||||
			err := parser.Parse(buf.Bytes())
 | 
								err := parser.Parse(buf.Bytes())
 | 
				
			||||||
@ -97,10 +99,12 @@ func extractMetadata(b []byte) (metadata Metadata, markdown []byte, err error) {
 | 
				
			|||||||
		buf.Write(line)
 | 
							buf.Write(line)
 | 
				
			||||||
		buf.WriteString("\r\n")
 | 
							buf.WriteString("\r\n")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// closing identifier not found
 | 
				
			||||||
	return metadata, nil, fmt.Errorf("Metadata not closed. '%v' not found", string(parser.Closing()))
 | 
						return metadata, nil, fmt.Errorf("Metadata not closed. '%v' not found", string(parser.Closing()))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// findParser locates the parser for an opening identifier
 | 
					// findParser finds the parser using line that contains opening identifier
 | 
				
			||||||
func findParser(line []byte) MetadataParser {
 | 
					func findParser(line []byte) MetadataParser {
 | 
				
			||||||
	line = bytes.TrimSpace(line)
 | 
						line = bytes.TrimSpace(line)
 | 
				
			||||||
	for _, parser := range parsers {
 | 
						for _, parser := range parsers {
 | 
				
			||||||
@ -111,13 +115,16 @@ func findParser(line []byte) MetadataParser {
 | 
				
			|||||||
	return nil
 | 
						return nil
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (md Markdown) processTemplate(c Config, fpath string, tmpl []byte, metadata Metadata) ([]byte, error) {
 | 
					// processTemplate processes a template given a requestPath,
 | 
				
			||||||
	// if template is specified
 | 
					// template (tmpl) and metadata
 | 
				
			||||||
	// replace parse the template
 | 
					func (md Markdown) processTemplate(c Config, requestPath string, tmpl []byte, metadata Metadata) ([]byte, error) {
 | 
				
			||||||
	if tmpl != nil {
 | 
						// if template is not specified,
 | 
				
			||||||
		tmpl = defaultTemplate(c, metadata, fpath)
 | 
						// use the default template
 | 
				
			||||||
 | 
						if tmpl == nil {
 | 
				
			||||||
 | 
							tmpl = defaultTemplate(c, metadata, requestPath)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// process the template
 | 
				
			||||||
	b := &bytes.Buffer{}
 | 
						b := &bytes.Buffer{}
 | 
				
			||||||
	t, err := template.New("").Parse(string(tmpl))
 | 
						t, err := template.New("").Parse(string(tmpl))
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
@ -128,7 +135,7 @@ func (md Markdown) processTemplate(c Config, fpath string, tmpl []byte, metadata
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// generate static page
 | 
						// generate static page
 | 
				
			||||||
	if err = md.generatePage(c, fpath, b.Bytes()); err != nil {
 | 
						if err = md.generatePage(c, requestPath, b.Bytes()); err != nil {
 | 
				
			||||||
		// if static page generation fails,
 | 
							// if static page generation fails,
 | 
				
			||||||
		// nothing fatal, only log the error.
 | 
							// nothing fatal, only log the error.
 | 
				
			||||||
		log.Println(err)
 | 
							log.Println(err)
 | 
				
			||||||
@ -138,8 +145,47 @@ func (md Markdown) processTemplate(c Config, fpath string, tmpl []byte, metadata
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func defaultTemplate(c Config, metadata Metadata, fpath string) []byte {
 | 
					// generatePage generates a static html page from the markdown in content.
 | 
				
			||||||
	// else, use default template
 | 
					func (md Markdown) generatePage(c Config, requestPath string, content []byte) error {
 | 
				
			||||||
 | 
						// should not happen,
 | 
				
			||||||
 | 
						// must be set on Markdown init.
 | 
				
			||||||
 | 
						if c.StaticDir == "" {
 | 
				
			||||||
 | 
							return fmt.Errorf("Static directory not set")
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// if static directory is not existing, create it
 | 
				
			||||||
 | 
						if _, err := os.Stat(c.StaticDir); err != nil {
 | 
				
			||||||
 | 
							err := os.MkdirAll(c.StaticDir, os.FileMode(0755))
 | 
				
			||||||
 | 
							if err != nil {
 | 
				
			||||||
 | 
								return err
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						filePath := filepath.Join(c.StaticDir, requestPath)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// If it is index file, use the directory instead
 | 
				
			||||||
 | 
						if md.IsIndexFile(filepath.Base(requestPath)) {
 | 
				
			||||||
 | 
							filePath, _ = filepath.Split(filePath)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Create the directory in case it is not existing
 | 
				
			||||||
 | 
						if err := os.MkdirAll(filePath, os.FileMode(0755)); err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// generate index.html file in the directory
 | 
				
			||||||
 | 
						filePath = filepath.Join(filePath, "index.html")
 | 
				
			||||||
 | 
						err := ioutil.WriteFile(filePath, content, os.FileMode(0755))
 | 
				
			||||||
 | 
						if err != nil {
 | 
				
			||||||
 | 
							return err
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						c.StaticFiles[requestPath] = filePath
 | 
				
			||||||
 | 
						return nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// defaultTemplate constructs a default template.
 | 
				
			||||||
 | 
					func defaultTemplate(c Config, metadata Metadata, requestPath string) []byte {
 | 
				
			||||||
	var scripts, styles bytes.Buffer
 | 
						var scripts, styles bytes.Buffer
 | 
				
			||||||
	for _, style := range c.Styles {
 | 
						for _, style := range c.Styles {
 | 
				
			||||||
		styles.WriteString(strings.Replace(cssTemplate, "{{url}}", style, 1))
 | 
							styles.WriteString(strings.Replace(cssTemplate, "{{url}}", style, 1))
 | 
				
			||||||
@ -153,7 +199,7 @@ func defaultTemplate(c Config, metadata Metadata, fpath string) []byte {
 | 
				
			|||||||
	// Title is first line (length-limited), otherwise filename
 | 
						// Title is first line (length-limited), otherwise filename
 | 
				
			||||||
	title := metadata.Title
 | 
						title := metadata.Title
 | 
				
			||||||
	if title == "" {
 | 
						if title == "" {
 | 
				
			||||||
		title = filepath.Base(fpath)
 | 
							title = filepath.Base(requestPath)
 | 
				
			||||||
		if body, _ := metadata.Variables["body"].([]byte); len(body) > 128 {
 | 
							if body, _ := metadata.Variables["body"].([]byte); len(body) > 128 {
 | 
				
			||||||
			title = string(body[:128])
 | 
								title = string(body[:128])
 | 
				
			||||||
		} else if len(body) > 0 {
 | 
							} else if len(body) > 0 {
 | 
				
			||||||
@ -169,42 +215,6 @@ func defaultTemplate(c Config, metadata Metadata, fpath string) []byte {
 | 
				
			|||||||
	return html
 | 
						return html
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func (md Markdown) generatePage(c Config, fpath string, content []byte) error {
 | 
					 | 
				
			||||||
	// should not happen
 | 
					 | 
				
			||||||
	// must be set on init
 | 
					 | 
				
			||||||
	if c.StaticDir == "" {
 | 
					 | 
				
			||||||
		return fmt.Errorf("Static directory not set")
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// if static directory is not existing, create it
 | 
					 | 
				
			||||||
	if _, err := os.Stat(c.StaticDir); err != nil {
 | 
					 | 
				
			||||||
		err := os.MkdirAll(c.StaticDir, os.FileMode(0755))
 | 
					 | 
				
			||||||
		if err != nil {
 | 
					 | 
				
			||||||
			return err
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	filePath := filepath.Join(c.StaticDir, fpath)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// If it is index file, use the directory instead
 | 
					 | 
				
			||||||
	if md.IsIndexFile(filepath.Base(fpath)) {
 | 
					 | 
				
			||||||
		filePath, _ = filepath.Split(filePath)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	if err := os.MkdirAll(filePath, os.FileMode(0755)); err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// generate index.html file in the directory
 | 
					 | 
				
			||||||
	filePath = filepath.Join(filePath, "index.html")
 | 
					 | 
				
			||||||
	err := ioutil.WriteFile(filePath, content, os.FileMode(0755))
 | 
					 | 
				
			||||||
	if err != nil {
 | 
					 | 
				
			||||||
		return err
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	c.StaticFiles[fpath] = filePath
 | 
					 | 
				
			||||||
	return nil
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	htmlTemplate = `<!DOCTYPE html>
 | 
						htmlTemplate = `<!DOCTYPE html>
 | 
				
			||||||
<html>
 | 
					<html>
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user