Skip to content

Commit

Permalink
Update: first version of the deno buildpack (0.0.1)
Browse files Browse the repository at this point in the history
Update: first version of the deno buildpack (0.1.0)
  • Loading branch information
till committed Sep 6, 2022
1 parent 43a43fd commit 76f30b6
Show file tree
Hide file tree
Showing 17 changed files with 4,029 additions and 0 deletions.
1 change: 1 addition & 0 deletions .envrc-dist
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export DOCKER_HOST=unix:///Users/till/.colima/default/docker.sock
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.envrc
bin/build
bin/detect
37 changes: 37 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
sample:=deno

buildpack?=.
bin_dir:=$(CURDIR)/bin
builder:=r.planetary-quantum.com/runway-public/paketo-builder:full

.PHONY: build
build: clean
GOOS=linux go build \
-ldflags="-s -w" \
-o "$(bin_dir)/detect" \
"$(CURDIR)/cmd/detect/main.go"

GOOS=linux go build \
-ldflags="-s -w" \
-o "$(bin_dir)/build" \
"$(CURDIR)/cmd/build/main.go"

.PHONY: clean
clean:
rm -f $(bin_dir)/detect
rm -f $(bin_dir)/run


.PHONY: setup
setup:
pack config default-builder $(builder)
pack config trusted-builders add $(builder)


.PHONY: test
test: build
pack \
build \
test-$(sample)-app \
--path ./samples/$(sample) \
--buildpack $(buildpack)
70 changes: 70 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# deno-buildpack

A deno buildpack (for [runway](https://runway.planetary-quantum.com/)).

> Deno is an alternative JavaScript runtime for the server. This buildpacks generates a Docker/OCI image from your application code and includes the correct version of deno to run the server with.
## Configuration

- `BP_RUNWAY_DENO_VERSION=v1.25.1`
- `BP_RUNWAY_DENO_FILE_VERSION=runtime.txt`
- `BP_RUNWAY_DENO_PERM_ENV=PORT`
- `BP_RUNWAY_DENO_PERM_HRTIME=false`
- `BP_RUNWAY_DENO_PERM_NET=true`
- `BP_RUNWAY_DENO_PERM_FFI=false`
- `BP_RUNWAY_DENO_PERM_READ=true`
- `BP_RUNWAY_DENO_PERM_RUN=false`
- `BP_RUNWAY_DENO_PERM_WRITE=false`
- `BP_RUNWAY_DENO_PERM_ALL=false`
- `BP_RUNWAY_DENO_MAIN=server.ts`

Supported permissions:

> --allow-env=<allow-env>
> --allow-hrtime
> --allow-net=<allow-net>
> --allow-ffi
> --allow-read=<allow-read>
> --allow-run=<allow-run>
> --allow-write=<allow-write>
> -A, --allow-all
### Environment variables

Configuration is done through environment variables.

Permissions can be generally enabled with a `true` value. So for example:

```sh
export BP_RUNWAY_DENO_PERM_NET=true
```

The above allows all net access, but it could be more granular with:

```sh
export BP_RUNWAY_DENO_PERM_NET=github.com:443
```

#### Deno version

Order of priority:

##### BP_RUNWAY_DENO_VERSION

Supersedes `BP_RUNWAY_DENO_FILE_VERSION`.

Contains a version such as `vA.B.C`.

##### BP_RUNWAY_DENO_FILE_VERSION

`runtime.txt` should contain a version, such as `vA.B.C`.

> (last) The buildpack also supports a `.dvmrc` file.
## Development

Run `make setup` to configure the default builder and trust it.

Run `make test` to build an (app) image from `./samples/deno` with one entrypoints:

- web: `docker run --rm -p 8080:8080 test-deno-app`
Empty file added bin/.gitkeep
Empty file.
14 changes: 14 additions & 0 deletions buildpack.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
api = "0.7"

[buildpack]
id = "deno-buildpack"
version = "0.1.0"
homepage = "https://runway.planetary-quantum.com"
description = "A deno buildpack (for runway)"

[metadata]
include-files = ["bin/build", "bin/detect", "buildpack.toml"]
pre-package = "make build"

[[stacks]]
id = "*"
26 changes: 26 additions & 0 deletions cmd/build/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package main

import (
"fmt"
"os"

"github.com/caarlos0/env"
"github.com/hostwithquantum/deno-buildpack/internal/build"
"github.com/hostwithquantum/deno-buildpack/internal/meta"

"github.com/paketo-buildpacks/packit/v2"
"github.com/paketo-buildpacks/packit/v2/scribe"
)

func main() {
logEmitter := scribe.NewEmitter(os.Stdout).WithLevel(os.Getenv("BP_LOG_LEVEL"))

var allTheVars meta.AppEnv
err := env.Parse(&allTheVars)
if err != nil {
fmt.Fprintln(os.Stdout, fmt.Errorf("failed getting environment: %s", err))
os.Exit(1)
}

packit.Build(build.Build(logEmitter, allTheVars))
}
16 changes: 16 additions & 0 deletions cmd/detect/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package main

import (
"os"

"github.com/hostwithquantum/deno-buildpack/internal/detect"

"github.com/paketo-buildpacks/packit/v2"
"github.com/paketo-buildpacks/packit/v2/scribe"
)

func main() {
logEmitter := scribe.NewEmitter(os.Stdout).WithLevel(os.Getenv("BP_LOG_LEVEL"))

packit.Detect(detect.Detect(logEmitter))
}
17 changes: 17 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module github.com/hostwithquantum/deno-buildpack

go 1.19

require (
github.com/caarlos0/env v3.5.0+incompatible
github.com/paketo-buildpacks/packit/v2 v2.4.2
)

require (
github.com/BurntSushi/toml v1.2.0 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/ulikunitz/xz v0.5.10 // indirect
golang.org/x/net v0.0.0-20220624214902-1bab6f366d9e // indirect
)
3,425 changes: 3,425 additions & 0 deletions go.sum

Large diffs are not rendered by default.

187 changes: 187 additions & 0 deletions internal/build/build.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
package build

import (
"fmt"
"net/http"
"os"
"path/filepath"

"github.com/hostwithquantum/deno-buildpack/internal/meta"
"github.com/hostwithquantum/deno-buildpack/internal/version"

"github.com/paketo-buildpacks/packit/v2"
"github.com/paketo-buildpacks/packit/v2/scribe"
"github.com/paketo-buildpacks/packit/v2/vacation"
)

type PackageJSON struct {
Scripts map[string]string `json:"scripts"`
}

func Build(logger scribe.Emitter, appEnv meta.AppEnv) packit.BuildFunc {
return func(context packit.BuildContext) (packit.BuildResult, error) {

logger.Title("%s %s", context.BuildpackInfo.ID, context.BuildpackInfo.Version)

finder := meta.Factory()
finder.Find(context.WorkingDir)

if !finder.HasMatch() {
logger.Process("not a deno app")
return packit.BuildResult{}, nil
}

layer, err := context.Layers.Get(meta.BPLayerName)
if err != nil {
logger.Process("failed to fetch layer: %s", err)
return packit.BuildResult{}, err
}
layer, err = layer.Reset()
if err != nil {
logger.Process("failed to reset layer: %s", err)
return packit.BuildResult{}, err
}

layer.Build = false
layer.Launch = true

logger.Process("getting deno version")

v := version.VersionFactory(appEnv, logger)
denoVersion, err := v.Find(context.WorkingDir)
if err != nil {
return packit.BuildResult{}, err
}

if denoVersion != "" {
logger.Detail("discovered %s", denoVersion)
}

layerBinPath := filepath.Join(layer.Path, "bin")
err = os.MkdirAll(layerBinPath, os.ModePerm)
if err != nil {
return packit.BuildResult{}, err
}

var downloadUrl string
downloadDest := filepath.Join(layer.Path, "deno.zip")

logger.Process("download")
if denoVersion != "latest" {
logger.Detail("building download for: %s", denoVersion)
downloadUrl = fmt.Sprintf(
"https://github.com/denoland/deno/releases/download/%s/deno-x86_64-unknown-linux-gnu.zip",
denoVersion)
} else {
logger.Detail("building download for latest")
downloadUrl = "https://github.com/denoland/deno/releases/latest/download/deno-x86_64-unknown-linux-gnu.zip"
}

logger.Process("installing deno %s", denoVersion)

logger.Subprocess("downloading deno")
logger.Subdetail("url: %s", downloadUrl)
logger.Subdetail("to: %s", downloadDest)

resp, err := http.Get(downloadUrl)
if err != nil {
logger.Detail("download failed")
return packit.BuildResult{}, err
}

defer resp.Body.Close()

logger.Subprocess("extracting download")
logger.Subdetail("to: %s", layerBinPath)

zip := vacation.NewZipArchive(resp.Body).StripComponents(0)
err = zip.Decompress(layerBinPath)
if err != nil {
logger.Detail("failed")
return packit.BuildResult{}, err
}

layer.BuildEnv.Append("PATH", layerBinPath, ":")
layer.LaunchEnv.Append("PATH", layerBinPath, ":")

var launchMetadata packit.LaunchMetadata

denoRunArgs := []string{"run"}

logger.Process("determine permissions for deno process")

if appEnv.AllowAll {
logger.Detail("granting all permissions — this is not very secure")
denoRunArgs = append(denoRunArgs, "--allow-all")
} else {
if appEnv.AllowEnv != "false" {
assembleArgs(&denoRunArgs, "--allow-env", appEnv.AllowEnv)
logger.Detail("Set --allow-env")
}

if appEnv.AllowHRTime {
denoRunArgs = append(denoRunArgs, "--allow-hrtime")
logger.Detail("Set --allow-hrtime")
}

if appEnv.AllowNet != "false" {
assembleArgs(&denoRunArgs, "--allow-net", appEnv.AllowNet)
logger.Detail("Set --allow-net")
}

if appEnv.AllowFFI {
denoRunArgs = append(denoRunArgs, "--allow-ffi")
logger.Detail("Set --allow-ffi")
}

if appEnv.AllowRead != "false" {
assembleArgs(&denoRunArgs, "--allow-read", appEnv.AllowRead)
logger.Detail("Set --allow-read")
}

if appEnv.AllowRun != "false" {
assembleArgs(&denoRunArgs, "--allow-run", appEnv.AllowRun)
logger.Detail("Set --allow-run")
}

if appEnv.AllowWrite != "false" {
assembleArgs(&denoRunArgs, "--allow-write", appEnv.AllowWrite)
logger.Detail("Set --allow-write")
}
}

// run bundle?
if _, err = os.Stat(filepath.Join(context.WorkingDir, "tsconfig.js")); err == nil {
fmt.Println("we could run bundle here")
}

logger.EnvironmentVariables(layer)

denoRunArgs = append(denoRunArgs, appEnv.DenoMain)

launchMetadata.Processes = []packit.Process{
{
Type: "web",
Command: "deno",
Args: denoRunArgs,
Default: true,
Direct: false,
},
}

logger.LaunchProcesses(launchMetadata.Processes)

return packit.BuildResult{
Layers: []packit.Layer{layer},
Launch: launchMetadata,
}, nil
}
}

func assembleArgs(args *[]string, opt string, optValue string) {
if len(optValue) == 0 || optValue == "true" {
*args = append(*args, opt)
} else {
*args = append(*args, fmt.Sprintf("%s=%s", opt, optValue))
}
}
17 changes: 17 additions & 0 deletions internal/detect/detect.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package detect

import (
"github.com/hostwithquantum/deno-buildpack/internal/meta"

"github.com/paketo-buildpacks/packit/v2"
"github.com/paketo-buildpacks/packit/v2/scribe"
)

func Detect(logs scribe.Emitter) packit.DetectFunc {
return func(context packit.DetectContext) (packit.DetectResult, error) {
logs.Title("%s %s", context.BuildpackInfo.Name, context.BuildpackInfo.Version)

finder := meta.Factory()
return packit.DetectResult{}, finder.Find(context.WorkingDir)
}
}
Loading

0 comments on commit 76f30b6

Please sign in to comment.