diff --git a/addressbook.cabal b/addressbook.cabal index ef0188e..00c35bc 100644 --- a/addressbook.cabal +++ b/addressbook.cabal @@ -42,6 +42,7 @@ library , containers , filepath , parallel + , unix hs-source-dirs: src default-language: Haskell2010 ghc-options: -Wall diff --git a/default.nix b/default.nix index 1431253..84a8668 100644 --- a/default.nix +++ b/default.nix @@ -1,7 +1,7 @@ { mkDerivation, attoparsec, base, bytestring, conduit , conduit-extra, containers, criterion, filepath, hedgehog , hedgehog-corpus, HUnit, lens, lib, mtl, optparse-applicative -, parallel, tasty, tasty-hedgehog, tasty-hunit, text, vector +, parallel, tasty, tasty-hedgehog, tasty-hunit, text, unix, vector }: mkDerivation { pname = "addressbook"; @@ -11,7 +11,7 @@ mkDerivation { isExecutable = true; libraryHaskellDepends = [ attoparsec base bytestring conduit conduit-extra containers - filepath lens mtl parallel text vector + filepath lens mtl parallel text unix vector ]; executableHaskellDepends = [ base bytestring containers criterion hedgehog-corpus diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..2e2c9f2 --- /dev/null +++ b/flake.lock @@ -0,0 +1,62 @@ +{ + "nodes": { + "easy-hls": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1637250802, + "narHash": "sha256-/crlHEVB148PGQLZCsHOR9L5qgvCAfRSocIoKgmMAhA=", + "owner": "jkachmar", + "repo": "easy-hls-nix", + "rev": "7c123399ef8a67dc0e505d9cf7f2c7f64f1cd847", + "type": "github" + }, + "original": { + "owner": "jkachmar", + "repo": "easy-hls-nix", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1637014545, + "narHash": "sha256-26IZAc5yzlD9FlDT54io1oqG/bBoyka+FJk5guaX4x4=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "bba5dcc8e0b20ab664967ad83d24d64cb64ec4f4", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1637312849, + "narHash": "sha256-OhVZopkyryEfLyPwcXk2IQsdi80lj6TY1YFoMNZ4hCQ=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "e4806bb4416f88c20f8be0b8ef9b5b09ff9022a6", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "easy-hls": "easy-hls", + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..b077c73 --- /dev/null +++ b/flake.nix @@ -0,0 +1,53 @@ +{ + description = "addressbook"; + + inputs = { + easy-hls = { + url = "github:jkachmar/easy-hls-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils = { + url = "github:numtide/flake-utils"; + }; + }; + + outputs = { self, nixpkgs, flake-utils, easy-hls }: + { overlay = final: prev: { + haskellPackages = prev.haskellPackages.override ( old: { + overrides = final.lib.composeExtensions (old.overrides or (_: _: {})) (f: p: { + addressbook = f.callPackage ./. {}; + }); + }); + }; + } + // + flake-utils.lib.eachSystem ["x86_64-linux" "x86_64-darwin"] ( system: + let + pkgs = import nixpkgs { inherit system; overlays = [ self.overlay ]; }; + hp = pkgs.haskellPackages; + hls = (easy-hls.withGhcs [ hp.ghc ]).${system}; + in + rec { + + packages = { inherit (hp) addressbook; }; + + defaultPackage = packages.addressbook; + apps.addressbook = { + type = "app"; + program = "${hp.addressbook}/bin/addressbook"; + }; + devShell = hp.shellFor { + packages = h: [h.addressbook]; + withHoogle = true; + buildInputs = with pkgs; [ + entr + cabal-install + hp.hlint + stylish-haskell + ghcid + hls + ]; + }; + } + ); +} diff --git a/src/Control/Addressbook/Streaming.hs b/src/Control/Addressbook/Streaming.hs index 59d1aca..856d11b 100644 --- a/src/Control/Addressbook/Streaming.hs +++ b/src/Control/Addressbook/Streaming.hs @@ -30,6 +30,7 @@ import System.IO.Unsafe (unsafeInterleaveIO) import Control.Parallel.Strategies (rseq, parMap) import qualified Data.List as L import Control.Monad (unless) +import System.Posix (touchFile) combine :: (MonadUnliftIO m, MonadResource m, MonadThrow m, MonadIO m) => ConduitM FilePath Header m () combine = await >>= \case @@ -45,6 +46,7 @@ run :: IO () run = do datDir <- fromMaybe "./" <$> lookupEnv "HOME" let datFile = datDir ".addressbook.dat" + touchFile datFile original <- Set.fromList . map LBS.toStrict . lbsLines <$> LBS.readFile datFile xs <- LBS.getContents >>= stream let set = original `Set.union` F.fold (parMap rseq F.fold (chunks 200 xs))