Skip to content

Commit af7e3d2

Browse files
committed
[glass] Optionally return full file content
Clients may want to update symbol positions to account for local changes to the source file, and for this they need the original file content as it was indexed. Currently the way to do that is to use the `revision` returned by Glass and retrieve the file from source control, but that might not be possible in general: * the indexed file might not be checked in (consider interactively indexing code in the background when using an IDE), or * the files might not be in source control at all (consider indexing packages you downloaded from a package manager). This provides a way for the Glass client to ask Glass for the original file content that was indexed. The content might not be available - it relies on the indexer having produced the appropriate `src.FileContent` facts, and only the Haskell indexer does this right now, but it could become more widely supported in the future. We could also have Glass try to get the content from the SCM; I haven't implemented that.
1 parent ac55002 commit af7e3d2

8 files changed

Lines changed: 53 additions & 9 deletions

File tree

glean/glass/Glean/Glass/Handler/Documents.hs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ import ServiceData.GlobalStats as Stats
8989
import ServiceData.Types as Stats
9090
import Util.Time (elapsedTime, toDiffMillis)
9191
import Glean.Glass.Attributes.PerfUtils (parseGitDiff, applyLineMappingToDefs, applyLineMappingToRefs)
92+
import qualified Glean.Glass.Query as Query
9293

9394
-- | Runner for methods that are keyed by a file path.
9495
-- Select the right Glean DBs and pass them to the function (via a GleanBackend)
@@ -199,7 +200,7 @@ translateMirroredRepoListXResult
199200
-> DocumentSymbolListXResult
200201
-> DocumentSymbolListXResult
201202
translateMirroredRepoListXResult
202-
(DocumentSymbolsRequest repository path _ _ _) res =
203+
(DocumentSymbolsRequest repository path _ _ _ _) res =
203204
case repoPathToMirror repository path of
204205
Just (Mirror mirror prefix origin) ->
205206
Utils.translateDocumentSymbolListXResult origin mirror prefix Nothing res
@@ -226,6 +227,7 @@ fetchSymbolsAndAttributesGlean
226227
(requestOptions_revision opts)
227228
(requestOptions_exact_revision opts)
228229
withContentHash
230+
fetchContent
229231
ExtraSymbolOpts{..} be mlang dbInfo (requestOptions_attribute_opts opts)
230232

231233
res1 <- if oAmendLinesOnRevisionMismatch
@@ -255,6 +257,7 @@ fetchSymbolsAndAttributesGlean
255257
oIncludeRefs = documentSymbolsRequest_include_refs req
256258
oLineRange = documentSymbolsRequest_range req
257259
withContentHash = shouldFetchContentHash opts
260+
fetchContent = documentSymbolsRequest_include_content req
258261
oIncludeXlangRefs = documentSymbolsRequest_include_xlang_refs req
259262
oAmendLinesOnRevisionMismatch = maybe False
260263
featureFlags_amend_lines_on_revision_mismatch (requestOptions_feature_flags opts)
@@ -465,6 +468,7 @@ fromDocumentSymbolResult DocumentSymbolListXResult{..} = DocumentSymbols
465468
, srcFile = Nothing
466469
, offsets = Nothing
467470
, attributes = documentSymbolListXResult_attributes
471+
, content = documentSymbolListXResult_content
468472
}
469473
where
470474
createDummyRefEntity :: ReferenceRangeSymbolX ->
@@ -591,15 +595,16 @@ fetchDocumentSymbols
591595
-> Maybe Revision
592596
-> Bool -- ^ exact revision only?
593597
-> Bool -- ^ fetch file content hash?
598+
-> Bool -- ^ fetch file content
594599
-> ExtraSymbolOpts
595600
-> GleanBackend b
596601
-> Maybe Language
597602
-> GleanDBInfo
598603
-> AttributeOptions
599604
-> IO (DocumentSymbols, QueryEachRepoLog, Maybe ErrorLogger)
600605
fetchDocumentSymbols env@Glass.Env{..} (FileReference scsrepo path)
601-
repoPath mlimit wantedRevision exactRevision fetchContentHash extraOpts
602-
b mlang dbInfo attrOpts = do
606+
repoPath mlimit wantedRevision exactRevision fetchContentHash fetchContent
607+
extraOpts b mlang dbInfo attrOpts = do
603608
backendRunHaxl b env $ do
604609
--
605610
-- we pick the first db in the list that has the full FileInfo{..}
@@ -644,6 +649,12 @@ fetchDocumentSymbols env@Glass.Env{..} (FileReference scsrepo path)
644649
(kinds, _, merr) <- withRepo fileRepo $
645650
documentSymbolKinds mlimit mlang fileId attrOpts
646651

652+
content <-
653+
if fetchContent then
654+
withRepo fileRepo $ Utils.fetchData $ Query.fileContent fileId
655+
else
656+
return Nothing
657+
647658
let revision = getDBRevision (scmRevisions dbInfo) fileRepo scsrepo
648659
contentMatch <- case wantedRevision of
649660
Nothing -> return Nothing
@@ -796,12 +807,13 @@ data DocumentSymbols = DocumentSymbols
796807
, srcFile :: Maybe Src.File
797808
, offsets :: Maybe Range.LineOffsets
798809
, attributes :: Maybe AttributeList
810+
, content :: Maybe Text
799811
}
800812

801813
emptyDocumentSymbols :: Revision -> DocumentSymbols
802814
emptyDocumentSymbols revision =
803815
DocumentSymbols [] [] revision Nothing False Nothing mempty mempty Nothing
804-
Nothing Nothing
816+
Nothing Nothing Nothing
805817

806818
-- | Drop any remnant entities after we are done with them
807819
toDocumentSymbolResult :: DocumentSymbols -> DocumentSymbolListXResult
@@ -815,6 +827,7 @@ toDocumentSymbolResult DocumentSymbols{..} = DocumentSymbolListXResult{..}
815827
documentSymbolListXResult_referenced_file_digests = xref_digests
816828
documentSymbolListXResult_content_match = contentMatch
817829
documentSymbolListXResult_attributes = attributes
830+
documentSymbolListXResult_content = content
818831

819832

820833

@@ -854,7 +867,8 @@ fetchDocumentSymbolIndex env latest req opts be
854867
documentSymbolListXResult_referenced_file_digests,
855868
documentSymbolIndex_content_match =
856869
documentSymbolListXResult_content_match,
857-
documentSymbolIndex_attributes = documentSymbolListXResult_attributes
870+
documentSymbolIndex_attributes = documentSymbolListXResult_attributes,
871+
documentSymbolIndex_content = documentSymbolListXResult_content
858872
}
859873
return ((idxResult, status, gleanDataLog, attrLog), merr1)
860874

glean/glass/Glean/Glass/Query.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module Glean.Glass.Query
1414
srcFile
1515
, fileInfo
1616
, fileDigests
17+
, fileContent
1718

1819
-- * Working with XRefs
1920
, fileEntityLocations
@@ -75,6 +76,13 @@ fileInfo (GleanPath path) = predicate @Glass.FileInfo $
7576
field @"file" (string path)
7677
end
7778

79+
fileContent :: Glean.IdOf Src.File -> Angle Text
80+
fileContent fileId =
81+
var $ \content ->
82+
content `where_` [
83+
stmt $ predicate @Src.FileContent $ factId fileId .-> content
84+
]
85+
7886
-- | Given a file id, look up the index of line endings
7987
--
8088
-- Line ending tables are needed to do line:col conversions, but we want to

glean/glass/if/glass.thrift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,12 @@ struct DocumentSymbolsRequest {
191191
// resolved using latest version of target db. This may add latency
192192
// to the query. includes_refs must be set to true.
193193
5: bool include_xlang_refs = false;
194+
195+
// Include indexed file content in the response, if available. This
196+
// may be useful if there is no SCM available to retrieve the
197+
// content from, or the file was not indexed from a specific SCM
198+
// revision.
199+
6: bool include_content = false;
194200
}
195201

196202
// response types
@@ -327,6 +333,9 @@ struct DocumentSymbolListXResult {
327333
// additional metadata associated with the file, non-symbol specific
328334
// e.g. list of available attributes / denominators for the file
329335
8: optional AttributeList attributes;
336+
337+
// optional file contents, if include_content = true in the request
338+
9: optional string content;
330339
}
331340

332341
// For cursor navigation in a file, it is useful to have a line indexed
@@ -359,6 +368,9 @@ struct DocumentSymbolIndex {
359368
// additional metadata associated with the file, non-symbol specific
360369
// e.g. list of available attributes / denominators for the file
361370
8: optional AttributeList attributes;
371+
372+
// optional file contents, if include_content = true in the request
373+
9: optional string content;
362374
}
363375

364376
// Generic server exception

glean/glass/test/regression/Glean/Glass/Regression/Haskell.hs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,17 @@
88

99
module Glean.Glass.Regression.Haskell (main) where
1010

11+
import System.Environment
1112
import Glean.Indexer.Haskell as Haskell ( indexer )
1213
import Glean.Glass.Regression.Snapshot ( mainGlassSnapshot )
1314

1415
main :: IO ()
15-
main = mainGlassSnapshot testName testPath testIndexer (const [])
16+
main = do
17+
args <- getArgs
18+
withArgs ("--arg=--store-src" : args) $
19+
-- tells the indexer to produce src.FileContent facts, which support
20+
-- include_content=true in documentSymbolIndex calls.
21+
mainGlassSnapshot testName testPath testIndexer (const [])
1622
where
1723
testName = "glass-regression-haskell"
1824
testPath = "glean/glass/test/regression/tests/haskell"

glean/glass/test/regression/lib/Glean/Glass/Regression/Snapshot.hs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -317,23 +317,25 @@ instance DeterministicResponse (Either [Text] Cxx.SymbolEnv) where
317317

318318
instance DeterministicResponse DocumentSymbolListXResult where
319319
det (DocumentSymbolListXResult refs defs _rev truncated digest fileMap
320-
contentMatch attributes) =
320+
contentMatch attributes content) =
321321
DocumentSymbolListXResult (det refs) (det defs) (Revision "testhash")
322322
truncated
323323
digest
324324
fileMap
325325
-- n.b. don't want to include any test group revision tags
326326
contentMatch
327327
attributes
328+
content
328329

329330
instance DeterministicResponse DocumentSymbolIndex where
330331
det (DocumentSymbolIndex syms _rev size truncated digest fileMap
331-
contentMatch attributes) =
332+
contentMatch attributes content) =
332333
DocumentSymbolIndex (Map.map sort syms) (Revision "testhash") size truncated
333334
digest
334335
fileMap
335336
contentMatch
336337
attributes
338+
content
337339

338340
instance DeterministicResponse SymbolSearchResult where
339341
det (SymbolSearchResult syms deets) =

glean/glass/test/regression/lib/Glean/Glass/Regression/Tests.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ testDocumentSymbolListX path get =
5050
, documentSymbolsRequest_range = Nothing
5151
, documentSymbolsRequest_include_refs = True
5252
, documentSymbolsRequest_include_xlang_refs = False
53+
, documentSymbolsRequest_include_content = False
5354
}
5455
res <- documentSymbolListX env req def
5556
assertBool "documentSymbolListX"

glean/glass/test/regression/tests/haskell/documentSymbolIndex.out

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
[
22
"@generated",
33
{
4+
"content": "{-\n Copyright (c) Meta Platforms, Inc. and affiliates.\n All rights reserved.\n\n This source code is licensed under the BSD-style license found in the\n LICENSE file in the root directory of this source tree.\n-}\n\n\nmodule A\n ( a\n , A\n , T(..)\n , R(..)\n , C(..)\n , zero\n , f\n ) where\n\nimport Data.Char (toLower, ord)\n\na :: String\na = map toLower \"A\"\n\ntype A = Int\n\ndata T a = C1 Float | C2 A | C3 a\n\ndata R a = R { f1 :: Char, f2 :: [a] }\n\nclass Eq a => C a where\n m :: a -> Bool\n\ninstance C Int where\n m x = x == x\n\nzero :: A\nzero = 0\n\nf :: R a -> T a\nf R{f2 = [x]} = C3 x\nf r | m (3::Int) = C2 (ord (f1 r { f1 = 'a' }))\n",
45
"referenced_file_digests": {},
56
"revision": "testhash",
67
"size": 59,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
action: documentSymbolIndex
2-
args: {"include_refs":true,"filepath":"glean/lang/codemarkup/tests/haskell/code/A.hs","repository":"test"}
2+
args: {"include_refs":true,"filepath":"glean/lang/codemarkup/tests/haskell/code/A.hs","repository":"test","include_content":true}
33

0 commit comments

Comments
 (0)