github.com/jgarto/itcv@v0.0.0-20180826224514-4eea09c1aa0d/_vendor/src/golang.org/x/tools/cmd/present/dir.go (about)

     1  // Copyright 2012 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package main
     6  
     7  import (
     8  	"html/template"
     9  	"io"
    10  	"log"
    11  	"net"
    12  	"net/http"
    13  	"os"
    14  	"path/filepath"
    15  	"sort"
    16  
    17  	"golang.org/x/tools/present"
    18  )
    19  
    20  func init() {
    21  	http.HandleFunc("/", dirHandler)
    22  }
    23  
    24  // dirHandler serves a directory listing for the requested path, rooted at basePath.
    25  func dirHandler(w http.ResponseWriter, r *http.Request) {
    26  	if r.URL.Path == "/favicon.ico" {
    27  		http.Error(w, "not found", 404)
    28  		return
    29  	}
    30  	const base = "."
    31  	name := filepath.Join(base, r.URL.Path)
    32  	if isDoc(name) {
    33  		err := renderDoc(w, name)
    34  		if err != nil {
    35  			log.Println(err)
    36  			http.Error(w, err.Error(), 500)
    37  		}
    38  		return
    39  	}
    40  	if isDir, err := dirList(w, name); err != nil {
    41  		addr, _, e := net.SplitHostPort(r.RemoteAddr)
    42  		if e != nil {
    43  			addr = r.RemoteAddr
    44  		}
    45  		log.Printf("request from %s: %s", addr, err)
    46  		http.Error(w, err.Error(), 500)
    47  		return
    48  	} else if isDir {
    49  		return
    50  	}
    51  	http.FileServer(http.Dir(base)).ServeHTTP(w, r)
    52  }
    53  
    54  func isDoc(path string) bool {
    55  	_, ok := contentTemplate[filepath.Ext(path)]
    56  	return ok
    57  }
    58  
    59  var (
    60  	// dirListTemplate holds the front page template.
    61  	dirListTemplate *template.Template
    62  
    63  	// contentTemplate maps the presentable file extensions to the
    64  	// template to be executed.
    65  	contentTemplate map[string]*template.Template
    66  )
    67  
    68  func initTemplates(base string) error {
    69  	// Locate the template file.
    70  	actionTmpl := filepath.Join(base, "templates/action.tmpl")
    71  
    72  	contentTemplate = make(map[string]*template.Template)
    73  
    74  	for ext, contentTmpl := range map[string]string{
    75  		".slide":   "slides.tmpl",
    76  		".article": "article.tmpl",
    77  	} {
    78  		contentTmpl = filepath.Join(base, "templates", contentTmpl)
    79  
    80  		// Read and parse the input.
    81  		tmpl := present.Template()
    82  		tmpl = tmpl.Funcs(template.FuncMap{"playable": playable})
    83  		if _, err := tmpl.ParseFiles(actionTmpl, contentTmpl); err != nil {
    84  			return err
    85  		}
    86  		contentTemplate[ext] = tmpl
    87  	}
    88  
    89  	var err error
    90  	dirListTemplate, err = template.ParseFiles(filepath.Join(base, "templates/dir.tmpl"))
    91  	return err
    92  }
    93  
    94  // renderDoc reads the present file, gets its template representation,
    95  // and executes the template, sending output to w.
    96  func renderDoc(w io.Writer, docFile string) error {
    97  	// Read the input and build the doc structure.
    98  	doc, err := parse(docFile, 0)
    99  	if err != nil {
   100  		return err
   101  	}
   102  
   103  	// Find which template should be executed.
   104  	tmpl := contentTemplate[filepath.Ext(docFile)]
   105  
   106  	// Execute the template.
   107  	return doc.Render(w, tmpl)
   108  }
   109  
   110  func parse(name string, mode present.ParseMode) (*present.Doc, error) {
   111  	f, err := os.Open(name)
   112  	if err != nil {
   113  		return nil, err
   114  	}
   115  	defer f.Close()
   116  	return present.Parse(f, name, mode)
   117  }
   118  
   119  // dirList scans the given path and writes a directory listing to w.
   120  // It parses the first part of each .slide file it encounters to display the
   121  // presentation title in the listing.
   122  // If the given path is not a directory, it returns (isDir == false, err == nil)
   123  // and writes nothing to w.
   124  func dirList(w io.Writer, name string) (isDir bool, err error) {
   125  	f, err := os.Open(name)
   126  	if err != nil {
   127  		return false, err
   128  	}
   129  	defer f.Close()
   130  	fi, err := f.Stat()
   131  	if err != nil {
   132  		return false, err
   133  	}
   134  	if isDir = fi.IsDir(); !isDir {
   135  		return false, nil
   136  	}
   137  	fis, err := f.Readdir(0)
   138  	if err != nil {
   139  		return false, err
   140  	}
   141  	d := &dirListData{Path: name}
   142  	for _, fi := range fis {
   143  		// skip the golang.org directory
   144  		if name == "." && fi.Name() == "golang.org" {
   145  			continue
   146  		}
   147  		e := dirEntry{
   148  			Name: fi.Name(),
   149  			Path: filepath.ToSlash(filepath.Join(name, fi.Name())),
   150  		}
   151  		if fi.IsDir() && showDir(e.Name) {
   152  			d.Dirs = append(d.Dirs, e)
   153  			continue
   154  		}
   155  		if isDoc(e.Name) {
   156  			if p, err := parse(e.Path, present.TitlesOnly); err != nil {
   157  				log.Println(err)
   158  			} else {
   159  				e.Title = p.Title
   160  			}
   161  			switch filepath.Ext(e.Path) {
   162  			case ".article":
   163  				d.Articles = append(d.Articles, e)
   164  			case ".slide":
   165  				d.Slides = append(d.Slides, e)
   166  			}
   167  		} else if showFile(e.Name) {
   168  			d.Other = append(d.Other, e)
   169  		}
   170  	}
   171  	if d.Path == "." {
   172  		d.Path = ""
   173  	}
   174  	sort.Sort(d.Dirs)
   175  	sort.Sort(d.Slides)
   176  	sort.Sort(d.Articles)
   177  	sort.Sort(d.Other)
   178  	return true, dirListTemplate.Execute(w, d)
   179  }
   180  
   181  // showFile reports whether the given file should be displayed in the list.
   182  func showFile(n string) bool {
   183  	switch filepath.Ext(n) {
   184  	case ".pdf":
   185  	case ".html":
   186  	case ".go":
   187  	default:
   188  		return isDoc(n)
   189  	}
   190  	return true
   191  }
   192  
   193  // showDir reports whether the given directory should be displayed in the list.
   194  func showDir(n string) bool {
   195  	if len(n) > 0 && (n[0] == '.' || n[0] == '_') || n == "present" {
   196  		return false
   197  	}
   198  	return true
   199  }
   200  
   201  type dirListData struct {
   202  	Path                          string
   203  	Dirs, Slides, Articles, Other dirEntrySlice
   204  }
   205  
   206  type dirEntry struct {
   207  	Name, Path, Title string
   208  }
   209  
   210  type dirEntrySlice []dirEntry
   211  
   212  func (s dirEntrySlice) Len() int           { return len(s) }
   213  func (s dirEntrySlice) Swap(i, j int)      { s[i], s[j] = s[j], s[i] }
   214  func (s dirEntrySlice) Less(i, j int) bool { return s[i].Name < s[j].Name }