packages feed

gargoyle 0.1 → 0.1.1.0

raw patch · 5 files changed

+85/−26 lines, 5 filesdep +unixdep ~basedep ~directorydep ~filelocksetup-changednew-uploaderPVP ok

version bump matches the API change (PVP)

Dependencies added: unix

Dependency ranges changed: base, directory, filelock, filepath, network, process

API changes (from Hackage documentation)

Files

+ ChangeLog.md view
@@ -0,0 +1,10 @@+# Changelog for gargoyle++## 0.1.1++* Bugfix: Error cases on opening file were non-exhaustive+* Loosen version bounds++## 0.1++* Initial release
+ README.md view
@@ -0,0 +1,34 @@+# gargoyle++Gargoyle is a framework for managing daemons from Haskell. Currently, the only requirement is that the daemon be able to communicate over a Unix domain socket. See [gargoyle-postgresql](https://hackage.haskell.org/package/gargoyle-postgresql) for an example that uses gargoyle to manage postgresql.++To use Gargoyle the client must:+* Define a value of the 'Gargoyle' type which specifies how to administer the daemon.+* Create an executable whose `main` is `gargoyleMain`. The name of this executable should match the executable name specified in the `_gargoyle_exec` field of the `Gargoyle`.+* The client will run their code with `withGargoyle` to gain access to the daemon.++# Importing into Haskell package set++```nix+haskellPackages.override {+  overrides = self: super:+    let gargoylePkgs = import ./path/to/gargoyle-repo { haskellPackages = self; };+    in gargoylePkgs // {+      # .. your overrides+    };+}+```++By default `gargoyle-postgresql-nix` will use the `postgresql` of the `pkgs` used by your `haskellPackages`. To override this, pass `postgresql` by changing the above line to look more like++```nix+gargoylePkgs = import ./path/to/gargoyle-repo { haskellPackages = self; postgresql = myCustomVersion; }+```++# Hacking++Do something like this:++```shell+nix-shell -A gargoyle-postgresql.env --run 'cd gargoyle-postgresql && cabal new-repl'+```
− Setup.hs
@@ -1,2 +0,0 @@-import Distribution.Simple-main = defaultMain
gargoyle.cabal view
@@ -1,14 +1,14 @@-name: gargoyle-version: 0.1-license: BSD3-license-file: LICENSE-author: Obsidian Systems LLC-maintainer: maintainer@obsidian.systems-copyright: Copyright (C) Obsidian Systems LLC 2017-category: System-build-type: Simple-cabal-version: >=1.10-synopsis: Automatically spin up and spin down local daemons+name:               gargoyle+version:            0.1.1.0+license:            BSD3+license-file:       LICENSE+author:             Obsidian Systems LLC+maintainer:         maintainer@obsidian.systems+copyright:          Copyright (C) Obsidian Systems LLC 2017+category:           System+build-type:         Simple+cabal-version:      >=1.10+synopsis:           Automatically spin up and spin down local daemons description:   Gargoyle is a framework for managing daemons from Haskell. In the current release the only requirement is that the daemon be able to communicate over a Unix domain socket. See <https://hackage.haskell.org/package/gargoyle-postgresql gargoyle-postgresql> for a fully worked out example.   .@@ -18,15 +18,24 @@   2. Create an executable whose `main` is 'gargoyleMain'. The name of this executable should match the executable name specified in the '_gargoyle_exec' field of the 'Gargoyle'.   3. The client will run their code with 'withGargoyle' to gain access to the daemon. +extra-source-files:+  ChangeLog.md+  README.md++tested-with:        GHC ==8.6.5 || ==8.8.4 || ==8.10.2+ library-  exposed-modules: Gargoyle-  ghc-options: -Wall-  ghc-prof-options: -fprof-auto-  build-depends: base >= 4.9 && < 4.11-               , directory == 1.3.*-               , filepath == 1.4.*-               , filelock == 0.1.*-               , network == 2.6.*-               , process == 1.4.*-  hs-source-dirs: src+  exposed-modules:  Gargoyle+  ghc-options:      -Wall+  ghc-prof-options: -fprof-auto-exported+  build-depends:+      base       >=4.12.0 && <4.15+    , directory  >=1.3.3  && <1.4+    , filelock   >=0.1.1  && <0.2+    , filepath   >=1.4.2  && <1.5+    , network    >=2.6.0  && <3.2+    , process    >=1.5.0  && <1.7+    , unix       >=2.7.2  && <2.8++  hs-source-dirs:   src   default-language: Haskell2010
src/Gargoyle.hs view
@@ -20,6 +20,7 @@ import System.IO.Error import System.Environment import System.FileLock+import System.Posix.Process import System.Process  import Debug.Trace@@ -92,7 +93,10 @@               let monProc = (proc (_gargoyle_exec g) [daemonDir])                     { std_in = CreatePipe                     , std_out = CreatePipe-                    , std_err = Inherit }+                    , std_err = Inherit+                    , close_fds = True+                    , new_session = True+                    }               (Just monIn, Just monOut, Nothing, monHnd) <- createProcess monProc               void $ forkOS $ void $ waitForProcess monHnd               hClose monIn@@ -102,7 +106,7 @@                   threadDelay 500000 -- These are expensive ops so don't try too hard                   acquire -- Try again                 "ready" -> acquire-                _ -> fail "Unexpected gargoyle message from monitor process"+                _ -> fail $ "Unexpected gargoyle message from monitor process: " <> r             | otherwise -> throwIO e   bracket_ acquire (shutdown s ShutdownBoth >> close s) $     b =<< _gargoyle_getInfo g (gWorkDir daemonDir)@@ -115,7 +119,7 @@ gargoyleMain :: Gargoyle pid a              -- ^ Description of how to initialize, spin up, and spin down a daemon.              -> IO () -- ^ Returns only when all clients have disconnected.-gargoyleMain g = do+gargoyleMain g = void $ forkProcess $ do   checkThreadedRuntime   [daemonDir] <- getArgs >>= \case     x@[_] -> return x@@ -126,6 +130,7 @@     | isAlreadyInUseError e -> return ()     | isDoesNotExistError e -> throwIO e -- this means it's not a file but it exists     | isPermissionError e -> throwIO e -- the daemon directory is in a bad state+    | otherwise -> throwIO e   -- The daemon tries to hold on to the lock file for its lifetime, signaling that it is   -- accepting connections.   lock <- tryLockFile lockPath Exclusive >>= \case@@ -166,6 +171,7 @@     shutdownVar <- newEmptyMVar     void $ forkOS $ forever $ do       (s, _) <- accept controlSocket+      acceptThread <- myThreadId       --TODO: What happens if we decide we're shutting down here?       modifyMVar_ numClientsVar $ \n -> do         return $ succ n@@ -182,6 +188,8 @@           case pred n of             0 -> do               shutdown controlSocket ShutdownBoth+              -- We have to explicitly kill the accept thread, because otherwise (sometimes?) 'accept' will begin returning EAGAIN, and ghc will continuously retry it.  This busywait consumes 100% of CPU, prevents the monitor from actually exiting, and leaves the control socket and lock file in a state where another monitor can't be started.+              killThread acceptThread               putMVar shutdownVar ()             n' -> putMVar numClientsVar n'     bracket (_gargoyle_start g (gWorkDir daemonDir)) (_gargoyle_stop g) $ \_ -> do