Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding global commandline parameters #2599

Closed
wants to merge 2 commits into from

Conversation

pgScorpio
Copy link
Contributor

@pgScorpio pgScorpio commented Apr 16, 2022

Short description of changes

Commandline parsing is now implemented in a separate class
Commandline parameters now accessible anywhere in the code.

CHANGELOG: Refactoring: Commandline parameters are now accessible anywhere in the code via the CCommandline class.

Context: Fixes an issue?

General improvement and preparation for sound-redesign.

Does this change need documentation? What needs to be documented and how?

No documentation changes required.

Status of this Pull Request

What is missing until this pull request can be merged?

Checklist

  • I've verified that this Pull Request follows the general code principles
  • I tested my code and it does what I want
  • My code follows the style guide
  • I waited some time after this Pull Request was opened and all GitHub checks completed without errors.
  • I've filled all the content above

@pgScorpio
Copy link
Contributor Author

Better(?) implementation of the Commandline parameters part of #2538 / #2541

Comment on lines -360 to -376

/* Prototypes for global functions ********************************************/
// command line parsing, TODO do not declare functions globally but in a class
QString UsageArguments ( char** argv );

bool GetFlagArgument ( char** argv, int& i, QString strShortOpt, QString strLongOpt );

bool GetStringArgument ( int argc, char** argv, int& i, QString strShortOpt, QString strLongOpt, QString& strArg );

bool GetNumericArgument ( int argc,
char** argv,
int& i,
QString strShortOpt,
QString strLongOpt,
double rRangeStart,
double rRangeStop,
double& rValue );
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From now on include "cmdline.h" to access commandline parameters via the CCommandline class

Comment on lines +61 to +66
void OnFatalError ( QString errMsg )
{
qCritical() << qUtf8Printable ( errMsg );
exit ( 1 );
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that OnFatalError could be used on many places in main.cpp.

    qCritical() << qUtf8Printable ( ... );
    exit ( 1 );

Is used in many places...

@hoffie hoffie requested a review from pljones April 16, 2022 16:14
Comment on lines -1085 to -1150

bool GetFlagArgument ( char** argv, int& i, QString strShortOpt, QString strLongOpt )
{
if ( ( !strShortOpt.compare ( argv[i] ) ) || ( !strLongOpt.compare ( argv[i] ) ) )
{
return true;
}
else
{
return false;
}
}

bool GetStringArgument ( int argc, char** argv, int& i, QString strShortOpt, QString strLongOpt, QString& strArg )
{
if ( ( !strShortOpt.compare ( argv[i] ) ) || ( !strLongOpt.compare ( argv[i] ) ) )
{
if ( ++i >= argc )
{
qCritical() << qUtf8Printable ( QString ( "%1: '%2' needs a string argument." ).arg ( argv[0] ).arg ( argv[i - 1] ) );
exit ( 1 );
}

strArg = argv[i];

return true;
}
else
{
return false;
}
}

bool GetNumericArgument ( int argc,
char** argv,
int& i,
QString strShortOpt,
QString strLongOpt,
double rRangeStart,
double rRangeStop,
double& rValue )
{
if ( ( !strShortOpt.compare ( argv[i] ) ) || ( !strLongOpt.compare ( argv[i] ) ) )
{
QString errmsg = "%1: '%2' needs a numeric argument from '%3' to '%4'.";
if ( ++i >= argc )
{
qCritical() << qUtf8Printable ( errmsg.arg ( argv[0] ).arg ( argv[i - 1] ).arg ( rRangeStart ).arg ( rRangeStop ) );
exit ( 1 );
}

char* p;
rValue = strtod ( argv[i], &p );
if ( *p || ( rValue < rRangeStart ) || ( rValue > rRangeStop ) )
{
qCritical() << qUtf8Printable ( errmsg.arg ( argv[0] ).arg ( argv[i - 1] ).arg ( rRangeStart ).arg ( rRangeStop ) );
exit ( 1 );
}

return true;
}
else
{
return false;
}
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These functions are now implemented in CCommandline.

Note that in the new implementation the

qCritical() << qUtf8Printable ( ... );
exit ( 1 );

parts are replaced by the CCommandline::onArgumentError function which can, optionally, be passed in the CCommandLine constructor, since we probably don't want the program to exit on parsing wrong (--special?) parameters.

Comment on lines 548 to 549
// clicking on the Mac application bundle, the actual application
// is called with weird command line args -> do not exit on these
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this is true, how about all other places in main using almost the same code ?

qCritical() << qUtf8Printable ( QString (...) );
exit (1);

OnFatalError uses this code now too.

@pgScorpio pgScorpio mentioned this pull request Apr 16, 2022
5 tasks
@ann0see ann0see added the refactoring Non-behavioural changes, Code cleanup label Apr 16, 2022
@pgScorpio
Copy link
Contributor Author

@pljones and others of the Jamulus team

Could we please have some reviews here?

Also my new settings implementation is now waiting on this one.

@pgScorpio pgScorpio mentioned this pull request Apr 28, 2022
4 tasks
@pgScorpio
Copy link
Contributor Author

@ann0see @pljones @hoffie

I also have a CCommandlineOptions class ready that reads all commandline options, and checks client/server validity and ranges,
But also that one depends on this PR and #2598 and #2620.
And I'm also working on a better implementation of Settings handling and that one, again, depends on CCommandlineOptions, and so also on all my other PR's
I'm aware of #2617, but could we please get things going ASAP so I can proceed while I still have the time?

@ann0see
Copy link
Member

ann0see commented May 6, 2022

@pljones could you review these PRs please, (I think we're missing a C++ developer/reviewer at the moment)

pgScorpio added 2 commits May 6, 2022 17:07
Commandline parsing is now implemented in a separate class
Commandline parameters now accessible anywhere in the code.
NOTE: These are needed for the upcomming CCmdlnOptions class that will
read and check all commandline parameters.
@pgScorpio pgScorpio force-pushed the global-commandline branch from 47a6c66 to 3f47e54 Compare May 6, 2022 15:07
@ann0see ann0see changed the base branch from master to main December 26, 2022 19:09
@ann0see
Copy link
Member

ann0see commented Jul 1, 2023

Not sure how to deal with this. I think this is still valid. NOT closing for now.

@pljones
Copy link
Collaborator

pljones commented Jul 2, 2023

My view remains that settings and command line handling need to be unified and that all the handling for client and server properties (i.e. the values configured either by settings or command line) should be handled through calls to the client or server instances.

This approach enables a consistent, UI-independent, development basis going forward. The CLI and GUI - and RPC interface - would be sharing common code for client and server. Where client and server needed common code, that would be separated out. It does mean a lot more work rearchitecting Jamulus, however.

@ann0see
Copy link
Member

ann0see commented Jul 2, 2023

I still think that this PR is a good starting point. We'd include the config file parsing in the provided class.

@pgScorpio
Copy link
Contributor Author

pgScorpio commented Jul 2, 2023

My view remains that settings and command line handling need to be unified and that all the handling for client and server properties (i.e. the values configured either by settings or command line) should be handled through calls to the client or server instances.

This approach enables a consistent, UI-independent, development basis going forward. The CLI and GUI - and RPC interface - would be sharing common code for client and server. Where client and server needed common code, that would be separated out. It does mean a lot more work rearchitecting Jamulus, however.

I must disagree, since the inifile is read before any module is initialized there should be no calls to the modules from reading the inifile but the modules should request the inifile values at their initialization!

@pgScorpio pgScorpio closed this Jul 2, 2023
@pgScorpio pgScorpio reopened this Jul 2, 2023
@pgScorpio
Copy link
Contributor Author

oops accidentally closed...

@pljones
Copy link
Collaborator

pljones commented Jul 3, 2023

I must disagree, since the inifile is read before any module is initialized there should be no calls to the modules from reading the inifile but the modules should request the inifile values at their initialization!

This requires the client and server to know about the inifile, if you're explaining yourself correctly.

I'm suggesting that the client and server know about settings and they "own" their own settings in the sense that any read or update goes through a client or server call. The implementation details (getting those changes to backing store) should, naturally, be independent.

Naming the inifile would come from parsing the command line. Loading the inifile would come next. Instantiating the client or server would come next, passing the settings (the combined inifile and command line values).

Updates to settings would not immediately trigger an update to the inifile, because we don't want interupts when in real time flows, so any disruption should be minimized. We should honour any request to save state from Qt and make sure that's definitely happened on exit. (This remains subject to:

  • if an inifile was supplied, in my view it should always be written - Volker thinks a headless server should never write an inifile, IIRC;
  • any inifile value where a command line option was used to override the value, in headless mode, should not get written - I agree with Volker on that one, again IIRC;
  • any inifile value in GUI, whether overridden by the command line or not, should be written with its current value on close - which could cause a command line option to change the inifile... this is current behaviour and I'm not sure I'm happy with it - but should the behaviour depend on whether an inifile was specified or the default used?)

@pgScorpio
Copy link
Contributor Author

pgScorpio commented Jul 3, 2023

I'm suggesting that the client and server know about settings and they "own" their own settings in the sense that any read or update goes through a client or server call. The implementation details (getting those changes to backing store) should, naturally, be independent.

I suggest we have a commandline class that reads commandline values and an inifile class containing 3 classes: app_settings, server_settings and client_settings.

First the commandline class parses the commandline and store these values. This comnandline class is passed to the inifile class which then reads the inifile values

Then the app is initialised using app_settings and client/server is initialised using their setting classes

app, client and server retrieve their settings by calls to their settings class, which will apply any commandline overrides.

app, client and server can update their settings by calls to the matching settings class during runtime.

At app closing the settings class writes out the new inifile using the stored settings if there where any changes.

@ann0see
Copy link
Member

ann0see commented Jul 4, 2023

I'd rename the commandline class to config as it's not just saving the CLI.

@pgScorpio
Copy link
Contributor Author

pgScorpio commented Jul 4, 2023

I'd rename the commandline class to config as it's not just saving the CLI.

It should just parse the CLI!

And config is way more than the commandline so it would be more logical if "inifile" was named config as it should contain all configurable settings (inifile as well as commandline).

The commandline can also contain commandline only (i.e. server/client, gui/nogui, logging, debugging) parameters and, as so, it should be a separate class accessible anywhere.

@ann0see
Copy link
Member

ann0see commented Jul 4, 2023

Hmm. I mean in the end having one class serving the whole configuration state/providing access to CLI/GUI/Commandline would be beneficial as this allows logical separation.

Do you think that's an issue?

@pgScorpio
Copy link
Contributor Author

Hmm. I mean in the end having one class serving the whole configuration state/providing access to CLI/GUI/Commandline would be beneficial as this allows logical separation.

Do you think that's an issue?

Why putting everything in one class?

I think separate classes are the perfect way to keep things organised, also they can be defined at different, logical locations.
Nevertheless don't confuse classes and class instances. The instances of multiple classes can still be located in one class instance.

Though I still think "commandline" and "inifile" should be different instances since the commandline should be parsed before the other instances are created, but even then "config" could be a class containing commandline and inifile...

P.S. Shouldn't we discuss this in another topic ?

@ann0see
Copy link
Member

ann0see commented Jul 17, 2023

Yes. Probably in #609

@pljones
Copy link
Collaborator

pljones commented Sep 18, 2023

Setting to draft as branch needs conflict resolution.

@pljones pljones marked this pull request as draft September 18, 2023 18:30

bool CCommandline::GetStringArgument ( const QString& strShortOpt, const QString& strLongOpt, QString& strArg )
{
for ( int i = 1; i < argc; i++ )
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Best case would be some kind of hash table/set to have a match in O(1). But that's just thinking out loudly

@ann0see
Copy link
Member

ann0see commented Oct 5, 2024

Closing for now. The ideas are still present.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
refactoring Non-behavioural changes, Code cleanup
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants