~yoctocell/flaskell

4f072033f5ecc332a736013a9574a1fd7e3a5f21 — yoctocell 1 year, 11 months ago 7c2c738
Add cli args
7 files changed, 86 insertions(+), 190 deletions(-)

M app/Main.hs
M default.nix
M flake.nix
M flaskell.cabal
D nix/sources.json
D nix/sources.nix
M src/Flaskell/Cli.hs
M app/Main.hs => app/Main.hs +2 -6
@@ 1,13 1,9 @@
module Main where

import           Flaskell
import           Flaskell.Cli    (cli)
import           Flaskell.Cli
import           Flaskell.Parser
import           Flaskell.Ui


main :: IO ()
main = do
  contents <- cli
  feedCards $ zip (map getHint contents) (map getAnswer contents)

main = cli

M default.nix => default.nix +17 -1
@@ 2,9 2,17 @@
, pkgs ? import sources.nixpkgs
}:
let
  flaskellOverlay = final: prev: rec {
    haskellPackages = prev.haskellPackages.override {
      packageOverrides = hfinal: hprev: {
        flaskell = hprev.callCabal2nix "flaskell" ./. { };
      };
    };
  };

  myEnv = pkgs.haskellPackages.ghcWithPackages (hpkgs: with hpkgs; [
    # ansi-terminal
    # optparse-applicative
    optparse-applicative
    base
    cabal-install
    regex


@@ 14,6 22,14 @@ in
{
  flaskell = pkgs.haskellPackages.callCabal2nix "flaskell" ./. { };

  flaskellOverlay = final: prev: rec {
    haskellPackages = prev.haskellPackages.override {
      packageOverrides = hfinal: hprev: {
        flaskell = hprev.callCabal2nix "flaskell" ./. { };
      };
    };
  };

  flaskellShell = pkgs.mkShell {
    buildInputs = [
      myEnv

M flake.nix => flake.nix +4 -0
@@ 14,8 14,12 @@
      in
      rec
      {
        overlays.flaskell = (import ./. { inherit pkgs; }).flaskellOverlay;
        overlay = overlays.flaskell;

        packages.flaskell = (pkgs.callPackage ./. { }).flaskell;
        defaultPackage = packages.flaskell;

        devShell = (import ./. { inherit pkgs; }).flaskellShell;
      });
}

M flaskell.cabal => flaskell.cabal +3 -4
@@ 23,7 23,7 @@ library
  other-modules:   Paths_flaskell
  hs-source-dirs:  src
  build-depends:   base >=4.7 && <5
                 -- , optparse-applicative >=0.16.0.0
                 , optparse-applicative >= 0.15.0.0
                 , regex >=1.1.0.0
                 -- , ansi-terminal >=0.11
  default-language: Haskell2010


@@ 33,7 33,6 @@ executable flaskell
  hs-source-dirs:      app
  -- other-modules:
  -- other-extensions:
  build-depends:
      base >=4.7 && <5
    , flaskell
  build-depends:  base >=4.7 && <5
                , flaskell
  default-language:    Haskell2010
\ No newline at end of file

D nix/sources.json => nix/sources.json +0 -26
@@ 1,26 0,0 @@
{
    "niv": {
        "branch": "master",
        "description": "Easy dependency management for Nix projects",
        "homepage": "https://github.com/nmattia/niv",
        "owner": "nmattia",
        "repo": "niv",
        "rev": "89ae775e9dfc2571f912156dd2f8627e14d4d507",
        "sha256": "0ssw6byyn79fpyzswi28s5b85x66xh4xsfhmcfl5mkdxxpmyy0ns",
        "type": "tarball",
        "url": "https://github.com/nmattia/niv/archive/89ae775e9dfc2571f912156dd2f8627e14d4d507.tar.gz",
        "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
    },
    "nixpkgs": {
        "branch": "nixpkgs-unstable",
        "description": "Nix Packages collection",
        "homepage": null,
        "owner": "NixOS",
        "repo": "nixpkgs",
        "rev": "f84aae6f67c921aa942d6b506db6509215c05591",
        "sha256": "09zjfflwnzsb9wfk3g3khjqy29nbhdviqbbjpvjvg6nsc9p4yrbp",
        "type": "tarball",
        "url": "https://github.com/NixOS/nixpkgs/archive/f84aae6f67c921aa942d6b506db6509215c05591.tar.gz",
        "url_template": "https://github.com/<owner>/<repo>/archive/<rev>.tar.gz"
    }
}

D nix/sources.nix => nix/sources.nix +0 -138
@@ 1,138 0,0 @@
# This file has been generated by Niv.

let

  #
  # The fetchers. fetch_<type> fetches specs of type <type>.
  #

  fetch_file = pkgs: spec:
    if spec.builtin or true then
      builtins_fetchurl { inherit (spec) url sha256; }
    else
      pkgs.fetchurl { inherit (spec) url sha256; };

  fetch_tarball = pkgs: name: spec:
    let
      ok = str: ! builtins.isNull (builtins.match "[a-zA-Z0-9+-._?=]" str);
      # sanitize the name, though nix will still fail if name starts with period
      name' = stringAsChars (x: if ! ok x then "-" else x) "${name}-src";
    in
      if spec.builtin or true then
        builtins_fetchTarball { name = name'; inherit (spec) url sha256; }
      else
        pkgs.fetchzip { name = name'; inherit (spec) url sha256; };

  fetch_git = spec:
    builtins.fetchGit { url = spec.repo; inherit (spec) rev ref; };

  fetch_local = spec: spec.path;

  fetch_builtin-tarball = name: throw
    ''[${name}] The niv type "builtin-tarball" is deprecated. You should instead use `builtin = true`.
        $ niv modify ${name} -a type=tarball -a builtin=true'';

  fetch_builtin-url = name: throw
    ''[${name}] The niv type "builtin-url" will soon be deprecated. You should instead use `builtin = true`.
        $ niv modify ${name} -a type=file -a builtin=true'';

  #
  # Various helpers
  #

  # The set of packages used when specs are fetched using non-builtins.
  mkPkgs = sources:
    let
      sourcesNixpkgs =
        import (builtins_fetchTarball { inherit (sources.nixpkgs) url sha256; }) {};
      hasNixpkgsPath = builtins.any (x: x.prefix == "nixpkgs") builtins.nixPath;
      hasThisAsNixpkgsPath = <nixpkgs> == ./.;
    in
      if builtins.hasAttr "nixpkgs" sources
      then sourcesNixpkgs
      else if hasNixpkgsPath && ! hasThisAsNixpkgsPath then
        import <nixpkgs> {}
      else
        abort
          ''
            Please specify either <nixpkgs> (through -I or NIX_PATH=nixpkgs=...) or
            add a package called "nixpkgs" to your sources.json.
          '';

  # The actual fetching function.
  fetch = pkgs: name: spec:

    if ! builtins.hasAttr "type" spec then
      abort "ERROR: niv spec ${name} does not have a 'type' attribute"
    else if spec.type == "file" then fetch_file pkgs spec
    else if spec.type == "tarball" then fetch_tarball pkgs name spec
    else if spec.type == "git" then fetch_git spec
    else if spec.type == "local" then fetch_local spec
    else if spec.type == "builtin-tarball" then fetch_builtin-tarball name
    else if spec.type == "builtin-url" then fetch_builtin-url name
    else
      abort "ERROR: niv spec ${name} has unknown type ${builtins.toJSON spec.type}";

  # Ports of functions for older nix versions

  # a Nix version of mapAttrs if the built-in doesn't exist
  mapAttrs = builtins.mapAttrs or (
    f: set: with builtins;
    listToAttrs (map (attr: { name = attr; value = f attr set.${attr}; }) (attrNames set))
  );

  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/lists.nix#L295
  range = first: last: if first > last then [] else builtins.genList (n: first + n) (last - first + 1);

  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L257
  stringToCharacters = s: map (p: builtins.substring p 1 s) (range 0 (builtins.stringLength s - 1));

  # https://github.com/NixOS/nixpkgs/blob/0258808f5744ca980b9a1f24fe0b1e6f0fecee9c/lib/strings.nix#L269
  stringAsChars = f: s: concatStrings (map f (stringToCharacters s));
  concatStrings = builtins.concatStringsSep "";

  # fetchTarball version that is compatible between all the versions of Nix
  builtins_fetchTarball = { url, name, sha256 }@attrs:
    let
      inherit (builtins) lessThan nixVersion fetchTarball;
    in
      if lessThan nixVersion "1.12" then
        fetchTarball { inherit name url; }
      else
        fetchTarball attrs;

  # fetchurl version that is compatible between all the versions of Nix
  builtins_fetchurl = { url, sha256 }@attrs:
    let
      inherit (builtins) lessThan nixVersion fetchurl;
    in
      if lessThan nixVersion "1.12" then
        fetchurl { inherit url; }
      else
        fetchurl attrs;

  # Create the final "sources" from the config
  mkSources = config:
    mapAttrs (
      name: spec:
        if builtins.hasAttr "outPath" spec
        then abort
          "The values in sources.json should not have an 'outPath' attribute"
        else
          spec // { outPath = fetch config.pkgs name spec; }
    ) config.sources;

  # The "config" used by the fetchers
  mkConfig =
    { sourcesFile ? ./sources.json
    , sources ? builtins.fromJSON (builtins.readFile sourcesFile)
    , pkgs ? mkPkgs sources
    }: rec {
      # The sources, i.e. the attribute set of spec name to spec
      inherit sources;

      # The "pkgs" (evaluated nixpkgs) to use for e.g. non-builtin fetchers
      inherit pkgs;
    };
in
mkSources (mkConfig {}) // { __functor = _: settings: mkSources (mkConfig settings); }

M src/Flaskell/Cli.hs => src/Flaskell/Cli.hs +60 -15
@@ 1,4 1,5 @@
module Flaskell.Cli
  -- ( getContent
  ( cli
  )
where


@@ 6,24 7,68 @@ where
import           Flaskell.Parser
import           Flaskell.Ui

-- import           Options.Applicative
import Options.Applicative
import System.Exit
import           System.Environment (getArgs, getProgName)

usage :: IO ()
usage = do
  progName <- getProgName
  putStrLn $ progName ++ " usage: "

version :: IO ()
version = putStrLn "0.1.0"
data Input = FileInput FilePath | StdInput

parseCliArgs :: [String] -> IO ()
parseCliArgs (arg : args) = case arg of
  "-v" -> version
  "-h" -> usage
  _    -> return ()
data Options = Options
  { version :: Bool
  , input :: Input }
  
versionNumber :: String
versionNumber = "0.1.0.0"

fileInput :: Parser Input
fileInput = FileInput <$> strOption
  (  long "file"
  <> short 'f'
  <> metavar "FILE"
  <> help "Input file" )

-- TODO cli arguments
cli :: IO [String]
cli = getArgs >>= fmap lines . readFile . head
stdInput :: Parser Input
stdInput = flag' StdInput
  (  long "stdin"
  <> help "Read from stdin" )
  
-- input :: Parser Input
-- input = fileInput <|> stdInput

cliArgs :: Parser Options
cliArgs = Options
          <$> switch
          (long "version"
          <> short 'v'
          <> help "Print the version number")
          <*> (fileInput <|> stdInput)

-- cliArgs :: ParserInfo Options
-- cliArgs = info (args <**> helper)
--   ( fullDesc
--   <> progDesc "Generate flashcards from FILE"
--   <> header "Flaskell - CLI flashcard program" )
--   where args = Options
--           <$> switch
--               ( long "version"
--              <> short 'v'
--              <> help "Print the version number" )

parseCliArgs :: Options -> IO ()
parseCliArgs (Options True _) = putStrLn versionNumber
parseCliArgs (Options False (FileInput file)) = putStrLn file
parseCliArgs (Options False (StdInput)) = putStrLn "stdin"

-- -- TODO cli arguments
-- getContent :: IO [String]
-- getContent = getArgs >>= fmap lines . readFile . head

cli :: IO ()
cli = do
  parseCliArgs =<< execParser args
  where
    args = info (cliArgs <**> helper)
      ( fullDesc
        <> progDesc "Generate flashcards from FILE"
        <> header "Flaskell - CLI flashcard program" )