I have a use case where I need to post the entire help for a CLI in a specified format. I have found a way to do that using the following:
#CommandLine.Command(name="myAp",
synopsisSubcommandLabel = "", usageHelpWidth = 120,
commandListHeading = "",
customSynopsis = "\n\nArguments for MyApp operation.\n"
+ "\n"
+ "Operations:\n"
+ " create Create the stuff\n"
+ " list List the stuff\n"
+ " add Add things\n"
+ " -r --type One or both of [Type1, Typ2]\n"
+ " -a --annualCost AnnualCost\n"
+ " -n --number Number of each type thing\n"
+ " subtract Subtract things\n"
+ " -r --reasons Combination of\n"
+ " fiscal (fiscal reason)\n"
+ " operational (operational reason\n"
+ " other (other reason)\n"
+ " -h Display this help message and exit\n"
)
class PicoCliParser {
// All of my other Parameters and options here
#Option(names = { "-h", "--help" }, usageHelp = true, hidden = true)
boolean helpRequested = false;
public static void main(String[] args) throws Exception {
PicoCliParser parser = new PicoCliParser();
CommandLine cmd = new CommandLine(parser);
try {
CommandLine.ParseResult parseResult = cmd.parseArgs(args);
System.err.println("parseResults: " + parseResult.matchedArgs().toString());
if (cmd.isUsageHelpRequested()) {
cmd.usage(System.out);
}
} catch (CommandLine.ParameterException e) {
}
}
}
If the user enters -h or --help, the help prints out in the format that I want, If they do not enter -h or -H it doesn't.
Is there a better way to do this?
If we add additional commands in the future, then whoever adds them has to remember to update the help string.
Your solution works, but has the drawback (like you mentioned) that the usage help message is static and won't reflect future updates like new subcommands or options being added.
Picocli does provide a way to customize the usage help message dynamically via its Help API. This allows you to reorder or replace sections in the usage help message. I believe the section you want to replace is the command list section.
This will require a bit of a deep dive into the picocli usage help model. To help you get started, the picocli-examples module has some custom help examples. This example shows how to modify the usage help message to show the full command hierarchy (without options though), which is fairly close to what you want to do. You could take it as a starting point. If you have more questions feel free to raise tickets on the picocli github issue tracker (or here).
Related
You need to set up map-remote on multiple phone URLs in autotest, but how do you do it via the command line?
launch example:
case ANDROID -> {
String[] command = {"mitmdump",
"--listen-port", String.valueOf(port),
"--set", "confdir=" + Objects.requireNonNull(Proxy.class.getClassLoader().getResource("mitmproxy")).toURI().getPath() + "/mitmproxy-certs",
"--map-remote", "|" + mapRemotePattern + "|http://localhost:" + String.valueOf(mockPort),
"--modify-headers", "/~hq localhost/Host/" + hostHeader,
"--save-stream-file", fileNameNetworkLog};
startMitmdump(command);
}
I can't find the answer in the documentation
when trying to add 1 more map-remote field with different url, then it doesn't work
If you try to write mapRemote by regular expression OR, to 2 url , then it doesn't work either.
how can I Print adittional information to Command line Console?
Output now is:
C:\Users\admin\Desktop\java>java -jar pdf.jar
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
at readDataIn.main(readDataIn.java:31)
Code:
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
try {
String arg = args[0];
fileNameSource = "import/" + arg + ".xml";
fileNameTarget = "export/" + arg + ".pdf";
} catch (Exception e) {
// TODO: handle exception
**System.out.println("Personal-Number is missing");**
e.printStackTrace();
}
How can i give the information out, that the Personal Number ist Missing?
First of all, as a general rule you should check for possible exceptions before they actually occur if that is possible, which in your case it definitely is.
So instead of catching the ArrayIndexOutOfBounds insert an if statement that checks the length of the args array before accessing it.
if(args.length == 0){
// no argument has been provided
// handle error here
}
In terms of how to handle the error, there are many options available and depending of what you want to do either could be a good fit.
IllegalArgumentException
It is a common idiom in Java that whenever a function receives an invalid/ illegal argument to throw an IllegalArgumentException.
if (args.length == 0){
throw new IllegalArgumentException("Personal number is missing");
}
This will print the message that you have provided and the stack trace. However if your application should be a Command Line Interface (CLI) you should not use this kind of error handling.
Print message & exit program
if (args.length == 0){
// notice: "err" instead of "out": print to stderr instead of stdout
System.err.println("Personal number is missing");
// exit program with non-zero exit code as exit code == 0 means everything is fine
System.exit(1);
}
For more information on stdout and stderr see this StackOverflow question.
This is what many CLI applications and e.g. java itself does. When you type java fdsdfsdfs or some similar nonsense as an argument Java will give you an error message and exit with some non-zero return code ("1" in this case).
It is also common that CLI applications print an error message and following some usage information on how to correctly use the application or provide a help command so a user can get more information. This happens for example if you just enter java without any parameters.
So it is really up to you what you want to do.
If you are thinking of implementing a full featured CLI application with more (complex) commands with multiple options etc. you should consider using a CLI library like JCommander or Apache Commons CLI as parsing command line arguments can quickly get ugly. All these common things are already handled there.
Logging
In case your application is some script that will be executed in a non-interactive way logging the error to a file and exiting with a non-zero exit code might also be an option.
PS
Your code looks to me like it should not compile at all as you are not declaring a type for your variables fileNameSource and fileNameTarget.
Use String or var here (assuming you're running > Java 11).
String fileNameSource = "import/" + arg + ".xml";
var fileNameTarget = "export/" + arg + ".pdf";
You might also need to consider that your program name is part of the args array, so you might have more than 0 values in the array and therefore might need to adjust the if statements above.
You may be interested in picocli, which is a modern CLI library for Java and other JVM languages.
Picocli does some basic validation automatically, and results in very compact code that produces user-friendly applications. For example:
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
#Command(name = "myapp", mixinStandardHelpOptions = true, version = "1.0",
description = "This command does something useful.")
class MyApp implements Runnable {
#Parameters(description = "File name (without extension) of the file to import and export.")
private String personalNumber;
#Override
public void run() {
String fileNameSource = "import/" + personalNumber + ".xml";
String fileNameTarget = "export/" + personalNumber + ".pdf";
// remaining business logic
}
public static void main(String[] args) {
System.exit(new CommandLine(new MyApp()).execute(args));
}
}
If I run this class without any parameters, the following message is printed to the standard error stream, and the process finished with exit code 2. (Exit codes are customizable.)
Missing required parameter: '<personalNumber>'
Usage: myapp [-hV] <personalNumber>
This command does something useful.
<personalNumber> File name (without extension) of the file to import
and export.
-h, --help Show this help message and exit.
-V, --version Print version information and exit.
The usage help message is created automatically from the descriptions of the command, and the descriptions of its options and positional parameters, but can be further customized.
Note how the mixinStandardHelpOptions = true annotation adds --help and --version options to the command. These options are handled by the library without requiring any further logic in the application.
Picocli comes with an annotation processor that makes it very easy to turn your application into a native image with GraalVM. Native images have faster startup time and lower runtime memory overhead compared to a Java VM.
Is there a way to authorize destinations with Apache Apollo MQ?
What I would like is to make it so that
1) users may write only to a shared topic but restrict read to an server/admin. This topic is to send messages to a server.
2) Users may read from their own private topic but no one but the server/admin may write to it.
For Example:
Topic User rights Server/Admin rights
/public Write only Read only
/user/foo ONLY the user foo may read Write only
/user/bar ONLY the user bar may read Write only
/user/<username> ONLY the <username> may read Write only
Now for the interesting part. This must work with dynamic topics. The user's name is NOT known ahead of time.
I had this working with Apache ActiveMQ using a custom BrokerFilter but am not sure how to do with with Apollo.
Thanks for any help.
After a lot of head scratching I figured it out.
In apollo.xml:
<broker xmlns="http://activemq.apache.org/schema/activemq/apollo" security_factory="com.me.MyAuthorizationPlugin">
In com.me.MyAuthorizationPlugin:
package com.me
import org.fusesource.hawtdispatch.DispatchQueue.QueueType
import org.apache.activemq.apollo.broker.security._
import org.apache.activemq.apollo.broker.{ Queue, Broker, VirtualHost }
import java.lang.Boolean
class MyAuthorizationPlugin extends SecurityFactory {
def install(broker: Broker) {
DefaultSecurityFactory.install(broker)
}
def install(virtual_host: VirtualHost) {
DefaultSecurityFactory.install(virtual_host)
val default_authorizer = virtual_host.authorizer
virtual_host.authorizer = new Authorizer() {
def can(ctx: SecurityContext, action: String, resource: SecuredResource): Boolean = {
println("Resource: " + resource.id + " User: " + ctx.user)
resource.resource_kind match {
case SecuredResource.TopicKind =>
val id = resource.id
println("Topic Resource: " + id + " User: " + ctx.user)
var result : Boolean = id.startsWith("user." + ctx.user) || id.startsWith("MDN." + ctx.user + ".")
println("Result: " + result)
return result
case _ =>
return default_authorizer.can(ctx, action, resource)
}
}
}
}
}
The following URLs seemed VERY useful and indeed nearly a perfect match:
https://github.com/apache/activemq-apollo/blob/trunk/apollo-stomp/src/test/resources/apollo-stomp-custom-security.xml#L18
https://github.com/apache/activemq-apollo/blob/trunk/apollo-stomp/src/test/scala/org/apache/activemq/apollo/stomp/test/UserOwnershipSecurityFactory.scala#L29
Now I only need to clean up my nasty scala and put it in Git.
I am thinking of doing two tests:
Speed of EXACTLY what I need
A Regex pattern matcher with username / clientID replacements and +/*/?/etc This pattern will be pulled from the config file.
If they are nearly identical I may see about adding it to Apollo by contacting commiters.
Is there a way to basically print my own output during a command line render?
Let's say I don't need/want all the other output that maya spits out by default, I know you can change the verbosity level, but there's very specific things I'd like to output but I can't figure it out. I currently render out the verbosity output to file, so I wanted to print in the terminal (I'm using MAC) the frame that the render is currently up to.
This may just be simple minded, but here's what I tried:
Render -preFrame "print `currentTime -q`;" -s 1 -e 20 -rd /render/directory/ maya_file.mb
Obviously, -preFrame expects a string, according to the docs this can take mel commands, but obviously this is limited to certain commands, I'm assuming the currentTime command is pulling the information from the timeline in maya, not queering it from the Renderer it self... When I run the above command, straight away, it spits out this: -bash: currentTime: command not found and soon after the render fails/doesn't start.
Idealy, I'd like to print the following as it starts each frame:
"Started rendering frame XXXX at TIME GOES HERE", that way, I can quickly look at the terminal, and see if the renderer has failed, stuck or where it's up to and when it started it.
So my question is, seeing is currentTime is a mel command used from within Maya, is there another way I could print this information?
Cheers,
Shannon
After many hours of searching for this answer, I ended up finding out that you can start maya as an interactive shell. By doing this, I was able to source a script as I opened it, and run whatever I want into memory as If I had Maya open at the time.
/Applications/Autodesk/maya2014/Maya.app/Contents/MacOS/maya -prompt -script "/Volumes/raid/farm_script/setupRender.mel"
In the setupRender.mel file, I was able to assign variables, containing options for renders etc, in doing this, I was also able to create a global variable for the frame number, and increment it during the preFrame callback, like so:
int $startFrame = 100;
int $endFrame = 1110;
global int $frameCount = 0;
string $preRenderStatistics = "'global int $frameCount; $frameCount = " + $startFrame + ";'";
string $preFrameStatistics = "'print(\"Rendering frame: \" + $frameCount++)'";
string $additionalFlags = "";
string $sceneFilePath = "'/Volumes/path/to/file/intro_video_001.mb'";
system("Render -preRender " + $preRenderStatistics + " -preFrame " + $preFrameStatistics + " -s " + $startFrame + " -e " + $endFrame + " -x " + $additionalFlags + " " + $sceneFilePath);
This is a very simplified version of what I currently have, but hopefully this will help others if they stumble across it.
Take a look at the pre render layer MEL and/or pre render frame MEL section of the Render Settings.
It expects MEL, so you'll either need to write it in MEL or wrap your python in MEL. For such a simple use, I'd say just write it in MEL:
print `currentTime -q`
I'm trying to create a CSV export for some data I have. Seems simple enough, and works beautifully in Firefox and Chrome, but in Internet Explorer I just get a message saying the file could not be downloaded. No other error messages, no break in Visual Studio, no debugging information that I can find.
Here's my code. Perhaps I'm doing something wrong?
public ActionResult ExportStudentsCSV(IEnumerable<Student> students) {
MemoryStream output = new MemoryStream();
StreamWriter writer = new StreamWriter(output, System.Text.Encoding.UTF8);
writer.WriteLine("Username,Year Level,School Name,State,Date Joined");
foreach (Student student in students) {
writer.WriteLine(
"\"" + student.username
+ "\",\"" + student.year_level
+ "\",\"" + student.SchoolName
+ "\",\"" + student.state
+ "\",\"" + student.join_date
+ "\""
);
}
writer.Flush();
output.Seek(0, SeekOrigin.Begin);
return File(output, "text/csv", "Students_" + DateTime.Now.ToShortDateString().Replace('/', '-') + ".csv");
}
And I'm calling this function in my controller with:
return ExportStudentsCSV(model.StudentReport.StudentList);
You may need to add a Content-Disposition header.
In your ExportStudentsCSV function, before returning:
var cd = new System.Net.Mime.ContentDisposition();
cd.FileName = "filename.csv";
Response.AddHeader("Content-Disposition", cd.ToString());
Or if you'd rather be brief about it (equivalent to above):
Response.AddHeader("Content-Disposition", "attachment;filename=filename.csv");
It may seem dodgy to be answering my own question, but I thought my experience may help someone. I did some more digging and found a completely alternate way of doing this using DataTables and a specific CsvActionResult which inherits from FileResult.
See this gist: https://gist.github.com/777376
Probably has something to do with the Content-Type/Content-Dispositon because IE follows standards when it wants to.
Check out ASP MVC3 FileResult with accents + IE8 - bugged?