Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(971)

Side by Side Diff: src/cmd/godoc/utils.go

Issue 5711058: code review 5711058: godoc: support $GOPATH, simplify file system code (Closed)
Patch Set: diff -r 8d4fd582202b https://go.googlecode.com/hg/ Created 12 years ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/cmd/godoc/parser.go ('k') | src/cmd/godoc/zip.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2010 The Go Authors. All rights reserved. 1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // This file contains support functionality for godoc. 5 // This file contains support functionality for godoc.
6 6
7 package main 7 package main
8 8
9 import ( 9 import (
10 » "io" 10 » pathpkg "path"
11 » "io/ioutil"
12 » "os"
13 » "path/filepath"
14 » "sort"
15 » "strings"
16 "sync" 11 "sync"
17 "time" 12 "time"
18 "unicode/utf8" 13 "unicode/utf8"
19 ) 14 )
20 15
21 // An RWValue wraps a value and permits mutually exclusive 16 // An RWValue wraps a value and permits mutually exclusive
22 // access to it and records the time the value was last set. 17 // access to it and records the time the value was last set.
23 // 18 //
24 type RWValue struct { 19 type RWValue struct {
25 mutex sync.RWMutex 20 mutex sync.RWMutex
26 value interface{} 21 value interface{}
27 timestamp time.Time // time of last set() 22 timestamp time.Time // time of last set()
28 } 23 }
29 24
30 func (v *RWValue) set(value interface{}) { 25 func (v *RWValue) set(value interface{}) {
31 v.mutex.Lock() 26 v.mutex.Lock()
32 v.value = value 27 v.value = value
33 v.timestamp = time.Now() 28 v.timestamp = time.Now()
34 v.mutex.Unlock() 29 v.mutex.Unlock()
35 } 30 }
36 31
37 func (v *RWValue) get() (interface{}, time.Time) { 32 func (v *RWValue) get() (interface{}, time.Time) {
38 v.mutex.RLock() 33 v.mutex.RLock()
39 defer v.mutex.RUnlock() 34 defer v.mutex.RUnlock()
40 return v.value, v.timestamp 35 return v.value, v.timestamp
41 } 36 }
42 37
43 // TODO(gri) For now, using os.Getwd() is ok here since the functionality
44 // based on this code is not invoked for the appengine version,
45 // but this is fragile. Determine what the right thing to do is,
46 // here (possibly have some Getwd-equivalent in FileSystem).
47 var cwd, _ = os.Getwd() // ignore errors
48
49 // canonicalizePaths takes a list of (directory/file) paths and returns
50 // the list of corresponding absolute paths in sorted (increasing) order.
51 // Relative paths are assumed to be relative to the current directory,
52 // empty and duplicate paths as well as paths for which filter(path) is
53 // false are discarded. filter may be nil in which case it is not used.
54 //
55 func canonicalizePaths(list []string, filter func(path string) bool) []string {
56 i := 0
57 for _, path := range list {
58 path = strings.TrimSpace(path)
59 if len(path) == 0 {
60 continue // ignore empty paths (don't assume ".")
61 }
62 // len(path) > 0: normalize path
63 if filepath.IsAbs(path) {
64 path = filepath.Clean(path)
65 } else {
66 path = filepath.Join(cwd, path)
67 }
68 // we have a non-empty absolute path
69 if filter != nil && !filter(path) {
70 continue
71 }
72 // keep the path
73 list[i] = path
74 i++
75 }
76 list = list[0:i]
77
78 // sort the list and remove duplicate entries
79 sort.Strings(list)
80 i = 0
81 prev := ""
82 for _, path := range list {
83 if path != prev {
84 list[i] = path
85 i++
86 prev = path
87 }
88 }
89
90 return list[0:i]
91 }
92
93 // writeFileAtomically writes data to a temporary file and then
94 // atomically renames that file to the file named by filename.
95 //
96 func writeFileAtomically(filename string, data []byte) error {
97 // TODO(gri) this won't work on appengine
98 f, err := ioutil.TempFile(filepath.Split(filename))
99 if err != nil {
100 return err
101 }
102 n, err := f.Write(data)
103 f.Close()
104 if err != nil {
105 return err
106 }
107 if n < len(data) {
108 return io.ErrShortWrite
109 }
110 return os.Rename(f.Name(), filename)
111 }
112
113 // isText returns true if a significant prefix of s looks like correct UTF-8; 38 // isText returns true if a significant prefix of s looks like correct UTF-8;
114 // that is, if it is likely that s is human-readable text. 39 // that is, if it is likely that s is human-readable text.
115 // 40 //
116 func isText(s []byte) bool { 41 func isText(s []byte) bool {
117 const max = 1024 // at least utf8.UTFMax 42 const max = 1024 // at least utf8.UTFMax
118 if len(s) > max { 43 if len(s) > max {
119 s = s[0:max] 44 s = s[0:max]
120 } 45 }
121 for i, c := range string(s) { 46 for i, c := range string(s) {
122 if i+utf8.UTFMax > len(s) { 47 if i+utf8.UTFMax > len(s) {
(...skipping 16 matching lines...) Expand all
139 ".js": false, // must be served raw 64 ".js": false, // must be served raw
140 } 65 }
141 66
142 // isTextFile returns true if the file has a known extension indicating 67 // isTextFile returns true if the file has a known extension indicating
143 // a text file, or if a significant chunk of the specified file looks like 68 // a text file, or if a significant chunk of the specified file looks like
144 // correct UTF-8; that is, if it is likely that the file contains human- 69 // correct UTF-8; that is, if it is likely that the file contains human-
145 // readable text. 70 // readable text.
146 // 71 //
147 func isTextFile(filename string) bool { 72 func isTextFile(filename string) bool {
148 // if the extension is known, use it for decision making 73 // if the extension is known, use it for decision making
149 » if isText, found := textExt[filepath.Ext(filename)]; found { 74 » if isText, found := textExt[pathpkg.Ext(filename)]; found {
150 return isText 75 return isText
151 } 76 }
152 77
153 // the extension is not known; read an initial chunk 78 // the extension is not known; read an initial chunk
154 // of the file and check if it looks like text 79 // of the file and check if it looks like text
155 f, err := fs.Open(filename) 80 f, err := fs.Open(filename)
156 if err != nil { 81 if err != nil {
157 return false 82 return false
158 } 83 }
159 defer f.Close() 84 defer f.Close()
160 85
161 var buf [1024]byte 86 var buf [1024]byte
162 n, err := f.Read(buf[0:]) 87 n, err := f.Read(buf[0:])
163 if err != nil { 88 if err != nil {
164 return false 89 return false
165 } 90 }
166 91
167 return isText(buf[0:n]) 92 return isText(buf[0:n])
168 } 93 }
OLDNEW
« no previous file with comments | « src/cmd/godoc/parser.go ('k') | src/cmd/godoc/zip.go » ('j') | no next file with comments »

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b