1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
|
// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// This file contains support functionality for godoc.
package main
import (
"io"
"io/ioutil"
"os"
pathutil "path"
"sort"
"strings"
"sync"
"time"
)
// An RWValue wraps a value and permits mutually exclusive
// access to it and records the time the value was last set.
type RWValue struct {
mutex sync.RWMutex
value interface{}
timestamp int64 // time of last set(), in seconds since epoch
}
func (v *RWValue) set(value interface{}) {
v.mutex.Lock()
v.value = value
v.timestamp = time.Seconds()
v.mutex.Unlock()
}
func (v *RWValue) get() (interface{}, int64) {
v.mutex.RLock()
defer v.mutex.RUnlock()
return v.value, v.timestamp
}
var cwd, _ = os.Getwd() // ignore errors
// canonicalizePaths takes a list of (directory/file) paths and returns
// the list of corresponding absolute paths in sorted (increasing) order.
// Relative paths are assumed to be relative to the current directory,
// empty and duplicate paths as well as paths for which filter(path) is
// false are discarded. filter may be nil in which case it is not used.
//
func canonicalizePaths(list []string, filter func(path string) bool) []string {
i := 0
for _, path := range list {
path = strings.TrimSpace(path)
if len(path) == 0 {
continue // ignore empty paths (don't assume ".")
}
// len(path) > 0: normalize path
if path[0] != '/' {
path = pathutil.Join(cwd, path)
} else {
path = pathutil.Clean(path)
}
// we have a non-empty absolute path
if filter != nil && !filter(path) {
continue
}
// keep the path
list[i] = path
i++
}
list = list[0:i]
// sort the list and remove duplicate entries
sort.SortStrings(list)
i = 0
prev := ""
for _, path := range list {
if path != prev {
list[i] = path
i++
prev = path
}
}
return list[0:i]
}
// writeFileAtomically writes data to a temporary file and then
// atomically renames that file to the file named by filename.
//
func writeFileAtomically(filename string, data []byte) os.Error {
f, err := ioutil.TempFile(cwd, filename)
if err != nil {
return err
}
n, err := f.Write(data)
f.Close()
if err != nil {
return err
}
if n < len(data) {
return io.ErrShortWrite
}
return os.Rename(f.Name(), filename)
}
|