packages feed

merge-bash-history (empty) → 0.1.0.0

raw patch · 7 files changed

+252/−0 lines, 7 filesdep +attoparsecdep +basedep +data-ordlistsetup-changed

Dependencies added: attoparsec, base, data-ordlist, errors, merge-bash-history, optparse-applicative, text

Files

+ LICENSE view
@@ -0,0 +1,30 @@+Copyright Jiri Marsicek (c) 2015++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++    * Redistributions of source code must retain the above copyright+      notice, this list of conditions and the following disclaimer.++    * Redistributions in binary form must reproduce the above+      copyright notice, this list of conditions and the following+      disclaimer in the documentation and/or other materials provided+      with the distribution.++    * Neither the name of Jiri Marsicek nor the names of other+      contributors may be used to endorse or promote products derived+      from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ README.md view
@@ -0,0 +1,50 @@+# merge-bash-history++Utility to be used with unison (http://www.cis.upenn.edu/~bcpierce/unison/) to merge `.bash_history` file accross multiple machines.++# Installation++Clone the repository++```+git clone https://github.com/j1r1k/merge-bash-history.git+```++Install using stack+```+cd merge-bash-history+stack install+```++# Example configuration in unison preferences file++Assuming you have root set to your home directory and `merge-bash-history` is in your $PATH++Add following to your unsion .prf file++```+merge = Name .bash_history -> merge-bash-history CURRENT1 CURRENT2 > NEW+backupcurrent = Name .bash_history+```++# Manual usage++```+merge-bash-history [INPUT-FILE1] [INPUT-FILE2] > [MERGED-FILE]+```++# Limitations+- Does not support line deletion (e.g. manual removal of lines from .bash_history file)++# Warnings+- Sorts .bash_history file by timestamp if not sorted+- removes duplicates (comparing timestamp and command)++# Recommended Bash settings++```+shopt -s histappend+PROMPT_COMMAND="${PROMPT_COMMAND};history -a"+```++From Pawel Hajdan (http://phajdan-jr.blogspot.de/2015/03/more-reliable-handling-of-bash-history.html)
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ app/Main.hs view
@@ -0,0 +1,35 @@+module Main where++import MergeBashHistory++import Data.Text.IO as TIO (readFile, putStr)++import Options.Applicative++data HmbhO = HmbhO FilePath FilePath++opParseFilePath :: Parser FilePath+opParseFilePath = argument str $ metavar "FILE"++opParseHmbhO :: Parser HmbhO+opParseHmbhO = HmbhO <$> opParseFilePath+                     <*> opParseFilePath++execOpParserHmbhO :: IO HmbhO+execOpParserHmbhO = execParser $ info (helper <*> opParseHmbhO) (fullDesc <> header "bash_history merger")++handleFile :: FilePath -> IO [HistoryRecord]+handleFile fp =+  do i <- TIO.readFile fp+     case parseFile i of Left e -> error $ show e+                         Right r -> return r++hmbhHandler :: HmbhO -> IO ()+hmbhHandler (HmbhO fp1 fp2) =+  do f1 <- handleFile fp1+     f2 <- handleFile fp2+     mapM_ (TIO.putStr . recordToText) $ mergeRecords f1 f2+++main :: IO ()+main = execOpParserHmbhO >>= hmbhHandler
+ merge-bash-history.cabal view
@@ -0,0 +1,49 @@+name:                merge-bash-history+version:             0.1.0.0+synopsis:            Initial project template from stack+description:         Please see README.md+homepage:            http://github.com/j1r1k/merge-bash-history#readme+license:             BSD3+license-file:        LICENSE+author:              Jiri Marsicek+maintainer:          jiri.marsicek@gmail.com+copyright:           2015 Jiri Marsicek+category:            Tools+build-type:          Simple+extra-source-files:  README.md+cabal-version:       >=1.10++library+  hs-source-dirs:      src+  exposed-modules:     MergeBashHistory+  build-depends:       base >= 4.7 && < 5+                     , attoparsec >= 0.12+                     , data-ordlist >= 0.4+                     , errors >= 2+                     , text >= 1.2+  ghc-options:         -Wall+  default-language:    Haskell2010++executable merge-bash-history+  hs-source-dirs:      app+  main-is:             Main.hs+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  build-depends:       base+                     , merge-bash-history+                     , optparse-applicative >=0.11+                     , text >= 1.2+  ghc-options:         -Wall+  default-language:    Haskell2010++test-suite MergeBashHistory-test+  type:                exitcode-stdio-1.0+  hs-source-dirs:      test+  main-is:             Spec.hs+  build-depends:       base+                     , merge-bash-history+  ghc-options:         -threaded -rtsopts -with-rtsopts=-N+  default-language:    Haskell2010++source-repository head+  type:     git+  location: https://github.com/j1r1k/merge-bash-history
+ src/MergeBashHistory.hs view
@@ -0,0 +1,84 @@+module MergeBashHistory+  ( Timestamp+  , Command+  , HmbhError+  , HistoryRecord+  , mergeRecords+  , parseFile+  , recordToText+  ) where++import Control.Applicative ((<|>))++import Data.EitherR (fmapL)+import Data.List.Ordered (merge, nub)+import Data.Text (Text)+import qualified Data.Text as Text++import Data.Attoparsec.Text+++type Timestamp = Integer+type Command = Text++data HistoryLine = Header Timestamp+                 | Command Command+                 deriving (Show)++data HmbhError = ParseError String+               | EmptyFile+               | MissingHeader++instance Show HmbhError where+  show (ParseError e) = "Error: Parser Error '" ++ e ++ "'"+  show EmptyFile      = "Error: Merging with empty file"+  show MissingHeader  = "Error: Missing header"++data HistoryRecord = HistoryRecord { header   :: Timestamp+                                   , commands :: [Command]+                                   } deriving (Eq, Show)++instance Ord HistoryRecord where+  h1 `compare` h2 = header h1 `compare` header h2++recordToText :: HistoryRecord -> Text+recordToText (HistoryRecord t c) = Text.unlines $ Text.pack ('#' : show t) : c++emptyRecord :: Timestamp -> HistoryRecord+emptyRecord t = HistoryRecord { header = t, commands = [] }++appendCommand :: HistoryRecord -> Command -> HistoryRecord+appendCommand hr c = hr { commands = commands hr ++ [c] }++linesToRecords :: [HistoryLine] -> Either HmbhError [HistoryRecord]+linesToRecords []             = Left EmptyFile+linesToRecords (Command _: _) = Left MissingHeader+linesToRecords (Header t: as) = Right $ squash $ foldr f (emptyRecord t, []) as+  where f (Header  s) acc           = (emptyRecord s, squash acc)+        f (Command c) (current, ps) = (appendCommand current c, ps)+        squash (x, xs) = x : xs++historyHeader :: Parser HistoryLine+historyHeader =+  do _ <- char '#'+     t <- decimal+     endOfLine+     return $ Header t++historyCommand :: Parser HistoryLine+historyCommand =+  do c <- takeTill isEndOfLine+     endOfLine+     return $ Command c++historyLine :: Parser HistoryLine+historyLine = historyHeader <|> historyCommand++historyLines :: Parser [HistoryLine]+historyLines = many' historyLine++mergeRecords :: [HistoryRecord] -> [HistoryRecord] -> [HistoryRecord]+mergeRecords a b = nub $ merge a b++parseFile :: Text -> Either HmbhError [HistoryRecord]+parseFile t = fmapL ParseError (parseOnly historyLines t) >>= linesToRecords
+ test/Spec.hs view
@@ -0,0 +1,2 @@+main :: IO ()+main = putStrLn "Test suite not yet implemented"