diff --git a/README.adoc b/README.adoc new file mode 100644 index 00000000..09f549cd --- /dev/null +++ b/README.adoc @@ -0,0 +1,393 @@ +// Do not edit this file (e.g. go instead to docs/src/main/asciidoc) + + +Spring Cloud Vault Config provides client-side support for externalized configuration in a distributed system. With https://www.vaultproject.io[Hashicorp's Vault] you have a central place to manage external secret properties for applications across all environments. Vault can manage static and dynamic secrets such as username/password for remote applications/resources and provide credentials for external services such as MySQL, PostgreSQL, Apache Cassandra, Consul, AWS and more. + +== Features + +=== Spring Cloud Vauld Config Client + +Specifically for Spring applications: + +* Bind to the Config Server and initialize Spring `Environment` with remote property sources +* Obtain secrets secured with SSL +* https://www.vaultproject.io/docs/auth/token.html[Token] and https://www.vaultproject.io/docs/auth/app-id.html[AppId] authentication +* Bootstrap application context: a parent context for the main application that can be trained to do anything + +== Quick Start + +Install Vault: + +---- +$ src/test/bash/install_vault.sh +---- + +Start the Vault server: + +---- +$ src/test/bash/local_run_vault.sh +---- + +Vault is started listening on `0.0.0.0:8200` using the `inmem` storage. +Vault is sealed and not initialized when starting up +so you need to initialize it first. + +---- +$ export VAULT_ADDR="http://localhost:8200" +$ export VAULT_TLS_SKIP=true +$ vault init +---- + +You should see something like: + +---- +Key 1: 7149c6a2e16b8833f6eb1e76df03e47f6113a3288b3093faf5033d44f0e70fe701 +Key 2: 901c534c7988c18c20435a85213c683bdcf0efcd82e38e2893779f152978c18c02 +Key 3: 03ff3948575b1165a20c20ee7c3e6edf04f4cdbe0e82dbff5be49c63f98bc03a03 +Key 4: 216ae5cc3ddaf93ceb8e1d15bb9fc3176653f5b738f5f3d1ee00cd7dccbe926e04 +Key 5: b2898fc8130929d569c1677ee69dc5f3be57d7c4b494a6062693ce0b1c4d93d805 +Initial Root Token: 19aefa97-cccc-bbbb-aaaa-225940e63d76 + +Vault initialized with 5 keys and a key threshold of 3. Please +securely distribute the above keys. When the Vault is re-sealed, +restarted, or stopped, you must provide at least 3 of these keys +to unseal it again. + +Vault does not store the master key. Without at least 3 keys, +your Vault will remain permanently sealed. +---- + +Vault will initialize and return a set of unsealing keys and the root token. +Pick 3 keys and unseal Vault. Store the Vault token in the `VAULT_TOKEN` + environment variable. + +---- +$ vault unseal (Key 1) +$ vault unseal (Key 2) +$ vault unseal (Key 3) +$ export VAULT_TOKEN=(Root token) +---- + +Spring Cloud Vault accesses different resources. By default, the secret +backend is enabled which accesses secret config settings via JSON endpoints. + +The HTTP service has resources in the form: + +---- +/secret/{application} +/secret/{application},{profile} +/secret/{defaultContext} +/secret/{defaultContext},{profile} +---- + +where the "application" is injected as the `spring.application.name` in the +`SpringApplication` (i.e. what is normally "application" in a regular +Spring Boot app), "profile" is an active profile (or comma-separated +list of properties). Properties retrieved from Vault will be used "as-is" +without further prefixing of the property names. + +== Client Side Usage + +To use these features in an application, just build it as a Spring +Boot application that depends on spring-cloud-vault-config (e.g. see +the test cases). Example Maven configuration: + +[source,xml,indent=0] +.pom.xml +---- + + org.springframework.boot + spring-boot-starter-parent + 1.3.3.RELEASE + + + + + + org.springframework.cloud + spring-cloud-vault-config + x.y.z + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +---- + +Then you can create a standard Spring Boot application, like this simple HTTP server: + +---- +@SpringBootApplication +@RestController +public class Application { + + @RequestMapping("/") + public String home() { + return "Hello World!"; + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} +---- + +When it runs it will pick up the external configuration from the +default local config server on port `8200` if it is running. To modify +the startup behaviour you can change the location of the Vault server +using `bootstrap.properties` (like `application.properties` but for +the bootstrap phase of an application context), e.g. + +[source,yaml] +---- +spring.cloud.vault: + enabled: true + token: vault-token +---- + +=== AppId authentication + +Vault supports https://www.vaultproject.io/docs/auth/app-id.html[AppId] +authentication that consists of two hard to guess tokens. The AppId +defaults to `spring.application.name` that is statically configured. +The second token is the UserId which is a part determined by the application, +usually related to the runtime environment. IP address, Mac address or a +Docker container name are good examples. Spring Cloud Vault Config supports +IP address, Mac address and static UserId's (e.g. supplied via System properties). +The IP and Mac address are represented as Hex-encoded SHA256 hash. + +IP address-based UserId's use the local host's IP address. + +[source,yaml] +.bootstrap.yml using SHA256 IP-Address UserId's +---- +spring.cloud.vault: + enabled: true + authentication: APPID + app-id: + user-id: IP_ADDRESS +---- + +The corresponding command to generate the IP address UserId from a command line is: + +---- +$ echo -n 192.168.99.1 | sha256sum +---- +NOTE: Including the line break of `echo` leads to a different hash value +so make sure to include the `-n` flag. + +Mac address-based UserId's obtain their network device from the +localhost-bound device. The configuration also allows specifying +a `network-interface` hint to pick the right device. The value of +`network-interface` is optional and can be either an interface +name or interface index (0-based). + +[source,yaml] +.bootstrap.yml using SHA256 Mac-Address UserId's +---- +spring.cloud.vault: + enabled: true + authentication: APPID + app-id: + user-id: MAC_ADDRESS + network-interface: eth0 +---- + +The corresponding command to generate the IP address UserId from a command line is: + +---- +$ echo -n 0AFEDE1234AC | sha256sum +---- + +NOTE: The Mac address is specified uppercase and without colons. +Including the line break of `echo` leads to a different hash value +so make sure to include the `-n` flag. + +== Building + +:jdkversion: 1.7 + +=== Basic Compile and Test + +To build the source you will need to install JDK {jdkversion}. + +Spring Cloud uses Maven for most build-related activities, and you +should be able to get off the ground quite quickly by cloning the +project you are interested in and typing + +---- +$ ./mvnw install +---- + +NOTE: You can also install Maven (>=3.3.3) yourself and run the `mvn` command +in place of `./mvnw` in the examples below. If you do that you also +might need to add `-P spring` if your local Maven settings do not +contain repository declarations for spring pre-release artifacts. + +NOTE: Be aware that you might need to increase the amount of memory +available to Maven by setting a `MAVEN_OPTS` environment variable with +a value like `-Xmx512m -XX:MaxPermSize=128m`. We try to cover this in +the `.mvn` configuration, so if you find you have to do it to make a +build succeed, please raise a ticket to get the settings added to +source control. + +For hints on how to build the project look in `.travis.yml` if there +is one. There should be a "script" and maybe "install" command. Also +look at the "services" section to see if any services need to be +running locally (e.g. mongo or rabbit). Ignore the git-related bits +that you might find in "before_install" since they're related to setting git +credentials and you already have those. + +The projects that require middleware generally include a +`docker-compose.yml`, so consider using +http://compose.docker.io/[Docker Compose] to run the middeware servers +in Docker containers. See the README in the +https://github.com/spring-cloud-samples/scripts[scripts demo +repository] for specific instructions about the common cases of mongo, +rabbit and redis. + +NOTE: If all else fails, build with the command from `.travis.yml` (usually +`./mvnw install`). + +=== Documentation + +The spring-cloud-build module has a "docs" profile, and if you switch +that on it will try to build asciidoc sources from +`src/main/asciidoc`. As part of that process it will look for a +`README.adoc` and process it by loading all the includes, but not +parsing or rendering it, just copying it to `${main.basedir}` +(defaults to `${basedir}`, i.e. the root of the project). If there are +any changes in the README it will then show up after a Maven build as +a modified file in the correct place. Just commit it and push the change. + +=== Working with the code +If you don't have an IDE preference we would recommend that you use +http://www.springsource.com/developer/sts[Spring Tools Suite] or +http://eclipse.org[Eclipse] when working with the code. We use the +http://eclipse.org/m2e/[m2eclipe] eclipse plugin for maven support. Other IDEs and tools +should also work without issue. + +==== Importing into eclipse with m2eclipse +We recommend the http://eclipse.org/m2e/[m2eclipe] eclipse plugin when working with +eclipse. If you don't already have m2eclipse installed it is available from the "eclipse +marketplace". + +Unfortunately m2e does not yet support Maven 3.3, so once the projects +are imported into Eclipse you will also need to tell m2eclipse to use +the `.settings.xml` file for the projects. If you do not do this you +may see many different errors related to the POMs in the +projects. Open your Eclipse preferences, expand the Maven +preferences, and select User Settings. In the User Settings field +click Browse and navigate to the Spring Cloud project you imported +selecting the `.settings.xml` file in that project. Click Apply and +then OK to save the preference changes. + +NOTE: Alternatively you can copy the repository settings from https://github.com/spring-cloud/spring-cloud-build/blob/master/.settings.xml[`.settings.xml`] into your own `~/.m2/settings.xml`. + +==== Importing into eclipse without m2eclipse +If you prefer not to use m2eclipse you can generate eclipse project metadata using the +following command: + +[indent=0] +---- + $ ./mvnw eclipse:eclipse +---- + +The generated eclipse projects can be imported by selecting `import existing projects` +from the `file` menu. + +==== Adding Project Lombok Agent + +Spring Cloud uses http://projectlombok.org/features/index.html[Project Lombok] +to generate getters and setters etc. Compiling from the command line this +shouldn't cause any problems, but in an IDE you need to add an agent +to the JVM. Full instructions can be found in the Lombok website. The +sign that you need to do this is a lot of compiler errors to do with +missing methods and fields, e.g. + +[indent=0] +---- +The method getInitialStatus() is undefined for the type EurekaInstanceConfigBean EurekaDiscoveryClientConfiguration.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka line 120 Java Problem +The method getInitialStatus() is undefined for the type EurekaInstanceConfigBean EurekaDiscoveryClientConfiguration.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka line 121 Java Problem +The method setNonSecurePort(int) is undefined for the type EurekaInstanceConfigBean EurekaDiscoveryClientConfiguration.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka line 112 Java Problem +The type EurekaInstanceConfigBean.IdentifyingDataCenterInfo must implement the inherited abstract method DataCenterInfo.getName() EurekaInstanceConfigBean.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/eureka line 131 Java Problem +The method getId() is undefined for the type ProxyRouteLocator.ProxyRouteSpec PreDecorationFilter.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre line 60 Java Problem +The method getLocation() is undefined for the type ProxyRouteLocator.ProxyRouteSpec PreDecorationFilter.java /spring-cloud-netflix-core/src/main/java/org/springframework/cloud/netflix/zuul/filters/pre line 55 Java Problem +---- + +==== Importing into Intellij +Spring Cloud projects use annotation processing, particularly Lombok, which requires configuration +or you will encounter compile problems. It also needs a specific version of maven and a profile +enabled. Intellij 14.1+ requires some configuration to ensure these are setup properly. + + 1. Click Preferences, Plugins. *Ensure Lombok is installed* + 2. Click New, Project from Existing Sources, choose your spring-cloud project directory + 3. Choose Maven, and select Environment Settings. *Ensure you are using Maven 3.3.3* + 4. In the next screen, *Select the profile `spring`* click Next until Finish. + 5. Click Preferences, "Build, Execution, Deployment", Compiler, Annotation Processors. *Click Enable Annotation Processing* + 6. Click Build, Rebuild Project, and you are ready to go! + +==== Importing into other IDEs +Maven is well supported by most Java IDEs. Refer to you vendor documentation. + + +== Contributing + +Spring Cloud is released under the non-restrictive Apache 2.0 license, +and follows a very standard Github development process, using Github +tracker for issues and merging pull requests into master. If you want +to contribute even something trivial please do not hesitate, but +follow the guidelines below. + +=== Sign the Contributor License Agreement +Before we accept a non-trivial patch or pull request we will need you to sign the +https://support.springsource.com/spring_committer_signup[contributor's agreement]. +Signing the contributor's agreement does not grant anyone commit rights to the main +repository, but it does mean that we can accept your contributions, and you will get an +author credit if we do. Active contributors might be asked to join the core team, and +given the ability to merge pull requests. + +=== Code of Conduct +This project adheres to the Contributor Covenant https://github.com/spring-cloud/spring-cloud-build/blob/master/docs/src/main/asciidoc/code-of-conduct.adoc[code of +conduct]. By participating, you are expected to uphold this code. Please report +unacceptable behavior to spring-code-of-conduct@pivotal.io. + +=== Code Conventions and Housekeeping +None of these is essential for a pull request, but they will all help. They can also be +added after the original pull request but before a merge. + +* Use the Spring Framework code format conventions. If you use Eclipse + you can import formatter settings using the + `eclipse-code-formatter.xml` file from the + https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/spring-cloud-dependencies-parent/eclipse-code-formatter.xml[Spring + Cloud Build] project. If using IntelliJ, you can use the + http://plugins.jetbrains.com/plugin/6546[Eclipse Code Formatter + Plugin] to import the same file. +* Make sure all new `.java` files to have a simple Javadoc class comment with at least an + `@author` tag identifying you, and preferably at least a paragraph on what the class is + for. +* Add the ASF license header comment to all new `.java` files (copy from existing files + in the project) +* Add yourself as an `@author` to the .java files that you modify substantially (more + than cosmetic changes). +* Add some Javadocs and, if you change the namespace, some XSD doc elements. +* A few unit tests would help a lot as well -- someone has to do it. +* If no-one else is using your branch, please rebase it against the current master (or + other target branch in the main project). +* When writing a commit message please follow http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html[these conventions], + if you are fixing an existing issue please add `Fixes gh-XXXX` at the end of the commit + message (where XXXX is the issue number). diff --git a/docs/pom.xml b/docs/pom.xml new file mode 100644 index 00000000..947ce913 --- /dev/null +++ b/docs/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + org.springframework.cloud + spring-cloud-vault-config-docs + 1.1.0.BUILD-SNAPSHOT + + org.springframework.cloud + spring-cloud-build + 1.1.0.BUILD-SNAPSHOT + + + pom + Spring Cloud Vault Config Docs + Spring Cloud Docs + + spring-cloud-vault-config + ${basedir}/.. + + + + + + maven-deploy-plugin + + true + + + + + + + docs + + + + org.asciidoctor + asciidoctor-maven-plugin + false + + + org.apache.maven.plugins + maven-antrun-plugin + false + + + org.codehaus.mojo + build-helper-maven-plugin + false + + + + + + \ No newline at end of file diff --git a/docs/src/main/asciidoc/README.adoc b/docs/src/main/asciidoc/README.adoc new file mode 100644 index 00000000..340c670f --- /dev/null +++ b/docs/src/main/asciidoc/README.adoc @@ -0,0 +1,25 @@ + +include::intro.adoc[] + +== Features + +=== Spring Cloud Vauld Config Client + +Specifically for Spring applications: + +* Bind to the Config Server and initialize Spring `Environment` with remote property sources +* Obtain secrets secured with SSL +* https://www.vaultproject.io/docs/auth/token.html[Token] and https://www.vaultproject.io/docs/auth/app-id.html[AppId] authentication +* Bootstrap application context: a parent context for the main application that can be trained to do anything + +== Quick Start + +include::quickstart.adoc[] + +== Building + +include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/building.adoc[] + +== Contributing + +include::https://raw.githubusercontent.com/spring-cloud/spring-cloud-build/master/docs/src/main/asciidoc/contributing.adoc[] \ No newline at end of file diff --git a/docs/src/main/asciidoc/ghpages.sh b/docs/src/main/asciidoc/ghpages.sh new file mode 100755 index 00000000..305ea78a --- /dev/null +++ b/docs/src/main/asciidoc/ghpages.sh @@ -0,0 +1,54 @@ +#!/bin/bash -x + +git remote set-url --push origin `git config remote.origin.url | sed -e 's/^git:/https:/'` + +if ! (git remote set-branches --add origin gh-pages && git fetch -q); then + echo "No gh-pages, so not syncing" + exit 0 +fi + +if ! [ -d docs/target/generated-docs ]; then + echo "No gh-pages sources in docs/target/generated-docs, so not syncing" + exit 0 +fi + +# Find name of current branch +################################################################### +branch=$TRAVIS_BRANCH +[ "$branch" == "" ] && branch=`git rev-parse --abbrev-ref HEAD` +target=. +if [ "$branch" != "master" ]; then target=./$branch; mkdir -p $target; fi + +# Stash any outstanding changes +################################################################### +git diff-index --quiet HEAD +dirty=$? +if [ "$dirty" != "0" ]; then git stash; fi + +# Switch to gh-pages branch to sync it with current branch +################################################################### +git checkout gh-pages + +for f in docs/target/generated-docs/*; do + file=${f#docs/target/generated-docs/*} + if ! git ls-files -i -o --exclude-standard --directory | grep -q ^$file$; then + # Not ignored... + cp -rf $f $target + git add -A $target/$file + fi +done + +git add -A README.adoc || echo "No change to README.adoc" +git commit -a -m "Sync docs from $branch to gh-pages" || echo "Nothing committed" + +# Uncomment the following push if you want to auto push to +# the gh-pages branch whenever you commit to branch locally. +# This is a little extreme. Use with care! +################################################################### +git push origin gh-pages || echo "Cannot push gh-pages" + +# Finally, switch back to the current branch and exit block +git checkout $branch +if [ "$dirty" != "0" ]; then git stash pop; fi + +exit 0 \ No newline at end of file diff --git a/docs/src/main/asciidoc/intro.adoc b/docs/src/main/asciidoc/intro.adoc new file mode 100644 index 00000000..34685c17 --- /dev/null +++ b/docs/src/main/asciidoc/intro.adoc @@ -0,0 +1,2 @@ + +Spring Cloud Vault Config provides client-side support for externalized configuration in a distributed system. With https://www.vaultproject.io[Hashicorp's Vault] you have a central place to manage external secret properties for applications across all environments. Vault can manage static and dynamic secrets such as username/password for remote applications/resources and provide credentials for external services such as MySQL, PostgreSQL, Apache Cassandra, Consul, AWS and more. \ No newline at end of file diff --git a/docs/src/main/asciidoc/quickstart.adoc b/docs/src/main/asciidoc/quickstart.adoc new file mode 100644 index 00000000..9cff8424 --- /dev/null +++ b/docs/src/main/asciidoc/quickstart.adoc @@ -0,0 +1,200 @@ +Install Vault: + +---- +$ src/test/bash/install_vault.sh +---- + +Start the Vault server: + +---- +$ src/test/bash/local_run_vault.sh +---- + +Vault is started listening on `0.0.0.0:8200` using the `inmem` storage. +Vault is sealed and not initialized when starting up +so you need to initialize it first. + +---- +$ export VAULT_ADDR="http://localhost:8200" +$ export VAULT_TLS_SKIP=true +$ vault init +---- + +You should see something like: + +---- +Key 1: 7149c6a2e16b8833f6eb1e76df03e47f6113a3288b3093faf5033d44f0e70fe701 +Key 2: 901c534c7988c18c20435a85213c683bdcf0efcd82e38e2893779f152978c18c02 +Key 3: 03ff3948575b1165a20c20ee7c3e6edf04f4cdbe0e82dbff5be49c63f98bc03a03 +Key 4: 216ae5cc3ddaf93ceb8e1d15bb9fc3176653f5b738f5f3d1ee00cd7dccbe926e04 +Key 5: b2898fc8130929d569c1677ee69dc5f3be57d7c4b494a6062693ce0b1c4d93d805 +Initial Root Token: 19aefa97-cccc-bbbb-aaaa-225940e63d76 + +Vault initialized with 5 keys and a key threshold of 3. Please +securely distribute the above keys. When the Vault is re-sealed, +restarted, or stopped, you must provide at least 3 of these keys +to unseal it again. + +Vault does not store the master key. Without at least 3 keys, +your Vault will remain permanently sealed. +---- + +Vault will initialize and return a set of unsealing keys and the root token. +Pick 3 keys and unseal Vault. Store the Vault token in the `VAULT_TOKEN` + environment variable. + +---- +$ vault unseal (Key 1) +$ vault unseal (Key 2) +$ vault unseal (Key 3) +$ export VAULT_TOKEN=(Root token) +---- + +Spring Cloud Vault accesses different resources. By default, the secret +backend is enabled which accesses secret config settings via JSON endpoints. + +The HTTP service has resources in the form: + +---- +/secret/{application} +/secret/{application},{profile} +/secret/{defaultContext} +/secret/{defaultContext},{profile} +---- + +where the "application" is injected as the `spring.application.name` in the +`SpringApplication` (i.e. what is normally "application" in a regular +Spring Boot app), "profile" is an active profile (or comma-separated +list of properties). Properties retrieved from Vault will be used "as-is" +without further prefixing of the property names. + +== Client Side Usage + +To use these features in an application, just build it as a Spring +Boot application that depends on spring-cloud-vault-config (e.g. see +the test cases). Example Maven configuration: + +[source,xml,indent=0] +.pom.xml +---- + + org.springframework.boot + spring-boot-starter-parent + 1.3.3.RELEASE + + + + + + org.springframework.cloud + spring-cloud-vault-config + x.y.z + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + +---- + +Then you can create a standard Spring Boot application, like this simple HTTP server: + +---- +@SpringBootApplication +@RestController +public class Application { + + @RequestMapping("/") + public String home() { + return "Hello World!"; + } + + public static void main(String[] args) { + SpringApplication.run(Application.class, args); + } + +} +---- + +When it runs it will pick up the external configuration from the +default local config server on port `8200` if it is running. To modify +the startup behaviour you can change the location of the Vault server +using `bootstrap.properties` (like `application.properties` but for +the bootstrap phase of an application context), e.g. + +[source,yaml] +---- +spring.cloud.vault: + enabled: true + token: vault-token +---- + +=== AppId authentication + +Vault supports https://www.vaultproject.io/docs/auth/app-id.html[AppId] +authentication that consists of two hard to guess tokens. The AppId +defaults to `spring.application.name` that is statically configured. +The second token is the UserId which is a part determined by the application, +usually related to the runtime environment. IP address, Mac address or a +Docker container name are good examples. Spring Cloud Vault Config supports +IP address, Mac address and static UserId's (e.g. supplied via System properties). +The IP and Mac address are represented as Hex-encoded SHA256 hash. + +IP address-based UserId's use the local host's IP address. + +[source,yaml] +.bootstrap.yml using SHA256 IP-Address UserId's +---- +spring.cloud.vault: + enabled: true + authentication: APPID + app-id: + user-id: IP_ADDRESS +---- + +The corresponding command to generate the IP address UserId from a command line is: + +---- +$ echo -n 192.168.99.1 | sha256sum +---- +NOTE: Including the line break of `echo` leads to a different hash value +so make sure to include the `-n` flag. + +Mac address-based UserId's obtain their network device from the +localhost-bound device. The configuration also allows specifying +a `network-interface` hint to pick the right device. The value of +`network-interface` is optional and can be either an interface +name or interface index (0-based). + +[source,yaml] +.bootstrap.yml using SHA256 Mac-Address UserId's +---- +spring.cloud.vault: + enabled: true + authentication: APPID + app-id: + user-id: MAC_ADDRESS + network-interface: eth0 +---- + +The corresponding command to generate the IP address UserId from a command line is: + +---- +$ echo -n 0AFEDE1234AC | sha256sum +---- + +NOTE: The Mac address is specified uppercase and without colons. +Including the line break of `echo` leads to a different hash value +so make sure to include the `-n` flag. diff --git a/docs/src/main/ruby/generate_readme.sh b/docs/src/main/ruby/generate_readme.sh new file mode 100755 index 00000000..560aeef2 --- /dev/null +++ b/docs/src/main/ruby/generate_readme.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env ruby + +base_dir = File.join(File.dirname(__FILE__),'../../..') +src_dir = File.join(base_dir, "/src/main/asciidoc") +require 'asciidoctor' +require 'optparse' + +options = {} +file = "#{src_dir}/README.adoc" + +OptionParser.new do |o| + o.on('-o OUTPUT_FILE', 'Output file (default is stdout)') { |file| options[:to_file] = file unless file=='-' } + o.on('-h', '--help') { puts o; exit } + o.parse! +end + +file = ARGV[0] if ARGV.length>0 + +srcDir = File.dirname(file) +out = "// Do not edit this file (e.g. go instead to docs/src/main/asciidoc)\n\n" +doc = Asciidoctor.load_file file, safe: :safe, parse: false, attributes: 'allow-uri-read' +out << doc.reader.read + +unless options[:to_file] + puts out +else + File.open(options[:to_file],'w+') do |file| + file.write(out) + end +end \ No newline at end of file