From 30a8bd54a5266ba2f2b107db52320a5fcb6f2cc0 Mon Sep 17 00:00:00 2001 From: Andrea Peruffo Date: Mon, 28 Jan 2019 17:35:29 +0000 Subject: [PATCH] feature: Initial implementation --- .circleci/config.yml | 102 +++++++++++++++++++++++++++++++++++++++++++ .gitignore | 1 + Makefile | 27 ++++++++++++ Readme.md | 89 +++++++++++++++++++++++++++++++++++++ src/env2props.cr | 48 ++++++++++++++++++++ 5 files changed, 267 insertions(+) create mode 100644 .circleci/config.yml create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 src/env2props.cr diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..745160e --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,102 @@ +version: 2 + +# Re-usable blocks to reduce boilerplate in job definitions. +references: + default_machine_job: &default_machine_job + machine: true + working_directory: ~/workdir + + set_version_env_variable: &set_version_env_variable + run: + name: Define Environment Variable VERSION_NUMBER and ENV at Runtime + command: | + echo export VERSION_NUMBER=$(cat ~/workdir/.version) >> $BASH_ENV + source $BASH_ENV + echo $VERSION_NUMBER + + compile_crystal: &compile_crystal + run: + name: Get version + command: | + make clean buildStatic + +jobs: + checkout_and_version: + docker: + - image: codacy/git-version:latest + working_directory: ~/workdir + steps: + - checkout + - run: + name: Set version + command: /bin/git-version > .version + - run: + name: Current version + command: cat .version + - persist_to_workspace: + root: ~/ + paths: + - workdir + + compile: + <<: *default_machine_job + steps: + - run: + name: Compile + command: make clean buildStatic + - persist_to_workspace: + root: ~/ + paths: + - workdir/* + - store_artifacts: + path: bin + + publish-github-release: + docker: + - image: circleci/golang:1.8 + steps: + - attach_workspace: + at: ./artifacts + - run: + name: "Publish Release on GitHub" + command: | + go get github.com/tcnksm/ghr + VERSION=$(cat .version) + ghr -t ${GITHUB_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} -delete ${VERSION} ./artifacts/ + + tag-version: + <<: *default_machine_job + steps: + - attach_workspace: + at: ~/ + - add_ssh_keys: + fingerprints: + - "df:83:d7:c7:d5:79:06:c2:3b:d1:fd:e2:a3:d1:12:c5" + - deploy: + name: Tag git repository + command: git tag $(cat .version) && git push --tags + +workflows: + version: 2 + publish: + jobs: + - checkout_and_version + - compile: + requires: + - checkout_and_version + - publish-github-release: + requires: + - compile + filters: + branches: + only: + - master + context: CodacyAWS + - tag-version: + requires: + - publish-github-release + filters: + branches: + only: + - master + context: CodacyAWS diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ba077a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +bin diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..cd62eba --- /dev/null +++ b/Makefile @@ -0,0 +1,27 @@ +CRYSTAL=/usr/bin/crystal +CRYSTAL_FLAGS=--release + +all: fmt build + +.PHONY: fmt +fmt: ## format the crystal sources + $(CRYSTAL) tool format + +.PHONY: docker +build: fmt ## compiles from crystal sources + mkdir -p bin + $(CRYSTAL) build $(CRYSTAL_FLAGS) src/env2props.cr -o bin/env2props + +.PHONY: clean +clean: ## clean target directories + rm -rf bin + +buildStatic: ## compiles from crystal sources into static binary + docker run --rm -it -v $(PWD):/app -w /app durosoft/crystal-alpine:latest crystal build src/env2props.cr -o bin/env2props --release --static --no-debug + +.PHONY: help +help: + @echo "make help" + @echo "\n" + @grep -E '^[a-zA-Z_/%\-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + @echo "\n" diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..42be47c --- /dev/null +++ b/Readme.md @@ -0,0 +1,89 @@ + +# ENV2PROPS + +This is a tool to transform your environment variables into the java Properties format intended to be passed from the command line. + +e.g.: + +``` +$ env +LC_PAPER=en_US.UTF-8 +LC_MONETARY=en_US.UTF-8 +LANG=en_US.UTF-8 + +$ env2props +-Dlc.paper="en_US.UTF-8" -Dlc.monetary="en_US.UTF-8" -Dlang="en_US.UTF-8" +``` + +Under the option `-p` or `--prefix` you can pass a matching prefix for the environment variables. + +e.g.: + +``` +$ env +LC_PAPER=en_US.UTF-8 +LC_MONETARY=en_US.UTF-8 +LANG=en_US.UTF-8 + +$ env2props -p LC_ +-Dpaper="en_US.UTF-8" -Dmonetary="en_US.UTF-8" +``` + +The output is provided on standard output and without any additional new-line, as it is intended to be used in-line within java command execution. + +## Conventions + +Each environment variable is transformed as follows: + + - remove the trailing prefix (if specified) + - down case the entire string + - trasform all the `_` characters into `.` + +## Usage + +After making the binary executable and available on the `PATh`(should work out-of-the-box on any linux machine). +You can use this tool in-line while launching java applications e.g.: + +``` +sh -c "java $(env2props) -jar .jar" +``` + +## Rationale + +According to the [Twelve-factor App](https://12factor.net/config) the configuration should be passed to the applications via environment variables. + +The "de-facto" standard for configuration in Scala application is [Typesafe Config](https://github.com/lightbend/config) and env variables are a [supported fallback](https://github.com/lightbend/config#optional-system-or-env-variable-overrides); still it is not possible to override *virtually* any configuration of our application if not properly encoded the binding accordingly. + +Although [Typesafe Config](https://github.com/lightbend/config#overview) offers a first class integration with Java system properties: + +> users can override the config with Java system properties + +This makes it easy to bridge the gap and by having a standard way to convert environment variables into Java system properties make it possible to fully comply with [Twelve-factor App](https://12factor.net/config). + +## Compile + +You need to have the crystal compiler available in your classpath to succesfully build this utility, otherwise you can compile it statically using a docker image using `make buildStatic`. + +## What is Codacy + +[Codacy](https://www.codacy.com/) is an Automated Code Review Tool that monitors your technical debt, helps you improve your code quality, teaches best practices to your developers, and helps you save time in Code Reviews. + +### Among Codacy’s features + +- Identify new Static Analysis issues +- Commit and Pull Request Analysis with GitHub, BitBucket/Stash, GitLab (and also direct git repositories) +- Auto-comments on Commits and Pull Requests +- Integrations with Slack, HipChat, Jira, YouTrack +- Track issues in Code Style, Security, Error Proneness, Performance, Unused Code and other categories + +Codacy also helps keep track of Code Coverage, Code Duplication, and Code Complexity. + +Codacy supports PHP, Python, Ruby, Java, JavaScript, and Scala, among others. + +## Free for Open Source + +Codacy is free for Open Source projects. + +## License + +git-version is available under the Apache 2 license. See the LICENSE file for more info. diff --git a/src/env2props.cr b/src/env2props.cr new file mode 100644 index 0000000..ee2243d --- /dev/null +++ b/src/env2props.cr @@ -0,0 +1,48 @@ +require "option_parser" + +prefix = "" + +OptionParser.parse! do |parser| + parser.banner = "Usage: env2prop [arguments]" + parser.on("-p PREFIX", "--prefix=PREFIX", "Transform only the ENV variables that have the provided prefix") { |p| prefix = p } + parser.on("-h", "--help", "Show this help") { puts parser } + parser.invalid_option do |flag| + STDERR.puts "ERROR: #{flag} is not a valid option." + STDERR.puts parser + exit(1) + end +end + +first = true + +props = String.build do |props| + ENV.each do |k, v| + if !k.starts_with?(prefix) + next + end + + key = k + .lchop(prefix) + .downcase # all downcase + .gsub("_", ".") # all underscores to dots + + # given https://docs.oracle.com/javase/8/docs/api/java/util/Properties.html#load-java.io.InputStream- + encoding = "ISO8859-1" + str = String.new(bytes: v.encode(encoding), encoding: encoding) + + str = str.dump + + if (key.size > 1) || (key.size == 1 && key[0].alphanumeric?) + if first + first = false + else + props << " " + end + + props << "-D#{key}=#{str}" + end + end +end + +STDOUT.set_encoding("UTF-8") +STDOUT.print props