Lazybones Project - “Lazybones” that works for you

  • Tutorial
I do not like Maven.
More than one article can be written about my passionate hatred of this thing, but today I want to talk about one very good feature of Maven - about archetypes. What is this you can read in the official documentation , in each of the tutorials on Maven on Habré ( 1 , 2 , 3 ), and indeed, you probably know yourself.

So, archetypes are cool, and it would be great if 1) they were in many projects with a standard structure. 2) it would be possible to fasten them to those who do not have them.

That's what Peter Ledbrook thought when he looked at the complete absence of archetypes in Ratpack . Then the Lazybones project was born- a tool for generating projects.

image

In this article I will tell you how to 1) Use Lazybones to generate projects for which templates have already been created. 2) Create new templates for any projects.

Using Existing Lazybones Templates

Then everything will be extremely short:
  1. Install Lazybones using GVM or download the distribution package from Bintray
  2. We look at what patterns exist using the command lazybones list(or study the repository )
  3. We study the information about the selected template using the command lazybones info <имя шаблона>(or read readme in packag-e of the template on Bintrey)
  4. Create a project team lazybones create <имя шаблона> <версия шаблона> <имя директории в которой создавать>

That's all, thank you for your attention, everyone is free. Although no, now we will do just interesting.

Creating your own project template

Since you are most likely familiar with the # 361 Maven archetype ( maven-archetype-quickstart ), we will do something similar (having recreated all the features, we will omit some repetitions).
Not only can you compare the number of downloaded Internet to create both projects, you can also compare the complexity of creating the template itself, because the process of creating the Maven archetype is perfectly described here .

So let's go.

What we want to achieve:
  • Create basic pom.xml with selected via the interactive command line groupId, artifactId and version
  • Create directories src / main / java, src / main / resources (the same for tests, but we will not, for simplicity's sake)
  • Create a class for the example, register the selected one through the interactive command line in it package and put it in the appropriate package directory (the same for the test, but we will not, for the simplicity of the example)
  • Generate in the class that main, when the test phase starts, print a message selected through the interactive command line
  • Assemble template
  • Create a project according to our template
  • Run mvn test
  • Profit


  1. To build the template, we need a Gradle script and a directory with templates. Since we are too lazy, we will run lazybones:
    >lazybones create lazybones-project lzb-templates
    As a result, we have the following:

    │ build.gradle // chalbon assembly script
    │ gradlew // script launch file for nyx
    │ gradlew.bat // script launch file for Windows
    │ README.md // file describing this project
    │
    ├───gradle // auxiliary directory for the script
    │
    └───templates // empty directory for our templates
    

  2. We go into the directory templates, create a sub-directory of our template in it, and begin to sculpt. Create a version file. It is called VERSIONand contains only a version, for example 0.1

    > mkdir maven-simple
    > cd maven simple
    > echo 0.1> VERSION
    

  3. In addition, you need to create readme.md, which will be shown after the creation of the project.
  4. Create a directory src/main/java, src/main/resources. In javaand resourcesof them we put on an empty file.retain

    ├───maven-simple
    │ │ README.md
    │ │ VERSION
    │ │
    │ └───src
    │ └───main
    │ ├───java
    │ │ .retain
    │ │
    │ └───resources
    │ .retain
    

  5. Now let's take care of the templates. Let's start with pom.xml:
    4.0.0${groupId}${artifactId}${version}org.codehaus.mojoexec-maven-plugin1.2.1testjava${pkg}.App${message}

    AAAAA !!!!!!!
    So, pulled ourselves together, look. Pay attention to all sorts ${...}. This is what we will change to the values ​​that the user will ask us at startup create. In essence, these are just Groovy Templates tokens . If you are familiar with Velocity, Freemarker or any other template handler, you will be familiar with everything. But more on that later.
    Hell hell in is just the start of a mainclass App. Please note that we are not yet aware of package this class and the parameter that we pass to main.
  6. Now look at the file App.java:
    package ${pkg};
    public class App {
        public static void main(String[] args) {
            System.out.println(args[0]);
        }
    }
    

    Here we have only one variable - again the same package. At the same time, we see that main prints the argument. This means that during the launch of the maven, in the test phase, we expect to see the message that the user selects, again, during create.
    So now we have all the directories and templates:
    │ App.java
    │ lazybones.groovy
    │ pom.xml
    │ README.md
    │ VERSION
    │
    └───src
        └───main
            ├───java
            │ .retain
            │
            └───resources
                    .retain
    

  7. And now the fun begins. It remains for us to write a post processor that will run after unpacking the directories. Tasks: 1) Find out everything the user needs, 2) transfer the java file to the directory corresponding to the package, 3) process the templates.
    The elegant Groove script will help us in this, of course:
    import static org.apache.commons.io.FileUtils.moveFileToDirectory
    Map props = [:]
    //метод ask принимает 2 параметра - сообщение, и значение по умолчанию.
    //он показывает сообщение и ждет ввода. Ввод (или значение по умолчанию, если ввод пустой) возвращается.
    props.groupId = ask('Выберите groupId [org.example]: ', 'org.example')
    props.artifactId = ask('Выберите artifactId [maven-simple]: ', 'maven-simple')
    props.version = ask('Выберите версию [1.0-SNAPSHOT]: ', '1.0-SNAPSHOT')
    props.pkg = ask("Выберите package для класса [$props.groupId]:", props.groupId)
    props.message = ask('Чего печатать в тесте? ', 'Привет, лентяй!')
    //метод processTemplates обрабатывает шаблоны, заменяя меаркеры значениями из мапы.
    processTemplates 'pom.xml', props
    //заменяем точки на слэши
    String packageDir = props.pkg.replaceAll(/\./, '/')
    //переносим исходник в нужную директорию
    moveFileToDirectory(new File(targetDir, 'App.java'), new File(targetDir, "src/main/java/$packageDir"), true)
    //обрабатываем шаблон
    processTemplates 'src/main/java/**/App.java', props
    

    I hope the comments explain what is happening quite clearly. The only thing that probably needs to be added is that the methods ask() and the processTemplates()field targetDirget into the script from the class uk.co.cacoethes.lazybones.LazybonesScript, which is a custom super-class of this script .
  8. It's time to collect. Lazybones has its own plugin for Gradle, which is already configured in the build script that we generated in step 1. This plugin defines task rules for building, installing in the local cache, and deploying templates to Bintray. Since the template is not serious, we won’t put it on Bintray, but it’s mandatory to install it in the cache to try to run it. We start assembly:
    >gradlew installTemplateMavenSimple
    :packageTemplateMavenSimple
    :installTemplateMavenSimple

    BUILD SUCCESSFUL
  9. Testing! We create a new directory and create a project from the template in it (as we have already seen): The
    >lazybones create maven-simple 0.1 maven-simple

    Creating project from template maven-simple 0.1 in 'maven-simple'
    Выберите groupId [org.example]: com.demo
    Выберите artifactId [maven-simple]:
    Выберите версию [1.0-SNAPSHOT]: 0.1
    Выберите package для класса [org.example]:org.simple
    Чего печатать в тесте? Привет, Хабр!

    Шаблон а-ля архетайп
    ---------------------------------
    Ты создал Мавеновский проект. Может хватит? Грейлд ждет тебя.

    Project created in maven-simple!

    message at the end comes, of course, from readme.md. Please note, I did not specify artifactId, expect maven-simpleby default.
    We go into the maven-simple directory, and admire:
    │ pom.xml
    │ README.md
    │
    └───src
        └───main
            ├───java
            │ └───org
            │ └───simple
            │ App.java
            │
            └───resources
    

    Open pom.xml:
    4.0.0com.demomaven-simple0.1org.codehaus.mojoexec-maven-plugin1.2.1testjavaorg.simple.AppПривет, Хабр!

    Everything is as it should. Open App.java:
    package org.simple;
    public class App {
        public static void main(String[] args) {
            System.out.println(args[0]);
        }
    }
    

    The same order. Launch Maven:
    > mvn test
    [INFO] Scanning for projects ...
    [INFO]
    [INFO] ----------------------------------------------- -------------------------
    [INFO] Building maven-simple 0.1
    [INFO] ----------------------------------------------- -------------------------
    [INFO]
    [INFO] --- maven-resources-plugin: 2.6: resources (default-resources) @ maven-simple ---
    [INFO] Copying 0 resource
    [INFO]
    [INFO] --- maven-compiler-plugin: 2.5.1: compile (default-compile) @ maven-simple ---
    [INFO] Nothing to compile - all classes are up to date
    [INFO]
    [INFO] --- maven-resources-plugin: 2.6: testResources (default-testResources) @ maven-simple ---
    [INFO]
    [INFO] --- maven-compiler-plugin: 2.5.1: testCompile (default-testCompile) @ maven-simple ---
    [INFO] No sources to compile
    [INFO]
    [INFO] --- maven-surefire-plugin: 2.12.4: test (default-test) @ maven-simple ---
    [INFO] No tests to run.
    [INFO]
    [INFO] >>> exec-maven-plugin: 1.2.1: java (default) @ maven-simple >>>
    [INFO]
    [INFO] <<< exec-maven-plugin: 1.2.1: java (default) @ maven-simple <<<
    [INFO]
    [INFO] --- exec-maven-plugin: 1.2.1: java (default) @ maven-simple ---
    Hello, Habr!
    [INFO] ----------------------------------------------- -------------------------
    [INFO] BUILD SUCCESS
    [INFO] ----------------------------------------------- -------------------------
    [INFO] Total time: 0.768s
    [INFO] Finished at: Fri Apr 04 02:54:57 IDT 2014
    [INFO] Final Memory: 7M / 304M
    [INFO] ----------------------------------------------- -------------------------
    


That's all. I hope you are imbued with simplicity and grace both creating projects from templates and creating the templates themselves in Lazybones. It seems to me that for these simplicity and grace it is in many ways necessary to thank Groovey.

Shameless PR, you can not read
If you liked and you agree with me on the account of grace and simplicity, and if you want to learn a little Groove yourself, then come to me for a training on April 15 in Kazan , or on April 17 in Moscow . I promise to teach Groovy buns.

Also popular now: