mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
Added classes ArgumentList and ConsoleApplcation which are helpers for writing console applications that parse and resolve command-line arguments
This commit is contained in:
parent
15e09fdc5e
commit
064656e2fb
7 changed files with 666 additions and 178 deletions
|
|
@ -91,7 +91,7 @@ void ProjucerApplication::initialise (const String& commandLine)
|
|||
|
||||
if (isRunningCommandLine)
|
||||
{
|
||||
const int appReturnCode = performCommandLine (commandLine);
|
||||
auto appReturnCode = performCommandLine (ArgumentList ("Projucer", commandLine));
|
||||
|
||||
if (appReturnCode != commandLineNotPerformed)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,13 +38,6 @@ const char* getPreferredLinefeed() { return preferredLinefeed; }
|
|||
//==============================================================================
|
||||
namespace
|
||||
{
|
||||
struct CommandLineError
|
||||
{
|
||||
CommandLineError (const String& s) : message (s) {}
|
||||
|
||||
String message;
|
||||
};
|
||||
|
||||
static void hideDockIcon()
|
||||
{
|
||||
#if JUCE_MAC
|
||||
|
|
@ -52,58 +45,6 @@ namespace
|
|||
#endif
|
||||
}
|
||||
|
||||
static bool matchArgument (const String& arg, const String& possible)
|
||||
{
|
||||
return arg == possible
|
||||
|| arg == "-" + possible
|
||||
|| arg == "--" + possible;
|
||||
}
|
||||
|
||||
static void checkArgumentCount (const StringArray& args, int minNumArgs)
|
||||
{
|
||||
if (args.size() < minNumArgs)
|
||||
throw CommandLineError ("Not enough arguments!");
|
||||
}
|
||||
|
||||
static bool findArgument (StringArray& args, const String& target)
|
||||
{
|
||||
for (int i = 0; i < args.size(); ++i)
|
||||
{
|
||||
if (args[i].trim() == target)
|
||||
{
|
||||
args.remove (i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static File getFile (const String& filename)
|
||||
{
|
||||
return File::getCurrentWorkingDirectory().getChildFile (filename.unquoted());
|
||||
}
|
||||
|
||||
static File getDirectoryCheckingForExistence (const String& filename)
|
||||
{
|
||||
File f = getFile (filename);
|
||||
|
||||
if (! f.isDirectory())
|
||||
throw CommandLineError ("Could not find folder: " + f.getFullPathName());
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static File getFileCheckingForExistence (const String& filename)
|
||||
{
|
||||
File f = getFile (filename);
|
||||
|
||||
if (! f.exists())
|
||||
throw CommandLineError ("Could not find file: " + f.getFullPathName());
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
static Array<File> findAllSourceFiles (const File& folder)
|
||||
{
|
||||
Array<File> files;
|
||||
|
|
@ -122,30 +63,30 @@ namespace
|
|||
TemporaryFile temp (file);
|
||||
|
||||
if (! temp.getFile().replaceWithText (newText, false, false, nullptr))
|
||||
throw CommandLineError ("!!! ERROR Couldn't write to temp file!");
|
||||
ConsoleApplication::fail ("!!! ERROR Couldn't write to temp file!");
|
||||
|
||||
if (! temp.overwriteTargetFileWithTemporary())
|
||||
throw CommandLineError ("!!! ERROR Couldn't write to file!");
|
||||
ConsoleApplication::fail ("!!! ERROR Couldn't write to file!");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct LoadedProject
|
||||
{
|
||||
LoadedProject (const String& fileToLoad)
|
||||
LoadedProject (const ArgumentList::Argument& fileToLoad)
|
||||
{
|
||||
hideDockIcon();
|
||||
|
||||
auto projectFile = getFileCheckingForExistence (fileToLoad);
|
||||
auto projectFile = fileToLoad.resolveAsExistingFile();
|
||||
|
||||
if (! projectFile.hasFileExtension (Project::projectFileExtension))
|
||||
throw CommandLineError (projectFile.getFullPathName() + " isn't a valid jucer project file!");
|
||||
ConsoleApplication::fail (projectFile.getFullPathName() + " isn't a valid jucer project file!");
|
||||
|
||||
project.reset (new Project (projectFile));
|
||||
|
||||
if (! project->loadFrom (projectFile, true))
|
||||
{
|
||||
project.reset();
|
||||
throw CommandLineError ("Failed to load the project file: " + projectFile.getFullPathName());
|
||||
ConsoleApplication::fail ("Failed to load the project file: " + projectFile.getFullPathName());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -159,7 +100,7 @@ namespace
|
|||
project.reset();
|
||||
|
||||
if (error.failed())
|
||||
throw CommandLineError ("Error when saving: " + error.getErrorMessage());
|
||||
ConsoleApplication::fail ("Error when saving: " + error.getErrorMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,9 +111,9 @@ namespace
|
|||
/* Running a command-line of the form "projucer --resave foobar.jucer" will try to load
|
||||
that project and re-export all of its targets.
|
||||
*/
|
||||
static void resaveProject (const StringArray& args, bool justSaveResources)
|
||||
static void resaveProject (const ArgumentList& args, bool justSaveResources)
|
||||
{
|
||||
checkArgumentCount (args, 2);
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
std::cout << (justSaveResources ? "Re-saving project resources: "
|
||||
|
|
@ -183,21 +124,21 @@ namespace
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
static void getVersion (const StringArray& args)
|
||||
static void getVersion (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 2);
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
std::cout << proj.project->getVersionString() << std::endl;
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void setVersion (const StringArray& args)
|
||||
static void setVersion (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 3);
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[2]);
|
||||
|
||||
String version (args[1].trim());
|
||||
String version (args[1].text.trim());
|
||||
|
||||
std::cout << "Setting project version: " << version << std::endl;
|
||||
|
||||
|
|
@ -206,9 +147,9 @@ namespace
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
static void bumpVersion (const StringArray& args)
|
||||
static void bumpVersion (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 2);
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
String version = proj.project->getVersionString();
|
||||
|
|
@ -222,15 +163,15 @@ namespace
|
|||
proj.save (false);
|
||||
}
|
||||
|
||||
static void gitTag (const StringArray& args)
|
||||
static void gitTag (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 2);
|
||||
args.checkMinNumArguments (2);
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
String version (proj.project->getVersionString());
|
||||
|
||||
if (version.trim().isEmpty())
|
||||
throw CommandLineError ("Cannot read version number from project!");
|
||||
ConsoleApplication::fail ("Cannot read version number from project!");
|
||||
|
||||
StringArray command;
|
||||
command.add ("git");
|
||||
|
|
@ -245,19 +186,19 @@ namespace
|
|||
ChildProcess c;
|
||||
|
||||
if (! c.start (command, 0))
|
||||
throw CommandLineError ("Cannot run git!");
|
||||
ConsoleApplication::fail ("Cannot run git!");
|
||||
|
||||
c.waitForProcessToFinish (10000);
|
||||
|
||||
if (c.getExitCode() != 0)
|
||||
throw CommandLineError ("git command failed!");
|
||||
ConsoleApplication::fail ("git command failed!");
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
static void showStatus (const StringArray& args)
|
||||
static void showStatus (const ArgumentList& args)
|
||||
{
|
||||
hideDockIcon();
|
||||
checkArgumentCount (args, 2);
|
||||
args.checkMinNumArguments (2);
|
||||
|
||||
LoadedProject proj (args[1]);
|
||||
|
||||
|
|
@ -286,13 +227,13 @@ namespace
|
|||
{
|
||||
jassert (targetFolder.isDirectory());
|
||||
|
||||
const File moduleFolderParent (moduleFolder.getParentDirectory());
|
||||
auto moduleFolderParent = moduleFolder.getParentDirectory();
|
||||
LibraryModule module (moduleFolder);
|
||||
|
||||
if (! module.isValid())
|
||||
throw CommandLineError (moduleFolder.getFullPathName() + " is not a valid module folder!");
|
||||
ConsoleApplication::fail (moduleFolder.getFullPathName() + " is not a valid module folder!");
|
||||
|
||||
const File targetFile (targetFolder.getChildFile (getModulePackageName (module)));
|
||||
auto targetFile = targetFolder.getChildFile (getModulePackageName (module));
|
||||
|
||||
ZipFile::Builder zip;
|
||||
|
||||
|
|
@ -314,22 +255,22 @@ namespace
|
|||
ok = ok && temp.overwriteTargetFileWithTemporary();
|
||||
|
||||
if (! ok)
|
||||
throw CommandLineError ("Failed to write to the target file: " + targetFile.getFullPathName());
|
||||
ConsoleApplication::fail ("Failed to write to the target file: " + targetFile.getFullPathName());
|
||||
}
|
||||
|
||||
static void buildModules (const StringArray& args, const bool buildAllWithIndex)
|
||||
static void buildModules (const ArgumentList& args, const bool buildAllWithIndex)
|
||||
{
|
||||
hideDockIcon();
|
||||
checkArgumentCount (args, 3);
|
||||
args.checkMinNumArguments (3);
|
||||
|
||||
const File targetFolder (getFile (args[1]));
|
||||
auto targetFolder = args[1].resolveAsFile();
|
||||
|
||||
if (! targetFolder.isDirectory())
|
||||
throw CommandLineError ("The first argument must be the directory to put the result.");
|
||||
ConsoleApplication::fail ("The first argument must be the directory to put the result.");
|
||||
|
||||
if (buildAllWithIndex)
|
||||
{
|
||||
const File folderToSearch (getFile (args[2]));
|
||||
auto folderToSearch = args[2].resolveAsFile();
|
||||
DirectoryIterator i (folderToSearch, false, "*", File::findDirectories);
|
||||
var infoList;
|
||||
|
||||
|
|
@ -348,14 +289,14 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
const File indexFile (targetFolder.getChildFile ("modulelist"));
|
||||
auto indexFile = targetFolder.getChildFile ("modulelist");
|
||||
std::cout << "Writing: " << indexFile.getFullPathName() << std::endl;
|
||||
indexFile.replaceWithText (JSON::toString (infoList), false, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 2; i < args.size(); ++i)
|
||||
zipModule (targetFolder, getFile (args[i]));
|
||||
zipModule (targetFolder, args[i].resolveAsFile());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -429,13 +370,13 @@ namespace
|
|||
: "Cleaning file: ");
|
||||
}
|
||||
|
||||
static void scanFilesForCleanup (const StringArray& args, CleanupOptions options)
|
||||
static void scanFilesForCleanup (const ArgumentList& args, CleanupOptions options)
|
||||
{
|
||||
checkArgumentCount (args, 2);
|
||||
args.checkMinNumArguments (2);
|
||||
|
||||
for (auto it = args.begin() + 1; it < args.end(); ++it)
|
||||
for (auto it = args.arguments.begin() + 1; it < args.arguments.end(); ++it)
|
||||
{
|
||||
auto target = getFileCheckingForExistence (*it);
|
||||
auto target = it->resolveAsExistingFile();
|
||||
|
||||
Array<File> files;
|
||||
|
||||
|
|
@ -449,13 +390,13 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
static void cleanWhitespace (const StringArray& args, bool replaceTabs)
|
||||
static void cleanWhitespace (const ArgumentList& args, bool replaceTabs)
|
||||
{
|
||||
CleanupOptions options = { replaceTabs, false };
|
||||
scanFilesForCleanup (args, options);
|
||||
}
|
||||
|
||||
static void tidyDividerComments (const StringArray& args)
|
||||
static void tidyDividerComments (const ArgumentList& args)
|
||||
{
|
||||
CleanupOptions options = { false, true };
|
||||
scanFilesForCleanup (args, options);
|
||||
|
|
@ -525,10 +466,10 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
static void fixRelativeIncludePaths (const StringArray& args)
|
||||
static void fixRelativeIncludePaths (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 2);
|
||||
auto target = getDirectoryCheckingForExistence (args[1]);
|
||||
args.checkMinNumArguments (2);
|
||||
auto target = args[1].resolveAsExistingFolder();
|
||||
auto files = findAllSourceFiles (target);
|
||||
|
||||
for (int i = 0; i < files.size(); ++i)
|
||||
|
|
@ -549,10 +490,10 @@ namespace
|
|||
+ " + " + getStringConcatenationExpression (rng, start + breakPos, length - breakPos) + ")";
|
||||
}
|
||||
|
||||
static void generateObfuscatedStringCode (const StringArray& args)
|
||||
static void generateObfuscatedStringCode (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 2);
|
||||
const String originalText (args[1].unquoted());
|
||||
args.checkMinNumArguments (2);
|
||||
auto originalText = args[1].text.unquoted();
|
||||
|
||||
struct Section
|
||||
{
|
||||
|
|
@ -608,29 +549,29 @@ namespace
|
|||
std::cout << out.toString() << std::endl;
|
||||
}
|
||||
|
||||
static void scanFoldersForTranslationFiles (const StringArray& args)
|
||||
static void scanFoldersForTranslationFiles (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 2);
|
||||
args.checkMinNumArguments (2);
|
||||
|
||||
StringArray translations;
|
||||
|
||||
for (auto it = args.begin() + 1; it != args.end(); ++it)
|
||||
for (auto it = args.arguments.begin() + 1; it != args.arguments.end(); ++it)
|
||||
{
|
||||
const File directoryToSearch (getDirectoryCheckingForExistence (*it));
|
||||
auto directoryToSearch = it->resolveAsExistingFolder();
|
||||
TranslationHelpers::scanFolderForTranslations (translations, directoryToSearch);
|
||||
}
|
||||
|
||||
std::cout << TranslationHelpers::mungeStrings (translations) << std::endl;
|
||||
}
|
||||
|
||||
static void createFinishedTranslationFile (const StringArray& args)
|
||||
static void createFinishedTranslationFile (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 3);
|
||||
args.checkMinNumArguments (3);
|
||||
|
||||
auto preTranslated = getFileCheckingForExistence (args[1]).loadFileAsString();
|
||||
auto postTranslated = getFileCheckingForExistence (args[2]).loadFileAsString();
|
||||
auto preTranslated = args[1].resolveAsExistingFile().loadFileAsString();
|
||||
auto postTranslated = args[2].resolveAsExistingFile().loadFileAsString();
|
||||
|
||||
auto localisedContent = (args.size() > 3 ? getFileCheckingForExistence (args[3]).loadFileAsString() : String());
|
||||
auto localisedContent = (args.size() > 3 ? args[3].resolveAsExistingFile().loadFileAsString() : String());
|
||||
auto localised = LocalisedStrings (localisedContent, false);
|
||||
|
||||
using TH = TranslationHelpers;
|
||||
|
|
@ -640,11 +581,11 @@ namespace
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
static void encodeBinary (const StringArray& args)
|
||||
static void encodeBinary (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 3);
|
||||
const File source (getFileCheckingForExistence (args[1]));
|
||||
const File target (getFile (args[2]));
|
||||
args.checkMinNumArguments (3);
|
||||
auto source = args[1].resolveAsExistingFile();
|
||||
auto target = args[2].resolveAsExistingFile();
|
||||
|
||||
MemoryOutputStream literal;
|
||||
size_t dataSize = 0;
|
||||
|
|
@ -693,7 +634,7 @@ namespace
|
|||
}
|
||||
else
|
||||
{
|
||||
throw CommandLineError ("You need to specify a .h or .cpp file as the target");
|
||||
ConsoleApplication::fail ("You need to specify a .h or .cpp file as the target");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -707,7 +648,7 @@ namespace
|
|||
else if (os == "linux") targetOS = TargetOS::linux;
|
||||
|
||||
if (targetOS == TargetOS::unknown)
|
||||
throw CommandLineError ("You need to specify a valid OS! Use osx, windows or linux");
|
||||
ConsoleApplication::fail ("You need to specify a valid OS! Use osx, windows or linux");
|
||||
|
||||
return targetOS == TargetOS::getThisOS();
|
||||
}
|
||||
|
|
@ -718,12 +659,12 @@ namespace
|
|||
|| id == "androidSDKPath" || id == "androidNDKPath" || id == "defaultJuceModulePath" || id == "defaultUserModulePath";
|
||||
}
|
||||
|
||||
static void setGlobalPath (const StringArray& args)
|
||||
static void setGlobalPath (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 3);
|
||||
args.checkMinNumArguments (3);
|
||||
|
||||
if (! isValidPathIdentifier (args[2], args[1]))
|
||||
throw CommandLineError ("Identifier " + args[2] + " is not valid for the OS " + args[1]);
|
||||
if (! isValidPathIdentifier (args[2].text, args[1].text))
|
||||
ConsoleApplication::fail ("Identifier " + args[2].text + " is not valid for the OS " + args[1].text);
|
||||
|
||||
auto userAppData = File::getSpecialLocation (File::userApplicationDataDirectory);
|
||||
|
||||
|
|
@ -736,10 +677,11 @@ namespace
|
|||
auto settingsTree = ValueTree::fromXml (*xml);
|
||||
|
||||
if (! settingsTree.isValid())
|
||||
throw CommandLineError ("Settings file not valid!");
|
||||
ConsoleApplication::fail ("Settings file not valid!");
|
||||
|
||||
ValueTree childToSet;
|
||||
if (isThisOS (args[1]))
|
||||
|
||||
if (isThisOS (args[1].text))
|
||||
{
|
||||
childToSet = settingsTree.getChildWithProperty (Ids::name, "PROJECT_DEFAULT_SETTINGS")
|
||||
.getChildWithName ("PROJECT_DEFAULT_SETTINGS");
|
||||
|
|
@ -748,26 +690,28 @@ namespace
|
|||
{
|
||||
childToSet = settingsTree.getChildWithProperty (Ids::name, "FALLBACK_PATHS")
|
||||
.getChildWithName ("FALLBACK_PATHS")
|
||||
.getChildWithName (args[1] + String ("Fallback"));
|
||||
.getChildWithName (args[1].text + "Fallback");
|
||||
}
|
||||
|
||||
if (! childToSet.isValid())
|
||||
throw CommandLineError ("Failed to set the requested setting!");
|
||||
ConsoleApplication::fail ("Failed to set the requested setting!");
|
||||
|
||||
childToSet.setProperty (args[2], File::getCurrentWorkingDirectory().getChildFile (args[3].unquoted()).getFullPathName(), nullptr);
|
||||
childToSet.setProperty (args[2].text, args[3].resolveAsFile().getFullPathName(), nullptr);
|
||||
|
||||
settingsFile.replaceWithText (settingsTree.toXmlString());
|
||||
}
|
||||
|
||||
static void createProjectFromPIP (const StringArray& args)
|
||||
static void createProjectFromPIP (const ArgumentList& args)
|
||||
{
|
||||
checkArgumentCount (args, 3);
|
||||
args.checkMinNumArguments (3);
|
||||
|
||||
auto pipFile = args[1].resolveAsFile();
|
||||
|
||||
auto pipFile = File::getCurrentWorkingDirectory().getChildFile (args[1].unquoted());
|
||||
if (! pipFile.existsAsFile())
|
||||
throw CommandLineError ("PIP file doesn't exist.");
|
||||
ConsoleApplication::fail ("PIP file doesn't exist.");
|
||||
|
||||
auto outputDir = args[2].resolveAsFile();
|
||||
|
||||
auto outputDir = File::getCurrentWorkingDirectory().getChildFile (args[2].unquoted());
|
||||
if (! outputDir.exists())
|
||||
{
|
||||
auto res = outputDir.createDirectory();
|
||||
|
|
@ -779,12 +723,12 @@ namespace
|
|||
auto createJucerFileResult = generator.createJucerFile();
|
||||
|
||||
if (! createJucerFileResult)
|
||||
throw CommandLineError (createJucerFileResult.getErrorMessage());
|
||||
ConsoleApplication::fail (createJucerFileResult.getErrorMessage());
|
||||
|
||||
auto createMainCppResult = generator.createMainCpp();
|
||||
|
||||
if (! createMainCppResult)
|
||||
throw CommandLineError (createMainCppResult.getErrorMessage());
|
||||
ConsoleApplication::fail (createMainCppResult.getErrorMessage());
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
|
|
@ -862,48 +806,45 @@ namespace
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
int performCommandLine (const String& commandLine)
|
||||
int performCommandLine (const ArgumentList& args)
|
||||
{
|
||||
StringArray args;
|
||||
args.addTokens (commandLine, true);
|
||||
args.trim();
|
||||
|
||||
if (findArgument (args, "--lf") || findArgument (args, "-lf"))
|
||||
preferredLinefeed = "\n";
|
||||
|
||||
String command (args[0]);
|
||||
|
||||
try
|
||||
return ConsoleApplication::invokeCatchingFailures ([&] () -> int
|
||||
{
|
||||
if (matchArgument (command, "help")) { showHelp(); return 0; }
|
||||
if (matchArgument (command, "h")) { showHelp(); return 0; }
|
||||
if (matchArgument (command, "resave")) { resaveProject (args, false); return 0; }
|
||||
if (matchArgument (command, "resave-resources")) { resaveProject (args, true); return 0; }
|
||||
if (matchArgument (command, "get-version")) { getVersion (args); return 0; }
|
||||
if (matchArgument (command, "set-version")) { setVersion (args); return 0; }
|
||||
if (matchArgument (command, "bump-version")) { bumpVersion (args); return 0; }
|
||||
if (matchArgument (command, "git-tag-version")) { gitTag (args); return 0; }
|
||||
if (matchArgument (command, "buildmodule")) { buildModules (args, false); return 0; }
|
||||
if (matchArgument (command, "buildallmodules")) { buildModules (args, true); return 0; }
|
||||
if (matchArgument (command, "status")) { showStatus (args); return 0; }
|
||||
if (matchArgument (command, "trim-whitespace")) { cleanWhitespace (args, false); return 0; }
|
||||
if (matchArgument (command, "remove-tabs")) { cleanWhitespace (args, true); return 0; }
|
||||
if (matchArgument (command, "tidy-divider-comments")) { tidyDividerComments (args); return 0; }
|
||||
if (matchArgument (command, "fix-broken-include-paths")) { fixRelativeIncludePaths (args); return 0; }
|
||||
if (matchArgument (command, "obfuscated-string-code")) { generateObfuscatedStringCode (args); return 0; }
|
||||
if (matchArgument (command, "encode-binary")) { encodeBinary (args); return 0; }
|
||||
if (matchArgument (command, "trans")) { scanFoldersForTranslationFiles (args); return 0; }
|
||||
if (matchArgument (command, "trans-finish")) { createFinishedTranslationFile (args); return 0; }
|
||||
if (matchArgument (command, "set-global-search-path")) { setGlobalPath (args); return 0; }
|
||||
if (matchArgument (command, "create-project-from-pip")) { createProjectFromPIP (args); return 0; }
|
||||
if (args.containsOption ("--lf"))
|
||||
preferredLinefeed = "\n";
|
||||
|
||||
if (command.startsWith ("-")) { throw CommandLineError ("Unrecognised command: " + command.quoted()); }
|
||||
}
|
||||
catch (const CommandLineError& error)
|
||||
{
|
||||
std::cout << error.message << std::endl << std::endl;
|
||||
return 1;
|
||||
}
|
||||
auto command = args[0];
|
||||
|
||||
return commandLineNotPerformed;
|
||||
auto matchCommand = [&] (StringRef name) -> bool
|
||||
{
|
||||
return command == name || command.isLongOption (name);
|
||||
};
|
||||
|
||||
if (matchCommand ("help")) { showHelp(); return 0; }
|
||||
if (matchCommand ("h")) { showHelp(); return 0; }
|
||||
if (matchCommand ("resave")) { resaveProject (args, false); return 0; }
|
||||
if (matchCommand ("resave-resources")) { resaveProject (args, true); return 0; }
|
||||
if (matchCommand ("get-version")) { getVersion (args); return 0; }
|
||||
if (matchCommand ("set-version")) { setVersion (args); return 0; }
|
||||
if (matchCommand ("bump-version")) { bumpVersion (args); return 0; }
|
||||
if (matchCommand ("git-tag-version")) { gitTag (args); return 0; }
|
||||
if (matchCommand ("buildmodule")) { buildModules (args, false); return 0; }
|
||||
if (matchCommand ("buildallmodules")) { buildModules (args, true); return 0; }
|
||||
if (matchCommand ("status")) { showStatus (args); return 0; }
|
||||
if (matchCommand ("trim-whitespace")) { cleanWhitespace (args, false); return 0; }
|
||||
if (matchCommand ("remove-tabs")) { cleanWhitespace (args, true); return 0; }
|
||||
if (matchCommand ("tidy-divider-comments")) { tidyDividerComments (args); return 0; }
|
||||
if (matchCommand ("fix-broken-include-paths")) { fixRelativeIncludePaths (args); return 0; }
|
||||
if (matchCommand ("obfuscated-string-code")) { generateObfuscatedStringCode (args); return 0; }
|
||||
if (matchCommand ("encode-binary")) { encodeBinary (args); return 0; }
|
||||
if (matchCommand ("trans")) { scanFoldersForTranslationFiles (args); return 0; }
|
||||
if (matchCommand ("trans-finish")) { createFinishedTranslationFile (args); return 0; }
|
||||
if (matchCommand ("set-global-search-path")) { setGlobalPath (args); return 0; }
|
||||
if (matchCommand ("create-project-from-pip")) { createProjectFromPIP (args); return 0; }
|
||||
|
||||
if (command.isLongOption() || command.isShortOption())
|
||||
ConsoleApplication::fail ("Unrecognised command: " + command.text.quoted());
|
||||
|
||||
return commandLineNotPerformed;
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
int performCommandLine (const String& commandLine);
|
||||
int performCommandLine (const ArgumentList&);
|
||||
|
||||
enum { commandLineNotPerformed = 0x72346231 };
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@
|
|||
#include "misc/juce_Result.cpp"
|
||||
#include "misc/juce_Uuid.cpp"
|
||||
#include "misc/juce_StdFunctionCompat.cpp"
|
||||
#include "misc/juce_ConsoleApplication.cpp"
|
||||
#include "network/juce_MACAddress.cpp"
|
||||
#include "network/juce_NamedPipe.cpp"
|
||||
#include "network/juce_Socket.cpp"
|
||||
|
|
|
|||
|
|
@ -275,6 +275,7 @@ namespace juce
|
|||
#include "text/juce_Base64.h"
|
||||
#include "misc/juce_Result.h"
|
||||
#include "misc/juce_Uuid.h"
|
||||
#include "misc/juce_ConsoleApplication.h"
|
||||
#include "containers/juce_Variant.h"
|
||||
#include "containers/juce_NamedValueSet.h"
|
||||
#include "containers/juce_DynamicObject.h"
|
||||
|
|
|
|||
276
modules/juce_core/misc/juce_ConsoleApplication.cpp
Normal file
276
modules/juce_core/misc/juce_ConsoleApplication.cpp
Normal file
|
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
File ArgumentList::Argument::resolveAsFile() const
|
||||
{
|
||||
return File::getCurrentWorkingDirectory().getChildFile (text.unquoted());
|
||||
}
|
||||
|
||||
File ArgumentList::Argument::resolveAsExistingFile() const
|
||||
{
|
||||
auto f = resolveAsFile();
|
||||
|
||||
if (! f.exists())
|
||||
ConsoleApplication::fail ("Could not find file: " + f.getFullPathName());
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
File ArgumentList::Argument::resolveAsExistingFolder() const
|
||||
{
|
||||
auto f = resolveAsFile();
|
||||
|
||||
if (! f.isDirectory())
|
||||
ConsoleApplication::fail ("Could not find folder: " + f.getFullPathName());
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
bool ArgumentList::Argument::isLongOption() const { return text[0] == '-' && text[1] == '-' && text[2] != '-'; }
|
||||
bool ArgumentList::Argument::isShortOption() const { return text[0] == '-' && text[1] != '-'; }
|
||||
|
||||
bool ArgumentList::Argument::isLongOption (const String& option) const
|
||||
{
|
||||
if (option.startsWith ("--"))
|
||||
return text == option;
|
||||
|
||||
jassert (! option.startsWithChar ('-')); // this will always fail to match
|
||||
|
||||
return text == "--" + option;
|
||||
}
|
||||
|
||||
bool ArgumentList::Argument::isShortOption (char option) const
|
||||
{
|
||||
jassert (option != '-'); // this is probably not what you intended to pass in
|
||||
|
||||
return isShortOption() && text.containsChar (option);
|
||||
}
|
||||
|
||||
static bool compareOptionStrings (StringRef s1, StringRef s2)
|
||||
{
|
||||
if (s1 == s2)
|
||||
return true;
|
||||
|
||||
for (auto& part1 : StringArray::fromTokens (s1, "|", {}))
|
||||
for (auto& part2 : StringArray::fromTokens (s2, "|", {}))
|
||||
if (part1.trim() == part2.trim())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ArgumentList::Argument::operator== (StringRef s) const { return compareOptionStrings (text, s); }
|
||||
bool ArgumentList::Argument::operator!= (StringRef s) const { return ! operator== (s); }
|
||||
|
||||
//==============================================================================
|
||||
ArgumentList::ArgumentList (String exeName, StringArray args)
|
||||
: executableName (std::move (exeName))
|
||||
{
|
||||
args.trim();
|
||||
|
||||
for (auto& a : args)
|
||||
arguments.add ({ a });
|
||||
}
|
||||
|
||||
ArgumentList::ArgumentList (int argc, char* argv[])
|
||||
: ArgumentList (argv[0], StringArray (argv + 1, argc - 1))
|
||||
{
|
||||
}
|
||||
|
||||
ArgumentList::ArgumentList (const String& exeName, const String& args)
|
||||
: ArgumentList (exeName, StringArray::fromTokens (args, true))
|
||||
{
|
||||
}
|
||||
|
||||
int ArgumentList::size() const { return arguments.size(); }
|
||||
ArgumentList::Argument ArgumentList::operator[] (int index) const { return arguments[index]; }
|
||||
|
||||
void ArgumentList::checkMinNumArguments (int expectedMinNumberOfArgs) const
|
||||
{
|
||||
if (size() < expectedMinNumberOfArgs)
|
||||
ConsoleApplication::fail ("Not enough arguments!");
|
||||
}
|
||||
|
||||
int ArgumentList::indexOfOption (StringRef option) const
|
||||
{
|
||||
jassert (option == String (option).trim()); // passing non-trimmed strings will always fail to find a match!
|
||||
|
||||
for (int i = 0; i < arguments.size(); ++i)
|
||||
if (arguments.getReference(i) == option)
|
||||
return i;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ArgumentList::containsOption (StringRef option) const
|
||||
{
|
||||
return indexOfOption (option) >= 0;
|
||||
}
|
||||
|
||||
void ArgumentList::failIfOptionIsMissing (StringRef option) const
|
||||
{
|
||||
if (! containsOption (option))
|
||||
ConsoleApplication::fail ("Expected the option " + option);
|
||||
}
|
||||
|
||||
ArgumentList::Argument ArgumentList::getArgumentAfterOption (StringRef option) const
|
||||
{
|
||||
for (int i = 0; i < arguments.size() - 1; ++i)
|
||||
if (arguments.getReference(i) == option)
|
||||
return arguments.getReference (i + 1);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
File ArgumentList::getFileAfterOption (StringRef option) const
|
||||
{
|
||||
failIfOptionIsMissing (option);
|
||||
auto arg = getArgumentAfterOption (option);
|
||||
|
||||
if (arg.text.isEmpty() || arg.text.startsWithChar ('-'))
|
||||
ConsoleApplication::fail ("Expected a filename after the " + option + " option");
|
||||
|
||||
return arg.resolveAsFile();
|
||||
}
|
||||
|
||||
File ArgumentList::getExistingFileAfterOption (StringRef option) const
|
||||
{
|
||||
failIfOptionIsMissing (option);
|
||||
auto arg = getArgumentAfterOption (option);
|
||||
|
||||
if (arg.text.isEmpty())
|
||||
ConsoleApplication::fail ("Expected a filename after the " + option + " option");
|
||||
|
||||
return arg.resolveAsExistingFile();
|
||||
}
|
||||
|
||||
File ArgumentList::getExistingFolderAfterOption (StringRef option) const
|
||||
{
|
||||
failIfOptionIsMissing (option);
|
||||
auto arg = getArgumentAfterOption (option);
|
||||
|
||||
if (arg.text.isEmpty())
|
||||
ConsoleApplication::fail ("Expected a folder name after the " + option + " option");
|
||||
|
||||
return arg.resolveAsExistingFolder();
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct ConsoleAppFailureCode
|
||||
{
|
||||
String errorMessage;
|
||||
int returnCode;
|
||||
};
|
||||
|
||||
void ConsoleApplication::fail (String errorMessage, int returnCode)
|
||||
{
|
||||
throw ConsoleAppFailureCode { std::move (errorMessage), returnCode };
|
||||
}
|
||||
|
||||
int ConsoleApplication::invokeCatchingFailures (std::function<int()>&& f)
|
||||
{
|
||||
int returnCode = 0;
|
||||
|
||||
try
|
||||
{
|
||||
returnCode = f();
|
||||
}
|
||||
catch (const ConsoleAppFailureCode& error)
|
||||
{
|
||||
std::cout << error.errorMessage << std::endl;
|
||||
returnCode = error.returnCode;
|
||||
}
|
||||
|
||||
return returnCode;
|
||||
}
|
||||
|
||||
int ConsoleApplication::findAndRunCommand (const ArgumentList& args) const
|
||||
{
|
||||
for (auto& c : commands)
|
||||
if (args.containsOption (c.commandOption))
|
||||
return invokeCatchingFailures ([&] { c.command (args); return 0; });
|
||||
|
||||
if (commandIfNoOthersRecognised.isNotEmpty())
|
||||
for (auto& c : commands)
|
||||
if (compareOptionStrings (c.commandOption, commandIfNoOthersRecognised))
|
||||
return invokeCatchingFailures ([&] { c.command (args); return 0; });
|
||||
|
||||
fail ("Unrecognised arguments");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ConsoleApplication::findAndRunCommand (int argc, char* argv[]) const
|
||||
{
|
||||
return findAndRunCommand (ArgumentList (argc, argv));
|
||||
}
|
||||
|
||||
void ConsoleApplication::addCommand (Command c)
|
||||
{
|
||||
commands.emplace_back (std::move (c));
|
||||
}
|
||||
|
||||
void ConsoleApplication::addHelpCommand (String arg, String helpMessage, bool invokeIfNoOtherCommandRecognised)
|
||||
{
|
||||
addCommand ({ arg, arg, "Prints this message",
|
||||
[this, helpMessage] (const ArgumentList& args) { printHelp (helpMessage, args); }});
|
||||
|
||||
if (invokeIfNoOtherCommandRecognised)
|
||||
commandIfNoOthersRecognised = arg;
|
||||
}
|
||||
|
||||
void ConsoleApplication::addVersionCommand (String arg, String versionText)
|
||||
{
|
||||
addCommand ({ arg, arg, "Prints the current version number",
|
||||
[versionText] (const ArgumentList&)
|
||||
{
|
||||
std::cout << versionText << std::endl;
|
||||
}});
|
||||
}
|
||||
|
||||
void ConsoleApplication::printHelp (const String& preamble, const ArgumentList& args) const
|
||||
{
|
||||
std::cout << preamble << std::endl;
|
||||
|
||||
auto exeName = args.executableName.fromLastOccurrenceOf ("/", false, false)
|
||||
.fromLastOccurrenceOf ("\\", false, false);
|
||||
|
||||
StringArray namesAndArgs;
|
||||
int maxLength = 0;
|
||||
|
||||
for (auto& c : commands)
|
||||
{
|
||||
auto nameAndArgs = exeName + " " + c.argumentDescription;
|
||||
namesAndArgs.add (nameAndArgs);
|
||||
maxLength = std::max (maxLength, nameAndArgs.length());
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < commands.size(); ++i)
|
||||
std::cout << " " << namesAndArgs[(int) i].paddedRight (' ', maxLength + 2)
|
||||
<< commands[i].commandDescription << std::endl;
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
} // namespace juce
|
||||
269
modules/juce_core/misc/juce_ConsoleApplication.h
Normal file
269
modules/juce_core/misc/juce_ConsoleApplication.h
Normal file
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
==============================================================================
|
||||
|
||||
This file is part of the JUCE library.
|
||||
Copyright (c) 2017 - ROLI Ltd.
|
||||
|
||||
JUCE is an open source library subject to commercial or open-source
|
||||
licensing.
|
||||
|
||||
The code included in this file is provided under the terms of the ISC license
|
||||
http://www.isc.org/downloads/software-support-policy/isc-license. Permission
|
||||
To use, copy, modify, and/or distribute this software for any purpose with or
|
||||
without fee is hereby granted provided that the above copyright notice and
|
||||
this permission notice appear in all copies.
|
||||
|
||||
JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
|
||||
EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
|
||||
DISCLAIMED.
|
||||
|
||||
==============================================================================
|
||||
*/
|
||||
|
||||
namespace juce
|
||||
{
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Holds a list of command-line arguments, and provides useful methods for searching
|
||||
and operating on them.
|
||||
|
||||
You can create an ArgumentList manually, or give it some argv/argc values from a
|
||||
main() function to parse.
|
||||
|
||||
@see ConsoleApplication
|
||||
*/
|
||||
struct ArgumentList
|
||||
{
|
||||
/** Creates an argument list for a given executable. */
|
||||
ArgumentList (String executable, StringArray arguments);
|
||||
|
||||
/** Parses a standard argv/argc pair to create an argument list. */
|
||||
ArgumentList (int argc, char* argv[]);
|
||||
|
||||
/** Tokenises a string containing all the arguments to create an argument list. */
|
||||
ArgumentList (const String& executable, const String& arguments);
|
||||
|
||||
ArgumentList (const ArgumentList&) = default;
|
||||
ArgumentList& operator= (const ArgumentList&) = default;
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
One of the arguments in an ArgumentList.
|
||||
*/
|
||||
struct Argument
|
||||
{
|
||||
/** The original text of this argument. */
|
||||
String text;
|
||||
|
||||
/** Resolves this argument as an absolute File, using the current working
|
||||
directory as a base for resolving relative paths, and stripping quotes, etc.
|
||||
*/
|
||||
File resolveAsFile() const;
|
||||
|
||||
/** Resolves this argument as an absolute File, using the current working
|
||||
directory as a base for resolving relative paths, and also doing a check to
|
||||
make sure the file exists.
|
||||
If the file doesn't exist, this will call fail() with a suitable error.
|
||||
@see resolveAsFile, resolveAsExistingFolder
|
||||
*/
|
||||
File resolveAsExistingFile() const;
|
||||
|
||||
/** Resolves a user-supplied folder name into an absolute File, using the current working
|
||||
directory as a base for resolving relative paths, and also doing a check to make
|
||||
sure the folder exists.
|
||||
If the folder doesn't exist, this will call fail() with a suitable error.
|
||||
@see resolveAsFile, resolveAsExistingFile
|
||||
*/
|
||||
File resolveAsExistingFolder() const;
|
||||
|
||||
/** Returns true if this argument starts with a double dash. */
|
||||
bool isLongOption() const;
|
||||
|
||||
/** Returns true if this argument starts with a single dash. */
|
||||
bool isShortOption() const;
|
||||
|
||||
/** Returns true if this argument starts with a double dash, followed by the given string. */
|
||||
bool isLongOption (const String& optionRoot) const;
|
||||
|
||||
/** Returns true if this argument starts with a single dash and then contains the given character somewhere inside it. */
|
||||
bool isShortOption (char shortOptionCharacter) const;
|
||||
|
||||
/** Compares this argument against a string.
|
||||
The string may be a pipe-separated list of options, e.g. "--help|-h"
|
||||
*/
|
||||
bool operator== (StringRef stringToCompare) const;
|
||||
|
||||
/** Compares this argument against a string.
|
||||
The string may be a pipe-separated list of options, e.g. "--help|-h"
|
||||
*/
|
||||
bool operator!= (StringRef stringToCompare) const;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Returns the number of arguments in the list. */
|
||||
int size() const;
|
||||
|
||||
/** Returns one of the arguments */
|
||||
Argument operator[] (int index) const;
|
||||
|
||||
/** Throws an error unless there are at least the given number of arguments. */
|
||||
void checkMinNumArguments (int expectedMinNumberOfArgs) const;
|
||||
|
||||
/** Returns true if the given string matches one of the arguments.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
*/
|
||||
bool containsOption (StringRef option) const;
|
||||
|
||||
/** Returns the index of the given string if it matches one of the arguments, or -1 if it doesn't.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
*/
|
||||
int indexOfOption (StringRef option) const;
|
||||
|
||||
/** Throws an error unless the given option is found in the argument list. */
|
||||
void failIfOptionIsMissing (StringRef option) const;
|
||||
|
||||
/** Looks for the given argument and returns the one that follows it in the list.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
If the argument isn't found, this returns an empty string.
|
||||
*/
|
||||
Argument getArgumentAfterOption (StringRef option) const;
|
||||
|
||||
/** Looks for a given argument and tries to parse the following argument as a file.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
If the option isn't found, or if the next argument isn't a filename, it will throw
|
||||
an error.
|
||||
*/
|
||||
File getFileAfterOption (StringRef option) const;
|
||||
|
||||
/** Looks for a given argument and tries to parse the following argument as a file
|
||||
which must exist for this to succeed.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
If the option isn't found, or if the next argument isn't a filename, or if the file
|
||||
doesn't exist, or if it's a folder rather than a file, then it will throw a suitable error.
|
||||
*/
|
||||
File getExistingFileAfterOption (StringRef option) const;
|
||||
|
||||
/** Looks for a given argument and tries to parse the following argument as a folder
|
||||
which must exist for this to succeed.
|
||||
The option can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
If the option isn't found, or if the next argument isn't a filename, or if it doesn't
|
||||
point to a folder, then it will throw a suitable error.
|
||||
*/
|
||||
File getExistingFolderAfterOption (StringRef option) const;
|
||||
|
||||
/** The name or path of the executable that was invoked, as it was specified on the command-line. */
|
||||
String executableName;
|
||||
|
||||
/** The list of arguments (not including the name of the executable that was invoked). */
|
||||
Array<Argument> arguments;
|
||||
};
|
||||
|
||||
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a the set of commands that a console app can perform, and provides
|
||||
helper functions for performing them.
|
||||
|
||||
When using these helper classes to implement a console app, you probably want to
|
||||
do something along these lines:
|
||||
|
||||
@code
|
||||
int main (int argc, char* argv[])
|
||||
{
|
||||
ConsoleApplication app;
|
||||
|
||||
app.addHelpCommand ("--help|-h", "Usage:", true);
|
||||
app.addVersionCommand ("--version|-v", "MyApp version 1.2.3");
|
||||
|
||||
app.addCommand ({ "--foo",
|
||||
"--foo filename",
|
||||
"Performs a foo operation on the given file",
|
||||
[] (const auto& args) { doFoo (args); }});
|
||||
|
||||
return app.findAndRunCommand (argc, argv);
|
||||
}
|
||||
@endcode
|
||||
|
||||
@see ArgumentList
|
||||
*/
|
||||
struct ConsoleApplication
|
||||
{
|
||||
//==============================================================================
|
||||
/**
|
||||
Represents a command that can be executed if its command-line arguments are matched.
|
||||
@see ConsoleApplication::addCommand(), ConsoleApplication::findAndRunCommand()
|
||||
*/
|
||||
struct Command
|
||||
{
|
||||
/** The option string that must appear in the argument list for this command to be invoked.
|
||||
This can also be a list of different versions separated by pipes, e.g. "--help|-h"
|
||||
*/
|
||||
String commandOption;
|
||||
|
||||
/** A description of the command-line arguments needed for this command, which will be
|
||||
printed as part of the help text.
|
||||
*/
|
||||
String argumentDescription;
|
||||
|
||||
/** A description of the meaning of this command, for use in the help text. */
|
||||
String commandDescription;
|
||||
|
||||
/** The actual command that should be invoked to perform this action. */
|
||||
std::function<void(const ArgumentList&)> command;
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
/** Adds a command to the list. */
|
||||
void addCommand (Command);
|
||||
|
||||
/** Adds a help command to the list.
|
||||
This command will print the user-supplied message that's passed in here as an
|
||||
argument, followed by a list of all the registered commands.
|
||||
*/
|
||||
void addHelpCommand (String helpArgument, String helpMessage,
|
||||
bool invokeIfNoOtherCommandRecognised);
|
||||
|
||||
/** Adds a command that will print the given text in response to the "--version" option. */
|
||||
void addVersionCommand (String versionArgument, String versionText);
|
||||
|
||||
//==============================================================================
|
||||
/** Throws a failure exception to cause a command-line app to terminate.
|
||||
This is intended to be called from code in a Command, so that the
|
||||
exception will be automatically caught and turned into a printed error message
|
||||
and a return code which will be returned from main().
|
||||
@see ConsoleApplication::invokeCatchingFailures()
|
||||
*/
|
||||
static void fail (String errorMessage, int returnCode = 1);
|
||||
|
||||
/** Invokes a function, catching any fail() calls that it might trigger, and handling
|
||||
them by printing their error message and returning their error code.
|
||||
@see ConsoleApplication::fail()
|
||||
*/
|
||||
static int invokeCatchingFailures (std::function<int()>&& functionToCall);
|
||||
|
||||
//==============================================================================
|
||||
/** Looks for the first command in the list which matches the given arguments, and
|
||||
tries to invoke it.
|
||||
|
||||
If no command is found, it prints a help message listing the available commands.
|
||||
If the command calls the fail() function, this will throw an exception that gets
|
||||
automatically caught and handled, and this method will return the error code that
|
||||
was passed into the fail() call.
|
||||
*/
|
||||
int findAndRunCommand (const ArgumentList&) const;
|
||||
|
||||
/** Creates an ArgumentList object from the argc and argv variablrs, and invokes
|
||||
findAndRunCommand() using it.
|
||||
*/
|
||||
int findAndRunCommand (int argc, char* argv[]) const;
|
||||
|
||||
private:
|
||||
//==============================================================================
|
||||
std::vector<Command> commands;
|
||||
String commandIfNoOthersRecognised;
|
||||
|
||||
void printHelp (const String& preamble, const ArgumentList&) const;
|
||||
};
|
||||
|
||||
} // namespace juce
|
||||
Loading…
Add table
Add a link
Reference in a new issue