diff --git a/src/css/mk.css b/src/css/mk.css index 50c32ba..a82509c 100644 --- a/src/css/mk.css +++ b/src/css/mk.css @@ -217,7 +217,7 @@ figure, .figure { content: ": "; } .notes { - padding: 5px 10px; + padding: 1ex; } .underline { text-decoration: underline; diff --git a/src/posts/0010-Haskell-Now/hspwg.init.tar.gz b/src/posts/0010-Haskell-Now/hspwg.init.tar.gz new file mode 100644 index 0000000..a7d61b5 Binary files /dev/null and b/src/posts/0010-Haskell-Now/hspwg.init.tar.gz differ diff --git a/src/posts/0010-Haskell-Now/hspwg/.envrc b/src/posts/0010-Haskell-Now/hspwg/.envrc new file mode 100644 index 0000000..1d953f4 --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/.envrc @@ -0,0 +1 @@ +use nix diff --git a/src/posts/0010-Haskell-Now/hspwg/.gitignore b/src/posts/0010-Haskell-Now/hspwg/.gitignore new file mode 100644 index 0000000..6d7e2df --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/.gitignore @@ -0,0 +1,2 @@ +dist-newstyle/ +result diff --git a/src/posts/0010-Haskell-Now/hspwg/CHANGELOG.md b/src/posts/0010-Haskell-Now/hspwg/CHANGELOG.md new file mode 100644 index 0000000..62981e2 --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/CHANGELOG.md @@ -0,0 +1,5 @@ +# Revision history for hspwg + +## 0.1.0.0 -- YYYY-mm-dd + +* First version. Released on an unsuspecting world. diff --git a/src/posts/0010-Haskell-Now/hspwg/LICENSE b/src/posts/0010-Haskell-Now/hspwg/LICENSE new file mode 100644 index 0000000..59ef795 --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/LICENSE @@ -0,0 +1,30 @@ +Copyright (c) 2020, Yann Esposito (Yogsototh) + +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 Yann Esposito (Yogsototh) 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. diff --git a/src/posts/0010-Haskell-Now/hspwg/Setup.hs b/src/posts/0010-Haskell-Now/hspwg/Setup.hs new file mode 100644 index 0000000..9a994af --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/src/posts/0010-Haskell-Now/hspwg/app/Main.hs b/src/posts/0010-Haskell-Now/hspwg/app/Main.hs new file mode 100644 index 0000000..4a932cc --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/app/Main.hs @@ -0,0 +1,12 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +module Main where + +import Protolude + +import qualified MyLib (genPassword) + +main :: IO () +main = do + pwd <- MyLib.genPassword + putText pwd diff --git a/src/posts/0010-Haskell-Now/hspwg/default.nix b/src/posts/0010-Haskell-Now/hspwg/default.nix new file mode 100644 index 0000000..40f3806 --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/default.nix @@ -0,0 +1,35 @@ +{ nixpkgs ? import ./nixpkgs.nix +, compiler ? "default" +, doBenchmark ? false }: +let + inherit (nixpkgs) pkgs; + name = "hspwg"; + haskellPackages = pkgs.haskellPackages; + variant = if doBenchmark + then pkgs.haskell.lib.doBenchmark + else pkgs.lib.id; + drv = haskellPackages.callCabal2nix name ./. {}; +in +{ + my_project = drv; + shell = haskellPackages.shellFor { + # generate hoogle doc + withHoogle = true; + packages = p: [drv]; + # packages dependencies (by default haskellPackages) + buildInputs = with haskellPackages; + [ hlint + ghcid + cabal-install + cabal2nix + hindent + # # if you want to add some system lib like ncurses + # # you could by writing it like: + # pkgs.ncurses + ]; + # nice prompt for the nix-shell + shellHook = '' + export PS1="\n[${name}:\033[1;32m\]\W\[\033[0m\]]> " + ''; + }; +} diff --git a/src/posts/0010-Haskell-Now/hspwg/hspwg.cabal b/src/posts/0010-Haskell-Now/hspwg/hspwg.cabal new file mode 100644 index 0000000..8f43f4f --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/hspwg.cabal @@ -0,0 +1,58 @@ +cabal-version: 2.4 +-- Initial package description 'hspwg.cabal' generated by 'cabal init'. +-- For further documentation, see http://haskell.org/cabal/users-guide/ + +name: hspwg +version: 0.1.0.0 +synopsis: Password Generator +-- description: +-- bug-reports: +license: BSD-3-Clause +license-file: LICENSE +author: Yann Esposito (Yogsototh) +maintainer: yann.esposito@gmail.com +-- copyright: +category: Security +extra-source-files: CHANGELOG.md + +common professional-properties + default-language: Haskell2010 + build-depends: + base ^>=4.12.0.0 + ghc-options: + -Wall + -Wcompat + -Wincomplete-uni-patterns + -Wredundant-constraints + -Wnoncanonical-monad-instances + -- -Werror + -- -O2 + +library + import: professional-properties + exposed-modules: MyLib + -- other-modules: + -- other-extensions: + build-depends: protolude, + random + hs-source-dirs: src + +executable hspwg + import: professional-properties + main-is: Main.hs + -- other-modules: + -- other-extensions: + ghc-options: + -- enable parallelism + -threaded + "-with-rtsopts=-N" + build-depends: hspwg, + protolude + hs-source-dirs: app + +test-suite hspwg-test + import: professional-properties + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: MyLibTest.hs + -- build-depends: base ^>=4.12.0.0 diff --git a/src/posts/0010-Haskell-Now/hspwg/nixpkgs.nix b/src/posts/0010-Haskell-Now/hspwg/nixpkgs.nix new file mode 100644 index 0000000..aae2b1d --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/nixpkgs.nix @@ -0,0 +1 @@ +import (fetchTarball https://github.com/NixOS/nixpkgs/archive/19.09.tar.gz) {} diff --git a/src/posts/0010-Haskell-Now/hspwg/release.nix b/src/posts/0010-Haskell-Now/hspwg/release.nix new file mode 100644 index 0000000..8a1ee52 --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/release.nix @@ -0,0 +1,4 @@ +let + def = import ./. {}; +in + { my_project = def.my_project; } diff --git a/src/posts/0010-Haskell-Now/hspwg/shell.nix b/src/posts/0010-Haskell-Now/hspwg/shell.nix new file mode 100644 index 0000000..0d9af5e --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/shell.nix @@ -0,0 +1 @@ +(import ./. {}).shell diff --git a/src/posts/0010-Haskell-Now/hspwg/src/MyLib.hs b/src/posts/0010-Haskell-Now/hspwg/src/MyLib.hs new file mode 100644 index 0000000..1555d91 --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/src/MyLib.hs @@ -0,0 +1,15 @@ +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +module MyLib (genPassword) where + +import Protolude + +import Data.Char (chr,ord) +import qualified System.Random as Random + +genPassword :: IO Text +genPassword = do + let stdgen = Random.mkStdGen 0 + numbers = take 10 (Random.randoms stdgen) + password = toS [ chr ( (n `mod` 27) + ord 'a') | n <- numbers ] + return password diff --git a/src/posts/0010-Haskell-Now/hspwg/test/MyLibTest.hs b/src/posts/0010-Haskell-Now/hspwg/test/MyLibTest.hs new file mode 100644 index 0000000..3e2059e --- /dev/null +++ b/src/posts/0010-Haskell-Now/hspwg/test/MyLibTest.hs @@ -0,0 +1,4 @@ +module Main (main) where + +main :: IO () +main = putStrLn "Test suite not yet implemented." diff --git a/src/posts/0010-Haskell-Now/index.org b/src/posts/0010-Haskell-Now/index.org index 70b61df..317ab29 100644 --- a/src/posts/0010-Haskell-Now/index.org +++ b/src/posts/0010-Haskell-Now/index.org @@ -162,7 +162,7 @@ The article contains five parts: - More on infinite tree; a more math oriented discussion about infinite trees -** Helpers :noexport: +** Helpers :noexport: :PROPERTIES: :CUSTOM_ID: helpers :END: @@ -177,9 +177,10 @@ The article contains five parts: #+CAPTION: Haskell logo [[./Haskell-logo.png]] -1. Install [[https://nixos.org/nix][nix]] -2. create a new empty directory =hsenv= somewhere -3. Put the following =shell.nix= file inside it +1. Install [[https://nixos.org/nix][nix]] (The version I use is nix (Nix) 2.3.1, future 2.X.X versions + should work with the examples in this article) +3. create a new empty directory =hsenv= somewhere +4. Put the following =shell.nix= file inside it {{{lnk(shell.nix)}}} #+begin_src nix :tangle shell.nix @@ -211,7 +212,7 @@ The article contains five parts: } #+end_src -4. In the =hsenv= directory, in a terminal, run =nix-shell --pure=. +5. In the =hsenv= directory, in a terminal, run =nix-shell --pure=. You should wait a lot of time for everything to download. And you should be ready. You will have in your PATH: @@ -220,7 +221,7 @@ The article contains five parts: - =runghc= that will be able to interpret a Haskell file - =cabal= which is the main tool to deal with Haskell projects - the Haskell libraries =protolude= and =containers=. -5. To test your env, rung =ghci= and type =import Protolude= you should see +6. To test your env, rung =ghci= and type =import Protolude= you should see something like this: #+begin_src @@ -3494,18 +3495,17 @@ it really "clicked" for them. :CUSTOM_ID: start-a-new-project :END: -There are many different way to start. +There are multiple starting options to create a new project. The most common one is certainly to use =cabal-install=. Another popular option is to use =stack=. -=stack= add a layer on top of =cabal-install= and use fixed set of libraries -known to compile together. -The last option is to use =cabal-install= but take care of the dependencies -of your project via =nix=. - -The last option is often considered as the most complex and difficult for -beginner. -And guess what? -Against all odds, I will introduce haskell project development via =nix=. +=stack= adds a layer on top of =cabal-install= and uses fixed set of +libraries known to compile together. +Another method is to =nix= to handle the dependencies and use +=cabal-install= for the rest. +That final choice is often considered as the most complex and difficult for +beginners. +Still this is the one I find the most elegant. +This is the method I will use in this article. Still, you shall not be intimidated. Look: @@ -3943,7 +3943,7 @@ executable my-app #+end_src #+begin_notes -I did not included a version constraint here. +I did not include a version constraint here. This is ok if you do not deploy your library publicly. This would be absolutely awful if you deploy your library publicly. So while developing a private app nobody can see except you, nothing is @@ -4081,6 +4081,25 @@ You can download the final cabal file: [[file:my-app/my-app.cabal][my-app.cabal] :CUSTOM_ID: command-line-application :END: +One of the simplest while still useful command line utility I can think of +is a simple strong password generator. + +*** Password Generator +:PROPERTIES: +:CUSTOM_ID: password-generator +:END: + +Create a new project named =hspwg= (HaSkell PassWord Generator). +If you do not want to go through the process of creating a new project form +scratch again you can download an archive here: [[file:hspwg.init.tar.gz]]. + +Let us write the most basic application possible. +Edit the file =src/Main.hs= with: + +#+begin_src haskell + +#+end_src + ** Web Application :PROPERTIES: :CUSTOM_ID: web-application