-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#244] Symlink scanner #262
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,26 +10,25 @@ | |
module Xrefcheck.Scan | ||
( ExclusionConfig | ||
, ExclusionConfig' (..) | ||
, Extension | ||
, ScanAction | ||
, FormatsSupport | ||
, FileSupport | ||
, ReadDirectoryMode(..) | ||
, ScanAction | ||
, ScanError (..) | ||
, ScanErrorDescription (..) | ||
, ScanResult (..) | ||
, ScanStage (..) | ||
|
||
, mkParseScanError | ||
, mkGatherScanError | ||
, scanRepo | ||
, specificFormatsSupport | ||
, defaultCompOption | ||
, defaultExecOption | ||
, ecIgnoreL | ||
, ecIgnoreLocalRefsToL | ||
, ecIgnoreRefsFromL | ||
, ecIgnoreExternalRefsToL | ||
, firstFileSupport | ||
, mkGatherScanError | ||
, mkParseScanError | ||
, reportScanErrs | ||
, scanRepo | ||
) where | ||
|
||
import Universum | ||
|
@@ -70,11 +69,14 @@ makeLensesWith postfixFields ''ExclusionConfig' | |
-- | File extension, dot included. | ||
type Extension = String | ||
|
||
-- | Whether the file is a symlink. | ||
type IsSymlink = Bool | ||
|
||
-- | Way to parse a file. | ||
type ScanAction = FilePath -> RelPosixLink -> IO (FileInfo, [ScanError 'Parse]) | ||
|
||
-- | All supported ways to parse a file. | ||
type FormatsSupport = Extension -> Maybe ScanAction | ||
type FileSupport = IsSymlink -> Extension -> Maybe ScanAction | ||
|
||
data ScanResult = ScanResult | ||
{ srScanErrors :: [ScanError 'Gather] | ||
|
@@ -153,14 +155,9 @@ instance Buildable ScanErrorDescription where | |
UnrecognisedErr txt -> [int||Unrecognised option "#{txt}" perhaps you meant \ | ||
<"ignore link"|"ignore paragraph"|"ignore all">|] | ||
|
||
specificFormatsSupport :: [([Extension], ScanAction)] -> FormatsSupport | ||
specificFormatsSupport formats = \ext -> M.lookup ext formatsMap | ||
where | ||
formatsMap = M.fromList | ||
[ (extension, parser) | ||
| (extensions, parser) <- formats | ||
, extension <- extensions | ||
] | ||
firstFileSupport :: [FileSupport] -> FileSupport | ||
firstFileSupport fs isSymlink = | ||
safeHead . catMaybes <$> traverse ($ isSymlink) fs | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps instead of taking the first There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That farsighted фтв actually makes sense. However I think let's leave it to change to people who will add other scanners. |
||
|
||
data ReadDirectoryMode | ||
= RdmTracked | ||
|
@@ -211,7 +208,7 @@ scanRepo | |
:: MonadIO m | ||
=> ScanPolicy | ||
-> Rewrite | ||
-> FormatsSupport | ||
-> FileSupport | ||
-> ExclusionConfig | ||
-> FilePath | ||
-> m ScanResult | ||
|
@@ -228,12 +225,13 @@ scanRepo scanMode rw formatsSupport config root = do | |
in liftIO $ (gatherScanErrs &&& gatherFileStatuses) | ||
<$> readDirectoryWith mode config processFile root | ||
|
||
notProcessedFiles <- case scanMode of | ||
notProcessedFiles <- case scanMode of | ||
OnlyTracked -> liftIO $ | ||
readDirectoryWith RdmUntracked config (const $ pure NotAddedToGit) root | ||
IncludeUntracked -> pure [] | ||
|
||
let scannableNotProcessedFiles = filter (isJust . mscanner . fst) notProcessedFiles | ||
scannableNotProcessedFiles <- liftIO $ | ||
filterM (fmap isJust . fileScanner . fst) notProcessedFiles | ||
|
||
whenJust (nonEmpty $ map fst scannableNotProcessedFiles) $ \files -> hPutStrLn @Text stderr | ||
[int|A| | ||
|
@@ -252,8 +250,10 @@ scanRepo scanMode rw formatsSupport config root = do | |
<> fmap (, UntrackedDirectory) untrackedDirs) | ||
} | ||
where | ||
mscanner :: RelPosixLink -> Maybe ScanAction | ||
mscanner = formatsSupport . takeExtension | ||
fileScanner :: RelPosixLink -> IO (Maybe ScanAction) | ||
fileScanner file = do | ||
isSymlink <- pathIsSymbolicLink (filePathFromRoot root file) | ||
pure $ formatsSupport isSymlink $ takeExtension file | ||
|
||
gatherScanErrs | ||
:: [(RelPosixLink, (FileStatus, [ScanError 'Parse]))] | ||
|
@@ -267,10 +267,9 @@ scanRepo scanMode rw formatsSupport config root = do | |
gatherFileStatuses = map (second fst) | ||
|
||
processFile :: RelPosixLink -> IO (FileStatus, [ScanError 'Parse]) | ||
processFile file = | ||
ifM (pathIsSymbolicLink (filePathFromRoot root file)) | ||
(pure (NotScannable, [])) | ||
case mscanner file of | ||
processFile file = do | ||
mScanner <- fileScanner file | ||
case mScanner of | ||
Nothing -> pure (NotScannable, []) | ||
Just scanner -> scanner root file <&> _1 %~ Scanned | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
{- SPDX-FileCopyrightText: 2023 Serokell <https://serokell.io> | ||
- | ||
- SPDX-License-Identifier: MPL-2.0 | ||
-} | ||
|
||
-- | Scanner for gathering references to verify from symlinks. | ||
-- | ||
Martoon-00 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
-- A symlink's reference corresponds to the file it points to. | ||
module Xrefcheck.Scanners.Symlink | ||
Martoon-00 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
( symlinkScanner | ||
, symlinkSupport | ||
) where | ||
|
||
import Universum | ||
|
||
import System.Directory (getSymbolicLinkTarget) | ||
|
||
import Xrefcheck.Core | ||
import Xrefcheck.Scan | ||
import Xrefcheck.System | ||
|
||
symlinkScanner :: ScanAction | ||
symlinkScanner root path = do | ||
rLink <- unRelPosixLink . mkRelPosixLink | ||
<$> getSymbolicLinkTarget (filePathFromRoot root path) | ||
|
||
let rName = "Symbolic Link" | ||
rPos = Position Nothing | ||
rInfo = referenceInfo rLink | ||
|
||
pure (FileInfo [Reference {rName, rPos, rInfo}] [], []) | ||
|
||
symlinkSupport :: FileSupport | ||
symlinkSupport isSymlink _ = do | ||
guard isSymlink | ||
pure symlinkScanner |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# SPDX-FileCopyrightText: 2023 Serokell <https://serokell.io> | ||
# | ||
# SPDX-License-Identifier: Unlicense | ||
|
||
exclusions: | ||
ignore: | ||
- broken.md | ||
- outside.md | ||
|
||
scanners: | ||
markdown: | ||
flavor: GitHub |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,4 @@ | |
|
||
[Empty file](a) | ||
|
||
[Symlink ref](../s.md) | ||
|
||
[Symlink ref with anchor](../s.md#a) | ||
[Some symlink](../ok.md) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of determining which scanner to use just from the file extension, I changed it to a more general check. Another option is to put the symlink scanner in a 'different level' that is above extension check: if it is a symlink, then symlink scanner, else get scanner from extension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about the type
Bool -> Extension -> Maybe ScanAction
, where the first bool denotesisLink
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like it. It is less general and can be better understood 👍