packages feed

mellon-core 0.8.0.2 → 0.8.0.3

raw patch · 3 files changed

+242/−203 lines, 3 filesdep +faildep +mellon-coredep +semigroupsdep ~QuickCheckdep ~doctestPVP ok

version bump matches the API change (PVP)

Dependencies added: fail, mellon-core, semigroups

Dependency ranges changed: QuickCheck, doctest

API changes (from Hackage documentation)

Files

changelog.md view
@@ -1,3 +1,15 @@+## 0.8.0.3 (2018-01-11)++- Use hpack.++- Support for GHC 8.2.2.++- Bump doctest, QuickCheck upper bounds.++- A few test fixes.++- Maintainer-related changes (better Nix support, Makefile, etc.).+ ## 0.8.0.2 (2017-09-04)  - No changes, version bump only.
mellon-core.cabal view
@@ -1,207 +1,235 @@-Name:                   mellon-core-Version:                0.8.0.2-Cabal-Version:          >= 1.18-Build-Type:             Simple-Author:                 Drew Hess <dhess-src@quixoftic.com>-Maintainer:             Drew Hess <dhess-src@quixoftic.com>-Homepage:               https://github.com/quixoftic/mellon/-Bug-Reports:            https://github.com/quixoftic/mellon/issues/-Stability:              experimental-License:                BSD3-License-File:           LICENSE-Copyright:              Copyright (c) 2017, Quixoftic, LLC-Tested-With:            GHC == 7.10.3, GHC == 8.0.1, GHC == 8.0.2-Category:               System-Synopsis:               Control physical access devices-Description:-  /Speak, friend, and enter./-  .-  @mellon-core@ is a Haskell package for controlling physical access-  devices designed for human factors, e.g., electric strikes. The-  access control protocol is quite simple: a device is either locked,-  or it is unlocked until a particular date and time (an-  /expiration date/). Once the expiration date passes, the device is-  automatically locked again. In the meantime, the device can be-  locked immediately, overriding the unlocked state; or the unlock-  period can be extended.-  .-  User programs incorporate @mellon-core@ functionality via a-  /controller/, which is responsible for handling user lock and unlock-  commands, and for scheduling and canceling unlock expirations.-  .-  User programs must also adapt their physical access devices to the-  interface expected by the controller. For this purpose,-  @mellon-core@ defines a /device/ type with 2 simple 'IO' actions for-  locking and unlocking the device. (@mellon-core@ does not provide-  any useful device implementations; see the companion @mellon-gpio@-  package for a GPIO-driven implementation.)-  .-  Note that @mellon-core@ does not provide authentication mechanisms-  or network services for interacting with controllers; that is the-  domain of higher-level packages which use the base @mellon-core@-  package (e.g., @mellon-web@).-  .-  /On the use of UTC dates for timers/-  .-  @mellon-core@ uses UTC dates for unlock expiration, rather than a-  time delta or a monotonic clock. You might disagree with this-  decision based on the common wisdom that it's a bad idea to use-  \"wall clock time\" (of which UTC is one flavor) for timers. In-  general, the common wisdom is correct. Wall clocks have lots of-  problems: they may not be accurate, they may disagree from one-  system to the next, they may \"jump around\" if the system is running-  a time daemon such as NTP, and they occasionally do something-  unexpected like adding a leap second.-  .-  If your timers must be high-precision (i.e., this timer must run for-  exactly /n/ microseconds, for some definition of \"exactly\"), then-  there's no argument: using a wall clock is a bad idea. However, as-  @mellon-core@ is designed for use with physical access devices,-  which themselves are typically designed for human factors, accuracy-  to within a second or two is acceptable in most cases. (If you have-  higher-precision needs, especially for extreme safety- or-  security-related scenarios, you should probably be using a real-time-  system anyway, not a Haskell program.)-  .-  Once the need for high precision is eliminated, and assuming that-  the system(s) controlling your physical access devices use a-  synchronized time source such as that provided by-  <https://en.wikipedia.org/wiki/Network_Time_Protocol NTP>, the-  advantages of using UTC over most of the alternatives become-  apparent:-  .-  * Absolute time deltas without a common reference do not work well-    in networked environments, where network problems may appreciably-    delay the delivery of commands from client to server. If a user-    wants to unlock a device for 7 seconds, does that mean 7 seconds-    from the clock time @T@ when the user presses \"send,\" or does it-    mean 7 seconds from opening to close, regardless of when the-    server receives the command? Without a common reference, there is-    no way for the user to communicate her intent.-  .-  * Monotonic clocks never go backwards, which is a nice invariant and-    eliminates a problem that occurs in some NTP implementations.-    However, monotonic clocks are a) non-portable, and not even-    supported on all systems; b) usually system-dependent, which-    renders them useless when attempting to communicate time across-    two systems; c) sometimes even process-dependent, in which case-    they're not even useful for communicating time between two-    processes on the same system; and d) often idle while the system-    is suspending or sleeping, in which case the clock does not move-    forward while the system is suspended, rendering the clock useless-    for absolute timers if there's any possibility that the system-    will be suspended or otherwise go into a low-power mode.-  .-  Using the TAI coordinate system rather than UTC has the advantage of-  guaranteeing that every (TAI) day is exactly 86400 (TAI) seconds,-  unlike UTC and all of the time systems based on it, where very-  rarely a day may have 86401 seconds, i.e., one standard day plus 1-  leap second. If TAI were well-supported and generally available,-  @mellon-core@ would probably use it, but circa 2016 it is not.-  Anyway, at worst, a @mellon-core@ unlock command which spans a time-  period in which a leap second is added will expire approximately 1-  second too soon / too early, depending on whether the user accounted-  for the leap second when she issued the command. As this error is-  more or less within the expected accuracy of a @mellon-core@ system-  under normal operation (due to the vagaries of thread scheduling,-  and not even accounting for clock drift and other real-world-  factors), it doesn't really seem worth the effort just to avoid the-  minor inconvenience of leap seconds.-  .-  In short, synchronizing time (and timers) across multiple systems is-  a very difficult problem, and one which the universally-supported-  Network Time Protocol attempts to address, mostly successfully.-  Given its intended application to controlling physical access for-  human beings, most likely in a networked environment, @mellon-core@-  makes the choice of relying on a working, accurate NTP (or other-  wall-clock synchronization) deployment for coordinating and-  synchronizing time across devices. If you cannot guarantee accurate-  wall clock time in your system, @mellon-core@ will not work-  properly, and you should look for an alternative solution.+-- This file has been generated from package.yaml by hpack version 0.21.2.+--+-- see: https://github.com/sol/hpack+--+-- hash: 03b9d6e60a651567d584825fe6863c4f050e9deb4b6986d9d668be39fb4bbdff -Extra-Doc-Files:        README.md-Extra-Source-Files:     changelog.md+name:                   mellon-core+version:                0.8.0.3+synopsis:               Control physical access devices+description:            /Speak, friend, and enter./+                        .+                        @mellon-core@ is a Haskell package for controlling physical access+                        devices designed for human factors, e.g., electric strikes. The+                        access control protocol is quite simple: a device is either locked,+                        or it is unlocked until a particular date and time (an+                        /expiration date/). Once the expiration date passes, the device is+                        automatically locked again. In the meantime, the device can be+                        locked immediately, overriding the unlocked state; or the unlock+                        period can be extended.+                        .+                        User programs incorporate @mellon-core@ functionality via a+                        /controller/, which is responsible for handling user lock and unlock+                        commands, and for scheduling and canceling unlock expirations.+                        .+                        User programs must also adapt their physical access devices to the+                        interface expected by the controller. For this purpose,+                        @mellon-core@ defines a /device/ type with 2 simple 'IO' actions for+                        locking and unlocking the device. (@mellon-core@ does not provide+                        any useful device implementations; see the companion @mellon-gpio@+                        package for a GPIO-driven implementation.)+                        .+                        Note that @mellon-core@ does not provide authentication mechanisms+                        or network services for interacting with controllers; that is the+                        domain of higher-level packages which use the base @mellon-core@+                        package (e.g., @mellon-web@).+                        .+                        /On the use of UTC dates for timers/+                        .+                        @mellon-core@ uses UTC dates for unlock expiration, rather than a+                        time delta or a monotonic clock. You might disagree with this+                        decision based on the common wisdom that it's a bad idea to use+                        \"wall clock time\" (of which UTC is one flavor) for timers. In+                        general, the common wisdom is correct. Wall clocks have lots of+                        problems: they may not be accurate, they may disagree from one+                        system to the next, they may \"jump around\" if the system is running+                        a time daemon such as NTP, and they occasionally do something+                        unexpected like adding a leap second.+                        .+                        If your timers must be high-precision (i.e., this timer must run for+                        exactly /n/ microseconds, for some definition of \"exactly\"), then+                        there's no argument: using a wall clock is a bad idea. However, as+                        @mellon-core@ is designed for use with physical access devices,+                        which themselves are typically designed for human factors, accuracy+                        to within a second or two is acceptable in most cases. (If you have+                        higher-precision needs, especially for extreme safety- or+                        security-related scenarios, you should probably be using a real-time+                        system anyway, not a Haskell program.)+                        .+                        Once the need for high precision is eliminated, and assuming that+                        the system(s) controlling your physical access devices use a+                        synchronized time source such as that provided by+                        <https://en.wikipedia.org/wiki/Network_Time_Protocol NTP>, the+                        advantages of using UTC over most of the alternatives become+                        apparent:+                        .+                        * Absolute time deltas without a common reference do not work well+                        in networked environments, where network problems may appreciably+                        delay the delivery of commands from client to server. If a user+                        wants to unlock a device for 7 seconds, does that mean 7 seconds+                        from the clock time @T@ when the user presses \"send,\" or does it+                        mean 7 seconds from opening to close, regardless of when the+                        server receives the command? Without a common reference, there is+                        no way for the user to communicate her intent.+                        .+                        * Monotonic clocks never go backwards, which is a nice invariant and+                        eliminates a problem that occurs in some NTP implementations.+                        However, monotonic clocks are a) non-portable, and not even+                        supported on all systems; b) usually system-dependent, which+                        renders them useless when attempting to communicate time across+                        two systems; c) sometimes even process-dependent, in which case+                        they're not even useful for communicating time between two+                        processes on the same system; and d) often idle while the system+                        is suspending or sleeping, in which case the clock does not move+                        forward while the system is suspended, rendering the clock useless+                        for absolute timers if there's any possibility that the system+                        will be suspended or otherwise go into a low-power mode.+                        .+                        Using the TAI coordinate system rather than UTC has the advantage of+                        guaranteeing that every (TAI) day is exactly 86400 (TAI) seconds,+                        unlike UTC and all of the time systems based on it, where very+                        rarely a day may have 86401 seconds, i.e., one standard day plus 1+                        leap second. If TAI were well-supported and generally available,+                        @mellon-core@ would probably use it, but circa 2016 it is not.+                        Anyway, at worst, a @mellon-core@ unlock command which spans a time+                        period in which a leap second is added will expire approximately 1+                        second too soon / too early, depending on whether the user accounted+                        for the leap second when she issued the command. As this error is+                        more or less within the expected accuracy of a @mellon-core@ system+                        under normal operation (due to the vagaries of thread scheduling,+                        and not even accounting for clock drift and other real-world+                        factors), it doesn't really seem worth the effort just to avoid the+                        minor inconvenience of leap seconds.+                        .+                        In short, synchronizing time (and timers) across multiple systems is+                        a very difficult problem, and one which the universally-supported+                        Network Time Protocol attempts to address, mostly successfully.+                        Given its intended application to controlling physical access for+                        human beings, most likely in a networked environment, @mellon-core@+                        makes the choice of relying on a working, accurate NTP (or other+                        wall-clock synchronization) deployment for coordinating and+                        synchronizing time across devices. If you cannot guarantee accurate+                        wall clock time in your system, @mellon-core@ will not work+                        properly, and you should look for an alternative solution.+category:               System+stability:              experimental+homepage:               https://github.com/quixoftic/mellon#readme+bug-reports:            https://github.com/quixoftic/mellon/issues+author:                 Drew Hess <dhess-src@quixoftic.com>+maintainer:             Drew Hess <dhess-src@quixoftic.com>+copyright:              Copyright (c) 2017, Quixoftic, LLC+license:                BSD3+license-file:           LICENSE+tested-with:            GHC==7.10.3 GHC==8.0.1 GHC==8.0.2 GHC==8.2.1 GHC==8.2.2+build-type:             Simple+cabal-version:          >= 1.10 --- Build doctests-Flag test-doctests-  Default: True-  Manual: True+extra-source-files:+    changelog.md+    README.md --- Build hlint test-Flag test-hlint-  Default: True-  Manual: True+source-repository head+  type: git+  location: https://github.com/quixoftic/mellon -Library-  Default-Language:     Haskell2010-  HS-Source-Dirs:       src-  GHC-Options:          -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates-  If impl(ghc > 8)-    GHC-Options:        -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances -fno-warn-redundant-constraints-  Exposed-Modules:      Mellon.Controller-                      , Mellon.Controller.Async-                      , Mellon.Device-                      , Mellon.StateMachine-  Other-Extensions:     DeriveDataTypeable-                      , DeriveGeneric-                      , Safe-  Build-Depends:        base         >= 4.8   && < 5-                      , async        == 2.1.*-                      , mtl          == 2.2.*-                      , time         >= 1.5   && < 2-                      , transformers >= 0.4.2 && < 0.6+flag test-doctests+  description: Build doctests+  manual: True+  default: True -Test-Suite hlint-  Type:                 exitcode-stdio-1.0-  Default-Language:     Haskell2010-  Hs-Source-Dirs:       test-  Ghc-Options:          -w -threaded -rtsopts -with-rtsopts=-N-  Main-Is:              hlint.hs-  If !flag(test-hlint)-    Buildable:          False-  Else-    Build-Depends:      base-                      , hlint >= 1.9 && < 2.1+flag test-hlint+  description: Build hlint test+  manual: True+  default: True -Test-Suite doctest-  Type:                 exitcode-stdio-1.0-  Default-Language:     Haskell2010-  Hs-Source-Dirs:       test-  Ghc-Options:          -Wall -threaded-  Main-Is:              doctest.hs-  If !flag(test-doctests)-    Buildable:          False-  Else-    Build-Depends:      base-                      , QuickCheck           >= 2.8    && < 2.10-                      , quickcheck-instances == 0.3.*-                      , doctest              == 0.11.*+library+  hs-source-dirs:+      src+  other-extensions: DeriveDataTypeable DeriveGeneric Safe+  build-depends:+      async ==2.1.*+    , base >=4.8 && <5+    , mtl ==2.2.*+    , time >=1.5 && <2+    , transformers >=0.4.2 && <0.6+  if impl(ghc >= 8.0)+    ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates+  else+    ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates+  if impl(ghc >= 8.0)+    ghc-options: -Wcompat -Wnoncanonical-monad-instances -Wnoncanonical-monadfail-instances+  else+    build-depends:+        fail ==4.9.*+      , semigroups ==0.18.*+  exposed-modules:+      Mellon.Controller+      Mellon.Controller.Async+      Mellon.Device+      Mellon.StateMachine+  other-modules:+      Paths_mellon_core+  default-language: Haskell2010 -Test-Suite spec-  Type:                 exitcode-stdio-1.0-  Default-Language:     Haskell2010-  Hs-Source-Dirs:       src-                      , test-  Ghc-Options:          -w -threaded -rtsopts -with-rtsopts=-N-  Main-Is:              Main.hs-  Build-Depends:        base-                      , async-                      , hspec        >= 2.2 && < 2.5-                      , mtl-                      , time-                      , transformers-  Other-Modules:        Mellon.Controller-                      , Mellon.Controller.Async-                      , Mellon.Device-                      , Mellon.StateMachine-                      , Spec-                      , Mellon.Controller.AsyncSpec+test-suite doctest+  type: exitcode-stdio-1.0+  main-is: doctest.hs+  hs-source-dirs:+      test+  ghc-options: -threaded+  if impl(ghc >= 8.0)+    ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates+  else+    ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates+  if !(flag(test-doctests))+    buildable: False+  else+    build-depends:+        QuickCheck >=2.8 && <2.11+      , base+      , doctest >=0.11 && <0.14+      , quickcheck-instances ==0.3.*+  default-language: Haskell2010 -Source-Repository head-  Type:                 git-  Location:             git://github.com/quixoftic/mellon.git+test-suite hlint+  type: exitcode-stdio-1.0+  main-is: hlint.hs+  hs-source-dirs:+      test+  ghc-options: -w -threaded -rtsopts -with-rtsopts=-N+  if impl(ghc >= 8.0)+    ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates+  else+    ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates+  if !(flag(test-hlint))+    buildable: False+  else+    build-depends:+        base+      , hlint >=1.9 && <2.1+  default-language: Haskell2010 -Source-Repository this-  Type:                 git-  Location:             git://github.com/quixoftic/mellon.git-  Tag:                  v0.8.0.2+test-suite spec+  type: exitcode-stdio-1.0+  main-is: Main.hs+  hs-source-dirs:+      test+  other-extensions: DeriveDataTypeable+  ghc-options: -w -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      async+    , base+    , hspec >=2.2 && <2.5+    , mellon-core+    , mtl+    , time+    , transformers+  if impl(ghc >= 8.0)+    ghc-options: -Wall -Wincomplete-uni-patterns -Wincomplete-record-updates+  else+    ghc-options: -Wall -fwarn-incomplete-uni-patterns -fwarn-incomplete-record-updates+  other-modules:+      Mellon.Controller.AsyncSpec+      Spec+      Paths_mellon_core+  default-language: Haskell2010
test/Mellon/Controller/AsyncSpec.hs view
@@ -17,8 +17,7 @@        (Controller, State(..), controller, minUnlockTime, lockController,         queryController, unlockController) import Mellon.Device-       (Device(..), MockLock, MockLockEvent(..), events, mockLock,-        mockLockDevice)+       (Device(..), MockLockEvent(..), events, mockLock, mockLockDevice)  sleep :: (MonadIO m) => Int -> m () sleep = liftIO . threadDelay . (* 1000000)@@ -32,8 +31,8 @@ type TestController d a = RWST (Controller d) [MockLockEvent] () IO a  testController :: Controller d -> IO [MockLockEvent]-testController cc =-  do (_, expectedResults) <- execRWST theTest cc ()+testController ctrl =+  do (_, expectedResults) <- execRWST theTest ctrl ()      return expectedResults    where theTest :: TestController d ()@@ -153,7 +152,7 @@      cc <- controller Nothing $ exceptionLockDevice el -- 1st lock op      now <- getCurrentTime      let expire = timePlusN now 3-     unlockController expire cc -- 2nd & 3rd lock op (unlock, timed lock)+     void $ unlockController expire cc -- 2nd & 3rd lock op (unlock, timed lock)      (sleep 5) `shouldThrow` isExceptionLockException -- async exception      queryController cc `shouldReturn` StateUnlocked expire -- should have state prior to exception