picocli : dependent arguments in ArgGroup - picocli

My question is similar, and simpler, to the one asked here.
I have three options, -A, -A1, -A2 (conceptually, part of a single group). The relationships required are these:
Neither of these are required
-A should be given along with at least one of -A1 or -A2
Both -A1 and -A2 can be given with a single -A
In other words:
Valid specifications: -A -A1, -A -A2, and -A -A1 -A2
Invalid specifications: -A, -A1, -A2, and -A1 -A2
This is what I have using two #ArgGroups:
import picocli.CommandLine;
import picocli.CommandLine.*;
import picocli.CommandLine.Model.CommandSpec;
public class App implements Runnable {
static class MyGroupX {
#Option(names="-A1", required=false) boolean A1;
#Option(names="-A2", required=false) boolean A2;
}
static class MyGroup {
#Option(names="-A", required=true) boolean A;
#ArgGroup(exclusive=false, multiplicity="1") MyGroupX myGroupX;
}
#ArgGroup(exclusive=false) MyGroup myGroup;
#Spec CommandSpec spec;
#Override
public void run() {
System.out.printf("OK: %s%n", spec.commandLine().getParseResult().originalArgs());
}
public static void main(String[] args) {
//test: these should be valid
new CommandLine(new App()).execute();
new CommandLine(new App()).execute("-A -A1".split(" "));
new CommandLine(new App()).execute("-A -A2".split(" "));
new CommandLine(new App()).execute("-A -A1 -A2".split(" "));
//test: these should FAIL
new CommandLine(new App()).execute("-A");
new CommandLine(new App()).execute("-A1");
new CommandLine(new App()).execute("-A2");
new CommandLine(new App()).execute("-A1 -A2".split(" "));
}
}
Is there a simpler way?
Thanks!

Some relationships cannot be expressed with the #ArgGroup annotations only, and in that case custom validation logic in the application is needed.
However, this is not the case for your application. It appears to me that you have found a very compact way to express your requirements.
The valid user input sequences -A -A1, -A -A2, and -A -A1 -A2 are all accepted.
The invalid user input sequences are all rejected with a reasonably clear error message:
Input Error message
----- -------------
-A Missing required argument(s): ([-A1] [-A2])
-A1 Missing required argument(s): -A
-A2 Missing required argument(s): -A
-A1 -A2 Missing required argument(s): -A
The application achieved all this without any explicit validation logic in the code, it was all done declaratively with annotations. Mission accomplished, I would say. I don't see a way to improve on this further.

Related

PGP encryption with multiple keys in mule

Given that PGP supports encryption using multiple public keys, how it can be achieved in mulesoft?
adding two keys in Public Key Ring File Name field on encryption config window for pgp encrypter tab results in error as org.mule.module.pgp.exception.MissingPGPKeyException: No key file found in: abc.gpg,test.pgp
Is it possible to add multiple public keys from this encrypt module or else how it can be done? mule runtime : 3.8.5
much appreciate any help. Thank you!
I solved this by using java component- invoking terminal and running gpg encrypt command from java runtime. I am just checking for OS first to build a command string to run its respective terminal
boolean isWindows = System.getProperty("os.name")
.toLowerCase().startsWith("windows");
/*gpg command options may vary as per your requirement. multiple --recipient option here is the way to encrypt with multiple public keys.
Using StringBuilder helps to build this string from input/dynamic values.
*/
String command = "gpg --pgp6 --armor --batch --output encryptedHelloWorld.pgp --trust-model always --recipient "<part of UserID1 (either name or emailId)>" --recipient "<part of UserID2>" --encrypt helloWorld.txt"
/*in case you need to change directory to where your file is to encrypt it from one command, you could append this
`"cd"+ <your path to file> "&" + command` ----> for windows
`"cd"+ <your path to file> ";" + command` ----> for linux
*/
public int executeCommand(String command) throws IOException, InterruptedException {
Process pr;
if (isWindows) {
String[] cmd = { "cmd.exe", "/c", command };
pr = Runtime.getRuntime().exec(cmd);
}
else {
String[] cmd = { "/bin/sh", "-c", command };
pr = Runtime.getRuntime().exec(cmd);
}
int exitStatus = pr.waitFor(); // this gives you value 0 if success or other than 0 which ties to error message
errorInputStream = pr.getErrorStream(); //streaming error message
return exitStatus;
}

Exclusion by annotation not working for sbt test/testOnly

Consider the following org.scalatest.TagAnnotation subclass:
public class TestSizeTags {
/** Tests with crazy long runtimes **/
#org.scalatest.TagAnnotation
#Inherited
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public static #interface HugeTestClass {}
}
Let us annotate/tag a class with it:
#HugeTestClass
class ItemsJobTest extends FunSuite with BeforeAndAfterEach with DataFrameSuiteBase {
Now we want a quick "smoke test suite" on the codebase; therefore, let us (attempt) to exclude the testcases annotated by HugeTestClass :
Command line:
sbt test * -- -l HugeTestClass
OR maybe:
sbt 'testOnly * -- -l HugeTestClass'
Let us also attempt it within sbt itself:
sbt> testOnly * -- -l HugeTestClass
In all cases above we (unfortunately) still see:
[info] ItemsJobTest:
^C[info] - Run Items Pipeline *** FAILED *** (2 seconds, 796 milliseconds)
So the test actually did run.. contrary to the intention.
So what is the correct syntax / approach to apply a Tag Filter(/Exclusion) via sbt to scalatest classes?
You missed to put the testOnly part in double quote and also give full package to the Tag Annotation to ignore,
sbt "test-only * -- -l full.package.to.HugeTestClass"
example,
Tag annotation
package tags;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#org.scalatest.TagAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public #interface ExcludeMePleaseTag {}
Test to exclude
#tags.ExcludeMePleaseTag
class ExcludeMeSpecs extends FlatSpec with Matchers {
"I" should " not run" in {
888 shouldBe 1
}
}
to exclude the tests
sbt "test-only * -- -l tags.ExcludeMePleaseTag"
This github issue was helpful - https://github.com/harrah/xsbt/issues/357#issuecomment-44867814
But it does not work with static Tag annotation,
public class WrapperClass {
#org.scalatest.TagAnnotation
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD, ElementType.TYPE})
public static #interface ExcludeMePleaseTag {
}
}
sbt "test-only * -- -l tags.WrapperClass.ExcludeMePleaseTag"

Unix command to find the number of debug statements in a source code

How do i find the count of the number of debug statements that is without an if checking?
This is an example of a debug statement that has an if checking:
if(log.isDebug()){
log.debug("This is a debug statement");
}
This is an example of a standalone debug statement that does not have if checking:
log.debug("This is a debug statement");
For example, to find the number of debug statements, i would use this command:
grep -ir "debug" * | wc -l
Here is a simple-minded awk program that tries to find debug statements outside your if guards. Adapt it to count as needed.
/if.*log.isDebug/ {
inif=1
}
/}/ {
inif=0
}
/log.debug/ {
if (!inif) print
}
grep -ir "debug" * | grep -v "if" | wc -l

How do I pass parameters to a jar file at the time of execution?

How do I pass parameters to a JAR file at the time of execution?
To pass arguments to the jar:
java -jar myjar.jar one two
You can access them in the main() method of "Main-Class" (mentioned in the manifest.mf file of a JAR).
String one = args[0];
String two = args[1];
The JAVA Documentation says:
java [ options ] -jar file.jar [
argument ... ]
and
... Non-option arguments after the
class name or JAR file name are passed
to the main function...
Maybe you have to put the arguments in single quotes.
You can do it with something like this, so if no arguments are specified it will continue anyway:
public static void main(String[] args) {
try {
String one = args[0];
String two = args[1];
}
catch (ArrayIndexOutOfBoundsException e){
System.out.println("ArrayIndexOutOfBoundsException caught");
}
finally {
}
}
And then launch the application:
java -jar myapp.jar arg1 arg2
java [ options ] -jar file.jar [ argument ... ]
if you need to pass the log4j properties file use the below option
-Dlog4j.configurationFile=directory/file.xml
java -Dlog4j.configurationFile=directory/file.xml -jar <JAR FILE> [arguments ...]
Incase arguments have spaces in it, you can pass like shown below.
java -jar myjar.jar 'first argument' 'second argument'

Equivalent of *Nix 'which' command in PowerShell?

How do I ask PowerShell where something is?
For instance, "which notepad" and it returns the directory where the notepad.exe is run from according to the current paths.
The very first alias I made once I started customizing my profile in PowerShell was 'which'.
New-Alias which get-command
To add this to your profile, type this:
"`nNew-Alias which get-command" | add-content $profile
The `n at the start of the last line is to ensure it will start as a new line.
Here is an actual *nix equivalent, i.e. it gives *nix-style output.
Get-Command <your command> | Select-Object -ExpandProperty Definition
Just replace with whatever you're looking for.
PS C:\> Get-Command notepad.exe | Select-Object -ExpandProperty Definition
C:\Windows\system32\notepad.exe
When you add it to your profile, you will want to use a function rather than an alias because you can't use aliases with pipes:
function which($name)
{
Get-Command $name | Select-Object -ExpandProperty Definition
}
Now, when you reload your profile you can do this:
PS C:\> which notepad
C:\Windows\system32\notepad.exe
I usually just type:
gcm notepad
or
gcm note*
gcm is the default alias for Get-Command.
On my system, gcm note* outputs:
[27] » gcm note*
CommandType Name Definition
----------- ---- ----------
Application notepad.exe C:\WINDOWS\notepad.exe
Application notepad.exe C:\WINDOWS\system32\notepad.exe
Application Notepad2.exe C:\Utils\Notepad2.exe
Application Notepad2.ini C:\Utils\Notepad2.ini
You get the directory and the command that matches what you're looking for.
Try this example:
(Get-Command notepad.exe).Path
My proposition for the Which function:
function which($cmd) { get-command $cmd | % { $_.Path } }
PS C:\> which devcon
C:\local\code\bin\devcon.exe
A quick-and-dirty match to Unix which is
New-Alias which where.exe
But it returns multiple lines if they exist so then it becomes
function which {where.exe command | select -first 1}
I like Get-Command | Format-List, or shorter, using aliases for the two and only for powershell.exe:
gcm powershell | fl
You can find aliases like this:
alias -definition Format-List
Tab completion works with gcm.
To have tab list all options at once:
set-psreadlineoption -editmode emacs
This seems to do what you want (I found it on http://huddledmasses.org/powershell-find-path/):
Function Find-Path($Path, [switch]$All = $false, [Microsoft.PowerShell.Commands.TestPathType]$type = "Any")
## You could comment out the function stuff and use it as a script instead, with this line:
#param($Path, [switch]$All = $false, [Microsoft.PowerShell.Commands.TestPathType]$type = "Any")
if($(Test-Path $Path -Type $type)) {
return $path
} else {
[string[]]$paths = #($pwd);
$paths += "$pwd;$env:path".split(";")
$paths = Join-Path $paths $(Split-Path $Path -leaf) | ? { Test-Path $_ -Type $type }
if($paths.Length -gt 0) {
if($All) {
return $paths;
} else {
return $paths[0]
}
}
}
throw "Couldn't find a matching path of type $type"
}
Set-Alias find Find-Path
Check this PowerShell Which.
The code provided there suggests this:
($Env:Path).Split(";") | Get-ChildItem -filter notepad.exe
Try the where command on Windows 2003 or later (or Windows 2000/XP if you've installed a Resource Kit).
BTW, this received more answers in other questions:
Is there an equivalent of 'which' on Windows?
PowerShell equivalent to Unix which command?
If you want a comamnd that both accepts input from pipeline or as paramater, you should try this:
function which($name) {
if ($name) { $input = $name }
Get-Command $input | Select-Object -ExpandProperty Path
}
copy-paste the command to your profile (notepad $profile).
Examples:
❯ echo clang.exe | which
C:\Program Files\LLVM\bin\clang.exe
❯ which clang.exe
C:\Program Files\LLVM\bin\clang.exe
I have this which advanced function in my PowerShell profile:
function which {
<#
.SYNOPSIS
Identifies the source of a PowerShell command.
.DESCRIPTION
Identifies the source of a PowerShell command. External commands (Applications) are identified by the path to the executable
(which must be in the system PATH); cmdlets and functions are identified as such and the name of the module they are defined in
provided; aliases are expanded and the source of the alias definition is returned.
.INPUTS
No inputs; you cannot pipe data to this function.
.OUTPUTS
.PARAMETER Name
The name of the command to be identified.
.EXAMPLE
PS C:\Users\Smith\Documents> which Get-Command
Get-Command: Cmdlet in module Microsoft.PowerShell.Core
(Identifies type and source of command)
.EXAMPLE
PS C:\Users\Smith\Documents> which notepad
C:\WINDOWS\SYSTEM32\notepad.exe
(Indicates the full path of the executable)
#>
param(
[String]$name
)
$cmd = Get-Command $name
$redirect = $null
switch ($cmd.CommandType) {
"Alias" { "{0}: Alias for ({1})" -f $cmd.Name, (. { which $cmd.Definition } ) }
"Application" { $cmd.Source }
"Cmdlet" { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
"Function" { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
"Workflow" { "{0}: {1} {2}" -f $cmd.Name, $cmd.CommandType, (. { if ($cmd.Source.Length) { "in module {0}" -f $cmd.Source} else { "from unspecified source" } } ) }
"ExternalScript" { $cmd.Source }
default { $cmd }
}
}
Use:
function Which([string] $cmd) {
$path = (($Env:Path).Split(";") | Select -uniq | Where { $_.Length } | Where { Test-Path $_ } | Get-ChildItem -filter $cmd).FullName
if ($path) { $path.ToString() }
}
# Check if Chocolatey is installed
if (Which('cinst.bat')) {
Write-Host "yes"
} else {
Write-Host "no"
}
Or this version, calling the original where command.
This version also works better, because it is not limited to bat files:
function which([string] $cmd) {
$where = iex $(Join-Path $env:SystemRoot "System32\where.exe $cmd 2>&1")
$first = $($where -split '[\r\n]')
if ($first.getType().BaseType.Name -eq 'Array') {
$first = $first[0]
}
if (Test-Path $first) {
$first
}
}
# Check if Curl is installed
if (which('curl')) {
echo 'yes'
} else {
echo 'no'
}
You can install the which command from https://goprogram.co.uk/software/commands, along with all of the other UNIX commands.
If you have scoop you can install a direct clone of which:
scoop install which
which notepad
There also always the option of using which. there are actually three ways to access which from Windows powershell, the first (not necessarily the best) wsl -e which command (this requires installation of windows subsystem for Linux and a running distro). B. gnuwin32 which is a port of several gnu binaries in .exe format as standle alone bundled lanunchers option three, install msys2 (cross compiler platform) if you go where it installed in /usr/bin you'll find many many gnu utils that are more up-to-date. most of them work as stand alone exe and can be copied from the bin folder to your home drive somewhere amd added to your PATH.
There also always the option of using which. there are actually three ways to access which from Windows powershell
The first, (though not the best) is wsl(windows subsystem for linux)
wsl -e which command
This requires installation of windows subsystem for Linux and a running distro.
Next is gnuwin32 which is a port of several gnu binaries in .exe format as standle alone bundled lanunchers
Third, install msys2 (cross compiler platform) if you go where it installed in /usr/bin you'll find many many gnu utils that are more up-to-date. most of them work as stand alone exe and can be copied from the bin folder to your home drive somewhere amd added to your PATH.

Resources