Skip to content

Commit 25e1cb3

Browse files
authored
Merge pull request #46 from expipiplus1/attrs
Implement attribute filtering
2 parents 67df858 + aa41087 commit 25e1cb3

File tree

10 files changed

+121
-30
lines changed

10 files changed

+121
-30
lines changed

.github/workflows/ci.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ jobs:
1616
matrix:
1717
os: [ubuntu-latest]
1818
cabal: [latest]
19-
ghc: [8.6.5, 8.8.4, 8.10.2]
19+
ghc: [8.8.4, 8.10.2]
2020
fail-fast: false
2121

2222
steps:

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## WIP
44

5+
## [0.2.3] - 2020-11-06
6+
7+
- Implement filtering updates based on binding name
8+
- Better error message output on parse failure
9+
- Drop support for GHC 8.6
10+
511
## [0.2.2] - 2020-11-03
612

713
- Require hnix version 0.11 with several important bugfixes

app/Main.hs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
{-# OPTIONS_GHC -Wno-orphans #-}
12

2-
module Main where
3+
module Main
4+
( main
5+
) where
36

47
import Data.Foldable
58
import qualified Data.Text.IO as T
@@ -14,6 +17,7 @@ import Text.ParserCombinators.ReadP ( char
1417
, readS_to_P
1518
, sepBy
1619
)
20+
import Text.Regex.TDFA
1721
import Update.Nix.FetchGit
1822
import Update.Nix.FetchGit.Types
1923

@@ -43,7 +47,8 @@ env Options {..} =
4347
Normal -> sayErr
4448
Quiet -> sayErr
4549
updateLocations = [ (l, c) | Position l c <- location ]
46-
in Env { .. }
50+
attrPatterns = attribute
51+
in Env { .. }
4752

4853
----------------------------------------------------------------
4954
-- Options
@@ -52,7 +57,9 @@ env Options {..} =
5257
data Options w = Options
5358
{ verbose :: w ::: Bool <!> "False"
5459
, quiet :: w ::: Bool <!> "False"
55-
, location :: w ::: [Position] <?> "Source location to limit updates to"
60+
, location :: w ::: [Position] <?> "Source location to limit updates to, Combined using inclusive or"
61+
, attribute
62+
:: w ::: [Regex] <?> "Pattern (POSIX regex) to limit updates to expressions under matching names in attrsets and let bindings. Combined using inclusing or, if this isn't specified then no expressions will be filtered by attribute name"
5663
}
5764
deriving stock Generic
5865

@@ -70,7 +77,9 @@ optParser =
7077
versionOption
7178
<*> ( (,)
7279
<$> (unwrap <$> parseRecordWithModifiers defaultModifiers
73-
{ shortNameModifier = firstLetter
80+
{ shortNameModifier = \case
81+
"attribute" -> Just 'A'
82+
n -> firstLetter n
7483
}
7584
)
7685
<*> many
@@ -88,7 +97,6 @@ optParser =
8897
(long "version" <> help ("print " <> versionString))
8998

9099
instance ParseRecord (Options Wrapped)
91-
deriving instance Show (Options Unwrapped)
92100

93101
data Position = Position Int Int
94102
deriving Show
@@ -101,3 +109,15 @@ instance Read Position where
101109

102110
instance ParseField Position where
103111
metavar _ = "LINE:COL"
112+
113+
instance Read Regex where
114+
readsPrec _ s = case makeRegexM s of
115+
Nothing -> []
116+
Just r -> [(r, "")]
117+
118+
instance ParseField Regex where
119+
metavar _ = "REGEX"
120+
readField = eitherReader makeRegexM
121+
122+
instance (e ~ String) => MonadFail (Either e) where
123+
fail = Left

package.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
name: update-nix-fetchgit
2-
version: "0.2.2"
2+
version: "0.2.3"
33
synopsis: A program to update fetchgit values in Nix expressions
44
description: |
55
This command-line utility is meant to be used by people maintaining Nix
@@ -29,9 +29,10 @@ executables:
2929
source-dirs: app
3030
ghc-options: -threaded -rtsopts -with-rtsopts=-N
3131
dependencies:
32-
- base
32+
- base >= 4.13
3333
- optparse-applicative
3434
- optparse-generic >= 1.4.2
35+
- regex-tdfa
3536
- say
3637
- text >= 1.2
3738
- update-nix-fetchgit
@@ -49,6 +50,7 @@ library:
4950
- monad-validate
5051
- mtl
5152
- process >= 1.2
53+
- regex-tdfa
5254
- syb
5355
- template-haskell
5456
- text >= 1.2

src/Update/Nix/FetchGit.hs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ module Update.Nix.FetchGit
77
) where
88

99
import Control.Monad ( when )
10+
import Control.Monad.Reader ( MonadReader(ask) )
11+
import Control.Monad.Validate ( MonadValidate(tolerate) )
1012
import Data.Fix
1113
import Data.Foldable
14+
import Data.Functor
1215
import Data.Maybe
1316
import Data.Text ( Text
1417
, pack
@@ -21,13 +24,11 @@ import Nix.Comments
2124
import Nix.Expr
2225
import Nix.Match.Typed
2326
import System.Exit
27+
import Text.Regex.TDFA
2428
import Update.Nix.FetchGit.Types
2529
import Update.Nix.FetchGit.Utils
2630
import Update.Nix.Updater
2731
import Update.Span
28-
import Control.Monad.Validate ( MonadValidate(tolerate) )
29-
import Data.Functor
30-
import Control.Monad.Reader ( MonadReader(ask) )
3132

3233
--------------------------------------------------------------------------------
3334
-- Tying it all together
@@ -57,7 +58,7 @@ updatesFromText t = do
5758
tree <- do
5859
expr <- fromEither $ ourParseNixText t
5960
findUpdates (getComment nixLines) expr
60-
us <- evalUpdates tree
61+
us <- evalUpdates =<< filterUpdates tree
6162
case us of
6263
[] -> logVerbose "Made no updates"
6364
[_] -> logVerbose "Made 1 update"
@@ -71,19 +72,53 @@ updatesFromText t = do
7172
findUpdates :: (NExprLoc -> Maybe Comment) -> NExprLoc -> M FetchTree
7273
findUpdates getComment e = do
7374
Env {..} <- ask
75+
-- First of all, if this expression doesn't enclose the requested position,
76+
-- return an empty tree
77+
-- Then check against all the updaters, if they match we have a leaf
7478
if not (null updateLocations || any (containsPosition e) updateLocations)
7579
then pure $ Node Nothing []
7680
else
77-
let updaters = ($ e) <$> fetchers getComment
81+
let
82+
updaters = ($ e) <$> fetchers getComment
83+
bindingTrees = \case
84+
NamedVar p e' _ | Just t <- pathText p ->
85+
(: []) . (Just t, ) <$> findUpdates getComment e'
86+
b ->
87+
traverse (fmap (Nothing, ) . findUpdates getComment) . toList $ b
7888
in
7989
case asum updaters of
8090
Just u -> UpdaterNode <$> u
8191
Nothing -> case e of
82-
[matchNixLoc|{ _version = ^version; }|] ->
83-
Node version
84-
<$> traverse (findUpdates getComment) (toList (unFix e))
85-
_ -> Node Nothing
86-
<$> traverse (findUpdates getComment) (toList (unFix e))
92+
[matchNixLoc|{ _version = ^version; }|] | NSet_ _ _ bs <- unFix e ->
93+
Node version . concat <$> traverse bindingTrees bs
94+
[matchNixLoc|let _version = ^version; in ^x|]
95+
| NLet_ _ bs _ <- unFix e -> do
96+
bs' <- concat <$> traverse bindingTrees bs
97+
x' <- findUpdates getComment x
98+
pure $ Node version ((Nothing, x') : bs')
99+
_ -> Node Nothing <$> traverse
100+
(fmap (Nothing, ) . findUpdates getComment)
101+
(toList (unFix e))
102+
103+
filterUpdates :: FetchTree -> M FetchTree
104+
filterUpdates t = do
105+
Env {..} <- ask
106+
let matches s = any (`match` s) attrPatterns
107+
-- If we're in a branch, include any bindings which match unconditionally,
108+
-- otherwise recurse
109+
-- If we reach a leaf, return empty because it hasn't been included by a
110+
-- binding yet
111+
let go = \case
112+
Node v cs -> Node
113+
v
114+
[ (n, c')
115+
| (n, c) <- cs
116+
, let c' = if maybe False matches n then c else go c
117+
]
118+
UpdaterNode _ -> Node Nothing []
119+
-- If there are no patterns, don't do any filtering
120+
pure $ if null attrPatterns then t else go t
121+
87122

88123
evalUpdates :: FetchTree -> M [SpanUpdate]
89124
evalUpdates = fmap snd . go
@@ -92,7 +127,7 @@ evalUpdates = fmap snd . go
92127
go = \case
93128
UpdaterNode (Updater u) -> u
94129
Node versionExpr cs -> do
95-
(ds, ss) <- unzip . catMaybes <$> traverse (tolerate . go) cs
130+
(ds, ss) <- unzip . catMaybes <$> traverse (tolerate . go . snd) cs
96131
-- Update version string with the maximum of versions in the children
97132
let latestDate = maximumMay (catMaybes ds)
98133
pure
@@ -101,7 +136,7 @@ evalUpdates = fmap snd . go
101136
| Just d <- pure latestDate
102137
, Just v <- pure versionExpr
103138
]
104-
<> concat ss
139+
<> concat ss
105140
)
106141

107142
----------------------------------------------------------------

src/Update/Nix/FetchGit/Types.hs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Data.Monoid
1111
import Data.Text ( Text )
1212
import Data.Time ( Day )
1313
import Nix.Expr ( NExprLoc )
14+
import Text.Regex.TDFA ( Regex )
1415
import Update.Nix.FetchGit.Warning
1516
import Update.Span
1617

@@ -28,8 +29,9 @@ asWarnings m = unValidateT MNothing m <&> \case
2829
Right (MNothing, a) -> (mempty, Just a)
2930

3031
data Env = Env
31-
{ sayLog :: Verbosity -> Text -> IO ()
32+
{ sayLog :: Verbosity -> Text -> IO ()
3233
, updateLocations :: [(Int, Int)]
34+
, attrPatterns :: [Regex]
3335
}
3436

3537
data Verbosity
@@ -45,7 +47,7 @@ newtype Updater = Updater
4547
-- parsing, but which only contains the information we care about.
4648
data FetchTree
4749
= Node { nodeVersionExpr :: Maybe NExprLoc
48-
, nodeChildren :: [FetchTree]
50+
, nodeChildren :: [(Maybe Text, FetchTree)]
4951
}
5052
| UpdaterNode Updater
5153

src/Update/Nix/FetchGit/Utils.hs

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module Update.Nix.FetchGit.Utils
77
, prettyRepoLocation
88
, quoteString
99
, extractFuncName
10+
, pathText
1011
, exprText
1112
, exprBool
1213
, exprSpan
@@ -101,6 +102,30 @@ extractFuncName (AnnE _ (NSym name)) = Just name
101102
extractFuncName (AnnE _ (NSelect _ (NE.last -> StaticKey name) _)) = Just name
102103
extractFuncName _ = Nothing
103104

105+
pathText :: NAttrPath r -> Maybe Text
106+
pathText = fmap (T.concat . toList) . traverse e
107+
where
108+
e :: NKeyName r -> Maybe Text
109+
e = \case
110+
StaticKey s -> Just s
111+
DynamicKey (Plain s) -> t s
112+
DynamicKey EscapedNewline -> Just "\n"
113+
DynamicKey (Antiquoted _) -> Nothing
114+
t :: NString r -> Maybe Text
115+
t =
116+
fmap T.concat
117+
. traverse a
118+
. (\case
119+
DoubleQuoted as -> as
120+
Indented _ as -> as
121+
)
122+
a :: Antiquoted Text r -> Maybe Text
123+
a = \case
124+
Plain s -> pure s
125+
EscapedNewline -> pure "\n"
126+
Antiquoted _ -> Nothing
127+
128+
104129
-- Takes an ISO 8601 date and returns just the day portion.
105130
parseISO8601DateToDay :: Text -> Either Warning Day
106131
parseISO8601DateToDay t =
@@ -110,7 +135,7 @@ parseISO8601DateToDay t =
110135
(parseTimeM False defaultTimeLocale "%Y-%m-%d" justDate)
111136

112137
formatWarning :: Warning -> Text
113-
formatWarning (CouldNotParseInput doc) = tShow doc
138+
formatWarning (CouldNotParseInput doc) = doc
114139
formatWarning (MissingAttr attrName) =
115140
"Error: The \"" <> attrName <> "\" attribute is missing."
116141
formatWarning (DuplicateAttrs attrName) =

src/Update/Nix/FetchGit/Warning.hs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ module Update.Nix.FetchGit.Warning
44

55
import Data.Text
66
import Nix.Expr
7-
import Data.Void
87

98
data Warning = CouldNotParseInput Text
109
| MissingAttr Text

tests/Samples.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ module Samples where
55
import Test.Tasty (TestTree, testGroup)
66
import Test.Tasty.Golden (goldenVsFile)
77
import System.FilePath ((</>))
8-
import Data.Bool (bool)
98
import Data.Maybe (mapMaybe)
109

1110
import qualified Data.List
@@ -30,6 +29,7 @@ import Data.Text.IO (hPutStrLn)
3029
-- * perform update
3130
-- * adjust @url@ to point to the expected one
3231
-- * copy file back to @tests/test_rec_sets.out.nix@ so it be compared to @expected.nix@
32+
runTest :: String -> IO ()
3333
runTest f =
3434
System.IO.Temp.withSystemTempDirectory "test-update-nix-fetchgit" $ \dir ->
3535
System.IO.Temp.withSystemTempDirectory "test-update-nix-fetchgit-store" $ \storeDir -> do
@@ -60,15 +60,15 @@ runTest f =
6060
(System.Process.shell ("nix-store --init"))
6161
mempty
6262

63-
let env = Env (const (Data.Text.IO.hPutStrLn System.IO.stderr)) []
63+
let env = Env (const (Data.Text.IO.hPutStrLn System.IO.stderr)) [] []
6464
Update.Nix.FetchGit.processFile env (dir </> inBase)
6565

6666
replaceFile (dir </> inBase) (Data.Text.pack dir) "/tmp/nix-update-fetchgit-test"
6767

6868
System.Directory.copyFile (dir </> inBase) f
6969
where
70-
replaceFile f what with =
71-
Data.Text.IO.readFile f >>= Data.Text.IO.writeFile f . Data.Text.replace what with
70+
replaceFile f' what with =
71+
Data.Text.IO.readFile f' >>= Data.Text.IO.writeFile f' . Data.Text.replace what with
7272

7373
test_derivation :: IO TestTree
7474
test_derivation = do

update-nix-fetchgit.cabal

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ cabal-version: 1.12
55
-- see: https://github.com/sol/hpack
66

77
name: update-nix-fetchgit
8-
version: 0.2.2
8+
version: 0.2.3
99
synopsis: A program to update fetchgit values in Nix expressions
1010
description: This command-line utility is meant to be used by people maintaining Nix
1111
expressions that fetch files from Git repositories. It automates the process
@@ -87,6 +87,7 @@ library
8787
, monad-validate
8888
, mtl
8989
, process >=1.2
90+
, regex-tdfa
9091
, syb
9192
, template-haskell
9293
, text >=1.2
@@ -104,9 +105,10 @@ executable update-nix-fetchgit
104105
default-extensions: DataKinds DefaultSignatures DeriveAnyClass DeriveDataTypeable DeriveGeneric DerivingStrategies FlexibleContexts FlexibleInstances GADTs LambdaCase MultiParamTypeClasses OverloadedStrings PolyKinds RankNTypes RecordWildCards ScopedTypeVariables StandaloneDeriving TemplateHaskellQuotes TupleSections TypeApplications TypeFamilies TypeOperators ViewPatterns
105106
ghc-options: -Wall -threaded -rtsopts -with-rtsopts=-N
106107
build-depends:
107-
base
108+
base >=4.13
108109
, optparse-applicative
109110
, optparse-generic >=1.4.2
111+
, regex-tdfa
110112
, say
111113
, text >=1.2
112114
, update-nix-fetchgit

0 commit comments

Comments
 (0)