1 Nuts Library

nuts is a package manager that can be embedded in your application as a general purpose library. This library can affords lots of functionalities

1.1 Maven Dependency

to make use of nuts library you need add the dependency .thevpc.nuts#nuts-lib:0.8.5.0 and provide a hint to maven to point to the right repository https://maven.thevpc.net

Configure your pom.xml


    <dependencie>
        <dependency><groupId>net.thevpc.nuts</groupId><artifactId>nuts-lib</artifactId><version>0.8.5.0</version></dependency>
    </dependencie>
    <repositories>
        <repository><id>thevpc</id><url>https://maven.thevpc.net</url></repository>
    </repositories>
    

1.2 NCmdLine

nuts provides a useful commandline parser NCmdLine it supports command lines in the following forms


my-app -o=y --name='some name' -ex --extra value arg1 arg2

where the command here supports short and long options (short ones are -o, -e and -x, where -e and -x are combined as -ex), and of course non options or regular arguments (here arg1 and arg2). Not also that value could be interpreted as a value for --extra (or not; depending on how you configure your parser, for this option).

Short vs Long Options

Options can be long options (starts with double hyphen) or short options (start with a single hyphen). Many arguments support both forms. For instance "-w" and "--workspace" are the supported forms to define the workspace location in the nuts command.

Valued / Non-valued Options

Options can also support a value of type string or boolean. The value can be suffixed to the option while separated with '=' sign or immediately after the option. As an example, all are equivalent. Of course, not all options can support values, an not all options neither support the suffixed and/or the non-suffixed mode. Please relate to the documentation of nuts or the application you are using to know how to use the options.

Boolean Options

Particularly, when the value is a boolean, the value do not need to be defined. As a result "--install-companions" and "--install-companions=true" are equivalent. However "--install-companions true" is not (because the option is of type boolean) and "true" will be parsed as a NonOption.

To define a false value to the boolean option we can either suffix with =false or prefix with ! or ~ sign. Hence, =false, !install-companions and ~install-companions are all equivalent. Note also that ~ if referred to ! because in bash shells (and some other shells) ! will be expanded in a special manner.

Combo Simple Options

Simple options can be grouped in a single word. "-ls" is equivalent to "-l -s". So one should be careful. One exception though. For portability reasons, "-version" is considered a single short option.

Ignoring Options, Comments

Options starting with "-//" and "--//" are simply ignored by the command line parser.

Creating NCmdLine

Command line can either created manually or parsed. You can create a command by simply providing the arguments:

    NCmdLine c1= NCmdLine.ofArgs("ls","-l");
You can also create a commandline by parsing a string.

nuts supports multiple commandline dialects (bash/linux, bat/Windows,...)


    NCmdLine c1= NCmdLine.of("ls -l", NShellFamily.BASH);
When you do not specify the NShellFamily, runtime OS default is considered.

    NCmdLine c1= NCmdLine.parse("ls -l");

You would want to be portable across all operating systems, you can use ofDefault method.


    NCmdLine c1= NCmdLine.ofDefault("ls -l");

Configuring NCmdLine

setCommandName(true|false)

This method help defining the name of the command supporting this command line. This is helpful when generating errors/exception so that the message is relevant for instance, you would call ("ls"), so that all errors are in the form of unexpected argument --how

setExpandSimpleOptions(true|false)

This method can change the default behavior of NCmdLine (defaulted to true). When true, options in the form -ex are expanded to -e -x.

registerSpecialSimpleOption(argName)

This method limits setExpandSimpleOptions application so that for some options that start with - (simple options), they are not expanded. A useful example is '-version'. You wouldnt whant it ti be interpreted as '-v -e -r -s -i -o -n', would you?

setExpandArgumentsFile(true|false)

This method can change the default behavior of NCmdLine (defaulted to true). When false, options in the form @path/to/arg/file are not supported. When true (which is the default), the parser will load arguments from the given file.

Using CommandLine


NCmdLine cmdLine = yourCommandLine();
boolean boolOption = false;
String stringOption = null;
List  others = new ArrayList<>();
NArg a;
while (cmdLine. hasNext()) {
  a = cmdLine. peek().get();
  if (a.isOption()) {
      switch (a.key()) {
          case "-o":
          case "--option": {
              a = cmdLine. nextFlag().get(session);
              if (a.isEnabled()) {
                  boolOption = a.getBooleanValue().get(session);
              }
              break;
          }
          case "-n":
          case "--name": {
              a = cmdLine.nextEntry().get(session);
              if (a.isEnabled()) {
                  stringOption = a.getStringValue().get(session);
              }
              break;
          }
          default: {
              session. configureLast(cmdLine);
          }
      }
  } else {
      others. add(cmdLine. next().get().toString());
  }
}
NOut.println(NMsg. ofC("boolOption=%s stringOption=%s others=%s", boolOption, stringOption, others));

Using CommandLine, The recommended way...


NCmdLine cmdLine = NApp.of().getCmdLine();
NBooleanRef  boolOption = NRef.of(false);
NRef<String>  stringOption = NRef.ofNull();
List<String>  others = new ArrayList<>();
cmdLine.forEachPeek ((a,l,c)-> {
  if (a.isOption()) {
      switch (a.key()) {
          case "-o":
          case "--option": {
              cmdLine.withNextFlag((v, e, s)->boolOption.set(v));
              return true;
          }
          case "-n":
          case "--name": {
              cmdLine.withNextEntry((v, e, s)->stringOption.set(v));
              return true;
          }
      }
      return false;
  } else {
      nonOptions.add(l.next().get().toString());
      return true;
  }
});


1.3 NOptional

nuts introduces a concept very similar to java's Optional but with better extension builtin mechanisms and helper methods : NOptional

NOptional is extensively used in Nuts Package Manager itself.

Non Null Assertion

Java has a builtin null Check mechanism but it does not enable customized messages or exceptions. Optional are described as per Java's (c) Documentation "A container object which may or may not contain a non-null value". NOptional is more of an Object Wrapper than addes several useful null related operators like '??' '?.' and '!' in typescript.

    if(stringWord==null){
        throw new IllegalArgumentException("missing user name");
    }
    stringWord.toUpperCase()
 
   // expected : stringWord!..toUpperCase()
    NOptional.ofNamed(stringWord,"user name").get().toUpperCase();
    // will throw an IllegalArgumentException|NIllegalArgumentException with "missing user name" message;

Nullish Coalescing


    Number roadNumber=road.number!=null?road.number:10;
 
    // expected : var roadNumber=road.number??10;
    Number roadNumber=NOptional.of(road.number).orElse(10);

Optional Chaining


    Number roadNumber=(app!=null && app.person!=null && app.person.road!=null)? app.person.address.road.number:null;
 
    // expected var roadNumber=app?.person?.address?.road?.number;
    Number roadNumber=NOptional.of(app).then(v->v.person).then(v->v.road).then(v->v.number).orNull();

Combining Optional Chaining


    Address address=(app!=null && app.person!=null)?app.person.address:null;
    if(address==null){
       throw new IllegalArgumentException("missing address"); 
    }
    Number roadNumber=(address!=null 
        && address.road!=null)
        ? address.road.number:0;
 
    // expected : var roadNumber=app?.person?.address!.road?.number??0;
    Number roadNumber=NOptional.of(app).then(v->v.person).then(v->v.address).get().then(v->v.road).then(v->v.number).orElse(0);

1.4 NPath

nuts introduces a concept very similar to java's URL but with better extension builtin mechanisms and helper methods : NPath

supported formats/protocols are:
  • file format /path/to/to/resource or c:\path\to\resource

  • file URL file:/path/to/to/resource or file:c:/path/to/resource

  • http/https URLs (or any other Java supported URL) //some-url or //some-url

  • classpath classpath:/path/to/to/resource (you must provide the used classpath upon creation)

  • resource Path resource://groupId1:artifactId1#version1;groupId2:artifactId2#version2/path/to/resource or //(groupId1:artifactId1#version1;groupId2:artifactId2#version2)/path/to/resource in that case the resource is looked up in any of the artifact classpaths (including dependencies)


1.5 NStream

nuts introduces a concept very similar to java's Stream but with better extension builtin mechanisms and helper methods : NStream

NStream is actually a wrapper to java's Stream, Iterator and Iterable and you can create a stream using .of(...) methods.

NStream is extensively used in Search Command.


1.6 NSession

nuts session holds current configuration and options

To get the current session instance :

    NSession session=NSession.of();
To run with a different session instance :

    NSession session=NSession.of();
    session=session.copy().setConfirm(NConfirmationMode.ASK);
    session.runWith(()->{
        // here run with new options
    });
Here another example

    // share allows NSession/NWorkspace to be accessible globally as a singleton
    Nuts.openWorkspace("-Z","-S","y","--json").share();
    // then you can get the current session anywhere in your code
    NSession session=NSession.of();
    session.setConfirm(NConfirmationMode.ASK);
    session.setOutputFormat(NContentType.XML);

    NOut.println("Hello");
    NOut.printlnf("Hello");

    NOut.println(Arrays.asList("Hello"));
    NOut.printlnf("Hello %s","world");
    NOut.println(NMsg.ofC("Hello %s","world"));
    NOut.println(NMsg.ofJ("Hello {0}","world"));
    NOut.println(NMsg.ofV("Hello $v",NMaps.of("v","world"));

1.7 NMsg

nuts Library allows multiple variants of string interpolation


    NSession session=NSession.of();
    session.setConfirm(NConfirmationMode.ASK);
    session.setOutputFormat(NContentType.XML);

    NOut.println("Hello");
    NOut.printlnf("Hello");
    NOut.println(Arrays.asList("Hello"));
    NOut.printlnf("Hello %s","world");
    NOut.println(NMsg.ofC("Hello %s","world"));
    NOut.println(NMsg.ofJ("Hello {0}","world"));
    NOut.println(NMsg.ofV("Hello $v",NMaps.of("v","world"));

1.8 NOut/NErr

nuts Library suppors colorful and structured output


    Nuts.openWorkspace("-Z","-S","y","--json").share();
NSession session=NSession.of();
    NOut.println("Hello");
    NOut.printlnf("Hello");

    NOut.println(Arrays.asList("Hello"));
        NOut.printlnf("Hello");

    session.err()....;
    session.in()....;

    NOut.printlnf("#Hello1# ##Hello2## ##:_:Hello3## ");
    NOut.printlnf("
java public static class MyClass {}
");
    NOut.printlnf("
js public static class MyClass {}
");
    NOut.printlnf("
xml null
");
    NOut.printlnf("
json {a:'hello'}
");

    NErr.printlnf("#Hello1# ##Hello2## ##:_:Hello3## ");
    NErr.printlnf("
java public static class MyClass {}
");
    NErr.printlnf("
js public static class MyClass {}
");
    NErr.printlnf("
xml null
");
    NErr.printlnf("
json {a:'hello'}
");

    NSession session=...;
    class Customer{String id;String name;}
    Customer customer1,customer2,customer3; ...
    //
    session.setOutputFormat(NContentType.JSON).out().printlnf(Arrays.asList(customer1,customer2,customer3))
    session.setOutputFormat(NContentType.TREE).out().printlnf(Arrays.asList(customer1,customer2,customer3))
    session.setOutputFormat(NContentType.PLAIN).out().printlnf(Arrays.asList(customer1,customer2,customer3))
    session.setOutputFormat(NContentType.XML).out().printlnf(Arrays.asList(customer1,customer2,customer3))
    session.setOutputFormat(NContentType.PROPS).out().printlnf(Arrays.asList(customer1,customer2,customer3))
    NOut.printlnf(Arrays.asList(customer1,customer2,customer3))

Working with Tables


    NSession session=...;
    Object a,b,c,d; ...
    NMutableTableModel m = NMutableTableModel.of();
    m.newRow().addCells(a,b,c,d);
    NOut.printlnf(m);

Working with Trees


    NSession session=...;
    Object a,b,c,d; ...
    NMutableTableModel m = NMutableTableModel.of();
    m.newRow().addCells(a,b,c,d);
    NOut.printlnf(m);

1.9 IO

nuts Library allows multiple variants of string interpolation

NCp


    NCp.of()
        .from("http://my-server.com/file.pdf")
        .to("/home/my-file")
        .setProgressMonitor(true)
        .setValidator((in)->checkSHA1Hash(in))
        .run();

    NPs ps=NPs.of()
        if(ps.isSupportedKillProcess()){
            ps.killProcess("1234");
        }

NCompress/NUncompress


    NCompress aa = NCompress.of()
        .setTarget(options.outZip);
        for (NPath file : options.files) {
        aa.addSource(file);
        }
        aa.run();
        

    NUncompress.of()
                    .from(is)
                    .visit(new NUncompressVisitor() {
    @Override
    public boolean visitFolder(String path) {
        return true;
    }

    @Override
    public boolean visitFile(String path, InputStream inputStream) {
        if ("META-INF/MANIFEST.MF".equals(path)) {
            ...
        } else) {
            ...
        }
        return true;
    }
}).run();

NDigest


   String digest=NDigest.of().setSource(x.getPath().getBytes()).computeString();
}).run();

1.10 Exec/Ps

nuts Library simplify creating and manipulating processes

To create a new process


    NSession session=Nuts.openWorkspace("-Z","-S");
int code=NExecCmd.of("ls", "-l").system().getResult();
String out=NExecCmd.of("nsh", "ls","--table")
        .getOutputString();

Find processes

NPs ps=NPs.of(); List null

1.11 NExpr

nuts expressions


NExprMutableDeclarations expr = NExprs.of().newMutableDeclarations();
NExprNode n1 = expr.parse("1+2*3").get();
NExprNode n = expr.parse("a.b>1").get();

NExprs nExprs = NExprs.of();
NDocNExprVar v = new NDocNExprVar();
decl = nExprs.newMutableDeclarations(true, new NExprEvaluator() {
    @Override
    public NOptional<NExprVar> getVar(String varName, NExprDeclarations context2) {
        return NOptional.of(new MyVar());
    }
});

decl.declareConstant("cwd", System.getProperty("user.dir"));
decl.declareFunction("myfct", new MyFct());

1.12 Spring Boot Integration

nuts can work flawlessly with spring boot applications. You just need one dependency and implement a NApplication interface. Add the following dependency to you spring boot project

    <dependency>
        <groupId>net.thevpc.nuts</groupId>
        <artifactId>nuts-spring-boot</artifactId>
        <version>0.8.5.0</version>
    </dependency>

Implement interface NApplication in your SpringBootApplication top class.


@SpringBootApplication
@Import(NutsSpringBootConfig.class)
public class AppExample implements NApplication {
    public static void main(String[] args) {
        SpringApplication.run(AppExample.class, args);
    }

    @Override
    public void run() {
        NOut.println("Hello ##World##");
    }
}
Now you can inject Nuts objects in your beans

@Component
public class MyBean {
    @Autowired NSession session;
    @Autowired NWorkspace workspace;
    @Autowired NElements elems;
    @Autowired NIO nio;
    @Autowired NScheduler scheduler;
    @Autowired NTerminal term;
    @Autowired NPrintStream out;
}



2 Nuts Application Framework

nuts is a package manager that can be embedded in your application and hence present a solid Application Framework and tooling to make the applicable more robust and more portable.

nuts as a Framework :

  • Adds support for Application Lifecycle (Hooks for install, update, uninstall)
  • Adds support for auto update
  • Adds support for isolated input/output (via session in/out)
  • Adds support for Desktop Integration
    • Adds Shortcuts, Menus
    • Adds Aliases
  • Adds support for Base Directory API
    • API to manage per application directories (log, cache, config,...)
  • Adds support for Base Commandline API
    • standardized commandline options
    • inherit common options (--table, --json, ...)

2.1 Nuts Application Framework

Using Nuts Application Framework (NAF)

Using nuts is transparent as we have seen so far. It's transparent both at build time and runtime. However, nuts can provide our application a set of unique helpful features, such as install and uninstall hooks, comprehensive command line support and so on.

To create your first NAF application, you will need to add nuts as a dependency and change your pom.xml as follows:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>net.thevpc.nuts</groupId>
            <artifactId>nuts-lib</artifactId>
            <version>0.8.5.0</version>
        </dependency>
        <dependency>
            <groupId>jexcelapi</groupId>
            <artifactId>jxl</artifactId>
            <version>2.4.2</version>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <nuts.application>true</nuts.application>
    </properties>
</project> 

Please take note that we have added a property nuts.application=true. Actually this is not mandatory, but this will help nuts package manager detect that this application uses NAF before downloading its jar (the information will be available in the .xml descriptor on the remote repository).

Then we will add some cool features to our application. We write a dummy message whenever the application is installed, uninstalled or updated. We will also add support to "--file=[path]" argument to specify the workbook path.

package com.mycompany.app;

import java.io.File;

import jxl.Workbook;
import jxl.write.WritableWorkbook;

public class App implements NApplication {

    public static void main(String[] args) {
        // just create an instance and call runAndExit in the main method
        // this method ensures that exist code is well propagated
        // from exceptions to caller processes
        new App().run(NAppRunOptions.ofExit(args));
    }

    @Override
    public void run() {
        NCmdLine cmd = NApp.of().getCmdLine();
        File file = new File("file.xls");
        while (cmd.hasNext()) {
            switch (cmd.getKey().getString()) {
                case "--file": {
                    NArg a = cmd.nextEntry().get();
                    file = new File(a.getStringValue());
                    break;
                }
                case "--fill": {
                    // process other options here ...
                    break;
                }
                default: {
                    s.configureLast(cmd);
                }
            }
        }
        try {
            WritableWorkbook w = Workbook.createWorkbook(file);
            s.out().printf("Workbook just created at %s%n", file);
        } catch (Exception ex) {
            ex.printStackTrace(s.err());
        }
    }

    @Override // this method is not required, implement when needed
    public void onInstallApplication() {
        NOut.println(NMsg.ofC("we are installing My Application : %s%n", NApp.of().getId()));
    }

    @Override // this method is not required, implement when needed
    public void onUninstallApplication(NSession s) {
        NOut.println(NMsg.ofC("we are uninstalling My Application : %s%n", NApp.of().getId()));
    }

    @Override // this method is not required, implement when needed
    public void onUpdateApplication(NSession s) {
        NOut.println(NMsg.ofC("we are updating My Application : %s%n", NApp.of().getId()));
    }
}

Now we can install or uninstall the application and see the expected messages.

nuts -y install com.mycompany.app:my-app
nuts -y uninstall com.mycompany.app:my-app

2.2 Your first Application using nuts

Running your application with Nuts

Lets take, step by step, an example of an application that you will run using nuts package manager

First we can create the project using your favourite IDE or using simply mvn command


mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-simple -DarchetypeVersion=1.4 -DinteractiveMode=false
We will have a fully generated java project

~/> tree
.
└── my-app
    ├── pom.xml
    └── src
        ├── main
        │   └── java
        │       └── com
        │           └── mycompany
        │               └── app
        │                   └── App.java
        └── test
            └── java
                └── com
                    └── mycompany
                        └── app
                            └── AppTest.java

Now we will add some dependencies to the project. Let's add jexcelapi:jxl#2.4.2 and update pom.xml consequently.


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>jexcelapi</groupId>
            <artifactId>jxl</artifactId>
            <version>2.4.2</version>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>
</project> 
Now we update the App.java file

package com.mycompany.app;

import java.io.File;

import jxl.Workbook;
import jxl.write.WritableWorkbook;

public class App {

    public static void main(String[] args) {
        try {
            WritableWorkbook w = Workbook.createWorkbook(new File("any-file.xls"));
            System.out.println("Workbook just created");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}

finally we compile the app:

mvn clean install

Of course, we won't be able to run the application yet. Would we? For this app to work there are several ways, all of them are complicated and require modifying the pom.xml and even modifying the output jar. we can for instance generate an output lib directory and update the META-INF file using maven-dependency-plugin. (see https://maven.apache.org/plugins/maven-shade-plugin ; https://www.baeldung.com/executable-jar-with-maven). We could also use maven-assembly-plugin to include the dependencies into the jar itself ('what the fat' jar!). Another alternative is to use an uglier solution with maven-shade-plugin and blend libraries into the main jar. In all cases we need as well to configure maven-jar-plugin to specify the main class file.

I am not exposing all solutions here. You can read this article for more details (https://www.baeldung.com/executable-jar-with-maven) but trust me, they all stink.Instead of that we will use nuts. In that case, actually we are already done, the app is already OK! We do not need to specify the main class neither are we required to bundle jxl and its dependencies. We only need to run the app. That's it.

Basically, you can install the application using its identifier com.mycompany.app:my-app. The latest version will be resolved.


nuts install com.mycompany.app:my-app
nuts my-app
This will install the application and run it on the fly. Dependencies will be detected, resolved and downloaded. The application is installed from local maven repository. It needs to be deployed to a public repository for it to be publicly accessible, however. We can also choose not to install the app and bundle it as a jar. No need for a public repository in that case:

nuts -y com my-app-1.0.0-SNAPSHOT.jar

As we can see, nuts provides the simplest and the most elegant way to deploy your application.

One question though. what happens if we define multiple main methods (in multiple public classes). It's handled as well by nuts seamlessly. It just asks, at runtime, for the appropriate class to run.

Using Nuts Application Framework

Using nuts is transparent as we have seen so far. It's transparent both at build time and runtime. However, nuts can provide our application a set of unique helpful features, such as install and uninstall hooks, comprehensive command line support and so on.

To create your first NAF application, you will need to add nuts as a dependency and change your pom.xml as follows:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.mycompany.app</groupId>
    <artifactId>my-app</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>net.thevpc.nuts</groupId>
            <artifactId>nuts-lib</artifactId>
            <version>0.8.5.0</version>
        </dependency>
        <dependency>
            <groupId>jexcelapi</groupId>
            <artifactId>jxl</artifactId>
            <version>2.4.2</version>
        </dependency>
    </dependencies>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <nuts.application>true</nuts.application>
    </properties>
</project> 

Please take note that we have added a property nuts.application=true. Actually this is not mandatory, but this will help nuts package manager detect that this application uses NAF before downloading its jar (the information will be available in the .xml descriptor on the remote repository).

Then we will add some cool features to our application. We write a dummy message whenever the application is installed, uninstalled or updated. We will also add support to "--file=[path]" argument to specify the workbook path.

package com.mycompany.app;

import java.io.File;

import jxl.Workbook;
import jxl.write.WritableWorkbook;

public class App implements NApplication {

    public static void main(String[] args) {
        // just create an instance and call runAndExit in the main method
        // this method ensures that exist code is well propagated
        // from exceptions to caller processes
        new App().run(NAppRunOptions.ofExit(args));
    }

    @Override
    public void run() {
        NCmdLine cmd = NApp.of().getCmdLine();
        File file = new File("file.xls");
        while (cmd.hasNext()) {
            switch (cmd.getKey().getString()) {
                case "--file": {
                    NArg a = cmd.nextEntry().get();
                    file = new File(a.getStringValue());
                    break;
                }
                case "--fill": {
                    // process other options here ...
                    break;
                }
                default: {
                    s.configureLast(cmd);
                }
            }
        }
        try {
            WritableWorkbook w = Workbook.createWorkbook(file);
            s.out().printf("Workbook just created at %s%n", file);
        } catch (Exception ex) {
            ex.printStackTrace(s.err());
        }
    }

    @Override // this method is not required, implement when needed
    public void onInstallApplication() {
        NOut.println(NMsg.ofC("we are installing My Application : %s%n", NApp.of().getId()));
    }

    @Override // this method is not required, implement when needed
    public void onUninstallApplication(NSession s) {
        NOut.println(NMsg.ofC("we are uninstalling My Application : %s%n", NApp.of().getId()));
    }

    @Override // this method is not required, implement when needed
    public void onUpdateApplication(NSession s) {
        NOut.println(NMsg.ofC("we are updating My Application : %s%n", NApp.of().getId()));
    }
}

Now we can install or uninstall the application and see the expected messages.

nuts -y install com.mycompany.app:my-app
nuts -y uninstall com.mycompany.app:my-app

2.3 Command Line Arguments

nuts supports a specific format for command line arguments. This format is the format supported in nuts Application Framework (NAF) and as such all NAF applications support the same command line arguments format. Arguments in nuts can be options or non options. Options always start with hyphen (-).

Nuts Application Framework CommandLine

Application Command line can be retrieved via NApp instance:


    NCmdLine c1= NApp.of().getCmdine();

Exec / Autocomplete modes


    NCmdLine c= NApp.of().getCmdine();
    if(c.isExecMode()){
        ///    
    }

Default Options

All Applications inherit some default and useful options (see Nuts Command Line options for details). These options affect current session behaviour.
  • -T
  • --output-format-option
  • -O
  • --output-format
  • --tson
  • --yaml
  • --json
  • --props
  • --plain
  • --table
  • --tree
  • --xml
  • -y
  • --yes
  • --ask
  • -n
  • --no
  • --error
  • --trace
  • --solver
  • --progress
  • --debug
  • -f
  • --fetch
  • -a
  • --anywhere
  • -F
  • --offline
  • --online
  • --remote
  • -c
  • --color
  • -B
  • --bot
  • --dry
  • -D
  • --out-line-prefix
  • --err-line-prefix
  • --line-prefix
    
    * 
- - embedded

* 
- b

* 
- - external

* 
- - spawn

* 
- x

* 
- - system

* 
- - current-user

* 
- - as-root

* 
- - sudo

* 
- - as-user

* 
- - verbose

* 
- - log-verbose

* 
- - log-finest

* 
- - log-finer

* 
- - log-fine

* 
- - log-info

* 
- - log-warning

* 
- - log-severe

* 
- - log-config

* 
- - log-all

* 
- - log-off

* 
- - log-term-verbose

* 
- - log-term-finest

* 
- - log-term-finer

* 
- - log-term-fine

* 
- - log-term-info

* 
- - log-term-warning

* 
- - log-term-severe

* 
- - log-term-config

* 
- - log-term-all

* 
- - log-term-off

* 
- - log-file-verbose

* 
- - log-file-finest

* 
- - log-file-finer

* 
- - log-file-fine

* 
- - log-file-info

* 
- - log-file-warning

* 
- - log-file-severe

* 
- - log-file-config

* 
- - log-file-all

* 
- - log-file-off

* 
- - log-file-size

* 
- - log-file-name

* 
- - log-file-base

* 
- - log-file-count

* 
- ?

* 
- h

* 
- - help

* 
- - skip-event

* 

--version


2.4 Nuts Descriptor Integration

Nuts Descriptor Integration

  • Seamless integration
  • Maven Solver

Nuts and Maven

  • nuts.executable=<true|false> : when true the artifact is an executable (contains main class)

  • nuts.application=<true|false> : when true the artifact is an executable application (implements NutsApplication)

  • nuts.gui=<true|false> : when true the requires a gui environment to execute

  • nuts.term=<true|false> : when true the artifact is a command line executable

  • nuts.icons=<icon-path-string-array> : an array (separated with ',' or new lines) of icon paths (url in the NPath format)

  • nuts.genericName=<genericNameString> : a generic name for the application like 'Text Editor'

  • nuts.<os>-os-dependencies : list (':',';' or line separated) of short ids of dependencies that shall be appended to classpath only if running on the given os (see NutsOsFamily). This is a ways more simple than using the builtin ' profile' concept of Maven (which is of course supported as well)

  • nuts.<arch>-arch-dependencies : list (':',';' or line separated) of short ids of dependencies that shall be appended to classpath only if running on the given hardware architecture (see NutsArchFamily). This is a ways more simple than using the builtin 'profile' concept of Maven (which is of course supported as well)

  • nuts.<os>-os-<arch>-arch-dependencies : list (':',';' or line separated) of short ids of dependencies that shall be appended to classpath only if running on the given hardware architecture and os family


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>your-group</groupId>
    <artifactId>your-project</artifactId>
    <version>1.2.3</version>
    <packaging>jar</packaging>
    <properties>
        <!--properties having special meanings in Nuts-->
        <maven.compiler.target>1.8</maven.compiler.target>

        <!--properties specific to nuts for developers extending nuts-->
        <nuts.runtime>true</nuts.runtime> <!--if you implement a whole new runtime-->
        <nuts.extension>true</nuts.extension> <!--if you implement an extension-->

        <!--other properties specific to nuts-->
        <nuts.genericName>A Generic Name</nuts.genericName>
        <nuts.executable>true</nuts.executable>
        <nuts.application>true</nuts.application>
        <nuts.gui>true</nuts.gui>
        <nuts.term>true</nuts.term>

        <nuts.categories>
            /Settings/YourCategory
        </nuts.categories>
        <nuts.icons>
            classpath://net/yourpackage/yourapp/icon.svg
            classpath://net/yourpackage/yourapp/icon.png
            classpath://net/yourpackage/yourapp/icon.ico
        </nuts.icons>
        <nuts.windows-os-dependencies>
            org.fusesource.jansi:jansi
            com.github.vatbub:mslinks
        </nuts.windows-os-dependencies>
        <nuts.windows-os-x86_32-arch-dependencies>
            org.fusesource.jansi:jansi
            com.github.vatbub:mslinks
        </nuts.windows-os-x86_32-arch-dependencies>
    </properties>

    <dependencies>
    </dependencies>
</project>

Nuts and Java MANIFEST.MF



Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: vpc
Created-By: Apache Maven 3.8.1
Build-Jdk: 1.8.0_302

Nuts-Id: groupid:artifactid#version
Nuts-Dependencies: org.fusesource.jansi:jansi#1.2?os=windows;com.github.vatbub:mslinks#1.3?os=windows
Nuts-Name: Your App Name
Nuts-Generic-Name: Your App Generic Name
Nuts-Description: Your App Description
Nuts-Categories: /Settings/YourCategory;/Settings/YourCategory2
Nuts-Icons: classpath://net/yourpackage/yourapp/icon.svg;classpath://net/yourpackage/yourapp/icon.png
Nuts-Property-YourProp: YourValue

Comment: if the Nuts-Id could not be found, best effort will be used from the following
Automatic-Module-Name: yourgroupid.yourartifactid.YourClass
Main-Class: groupid.artifactid.YourClass
Implementation-Version: 1.2.3

Nuts and Java 9 (jdeps)

Nuts supports Automatic-Module-Name.


Automatic-Module-Name: yourgroupid.yourartifactid.YourClass

Nuts and Gradle (TODO)