diff --git a/.github/pipeline-descriptor.yml b/.github/pipeline-descriptor.yml new file mode 100644 index 0000000..fa085cc --- /dev/null +++ b/.github/pipeline-descriptor.yml @@ -0,0 +1,13 @@ +github: + username: ${{ github.actor }} + token: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }} + +package: + repositories: ["ghcr.io/amp-buildpacks/sway"] + register: false + registry_token: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }} + +docker_credentials: + - registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/pb-update-pipeline.yml b/.github/workflows/pb-update-pipeline.yml new file mode 100644 index 0000000..295a16b --- /dev/null +++ b/.github/workflows/pb-update-pipeline.yml @@ -0,0 +1,93 @@ +name: Update Pipeline +"on": + push: + branches: + - main + paths: + - .github/pipeline-descriptor.yml + schedule: + - cron: 0 5 * * 1-5 + workflow_dispatch: {} +jobs: + update: + name: Update Pipeline + runs-on: + - ubuntu-latest + steps: + - uses: actions/setup-go@v5 + with: + go-version: "1.22" + - name: Install octo + run: | + #!/usr/bin/env bash + + set -euo pipefail + + go install -ldflags="-s -w" github.com/paketo-buildpacks/pipeline-builder/cmd/octo@latest + - uses: actions/checkout@v4 + - name: Update Pipeline + id: pipeline + run: | + #!/usr/bin/env bash + + set -euo pipefail + + if [[ -f .github/pipeline-version ]]; then + OLD_VERSION=$(cat .github/pipeline-version) + else + OLD_VERSION="0.0.0" + fi + + rm .github/workflows/pb-*.yml || true + octo --descriptor "${DESCRIPTOR}" + + PAYLOAD=$(gh api /repos/paketo-buildpacks/pipeline-builder/releases/latest) + + NEW_VERSION=$(jq -n -r --argjson PAYLOAD "${PAYLOAD}" '$PAYLOAD.name') + echo "${NEW_VERSION}" > .github/pipeline-version + + RELEASE_NOTES=$( + gh api \ + -F text="$(jq -n -r --argjson PAYLOAD "${PAYLOAD}" '$PAYLOAD.body')" \ + -F mode="gfm" \ + -F context="paketo-buildpacks/pipeline-builder" \ + -X POST /markdown + ) + + git add .github/ + git add .gitignore + + if [ -f scripts/build.sh ]; then + git add scripts/build.sh + fi + + git checkout -- . + + echo "old-version=${OLD_VERSION}" >> "$GITHUB_OUTPUT" + echo "new-version=${NEW_VERSION}" >> "$GITHUB_OUTPUT" + + DELIMITER=$(openssl rand -hex 16) # roughly the same entropy as uuid v4 used in https://github.com/actions/toolkit/blob/b36e70495fbee083eb20f600eafa9091d832577d/packages/core/src/file-command.ts#L28 + printf "release-notes<<%s\n%s\n%s\n" "${DELIMITER}" "${RELEASE_NOTES}" "${DELIMITER}" >> "${GITHUB_OUTPUT}" # see https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings + env: + DESCRIPTOR: .github/pipeline-descriptor.yml + GITHUB_TOKEN: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }} + - uses: peter-evans/create-pull-request@v6 + with: + author: ${{ github.actor }} <${{ github.actor }}@users.noreply.github.com> + body: |- + Bumps pipeline from `${{ steps.pipeline.outputs.old-version }}` to `${{ steps.pipeline.outputs.new-version }}`. + +
+ Release Notes + ${{ steps.pipeline.outputs.release-notes }} +
+ branch: update/pipeline + commit-message: |- + Bump pipeline from ${{ steps.pipeline.outputs.old-version }} to ${{ steps.pipeline.outputs.new-version }} + + Bumps pipeline from ${{ steps.pipeline.outputs.old-version }} to ${{ steps.pipeline.outputs.new-version }}. + delete-branch: true + labels: semver:patch, type:task + signoff: true + title: Bump pipeline from ${{ steps.pipeline.outputs.old-version }} to ${{ steps.pipeline.outputs.new-version }} + token: ${{ secrets.AMP_BUILDPACKS_BOT_GITHUB_TOKEN }} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..88bbcad --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Copyright (c) The Amphitheatre Authors. All rights reserved. +# +# 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 +# +# https://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. + +bin/ +dependencies/ +package/ +scratch/ 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/README.md b/README.md new file mode 100644 index 0000000..b3a396a --- /dev/null +++ b/README.md @@ -0,0 +1,70 @@ +# `ghcr.io/amp-buildpacks/sway` + +A Cloud Native Buildpack that provides the Sway Tool Suite + +## Configuration + +| Environment Variable | Description | +| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `$BP_SWAY_VERSION` | Configure the version of Sway to install. It can be a specific version or a wildcard like `1.*`. It defaults to the latest `1.*` version. | + + +## Usage + +### 1. To use this buildpack, simply run: + +```shell +pack build \ + --path \ + --buildpack ghcr.io/amp-buildpacks/sway \ + --builder paketobuildpacks/builder-jammy-base +``` + +For example: + +```shell +pack build sway-sample \ + --path ./samples/sway \ + --buildpack ghcr.io/amp-buildpacks/sway \ + --builder paketobuildpacks/builder-jammy-base +``` + +### 2. To run the image, simply run: + +```shell +docker run -u : -it +``` + +For example: + +```shell +docker run -u 1001:cnb -e HOME=/layers/amp-buildpacks_sway/forc-amd64/fuel -it sway-sample +``` + +## Contributing + +If anything feels off, or if you feel that some functionality is missing, please +check out the [contributing +page](https://docs.amphitheatre.app/contributing/). There you will find +instructions for sharing your feedback, building the tool locally, and +submitting pull requests to the project. + +## License + +Copyright (c) The Amphitheatre Authors. All rights reserved. + +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 + + https://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. + +## Credits + +Heavily inspired by https://buildpacks.io/docs/buildpack-author-guide/create-buildpack/ diff --git a/buildpack.toml b/buildpack.toml new file mode 100644 index 0000000..fa05262 --- /dev/null +++ b/buildpack.toml @@ -0,0 +1,82 @@ +# Copyright (c) The Amphitheatre Authors. All rights reserved. +# +# 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 +# +# https://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. + +api = "0.8" + +[buildpack] + description = "A Cloud Native Buildpack that provides the Sway Tool Suite" + homepage = "https://github.com/amp-buildpacks/sway" + id = "amp-buildpacks/sway" + keywords = ["Sway"] + sbom-formats = ["application/vnd.cyclonedx+json", "application/vnd.syft+json"] + name = "AMP Buildpack for Sway" + version = "{{ .version }}" + + [[buildpack.licenses]] + type = "Apache-2.0" + uri = "https://github.com/amp-buildpacks/sway/blob/main/LICENSE" + +[metadata] + include-files = ["LICENSE", "README.md", "linux/amd64/bin/build", "linux/amd64/bin/detect", "linux/amd64/bin/main", "linux/arm64/bin/build", "linux/arm64/bin/detect", "linux/arm64/bin/main", "buildpack.toml"] + pre-package = "scripts/build.sh" + + [[metadata.configurations]] + build = true + default = "0.63.5" + description = "The Forc version" + name = "BP_FORC_VERSION" + + [[metadata.configurations]] + build = true + default = "amd64" + description = "The Forc Platform, support: amd64,arm64" + name = "BP_FORC_PLATFORM" + + [[metadata.configurations]] + build = true + default = "true" + description = "Enable the Forc deploy tool" + name = "BP_ENABLE_FORC_DEPLOY" + + [[metadata.dependencies]] + id = "forc-amd64" + name = "Forc AMD64" + purl = "pkg:generic/forc@v0.63.5" + sha256 = "372d8002055508bb822278fe1cbf74e8765cd4de7e8f56fbc90fb9e73235bf4e" + uri = "https://github.com/FuelLabs/sway/releases/download/v0.63.5/forc-binaries-linux_amd64.tar.gz" + stacks = ["*"] + version = "0.63.5" + licenses = [ "GNU" ] + + [[metadata.dependencies]] + id = "forc-arm64" + name = "Forc ARM64" + purl = "pkg:generic/forc@v0.63.5" + sha256 = "73e031e1c3fb20ed854fc77e8717bddba56324958c702a1a670edb89270a3e70" + uri = "https://github.com/FuelLabs/sway/releases/download/v0.63.5/forc-binaries-linux_arm64.tar.gz" + stacks = ["*"] + version = "0.63.5" + licenses = [ "GNU" ] + + +[[stacks]] + id = "*" + +[[targets]] + arch = "amd64" + os = "linux" + +[[targets]] + arch = "arm64" + os = "linux" diff --git a/cmd/main/main.go b/cmd/main/main.go new file mode 100644 index 0000000..493b2bd --- /dev/null +++ b/cmd/main/main.go @@ -0,0 +1,30 @@ +// Copyright (c) The Amphitheatre Authors. All rights reserved. +// +// 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 +// +// https://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. + +package main + +import ( + "os" + + sway "github.com/amp-buildpacks/sway/sway" + "github.com/buildpacks/libcnb" + "github.com/paketo-buildpacks/libpak/bard" +) + +func main() { + libcnb.Main( + sway.Detect{}, + sway.Build{Logger: bard.NewLogger(os.Stdout)}, + ) +} diff --git a/config.toml b/config.toml new file mode 100644 index 0000000..c04f84f --- /dev/null +++ b/config.toml @@ -0,0 +1,17 @@ +[[dependencies]] +id = "forc-amd64" +name = "Forc AMD64" +pkg_name = "forc" +sha256 = "372d8002055508bb822278fe1cbf74e8765cd4de7e8f56fbc90fb9e73235bf4e" +uri = "https://github.com/FuelLabs/sway/releases/download/v0.63.5/forc-binaries-linux_amd64.tar.gz" +version = "0.63.5" +license = "GNU" + +[[dependencies]] +id = "forc-arm64" +name = "Forc ARM64" +pkg_name = "forc" +sha256 = "73e031e1c3fb20ed854fc77e8717bddba56324958c702a1a670edb89270a3e70" +uri = "https://github.com/FuelLabs/sway/releases/download/v0.63.5/forc-binaries-linux_arm64.tar.gz" +version = "0.63.5" +license = "GNU" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..d3124be --- /dev/null +++ b/go.mod @@ -0,0 +1,24 @@ +module github.com/amp-buildpacks/sway + +go 1.22 + +require ( + github.com/buildpacks/libcnb v1.30.3 + github.com/paketo-buildpacks/libpak v1.70.0 + github.com/mattn/go-shellwords v1.0.12 +) + +require ( + github.com/BurntSushi/toml v1.4.0 // indirect + github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/creack/pty v1.1.21 // indirect + github.com/h2non/filetype v1.1.3 // indirect + github.com/heroku/color v0.0.6 // indirect + github.com/imdario/mergo v0.3.16 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect + github.com/onsi/gomega v1.33.1 // indirect + github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 // indirect + golang.org/x/sys v0.21.0 // indirect +) \ No newline at end of file diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..04f248b --- /dev/null +++ b/go.sum @@ -0,0 +1,57 @@ +github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= +github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= +github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= +github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/buildpacks/libcnb v1.30.3 h1:JtFMFPO2450uDLzpE1b50TvmM1GEZa8YT9cQ2ZZtHqA= +github.com/buildpacks/libcnb v1.30.3/go.mod h1:JPb1vC7HQcGK0oONfqJvsYzOjw3be+WBbQ0KYOIhNvA= +github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0= +github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/h2non/filetype v1.1.3 h1:FKkx9QbD7HR/zjK1Ia5XiBsq9zdLi5Kf3zGyFTAFkGg= +github.com/h2non/filetype v1.1.3/go.mod h1:319b3zT68BvV+WRj7cwy856M2ehB3HqNOt6sy1HndBY= +github.com/heroku/color v0.0.6 h1:UTFFMrmMLFcL3OweqP1lAdp8i1y/9oHqkeHjQ/b/Ny0= +github.com/heroku/color v0.0.6/go.mod h1:ZBvOcx7cTF2QKOv4LbmoBtNl5uB17qWxGuzZrsi1wLU= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk= +github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y= +github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= +github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/paketo-buildpacks/libpak v1.70.0 h1:J2Vo4lkqfrkEhOsbJbTpAHjRCszEprHjdnrLlLkL3c8= +github.com/paketo-buildpacks/libpak v1.70.0/go.mod h1:VJpKQDq1ajyi3JIjfqIyg1Dgf/ayd4jzkO38bbqgQLc= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sclevine/spec v1.4.0 h1:z/Q9idDcay5m5irkZ28M7PtQM4aOISzOpj4bUPkDee8= +github.com/sclevine/spec v1.4.0/go.mod h1:LvpgJaFyvQzRvc1kaDs0bulYwzC70PbiYjC4QnFHkOM= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8 h1:nIPpBwaJSVYIxUFsDv3M8ofmx9yWTog9BfvIu0q41lo= +github.com/xi2/xz v0.0.0-20171230120015-48954b6210f8/go.mod h1:HUYIGzjTL3rfEspMxjDjgmT5uz5wzYJKVo23qUhYTos= +golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= +golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk= +golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +google.golang.org/protobuf v1.34.0 h1:Qo/qEd2RZPCf2nKuorzksSknv0d3ERwp1vFG38gSmH4= +google.golang.org/protobuf v1.34.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= \ No newline at end of file diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000..a7680d1 --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,35 @@ +#!/usr/bin/env bash +# Copyright (c) The Amphitheatre Authors. All rights reserved. +# +# 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 +# +# https://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. + +set -euo pipefail + +GOMOD=$(head -1 go.mod | awk '{print $2}') +GOOS="linux" GOARCH="amd64" go build -ldflags='-s -w' -o linux/amd64/bin/main "$GOMOD/cmd/main" +GOOS="linux" GOARCH="arm64" go build -ldflags='-s -w' -o linux/arm64/bin/main "$GOMOD/cmd/main" + +if [ "${STRIP:-false}" != "false" ]; then + strip linux/amd64/bin/main linux/arm64/bin/main +fi + +if [ "${COMPRESS:-none}" != "none" ]; then + $COMPRESS linux/amd64/bin/main linux/arm64/bin/main +fi + +ln -fs main linux/amd64/bin/build +ln -fs main linux/arm64/bin/build +ln -fs main linux/amd64/bin/detect +ln -fs main linux/arm64/bin/detect + +cp -pR linux/amd64/bin . diff --git a/sway/build.go b/sway/build.go new file mode 100644 index 0000000..a3bc692 --- /dev/null +++ b/sway/build.go @@ -0,0 +1,73 @@ +// Copyright (c) The Amphitheatre Authors. All rights reserved. +// +// 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 +// +// https://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. + +package sway + +import ( + "fmt" + + "github.com/buildpacks/libcnb" + "github.com/paketo-buildpacks/libpak" + "github.com/paketo-buildpacks/libpak/bard" +) + +type Build struct { + Logger bard.Logger +} + +func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { + b.Logger.Title(context.Buildpack) + result := libcnb.NewBuildResult() + + pr := libpak.PlanEntryResolver{Plan: context.Plan} + + if _, ok, err := pr.Resolve(PlanEntryForc); err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to resolve Sway plan entry\n%w", err) + } else if ok { + cr, err := libpak.NewConfigurationResolver(context.Buildpack, &b.Logger) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to create configuration resolver\n%w", err) + } + + dc, err := libpak.NewDependencyCache(context) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to create dependency cache\n%w", err) + } + dc.Logger = b.Logger + + dr, err := libpak.NewDependencyResolver(context) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to create dependency resolver\n%w", err) + } + + // install forc + v, _ := cr.Resolve("BP_FORC_VERSION") + platform, _ := cr.Resolve("BP_FORC_PLATFORM") + dependency, err := dr.Resolve(fmt.Sprintf("%s-%s", PlanEntryForc, platform), v) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to find dependency\n%w", err) + } + + swayLayer := NewSway(dependency, dc, cr) + swayLayer.Logger = b.Logger + + result.Processes, err = swayLayer.BuildProcessTypes(cr, context.Application) + if err != nil { + return libcnb.BuildResult{}, fmt.Errorf("unable to build list of process types\n%w", err) + } + result.Layers = append(result.Layers, swayLayer) + } + + return result, nil +} diff --git a/sway/detect.go b/sway/detect.go new file mode 100644 index 0000000..c1eeae8 --- /dev/null +++ b/sway/detect.go @@ -0,0 +1,91 @@ +// Copyright (c) The Amphitheatre Authors. All rights reserved. +// +// 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 +// +// https://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. + +package sway + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/buildpacks/libcnb" +) + +const ( + PlanEntryForc = "forc" +) + +type Detect struct { +} + +func (d Detect) Detect(context libcnb.DetectContext) (libcnb.DetectResult, error) { + found, err := d.swayProject(context.Application.Path) + if err != nil { + return libcnb.DetectResult{Pass: false}, fmt.Errorf("unable to detect Sway requirements\n%w", err) + } + + if !found { + return libcnb.DetectResult{Pass: false}, nil + } + + return libcnb.DetectResult{ + Pass: true, + Plans: []libcnb.BuildPlan{ + { + Provides: []libcnb.BuildPlanProvide{ + {Name: PlanEntryForc}, + }, + Requires: []libcnb.BuildPlanRequire{ + {Name: PlanEntryForc}, + }, + }, + }, + }, nil +} + +func (d Detect) swayProject(appDir string) (bool, error) { + filename := "Forc.toml" + _, err := os.Stat(filepath.Join(appDir, filename)) + if os.IsNotExist(err) || err != nil { + return false, fmt.Errorf("unable to determine if %s exists\n%w", filename, err) + } + + buildDirectory := filepath.Join(appDir, ".") + extension := ".sw" + if err := existsFilesWithExtension(buildDirectory, extension); err != nil { + return false, fmt.Errorf("unable to determine if '%s' exists\n%w", extension, err) + } + return true, nil +} + +func existsFilesWithExtension(directory, extension string) error { + var found bool + err := filepath.Walk(directory, func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + // Check if the file has the specified extension. + if !info.IsDir() && filepath.Ext(path) == extension { + found = true + return nil + } + return nil + }) + + if !found { + return fmt.Errorf("no files with extension '%s' found", extension) + } + return err +} diff --git a/sway/sway.go b/sway/sway.go new file mode 100644 index 0000000..dc8385d --- /dev/null +++ b/sway/sway.go @@ -0,0 +1,240 @@ +// Copyright (c) The Amphitheatre Authors. All rights reserved. +// +// 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 +// +// https://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. + +package sway + +import ( + "bytes" + "fmt" + "io" + "os" + "path/filepath" + "strings" + + "github.com/buildpacks/libcnb" + "github.com/paketo-buildpacks/libpak" + "github.com/paketo-buildpacks/libpak/bard" + "github.com/paketo-buildpacks/libpak/crush" + "github.com/paketo-buildpacks/libpak/effect" + "github.com/paketo-buildpacks/libpak/sherpa" +) + +type Sway struct { + LayerContributor libpak.DependencyLayerContributor + configResolver libpak.ConfigurationResolver + Logger bard.Logger + Executor effect.Executor +} + +func NewSway(dependency libpak.BuildpackDependency, cache libpak.DependencyCache, configResolver libpak.ConfigurationResolver) Sway { + contributor := libpak.NewDependencyLayerContributor(dependency, cache, libcnb.LayerTypes{ + Cache: true, + Launch: true, + }) + return Sway{ + LayerContributor: contributor, + configResolver: configResolver, + Executor: effect.NewExecutor(), + } +} + +func (r Sway) Contribute(layer libcnb.Layer) (libcnb.Layer, error) { + r.LayerContributor.Logger = r.Logger + return r.LayerContributor.Contribute(layer, func(artifact *os.File) (libcnb.Layer, error) { + bin := filepath.Join(layer.Path, "bin") + + // TODO: May be use copy instead of it or update Extract Path or stripComponents=1 + r.Logger.Bodyf("Expanding %s to %s", artifact.Name(), bin) + if err := crush.Extract(artifact, bin, 2); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to expand %s\n%w", artifact.Name(), err) + } + + // Must be set to executable + file := filepath.Join(bin, PlanEntryForc) + r.Logger.Bodyf("Setting %s as executable", file) + if err := os.Chmod(file, 0755); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to chmod %s\n%w", file, err) + } + + // Must be set to PATH + r.Logger.Bodyf("Setting %s in PATH", bin) + if err := os.Setenv("PATH", sherpa.AppendToEnvVar("PATH", ":", bin)); err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to set $PATH\n%w", err) + } + + // get version + buf, err := r.Execute(PlanEntryForc, []string{"--version"}) + if err != nil { + return libcnb.Layer{}, fmt.Errorf("unable to get %s version\n%w", PlanEntryForc, err) + } + version := strings.Split(strings.TrimSpace(buf.String()), " ") + r.Logger.Bodyf("Checking %s version: %s", PlanEntryForc, version[1]) + + fuelHome := filepath.Join(layer.Path, "fuel") + + // initialize wallet for deploy + walletDir := filepath.Join(fuelHome, "wallets") + if ok, err := r.InitializeWallet(walletDir); !ok { + return libcnb.Layer{}, err + } + + err = r.BuildContract() + if err != nil { + return libcnb.Layer{}, err + } + + // need to set layer.Path/fuel to HOME variable + forcGitHome := "/home/cnb/.forc" + forcDependencyDir := filepath.Join(fuelHome, ".forc") + copyDir(forcGitHome, forcDependencyDir) + r.Logger.Bodyf("Copy dependency from %s to %s", forcGitHome, forcDependencyDir) + + layer.LaunchEnvironment.Default("WALLET_PATH", walletDir) + layer.LaunchEnvironment.Default("FUEL_HOME", fuelHome) + layer.LaunchEnvironment.Default("HOME", fuelHome) + return layer, nil + }) +} + +func (r Sway) Execute(command string, args []string) (*bytes.Buffer, error) { + buf := &bytes.Buffer{} + if err := r.Executor.Execute(effect.Execution{ + Command: command, + Args: args, + Stdout: buf, + Stderr: buf, + }); err != nil { + return buf, fmt.Errorf("%s: %w", buf.String(), err) + } + return buf, nil +} + +func (r Sway) BuildProcessTypes(cr libpak.ConfigurationResolver, app libcnb.Application) ([]libcnb.Process, error) { + processes := []libcnb.Process{} + + enableDeploy := cr.ResolveBool("BP_ENABLE_FORC_DEPLOY") + if enableDeploy { + processes = append(processes, libcnb.Process{ + Type: PlanEntryForc, + Command: PlanEntryForc, + Arguments: []string{"deploy", "--testnet", "--default-signer"}, + Default: true, + }) + } + return processes, nil +} + +func (r Sway) InitializeWallet(walletDir string) (bool, error) { + r.Logger.Bodyf("Initializing deploy wallet and save to dir: %s", walletDir) + os.MkdirAll(walletDir, os.ModePerm) + + // TODO: The official does not support command-line operations. For now, a wallet address is hardcoded. A patch is being submitted to the official team. Once accepted, this part will be optimized accordingly. + wallet := `{"crypto":{"cipher":"aes-128-ctr","cipherparams":{"iv":"4d4a85c291ffad4477bd2c3e6e64f078"},"ciphertext":"89067d9bfffe1db17a37dd65c4e45e7953b8fc00143a6e1090937add1e3cb21153ca3156cc50e5ccedbe72534843bf7ad80fc4a9bc65fea82427e8905aa64fa241cb1522d8f5f817dfc144e45285a03ca36d4399f4276d0fd5a5c1d7d906ad2d7e5e861c7a58796ca08c73510fb5d806f15938b337f21e292d3eab92e25f1ed57a48906794cb2c6616220bde9bec526c5abc74a518ee6d92290105","kdf":"scrypt","kdfparams":{"dklen":32,"n":8192,"p":1,"r":8,"salt":"4a118a37f92754b0c472b9affc54a70f462d216b5e01a823c3e41ec234b96eba"},"mac":"132446b450cee5fe1c39f456c275cedeff72db61e84f9534de84ec462c745154"},"id":"380a7b4c-725e-4c3d-9667-50f9cdf43a94","version":3}` + + testnetWalletFile := filepath.Join(walletDir, ".wallet") + os.WriteFile(testnetWalletFile, []byte(wallet), 0644) + r.Logger.Bodyf("Initialize deploy wallet:%s success", testnetWalletFile) + + // args := []string{"wallet", "--path", testnetWalletFile, "accounts", "--unverified"} + // if _, err := r.Execute(PlanEntryForc, args); err != nil { + // return false, fmt.Errorf("unable to initialize deploy wallet\n%w", err) + // } + return true, nil +} + +func (r Sway) BuildContract() error { + args := []string{"build", "--release"} + _, err := r.Execute(PlanEntryForc, args) + if err != nil { + return fmt.Errorf("unable to build contract\n%w", err) + } + r.Logger.Bodyf("Build contract success") + return nil +} + +func (r Sway) Name() string { + return r.LayerContributor.LayerName() +} + +// copyDir recursively copies a directory tree, attempting to preserve permissions. +// Source directory must exist, while destination directory must not. +func copyDir(src string, dst string) error { + var err error + var srcInfo os.FileInfo + + if srcInfo, err = os.Stat(src); err != nil { + return err + } + + if err = os.MkdirAll(dst, srcInfo.Mode()); err != nil { + return err + } + + fds, err := os.ReadDir(src) + if err != nil { + return err + } + + for _, fd := range fds { + srcFp := filepath.Join(src, fd.Name()) + dstFp := filepath.Join(dst, fd.Name()) + + if fd.IsDir() { + if err = copyDir(srcFp, dstFp); err != nil { + fmt.Println(err) + } + } else { + if err = copyFile(srcFp, dstFp); err != nil { + fmt.Println(err) + } + } + } + return nil +} + +// copyFile copies a single file from src to dst +func copyFile(src, dst string) error { + sourceFileStat, err := os.Stat(src) + if err != nil { + return err + } + + if !sourceFileStat.Mode().IsRegular() { + return fmt.Errorf("%s is not a regular file", src) + } + + source, err := os.Open(src) + if err != nil { + return err + } + defer source.Close() + + destination, err := os.Create(dst) + if err != nil { + return err + } + defer destination.Close() + + _, err = io.Copy(destination, source) + if err != nil { + return err + } + + err = destination.Sync() + if err != nil { + return err + } + + return nil +}