Skip to content

Commit

Permalink
src: make CLI options programatically accesible
Browse files Browse the repository at this point in the history
Provide `internalBinding('options')` with some utilities
around making the options parser and current options values
programatically accessible.

PR-URL: nodejs#22490
Reviewed-By: Michaël Zasso <targos@protonmail.com>
  • Loading branch information
addaleax committed Aug 31, 2018
1 parent 403df7c commit e812be4
Show file tree
Hide file tree
Showing 9 changed files with 476 additions and 101 deletions.
4 changes: 4 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@ struct PackageConfig {
// for the sake of convenience. Strings should be ASCII-only.
#define PER_ISOLATE_STRING_PROPERTIES(V) \
V(address_string, "address") \
V(aliases_string, "aliases") \
V(args_string, "args") \
V(async, "async") \
V(async_ids_stack_string, "async_ids_stack") \
Expand Down Expand Up @@ -156,6 +157,7 @@ struct PackageConfig {
V(entries_string, "entries") \
V(entry_type_string, "entryType") \
V(env_pairs_string, "envPairs") \
V(env_var_settings_string, "envVarSettings") \
V(errno_string, "errno") \
V(error_string, "error") \
V(exit_code_string, "exitCode") \
Expand All @@ -176,6 +178,7 @@ struct PackageConfig {
V(get_shared_array_buffer_id_string, "_getSharedArrayBufferId") \
V(gid_string, "gid") \
V(handle_string, "handle") \
V(help_text_string, "helpText") \
V(homedir_string, "homedir") \
V(host_string, "host") \
V(hostmaster_string, "hostmaster") \
Expand Down Expand Up @@ -233,6 +236,7 @@ struct PackageConfig {
V(onunpipe_string, "onunpipe") \
V(onwrite_string, "onwrite") \
V(openssl_error_stack, "opensslErrorStack") \
V(options_string, "options") \
V(output_string, "output") \
V(order_string, "order") \
V(parse_error_string, "Parse Error") \
Expand Down
26 changes: 17 additions & 9 deletions src/node.cc
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,8 @@ typedef int mode_t;

namespace node {

using options_parser::kAllowedInEnvironment;
using options_parser::kDisallowedInEnvironment;
using v8::Array;
using v8::ArrayBuffer;
using v8::Boolean;
Expand Down Expand Up @@ -183,6 +185,7 @@ bool linux_at_secure = false;
// process-relative uptime base, initialized at start-up
double prog_start_time;

Mutex per_process_opts_mutex;
std::shared_ptr<PerProcessOptions> per_process_opts {
new PerProcessOptions() };

Expand Down Expand Up @@ -2346,8 +2349,6 @@ void LoadEnvironment(Environment* env) {
}

static void PrintHelp() {
// XXX: If you add an option here, please also add it to doc/node.1 and
// doc/api/cli.md
printf("Usage: node [options] [ -e script | script.js | - ] [arguments]\n"
" node inspect script.js [arguments]\n"
"\n"
Expand Down Expand Up @@ -2747,13 +2748,20 @@ void ProcessArgv(std::vector<std::string>* args,
// Parse a few arguments which are specific to Node.
std::vector<std::string> v8_args;
std::string error;
PerProcessOptionsParser::instance.Parse(
args,
exec_args,
&v8_args,
per_process_opts.get(),
is_env ? kAllowedInEnvironment : kDisallowedInEnvironment,
&error);

{
// TODO(addaleax): The mutex here should ideally be held during the
// entire function, but that doesn't play well with the exit() calls below.
Mutex::ScopedLock lock(per_process_opts_mutex);
options_parser::PerProcessOptionsParser::instance.Parse(
args,
exec_args,
&v8_args,
per_process_opts.get(),
is_env ? kAllowedInEnvironment : kDisallowedInEnvironment,
&error);
}

if (!error.empty()) {
fprintf(stderr, "%s: %s\n", args->at(0).c_str(), error.c_str());
exit(9);
Expand Down
2 changes: 2 additions & 0 deletions src/node_internals.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ struct sockaddr;
V(js_stream) \
V(messaging) \
V(module_wrap) \
V(options) \
V(os) \
V(performance) \
V(pipe_wrap) \
Expand Down Expand Up @@ -176,6 +177,7 @@ extern Mutex environ_mutex;
// Tells whether it is safe to call v8::Isolate::GetCurrent().
extern bool v8_initialized;

extern Mutex per_process_opts_mutex;
extern std::shared_ptr<PerProcessOptions> per_process_opts;

extern const char* const environment_flags[];
Expand Down
90 changes: 51 additions & 39 deletions src/node_options-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,73 +21,88 @@ EnvironmentOptions* PerIsolateOptions::get_per_env_options() {
return per_env.get();
}

namespace options_parser {

template <typename Options>
void OptionsParser<Options>::AddOption(const std::string& name,
const std::string& help_text,
bool Options::* field,
OptionEnvvarSettings env_setting) {
options_.emplace(name, OptionInfo {
kBoolean,
std::make_shared<SimpleOptionField<bool>>(field),
env_setting
});
options_.emplace(name,
OptionInfo{kBoolean,
std::make_shared<SimpleOptionField<bool>>(field),
env_setting,
help_text});
}

template <typename Options>
void OptionsParser<Options>::AddOption(const std::string& name,
const std::string& help_text,
int64_t Options::* field,
OptionEnvvarSettings env_setting) {
options_.emplace(name, OptionInfo {
kInteger,
std::make_shared<SimpleOptionField<int64_t>>(field),
env_setting
});
options_.emplace(
name,
OptionInfo{kInteger,
std::make_shared<SimpleOptionField<int64_t>>(field),
env_setting,
help_text});
}

template <typename Options>
void OptionsParser<Options>::AddOption(const std::string& name,
const std::string& help_text,
std::string Options::* field,
OptionEnvvarSettings env_setting) {
options_.emplace(name, OptionInfo {
kString,
std::make_shared<SimpleOptionField<std::string>>(field),
env_setting
});
options_.emplace(
name,
OptionInfo{kString,
std::make_shared<SimpleOptionField<std::string>>(field),
env_setting,
help_text});
}

template <typename Options>
void OptionsParser<Options>::AddOption(
const std::string& name,
const std::string& help_text,
std::vector<std::string> Options::* field,
OptionEnvvarSettings env_setting) {
options_.emplace(name, OptionInfo {
kStringList,
std::make_shared<SimpleOptionField<std::vector<std::string>>>(field),
env_setting
env_setting,
help_text
});
}

template <typename Options>
void OptionsParser<Options>::AddOption(const std::string& name,
const std::string& help_text,
HostPort Options::* field,
OptionEnvvarSettings env_setting) {
options_.emplace(name, OptionInfo {
kHostPort,
std::make_shared<SimpleOptionField<HostPort>>(field),
env_setting
});
options_.emplace(
name,
OptionInfo{kHostPort,
std::make_shared<SimpleOptionField<HostPort>>(field),
env_setting,
help_text});
}

template <typename Options>
void OptionsParser<Options>::AddOption(const std::string& name, NoOp no_op_tag,
void OptionsParser<Options>::AddOption(const std::string& name,
const std::string& help_text,
NoOp no_op_tag,
OptionEnvvarSettings env_setting) {
options_.emplace(name, OptionInfo { kNoOp, nullptr, env_setting });
options_.emplace(name, OptionInfo{kNoOp, nullptr, env_setting, help_text});
}

template <typename Options>
void OptionsParser<Options>::AddOption(const std::string& name,
const std::string& help_text,
V8Option v8_option_tag,
OptionEnvvarSettings env_setting) {
options_.emplace(name, OptionInfo { kV8Option, nullptr, env_setting });
options_.emplace(name,
OptionInfo{kV8Option, nullptr, env_setting, help_text});
}

template <typename Options>
Expand Down Expand Up @@ -161,11 +176,10 @@ template <typename ChildOptions>
auto OptionsParser<Options>::Convert(
typename OptionsParser<ChildOptions>::OptionInfo original,
ChildOptions* (Options::* get_child)()) {
return OptionInfo {
original.type,
Convert(original.field, get_child),
original.env_setting
};
return OptionInfo{original.type,
Convert(original.field, get_child),
original.env_setting,
original.help_text};
}

template <typename Options>
Expand Down Expand Up @@ -385,24 +399,21 @@ void OptionsParser<Options>::Parse(

switch (info.type) {
case kBoolean:
*std::static_pointer_cast<OptionField<bool>>(info.field)
->Lookup(options) = true;
*Lookup<bool>(info.field, options) = true;
break;
case kInteger:
*std::static_pointer_cast<OptionField<int64_t>>(info.field)
->Lookup(options) = std::atoll(value.c_str());
*Lookup<int64_t>(info.field, options) = std::atoll(value.c_str());
break;
case kString:
*std::static_pointer_cast<OptionField<std::string>>(info.field)
->Lookup(options) = value;
*Lookup<std::string>(info.field, options) = value;
break;
case kStringList:
std::static_pointer_cast<OptionField<std::vector<std::string>>>(
info.field)->Lookup(options)->emplace_back(std::move(value));
Lookup<std::vector<std::string>>(info.field, options)
->emplace_back(std::move(value));
break;
case kHostPort:
std::static_pointer_cast<OptionField<HostPort>>(info.field)
->Lookup(options)->Update(SplitHostPort(value, error));
Lookup<HostPort>(info.field, options)
->Update(SplitHostPort(value, error));
break;
case kNoOp:
break;
Expand All @@ -415,6 +426,7 @@ void OptionsParser<Options>::Parse(
}
}

} // namespace options_parser
} // namespace node

#endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS
Expand Down
Loading

0 comments on commit e812be4

Please sign in to comment.