language-puppet 1.3.17 → 1.3.18
raw patch · 12 files changed
+174/−6 lines, 12 filesdep ~pcre-utils
Dependency ranges changed: pcre-utils
Files
- CHANGELOG +6/−0
- language-puppet.cabal +4/−1
- src/Puppet/Interpreter/Resolve.hs +4/−0
- src/Puppet/Language/Value.hs +8/−1
- src/Puppet/Parser.hs +43/−2
- src/Puppet/Parser/PrettyPrinter.hs +1/−0
- src/Puppet/Parser/Types.hs +1/−0
- src/Puppet/Runner/Stdlib.hs +21/−2
- tests/DT/Parser.hs +4/−0
- tests/Function/PrefixSpec.hs +39/−0
- tests/Function/SuffixSpec.hs +39/−0
- tests/Spec.hs +4/−0
CHANGELOG view
@@ -1,3 +1,9 @@+language-puppet (1.3.18) UNRELEASED; urgency=medium++ * Added prefix and suffix functions (Fix #246)++ -- Simon Marechal <bartavelle@gmail.com> Fri, 18 May 2018 11:42:19 +0200+ language-puppet (1.3.17) artful; urgency=medium * Loose upperbound for servant to include 0.13 * Loose upperbound for exceptions to include 0.10.0
language-puppet.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: language-puppet-version: 1.3.17+version: 1.3.18 synopsis: Tools to parse and evaluate the Puppet DSL. description: This is a set of tools that is supposed to fill all your Puppet needs : syntax checks, catalog compilation, PuppetDB queries, simulationg of complex interactions between nodes, Puppet master replacement, and more ! homepage: http://lpuppet.banquise.net/@@ -160,6 +160,7 @@ , transformers , unordered-containers , vector+ , pcre-utils other-modules: DT.Parser ErbSpec EvalSpec@@ -174,6 +175,8 @@ Function.AssertPrivateSpec Function.JoinKeysToValuesSpec Function.LookupSpec+ Function.SuffixSpec+ Function.PrefixSpec Helpers InterpreterSpec Interpreter.CollectorSpec
src/Puppet/Interpreter/Resolve.hs view
@@ -668,6 +668,7 @@ UDTEnum ens -> DTEnum . NE.fromList . sconcat <$> traverse resolveExpressionStrings ens UDTAny -> pure DTAny UDTCollection -> pure DTCollection+ UDTRegexp mr -> pure (DTRegexp mr) -- | Generates variable associations for evaluation of blocks. -- Each item corresponds to an iteration in the calling block.@@ -790,6 +791,9 @@ DTAny -> True DTCollection -> datatypeMatch (DTVariant (DTArray DTData 0 Nothing :| [DTHash DTScalar DTData 0 Nothing])) v DTPattern patterns -> maybe False (\str -> any (checkPattern (Text.encodeUtf8 str)) patterns) (v ^? _PString)+ DTRegexp mr -> case v ^? _PRegexp of+ Nothing -> False+ Just cr -> maybe True (== cr) mr where checkPattern str (CompRegex _ ptrn) = case Regex.execute' ptrn str of
src/Puppet/Language/Value.hs view
@@ -8,6 +8,7 @@ import Data.Aeson import Data.Aeson.Lens import Data.Aeson.TH+import qualified Data.HashMap.Strict as HM import Foreign.Ruby.Helpers import Puppet.Language.Core@@ -30,6 +31,7 @@ | DTEnum (NonEmpty Text) | DTAny | DTCollection+ | DTRegexp (Maybe CompRegex) deriving (Show, Eq) instance Pretty DataType where@@ -51,6 +53,7 @@ DTEnum tx -> "Enum" <> list (foldMap (pure . ppline) tx) DTAny -> "Any" DTCollection -> "Collection"+ DTRegexp mr -> "Regex" <> foldMap (brackets . pretty) mr where bounded :: (Pretty a, Pretty b) => Doc -> Maybe a -> Maybe b -> Doc bounded s ma mb = s <> case (ma, mb) of@@ -69,7 +72,8 @@ | PArray !(Vector PValue) | PHash !(Container PValue) | PNumber !Scientific- | PType DataType+ | PType !DataType+ | PRegexp !CompRegex deriving (Eq, Show) makePrisms ''PValue@@ -84,6 +88,7 @@ pretty (PArray v) = list (map pretty (toList v)) pretty (PHash g) = containerComma g pretty (PType dt) = pretty dt+ pretty (PRegexp cr) = pretty cr instance IsString PValue where fromString = PString . toS@@ -109,6 +114,7 @@ parseJSON (String s) = return (PString s) parseJSON (Bool b) = return (PBoolean b) parseJSON (Array v) = fmap PArray (mapM parseJSON v)+ parseJSON (Object o) | HM.size o == 1 && HM.keys o == ["regexp"] = o .: "regexp" parseJSON (Object o) = fmap PHash (mapM parseJSON o) instance ToJSON PValue where@@ -120,6 +126,7 @@ toJSON (PArray r) = Array (fmap toJSON r) toJSON (PHash x) = Object (fmap toJSON x) toJSON (PNumber n) = Number n+ toJSON (PRegexp r) = object [("regexp", toJSON r)] instance ToRuby PValue where toRuby = toRuby . toJSON
src/Puppet/Parser.hs view
@@ -670,6 +670,7 @@ <|> (reserved "Optional" *> (UDTOptional <$> brackets datatype)) <|> (UNotUndef <$ reserved "NotUndef") <|> (reserved "Variant" *> (UDTVariant . NE.fromList <$> brackets (datatype `sepBy1` symbolic ',')))+ <|> (reserved "Regexp" *> (UDTRegexp <$> optional (brackets termRegexp))) -- while all the other cases are straightforward, it seems that the -- following syntax is a valid regexp for puppet: -- '^dqsqsdqs$'@@ -725,9 +726,49 @@ Just (tk, tv, Just [mi, mx]) -> return (UDTHash tk tv mi (Just mx)) Just (_, _, Just _) -> fail "Too many arguments to datatype Hash" dtExternal =- reserved "Stdlib::HTTPUrl" $> UDTData- <|> reserved "Stdlib::Absolutepath" $> UDTData+ reserved "Stdlib::Absolutepath" $> UDTData+ <|> reserved "Stdlib::Base32" $> UDTData+ <|> reserved "Stdlib::Base64" $> UDTData+ <|> reserved "Stdlib::Compat::Absolute_path" $> UDTData+ <|> reserved "Stdlib::Compat::Array" $> UDTData+ <|> reserved "Stdlib::Compat::Bool" $> UDTData+ <|> reserved "Stdlib::Compat::Float" $> UDTData+ <|> reserved "Stdlib::Compat::Hash" $> UDTData+ <|> reserved "Stdlib::Compat::Integer" $> UDTData+ <|> reserved "Stdlib::Compat::Ip_address" $> UDTData+ <|> reserved "Stdlib::Compat::Ipv4" $> UDTData+ <|> reserved "Stdlib::Compat::Ipv6" $> UDTData+ <|> reserved "Stdlib::Compat::Numeric" $> UDTData+ <|> reserved "Stdlib::Compat::String" $> UDTData+ <|> reserved "Stdlib::Ensure::Service" $> UDTData+ <|> reserved "Stdlib::Filemode" $> UDTData+ <|> reserved "Stdlib::Filesource" $> UDTData+ <|> reserved "Stdlib::Fqdn" $> UDTData+ <|> reserved "Stdlib::Host" $> UDTData+ <|> reserved "Stdlib::HTTPSUrl" $> UDTData+ <|> reserved "Stdlib::HTTPUrl" $> UDTData+ <|> reserved "Stdlib::IP::Address::Nosubnet" $> UDTData+ <|> reserved "Stdlib::Ip_address" $> UDTData+ <|> reserved "Stdlib::IP::Address" $> UDTData+ <|> reserved "Stdlib::IP::Address::V4::CIDR" $> UDTData+ <|> reserved "Stdlib::IP::Address::V4::Nosubnet" $> UDTData+ <|> reserved "Stdlib::IP::Address::V4" $> UDTData+ <|> reserved "Stdlib::IP::Address::V6::Alternative" $> UDTData+ <|> reserved "Stdlib::IP::Address::V6::Compressed" $> UDTData+ <|> reserved "Stdlib::IP::Address::V6::Full" $> UDTData+ <|> reserved "Stdlib::IP::Address::V6::Nosubnet::Alternative" $> UDTData+ <|> reserved "Stdlib::IP::Address::V6::Nosubnet::Compressed" $> UDTData+ <|> reserved "Stdlib::IP::Address::V6::Nosubnet::Full" $> UDTData+ <|> reserved "Stdlib::IP::Address::V6::Nosubnet" $> UDTData+ <|> reserved "Stdlib::IP::Address::V6" $> UDTData+ <|> reserved "Stdlib::Ipv4" $> UDTData+ <|> reserved "Stdlib::Ipv6" $> UDTData+ <|> reserved "Stdlib::MAC" $> UDTData+ <|> reserved "Stdlib::Port::Privileged" $> UDTData+ <|> reserved "Stdlib::Port" $> UDTData+ <|> reserved "Stdlib::Port::Unprivileged" $> UDTData <|> reserved "Stdlib::Unixpath" $> UDTData+ <|> reserved "Stdlib::Windowspath" $> UDTData <|> reserved "Nginx::ErrorLogSeverity" $> UDTData <|> reserved "Jenkins::Tunnel" $> UDTData <|> reserved "Systemd::Unit" $> UDTData
src/Puppet/Parser/PrettyPrinter.hs view
@@ -44,6 +44,7 @@ UDTEnum tx -> "Enum" <> list (foldMap (pure . pretty) tx) UDTAny -> "Any" UDTCollection -> "Collection"+ UDTRegexp mr -> "Regexp" <> foldMap (brackets . pretty) mr where bounded :: (Pretty a, Pretty b) => Doc -> Maybe a -> Maybe b -> Doc bounded s ma mb = s <> case (ma, mb) of
src/Puppet/Parser/Types.hs view
@@ -179,6 +179,7 @@ | UDTEnum (NonEmpty Expression) | UDTAny | UDTCollection+ | UDTRegexp (Maybe CompRegex) -- Tuple (NonEmpty DataType) Integer Integer -- DTDefault -- Struct TODO
src/Puppet/Runner/Stdlib.hs view
@@ -91,7 +91,7 @@ -- parseyaml , ("pick", pick) , ("pick_default", pickDefault)- -- prefix+ , ("prefix", prefix) -- private -- pw_hash -- range@@ -107,7 +107,7 @@ -- strtosaltedshar512 -- strftime , ("strip", stringArrayFunction Text.strip)- -- suffix+ , ("suffix", suffix ) -- swapcase -- time -- to_bytes@@ -171,6 +171,25 @@ puppetAbs y = case y ^? _Number of Just x -> return $ _Number # abs x Nothing -> throwPosError ("abs(): Expects a number, not" <+> pretty y)++suffix :: [PValue] -> InterpreterMonad PValue+suffix = foofix "suffix" (flip (<>))++prefix :: [PValue] -> InterpreterMonad PValue+prefix = foofix "prefix" (<>)++foofix :: Doc -> (Text -> Text -> Text) -> [PValue] -> InterpreterMonad PValue+foofix nm f args =+ case args of+ [PHash h] -> pure (PHash h)+ [PArray r] -> pure (PArray r)+ [_] -> throwPosError (nm <> ": expects the first argument to be an array or a hash")+ [PHash h, PString s] -> pure (PHash . HM.fromList . map (_1 %~ f s) . HM.toList $ h)+ [PArray r, PString s] -> pure (PArray (r & traverse . _PString %~ f s))+ [PHash _, _] -> throwPosError (nm <> ": expects the second argument to be a string")+ [PArray _, _] -> throwPosError (nm <> ": expects the second argument to be a string")+ [_, _] -> throwPosError (nm <> ": expects the first argument to be an array or a hash")+ _ -> throwPosError (nm <> ": expects two arguments") assertPrivate :: [PValue] -> InterpreterMonad PValue assertPrivate args =
tests/DT/Parser.hs view
@@ -4,6 +4,7 @@ import Test.Hspec.Megaparsec import Text.Megaparsec (parse)+import qualified Text.Regex.PCRE.ByteString.Utils as Regex spec :: Spec spec = do@@ -15,6 +16,9 @@ failed "String[4,5,6]" "String[5]" `parsed` UDTString (Just 5) Nothing "String[5,8]" `parsed` UDTString (Just 5) (Just 8)+ "Regexp" `parsed` UDTRegexp Nothing+ let Right foore = Regex.compile' Regex.compBlank Regex.execBlank "foo"+ "Regexp[/foo/]" `parsed` UDTRegexp (Just (CompRegex "foo" foore)) it "accepts variables" $ pendingWith "to be fixed" *> parse datatype "?" "String[$var]" `shouldParse` UDTString (Just 5) Nothing describe "Stdlib::" $ do "Stdlib::HTTPUrl" `parsed` UDTData
+ tests/Function/PrefixSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedLists #-}+module Function.PrefixSpec (spec, main) where++import qualified Data.Text as T++import Helpers++main :: IO ()+main = hspec spec++fname :: Text+fname = "prefix"++spec :: Spec+spec = withStdlibFunction fname $ \tester -> do+ let checkError input expectederror =+ case dummyEval (tester input) of+ Left rr -> show (getError rr) `shouldStartWith` (T.unpack fname ++ ": " ++ expectederror)+ Right _ -> expectationFailure "should have failed"+ checkSuccess input expected =+ case dummyEval (tester input) of+ Left rr -> expectationFailure (show rr)+ Right r -> r `shouldBe` expected+ it "should fail with no argument" (checkError [] "expects two arguments")+ it "should fail if the first argument isn't an array or hash" (checkError ["lol"] "expects the first argument to be an array or a hash")+ it "should fail if the second argument isn't a string" $ do+ checkError [PArray [], PNumber 1] "expects the second argument to be a string"+ checkError [PArray [], PArray []] "expects the second argument to be a string"+ it "should work with arrays" $ do+ checkSuccess [ PArray []] (PArray [])+ checkSuccess [ PArray [], ""] (PArray [])+ checkSuccess [ PArray ["one"], "pre" ] (PArray ["preone"])+ checkSuccess [ PArray ["one","two","three"], "pre" ] (PArray ["preone","pretwo","prethree"])+ it "should work with hashes" $ do+ checkSuccess [(PHash mempty)] (PHash mempty)+ checkSuccess [(PHash mempty), ""] (PHash mempty)+ checkSuccess [(PHash [("one", PNumber 5)] ), "pre" ] (PHash [("preone", PNumber 5)])+ checkSuccess [(PHash [("one", PNumber 5), ("two", "lol"), ("three", PNumber 7)]), "pre" ] (PHash [("preone", PNumber 5), ("pretwo", "lol"), ("prethree", PNumber 7)])+
+ tests/Function/SuffixSpec.hs view
@@ -0,0 +1,39 @@+{-# LANGUAGE OverloadedLists #-}+module Function.SuffixSpec (spec, main) where++import qualified Data.Text as T++import Helpers++main :: IO ()+main = hspec spec++fname :: Text+fname = "suffix"++spec :: Spec+spec = withStdlibFunction fname $ \tester -> do+ let checkError input expectederror =+ case dummyEval (tester input) of+ Left rr -> show (getError rr) `shouldStartWith` (T.unpack fname ++ ": " ++ expectederror)+ Right _ -> expectationFailure "should have failed"+ checkSuccess input expected =+ case dummyEval (tester input) of+ Left rr -> expectationFailure (show rr)+ Right r -> r `shouldBe` expected+ it "should fail with no argument" (checkError [] "expects two arguments")+ it "should fail if the first argument isn't an array or hash" (checkError ["lol"] "expects the first argument to be an array or a hash")+ it "should fail if the second argument isn't a string" $ do+ checkError [PArray [], PNumber 1] "expects the second argument to be a string"+ checkError [PArray [], PArray []] "expects the second argument to be a string"+ it "should work with arrays" $ do+ checkSuccess [ PArray []] (PArray [])+ checkSuccess [ PArray [], ""] (PArray [])+ checkSuccess [ PArray ["one"], "post" ] (PArray ["onepost"])+ checkSuccess [ PArray ["one","two","three"], "post" ] (PArray ["onepost","twopost","threepost"])+ it "should work with hashes" $ do+ checkSuccess [(PHash mempty)] (PHash mempty)+ checkSuccess [(PHash mempty), ""] (PHash mempty)+ checkSuccess [(PHash [("one", PNumber 5)] ), "post" ] (PHash [("onepost", PNumber 5)])+ checkSuccess [(PHash [("one", PNumber 5), ("two", "lol"), ("three", PNumber 7)]), "post" ] (PHash [("onepost", PNumber 5), ("twopost", "lol"), ("threepost", PNumber 7)])+
tests/Spec.hs view
@@ -15,6 +15,8 @@ import qualified Function.ShellquoteSpec import qualified Function.SizeSpec import qualified Function.SprintfSpec+import qualified Function.SuffixSpec+import qualified Function.PrefixSpec import qualified Interpreter.CollectorSpec import qualified Interpreter.IfSpec import qualified InterpreterSpec@@ -43,6 +45,8 @@ describe "The sprintf function" Function.SprintfSpec.spec describe "The each function" Function.EachSpec.spec describe "The lookup function" Function.LookupSpec.spec+ describe "The suffix function" Function.SuffixSpec.spec+ describe "The prefix function" Function.PrefixSpec.spec describe "stdlib functions" $ do describe "The assert_private function" Function.AssertPrivateSpec.spec describe "The join_keys_to_values function" Function.JoinKeysToValuesSpec.spec