mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-31 05:40:42 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			292 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			292 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| /*
 | |
| Copyright 2015 The Kubernetes Authors.
 | |
| 
 | |
| Licensed under the Apache License, Version 2.0 (the "License");
 | |
| you may not use this file except in compliance with the License.
 | |
| You may obtain a copy of the License at
 | |
| 
 | |
|     http://www.apache.org/licenses/LICENSE-2.0
 | |
| 
 | |
| Unless required by applicable law or agreed to in writing, software
 | |
| distributed under the License is distributed on an "AS IS" BASIS,
 | |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| See the License for the specific language governing permissions and
 | |
| limitations under the License.
 | |
| */
 | |
| 
 | |
| package main
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"path"
 | |
| 	"path/filepath"
 | |
| 	"regexp"
 | |
| 	"strings"
 | |
| 	"unicode"
 | |
| )
 | |
| 
 | |
| // Replaces the text between matching "beginMark" and "endMark" within the
 | |
| // document represented by "lines" with "insertThis".
 | |
| //
 | |
| // Delimiters should occupy own line.
 | |
| // Returns copy of document with modifications.
 | |
| func updateMacroBlock(mlines mungeLines, token string, insertThis mungeLines) (mungeLines, error) {
 | |
| 	beginMark := beginMungeTag(token)
 | |
| 	endMark := endMungeTag(token)
 | |
| 	var out mungeLines
 | |
| 	betweenBeginAndEnd := false
 | |
| 	for _, mline := range mlines {
 | |
| 		if mline.preformatted && !betweenBeginAndEnd {
 | |
| 			out = append(out, mline)
 | |
| 			continue
 | |
| 		}
 | |
| 		line := mline.data
 | |
| 		if mline.beginTag && line == beginMark {
 | |
| 			if betweenBeginAndEnd {
 | |
| 				return nil, fmt.Errorf("found second begin mark while updating macro blocks")
 | |
| 			}
 | |
| 			betweenBeginAndEnd = true
 | |
| 			out = append(out, mline)
 | |
| 		} else if mline.endTag && line == endMark {
 | |
| 			if !betweenBeginAndEnd {
 | |
| 				return nil, fmt.Errorf("found end mark without begin mark while updating macro blocks")
 | |
| 			}
 | |
| 			betweenBeginAndEnd = false
 | |
| 			out = append(out, insertThis...)
 | |
| 			out = append(out, mline)
 | |
| 		} else {
 | |
| 			if !betweenBeginAndEnd {
 | |
| 				out = append(out, mline)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if betweenBeginAndEnd {
 | |
| 		return nil, fmt.Errorf("never found closing end mark while updating macro blocks")
 | |
| 	}
 | |
| 	return out, nil
 | |
| }
 | |
| 
 | |
| // Tests that a document, represented as a slice of lines, has a line.  Ignores
 | |
| // leading and trailing space.
 | |
| func hasLine(lines mungeLines, needle string) bool {
 | |
| 	for _, mline := range lines {
 | |
| 		haystack := strings.TrimSpace(mline.data)
 | |
| 		if haystack == needle {
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| func removeMacroBlock(token string, mlines mungeLines) (mungeLines, error) {
 | |
| 	beginMark := beginMungeTag(token)
 | |
| 	endMark := endMungeTag(token)
 | |
| 	var out mungeLines
 | |
| 	betweenBeginAndEnd := false
 | |
| 	for _, mline := range mlines {
 | |
| 		if mline.preformatted {
 | |
| 			out = append(out, mline)
 | |
| 			continue
 | |
| 		}
 | |
| 		line := mline.data
 | |
| 		if mline.beginTag && line == beginMark {
 | |
| 			if betweenBeginAndEnd {
 | |
| 				return nil, fmt.Errorf("found second begin mark while updating macro blocks")
 | |
| 			}
 | |
| 			betweenBeginAndEnd = true
 | |
| 		} else if mline.endTag && line == endMark {
 | |
| 			if !betweenBeginAndEnd {
 | |
| 				return nil, fmt.Errorf("found end mark without begin mark while updating macro blocks")
 | |
| 			}
 | |
| 			betweenBeginAndEnd = false
 | |
| 		} else {
 | |
| 			if !betweenBeginAndEnd {
 | |
| 				out = append(out, mline)
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 	if betweenBeginAndEnd {
 | |
| 		return nil, fmt.Errorf("never found closing end mark while updating macro blocks")
 | |
| 	}
 | |
| 	return out, nil
 | |
| }
 | |
| 
 | |
| // Add a macro block to the beginning of a set of lines
 | |
| func prependMacroBlock(token string, mlines mungeLines) mungeLines {
 | |
| 	beginLine := newMungeLine(beginMungeTag(token))
 | |
| 	endLine := newMungeLine(endMungeTag(token))
 | |
| 	out := mungeLines{beginLine, endLine}
 | |
| 	if len(mlines) > 0 && mlines[0].data != "" {
 | |
| 		out = append(out, blankMungeLine)
 | |
| 	}
 | |
| 	return append(out, mlines...)
 | |
| }
 | |
| 
 | |
| // Add a macro block to the end of a set of lines
 | |
| func appendMacroBlock(mlines mungeLines, token string) mungeLines {
 | |
| 	beginLine := newMungeLine(beginMungeTag(token))
 | |
| 	endLine := newMungeLine(endMungeTag(token))
 | |
| 	out := mlines
 | |
| 	if len(mlines) > 0 && mlines[len(mlines)-1].data != "" {
 | |
| 		out = append(out, blankMungeLine)
 | |
| 	}
 | |
| 	return append(out, beginLine, endLine)
 | |
| }
 | |
| 
 | |
| // Tests that a document, represented as a slice of lines, has a macro block.
 | |
| func hasMacroBlock(lines mungeLines, token string) bool {
 | |
| 	beginMark := beginMungeTag(token)
 | |
| 	endMark := endMungeTag(token)
 | |
| 
 | |
| 	foundBegin := false
 | |
| 	for _, mline := range lines {
 | |
| 		if mline.preformatted {
 | |
| 			continue
 | |
| 		}
 | |
| 		if !mline.beginTag && !mline.endTag {
 | |
| 			continue
 | |
| 		}
 | |
| 		line := mline.data
 | |
| 		switch {
 | |
| 		case !foundBegin && line == beginMark:
 | |
| 			foundBegin = true
 | |
| 		case foundBegin && line == endMark:
 | |
| 			return true
 | |
| 		}
 | |
| 	}
 | |
| 	return false
 | |
| }
 | |
| 
 | |
| // Returns the canonical begin-tag for a given description.  This does not
 | |
| // include the trailing newline.
 | |
| func beginMungeTag(desc string) string {
 | |
| 	return fmt.Sprintf("<!-- BEGIN MUNGE: %s -->", desc)
 | |
| }
 | |
| 
 | |
| // Returns the canonical end-tag for a given description.  This does not
 | |
| // include the trailing newline.
 | |
| func endMungeTag(desc string) string {
 | |
| 	return fmt.Sprintf("<!-- END MUNGE: %s -->", desc)
 | |
| }
 | |
| 
 | |
| type mungeLine struct {
 | |
| 	data         string
 | |
| 	preformatted bool
 | |
| 	header       bool
 | |
| 	link         bool
 | |
| 	beginTag     bool
 | |
| 	endTag       bool
 | |
| }
 | |
| 
 | |
| type mungeLines []mungeLine
 | |
| 
 | |
| func (m1 mungeLines) Equal(m2 mungeLines) bool {
 | |
| 	if len(m1) != len(m2) {
 | |
| 		return false
 | |
| 	}
 | |
| 	for i := range m1 {
 | |
| 		if m1[i].data != m2[i].data {
 | |
| 			return false
 | |
| 		}
 | |
| 	}
 | |
| 	return true
 | |
| }
 | |
| 
 | |
| func (mlines mungeLines) String() string {
 | |
| 	slice := []string{}
 | |
| 	for _, mline := range mlines {
 | |
| 		slice = append(slice, mline.data)
 | |
| 	}
 | |
| 	s := strings.Join(slice, "\n")
 | |
| 	// We need to tack on an extra newline at the end of the file
 | |
| 	return s + "\n"
 | |
| }
 | |
| 
 | |
| func (mlines mungeLines) Bytes() []byte {
 | |
| 	return []byte(mlines.String())
 | |
| }
 | |
| 
 | |
| var (
 | |
| 	// Finds all preformatted block start/stops.
 | |
| 	preformatRE    = regexp.MustCompile("^\\s*```")
 | |
| 	notPreformatRE = regexp.MustCompile("^\\s*```.*```")
 | |
| 	// Is this line a header?
 | |
| 	mlHeaderRE = regexp.MustCompile(`^#`)
 | |
| 	// Is there a link on this line?
 | |
| 	mlLinkRE   = regexp.MustCompile(`\[[^]]*\]\([^)]*\)`)
 | |
| 	beginTagRE = regexp.MustCompile(`<!-- BEGIN MUNGE:`)
 | |
| 	endTagRE   = regexp.MustCompile(`<!-- END MUNGE:`)
 | |
| 
 | |
| 	blankMungeLine = newMungeLine("")
 | |
| )
 | |
| 
 | |
| // Does not set 'preformatted'
 | |
| func newMungeLine(line string) mungeLine {
 | |
| 	return mungeLine{
 | |
| 		data:     line,
 | |
| 		header:   mlHeaderRE.MatchString(line),
 | |
| 		link:     mlLinkRE.MatchString(line),
 | |
| 		beginTag: beginTagRE.MatchString(line),
 | |
| 		endTag:   endTagRE.MatchString(line),
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func trimRightSpace(in string) string {
 | |
| 	return strings.TrimRightFunc(in, unicode.IsSpace)
 | |
| }
 | |
| 
 | |
| // Splits a document up into a slice of lines.
 | |
| func splitLines(document string) []string {
 | |
| 	lines := strings.Split(document, "\n")
 | |
| 	// Skip trailing empty string from Split-ing
 | |
| 	if len(lines) > 0 && lines[len(lines)-1] == "" {
 | |
| 		lines = lines[:len(lines)-1]
 | |
| 	}
 | |
| 	return lines
 | |
| }
 | |
| 
 | |
| func getMungeLines(in string) mungeLines {
 | |
| 	var out mungeLines
 | |
| 	preformatted := false
 | |
| 
 | |
| 	lines := splitLines(in)
 | |
| 	// We indicate if any given line is inside a preformatted block or
 | |
| 	// outside a preformatted block
 | |
| 	for _, line := range lines {
 | |
| 		if !preformatted {
 | |
| 			if preformatRE.MatchString(line) && !notPreformatRE.MatchString(line) {
 | |
| 				preformatted = true
 | |
| 			}
 | |
| 		} else {
 | |
| 			if preformatRE.MatchString(line) {
 | |
| 				preformatted = false
 | |
| 			}
 | |
| 		}
 | |
| 		ml := newMungeLine(line)
 | |
| 		ml.preformatted = preformatted
 | |
| 		out = append(out, ml)
 | |
| 	}
 | |
| 	return out
 | |
| }
 | |
| 
 | |
| // filePath is the file we are looking for
 | |
| // inFile is the file where we found the link. So if we are processing
 | |
| //    /path/to/repoRoot/docs/admin/README.md and are looking for
 | |
| //    ../../file.json we can find that location.
 | |
| // In many cases filePath and processingFile may be the same
 | |
| func makeRepoRelative(filePath string, processingFile string) (string, error) {
 | |
| 	if filePath, err := filepath.Rel(repoRoot, filePath); err == nil {
 | |
| 		return filePath, nil
 | |
| 	}
 | |
| 	cwd := path.Dir(processingFile)
 | |
| 	return filepath.Rel(repoRoot, path.Join(cwd, filePath))
 | |
| }
 | |
| 
 | |
| func makeFileRelative(filePath string, processingFile string) (string, error) {
 | |
| 	cwd := path.Dir(processingFile)
 | |
| 	if filePath, err := filepath.Rel(cwd, filePath); err == nil {
 | |
| 		return filePath, nil
 | |
| 	}
 | |
| 	return filepath.Rel(cwd, path.Join(cwd, filePath))
 | |
| }
 |