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

Side by Side Diff: src/cmd/godoc/httpzip.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/godoc.go ('k') | src/cmd/godoc/index.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2011 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 // This file provides an implementation of the http.FileSystem
6 // interface based on the contents of a .zip file.
7 //
8 // Assumptions:
9 //
10 // - The file paths stored in the zip file must use a slash ('/') as path
11 // separator; and they must be relative (i.e., they must not start with
12 // a '/' - this is usually the case if the file was created w/o special
13 // options).
14 // - The zip file system treats the file paths found in the zip internally
15 // like absolute paths w/o a leading '/'; i.e., the paths are considered
16 // relative to the root of the file system.
17 // - All path arguments to file system methods are considered relative to
18 // the root specified with NewHttpZipFS (even if the paths start with a '/').
19
20 // TODO(gri) Should define a commonly used FileSystem API that is the same
21 // for http and godoc. Then we only need one zip-file based file
22 // system implementation.
23
24 package main
25
26 import (
27 "archive/zip"
28 "fmt"
29 "io"
30 "net/http"
31 "os"
32 "path"
33 "sort"
34 "strings"
35 "time"
36 )
37
38 type fileInfo struct {
39 name string
40 mode os.FileMode
41 size int64
42 mtime time.Time
43 }
44
45 func (fi *fileInfo) Name() string { return fi.name }
46 func (fi *fileInfo) Mode() os.FileMode { return fi.mode }
47 func (fi *fileInfo) Size() int64 { return fi.size }
48 func (fi *fileInfo) ModTime() time.Time { return fi.mtime }
49 func (fi *fileInfo) IsDir() bool { return fi.mode.IsDir() }
50 func (fi *fileInfo) Sys() interface{} { return nil }
51
52 // httpZipFile is the zip-file based implementation of http.File
53 type httpZipFile struct {
54 path string // absolute path within zip FS without leading '/'
55 info os.FileInfo
56 io.ReadCloser // nil for directory
57 list zipList
58 }
59
60 func (f *httpZipFile) Close() error {
61 if !f.info.IsDir() {
62 return f.ReadCloser.Close()
63 }
64 f.list = nil
65 return nil
66 }
67
68 func (f *httpZipFile) Stat() (os.FileInfo, error) {
69 return f.info, nil
70 }
71
72 func (f *httpZipFile) Readdir(count int) ([]os.FileInfo, error) {
73 var list []os.FileInfo
74 dirname := f.path + "/"
75 prevname := ""
76 for i, e := range f.list {
77 if count == 0 {
78 f.list = f.list[i:]
79 break
80 }
81 if !strings.HasPrefix(e.Name, dirname) {
82 f.list = nil
83 break // not in the same directory anymore
84 }
85 name := e.Name[len(dirname):] // local name
86 var mode os.FileMode
87 var size int64
88 var mtime time.Time
89 if i := strings.IndexRune(name, '/'); i >= 0 {
90 // We infer directories from files in subdirectories.
91 // If we have x/y, return a directory entry for x.
92 name = name[0:i] // keep local directory name only
93 mode = os.ModeDir
94 // no size or mtime for directories
95 } else {
96 mode = 0
97 size = int64(e.UncompressedSize)
98 mtime = e.ModTime()
99 }
100 // If we have x/y and x/z, don't return two directory entries fo r x.
101 // TODO(gri): It should be possible to do this more efficiently
102 // by determining the (fs.list) range of local directory entries
103 // (via two binary searches).
104 if name != prevname {
105 list = append(list, &fileInfo{
106 name,
107 mode,
108 size,
109 mtime,
110 })
111 prevname = name
112 count--
113 }
114 }
115
116 if count >= 0 && len(list) == 0 {
117 return nil, io.EOF
118 }
119
120 return list, nil
121 }
122
123 func (f *httpZipFile) Seek(offset int64, whence int) (int64, error) {
124 return 0, fmt.Errorf("Seek not implemented for zip file entry: %s", f.in fo.Name())
125 }
126
127 // httpZipFS is the zip-file based implementation of http.FileSystem
128 type httpZipFS struct {
129 *zip.ReadCloser
130 list zipList
131 root string
132 }
133
134 func (fs *httpZipFS) Open(name string) (http.File, error) {
135 // fs.root does not start with '/'.
136 path := path.Join(fs.root, name) // path is clean
137 index, exact := fs.list.lookup(path)
138 if index < 0 || !strings.HasPrefix(path, fs.root) {
139 // file not found or not under root
140 return nil, fmt.Errorf("file not found: %s", name)
141 }
142
143 if exact {
144 // exact match found - must be a file
145 f := fs.list[index]
146 rc, err := f.Open()
147 if err != nil {
148 return nil, err
149 }
150 return &httpZipFile{
151 path,
152 &fileInfo{
153 name,
154 0,
155 int64(f.UncompressedSize),
156 f.ModTime(),
157 },
158 rc,
159 nil,
160 }, nil
161 }
162
163 // not an exact match - must be a directory
164 return &httpZipFile{
165 path,
166 &fileInfo{
167 name,
168 os.ModeDir,
169 0, // no size for directory
170 time.Time{}, // no mtime for directory
171 },
172 nil,
173 fs.list[index:],
174 }, nil
175 }
176
177 func (fs *httpZipFS) Close() error {
178 fs.list = nil
179 return fs.ReadCloser.Close()
180 }
181
182 // NewHttpZipFS creates a new http.FileSystem based on the contents of
183 // the zip file rc restricted to the directory tree specified by root;
184 // root must be an absolute path.
185 func NewHttpZipFS(rc *zip.ReadCloser, root string) http.FileSystem {
186 list := make(zipList, len(rc.File))
187 copy(list, rc.File) // sort a copy of rc.File
188 sort.Sort(list)
189 return &httpZipFS{rc, list, zipPath(root)}
190 }
OLDNEW
« no previous file with comments | « src/cmd/godoc/godoc.go ('k') | src/cmd/godoc/index.go » ('j') | no next file with comments »

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