GithubHelp home page GithubHelp logo

Allow users to categorize flags about gflags HOT 16 OPEN

sharper avatar sharper commented on May 11, 2024
Allow users to categorize flags

from gflags.

Comments (16)

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
Hm. I made the macro auto-stringify the argument for consistency with the flag 
name, but I think I'm reconsidering the logic of that... having it take a const 
char* directly might be better.

Original comment by novas0x2a on 25 Aug 2010 at 9:24

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
Thank you for the suggestion.  I do agree this is something that wouldn't be 
too hard to implement.

However, one of the goals with this flags package is to keep the API as narrow 
as practicable.  I'd rather not have two versions of every DEFINE macro.

I'm also not sure how you plan on using this category information.  Is the idea 
that you would just call GetCommandlineFlagInfo() on the flag you cared about, 
and look at the category field manually, and do something with it?  Or were you 
planning to further modify the flags system in the future to do something with 
the category?

If the former, it would be easy enough to just keep this information elsewhere, 
outside the flags system (have a map from flagname to category that you 
maintain).  If the latter, I guess I'd like to see how you planned to use it, 
but it would have to be pretty compelling to justify the API widening.

Original comment by [email protected] on 25 Aug 2010 at 10:52

  • Added labels: Type-Enhancement
  • Removed labels: Type-Defect

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
My ideal use case:
__file1.cc__
DEFINE_TAG_bool(Module1, foo, true, "Foo")

__file2.cc__
DEFINE_TAG_bool(Module2, bar, true, "Bar")

__app.cc__
static const char kTOOL = "app";

DEFINE_TAG_bool(app, "baz", false, "Baz");
DEFINE_TAG_bool(app, "qux", false, "Qux");

int main(int argc, char *argv[]) {
  gflags::SetUsageMessage("[options]\n  Frozzle a Gibble");
  gflags::ParseCommandLineFlags(&argc, &argv, true);
  return 0;
}

__OUTPUT for `app --help`__
app [options]
  Frozzle a Gibble

  Help Options:
    --help
      Show abbreviated help
    --help-all
      Show all options
    --help-module1
      Display help for Module1
    --help-module2
      Display help for Module2

  Application Options:
    --baz
      Baz [default="false"]
    --qux
      Qux [default="false"]

__OUTPUT for `app --help-all`__

app [options]
  Frozzle a Gibble

  Help Options:
    --help
      Show abbreviated help
    --help-all
      Show all options
    --help-module1
      Display help for Module1
    --help-module2
      Display help for Module2

  Module1 Options:
    --foo
      Foo [default="true"]

  Module2 Options:
    --bar
      Bar [default="true"]

  Application Options:
    --baz
      Baz [default="false"]
    --qux
      Qux [default="false"]

__END__

"Application Options" are the ones where flag.category() == 
ProgramInvocationShortName() || flag.isKey(). I have code for some/most of this 
already, but I'm basically reimplementing all of gflags_reporting in my own 
code to do so. It seems like this would be useful to others, but only if I 
actually integrate it into gflags. Is this somewhere you'd like to go?

Original comment by novas0x2a on 26 Aug 2010 at 7:16

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
Good question.  I'll ask the folks who have been working with key-flags here 
(only in python for now, I think), and see what they think.

Original comment by [email protected] on 28 Aug 2010 at 5:19

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
We've started discussions, and I'd like to understand a bit more how you'd use 
this.  What values would you use for the 'category' values?  Would they really 
just be replacements for the filename (so all flags in a given file would have 
the same category name)?

What happens when you use a library that you didn't write, that happens to use 
the same category name for a flag that you want to use in your app?  Or if you 
write a library that uses a category name, how do you make sure its name 
doesn't conflict with other category names?  This question makes more sense if 
categories are meant to be descriptive ("debug" or "required" or "performance" 
or whatever), rather than replacements for filenames.

Original comment by [email protected] on 31 Aug 2010 at 12:54

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
In my particular case, I'll probably be using n categories for m files, where n 
<< m, organized by source module (vwCore, vwFileIO, etc).

> What happens when you use a library that you didn't write, that happens to 
use the same category name for a flag that you want to use in your app?

I just see that as an namespace/API problem that gflags doesn't need to try to 
solve directly. If the library is using general names (read: "putting things 
into the global namespace") then they need to put some thought into their 
published interfaces, to allow downstream users to multiplex on the same flag 
names (so parent and child library can both use FLAGS_debug, for example).

Original comment by novas0x2a on 31 Aug 2010 at 1:31

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
I see -- so for you, categories are a way to kind of 'group' files together, is 
that right?

Original comment by [email protected] on 31 Aug 2010 at 1:44

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
Yep!

One additional thought is that, perhaps one more type of crowd control might be 
useful: marking a flag as boring (the opposite of key).

Flags start at 1.
1) +1 if flag isKey or flag.category() == ProgramInvocationShortName()
2) -1 if flag is boring
3) +1 for each flag in modulename if --help-modulename is passed

When listing flags (with --help):

if flag.interesting < 1: 
    skip printing flag. skip printing --help-category for empty categories.
elif flag.interesting == 1:
    skip printing flag, but print --help-category entry
elif flag.interesting > 1:
    print flag and category

That way the application (which should be the final arbiter anyway, being 
closest to the end user) gets full control over the flags printed. Boringness 
is naturally overridden by specifically requesting information on a flag 
(though there's a hole in this state machine if flags in the same category have 
different interestingness levels)

Original comment by novas0x2a on 31 Aug 2010 at 2:13

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
OK, I've got a design written up for how we might implement flag 
categorization.  But I've been swamped with other things and haven't had a 
chance to start it yet.  But it's on the plate!

If you're interested, here are the design requirements and ideas as I've 
written them down so far.
---
Objective

The --help flag is not very useful for large binaries, which may
include hundreds of flags.  --helpshort has less output, but
still mixes useful and less-useful flags, and can leave out
useful flags defined in libraries.

To improve the utility of --help, I propose adding flag
categories to gflags for c++.  (Python already has a related
functionality with "key flags".)  The intended use is that
file-writers can annotate how important their flags are by
assigning them to an appropriate category, and the --help system
can make use of this information to display the most important
flags in a more user-friendly way.

The category system is flexible enough to serve other uses as
well, though they are not an objective of the design.  For
instance, even if two files are conceptually related, they will
show up in different sections of traditional --help output.  With
categories, the flags in each file could be assigned to the same
category, and hence show up together in --help.

Design Highlights We will add new functionality to gflags.h to
assign a flag to a category.  Categories are arbitrary
strings (though some category names will have special meanings to
the flags system). For v1.0, we will restrict each flag to being
in exactly one category.  Flags that do not use this new
functionality to obtain a user-defined category, will be assigned
their filename as their category.  In this case, we say the flag
is in its "default category."  Registering Categories We will
choose between one of these four possible mechanisms for adding a
category.

   1. Add a function: RegisterCategory(&flag, "category_name").
   This is analogous to to the current RegisterFlagValidator().
   As with RegisterFlagValidator, RegisterCategory will require a
   dummy variable so we can call this function at global
   initialization time.

   2. Add a macro REGISTER_CATEGORY(flag, "category_name").  This
   is similar to above, but has a prettier syntax (it creates the
   dummy variable for you, etc.).

   3. Add a new series of macros: DEFINE_category_bool(flagname,
   default value, category, description),
   DEFINE_category_int(...), etc.  Have folks move to these new
   macros for new code.

   4. Use some preprocessor tricks to allow for "variadic
   macros," where folks can add a category name as an optional
   third argument to DEFINE_bool, etc.  So DEFINE_bool(flagname,
   dflt, helpstring) will continue to work, but
   DEFINE_bool(flagname, dflt, category, helpstring) will also
   work, and add the given flag to the given category.For the
   curious, here's how the trick would work:

      #define CATEGORY_NAME(a, b, c, ...) c
      #define HELP_STRING(a, b, c, ...) b
      #define DEFINE_bool(flagname, dflt, ...) \
         const char* category = CATEGORY_NAME(__VA_ARGS__, __VA_ARGS__, NULL); \
        const char* helpstring = HELP_STRING(__VA_ARGS__, __VA_ARGS__); \
         etc.  


I think (1) and (4) are the best options.  I like (4) because one
day, in an ideal world, we'll move every flag over to the new
scheme, and at that time the macros will have the name we
want (unlike with (3)), without having to have a big flag
day (pun intended) to rename all these macros.  (1) fits well as
it parallels existing functionality with the flag validators.

Arguing against (1), the flag validators aren't used very often, and I think 
one reason why is the awkward syntax for using them.  So I'm leaning towards 
(4).

Changes to --help

--help will change to group flags by category instead of by
filename, as it does today.  For flags not in their default
category (of the filename they're defined in), we will augment
the --help output to say what file the flag is found in.

The order we display the categories will be hard-coded.  Some
names -- to be determined -- will be hard-coded by the flags
library to display first: "required", perhaps "important", etc.
Then all remaining categories mentioned in the same file as
main() (including the default category of the 'main'-file
filename) will be listed, in alphabetical order.  Then all
remaining user-defined categories will be listed, in alphabetical
order.  Finally, all default categories will be listed, in
alphabetical order.

All existing --help variants that work on
filenames (--helpmodules, for instance) would change semantics to
work on categories instead.  We may add --helpcategories as an
alias for --helpmodules.

A property of this design is that until explicit categorization
is done, the output of --help will be exactly the same after the
change as before.

Based on user feedback, we may change --helpshort from its
current behavior, to new behavior of only listing flags in
certain categories: "required", "important", etc.  Once all
important libraries and binaries have had their major flags
categorized, we will consider changing --help to act the same as
--helpshort.  --helpall will be added as a way to get the old
behavior where all flags are listed.

The Category Taxonomy

We will have to decide on some common categories that all apps
can use.  We will want a mix of category names that range from
critical flags (app won't run if these aren't set to a
non-default value) to totally unimportant flags (deprecated flags
that don't do anything), with several levels in between.  We may
also want some flags based on usage: for instance, "network
performance tweaking".

Applications can also develop their own categories, but since
category names are global, they will probably want to include the
application identifier, or some other unique token, in the
category names.

We will restrict category names to being printable 7-bit ascii.
We may restrict further to [-_A-Za-z0-9 ].

This section should expand with the list of category names, as we
develop them.

Overriding Categories

(This idea is taken from python key flags.)  It should be
possible for an application to override the category decisions
that a library makes.  For instance, library X may decide its
flag --compress_frobs is a performance flag (turn it off for
faster performance).  However, if a particular app never uses the
frob feature of library X, or only uses it once for a small
amount of data, --compress_frobs would be a useless flag for that
app.  So it should be possible for an app -- a file containing
main() -- to override library determinations of categories.

For v1.0, we'll implement a simple scheme where an app can change
the category for all flags in a given file or directory.  We'll
add a new function ChangeFlagCategoriesTo("category",
path_substring).  (Could use a better name.)  This will cause the
flags system to iterate through all flags its seen.  For every
flag that's found in a file that has "path_substring" as a
substring, it changes the flag's category
to "category".  "path_substring" will typically be a file or
directory name.

Original comment by [email protected] on 14 Oct 2010 at 1:26

  • Changed state: Accepted

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
Hi,

I'd really love to see this implemented and released as it would be currently 
the major reason for us not to adopt gflags. (We need to have a --help output 
which users who are less into software development can grasp without getting 
distracted by module names and less important flags.) From the design of how to 
associate category names with flags, I would also say that (4) is the best 
solution. However, I would also suggest to implement (1) as an option to 
override the category assignment.

For example, consider a flag that was defined in a library such as glog. Here 
the developer of glog will decide for a category name. If I am as user of this 
library am not happy with this assignment or want to put those flags in a group 
of my own, e.g., together with some of the flags defined in my own modules, 
where I want to use a different category name because the one chosen by the 
glog developer is not meaningful enough for my flags, I would need to assign a 
new category name to those flags.

As (1) and (4) both would do the assignment during static initialization, I 
wouldn't be too certain about the order of code execution. But as we talk about 
categories which are mainly if not only used for the reporting system, it might 
be reasonable to have the RegisterCategory() function not be called at static 
initialization, but simply inside the main() function before the parsing of the 
command-line.

Example usage:

io.h:
DECLARE_string (format);

io.cc:
DEFINE_string (format, "nifti", "File formats", "Select format for output image 
files.");

main.cc:
#include "io.h" // defines flag "format" in category "File formats"

// category names
const char *kIoFlagsCategory = "Input/Output options";

// define some more flags in the main module
DEFINE_string (in, "", kIoFlagsCategory, "Input file path");

int main (int argc, char *argv [])
{
    // change category of flags defined in module foo
    RegisterCategory (format, kIoFlagsCategory);

    // parse command-line
    ParseCommandLineFlags (&argc, &argv, true);

    // ...

    return 0;
}

Original comment by [email protected] on 11 Aug 2011 at 4:38

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
Wow, this bug is coming up on its year anniversary!

We finally got someone within google interested in implementing this, or at 
least a portion of this, so it may be coming.  Of course, there are lots of 
issues still to design, so it may be slow going.

I think the plan is to go with (4), like you liked too.  Keeping (1) as an 
option to override (4) is interesting.  I think you're right it would make more 
sense as a function call you do in main before flags-parsing (just like you can 
override the default flag value in main before flags-parsing).  We probably 
wouldn't do that in v1, just to keep the API as small as we can, but would look 
to see if there's a need to add it afterwards.


Original comment by [email protected] on 11 Aug 2011 at 9:01

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
I started the implementation, and immediately got some pushback from some 
relevant folks (big users inside google), who are not convinced about the 
complexity/benefit trade-off.  So the "slow going" is an accurate prediction. 
:-(  I'm keeping this bug open, so we can hopefully figure a good solution for, 
at least, the original request, if not for flag categories in general.

Original comment by [email protected] on 25 Aug 2011 at 11:56

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
Hi, I just wanted to note that just after my first comment here, I extended the 
shFlags written by Kate to account for categories as well as to clean up the 
--help output and adding --helpshort and --helpxml similar to the C++ and 
Python solutions (some modifications might be a matter of taste, though)... 
sure this is another project and I probably should get in touch with Kate to 
see what she'd like to incorporate into the shFlags project.

Next I was about to touch also google-gflags as well as python-gflags to make 
all three options parsing solutions more similar regarding use as well as look 
and feel (including support for custom categories to give the user a chance to 
arrange the output; yet, I think the three independent projects are kind of 
"out-of-sync"). I would be open for any teamwork as well as contributions to 
the "official" open source Google projects.

Original comment by [email protected] on 28 Aug 2011 at 4:35

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
You're definitely right that c++ flags and python flags have diverged a little 
bit.  In some sense I think that's appropriate, since the languages are 
different (for instance, we aim to provide flags for each 'built-in' type, 
approximately, but the set of 'built-in' types is much larger in python than in 
C++).  That said, there are some differences that aren't motivated by language, 
like the python-only 'key flags'.

I'm not sure how much support there would be for changing the API for any of 
these at this point though, even to gain consistency.  I guess it would depend 
a lot on the specific details.

Original comment by [email protected] on 29 Aug 2011 at 11:08

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
I understand your point. Certainly, the priorities of Google and us (a research 
group at the University of Pennsylvania) differ. Thus, I will be working on our 
own fork of these libraries for our internal use and once it's stable we will 
see how we can best make it part of the public domain.

Original comment by [email protected] on 30 Aug 2011 at 3:46

from gflags.

GoogleCodeExporter avatar GoogleCodeExporter commented on May 11, 2024
Custom flag categorizes which are used in-place of per-module help output are a 
feature which I believe is one of the most important for users of the library. 
Comparing it to other command-line flag parsing libraries, only gflags has this 
quite developer-oriented help output with C++ module file paths and such, 
whereas the help output of a program is generally meant for users of a 
software, not those that develop it.

A solution to this issue should also consider the comments and suggestions of 
issue 32.

Original comment by [email protected] on 20 Mar 2014 at 3:56

  • Added labels: Milestone-v2.2

from gflags.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.