Open parsonsmatt opened 7 years ago
@parsonsmatt I'd like to take a stab at this since I'm not really sure what this project's purpose is and I figure writing the docs would be a good way to find out. :) Perhaps you could describe the purpose in a little more detail and/or provide an example use case.
Looking at the code it seems to me that this app will generate Haskell source code for user-provided "Tasks" in a particular location that are not known to kale at compile time. These tasks would do . . . what? Anything? This seems to be in the spirit of other command line tools like git, for example, that have sub-commands (git branch
, git checkout
, etc.). In this case it would be kale runMySpecialCommand
or kale runThisOtherSpecialCommand
. Am I close?
That's the idea!
There's a decent amount of boilerplate associated with writing a command line parsing utility, and most of it can be discovered and automated away. Stuff like optparse-generic
goes a really long way to making it declarative and gets rid of 99% of the boilerplate, but we can do better :)
The "big idea" is to discover all the modules with a form:
module Lib.FooTask where
data Args = Args { i am command line arguments for the program }
task :: Args -> IO ()
task args = ...
And create a nice command line interface for calling them. What the users end up doing is totally up to them, this library's purpose is to eliminate the boilerplate of:
module Task where
import qualified Lib.FooTask as FooTask
import qualified Lib.BarTask as BarTask
-- ...
data Command = Foo { fooArgs ... } | Bar { barArgs ... } | ...
deriving (Generic, ParseRecord)
main :: IO ()
main = do
cmd <- getRecord "the program"
case cmd of
Foo {..} -> FooTask.task FooTask.Args {..}
Bar {..} -> BarTask.task BarTask.Args {..}
...
Thanks for the speedy response! This is great and is enough to get me started. PR coming your way soon.
I seem to be having a little trouble with Haddock (I've never used it before). I added several docs to functions in Kale.hs
and when I run
$ cabal haddock
I see this output:
Running Haddock for kale-0.1.0.0...
Preprocessing library kale-0.1.0.0...
Warning: The documentation for the following packages are not installed. No
links will be generated to these packages: Only-0.1, ansi-terminal-0.7.1.1,
ansi-wl-pprint-0.6.8.1, colour-2.3.3, optparse-applicative-0.14.0.0,
optparse-generic-1.2.3, semigroups-0.18.3, system-filepath-0.4.13.4,
text-1.2.2.2, transformers-compat-0.5.1.4, void-0.7.2
target ‘command’ is not a module name or a source file
And no documentation is generated. Any ideas?
I'd suggest using stack
for building documentation. stack haddock
works for me on the master branch.
If you want to open a PR, I can take a look at it :)
I have a couple of questions regarding Kale's command line arguments. First, this line takes the first and third command line arguments and ignore the second and fourth. Why is that? What are the second and fourth arguments supposed to be?
On this line it says that Kale doesn't take command line arguments. It seems that this is a misstatement, correct?
Good questions!
The GHC preprocesser step provides some arguments to the executable that's used to process the source file. I don't know what the arguments do exactly -- I copied the structure from hspec-discover
.
The arguments that Kale takes are provided by GHC. It doesn't accept any user arguments.
OK. That leads to a question I've had about the intended workflow of Kale. Is Kale expected to be executed as part the client project's build? How exactly? It sounds like you intend for it to be run by hspec
, correct?
GHC has a textual preprocessor step that allows you to provide your own way to manipulate the source files. It calls the executable and that executable writes a Haskell source file to disk, which GHC then compiles as usual.
So kale
gets called in this step, discovers all the task modules, and then writes a Haskell file that GHC compiles and runs.
@parsonsmatt Thanks for the info. I did not know that GHC had such a textual preprocessing step and some quick googling only seems to lead me to CPP-related stuff but I suspect that is not what's at play here. Can you give more information about this or perhaps a link? In particular, I'm interested to know how you "provide your own way to manipulate the source files." Where do you tell GHC to call Kale's main
function?
This file in the example
is where it is called. I found the pgmF
flag thanks to hspec
and it's discovery feature.
I've created test client application for Kale here but when I run stack build
, I get the following error:
$ stack build
kaletest-0.1.0.0: configure (lib + exe)
colour-2.3.4: download
kaletest-0.1.0.0: build (lib + exe)
Only-0.1: configure
Only-0.1: build
semigroups-0.18.3: configure
semigroups-0.18.3: build
colour-2.3.4: configure
colour-2.3.4: build
semigroups-0.18.3: copy/register
Only-0.1: copy/register
colour-2.3.4: copy/register
Log files have been written to: /home/tim/workspace/haskell/kaletest/.stack-work/logs/
Progress: 4/13
-- While building custom Setup.hs for package kaletest-0.1.0.0 using:
/home/tim/.stack/setup-exe-cache/x86_64-linux/Cabal-simple_mPHDZzAJ_2.0.1.0_ghc-8.2.2 --builddir=.stack-work/dist/x86_64-linux/Cabal-2.0.1.0 build lib:kaletest exe:kaletest-exe --ghc-options " -ddump-hi -ddump-to-file -fdiagnostics-color=always"
Process exited with code: ExitFailure 1
Logs have been written to: /home/tim/workspace/haskell/kaletest/.stack-work/logs/kaletest-0.1.0.0.log
Configuring kaletest-0.1.0.0...
Preprocessing library for kaletest-0.1.0.0..
Building library for kaletest-0.1.0.0..
["src/Lib.hs","src/Lib.hs","/tmp/ghc456_0/ghc_1.hspp"]
[2 of 3] Compiling Lib ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-2.0.1.0/build/Lib.o )
/home/tim/workspace/haskell/kaletest/src/Lib.hs:10:1: error:
Could not find module ‘Kale.Discover’
Use -v to see a list of the files searched for.
It seems that GHC is looking for a Haskell module and not an executable named kale-discover
as I'm expecting. Any idea what I'm doing wrong?
You need kale
in the dependencies of your project.
Matt Parsons
On Mon, Jan 22, 2018 at 10:46 AM, Tim McIver notifications@github.com wrote:
I've created test client application for Kale here https://github.com/tmciver/kaletest but when I run stack build, I get the following error:
$ stack build kaletest-0.1.0.0: configure (lib + exe) colour-2.3.4: download kaletest-0.1.0.0: build (lib + exe) Only-0.1: configure Only-0.1: build semigroups-0.18.3: configure semigroups-0.18.3: build colour-2.3.4: configure colour-2.3.4: build semigroups-0.18.3: copy/register Only-0.1: copy/register colour-2.3.4: copy/register Log files have been written to: /home/tim/workspace/haskell/kaletest/.stack-work/logs/ Progress: 4/13 -- While building custom Setup.hs for package kaletest-0.1.0.0 using: /home/tim/.stack/setup-exe-cache/x86_64-linux/Cabal-simple_mPHDZzAJ_2.0.1.0_ghc-8.2.2 --builddir=.stack-work/dist/x86_64-linux/Cabal-2.0.1.0 build lib:kaletest exe:kaletest-exe --ghc-options " -ddump-hi -ddump-to-file -fdiagnostics-color=always" Process exited with code: ExitFailure 1 Logs have been written to: /home/tim/workspace/haskell/kaletest/.stack-work/logs/kaletest-0.1.0.0.log
Configuring kaletest-0.1.0.0... Preprocessing library for kaletest-0.1.0.0.. Building library for kaletest-0.1.0.0.. ["src/Lib.hs","src/Lib.hs","/tmp/ghc456_0/ghc_1.hspp"] [2 of 3] Compiling Lib ( src/Lib.hs, .stack-work/dist/x86_64-linux/Cabal-2.0.1.0/build/Lib.o ) /home/tim/workspace/haskell/kaletest/src/Lib.hs:10:1: error: Could not find module ‘Kale.Discover’ Use -v to see a list of the files searched for.
It seems that GHC is looking for a Haskell module and not an executable named kale-discover as I'm expecting. Any idea what I'm doing wrong?
— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/parsonsmatt/kale/issues/4#issuecomment-359506338, or mute the thread https://github.com/notifications/unsubscribe-auth/AG-LIBklH1kJ0x8FOxWMDZDHss6vOSXQks5tNMmLgaJpZM4QhaGW .
I see. I added kale
as a dep to package.yaml
and it builds without error now. I was under the impression that the preprocessor specified in {-# OPTIONS_GHC -F -pgmF my-pre-processor #-}
could be any old executable on the path in which case the kaletest
project would not need to depend on kale at all. Can you tell me why I need to set kale
as a dependency?
Also, when stack build
completed I expected to see a new file generated by the preprocessor. Is this not a correct expectation? Is that generated file ephemeral?
I don't understand the pgmF
flag or how exactly it works. I coped code from hspec
:slightly_smiling_face:
Yes, the generated file only exists temporarily while GHC compiles and builds it into the executable.
I'm starting to understand this pgmF
business a bit better. One thing I tried in an effort to understand things better was to specify these GHC options on the command line instead of in a Lib.hs
file like so:
$ stack build --ghc-options="-F -pgmF kale-discover"
but it gives this error:
/home/tim/workspace/haskell/kaletest/src/Lib/Task.hs:8:8: error:
File name does not match module name:
Saw: ‘Task’
Expected: ‘Lib.Task’
This seems to ultimately be due to the way kale
generates the module name for the generated Haskell (in the pathToModule
function) which only takes the final segment of the path as the module name. This seems to work since the current method of preprocessing is done at the same level as the Lib
directory so the generated module is directly under src
. (The above method apparently does the preprocessing in the same directory as the module, which makes sense.)
So I wonder if you have a preference for how users might specify the GHC options. You could leave things as is and just tell the user how to specify the options or change things so that the options could be specified in other ways.
Interesting. The -pgmF
flag when used liket hat is likely going to apply the preprocessor to all of the files in the project, which isn't what we want.
I would definitely prefer folks to write the GHC options in the file that is going to become the module containing the task executable stuff -- in the same way that hspec-discover
only is ever used like
-- test/Spec.hs
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
Good enough! Yes, I had thought about how that command would run the preprocessor on all the files but forgot to mention it. For that reason I agree that it's a good idea to specify the options as you are doing.
This project needs: