From 836f11f60285a5ba0473c17b8874b90f151115a0 Mon Sep 17 00:00:00 2001 From: Tiago Tristao Date: Thu, 7 Apr 2022 17:21:05 +0100 Subject: [PATCH 1/3] First commit --- .github/workflows/plugin.yaml | 13 +++ .gitignore | 4 + .plzconfig | 5 + ChangeLog | 3 + LICENSE | 201 ++++++++++++++++++++++++++++++++++ VERSION | 1 + builds_defs/BUILD | 5 + builds_defs/shell.build_defs | 196 +++++++++++++++++++++++++++++++++ pleasew | 99 +++++++++++++++++ 9 files changed, 527 insertions(+) create mode 100644 .github/workflows/plugin.yaml create mode 100644 .gitignore create mode 100644 .plzconfig create mode 100644 ChangeLog create mode 100644 LICENSE create mode 100644 VERSION create mode 100644 builds_defs/BUILD create mode 100644 builds_defs/shell.build_defs create mode 100755 pleasew diff --git a/.github/workflows/plugin.yaml b/.github/workflows/plugin.yaml new file mode 100644 index 0000000..ab758e3 --- /dev/null +++ b/.github/workflows/plugin.yaml @@ -0,0 +1,13 @@ +name: Shell rules +on: [push, pull_request] +jobs: + release: + runs-on: ubuntu-latest + if: github.ref == 'refs/heads/master' + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Release + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + uses: tatskaari/release-action@master diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7d667e8 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ + +# Entries below this point are managed by Please (DO NOT EDIT) +plz-out +.plzconfig.local diff --git a/.plzconfig b/.plzconfig new file mode 100644 index 0000000..844dc89 --- /dev/null +++ b/.plzconfig @@ -0,0 +1,5 @@ +[Please] +Version = 16.20.0-beta.14 + +[FeatureFlags] +ExcludeShellRules = true diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..8ad5583 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,3 @@ +Version 0.1.0 +------------- + * Initial release diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/VERSION b/VERSION new file mode 100644 index 0000000..6e8bf73 --- /dev/null +++ b/VERSION @@ -0,0 +1 @@ +0.1.0 diff --git a/builds_defs/BUILD b/builds_defs/BUILD new file mode 100644 index 0000000..66067be --- /dev/null +++ b/builds_defs/BUILD @@ -0,0 +1,5 @@ +filegroup( + name = "shell", + srcs = ["shell.build_defs"], + visibility = ["PUBLIC"], +) diff --git a/builds_defs/shell.build_defs b/builds_defs/shell.build_defs new file mode 100644 index 0000000..22514ba --- /dev/null +++ b/builds_defs/shell.build_defs @@ -0,0 +1,196 @@ +""" Rules to 'build' shell scripts. + +Note that these do pretty much nothing beyond collecting the files. In future we might +implement something more advanced (ala .sar files or whatever). +""" + +_SH_BINARY_TMPL_PREFIX = """ +unzip -qo $0 -d $(dirname $0) +""".replace('$', '\\\$').replace('"', '\\"') + +_SH_BINARY_TMPL_SUFFIX = """ +exit 0\n\ +""" + + +def sh_library(name:str, src:str, deps:list=None, visibility:list=None, labels:list&features&tags=None): + """Generates a shell script binary, essentially just the given source. + + Note that these are individually executable so can only have one source file each. + This is a bit tedious and would be nice to improve sometime. + + Args: + name (str): Name of the rule. + src (str): Source file for the rule. + deps (list): Dependencies of this rule. + visibility (list): Visibility declaration of the rule. + labels (list): List of labels. + """ + return filegroup( + name=name, + srcs=[src], + deps=deps, + visibility=visibility, + binary=True, + labels=labels, + ) + + +def sh_binary(name:str, main:str|list&srcs, out:str="", deps:list=None, data:list=None, visibility:list=None, + labels:list&features&tags=None): + """Generates a shell script binary. + + It assumes that unzip is in your path. + + The resulting script will contain three things: + 1) Code necessary to unzip dependent files. + 2) The user defined shell script. + 3) The zipfile containing all dependent files. + + Args: + name (str): Name of the rule + main (str): The script to execute after all files have been uncompressed + out (str): Name of the output file to create. Defaults to name + .sh. + data (list): Runtime data for this rule. + deps (list): Dependencies of this rule + visibility (list): Visibility declaration of the rule. + labels (list): List of labels. + """ + if isinstance(main, list): + assert len(main) == 1, "srcs must be a single-element list" + main = main[0] + # No need to go through zip/unzip and injecting code if there are no dependencies + if deps: + cmds = ' && '.join([ + # If set, use the same shebang as the original script + 'head -1 "$SRCS" | { grep "^#\!" || true; } > "$TMPDIR"/_tmp.txt', + # Inject bash code to untar the compressed files. + f'echo "{_SH_BINARY_TMPL_PREFIX}" >> "$TMPDIR"/_tmp.txt', + # Inject the user defined script. + 'cat $SRCS >> "$TMPDIR"/_tmp.txt', + # Inject a final exit so it doesn't try to execute the zipfile contents. + f'echo "{_SH_BINARY_TMPL_SUFFIX}" >> "$TMPDIR"/_tmp.txt', + # Compress the dependent files and dump out into the bash script. + '"$TOOL" z -d -n -i . -o "$OUT" --preamble_file "$TMPDIR"/_tmp.txt --strip_prefix ./', + ]) + else: + cmds = 'cp "$SRC" "$OUT"' + + return build_rule( + name = name, + srcs = [main], + outs = [out or f'{name}.sh'], + data = data, + tools = [CONFIG.JARCAT_TOOL], + cmd = cmds, + deps = deps, + binary = True, + needs_transitive_deps = True, + labels = labels, + visibility = visibility, + ) + + +def sh_test(name:str, src:str=None, labels:list&features&tags=None, data:list|dict=None, deps:list=None, worker:str='', + size:str=None, visibility:list=None, flags:str='', flaky:bool|int=0, test_outputs:list=None, timeout:int=0, + sandbox:bool=None): + """Generates a shell test. Note that these aren't packaged in a useful way. + + Args: + name (str): Name of the rule + src (str): Test script file. + labels (list): Labels to apply to this test. + data (list): Runtime data for the test. + deps (list): Dependencies of this rule + worker (str): Reference to worker script, A persistent worker process that is used to set up the test. + size (str): Test size (enormous, large, medium or small). + visibility (list): Visibility declaration of the rule. + flags (str): Flags to apply to the test invocation. + timeout (int): Maximum length of time, in seconds, to allow this test to run for. + flaky (int | bool): True to mark this as flaky and automatically rerun. + test_outputs (list): Extra test output files to generate from this test. + sandbox (bool): Sandbox the test on Linux to restrict access to namespaces such as network. + """ + test_cmd = '$TEST %s' % flags + if worker: + test_cmd = f'$(worker {worker}) && {test_cmd} ' + deps += [worker] + + return build_rule( + name=name, + srcs=[src or test], + data=data, + deps=deps, + outs=[name + '.sh'], + cmd='cp "$SRC" "$OUT"', + test_cmd=test_cmd, + visibility=visibility, + labels=labels, + binary=True, + test=True, + no_test_output=True, + flaky=flaky, + requires=['test'], + test_outputs=test_outputs, + test_timeout=timeout, + size = size, + test_sandbox=sandbox, + ) + + +def sh_cmd(name:str, cmd:str|dict|list, srcs:list|dict=[], data:list=[], out:str="", shell:str='/bin/sh', + labels:list&features&tags=[], deps:list=[], visibility:list=None, expand_env_vars:bool=True, + test_only:bool=False): + """Generates a runnable shell script from a command. + + This is doable with a genrule with a little effort but it's awkward enough to be nice + to have a builtin. + The command is subject to Please's usual variable expansion at build time. Note that if + you want `plz run` to transparently work and refer to other files, you may need to use + $(out_location ...) instead of $(location ...). + + Args: + name (str): Name of the rule. + cmd (str | dict): Command to write into the output script file. The commands are subject to + shell expansion during build time by default. If that is to be avoided, set expand_env_vars to + False, or escape the variables with \\\\\\$, i.e. \\\\\\${@}. + expand_env_vars (bool): Whether to expand + srcs (list | dict): Source files. Can be consumed as env variables by the generated command (but are not + written into the output in any other way). + data (list): Runtime data for this rule. + out (str): Name of the output file to create. Defaults to name + .sh. + shell (str): Shell to invoke in, by default /bin/sh. + labels (list): Labels to apply to this rule. + deps (list): Any dependencies for this rule. These can be consumed as env variables in the cmd but are not + used in any other way. + visibility (list): Visibility declaration of the rule. + test_only (bool): If True, this rule can only be depended on by tests. + """ + cmd = ' && '.join(cmd) if isinstance(cmd, list) else cmd + cmd = cmd[CONFIG.BUILD_CONFIG] if isinstance(cmd, dict) else cmd + if not expand_env_vars: + return text_file( + name = name, + out = out or name + '.sh', + data = data, + labels = labels + ["sh_cmd"], + deps = deps + srcs, # There's no difference between these two as we're not expanding env vars as below + visibility = visibility, + binary = True, + test_only = test_only, + content = f"#!{shell}\n{cmd}\n", + ) + + cmd = f'{{ cat > "$OUT" << EOF\n#!{shell}\n{cmd}\nEOF\n}}' + return build_rule( + name = name, + outs = [out or name + '.sh'], + srcs = srcs, + data = data, + cmd = cmd, + labels = labels, + deps = deps, + visibility = visibility, + binary = True, + test_only = test_only, + ) diff --git a/pleasew b/pleasew new file mode 100755 index 0000000..1b81ad4 --- /dev/null +++ b/pleasew @@ -0,0 +1,99 @@ +#!/usr/bin/env bash +set -u + +RED="\x1B[31m" +GREEN="\x1B[32m" +YELLOW="\x1B[33m" +RESET="\x1B[0m" + +DEFAULT_URL_BASE="https://get.please.build" + +OS="$(uname)" + +if [[ $OS == "Darwin" ]]; then + # switch between mac amd64/arm64 + ARCH="$(uname -m)" +else + # default to amd64 on other operating systems + # because we only build intel binaries + ARCH="amd64" +fi + +# Check PLZ_CONFIG_PROFILE or fall back to arguments for a profile. +PROFILE="${PLZ_CONFIG_PROFILE:-$(sed -E 's/.*--profile[= ]([^ ]+).*/\1/g' <<< "$*")}" + +# Config files on order of precedence high to low. +CONFIGS=( + ".plzconfig.local" + "${PROFILE:+.plzconfig.$PROFILE}" + ".plzconfig_${OS}_${ARCH}" + ".plzconfig" + "$HOME/.config/please/plzconfig" + "/etc/please/plzconfig" +) + +function read_config() { + grep -i "$1" "${CONFIGS[@]}" 2>/dev/null | head -n 1 +} + +# We might already have it downloaded... +LOCATION="$(read_config "^location" | cut -d '=' -f 2 | tr -d ' ')" +if [ -z "$LOCATION" ]; then + if [ -z "$HOME" ]; then + echo -e >&2 "${RED}\$HOME not set, not sure where to look for Please.${RESET}" + exit 1 + fi + LOCATION="${HOME}/.please" +else + # It can contain a literal ~, need to explicitly handle that. + LOCATION="${LOCATION/\~/$HOME}" +fi +# If this exists at any version, let it handle any update. +TARGET="${LOCATION}/please" +if [ -f "$TARGET" ]; then + exec "$TARGET" ${PLZ_ARGS:-} "$@" +fi + +URL_BASE="$(read_config "^downloadlocation" | cut -d '=' -f 2 | tr -d ' ')" +if [ -z "$URL_BASE" ]; then + URL_BASE=$DEFAULT_URL_BASE +fi +URL_BASE="${URL_BASE%/}" + +VERSION="$(read_config "^version[^a-z]")" +VERSION="${VERSION#*=}" # Strip until after first = +VERSION="${VERSION/ /}" # Remove all spaces +VERSION="${VERSION#>=}" # Strip any initial >= +if [ -z "$VERSION" ]; then + echo -e >&2 "${YELLOW}Can't determine version, will use latest.${RESET}" + VERSION=$(curl -fsSL ${URL_BASE}/latest_version) +fi + +# Find the os / arch to download. You can do this quite nicely with go env +# but we use this script on machines that don't necessarily have Go itself. +if [ "$OS" = "Linux" ]; then + GOOS="linux" +elif [ "$OS" = "Darwin" ]; then + GOOS="darwin" +elif [ "$OS" = "FreeBSD" ]; then + GOOS="freebsd" +else + echo -e >&2 "${RED}Unknown operating system $OS${RESET}" + exit 1 +fi + +PLEASE_URL="${URL_BASE}/${GOOS}_${ARCH}/${VERSION}/please_${VERSION}.tar.xz" +DIR="${LOCATION}/${VERSION}" +# Potentially we could reuse this but it's easier not to really. +if [ ! -d "$DIR" ]; then + rm -rf "$DIR" +fi +echo -e >&2 "${GREEN}Downloading Please ${VERSION} to ${DIR}...${RESET}" +mkdir -p "$DIR" +curl -fsSL "${PLEASE_URL}" | tar -xJpf- --strip-components=1 -C "$DIR" +# Link it all back up a dir +for x in $(ls "$DIR"); do + ln -sf "${DIR}/${x}" "$LOCATION" +done +echo -e >&2 "${GREEN}Should be good to go now, running plz...${RESET}" +exec "$TARGET" ${PLZ_ARGS:-} "$@" From 61f551b66376b3677c459a789713b0caa8ce0abd Mon Sep 17 00:00:00 2001 From: Tiago Tristao Date: Thu, 7 Apr 2022 17:34:35 +0100 Subject: [PATCH 2/3] Add tests --- .github/workflows/plugin.yaml | 15 ++++++ test/BUILD | 90 +++++++++++++++++++++++++++++++++++ test/data_files_test.sh | 6 +++ test/no_shebang.sh | 8 ++++ test/pass_env_test.sh | 8 ++++ test/sh_binary.sh | 8 ++++ test/sh_lib.sh | 3 ++ test/shebang.sh | 7 +++ 8 files changed, 145 insertions(+) create mode 100644 test/BUILD create mode 100755 test/data_files_test.sh create mode 100755 test/no_shebang.sh create mode 100755 test/pass_env_test.sh create mode 100755 test/sh_binary.sh create mode 100755 test/sh_lib.sh create mode 100755 test/shebang.sh diff --git a/.github/workflows/plugin.yaml b/.github/workflows/plugin.yaml index ab758e3..86664de 100644 --- a/.github/workflows/plugin.yaml +++ b/.github/workflows/plugin.yaml @@ -1,7 +1,22 @@ name: Shell rules on: [push, pull_request] jobs: + test: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v2 + - name: Run tests + run: ./pleasew test -p -v notice --log_file plz-out/log/test.log + - name: Archive logs + if: always() + uses: actions/upload-artifact@v2 + with: + name: logs + path: | + plz-out/log release: + needs: [test] runs-on: ubuntu-latest if: github.ref == 'refs/heads/master' steps: diff --git a/test/BUILD b/test/BUILD new file mode 100644 index 0000000..ee0ef33 --- /dev/null +++ b/test/BUILD @@ -0,0 +1,90 @@ +# This tests that data files exist in the correct location, and +# indirectly performs a basic test of sh_test which we don't use elsewhere. +sh_test( + name = "data_files_test", + src = "data_files_test.sh", + data = ["container_data.txt"], +) + +sh_test( + name = "pass_env_test", + src = "pass_env_test.sh", + data = [":pass_env"], + labels = ["manual"], # Unclear what a good env var to pass is that works locally & on CI. +) + +sh_library( + name = "sh_lib", + src = "sh_lib.sh", +) + +sh_binary( + name = "sh_binary", + main = "sh_binary.sh", + deps = [ + ":sh_lib", + ], +) + +sh_test( + name = "sh_test", + src = ":sh_binary", +) + +sh_cmd( + name = "sh_cmd", + cmd = [ + 'BUILD_TIME_EXPANSION_VAR="$OUT"', + 'NO_EXPANSION_VAR="\\\\$@"', + '[ "\\\\$BUILD_TIME_EXPANSION_VAR" != "" ] || (echo "Expected a build time var to be expanded." >&2 && exit 11)', + '[ "\\\\$NO_EXPANSION_VAR" = "test_value" ] || (echo "Expected a expansion not to happen" >&2 && exit 11)', + ], +) + +sh_cmd( + name = "sh_cmd_unexpanded", + cmd = [ + 'VAR="$OUT"', + '[ "$VAR" = "" ] || (echo "Expected a build time var to be unexpanded." >&2 && exit 11)', + ], + expand_env_vars = False, +) + +sh_test( + name = "sh_cmd_test", + src = ":sh_cmd", + flags = "test_value", +) + +sh_test( + name = "sh_cmd_unexpanded_test", + src = ":sh_cmd_unexpanded", +) + +sh_binary( + name = "no_shebang", + main = "no_shebang.sh", + deps = [ + # Although not used by `no_shebang.sh` directly, the shebang is currently reused when `deps` are provided. + ":sh_lib", + ], +) + +sh_test( + name = "no_shebang_test", + src = ":no_shebang", +) + +sh_binary( + name = "shebang", + main = "shebang.sh", + deps = [ + # Although not used by `shebang.sh` directly, the shebang is currently reused when `deps` are provided. + ":sh_lib", + ], +) + +sh_test( + name = "shebang_test", + src = ":shebang", +) diff --git a/test/data_files_test.sh b/test/data_files_test.sh new file mode 100755 index 0000000..11feee1 --- /dev/null +++ b/test/data_files_test.sh @@ -0,0 +1,6 @@ +#!/bin/sh + +# Check this file exists in the expected location. +if [ ! -f test/container_data.txt ]; then + exit 1 +fi diff --git a/test/no_shebang.sh b/test/no_shebang.sh new file mode 100755 index 0000000..823475d --- /dev/null +++ b/test/no_shebang.sh @@ -0,0 +1,8 @@ +true + +# This checks that the top line of the script isn't reused for building the target as it's not a shebang. +if [ "`grep -axc "true" $0`" != "1" ]; then + echo "The top line of the original file is being reused and it's not a shebang" >&2 + exit 1 +fi + diff --git a/test/pass_env_test.sh b/test/pass_env_test.sh new file mode 100755 index 0000000..4fa9177 --- /dev/null +++ b/test/pass_env_test.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -eu + +source "test/pass_env.sh" +if [ -z "$USER" ]; then + echo '$USER is not set' + exit 1 +fi diff --git a/test/sh_binary.sh b/test/sh_binary.sh new file mode 100755 index 0000000..d009f54 --- /dev/null +++ b/test/sh_binary.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash +set -eu + +# test /bin/bash can be used +[ ! -z "$BASH_VERSION" ] || (echo "Expected a bash shell" >&2 && exit 11) + +source test/sh_rules/sh_lib.sh +[ "$TEST_DEPS_VAR" = "123" ] || (echo "Could not source variable from dependency" && exit 12) diff --git a/test/sh_lib.sh b/test/sh_lib.sh new file mode 100755 index 0000000..3b96a51 --- /dev/null +++ b/test/sh_lib.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env bash +# used by the sh deps test +export TEST_DEPS_VAR="123" diff --git a/test/shebang.sh b/test/shebang.sh new file mode 100755 index 0000000..07b3bc3 --- /dev/null +++ b/test/shebang.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +if [ "`head -1 $0`" != "#!/usr/bin/env bash" ]; then + echo "Shebang of the original file isn't the first line of the produced artefact" >&2 + exit 1 +fi + From 01a65496e0786505322e71495a86e39b8aa6093f Mon Sep 17 00:00:00 2001 From: Tiago Tristao Date: Thu, 7 Apr 2022 17:38:02 +0100 Subject: [PATCH 3/3] Fix tests --- test/BUILD | 7 +++++++ test/container_data.txt | 1 + test/sh_binary.sh | 2 +- 3 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 test/container_data.txt diff --git a/test/BUILD b/test/BUILD index ee0ef33..f401840 100644 --- a/test/BUILD +++ b/test/BUILD @@ -6,6 +6,13 @@ sh_test( data = ["container_data.txt"], ) +genrule( + name = "pass_env", + outs = ["pass_env.sh"], + cmd = "echo \"export USER='$USER'\" > \"$OUT\"", + pass_env = ["USER"], +) + sh_test( name = "pass_env_test", src = "pass_env_test.sh", diff --git a/test/container_data.txt b/test/container_data.txt new file mode 100644 index 0000000..7d2f09b --- /dev/null +++ b/test/container_data.txt @@ -0,0 +1 @@ +This file will only appear in the container if data is working properly. diff --git a/test/sh_binary.sh b/test/sh_binary.sh index d009f54..4b22630 100755 --- a/test/sh_binary.sh +++ b/test/sh_binary.sh @@ -4,5 +4,5 @@ set -eu # test /bin/bash can be used [ ! -z "$BASH_VERSION" ] || (echo "Expected a bash shell" >&2 && exit 11) -source test/sh_rules/sh_lib.sh +source test/sh_lib.sh [ "$TEST_DEPS_VAR" = "123" ] || (echo "Could not source variable from dependency" && exit 12)