kythe.io@v0.0.68-0.20240422202219-7225dbc01741/kythe/go/serving/filetree/filetree.go (about) 1 /* 2 * Copyright 2015 The Kythe Authors. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 // Package filetree implements a lookup table for files in a tree structure. 18 // 19 // Table format: 20 // 21 // dirs:<corpus>\n<root>\n<path> -> srvpb.FileDirectory 22 // dirs:corpusRoots -> srvpb.CorpusRoots 23 package filetree // import "kythe.io/kythe/go/serving/filetree" 24 25 import ( 26 "context" 27 "errors" 28 "fmt" 29 "path/filepath" 30 "strings" 31 32 "kythe.io/kythe/go/storage/table" 33 "kythe.io/kythe/go/util/kytheuri" 34 "kythe.io/kythe/go/util/log" 35 36 ftpb "kythe.io/kythe/proto/filetree_go_proto" 37 srvpb "kythe.io/kythe/proto/serving_go_proto" 38 ) 39 40 const ( 41 // DirTablePrefix is used as the prefix of the keys of a combined serving 42 // table. CorpusRootsPrefixedKey and PrefixedDirKey use this prefix to 43 // construct their keys. Table uses this prefix when PrefixedKeys is true. 44 DirTablePrefix = "dirs:" 45 46 dirKeySep = "\n" 47 ) 48 49 // CorpusRootsKey is the filetree lookup key for the tree's srvpb.CorpusRoots. 50 var CorpusRootsKey = []byte("corpusRoots") 51 52 // CorpusRootsPrefixedKey is the filetree lookup key for the tree's 53 // srvpb.CorpusRoots when using PrefixedKeys. 54 var CorpusRootsPrefixedKey = []byte(DirTablePrefix + "corpusRoots") 55 56 // Table implements the FileTree interface using a static lookup table. 57 type Table struct { 58 table.Proto 59 60 // PrefixedKeys indicates whether all keys are prefixed by DirTablePrefix 61 // (i.e. when using a combined serving table). 62 PrefixedKeys bool 63 } 64 65 // Directory implements part of the filetree Service interface. 66 func (t *Table) Directory(ctx context.Context, req *ftpb.DirectoryRequest) (*ftpb.DirectoryReply, error) { 67 var key []byte 68 if t.PrefixedKeys { 69 key = PrefixedDirKey(req.Corpus, req.Root, req.Path) 70 } else { 71 key = DirKey(req.Corpus, req.Root, req.Path) 72 } 73 var d srvpb.FileDirectory 74 if err := t.Lookup(ctx, key, &d); err == table.ErrNoSuchKey { 75 return &ftpb.DirectoryReply{}, nil 76 } else if err != nil { 77 return nil, fmt.Errorf("lookup error: %v", err) 78 } 79 entries := make([]*ftpb.DirectoryReply_Entry, 0, len(d.Entry)) 80 for _, e := range d.Entry { 81 if !req.GetIncludeFilesMissingText() && e.GetMissingText() { 82 continue 83 } 84 re := &ftpb.DirectoryReply_Entry{ 85 Name: e.Name, 86 BuildConfig: e.BuildConfig, 87 Generated: e.GetGenerated(), 88 MissingText: e.GetMissingText(), 89 } 90 switch e.Kind { 91 case srvpb.FileDirectory_FILE: 92 re.Kind = ftpb.DirectoryReply_FILE 93 case srvpb.FileDirectory_DIRECTORY: 94 re.Kind = ftpb.DirectoryReply_DIRECTORY 95 default: 96 log.WarningContextf(ctx, "unknown directory entry type: %T", e) 97 continue 98 } 99 entries = append(entries, re) 100 } 101 entries, err := parseLegacyEntries(entries, ftpb.DirectoryReply_FILE, d.FileTicket) 102 if err != nil { 103 return nil, err 104 } 105 entries, err = parseLegacyEntries(entries, ftpb.DirectoryReply_DIRECTORY, d.Subdirectory) 106 if err != nil { 107 return nil, err 108 } 109 return &ftpb.DirectoryReply{ 110 Corpus: req.Corpus, 111 Root: req.Root, 112 Path: req.Path, 113 Entry: entries, 114 }, nil 115 } 116 117 func parseLegacyEntries(entries []*ftpb.DirectoryReply_Entry, kind ftpb.DirectoryReply_Kind, tickets []string) ([]*ftpb.DirectoryReply_Entry, error) { 118 for _, ticket := range tickets { 119 uri, err := kytheuri.Parse(ticket) 120 if err != nil { 121 return nil, fmt.Errorf("invalid serving data: %v", err) 122 } 123 entries = append(entries, &ftpb.DirectoryReply_Entry{ 124 Kind: kind, 125 Name: filepath.Base(uri.Path), 126 Generated: uri.Root != "", 127 }) 128 } 129 return entries, nil 130 } 131 132 // CorpusRoots implements part of the filetree Service interface. 133 func (t *Table) CorpusRoots(ctx context.Context, req *ftpb.CorpusRootsRequest) (*ftpb.CorpusRootsReply, error) { 134 key := CorpusRootsKey 135 if t.PrefixedKeys { 136 key = CorpusRootsPrefixedKey 137 } 138 var cr srvpb.CorpusRoots 139 if err := t.Lookup(ctx, key, &cr); err == table.ErrNoSuchKey { 140 return nil, errors.New("internal error: missing corpusRoots in table") 141 } else if err != nil { 142 return nil, fmt.Errorf("corpusRoots lookup error: %v", err) 143 } 144 145 reply := &ftpb.CorpusRootsReply{ 146 Corpus: make([]*ftpb.CorpusRootsReply_Corpus, len(cr.Corpus)), 147 } 148 149 for i, corpus := range cr.Corpus { 150 reply.Corpus[i] = &ftpb.CorpusRootsReply_Corpus{ 151 Name: corpus.Corpus, 152 Root: corpus.Root, 153 BuildConfig: corpus.BuildConfig, 154 } 155 } 156 157 return reply, nil 158 } 159 160 // DirKey returns the filetree lookup table key for the given corpus path. 161 func DirKey(corpus, root, path string) []byte { 162 return []byte(strings.Join([]string{corpus, root, path}, dirKeySep)) 163 } 164 165 // PrefixedDirKey returns the filetree lookup table key for the given corpus 166 // path, prefixed by DirTablePrefix. 167 func PrefixedDirKey(corpus, root, path string) []byte { 168 return []byte(DirTablePrefix + strings.Join([]string{corpus, root, path}, dirKeySep)) 169 }