packages feed

confetti 0.3.2 → 1.0.0

raw patch · 4 files changed

+83/−57 lines, 4 filesdep +cmdargsPVP ok

version bump matches the API change (PVP)

Dependencies added: cmdargs

API changes (from Hackage documentation)

- Confetti: newtype ApplyError a
+ Confetti: VariantAlreadyExists :: [a] -> ApplyError a
+ Confetti: [forceSymlink] :: ConfigSpec -> Bool
+ Confetti: appendVariantExists :: ApplyError a -> ApplyError a -> ApplyError a
+ Confetti: concatVariantExists :: [ApplyError a] -> ApplyError a
+ Confetti: data ApplyError a
+ Confetti: instance Data.Foldable.Foldable Confetti.ApplyError
+ Confetti: maybeApplyError :: ApplyError a -> Maybe (ApplyError a)
- Confetti: ConfigSpec :: ConfigGroup -> ConfigVariantPrefix -> ConfigSpec
+ Confetti: ConfigSpec :: ConfigGroup -> ConfigVariantPrefix -> Bool -> ConfigSpec
- Confetti: backUpIfNonSymLink :: FilePath -> IO ()
+ Confetti: backUpIfNonSymLink :: Bool -> FilePath -> IO (Maybe (ApplyError FilePath))

Files

app/Main.hs view
@@ -1,54 +1,56 @@-{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings  #-} -import           Data.Version       (showVersion) import           Confetti-import           Paths_confetti     (version)++import           Data.Maybe+import           Data.Version                    (showVersion)+import           Paths_confetti                  (version)+import           System.Console.CmdArgs+import           System.Console.CmdArgs.Implicit import           System.Environment import           System.Exit import           Text.Printf -import qualified Data.Text          as T+import qualified Data.Text                       as T  -- Structure for our command line arguments data MainArgs = MainArgs-  { groupName     :: String-  , variantPrefix :: ConfigVariantPrefix-  } deriving (Show)+  { group_name     :: String+  , variant_prefix :: ConfigVariantPrefix+  , force          :: Bool+  } deriving (Show, Data, Typeable, Eq) --- Parse our command line arguments for a confetti command,--- or display some information and exit-parseMainArgs :: [String] -> IO MainArgs-parseMainArgs [g, v] = return (MainArgs g $ Just v)-parseMainArgs a =-  let usage =-        "Usage: `confetti [required group_name] [optional variant_prefix]`"-      showHelp = (putStrLn usage >> exitSuccess)-      confettiVersion =-        putStrLn ("confetti " ++ showVersion version) >> exitSuccess-  in case a of-       ["-h"]        -> showHelp-       ["--help"]    -> showHelp-       ["-v"]        -> confettiVersion-       ["--version"] -> confettiVersion-       [g]           -> return (MainArgs g Nothing)-       _             -> printFail usage >> exitWith (ExitFailure 1)+argParser :: MainArgs+argParser =+  MainArgs+  { group_name = def &= argPos 0 &= typ "GROUP_NAME"+  , variant_prefix = def &= argPos 1 &= typ "VARIANT_PREFIX" &= opt (Nothing :: Maybe T.Text)+  , force = def &= help "If the target already exists as a regular file, back it up and then create a link"+  } &=+  summary ("confetti " ++ showVersion version) &=+  program "confetti" &=+  verbosity &=+  help "Easily swap groups of config files" +confettiArgs :: IO MainArgs+confettiArgs = cmdArgs argParser+ main :: IO () main = do-  args <- getArgs-  parsed <- parseMainArgs args+  parsed <- confettiArgs   printf     "Setting %s to %s\n"-    (groupName parsed)-    (showPrefix $ variantPrefix parsed)+    (group_name parsed)+    (showPrefix $ variant_prefix parsed)   specPath <- absolutePath "~/.confetti.yml"-  group <- parseGroup specPath (T.pack $ groupName parsed)+  group <- parseGroup specPath (T.pack $ group_name parsed)   let validatedGroup = group >>= validateSpec-  either (printFail . show) (runSpec (variantPrefix parsed)) validatedGroup+  either (printFail . show) (runSpec (variant_prefix parsed) (force parsed)) validatedGroup  -- Run our configuration spec. Prints whatever error message we get back, -- or a success message-runSpec :: ConfigVariantPrefix -> ConfigGroup -> IO ()-runSpec prefix group =-  applySpec (ConfigSpec group prefix) >>= \maybeError ->+runSpec :: ConfigVariantPrefix -> Bool -> ConfigGroup -> IO ()+runSpec prefix shouldForce group =+  applySpec (ConfigSpec group prefix shouldForce) >>= \maybeError ->     maybe (printSuccess "Success (ノ◕ヮ◕)ノ*:・゚✧") (printFail . show) maybeError
confetti.cabal view
@@ -1,5 +1,5 @@ name:                confetti-version:             0.3.2+version:             1.0.0 synopsis:            A simple config file swapping tool category:            Command Line Tools description:         See the README on GitHub at <https://github.com/aviaviavi/confetti#readme>@@ -45,6 +45,7 @@   main-is:           Main.hs   build-depends:     base >= 4.8 && < 5                    , directory+                   , cmdargs                    , confetti                    , text >= 1.2.2.1   other-modules:
src/Confetti.hs view
@@ -1,13 +1,15 @@-{-# LANGUAGE DeriveGeneric         #-}-{-# LANGUAGE OverloadedStrings     #-}+{-# LANGUAGE DeriveFoldable    #-}+{-# LANGUAGE DeriveGeneric     #-}+{-# LANGUAGE OverloadedStrings #-}  module Confetti where +import           Control.Applicative import           Control.Exception import           Control.Monad+import           Data.Either.Utils import           Data.List import           Data.List.Utils-import           Data.Either.Utils import           Data.Maybe import           Data.Monoid import           Data.Time.Clock.POSIX@@ -41,10 +43,24 @@       (show a)  -- Errors from applying our config spec-newtype ApplyError a = VariantsMissing [a]+data ApplyError a = VariantsMissing [a] | VariantAlreadyExists [a] deriving (Foldable) instance (Show a) => Show (ApplyError a)  where   show (VariantsMissing a) = "Couldn't find one or more of your variant files to use: " ++ show a+  show (VariantAlreadyExists a) = printf "Target(s) %s already exists as a regular file. To backup and then symlink, use the -f flag when invoking confetti" $ show a +appendVariantExists :: ApplyError a -> ApplyError a -> ApplyError a+appendVariantExists (VariantAlreadyExists a) (VariantAlreadyExists b) =+  VariantAlreadyExists $ a ++ b++concatVariantExists :: [ApplyError a] -> ApplyError a+concatVariantExists = foldr appendVariantExists (VariantAlreadyExists [])++maybeApplyError :: ApplyError a -> Maybe (ApplyError a)+maybeApplyError err = if null err then Nothing else Just err++-- applyErrorToMaybe :: ApplyError a -> Maybe (ApplyError a)+--   applyErrorToMaybe a = fmap listToMaybe+ -- A config file version we want to swap in or out type ConfigVariant = String @@ -122,6 +138,7 @@ data ConfigSpec = ConfigSpec   { configGroup         :: ConfigGroup   , configVariantPrefix :: ConfigVariantPrefix+  , forceSymlink        :: Bool   }  -- Given a yaml file and a group name, parse the group into a ConfigGroup, or@@ -211,14 +228,17 @@  -- If a target config file is _not_ a symlink, -- make a backup before we swap out the config-backUpIfNonSymLink :: FilePath -> IO ()-backUpIfNonSymLink file = do+backUpIfNonSymLink :: Bool -> FilePath -> IO (Maybe (ApplyError FilePath))+backUpIfNonSymLink shouldForce file = do   exists <- doesFileExist file   isLink <-     if exists       then pathIsSymbolicLink file       else return False-  when (exists && not isLink) $ createBackup file+  if exists && not isLink then+    if shouldForce then createBackup file >> return Nothing+    else return . Just $ VariantAlreadyExists [file]+  else return Nothing  -- Backs up a file, eg config.json -> config.json.$time.backup createBackup :: FilePath -> IO ()@@ -323,21 +343,24 @@             (\t -> SearchPath {path = takeDirectory t, recursive = Just False})             groupTargets)          (searchPaths $ configGroup spec))-  mapM_ backUpIfNonSymLink groupTargets-  mapM_ removeIfExists groupTargets-  let confirmedVariantFiles = filter (isJust . result) searchResults-      foundFiles =-        uniq $ map (takeFileName . fromJust . result) confirmedVariantFiles-      allFiles = uniq $ map fileName searchResults-      missingVariants = allFiles \\ foundFiles-  if null missingVariants-    then do-      mapM_-        (\s -> printSuccess $ linkToCreate s ++ " -> " ++ fromJust (result s))-        confirmedVariantFiles-      linkTargets confirmedVariantFiles-      return Nothing-    else return $ Just (VariantsMissing missingVariants)+  backupErr <- maybeApplyError . concatVariantExists . catMaybes <$> mapM (backUpIfNonSymLink (forceSymlink spec)) groupTargets+  if isJust backupErr+    then return backupErr+    else do+      let confirmedVariantFiles = filter (isJust . result) searchResults+          foundFiles =+            uniq $ map (takeFileName . fromJust . result) confirmedVariantFiles+          allFiles = uniq $ map fileName searchResults+          missingVariants = allFiles \\ foundFiles+      if null missingVariants+        then do+          mapM_ removeIfExists groupTargets+          mapM_+            (\s -> printSuccess $ linkToCreate s ++ " -> " ++ fromJust (result s))+            confirmedVariantFiles+          linkTargets confirmedVariantFiles+          return Nothing+        else return $ Just (VariantsMissing missingVariants)  -- Expands ~ to $HOME in a path absolutePath :: FilePath -> IO FilePath
test/Main.hs view
@@ -7,6 +7,6 @@ main :: IO () main = defaultMain $ testGroup "all-tests" tests --- TODO: some tests would be good for future avi to write.+-- TODO(|p=101|#lol) - some tests would be good for future avi to write. tests :: [TestTree] tests = []