As part of the webmod rework, I've been re-evalating the fand pod. Originally I envisioned this API as a daemon framework, but after several years it is looking like things are so simple, there really isn't a need for a "framework" per se.
There are two classes in this pod:
fand::BootScript - nice base class for installing/starting up list of services
Both of these classes are useful utils, but I am not sure it makes sense to have a fand pod in its own right. I propose the following:
rename fand pod to util as catch-all for utility classes like these
add AbstractMain class for common handling of command line parameters, usage, etc
rework BootScript to be DaemonMain which subclasses from AbstractMain
lbertrandMon 30 Nov 2009
I have no issue with the proposed changes...
But, I don't really like a util package with a lot of everything in it, in general... Why not having FileLogger part of the log pod? For the BootScript, I don't know but I am sure there is a better pod for it than a generic util.
brianMon 30 Nov 2009
But, I don't really like a util package with a lot of everything in it, in general
I don't love the idea of a generic util pod either, but I think it makes sense to have a nice catch all for stuff like this versus a bunch of little pods that might only have one or two classes (like fand).
There are lots of little things I keep re-inventing b/c I haven't had a good place to stick stuff, and util might be a nice misc pod.
The restriction will be that util has no dependencies other than sys. Then you can depend on util for your own pods without pulling in anything else.
lbertrandMon 30 Nov 2009
As long as util does not grow too much I think it is ok...
But first thing should be: can this class be in another pod, if not, this is really a util class, stick it in the util pod.
brianTue 1 Dec 2009
Promoted to ticket #841 and assigned to brian
brianTue 1 Dec 2009
This is what I am thinking for AbstractMain - make it easy to define your options and arguments as fields annotated with facets:
class MyMain : AbstractMain
{
@option="HTTP port for server"
Int port := 80
@option="Debug mode"
Bool debug := false
@requiredArgument="File to run"
File? file
override Int run() { ... }
}
The base class would handle parsing options, usage, etc by introspecting the facets:
C:> fan MyMain -?
usage MyMain [options] <file>
Arguments
file File to run
Options
-port <Int> HTTP port for server (default 80)
-debug Debug mode
C:> fan MyMain -debug -port 8080 somefile.txt
Does everybody like that design?
KevinKelleyTue 1 Dec 2009
nice.
andyTue 1 Dec 2009
I like that - can you use osPath for specifying files?
ivanTue 1 Dec 2009
I like it!
Few questions:
will optional arguments support list types as well?
can there be more than one required arg? If so, how parameter order is determined?
brianTue 1 Dec 2009
Options will not support lists, but can support any type with a fromStr factory
Arguments are ordered by the field declaration order
The last argument can be a list
File (or File[]) will take a Uri or an osPath
Decided to just stick service stuff in AbstractMain versus having a separate DaemonMain
qualidafialTue 1 Dec 2009
Can we have aliases for options? e.g. so that -o and -output are synonymous.
brianTue 1 Dec 2009
Can we have aliases for options? e.g. so that -o and -output are synonymous.
Seems like that would pretty easy to add with a Str[] optAliases facet, and probably makes sense since I always alias -help, -h, and -?.
qualidafialTue 1 Dec 2009
Seems like that would pretty easy to add with a Str[] optAliases facet, and probably makes sense since I always alias -help, -h, and -?.
Assuming I understand you this would make the code look like:
@option="Display help message"
@optAliases=["h","?"]
Bool help := false
+1, I like it.
However I'm curious about the reasoning for deciding to leave the service stuff in AbstractMain rather than separating it out into DaemonMain. That seemed like a good separation of concerns to me.
brianTue 1 Dec 2009
However I'm curious about the reasoning for deciding to leave the service stuff in AbstractMain rather than separating it out into DaemonMain.
I think the only thing DaemonMain would add is a method to declare the services, then put the main thread to sleep. Because non-daemons might want to spin up services too, I think it the service spin up really does belong in AbstractMain.
qualidafialTue 1 Dec 2009
What about putting the service spin-up in ServiceMain : AbstractMain, and the daemon stuff in a DaemonMain : ServiceMain?
brianTue 1 Dec 2009
Basically everything now just boils down one extra method called runServices on AbstractMain that you can call from your run method. So here is what the new web server hello world looks like with port opt:
class WebHello : AbstractMain
{
@opt="http port"
Int port := 8080
override Void run()
{
wisp := WispService
{
it.port = this.port
it.root = HelloMod()
}
runServices([wisp])
}
}
andyTue 1 Dec 2009
What about putting the service spin-up in ServiceMain : AbstractMain, and the daemon stuff in a DaemonMain : ServiceMain
Agree with Brian, its such a small tweak to a utility class, I'd keep it simple and just stick everything on AbstractMain.
brianTue 1 Dec 2009
Ticket resolved in 1.0.48
I've pushed these changes to hg.
The AbstractMain class is pretty slick for easily setting up your options and arguments. Also take a look at new example script "examples/util/main.fan" and the updated "example/web" scripts (which now all take a port option).
If you take AbstractMain for a test drive, let me know how it works for you.
brian Mon 30 Nov 2009
As part of the webmod rework, I've been re-evalating the fand pod. Originally I envisioned this API as a daemon framework, but after several years it is looking like things are so simple, there really isn't a need for a "framework" per se.
There are two classes in this pod:
Both of these classes are useful utils, but I am not sure it makes sense to have a fand pod in its own right. I propose the following:
lbertrand Mon 30 Nov 2009
I have no issue with the proposed changes...
But, I don't really like a util package with a lot of everything in it, in general... Why not having FileLogger part of the log pod? For the BootScript, I don't know but I am sure there is a better pod for it than a generic util.
brian Mon 30 Nov 2009
I don't love the idea of a generic util pod either, but I think it makes sense to have a nice catch all for stuff like this versus a bunch of little pods that might only have one or two classes (like fand).
There are lots of little things I keep re-inventing b/c I haven't had a good place to stick stuff, and util might be a nice misc pod.
The restriction will be that util has no dependencies other than sys. Then you can depend on util for your own pods without pulling in anything else.
lbertrand Mon 30 Nov 2009
As long as util does not grow too much I think it is ok...
But first thing should be: can this class be in another pod, if not, this is really a util class, stick it in the util pod.
brian Tue 1 Dec 2009
Promoted to ticket #841 and assigned to brian
brian Tue 1 Dec 2009
This is what I am thinking for AbstractMain - make it easy to define your options and arguments as fields annotated with facets:
The base class would handle parsing options, usage, etc by introspecting the facets:
Does everybody like that design?
KevinKelley Tue 1 Dec 2009
nice.
andy Tue 1 Dec 2009
I like that - can you use osPath for specifying files?
ivan Tue 1 Dec 2009
I like it!
Few questions:
brian Tue 1 Dec 2009
qualidafial Tue 1 Dec 2009
Can we have aliases for options? e.g. so that
-o
and-output
are synonymous.brian Tue 1 Dec 2009
Seems like that would pretty easy to add with a Str[] optAliases facet, and probably makes sense since I always alias -help, -h, and -?.
qualidafial Tue 1 Dec 2009
Assuming I understand you this would make the code look like:
+1, I like it.
However I'm curious about the reasoning for deciding to leave the service stuff in AbstractMain rather than separating it out into DaemonMain. That seemed like a good separation of concerns to me.
brian Tue 1 Dec 2009
I think the only thing DaemonMain would add is a method to declare the services, then put the main thread to sleep. Because non-daemons might want to spin up services too, I think it the service spin up really does belong in AbstractMain.
qualidafial Tue 1 Dec 2009
What about putting the service spin-up in ServiceMain : AbstractMain, and the daemon stuff in a DaemonMain : ServiceMain?
brian Tue 1 Dec 2009
Basically everything now just boils down one extra method called
runServices
on AbstractMain that you can call from yourrun
method. So here is what the new web server hello world looks like with port opt:andy Tue 1 Dec 2009
Agree with Brian, its such a small tweak to a utility class, I'd keep it simple and just stick everything on AbstractMain.
brian Tue 1 Dec 2009
Ticket resolved in 1.0.48
I've pushed these changes to hg.
The
AbstractMain
class is pretty slick for easily setting up your options and arguments. Also take a look at new example script "examples/util/main.fan" and the updated "example/web" scripts (which now all take a port option).If you take
AbstractMain
for a test drive, let me know how it works for you.