Skip to content

Commit

Permalink
Merge branch 'main' of github.com:seanhess/hyperbole
Browse files Browse the repository at this point in the history
  • Loading branch information
seanhess committed Jan 8, 2025
2 parents c55dc95 + e0846cd commit dce22ab
Show file tree
Hide file tree
Showing 13 changed files with 559 additions and 140 deletions.
44 changes: 13 additions & 31 deletions .github/workflows/haskell.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Haskell CI

on:
push:
branches: [ "main", "ci" ]
branches: [ "main" ]
pull_request:
branches: [ "main" ]

Expand All @@ -11,38 +11,20 @@ permissions:

jobs:
build:

runs-on: ubuntu-latest

container:
image: haskell:9.8.2
strategy:
matrix:
os: [ubuntu-latest]
runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4

# - uses: actions/setup-haskell@v1
# with:
# ghc-version: '9.6'
# cabal-version: '3.2'
- uses: actions/checkout@v3

# - name: Cache
# uses: actions/cache@v3
# env:
# cache-name: cache-cabal
# with:
# path: ~/.cabal
# key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/*.cabal') }}-${{ hashFiles('**/cabal.project') }}
# restore-keys: |
# ${{ runner.os }}-build-${{ env.cache-name }}-
# ${{ runner.os }}-build-
# ${{ runner.os }}-
- name: Install Nix
uses: DeterminateSystems/nix-installer-action@main

- name: Install dependencies
run: |
cabal update
cabal build --only-dependencies --enable-tests --enable-benchmarks
- name: Build
run: cabal build --enable-tests --enable-benchmarks all
- name: Test
run: cabal test
- name: Setup Nix cache
uses: DeterminateSystems/magic-nix-cache-action@main

- name: Check packages
run: |
nix flake check
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ node_modules
.pre-commit-config.yaml
# Nix output dir
result

.direnv
client/dist/hyperbole.js.LICENSE.txt
client/dist/hyperbole.js.map

Session.vim
55 changes: 53 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ The example directory contains an app demonstrating various features. See it in
<img alt="Hyperbole Examples" src="example/static/examples.png"/>
</a>

### Try Example Project with Nix

If you want to get a feel for hyperbole without cloning the project run `nix run github:seanhess/hyperbole` to run the example webserver locally

Learn More
----------
Expand All @@ -106,11 +109,59 @@ The NSO uses Hyperbole for the Level 2 Data creation tool for the [DKIST telesco
Local Development
-----------------

### Dependencies with Nix
### Recommended ghcid command

If you want to work on both the hyperbole library and example code, this `ghcid` command will run (and hot reload) the examples server as you change any non-testing code.

```
ghcid --setup=Main.update --command="cabal repl exe:examples lib:hyperbole" --run=Main.update --warnings --reload=./client/dist/hyperbole.js
```

With nix installed, you can use `nix develop` to get a shell with all dependencies installed.
If you want to work on the test suite, this will run the tests each time any library code is changed.

```
ghcid --command="cabal repl test lib:hyperbole" --run=Main.main --warnings --reload=./client/dist/hyperbole.js
```

### Nix

Prepend targets with ghc982 or ghc966 to use GHC 9.8.2 or GHC 9.6.6

- `nix run` or `nix run .#ghc966-hyperbole-examples` to start the example project with GHC 9.8.2
- `nix develop` or `nix develop .#ghc982-shell` to get a shell with all dependencies installed for GHC 9.8.2.

You can import this flake's overlay to add `hyperbole` to all package sets and override ghc966 and ghc982 with the packages to satisfy `hyperbole`'s dependencies.

```nix
{
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable";
hyperbole.url = "github:seanhess/hyperbole"; # or "path:/path/to/cloned/hyperbole";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, hyperbole, flake-utils, ... }:
flake-utils.lib.eachDefaultSystem (
system:
let
pkgs = import nixpkgs {
inherit system;
overlays = [ hyperbole.overlays.default ];
};
haskellPackagesOverride = pkgs.haskell.packages.ghc966.override (old: {
overrides = pkgs.lib.composeExtensions (old.overrides or (_: _: { })) (hfinal: hprev: {
# your overrides here
});
});
in
{
devShells.default = haskellPackagesOverride.shellFor {
packages = p: [ p.hyperbole ];
};
}
);
}
```

### Manual dependency installation

Expand Down
5 changes: 2 additions & 3 deletions bin/dev
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,8 @@ package() {
}

compile() {
cd example
hpack
ghcid -T main -W --command="cabal repl examples"
hpack example/
ghcid --setup=Main.update --command="cabal repl exe:examples lib:hyperbole" --run=Main.update --warnings --reload=./client/dist/hyperbole.js
}

client() {
Expand Down
2 changes: 2 additions & 0 deletions cabal.project
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
tests: True
multi-repl: True
packages:
.
example
-- ../web-view/
-- https://hackage.haskell.org/package/web-view-0.6.2/candidate/web-view-0.6.2.tar.gz
4 changes: 2 additions & 2 deletions example/Example/Page/Search.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
module Example.Page.Search where

import Control.Monad (forM_)
import Data.List ((!?))
import Data.Text (Text)
import Data.Text qualified as T
import Effectful
Expand All @@ -12,6 +11,7 @@ import Example.Colors
import Example.Data.ProgrammingLanguage (ProgrammingLanguage (..), allLanguages, isMatchLanguage)
import Example.Page.Filter as Filter (chosenView, resultsTable)
import Example.View.Layout (exampleLayout)
import Safe (atMay)
import Web.Hyperbole
import Prelude hiding (even, odd)

Expand Down Expand Up @@ -54,7 +54,7 @@ liveSearchView langs current term = do
where
matchedLanguages = filter (isMatchLanguage term) langs

currentSearchLang = matchedLanguages !? current
currentSearchLang = matchedLanguages `atMay` current

-- Only show the search popup if there is a search term
shownIfTerm = if T.null term then hide else flexCol
Expand Down
84 changes: 83 additions & 1 deletion example/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@

module Main where

import Control.Monad (forever)
import Control.Concurrent
( MVar
, ThreadId
, forkFinally
, killThread
, newEmptyMVar
, putMVar
, takeMVar
)
import Control.Monad (forever, (>=>))
import Data.ByteString.Lazy qualified as BL
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.String.Conversions (cs)
import Data.String.Interpolate (i)
import Data.Text (Text)
Expand Down Expand Up @@ -42,20 +52,37 @@ import Example.Page.Todo qualified as Todo
import Example.Page.Transitions qualified as Transitions
import Example.Style qualified as Style
import Example.View.Layout as Layout (exampleLayout, examplesView)
import Foreign.Store
( Store (..)
, lookupStore
, readStore
, storeAction
, withStore
)
import GHC.Generics (Generic)
import Network.HTTP.Types (Method, QueryItem, methodPost, status200, status404)
import Network.Wai qualified as Wai
import Network.Wai.Handler.Warp qualified as Warp
import Network.Wai.Middleware.Static (addBase, staticPolicy)
import Network.WebSockets (Connection, PendingConnection, acceptRequest, defaultConnectionOptions)
import System.IO
( BufferMode (LineBuffering)
, hSetBuffering
, stdout
)
import Web.Hyperbole
import Web.Hyperbole.Effect.Handler (RunHandlers)
import Web.Hyperbole.Effect.Server (Request (..))

-- import System.Process (callCommand)
-- import Network.Wai.Handler.Warp
import GHC.Word (Word32)

-- import Network.Wai.Handler.WebSockets (websocketsOr)

main :: IO ()
main = do
hSetBuffering stdout LineBuffering
putStrLn "Starting Examples on http://localhost:3000"
users <- Users.initUsers
count <- runEff $ runConcurrent Counter.initCounter
Expand Down Expand Up @@ -128,3 +155,58 @@ app users count = do
</head>
<body>#{cnt}</body>
</html>|]

{- | Made for local development
-
- ghcid --setup=Main.update --command="cabal repl exe:examples lib:hyperbole test" --run=Main.update --warnings
-
- Start or restart the server.
newStore is from foreign-store.
A Store holds onto some data across ghci reloads
-}
update :: IO ()
update = do
mtidStore <- lookupStore tidStoreNum
case mtidStore of
-- no server running
Nothing -> do
done <- storeAction doneStore newEmptyMVar
tid <- start done
_ <- storeAction (Store tidStoreNum) (newIORef tid)
return ()
-- server is already running
Just tidStore -> do
restartAppInNewThread tidStore
where
-- callCommand "xmonadctl refreshFirefox"

doneStore :: Store (MVar ())
doneStore = Store 0

-- shut the server down with killThread and wait for the done signal
restartAppInNewThread :: Store (IORef ThreadId) -> IO ()
restartAppInNewThread tidStore = modifyStoredIORef tidStore $ \tid -> do
killThread tid
withStore doneStore takeMVar
readStore doneStore >>= start

-- \| Start the server in a separate thread.
start
:: MVar ()
-- \^ Written to when the thread is killed.
-> IO ThreadId
start done = do
forkFinally
main
-- Note that this implies concurrency
-- between shutdownApp and the next app that is starting.
-- Normally this should be fine
(\_ -> putMVar done ())

tidStoreNum :: Word32
tidStoreNum = 1

modifyStoredIORef :: Store (IORef a) -> (a -> IO a) -> IO ()
modifyStoredIORef store f = withStore store $ \ref -> do
v <- readIORef ref
f v >>= writeIORef ref
5 changes: 0 additions & 5 deletions example/cabal.project

This file was deleted.

5 changes: 3 additions & 2 deletions example/package.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ dependencies:
- network
- websockets
- cookie
- hyperbole

executables:
examples:
Expand All @@ -57,15 +58,15 @@ executables:
- -rtsopts
- -with-rtsopts=-N
source-dirs:
- ../src
- ./
dependencies:
- wai-middleware-static
- safe
- foreign-store
docgen:
main: Main.hs
source-dirs:
- ./docgen
dependencies:
- hyperbole
- directory
- filepath
Loading

0 comments on commit dce22ab

Please sign in to comment.