Merge branch 'master' into bernie/export-png
This commit is contained in:
commit
e8340ff610
28 changed files with 1099 additions and 394 deletions
26
.github/workflows/ci.yml
vendored
26
.github/workflows/ci.yml
vendored
|
|
@ -11,7 +11,7 @@ jobs:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
submodules: recursive
|
submodules: recursive
|
||||||
- run: TERM=xterm-256color ./make.sh assert-linear
|
- run: COLOR=1 ./make.sh assert-linear
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
||||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
|
|
@ -25,7 +25,21 @@ jobs:
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
cache: true
|
cache: true
|
||||||
- run: TERM=xterm-256color ./make.sh fmt
|
- run: COLOR=1 ./make.sh fmt
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
||||||
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
|
gen:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
- uses: actions/setup-go@v3
|
||||||
|
with:
|
||||||
|
go-version-file: ./go.mod
|
||||||
|
cache: true
|
||||||
|
- run: COLOR=1 ./make.sh gen
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
||||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
|
|
@ -39,7 +53,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
cache: true
|
cache: true
|
||||||
- run: TERM=xterm-256color ./make.sh lint
|
- run: COLOR=1 ./make.sh lint
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
||||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
|
|
@ -53,7 +67,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
cache: true
|
cache: true
|
||||||
- run: TERM=xterm-256color ./make.sh build
|
- run: COLOR=1 ./make.sh build
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
||||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
|
|
@ -67,7 +81,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
cache: true
|
cache: true
|
||||||
- run: TERM=xterm-256color ./make.sh test
|
- run: COLOR=1 ./make.sh test
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
||||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
|
|
@ -86,7 +100,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
cache: true
|
cache: true
|
||||||
- run: TERM=xterm-256color ./make.sh race
|
- run: COLOR=1 ./make.sh race
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
||||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
|
|
|
||||||
2
.github/workflows/daily.yml
vendored
2
.github/workflows/daily.yml
vendored
|
|
@ -20,7 +20,7 @@ jobs:
|
||||||
with:
|
with:
|
||||||
go-version-file: ./go.mod
|
go-version-file: ./go.mod
|
||||||
cache: true
|
cache: true
|
||||||
- run: CI_ALL=1 TERM=xterm-256color ./make.sh
|
- run: CI_ALL=1 COLOR=1 ./make.sh
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets._GITHUB_TOKEN }}
|
||||||
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
||||||
|
|
|
||||||
5
Makefile
5
Makefile
|
|
@ -1,7 +1,7 @@
|
||||||
.POSIX:
|
.POSIX:
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: fmt lint build test
|
all: fmt gen lint build test
|
||||||
ifdef CI
|
ifdef CI
|
||||||
all: assert-linear
|
all: assert-linear
|
||||||
endif
|
endif
|
||||||
|
|
@ -9,6 +9,9 @@ endif
|
||||||
.PHONY: fmt
|
.PHONY: fmt
|
||||||
fmt:
|
fmt:
|
||||||
prefix "$@" ./ci/sub/fmt/make.sh
|
prefix "$@" ./ci/sub/fmt/make.sh
|
||||||
|
.PHONY: gen
|
||||||
|
gen:
|
||||||
|
prefix "$@" ./ci/gen.sh
|
||||||
.PHONY: lint
|
.PHONY: lint
|
||||||
lint:
|
lint:
|
||||||
prefix "$@" go vet --composites=false ./...
|
prefix "$@" go vet --composites=false ./...
|
||||||
|
|
|
||||||
30
README.md
30
README.md
|
|
@ -22,8 +22,6 @@
|
||||||
|
|
||||||
- [Quickstart](#quickstart)
|
- [Quickstart](#quickstart)
|
||||||
- [Install](#install)
|
- [Install](#install)
|
||||||
* [Install script](#install-script)
|
|
||||||
* [Install from source](#install-from-source)
|
|
||||||
- [D2 as a library](#d2-as-a-library)
|
- [D2 as a library](#d2-as-a-library)
|
||||||
- [Themes](#themes)
|
- [Themes](#themes)
|
||||||
- [Fonts](#fonts)
|
- [Fonts](#fonts)
|
||||||
|
|
@ -58,42 +56,20 @@ A browser window will open with `out.svg` and live-reload on changes to `in.d2`.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
### Install script
|
The easiest way to install is with our install script:
|
||||||
|
|
||||||
The recommended way to install is to run our install script, which will figure out the
|
|
||||||
best way to install based on your machine.
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
# With --dry-run the install script will print the commands it will use
|
|
||||||
# to install without actually installing so you know what it's going to do.
|
|
||||||
curl -fsSL https://d2lang.com/install.sh | sh -s -- --dry-run
|
|
||||||
# If things look good, install for real.
|
|
||||||
curl -fsSL https://d2lang.com/install.sh | sh -s --
|
curl -fsSL https://d2lang.com/install.sh | sh -s --
|
||||||
```
|
```
|
||||||
|
|
||||||
We have precompiled binaries on the [releases](https://github.com/terrastruct/d2/releases)
|
|
||||||
page for macOS and Linux. For both amd64 and arm64. We will release package manager
|
|
||||||
distributions like .rpm, .deb soon. We also want to get D2 on Homebrew for macOS
|
|
||||||
and release a docker image.
|
|
||||||
|
|
||||||
To uninstall:
|
To uninstall:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
curl -fsSL https://d2lang.com/install.sh | sh -s -- --uninstall --dry-run
|
|
||||||
# If things look good, uninstall for real.
|
|
||||||
curl -fsSL https://d2lang.com/install.sh | sh -s -- --uninstall
|
curl -fsSL https://d2lang.com/install.sh | sh -s -- --uninstall
|
||||||
```
|
```
|
||||||
|
|
||||||
> warn: Our binary releases aren't fully portable like normal Go binaries due to the C
|
For detailed installation docs, with alternative methods and examples for each OS, see
|
||||||
> dependency on v8go for executing dagre.
|
[./docs/INSTALL.md](./docs/INSTALL.md).
|
||||||
|
|
||||||
### Install from source
|
|
||||||
|
|
||||||
Alternatively, you can install from source:
|
|
||||||
|
|
||||||
```sh
|
|
||||||
go install oss.terrastruct.com/d2
|
|
||||||
```
|
|
||||||
|
|
||||||
## D2 as a library
|
## D2 as a library
|
||||||
|
|
||||||
|
|
|
||||||
11
ci/gen.sh
Executable file
11
ci/gen.sh
Executable file
|
|
@ -0,0 +1,11 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
cd -- "$(dirname "$0")/.."
|
||||||
|
. ./ci/sub/lib.sh
|
||||||
|
|
||||||
|
./ci/release/gen_install.sh
|
||||||
|
./ci/release/gen_template_lib.sh
|
||||||
|
|
||||||
|
if [ -n "${CI-}" ]; then
|
||||||
|
git_assert_clean
|
||||||
|
fi
|
||||||
|
|
@ -18,8 +18,11 @@ usage: $arg0 [--dry-run] [--version vX.X.X] [--edge] [--method detect] [--prefix
|
||||||
[--tala latest] [--force] [--uninstall]
|
[--tala latest] [--force] [--uninstall]
|
||||||
|
|
||||||
install.sh automates the installation of D2 onto your system. It currently only supports
|
install.sh automates the installation of D2 onto your system. It currently only supports
|
||||||
the installation of standalone releases from GitHub. If you pass --edge, it will clone the
|
the installation of standalone releases from GitHub and via Homebrew on macOS. See the
|
||||||
source, build a release and install from it.
|
docs for --detect below for more information
|
||||||
|
|
||||||
|
If you pass --edge, it will clone the source, build a release and install from it.
|
||||||
|
--edge is incompatible with --tala and currently unimplemented.
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
|
|
||||||
|
|
@ -29,6 +32,8 @@ Flags:
|
||||||
|
|
||||||
--version vX.X.X
|
--version vX.X.X
|
||||||
Pass to have install.sh install the given version instead of the latest version.
|
Pass to have install.sh install the given version instead of the latest version.
|
||||||
|
warn: The version may not be obeyed with package manager installations. Use
|
||||||
|
--method=standalone to enforce the version.
|
||||||
|
|
||||||
--edge
|
--edge
|
||||||
Pass to build and install D2 from source. This will still use --method if set to detect
|
Pass to build and install D2 from source. This will still use --method if set to detect
|
||||||
|
|
@ -36,14 +41,15 @@ Flags:
|
||||||
if an unsupported package manager is used. To install from source like a dev would,
|
if an unsupported package manager is used. To install from source like a dev would,
|
||||||
use go install oss.terrastruct.com/d2
|
use go install oss.terrastruct.com/d2
|
||||||
note: currently unimplemented.
|
note: currently unimplemented.
|
||||||
|
warn: incompatible with --tala as TALA is closed source.
|
||||||
|
|
||||||
--method [detect | standalone]
|
--method [detect | standalone | homebrew ]
|
||||||
Pass to control the method by which to install. Right now we only support standalone
|
Pass to control the method by which to install. Right now we only support standalone
|
||||||
releases from GitHub but later we'll add support for brew, rpm, deb and more.
|
releases from GitHub but later we'll add support for brew, rpm, deb and more.
|
||||||
note: currently unimplemented.
|
|
||||||
|
|
||||||
- detect is currently unimplemented but would use your OS's package manager
|
- detect will use your OS's package manager automatically.
|
||||||
automatically.
|
So far it only detects macOS and automatically uses homebrew.
|
||||||
|
- homebrew uses https://brew.sh/ which is a macOS and Linux package manager.
|
||||||
- standalone installs a standalone release archive into the unix hierarchy path
|
- standalone installs a standalone release archive into the unix hierarchy path
|
||||||
specified by --prefix which defaults to /usr/local
|
specified by --prefix which defaults to /usr/local
|
||||||
Ensure /usr/local/bin is in your \$PATH to use it.
|
Ensure /usr/local/bin is in your \$PATH to use it.
|
||||||
|
|
@ -51,16 +57,19 @@ Flags:
|
||||||
--prefix /usr/local
|
--prefix /usr/local
|
||||||
Controls the unix hierarchy path into which standalone releases are installed.
|
Controls the unix hierarchy path into which standalone releases are installed.
|
||||||
Defaults to /usr/local. You may also want to use ~/.local to avoid needing sudo.
|
Defaults to /usr/local. You may also want to use ~/.local to avoid needing sudo.
|
||||||
Remember that whatever you use, you must have the bin directory of your prefix
|
We use ~/.local by default on arm64 macOS machines as SIP now disables access to
|
||||||
path in \$PATH to execute the d2 binary. For example, if my prefix directory is
|
/usr/local. Remember that whatever you use, you must have the bin directory of your
|
||||||
|
prefix path in \$PATH to execute the d2 binary. For example, if my prefix directory is
|
||||||
/usr/local then my \$PATH must contain /usr/local/bin.
|
/usr/local then my \$PATH must contain /usr/local/bin.
|
||||||
|
|
||||||
--tala [latest]
|
--tala [latest]
|
||||||
Install Terrastruct's closed source TALA for improved layouts.
|
Install Terrastruct's closed source TALA for improved layouts.
|
||||||
See https://github.com/terrastruct/TALA
|
See https://github.com/terrastruct/tala
|
||||||
It optionally takes an argument of the TALA version to install.
|
It optionally takes an argument of the TALA version to install.
|
||||||
Installation obeys all other flags, just like the installation of d2. For example,
|
Installation obeys all other flags, just like the installation of d2. For example,
|
||||||
the d2plugin-tala binary will be installed into /usr/local/bin/d2plugin-tala
|
the d2plugin-tala binary will be installed into /usr/local/bin/d2plugin-tala
|
||||||
|
warn: The version may not be obeyed with package manager installations. Use
|
||||||
|
--method=standalone to enforce the version.
|
||||||
|
|
||||||
--force:
|
--force:
|
||||||
Force installation over the existing version even if they match. It will attempt a
|
Force installation over the existing version even if they match. It will attempt a
|
||||||
|
|
@ -73,6 +82,7 @@ Flags:
|
||||||
as for installation. i.e if you used --method standalone you must again use --method
|
as for installation. i.e if you used --method standalone you must again use --method
|
||||||
standalone for uninstallation. With detect, the install script will try to use the OS
|
standalone for uninstallation. With detect, the install script will try to use the OS
|
||||||
package manager to uninstall instead.
|
package manager to uninstall instead.
|
||||||
|
note: tala will also be uninstalled if installed.
|
||||||
|
|
||||||
All downloaded archives are cached into ~/.cache/d2/release. use \$XDG_CACHE_HOME to change
|
All downloaded archives are cached into ~/.cache/d2/release. use \$XDG_CACHE_HOME to change
|
||||||
path of the cached assets. Release archives are unarchived into /usr/local/lib/d2/d2-<VERSION>
|
path of the cached assets. Release archives are unarchived into /usr/local/lib/d2/d2-<VERSION>
|
||||||
|
|
@ -85,9 +95,7 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
METHOD=standalone
|
while flag_parse "$@"; do
|
||||||
while :; do
|
|
||||||
flag_parse "$@"
|
|
||||||
case "$FLAG" in
|
case "$FLAG" in
|
||||||
h|help)
|
h|help)
|
||||||
help
|
help
|
||||||
|
|
@ -114,8 +122,6 @@ main() {
|
||||||
method)
|
method)
|
||||||
flag_nonemptyarg && shift "$FLAGSHIFT"
|
flag_nonemptyarg && shift "$FLAGSHIFT"
|
||||||
METHOD=$FLAGARG
|
METHOD=$FLAGARG
|
||||||
echoerr "$FLAGRAW is currently unimplemented"
|
|
||||||
return 1
|
|
||||||
;;
|
;;
|
||||||
prefix)
|
prefix)
|
||||||
flag_nonemptyarg && shift "$FLAGSHIFT"
|
flag_nonemptyarg && shift "$FLAGSHIFT"
|
||||||
|
|
@ -129,15 +135,12 @@ main() {
|
||||||
flag_noarg && shift "$FLAGSHIFT"
|
flag_noarg && shift "$FLAGSHIFT"
|
||||||
UNINSTALL=1
|
UNINSTALL=1
|
||||||
;;
|
;;
|
||||||
'')
|
|
||||||
shift "$FLAGSHIFT"
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
flag_errusage "unrecognized flag $FLAGRAW"
|
flag_errusage "unrecognized flag $FLAGRAW"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
shift "$FLAGSHIFT"
|
||||||
|
|
||||||
if [ $# -gt 0 ]; then
|
if [ $# -gt 0 ]; then
|
||||||
flag_errusage "no arguments are accepted"
|
flag_errusage "no arguments are accepted"
|
||||||
|
|
@ -153,42 +156,79 @@ main() {
|
||||||
PREFIX=${PREFIX:-/usr/local}
|
PREFIX=${PREFIX:-/usr/local}
|
||||||
CACHE_DIR=$(cache_dir)
|
CACHE_DIR=$(cache_dir)
|
||||||
mkdir -p "$CACHE_DIR"
|
mkdir -p "$CACHE_DIR"
|
||||||
|
METHOD=${METHOD:-detect}
|
||||||
INSTALL_DIR=$PREFIX/lib/d2
|
INSTALL_DIR=$PREFIX/lib/d2
|
||||||
|
|
||||||
|
case $METHOD in
|
||||||
|
detect)
|
||||||
|
case "$OS" in
|
||||||
|
macos)
|
||||||
|
if command -v brew >/dev/null; then
|
||||||
|
log "detected macOS with homebrew, using homebrew for (un)installation"
|
||||||
|
METHOD=homebrew
|
||||||
|
else
|
||||||
|
warn "detected macOS without homebrew, falling back to --method=standalone"
|
||||||
|
METHOD=standalone
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
warn "unrecognized OS $OS, falling back to --method=standalone"
|
||||||
|
METHOD=standalone
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
standalone) ;;
|
||||||
|
homebrew) ;;
|
||||||
|
*)
|
||||||
|
echoerr "unknown (un)installation method $METHOD"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ -n "${UNINSTALL-}" ]; then
|
if [ -n "${UNINSTALL-}" ]; then
|
||||||
uninstall
|
uninstall
|
||||||
return 0
|
if [ -n "${DRY_RUN-}" ]; then
|
||||||
|
log "Rerun without --dry-run to execute printed commands and perform uninstall."
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
VERSION=${VERSION:-latest}
|
|
||||||
if [ "$VERSION" = latest ]; then
|
|
||||||
header "fetching latest release info"
|
|
||||||
fetch_release_info
|
|
||||||
fi
|
|
||||||
|
|
||||||
install
|
install
|
||||||
|
if [ -n "${DRY_RUN-}" ]; then
|
||||||
|
log "Rerun without --dry-run to execute printed commands and perform install."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
install_d2
|
case $METHOD in
|
||||||
|
standalone)
|
||||||
|
install_d2_standalone
|
||||||
if [ -n "${TALA-}" ]; then
|
if [ -n "${TALA-}" ]; then
|
||||||
# Run in subshell to avoid overwriting VERSION.
|
# Run in subshell to avoid overwriting VERSION.
|
||||||
TALA_VERSION="$( install_tala && echo "$VERSION" )"
|
TALA_VERSION="$( RELEASE_INFO= install_tala_standalone && echo "$VERSION" )"
|
||||||
fi
|
fi
|
||||||
|
;;
|
||||||
|
homebrew)
|
||||||
|
install_d2_brew
|
||||||
|
if [ -n "${TALA-}" ]; then install_tala_brew; fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
COLOR=2 header success
|
FGCOLOR=2 bigheader 'next steps'
|
||||||
|
case $METHOD in
|
||||||
|
standalone) install_post_standalone ;;
|
||||||
|
homebrew) install_post_brew ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
install_post_standalone() {
|
||||||
log "d2-$VERSION-$OS-$ARCH has been successfully installed into $PREFIX"
|
log "d2-$VERSION-$OS-$ARCH has been successfully installed into $PREFIX"
|
||||||
if [ -n "${TALA-}" ]; then
|
if [ -n "${TALA-}" ]; then
|
||||||
log "tala-$TALA_VERSION-$OS-$ARCH has been successfully installed into $PREFIX"
|
log "tala-$TALA_VERSION-$OS-$ARCH has been successfully installed into $PREFIX"
|
||||||
fi
|
fi
|
||||||
log "Rerun this install script with --uninstall to uninstall"
|
log "Rerun this install script with --uninstall to uninstall."
|
||||||
|
log
|
||||||
if ! echo "$PATH" | grep -qF "$PREFIX/bin"; then
|
if ! echo "$PATH" | grep -qF "$PREFIX/bin"; then
|
||||||
logcat >&2 <<EOF
|
logcat >&2 <<EOF
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
NEXT STEPS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Extend your \$PATH to use d2:
|
Extend your \$PATH to use d2:
|
||||||
export PATH=$PREFIX/bin:\$PATH
|
export PATH=$PREFIX/bin:\$PATH
|
||||||
Then run:
|
Then run:
|
||||||
|
|
@ -210,34 +250,59 @@ EOF
|
||||||
else
|
else
|
||||||
log "Run man d2 for detailed docs."
|
log "Run man d2 for detailed docs."
|
||||||
if [ -n "${TALA-}" ]; then
|
if [ -n "${TALA-}" ]; then
|
||||||
log " Run man d2plugin-tala for detailed docs."
|
log "Run man d2plugin-tala for detailed TALA docs."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
logcat >&2 <<EOF
|
logcat >&2 <<EOF
|
||||||
|
|
||||||
Something not working? Please let us know:
|
Something not working? Please let us know:
|
||||||
https://github.com/terrastruct/d2/issues/new
|
https://github.com/terrastruct/d2/issues
|
||||||
|
https://github.com/terrastruct/d2/discussions
|
||||||
|
https://discord.gg/NF6X8K4eDq
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
install_d2() {
|
install_post_brew() {
|
||||||
|
log "d2 has been successfully installed with homebrew."
|
||||||
|
if [ -n "${TALA-}" ]; then
|
||||||
|
log "tala has been successfully installed with homebrew."
|
||||||
|
fi
|
||||||
|
log "Rerun this install script with --uninstall to uninstall."
|
||||||
|
log
|
||||||
|
log "Run ${TALA+D2_LAYOUT=tala }d2 --help for usage."
|
||||||
|
log "Run man d2 for detailed docs."
|
||||||
|
if [ -n "${TALA-}" ]; then
|
||||||
|
log "Run man d2plugin-tala for detailed TALA docs."
|
||||||
|
fi
|
||||||
|
logcat >&2 <<EOF
|
||||||
|
|
||||||
|
Something not working? Please let us know:
|
||||||
|
https://github.com/terrastruct/d2/issues
|
||||||
|
https://github.com/terrastruct/d2/discussions
|
||||||
|
https://discord.gg/NF6X8K4eDq
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
install_d2_standalone() {
|
||||||
|
VERSION=${VERSION:-latest}
|
||||||
|
header "installing d2-$VERSION"
|
||||||
|
|
||||||
|
if [ "$VERSION" = latest ]; then
|
||||||
|
fetch_release_info
|
||||||
|
fi
|
||||||
|
|
||||||
if command -v d2 >/dev/null; then
|
if command -v d2 >/dev/null; then
|
||||||
INSTALLED_VERSION="$(d2 version)"
|
INSTALLED_VERSION="$(d2 version)"
|
||||||
if [ ! "${FORCE-}" -a "$VERSION" = "$INSTALLED_VERSION" ]; then
|
if [ ! "${FORCE-}" -a "$VERSION" = "$INSTALLED_VERSION" ]; then
|
||||||
log "skipping installation as version $VERSION is already installed."
|
log "skipping installation as d2 $VERSION is already installed."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
log "uninstalling $INSTALLED_VERSION to install $VERSION"
|
log "uninstalling d2 $INSTALLED_VERSION to install $VERSION"
|
||||||
if ! uninstall_d2; then
|
if ! uninstall_d2_standalone; then
|
||||||
warn "failed to uninstall $INSTALLED_VERSION"
|
warn "failed to uninstall d2 $INSTALLED_VERSION"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
header "installing d2-$VERSION"
|
|
||||||
install_standalone_d2
|
|
||||||
}
|
|
||||||
|
|
||||||
install_standalone_d2() {
|
|
||||||
ARCHIVE="d2-$VERSION-$OS-$ARCH.tar.gz"
|
ARCHIVE="d2-$VERSION-$OS-$ARCH.tar.gz"
|
||||||
log "installing standalone release $ARCHIVE from github"
|
log "installing standalone release $ARCHIVE from github"
|
||||||
|
|
||||||
|
|
@ -256,19 +321,38 @@ install_standalone_d2() {
|
||||||
"$sh_c" sh -c "'cd \"$INSTALL_DIR/d2-$VERSION\" && make install PREFIX=\"$PREFIX\"'"
|
"$sh_c" sh -c "'cd \"$INSTALL_DIR/d2-$VERSION\" && make install PREFIX=\"$PREFIX\"'"
|
||||||
}
|
}
|
||||||
|
|
||||||
install_tala() {
|
install_d2_brew() {
|
||||||
REPO="${REPO_TALA:-terrastruct/TALA}"
|
header "installing d2 with homebrew"
|
||||||
VERSION=$TALA
|
sh_c brew tap terrastruct/d2
|
||||||
RELEASE_INFO=
|
sh_c brew install d2
|
||||||
fetch_release_info
|
|
||||||
header "installing tala-$VERSION"
|
|
||||||
install_standalone_tala
|
|
||||||
}
|
}
|
||||||
|
|
||||||
install_standalone_tala() {
|
install_tala_standalone() {
|
||||||
|
REPO="${REPO_TALA:-terrastruct/tala}"
|
||||||
|
VERSION=$TALA
|
||||||
|
|
||||||
|
header "installing tala-$VERSION"
|
||||||
|
|
||||||
|
if [ "$VERSION" = latest ]; then
|
||||||
|
fetch_release_info
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v d2plugin-tala >/dev/null; then
|
||||||
|
INSTALLED_VERSION="$(d2plugin-tala --version)"
|
||||||
|
if [ ! "${FORCE-}" -a "$VERSION" = "$INSTALLED_VERSION" ]; then
|
||||||
|
log "skipping installation as tala $VERSION is already installed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log "uninstalling tala $INSTALLED_VERSION to install $VERSION"
|
||||||
|
if ! uninstall_tala_standalone; then
|
||||||
|
warn "failed to uninstall tala $INSTALLED_VERSION"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
ARCHIVE="tala-$VERSION-$OS-$ARCH.tar.gz"
|
ARCHIVE="tala-$VERSION-$OS-$ARCH.tar.gz"
|
||||||
log "installing standalone release $ARCHIVE from github"
|
log "installing standalone release $ARCHIVE from github"
|
||||||
|
|
||||||
|
fetch_release_info
|
||||||
asset_line=$(sh_c 'cat "$RELEASE_INFO" | grep -n "$ARCHIVE" | cut -d: -f1 | head -n1')
|
asset_line=$(sh_c 'cat "$RELEASE_INFO" | grep -n "$ARCHIVE" | cut -d: -f1 | head -n1')
|
||||||
asset_url=$(sh_c 'sed -n $((asset_line-3))p "$RELEASE_INFO" | sed "s/^.*: \"\(.*\)\",$/\1/g"')
|
asset_url=$(sh_c 'sed -n $((asset_line-3))p "$RELEASE_INFO" | sed "s/^.*: \"\(.*\)\",$/\1/g"')
|
||||||
|
|
||||||
|
|
@ -284,36 +368,40 @@ install_standalone_tala() {
|
||||||
"$sh_c" sh -c "'cd \"$INSTALL_DIR/tala-$VERSION\" && make install PREFIX=\"$PREFIX\"'"
|
"$sh_c" sh -c "'cd \"$INSTALL_DIR/tala-$VERSION\" && make install PREFIX=\"$PREFIX\"'"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_tala_brew() {
|
||||||
|
header "installing tala with homebrew"
|
||||||
|
sh_c brew tap terrastruct/d2
|
||||||
|
sh_c brew install tala
|
||||||
|
}
|
||||||
|
|
||||||
uninstall() {
|
uninstall() {
|
||||||
|
# We uninstall tala first as package managers require that it be uninstalled before
|
||||||
|
# uninstalling d2 as TALA depends on d2.
|
||||||
|
if command -v d2plugin-tala >/dev/null; then
|
||||||
|
INSTALLED_VERSION="$(d2plugin-tala --version)"
|
||||||
|
header "uninstalling tala-$INSTALLED_VERSION"
|
||||||
|
case $METHOD in
|
||||||
|
standalone) uninstall_tala_standalone ;;
|
||||||
|
homebrew) uninstall_tala_brew ;;
|
||||||
|
esac
|
||||||
|
elif [ "${TALA-}" ]; then
|
||||||
|
warn "no version of tala installed"
|
||||||
|
fi
|
||||||
|
|
||||||
if ! command -v d2 >/dev/null; then
|
if ! command -v d2 >/dev/null; then
|
||||||
warn "no version of d2 installed"
|
warn "no version of d2 installed"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INSTALLED_VERSION="$(d2 --version)"
|
INSTALLED_VERSION="$(d2 --version)"
|
||||||
if ! uninstall_d2; then
|
|
||||||
echoerr "failed to uninstall $INSTALLED_VERSION"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if [ "${TALA-}" ]; then
|
|
||||||
if ! command -v d2plugin-tala >/dev/null; then
|
|
||||||
warn "no version of tala installed"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
INSTALLED_VERSION="$(d2plugin-tala --version)"
|
|
||||||
if ! uninstall_tala; then
|
|
||||||
echoerr "failed to uninstall tala $INSTALLED_VERSION"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
uninstall_d2() {
|
|
||||||
header "uninstalling d2-$INSTALLED_VERSION"
|
header "uninstalling d2-$INSTALLED_VERSION"
|
||||||
uninstall_standalone_d2
|
case $METHOD in
|
||||||
|
standalone) uninstall_d2_standalone ;;
|
||||||
|
homebrew) uninstall_d2_brew ;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_standalone_d2() {
|
uninstall_d2_standalone() {
|
||||||
log "uninstalling standalone release of d2-$INSTALLED_VERSION"
|
log "uninstalling standalone release of d2-$INSTALLED_VERSION"
|
||||||
|
|
||||||
if [ ! -e "$INSTALL_DIR/d2-$INSTALLED_VERSION" ]; then
|
if [ ! -e "$INSTALL_DIR/d2-$INSTALLED_VERSION" ]; then
|
||||||
|
|
@ -331,12 +419,11 @@ uninstall_standalone_d2() {
|
||||||
"$sh_c" rm -rf "$INSTALL_DIR/d2-$INSTALLED_VERSION"
|
"$sh_c" rm -rf "$INSTALL_DIR/d2-$INSTALLED_VERSION"
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_tala() {
|
uninstall_d2_brew() {
|
||||||
header "uninstalling tala-$INSTALLED_VERSION"
|
sh_c brew remove d2
|
||||||
uninstall_standalone_tala
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_standalone_tala() {
|
uninstall_tala_standalone() {
|
||||||
log "uninstalling standalone release tala-$INSTALLED_VERSION"
|
log "uninstalling standalone release tala-$INSTALLED_VERSION"
|
||||||
|
|
||||||
if [ ! -e "$INSTALL_DIR/tala-$INSTALLED_VERSION" ]; then
|
if [ ! -e "$INSTALL_DIR/tala-$INSTALLED_VERSION" ]; then
|
||||||
|
|
@ -354,6 +441,10 @@ uninstall_standalone_tala() {
|
||||||
"$sh_c" rm -rf "$INSTALL_DIR/tala-$INSTALLED_VERSION"
|
"$sh_c" rm -rf "$INSTALL_DIR/tala-$INSTALLED_VERSION"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uninstall_tala_brew() {
|
||||||
|
sh_c brew remove tala
|
||||||
|
}
|
||||||
|
|
||||||
is_prefix_writable() {
|
is_prefix_writable() {
|
||||||
sh_c "mkdir -p '$INSTALL_DIR' 2>/dev/null" || true
|
sh_c "mkdir -p '$INSTALL_DIR' 2>/dev/null" || true
|
||||||
# The reason for checking whether $INSTALL_DIR is writable is that on macOS you have
|
# The reason for checking whether $INSTALL_DIR is writable is that on macOS you have
|
||||||
|
|
@ -409,4 +500,9 @@ fetch_gh() {
|
||||||
sh_c mv "$file.inprogress" "$file"
|
sh_c mv "$file.inprogress" "$file"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
brew() {
|
||||||
|
# Makes brew sane.
|
||||||
|
HOMEBREW_NO_INSTALL_CLEANUP=1 HOMEBREW_NO_AUTO_UPDATE=1 command brew "$@"
|
||||||
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|
|
||||||
|
|
@ -42,8 +42,7 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
while :; do
|
while flag_parse "$@"; do
|
||||||
flag_parse "$@"
|
|
||||||
case "$FLAG" in
|
case "$FLAG" in
|
||||||
h|help)
|
h|help)
|
||||||
help
|
help
|
||||||
|
|
@ -78,16 +77,12 @@ main() {
|
||||||
flag_noarg && shift "$FLAGSHIFT"
|
flag_noarg && shift "$FLAGSHIFT"
|
||||||
LOCKFILE_FORCE=1
|
LOCKFILE_FORCE=1
|
||||||
;;
|
;;
|
||||||
'')
|
|
||||||
shift "$FLAGSHIFT"
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
flag_errusage "unrecognized flag $FLAGRAW"
|
flag_errusage "unrecognized flag $FLAGRAW"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
shift "$FLAGSHIFT"
|
||||||
if [ $# -gt 0 ]; then
|
if [ $# -gt 0 ]; then
|
||||||
flag_errusage "no arguments are accepted"
|
flag_errusage "no arguments are accepted"
|
||||||
fi
|
fi
|
||||||
|
|
@ -169,16 +164,16 @@ build_local() {
|
||||||
|
|
||||||
build_remote_macos() {
|
build_remote_macos() {
|
||||||
sh_c lockfile_ssh "$REMOTE_HOST" .d2-build-lock
|
sh_c lockfile_ssh "$REMOTE_HOST" .d2-build-lock
|
||||||
trap unlockfile_ssh EXIT
|
|
||||||
sh_c ssh "$REMOTE_HOST" mkdir -p src
|
sh_c ssh "$REMOTE_HOST" mkdir -p src
|
||||||
sh_c rsync --archive --human-readable --delete ./ "$REMOTE_HOST:src/d2/"
|
sh_c rsync --archive --human-readable --delete ./ "$REMOTE_HOST:src/d2/"
|
||||||
sh_c ssh "$REMOTE_HOST" "DRY_RUN=${DRY_RUN-} \
|
sh_c ssh "$REMOTE_HOST" "COLOR=${COLOR-} \
|
||||||
|
TERM=${TERM-} \
|
||||||
|
DRY_RUN=${DRY_RUN-} \
|
||||||
HW_BUILD_DIR=$HW_BUILD_DIR \
|
HW_BUILD_DIR=$HW_BUILD_DIR \
|
||||||
VERSION=$VERSION \
|
VERSION=$VERSION \
|
||||||
OS=$OS \
|
OS=$OS \
|
||||||
ARCH=$ARCH \
|
ARCH=$ARCH \
|
||||||
ARCHIVE=$ARCHIVE \
|
ARCHIVE=$ARCHIVE \
|
||||||
TERM=$TERM \
|
|
||||||
PATH=\\\"/usr/local/bin:/usr/local/sbin:/opt/homebrew/bin:/opt/homebrew/sbin\\\${PATH+:\\\$PATH}\\\" \
|
PATH=\\\"/usr/local/bin:/usr/local/sbin:/opt/homebrew/bin:/opt/homebrew/sbin\\\${PATH+:\\\$PATH}\\\" \
|
||||||
./src/d2/ci/release/_build.sh"
|
./src/d2/ci/release/_build.sh"
|
||||||
sh_c mkdir -p "$HW_BUILD_DIR"
|
sh_c mkdir -p "$HW_BUILD_DIR"
|
||||||
|
|
@ -187,16 +182,16 @@ PATH=\\\"/usr/local/bin:/usr/local/sbin:/opt/homebrew/bin:/opt/homebrew/sbin\\\$
|
||||||
|
|
||||||
build_remote_linux() {
|
build_remote_linux() {
|
||||||
sh_c lockfile_ssh "$REMOTE_HOST" .d2-build-lock
|
sh_c lockfile_ssh "$REMOTE_HOST" .d2-build-lock
|
||||||
trap unlockfile_ssh EXIT
|
|
||||||
sh_c ssh "$REMOTE_HOST" mkdir -p src
|
sh_c ssh "$REMOTE_HOST" mkdir -p src
|
||||||
sh_c rsync --archive --human-readable --delete ./ "$REMOTE_HOST:src/d2/"
|
sh_c rsync --archive --human-readable --delete ./ "$REMOTE_HOST:src/d2/"
|
||||||
sh_c ssh "$REMOTE_HOST" "DRY_RUN=${DRY_RUN-} \
|
sh_c ssh "$REMOTE_HOST" "COLOR=${COLOR-} \
|
||||||
|
TERM=${TERM-} \
|
||||||
|
DRY_RUN=${DRY_RUN-} \
|
||||||
HW_BUILD_DIR=$HW_BUILD_DIR \
|
HW_BUILD_DIR=$HW_BUILD_DIR \
|
||||||
VERSION=$VERSION \
|
VERSION=$VERSION \
|
||||||
OS=$OS \
|
OS=$OS \
|
||||||
ARCH=$ARCH \
|
ARCH=$ARCH \
|
||||||
ARCHIVE=$ARCHIVE \
|
ARCHIVE=$ARCHIVE \
|
||||||
TERM=$TERM \
|
|
||||||
./src/d2/ci/release/build_docker.sh"
|
./src/d2/ci/release/build_docker.sh"
|
||||||
sh_c mkdir -p "$HW_BUILD_DIR"
|
sh_c mkdir -p "$HW_BUILD_DIR"
|
||||||
sh_c rsync --archive --human-readable "$REMOTE_HOST:src/d2/$ARCHIVE" "$ARCHIVE"
|
sh_c rsync --archive --human-readable "$REMOTE_HOST:src/d2/$ARCHIVE" "$ARCHIVE"
|
||||||
|
|
|
||||||
|
|
@ -13,5 +13,4 @@ docker_run \
|
||||||
-e OS \
|
-e OS \
|
||||||
-e ARCH \
|
-e ARCH \
|
||||||
-e ARCHIVE \
|
-e ARCHIVE \
|
||||||
-e TERM \
|
|
||||||
"$tag" ./src/d2/ci/release/_build.sh
|
"$tag" ./src/d2/ci/release/_build.sh
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
while :; do
|
while flag_parse "$@"; do
|
||||||
flag_parse "$@"
|
|
||||||
case "$FLAG" in
|
case "$FLAG" in
|
||||||
h|help)
|
h|help)
|
||||||
help
|
help
|
||||||
|
|
@ -27,15 +26,12 @@ main() {
|
||||||
flag_nonemptyarg && shift "$FLAGSHIFT"
|
flag_nonemptyarg && shift "$FLAGSHIFT"
|
||||||
KEY_FILE=$FLAGARG
|
KEY_FILE=$FLAGARG
|
||||||
;;
|
;;
|
||||||
'')
|
|
||||||
shift "$FLAGSHIFT"
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
flag_errusage "unrecognized flag $FLAGRAW"
|
flag_errusage "unrecognized flag $FLAGRAW"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
shift "$FLAGSHIFT"
|
||||||
if [ -z "${KEY_FILE-}" ]; then
|
if [ -z "${KEY_FILE-}" ]; then
|
||||||
echoerr "-i is required"
|
echoerr "-i is required"
|
||||||
exit 1
|
exit 1
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
while :; do
|
while flag_parse "$@"; do
|
||||||
flag_parse "$@"
|
|
||||||
case "$FLAG" in
|
case "$FLAG" in
|
||||||
h|help)
|
h|help)
|
||||||
help
|
help
|
||||||
|
|
@ -27,15 +26,12 @@ main() {
|
||||||
flag_noarg && shift "$FLAGSHIFT"
|
flag_noarg && shift "$FLAGSHIFT"
|
||||||
SKIP_CREATE=1
|
SKIP_CREATE=1
|
||||||
;;
|
;;
|
||||||
'')
|
|
||||||
shift "$FLAGSHIFT"
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
flag_errusage "unrecognized flag $FLAGRAW"
|
flag_errusage "unrecognized flag $FLAGRAW"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
shift "$FLAGSHIFT"
|
||||||
if [ $# -gt 0 ]; then
|
if [ $# -gt 0 ]; then
|
||||||
flag_errusage "no arguments are accepted"
|
flag_errusage "no arguments are accepted"
|
||||||
fi
|
fi
|
||||||
|
|
@ -204,7 +200,7 @@ init_remote_hosts() {
|
||||||
header macos-arm64
|
header macos-arm64
|
||||||
REMOTE_HOST=$TSTRUCT_MACOS_ARM64_BUILDER init_remote_macos
|
REMOTE_HOST=$TSTRUCT_MACOS_ARM64_BUILDER init_remote_macos
|
||||||
|
|
||||||
COLOR=2 header summary
|
FGCOLOR=2 header summary
|
||||||
log "export TSTRUCT_LINUX_AMD64_BUILDER=$TSTRUCT_LINUX_AMD64_BUILDER"
|
log "export TSTRUCT_LINUX_AMD64_BUILDER=$TSTRUCT_LINUX_AMD64_BUILDER"
|
||||||
log "export TSTRUCT_LINUX_ARM64_BUILDER=$TSTRUCT_LINUX_ARM64_BUILDER"
|
log "export TSTRUCT_LINUX_ARM64_BUILDER=$TSTRUCT_LINUX_ARM64_BUILDER"
|
||||||
log "export TSTRUCT_MACOS_AMD64_BUILDER=$TSTRUCT_MACOS_AMD64_BUILDER"
|
log "export TSTRUCT_MACOS_AMD64_BUILDER=$TSTRUCT_MACOS_AMD64_BUILDER"
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,7 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
while :; do
|
while flag_parse "$@"; do
|
||||||
flag_parse "$@"
|
|
||||||
case "$FLAG" in
|
case "$FLAG" in
|
||||||
h|help)
|
h|help)
|
||||||
help
|
help
|
||||||
|
|
@ -27,15 +26,12 @@ main() {
|
||||||
flag_reqarg && shift "$FLAGSHIFT"
|
flag_reqarg && shift "$FLAGSHIFT"
|
||||||
JOBFILTER="$FLAGARG"
|
JOBFILTER="$FLAGARG"
|
||||||
;;
|
;;
|
||||||
'')
|
|
||||||
shift "$FLAGSHIFT"
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
flag_errusage "unrecognized flag $FLAGRAW"
|
flag_errusage "unrecognized flag $FLAGRAW"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
shift "$FLAGSHIFT"
|
||||||
|
|
||||||
REMOTE_HOST=$TSTRUCT_LINUX_AMD64_BUILDER; runjob linux-amd64 ssh "$REMOTE_HOST" "$@"
|
REMOTE_HOST=$TSTRUCT_LINUX_AMD64_BUILDER; runjob linux-amd64 ssh "$REMOTE_HOST" "$@"
|
||||||
REMOTE_HOST=$TSTRUCT_LINUX_ARM64_BUILDER; runjob linux-arm64 ssh "$REMOTE_HOST" "$@"
|
REMOTE_HOST=$TSTRUCT_LINUX_ARM64_BUILDER; runjob linux-arm64 ssh "$REMOTE_HOST" "$@"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ For v0.0.99 we focused on X, Y and Z. Enjoy!
|
||||||
|
|
||||||
#### Improvements 🔧
|
#### Improvements 🔧
|
||||||
|
|
||||||
- Add table columns indices in edges between SQL Tables so that layout engines can route exactly between them
|
- Equivalency between flags and environment variables. You can set either one for all
|
||||||
|
options (flags take precedence).
|
||||||
|
|
||||||
#### Bugfixes 🔴
|
#### Bugfixes 🔴
|
||||||
|
|
||||||
|
|
|
||||||
29
ci/release/gen_template_lib.sh
Executable file
29
ci/release/gen_template_lib.sh
Executable file
|
|
@ -0,0 +1,29 @@
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
cd -- "$(dirname "$0")/../.."
|
||||||
|
. ./ci/sub/lib.sh
|
||||||
|
|
||||||
|
sh_c chmod +w ./ci/release/template/scripts/lib.sh
|
||||||
|
sh_c cat >./ci/release/template/scripts/lib.sh <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# *************
|
||||||
|
# DO NOT EDIT
|
||||||
|
#
|
||||||
|
# lib.sh was bundled together from
|
||||||
|
#
|
||||||
|
# - ./ci/sub/lib/rand.sh
|
||||||
|
# - ./ci/sub/lib/log.sh
|
||||||
|
#
|
||||||
|
# Generated by ./ci/release/gen_template_lib.sh.
|
||||||
|
# *************
|
||||||
|
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# sed removes the sourcing dependency lines as we're bundled everything into a single
|
||||||
|
# script.
|
||||||
|
sh_c cat \
|
||||||
|
./ci/sub/lib/rand.sh \
|
||||||
|
./ci/sub/lib/log.sh \
|
||||||
|
\| sed "-e'/^\. /d'" \>\>./ci/release/template/scripts/lib.sh
|
||||||
|
sh_c chmod -w ./ci/release/template/scripts/lib.sh
|
||||||
|
|
@ -40,10 +40,22 @@ See more docs, the source code and license at
|
||||||
.It Fl w , -watch Ar false
|
.It Fl w , -watch Ar false
|
||||||
Watch for changes to input and live reload. Use
|
Watch for changes to input and live reload. Use
|
||||||
.Ev $PORT and Ev $HOST to specify the listening address.
|
.Ev $PORT and Ev $HOST to specify the listening address.
|
||||||
.Ev $D2_PORT and $D2_HOST are also accepted and take priority. Default is localhost:0
|
.It Fl h , -host Ar localhost
|
||||||
|
Host listening address when used with
|
||||||
|
.Ar watch
|
||||||
|
.Ns .
|
||||||
|
.It Fl p , -port Ar 0
|
||||||
|
Port listening address when used with
|
||||||
|
.Ar watch
|
||||||
|
.Ns .
|
||||||
.It Fl t , -theme Ar 0
|
.It Fl t , -theme Ar 0
|
||||||
Set the diagram theme to the passed integer. For a list of available options, see
|
Set the diagram theme to the passed integer. For a list of available options, see
|
||||||
.Lk https://oss.terrastruct.com/d2
|
.Lk https://oss.terrastruct.com/d2
|
||||||
|
.Ns .
|
||||||
|
.It Fl l , -layout Ar dagre
|
||||||
|
Set the diagram layout engine to the passed string. For a list of available options, run
|
||||||
|
.Ar layout
|
||||||
|
.Ns .
|
||||||
.It Fl b , -bundle Ar true
|
.It Fl b , -bundle Ar true
|
||||||
Bundle all assets and layers into the output svg.
|
Bundle all assets and layers into the output svg.
|
||||||
.It Fl d , -debug
|
.It Fl d , -debug
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,21 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
|
|
||||||
if [ -n "${DEBUG-}" ]; then
|
# *************
|
||||||
set -x
|
# DO NOT EDIT
|
||||||
|
#
|
||||||
|
# lib.sh was bundled together from
|
||||||
|
#
|
||||||
|
# - ./ci/sub/lib/rand.sh
|
||||||
|
# - ./ci/sub/lib/log.sh
|
||||||
|
#
|
||||||
|
# Generated by ./ci/release/gen_template_lib.sh.
|
||||||
|
# *************
|
||||||
|
|
||||||
|
#!/bin/sh
|
||||||
|
if [ "${LIB_RAND-}" ]; then
|
||||||
|
return 0
|
||||||
fi
|
fi
|
||||||
|
LIB_RAND=1
|
||||||
|
|
||||||
rand() {
|
rand() {
|
||||||
seed="$1"
|
seed="$1"
|
||||||
|
|
@ -14,15 +27,51 @@ rand() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pick() {
|
pick() {
|
||||||
|
if ! command -v shuf >/dev/null || ! command -v md5sum >/dev/null; then
|
||||||
|
eval "_echo \"\$3\""
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
|
||||||
seed="$1"
|
seed="$1"
|
||||||
shift
|
shift
|
||||||
i="$(rand "$seed" "1-$#")"
|
i="$(rand "$seed" "1-$#")"
|
||||||
eval "_echo \"\$$i\""
|
eval "_echo \"\$$i\""
|
||||||
}
|
}
|
||||||
|
#!/bin/sh
|
||||||
|
if [ "${LIB_LOG-}" ]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
LIB_LOG=1
|
||||||
|
|
||||||
|
if [ -n "${DEBUG-}" ]; then
|
||||||
|
set -x
|
||||||
|
fi
|
||||||
|
|
||||||
tput() {
|
tput() {
|
||||||
if [ -n "$TERM" ]; then
|
if should_color; then
|
||||||
command tput "$@"
|
TERM=${TERM:-xterm-256color} command tput "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
should_color() {
|
||||||
|
if [ -n "${COLOR-}" ]; then
|
||||||
|
if [ "$COLOR" = 0 -o "$COLOR" = false ]; then
|
||||||
|
_COLOR=
|
||||||
|
return 1
|
||||||
|
elif [ "$COLOR" = 1 -o "$COLOR" = true ]; then
|
||||||
|
_COLOR=1
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
printf '$COLOR must be 0, 1, false or true but got %s' "$COLOR" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
_COLOR=1
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_COLOR=
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -59,14 +108,14 @@ printfp() {(
|
||||||
prefix="$1"
|
prefix="$1"
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if [ -z "${COLOR:-}" ]; then
|
if [ -z "${FGCOLOR-}" ]; then
|
||||||
COLOR="$(get_rand_color "$prefix")"
|
FGCOLOR="$(get_rand_color "$prefix")"
|
||||||
fi
|
fi
|
||||||
printf '%s' "$(setaf "$COLOR" "$prefix")"
|
should_color || true
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
if [ $# -gt 0 ]; then
|
printf '%s' "$(COLOR=${_COLOR-} setaf "$FGCOLOR" "$prefix")"
|
||||||
printf ': '
|
else
|
||||||
printf "$@"
|
printf '%s: %s\n' "$(COLOR=${_COLOR-} setaf "$FGCOLOR" "$prefix")" "$(printf "$@")"
|
||||||
fi
|
fi
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -74,13 +123,8 @@ catp() {
|
||||||
prefix="$1"
|
prefix="$1"
|
||||||
shift
|
shift
|
||||||
|
|
||||||
printfp "$prefix"
|
should_color || true
|
||||||
printf ': '
|
sed "s/^/$(COLOR=${_COLOR-} printfp "$prefix" '')/"
|
||||||
read -r line
|
|
||||||
_echo "$line"
|
|
||||||
|
|
||||||
indent=$(repeat ' ' 2)
|
|
||||||
sed "s/^/$indent/"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
repeat() {
|
repeat() {
|
||||||
|
|
@ -94,48 +138,150 @@ strlen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
echoerr() {
|
echoerr() {
|
||||||
COLOR=1 echop err "$*" >&2
|
FGCOLOR=1 logp err "$*" | humanpath>&2
|
||||||
}
|
}
|
||||||
|
|
||||||
caterr() {
|
caterr() {
|
||||||
COLOR=1 catp err "$@" >&2
|
FGCOLOR=1 logpcat err "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
printferr() {
|
printferr() {
|
||||||
COLOR=1 printfp err "$@" >&2
|
FGCOLOR=1 logfp err "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
logp() {
|
logp() {
|
||||||
echop "$@" >&2
|
should_color >&2 || true
|
||||||
|
COLOR=${_COLOR-} echop "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
logfp() {
|
logfp() {
|
||||||
printfp "$@" >&2
|
should_color >&2 || true
|
||||||
|
COLOR=${_COLOR-} printfp "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
logpcat() {
|
logpcat() {
|
||||||
catp "$@" >&2
|
should_color >&2 || true
|
||||||
|
COLOR=${_COLOR-} catp "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
COLOR=5 logp log "$@"
|
FGCOLOR=5 logp log "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
logf() {
|
logf() {
|
||||||
COLOR=5 logfp log "$@"
|
FGCOLOR=5 logfp log "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
logcat() {
|
logcat() {
|
||||||
COLOR=5 catp log "$@" >&2
|
FGCOLOR=5 logpcat log "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
FGCOLOR=3 logp warn "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
warnf() {
|
||||||
|
FGCOLOR=3 logfp warn "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
warncat() {
|
||||||
|
FGCOLOR=3 logpcat warn "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
sh_c() {
|
sh_c() {
|
||||||
COLOR=3 logp exec "$*"
|
FGCOLOR=3 logp exec "$*"
|
||||||
if [ -z "${DRY_RUN-}" ]; then
|
if [ -z "${DRY_RUN-}" ]; then
|
||||||
"$@"
|
eval "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
sudo_sh_c() {
|
||||||
|
if [ "$(id -u)" -eq 0 ]; then
|
||||||
|
sh_c "$@"
|
||||||
|
elif command -v doas >/dev/null; then
|
||||||
|
sh_c "doas $*"
|
||||||
|
elif command -v sudo >/dev/null; then
|
||||||
|
sh_c "sudo $*"
|
||||||
|
elif command -v su >/dev/null; then
|
||||||
|
sh_c "su root -c '$*'"
|
||||||
|
else
|
||||||
|
caterr <<EOF
|
||||||
|
This script needs to run the following command as root:
|
||||||
|
$*
|
||||||
|
Please install doas, sudo, or su.
|
||||||
|
EOF
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
header() {
|
header() {
|
||||||
logp "/* $1 */"
|
logp "/* $1 */"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bigheader() {
|
||||||
|
logp "/**
|
||||||
|
* $1
|
||||||
|
**/"
|
||||||
|
}
|
||||||
|
|
||||||
|
# humanpath replaces all occurrences of " $HOME" with " ~"
|
||||||
|
# and all occurrences of '$HOME' with the literal '$HOME'.
|
||||||
|
humanpath() {
|
||||||
|
if [ -z "${HOME-}" ]; then
|
||||||
|
cat
|
||||||
|
else
|
||||||
|
sed -e "s# $HOME# ~#g" -e "s#$HOME#\$HOME#g"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
out="$(mktemp)"
|
||||||
|
set +e
|
||||||
|
"$@" >"$out" 2>&1
|
||||||
|
code="$?"
|
||||||
|
set -e
|
||||||
|
if [ "$code" -eq 0 ]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
cat "$out" >&2
|
||||||
|
return "$code"
|
||||||
|
}
|
||||||
|
|
||||||
|
echo_dur() {
|
||||||
|
local dur=$1
|
||||||
|
local h=$((dur/60/60))
|
||||||
|
local m=$((dur/60%60))
|
||||||
|
local s=$((dur%60))
|
||||||
|
printf '%dh%dm%ds' "$h" "$m" "$s"
|
||||||
|
}
|
||||||
|
|
||||||
|
sponge() {
|
||||||
|
dst="$1"
|
||||||
|
tmp="$(mktemp)"
|
||||||
|
cat > "$tmp"
|
||||||
|
cat "$tmp" > "$dst"
|
||||||
|
}
|
||||||
|
|
||||||
|
stripansi() {
|
||||||
|
# First regex gets rid of standard xterm escape sequences for controlling
|
||||||
|
# visual attributes.
|
||||||
|
# The second regex I'm not 100% sure, the reference says it selects the US
|
||||||
|
# encoding but I'm not sure why that's necessary or why it always occurs
|
||||||
|
# in tput sgr0 before the standard escape sequence.
|
||||||
|
# See tput sgr0 | xxd
|
||||||
|
sed -e $'s/\x1b\[[0-9;]*m//g' -e $'s/\x1b(.//g'
|
||||||
|
}
|
||||||
|
|
||||||
|
runtty() {
|
||||||
|
case "$(uname)" in
|
||||||
|
Darwin)
|
||||||
|
script -q /dev/null "$@"
|
||||||
|
;;
|
||||||
|
Linux)
|
||||||
|
script -eqc "$*"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echoerr "runtty: unsupported OS $(uname)"
|
||||||
|
return 1
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
|
||||||
2
ci/sub
2
ci/sub
|
|
@ -1 +1 @@
|
||||||
Subproject commit df51b90892737ebe9feca3dd982bcdfc7f684834
|
Subproject commit 824046d952b1442c76a057553591652c889fb7cb
|
||||||
|
|
@ -28,13 +28,13 @@ Subcommands:
|
||||||
%[1]s layout [layout name] - Display long help for a particular layout engine
|
%[1]s layout [layout name] - Display long help for a particular layout engine
|
||||||
|
|
||||||
See more docs and the source code at https://oss.terrastruct.com/d2
|
See more docs and the source code at https://oss.terrastruct.com/d2
|
||||||
`, ms.Name, ms.FlagHelp())
|
`, ms.Name, ms.Opts.Defaults())
|
||||||
}
|
}
|
||||||
|
|
||||||
func layoutHelp(ctx context.Context, ms *xmain.State) error {
|
func layoutHelp(ctx context.Context, ms *xmain.State) error {
|
||||||
if len(ms.FlagSet.Args()) == 1 {
|
if len(ms.Opts.Flags.Args()) == 1 {
|
||||||
return shortLayoutHelp(ctx, ms)
|
return shortLayoutHelp(ctx, ms)
|
||||||
} else if len(ms.FlagSet.Args()) == 2 {
|
} else if len(ms.Opts.Flags.Args()) == 2 {
|
||||||
return longLayoutHelp(ctx, ms)
|
return longLayoutHelp(ctx, ms)
|
||||||
} else {
|
} else {
|
||||||
return pluginSubcommand(ctx, ms)
|
return pluginSubcommand(ctx, ms)
|
||||||
|
|
@ -61,7 +61,7 @@ func shortLayoutHelp(ctx context.Context, ms *xmain.State) error {
|
||||||
%s
|
%s
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
To use a particular layout engine, set the environment variable D2_LAYOUT=[layout name].
|
To use a particular layout engine, set the environment variable D2_LAYOUT=[name] or flag --layout=[name].
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
D2_LAYOUT=dagre d2 in.d2 out.svg
|
D2_LAYOUT=dagre d2 in.d2 out.svg
|
||||||
|
|
@ -75,7 +75,7 @@ See more docs at https://oss.terrastruct.com/d2
|
||||||
}
|
}
|
||||||
|
|
||||||
func longLayoutHelp(ctx context.Context, ms *xmain.State) error {
|
func longLayoutHelp(ctx context.Context, ms *xmain.State) error {
|
||||||
layout := ms.FlagSet.Arg(1)
|
layout := ms.Opts.Flags.Arg(1)
|
||||||
plugin, path, err := d2plugin.FindPlugin(ctx, layout)
|
plugin, path, err := d2plugin.FindPlugin(ctx, layout)
|
||||||
if errors.Is(err, exec.ErrNotFound) {
|
if errors.Is(err, exec.ErrNotFound) {
|
||||||
return layoutNotFound(ctx, layout)
|
return layoutNotFound(ctx, layout)
|
||||||
|
|
@ -119,13 +119,13 @@ For more information on setup, please visit https://github.com/terrastruct/d2.`,
|
||||||
}
|
}
|
||||||
|
|
||||||
func pluginSubcommand(ctx context.Context, ms *xmain.State) error {
|
func pluginSubcommand(ctx context.Context, ms *xmain.State) error {
|
||||||
layout := ms.FlagSet.Arg(1)
|
layout := ms.Opts.Flags.Arg(1)
|
||||||
plugin, _, err := d2plugin.FindPlugin(ctx, layout)
|
plugin, _, err := d2plugin.FindPlugin(ctx, layout)
|
||||||
if errors.Is(err, exec.ErrNotFound) {
|
if errors.Is(err, exec.ErrNotFound) {
|
||||||
return layoutNotFound(ctx, layout)
|
return layoutNotFound(ctx, layout)
|
||||||
}
|
}
|
||||||
|
|
||||||
ms.Args = ms.FlagSet.Args()[2:]
|
ms.Opts.Args = ms.Opts.Flags.Args()[2:]
|
||||||
return d2plugin.Serve(plugin)(ctx, ms)
|
return d2plugin.Serve(plugin)(ctx, ms)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -32,19 +31,38 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
// :(
|
// :(
|
||||||
ctx = xmain.DiscardSlog(ctx)
|
ctx = xmain.DiscardSlog(ctx)
|
||||||
|
|
||||||
watchFlag := ms.FlagSet.BoolP("watch", "w", false, "watch for changes to input and live reload. Use $PORT and $HOST to specify the listening address.\n$D2_PORT and $D2_HOST are also accepted and take priority. Default is localhost:0")
|
// These should be kept up-to-date with the d2 man page
|
||||||
themeFlag := ms.FlagSet.Int64P("theme", "t", 0, "set the diagram theme. For a list of available options, see https://oss.terrastruct.com/d2")
|
watchFlag, err := ms.Opts.Bool("D2_WATCH", "watch", "w", false, "watch for changes to input and live reload. Use $HOST and $PORT to specify the listening address.\n(default localhost:0, which is will open on a randomly available local port).")
|
||||||
bundleFlag := ms.FlagSet.BoolP("bundle", "b", true, "when outputting SVG, bundle all assets and layers into the output file")
|
if err != nil {
|
||||||
versionFlag := ms.FlagSet.BoolP("version", "v", false, "get the version")
|
return xmain.UsageErrorf(err.Error())
|
||||||
debugFlag := ms.FlagSet.BoolP("debug", "d", false, "print debug logs")
|
}
|
||||||
err = ms.FlagSet.Parse(ms.Args)
|
hostFlag := ms.Opts.String("HOST", "host", "h", "localhost", "host listening address when used with watch")
|
||||||
|
portFlag := ms.Opts.String("PORT", "port", "p", "0", "port listening address when used with watch")
|
||||||
|
bundleFlag, err := ms.Opts.Bool("D2_BUNDLE", "bundle", "b", true, "when outputting SVG, bundle all assets and layers into the output file.")
|
||||||
|
if err != nil {
|
||||||
|
return xmain.UsageErrorf(err.Error())
|
||||||
|
}
|
||||||
|
debugFlag, err := ms.Opts.Bool("DEBUG", "debug", "d", false, "print debug logs.")
|
||||||
|
if err != nil {
|
||||||
|
return xmain.UsageErrorf(err.Error())
|
||||||
|
}
|
||||||
|
layoutFlag := ms.Opts.String("D2_LAYOUT", "layout", "l", "dagre", `the layout engine used.`)
|
||||||
|
themeFlag, err := ms.Opts.Int64("D2_THEME", "theme", "t", 0, "the diagram theme ID. For a list of available options, see https://oss.terrastruct.com/d2")
|
||||||
|
if err != nil {
|
||||||
|
return xmain.UsageErrorf(err.Error())
|
||||||
|
}
|
||||||
|
versionFlag, err := ms.Opts.Bool("", "version", "v", false, "get the version")
|
||||||
|
if err != nil {
|
||||||
|
return xmain.UsageErrorf(err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
err = ms.Opts.Flags.Parse(ms.Opts.Args)
|
||||||
if !errors.Is(err, pflag.ErrHelp) && err != nil {
|
if !errors.Is(err, pflag.ErrHelp) && err != nil {
|
||||||
return xmain.UsageErrorf("failed to parse flags: %v", err)
|
return xmain.UsageErrorf("failed to parse flags: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(ms.FlagSet.Args()) > 0 {
|
if len(ms.Opts.Flags.Args()) > 0 {
|
||||||
switch ms.FlagSet.Arg(0) {
|
switch ms.Opts.Flags.Arg(0) {
|
||||||
case "layout":
|
case "layout":
|
||||||
return layoutHelp(ctx, ms)
|
return layoutHelp(ctx, ms)
|
||||||
}
|
}
|
||||||
|
|
@ -62,25 +80,26 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
var inputPath string
|
var inputPath string
|
||||||
var outputPath string
|
var outputPath string
|
||||||
|
|
||||||
if len(ms.FlagSet.Args()) == 0 {
|
if len(ms.Opts.Flags.Args()) == 0 {
|
||||||
if versionFlag != nil && *versionFlag {
|
if versionFlag != nil && *versionFlag {
|
||||||
fmt.Println(version.Version)
|
fmt.Println(version.Version)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
help(ms)
|
help(ms)
|
||||||
return nil
|
return nil
|
||||||
} else if len(ms.FlagSet.Args()) >= 3 {
|
} else if len(ms.Opts.Flags.Args()) >= 3 {
|
||||||
return xmain.UsageErrorf("too many arguments passed")
|
return xmain.UsageErrorf("too many arguments passed")
|
||||||
}
|
}
|
||||||
if len(ms.FlagSet.Args()) >= 1 {
|
|
||||||
if ms.FlagSet.Arg(0) == "version" {
|
if len(ms.Opts.Flags.Args()) >= 1 {
|
||||||
|
if ms.Opts.Flags.Arg(0) == "version" {
|
||||||
fmt.Println(version.Version)
|
fmt.Println(version.Version)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
inputPath = ms.FlagSet.Arg(0)
|
inputPath = ms.Opts.Flags.Arg(0)
|
||||||
}
|
}
|
||||||
if len(ms.FlagSet.Args()) >= 2 {
|
if len(ms.Opts.Flags.Args()) >= 2 {
|
||||||
outputPath = ms.FlagSet.Arg(1)
|
outputPath = ms.Opts.Flags.Arg(1)
|
||||||
} else {
|
} else {
|
||||||
if inputPath == "-" {
|
if inputPath == "-" {
|
||||||
outputPath = "-"
|
outputPath = "-"
|
||||||
|
|
@ -93,16 +112,11 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
if match == (d2themes.Theme{}) {
|
if match == (d2themes.Theme{}) {
|
||||||
return xmain.UsageErrorf("-t[heme] could not be found. The available options are:\n%s\nYou provided: %d", d2themescatalog.CLIString(), *themeFlag)
|
return xmain.UsageErrorf("-t[heme] could not be found. The available options are:\n%s\nYou provided: %d", d2themescatalog.CLIString(), *themeFlag)
|
||||||
}
|
}
|
||||||
ms.Env.Setenv("D2_THEME", fmt.Sprintf("%d", *themeFlag))
|
ms.Log.Debug.Printf("using theme %s (ID: %d)", match.Name, *themeFlag)
|
||||||
|
|
||||||
envD2Layout := ms.Env.Getenv("D2_LAYOUT")
|
plugin, path, err := d2plugin.FindPlugin(ctx, *layoutFlag)
|
||||||
if envD2Layout == "" {
|
|
||||||
envD2Layout = "dagre"
|
|
||||||
}
|
|
||||||
|
|
||||||
plugin, path, err := d2plugin.FindPlugin(ctx, envD2Layout)
|
|
||||||
if errors.Is(err, exec.ErrNotFound) {
|
if errors.Is(err, exec.ErrNotFound) {
|
||||||
return layoutNotFound(ctx, envD2Layout)
|
return layoutNotFound(ctx, *layoutFlag)
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +125,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
if path != "" {
|
if path != "" {
|
||||||
pluginLocation = fmt.Sprintf("executable plugin at %s", humanPath(path))
|
pluginLocation = fmt.Sprintf("executable plugin at %s", humanPath(path))
|
||||||
}
|
}
|
||||||
ms.Log.Debug.Printf("using layout plugin %s (%s)", envD2Layout, pluginLocation)
|
ms.Log.Debug.Printf("using layout plugin %s (%s)", *layoutFlag, pluginLocation)
|
||||||
|
|
||||||
var pw png.Playwright
|
var pw png.Playwright
|
||||||
if filepath.Ext(outputPath) == ".png" {
|
if filepath.Ext(outputPath) == ".png" {
|
||||||
|
|
@ -133,7 +147,15 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
return xmain.UsageErrorf("-w[atch] cannot be combined with reading input from stdin")
|
return xmain.UsageErrorf("-w[atch] cannot be combined with reading input from stdin")
|
||||||
}
|
}
|
||||||
ms.Env.Setenv("LOG_TIMESTAMPS", "1")
|
ms.Env.Setenv("LOG_TIMESTAMPS", "1")
|
||||||
w, err := newWatcher(ctx, ms, plugin, inputPath, outputPath, pw)
|
w, err := newWatcher(ctx, ms, watcherOpts{
|
||||||
|
layoutPlugin: plugin,
|
||||||
|
themeID: *themeFlag,
|
||||||
|
host: *hostFlag,
|
||||||
|
port: *portFlag,
|
||||||
|
inputPath: inputPath,
|
||||||
|
outputPath: outputPath,
|
||||||
|
pw: pw,
|
||||||
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -147,7 +169,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
_ = 343
|
_ = 343
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = compile(ctx, ms, plugin, inputPath, outputPath, pw.Page)
|
_, err = compile(ctx, ms, plugin, *themeFlag, inputPath, outputPath, pw.Page)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
@ -156,7 +178,7 @@ func run(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, inputPath, outputPath string, page playwright.Page) ([]byte, error) {
|
func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, themeID int64, inputPath, outputPath string, page playwright.Page) ([]byte, error) {
|
||||||
input, err := ms.ReadPath(inputPath)
|
input, err := ms.ReadPath(inputPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -167,7 +189,6 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, input
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
themeID, _ := strconv.ParseInt(ms.Env.Getenv("D2_THEME"), 10, 64)
|
|
||||||
d, err := d2.Compile(ctx, string(input), &d2.CompileOptions{
|
d, err := d2.Compile(ctx, string(input), &d2.CompileOptions{
|
||||||
Layout: plugin.Layout,
|
Layout: plugin.Layout,
|
||||||
Ruler: ruler,
|
Ruler: ruler,
|
||||||
|
|
@ -197,7 +218,7 @@ func compile(ctx context.Context, ms *xmain.State, plugin d2plugin.Plugin, input
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return out, nil
|
return svg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newExt must include leading .
|
// newExt must include leading .
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,16 @@ var devMode = false
|
||||||
//go:embed static
|
//go:embed static
|
||||||
var staticFS embed.FS
|
var staticFS embed.FS
|
||||||
|
|
||||||
|
type watcherOpts struct {
|
||||||
|
layoutPlugin d2plugin.Plugin
|
||||||
|
themeID int64
|
||||||
|
host string
|
||||||
|
port string
|
||||||
|
inputPath string
|
||||||
|
outputPath string
|
||||||
|
pw png.Playwright
|
||||||
|
}
|
||||||
|
|
||||||
type watcher struct {
|
type watcher struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
|
|
@ -42,9 +52,7 @@ type watcher struct {
|
||||||
devMode bool
|
devMode bool
|
||||||
|
|
||||||
ms *xmain.State
|
ms *xmain.State
|
||||||
layoutPlugin d2plugin.Plugin
|
watcherOpts
|
||||||
inputPath string
|
|
||||||
outputPath string
|
|
||||||
|
|
||||||
compileCh chan struct{}
|
compileCh chan struct{}
|
||||||
|
|
||||||
|
|
@ -62,8 +70,6 @@ type watcher struct {
|
||||||
|
|
||||||
resMu sync.Mutex
|
resMu sync.Mutex
|
||||||
res *compileResult
|
res *compileResult
|
||||||
|
|
||||||
pw png.Playwright
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type compileResult struct {
|
type compileResult struct {
|
||||||
|
|
@ -71,7 +77,7 @@ type compileResult struct {
|
||||||
SVG string `json:"svg"`
|
SVG string `json:"svg"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func newWatcher(ctx context.Context, ms *xmain.State, layoutPlugin d2plugin.Plugin, inputPath, outputPath string, pw png.Playwright) (*watcher, error) {
|
func newWatcher(ctx context.Context, ms *xmain.State, opts watcherOpts) (*watcher, error) {
|
||||||
ctx, cancel := context.WithCancel(ctx)
|
ctx, cancel := context.WithCancel(ctx)
|
||||||
|
|
||||||
w := &watcher{
|
w := &watcher{
|
||||||
|
|
@ -80,13 +86,10 @@ func newWatcher(ctx context.Context, ms *xmain.State, layoutPlugin d2plugin.Plug
|
||||||
devMode: devMode,
|
devMode: devMode,
|
||||||
|
|
||||||
ms: ms,
|
ms: ms,
|
||||||
layoutPlugin: layoutPlugin,
|
watcherOpts: opts,
|
||||||
inputPath: inputPath,
|
|
||||||
outputPath: outputPath,
|
|
||||||
|
|
||||||
compileCh: make(chan struct{}, 1),
|
compileCh: make(chan struct{}, 1),
|
||||||
wsclients: make(map[*wsclient]struct{}),
|
wsclients: make(map[*wsclient]struct{}),
|
||||||
pw: pw,
|
|
||||||
}
|
}
|
||||||
err := w.init()
|
err := w.init()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -342,7 +345,7 @@ func (w *watcher) compileLoop(ctx context.Context) error {
|
||||||
w.pw = newPW
|
w.pw = newPW
|
||||||
}
|
}
|
||||||
|
|
||||||
b, err := compile(ctx, w.ms, w.layoutPlugin, w.inputPath, w.outputPath, w.pw.Page)
|
b, err := compile(ctx, w.ms, w.layoutPlugin, w.themeID, w.inputPath, w.outputPath, w.pw.Page)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err = fmt.Errorf("failed to %scompile: %w", recompiledPrefix, err)
|
err = fmt.Errorf("failed to %scompile: %w", recompiledPrefix, err)
|
||||||
w.ms.Log.Error.Print(err)
|
w.ms.Log.Error.Print(err)
|
||||||
|
|
@ -368,18 +371,7 @@ func (w *watcher) compileLoop(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *watcher) listen() error {
|
func (w *watcher) listen() error {
|
||||||
host := "localhost"
|
l, err := net.Listen("tcp", net.JoinHostPort(w.host, w.port))
|
||||||
port := "0"
|
|
||||||
hostEnv := w.ms.Env.Getenv("HOST")
|
|
||||||
if hostEnv != "" {
|
|
||||||
host = hostEnv
|
|
||||||
}
|
|
||||||
portEnv := w.ms.Env.Getenv("PORT")
|
|
||||||
if portEnv != "" {
|
|
||||||
port = portEnv
|
|
||||||
}
|
|
||||||
|
|
||||||
l, err := net.Listen("tcp", net.JoinHostPort(host, port))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,12 @@ import (
|
||||||
// Also see execPlugin in exec.go for the d2 binary plugin protocol.
|
// Also see execPlugin in exec.go for the d2 binary plugin protocol.
|
||||||
func Serve(p Plugin) func(context.Context, *xmain.State) error {
|
func Serve(p Plugin) func(context.Context, *xmain.State) error {
|
||||||
return func(ctx context.Context, ms *xmain.State) (err error) {
|
return func(ctx context.Context, ms *xmain.State) (err error) {
|
||||||
if len(ms.Args) < 1 {
|
if len(ms.Opts.Flags.Args()) < 1 {
|
||||||
return errors.New("expected first argument to plugin binary to be function name")
|
return errors.New("expected first argument to plugin binary to be function name")
|
||||||
}
|
}
|
||||||
reqFunc := ms.Args[0]
|
reqFunc := ms.Opts.Flags.Arg(0)
|
||||||
|
|
||||||
switch ms.Args[0] {
|
switch ms.Opts.Flags.Arg(0) {
|
||||||
case "info":
|
case "info":
|
||||||
return info(ctx, p, ms)
|
return info(ctx, p, ms)
|
||||||
case "layout":
|
case "layout":
|
||||||
|
|
|
||||||
|
|
@ -65,8 +65,7 @@ language. Sometimes it gives controversial sentences -- don't use those.
|
||||||
Script to generate one line of random text:
|
Script to generate one line of random text:
|
||||||
```
|
```
|
||||||
ipsum1() {
|
ipsum1() {
|
||||||
fortune | head -n1 | sed 's/^ *//;s/ *$//' | tr -d '\n' | pbcopy
|
fortune | head -n1 | sed 's/^ *//;s/ *$//' | tr -d '\n' | tee /dev/stderr | pbcopy
|
||||||
echo "$(pbpaste -Prefer txt)"
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
91
docs/INSTALL.md
Normal file
91
docs/INSTALL.md
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
# install
|
||||||
|
|
||||||
|
This file documents all the ways by which you can install D2.
|
||||||
|
|
||||||
|
<!-- toc -->
|
||||||
|
|
||||||
|
- [install.sh](#installsh)
|
||||||
|
- [macOS (Homebrew)](#macos-homebrew)
|
||||||
|
- [Standalone](#standalone)
|
||||||
|
- [From source](#from-source)
|
||||||
|
|
||||||
|
<!-- tocstop -->
|
||||||
|
|
||||||
|
## install.sh
|
||||||
|
|
||||||
|
The recommended and easiest way to install is with our install script, which will detect
|
||||||
|
the OS and architecture you're on and use the best method:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# With --dry-run the install script will print the commands it will use
|
||||||
|
# to install without actually installing so you know what it's going to do.
|
||||||
|
curl -fsSL https://d2lang.com/install.sh | sh -s -- --dry-run
|
||||||
|
# If things look good, install for real.
|
||||||
|
curl -fsSL https://d2lang.com/install.sh | sh -s --
|
||||||
|
```
|
||||||
|
|
||||||
|
For help on the terminal run, including the supported package managers and detection
|
||||||
|
methods:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
curl -fsSL https://d2lang.com/install.sh | sh -s -- --help
|
||||||
|
```
|
||||||
|
|
||||||
|
## macOS (Homebrew)
|
||||||
|
|
||||||
|
If you're on macOS, you can alternatively install with `brew`. (the install script above
|
||||||
|
does this automatically if you have `brew` installed).
|
||||||
|
|
||||||
|
```sh
|
||||||
|
brew tap terrastruct/d2
|
||||||
|
brew install d2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Standalone
|
||||||
|
|
||||||
|
We publish standalone release archives with every release on Github.
|
||||||
|
Download the `.tar.gz` release for your OS/ARCH combination and then run the following
|
||||||
|
inside the extracted directory to install:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make install
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the following to uninstall:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
make uninstall
|
||||||
|
```
|
||||||
|
|
||||||
|
You will be prompted for sudo/su/doas if root permissions are required for installation.
|
||||||
|
You can control the Unix hierarchy installation path with `PREFIX=`. For example:
|
||||||
|
|
||||||
|
```
|
||||||
|
# Install under ~/.local.
|
||||||
|
# Binaries will be at ~/.local/bin
|
||||||
|
# And manpages will be under ~/.local/share/man
|
||||||
|
# And supporting data like icons and fonts at ~/.local/share/d2
|
||||||
|
make install PREFIX=$HOME/.local
|
||||||
|
```
|
||||||
|
|
||||||
|
The install script places the standalone release into `$PREFIX/lib/d2/d2-<version>`
|
||||||
|
and we recommend doing the same with manually installed releases so that you
|
||||||
|
know where the release directory is for easy uninstall.
|
||||||
|
|
||||||
|
> warn: Our binary releases aren't fully portable like normal Go binaries due to the C
|
||||||
|
> dependency on v8go for executing dagre.
|
||||||
|
|
||||||
|
## From source
|
||||||
|
|
||||||
|
Alternatively, you can always install from source:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go install oss.terrastruct.com/d2/cmd/d2@latest
|
||||||
|
```
|
||||||
|
|
||||||
|
## Coming soon
|
||||||
|
|
||||||
|
- Docker image
|
||||||
|
- Windows install
|
||||||
|
- rpm and deb packages
|
||||||
|
- homebrew core
|
||||||
2
go.sum
2
go.sum
|
|
@ -778,6 +778,8 @@ honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9
|
||||||
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g=
|
||||||
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0=
|
||||||
oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37 h1:Xy1JKJHc4hcuwi57s0BvGUY16GjxTtBmLUybsuGDU7E=
|
oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37 h1:Xy1JKJHc4hcuwi57s0BvGUY16GjxTtBmLUybsuGDU7E=
|
||||||
|
oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37 h1:Xy1JKJHc4hcuwi57s0BvGUY16GjxTtBmLUybsuGDU7E=
|
||||||
|
oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37/go.mod h1:ROL3yxl2X+S3O+Rls00qdX6aMh+p1dF8IdxDRwDDpsg=
|
||||||
oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37/go.mod h1:ROL3yxl2X+S3O+Rls00qdX6aMh+p1dF8IdxDRwDDpsg=
|
oss.terrastruct.com/cmdlog v0.0.0-20221116181457-07977d95ac37/go.mod h1:ROL3yxl2X+S3O+Rls00qdX6aMh+p1dF8IdxDRwDDpsg=
|
||||||
oss.terrastruct.com/diff v1.0.2-0.20221116222035-8bf4dd3ab541 h1:I9B1O1IJ6spivIQxbFRZmbhAwVeLwrcQRR1JbYUOvrI=
|
oss.terrastruct.com/diff v1.0.2-0.20221116222035-8bf4dd3ab541 h1:I9B1O1IJ6spivIQxbFRZmbhAwVeLwrcQRR1JbYUOvrI=
|
||||||
oss.terrastruct.com/diff v1.0.2-0.20221116222035-8bf4dd3ab541/go.mod h1:ags2QDy/T6jr69hT6bpmAmhr2H98n9o8Atf3QlUJPiU=
|
oss.terrastruct.com/diff v1.0.2-0.20221116222035-8bf4dd3ab541/go.mod h1:ags2QDy/T6jr69hT6bpmAmhr2H98n9o8Atf3QlUJPiU=
|
||||||
|
|
|
||||||
356
install.sh
356
install.sh
|
|
@ -54,8 +54,30 @@ if [ -n "${DEBUG-}" ]; then
|
||||||
fi
|
fi
|
||||||
|
|
||||||
tput() {
|
tput() {
|
||||||
if [ -n "$TERM" ]; then
|
if should_color; then
|
||||||
command tput "$@"
|
TERM=${TERM:-xterm-256color} command tput "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
should_color() {
|
||||||
|
if [ -n "${COLOR-}" ]; then
|
||||||
|
if [ "$COLOR" = 0 -o "$COLOR" = false ]; then
|
||||||
|
_COLOR=
|
||||||
|
return 1
|
||||||
|
elif [ "$COLOR" = 1 -o "$COLOR" = true ]; then
|
||||||
|
_COLOR=1
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
printf '$COLOR must be 0, 1, false or true but got %s' "$COLOR" >&2
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ -t 1 ]; then
|
||||||
|
_COLOR=1
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
_COLOR=
|
||||||
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -92,14 +114,14 @@ printfp() {(
|
||||||
prefix="$1"
|
prefix="$1"
|
||||||
shift
|
shift
|
||||||
|
|
||||||
if [ -z "${COLOR:-}" ]; then
|
if [ -z "${FGCOLOR-}" ]; then
|
||||||
COLOR="$(get_rand_color "$prefix")"
|
FGCOLOR="$(get_rand_color "$prefix")"
|
||||||
fi
|
fi
|
||||||
printf '%s' "$(setaf "$COLOR" "$prefix")"
|
should_color || true
|
||||||
|
if [ $# -eq 0 ]; then
|
||||||
if [ $# -gt 0 ]; then
|
printf '%s' "$(COLOR=${_COLOR-} setaf "$FGCOLOR" "$prefix")"
|
||||||
printf ': '
|
else
|
||||||
printf "$@"
|
printf '%s: %s\n' "$(COLOR=${_COLOR-} setaf "$FGCOLOR" "$prefix")" "$(printf "$@")"
|
||||||
fi
|
fi
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -107,7 +129,8 @@ catp() {
|
||||||
prefix="$1"
|
prefix="$1"
|
||||||
shift
|
shift
|
||||||
|
|
||||||
sed "s/^/$(printfp "$prefix" '')/"
|
should_color || true
|
||||||
|
sed "s/^/$(COLOR=${_COLOR-} printfp "$prefix" '')/"
|
||||||
}
|
}
|
||||||
|
|
||||||
repeat() {
|
repeat() {
|
||||||
|
|
@ -121,51 +144,58 @@ strlen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
echoerr() {
|
echoerr() {
|
||||||
COLOR=1 echop err "$*" | humanpath>&2
|
FGCOLOR=1 logp err "$*" | humanpath>&2
|
||||||
}
|
}
|
||||||
|
|
||||||
caterr() {
|
caterr() {
|
||||||
COLOR=1 catp err "$@" | humanpath >&2
|
FGCOLOR=1 logpcat err "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
printferr() {
|
printferr() {
|
||||||
COLOR=1 printfp err "$@" | humanpath >&2
|
FGCOLOR=1 logfp err "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
logp() {
|
logp() {
|
||||||
echop "$@" | humanpath >&2
|
should_color >&2 || true
|
||||||
|
COLOR=${_COLOR-} echop "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
logfp() {
|
logfp() {
|
||||||
printfp "$@" | humanpath >&2
|
should_color >&2 || true
|
||||||
|
COLOR=${_COLOR-} printfp "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
logpcat() {
|
logpcat() {
|
||||||
catp "$@" | humanpath >&2
|
should_color >&2 || true
|
||||||
|
COLOR=${_COLOR-} catp "$@" | humanpath >&2
|
||||||
}
|
}
|
||||||
|
|
||||||
log() {
|
log() {
|
||||||
COLOR=5 logp log "$@"
|
FGCOLOR=5 logp log "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
logf() {
|
logf() {
|
||||||
COLOR=5 logfp log "$@"
|
FGCOLOR=5 logfp log "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
logcat() {
|
logcat() {
|
||||||
COLOR=5 logpcat log "$@"
|
FGCOLOR=5 logpcat log "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
warn() {
|
warn() {
|
||||||
COLOR=3 logp warn "$@"
|
FGCOLOR=3 logp warn "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
warnf() {
|
warnf() {
|
||||||
COLOR=3 logfp warn "$@"
|
FGCOLOR=3 logfp warn "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
warncat() {
|
||||||
|
FGCOLOR=3 logpcat warn "$@"
|
||||||
}
|
}
|
||||||
|
|
||||||
sh_c() {
|
sh_c() {
|
||||||
COLOR=3 logp exec "$*"
|
FGCOLOR=3 logp exec "$*"
|
||||||
if [ -z "${DRY_RUN-}" ]; then
|
if [ -z "${DRY_RUN-}" ]; then
|
||||||
eval "$@"
|
eval "$@"
|
||||||
fi
|
fi
|
||||||
|
|
@ -194,6 +224,12 @@ header() {
|
||||||
logp "/* $1 */"
|
logp "/* $1 */"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bigheader() {
|
||||||
|
logp "/**
|
||||||
|
* $1
|
||||||
|
**/"
|
||||||
|
}
|
||||||
|
|
||||||
# humanpath replaces all occurrences of " $HOME" with " ~"
|
# humanpath replaces all occurrences of " $HOME" with " ~"
|
||||||
# and all occurrences of '$HOME' with the literal '$HOME'.
|
# and all occurrences of '$HOME' with the literal '$HOME'.
|
||||||
humanpath() {
|
humanpath() {
|
||||||
|
|
@ -280,9 +316,8 @@ LIB_FLAG=1
|
||||||
# FLAGSHIFT contains the number by which the arguments should be shifted to
|
# FLAGSHIFT contains the number by which the arguments should be shifted to
|
||||||
# start at the next flag/argument
|
# start at the next flag/argument
|
||||||
#
|
#
|
||||||
# After each call check $FLAG for the name of the parsed flag.
|
# flag_parse exits with a non zero code when there are no more flags
|
||||||
# If empty, then no more flags are left.
|
# to be parsed. Still, call shift "$FLAGSHIFT" in case there was a --
|
||||||
# Still, call shift "$FLAGSHIFT" in case there was a --
|
|
||||||
#
|
#
|
||||||
# If the argument for the flag is optional, then use ${FLAGARG-} to access
|
# If the argument for the flag is optional, then use ${FLAGARG-} to access
|
||||||
# the argument if one was passed. Use ${FLAGARG+x} = x to check if it was set.
|
# the argument if one was passed. Use ${FLAGARG+x} = x to check if it was set.
|
||||||
|
|
@ -310,18 +345,15 @@ flag_parse() {
|
||||||
# Remove everything before first equal sign.
|
# Remove everything before first equal sign.
|
||||||
FLAGARG="${1#*=}"
|
FLAGARG="${1#*=}"
|
||||||
FLAGSHIFT=1
|
FLAGSHIFT=1
|
||||||
|
return 0
|
||||||
;;
|
;;
|
||||||
-)
|
-)
|
||||||
FLAG=
|
|
||||||
FLAGRAW=
|
|
||||||
unset FLAGARG
|
|
||||||
FLAGSHIFT=0
|
FLAGSHIFT=0
|
||||||
|
return 1
|
||||||
;;
|
;;
|
||||||
--)
|
--)
|
||||||
FLAG=
|
|
||||||
FLAGRAW=
|
|
||||||
unset FLAGARG
|
|
||||||
FLAGSHIFT=1
|
FLAGSHIFT=1
|
||||||
|
return 1
|
||||||
;;
|
;;
|
||||||
-*)
|
-*)
|
||||||
# Remove leading hyphens.
|
# Remove leading hyphens.
|
||||||
|
|
@ -343,15 +375,13 @@ flag_parse() {
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
|
return 0
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
FLAG=
|
|
||||||
FLAGRAW=
|
|
||||||
unset FLAGARG
|
|
||||||
FLAGSHIFT=0
|
FLAGSHIFT=0
|
||||||
|
return 1
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
return 0
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flag_reqarg() {
|
flag_reqarg() {
|
||||||
|
|
@ -452,8 +482,11 @@ usage: $arg0 [--dry-run] [--version vX.X.X] [--edge] [--method detect] [--prefix
|
||||||
[--tala latest] [--force] [--uninstall]
|
[--tala latest] [--force] [--uninstall]
|
||||||
|
|
||||||
install.sh automates the installation of D2 onto your system. It currently only supports
|
install.sh automates the installation of D2 onto your system. It currently only supports
|
||||||
the installation of standalone releases from GitHub. If you pass --edge, it will clone the
|
the installation of standalone releases from GitHub and via Homebrew on macOS. See the
|
||||||
source, build a release and install from it.
|
docs for --detect below for more information
|
||||||
|
|
||||||
|
If you pass --edge, it will clone the source, build a release and install from it.
|
||||||
|
--edge is incompatible with --tala and currently unimplemented.
|
||||||
|
|
||||||
Flags:
|
Flags:
|
||||||
|
|
||||||
|
|
@ -463,6 +496,8 @@ Flags:
|
||||||
|
|
||||||
--version vX.X.X
|
--version vX.X.X
|
||||||
Pass to have install.sh install the given version instead of the latest version.
|
Pass to have install.sh install the given version instead of the latest version.
|
||||||
|
warn: The version may not be obeyed with package manager installations. Use
|
||||||
|
--method=standalone to enforce the version.
|
||||||
|
|
||||||
--edge
|
--edge
|
||||||
Pass to build and install D2 from source. This will still use --method if set to detect
|
Pass to build and install D2 from source. This will still use --method if set to detect
|
||||||
|
|
@ -470,14 +505,15 @@ Flags:
|
||||||
if an unsupported package manager is used. To install from source like a dev would,
|
if an unsupported package manager is used. To install from source like a dev would,
|
||||||
use go install oss.terrastruct.com/d2
|
use go install oss.terrastruct.com/d2
|
||||||
note: currently unimplemented.
|
note: currently unimplemented.
|
||||||
|
warn: incompatible with --tala as TALA is closed source.
|
||||||
|
|
||||||
--method [detect | standalone]
|
--method [detect | standalone | homebrew ]
|
||||||
Pass to control the method by which to install. Right now we only support standalone
|
Pass to control the method by which to install. Right now we only support standalone
|
||||||
releases from GitHub but later we'll add support for brew, rpm, deb and more.
|
releases from GitHub but later we'll add support for brew, rpm, deb and more.
|
||||||
note: currently unimplemented.
|
|
||||||
|
|
||||||
- detect is currently unimplemented but would use your OS's package manager
|
- detect will use your OS's package manager automatically.
|
||||||
automatically.
|
So far it only detects macOS and automatically uses homebrew.
|
||||||
|
- homebrew uses https://brew.sh/ which is a macOS and Linux package manager.
|
||||||
- standalone installs a standalone release archive into the unix hierarchy path
|
- standalone installs a standalone release archive into the unix hierarchy path
|
||||||
specified by --prefix which defaults to /usr/local
|
specified by --prefix which defaults to /usr/local
|
||||||
Ensure /usr/local/bin is in your \$PATH to use it.
|
Ensure /usr/local/bin is in your \$PATH to use it.
|
||||||
|
|
@ -485,16 +521,19 @@ Flags:
|
||||||
--prefix /usr/local
|
--prefix /usr/local
|
||||||
Controls the unix hierarchy path into which standalone releases are installed.
|
Controls the unix hierarchy path into which standalone releases are installed.
|
||||||
Defaults to /usr/local. You may also want to use ~/.local to avoid needing sudo.
|
Defaults to /usr/local. You may also want to use ~/.local to avoid needing sudo.
|
||||||
Remember that whatever you use, you must have the bin directory of your prefix
|
We use ~/.local by default on arm64 macOS machines as SIP now disables access to
|
||||||
path in \$PATH to execute the d2 binary. For example, if my prefix directory is
|
/usr/local. Remember that whatever you use, you must have the bin directory of your
|
||||||
|
prefix path in \$PATH to execute the d2 binary. For example, if my prefix directory is
|
||||||
/usr/local then my \$PATH must contain /usr/local/bin.
|
/usr/local then my \$PATH must contain /usr/local/bin.
|
||||||
|
|
||||||
--tala [latest]
|
--tala [latest]
|
||||||
Install Terrastruct's closed source TALA for improved layouts.
|
Install Terrastruct's closed source TALA for improved layouts.
|
||||||
See https://github.com/terrastruct/TALA
|
See https://github.com/terrastruct/tala
|
||||||
It optionally takes an argument of the TALA version to install.
|
It optionally takes an argument of the TALA version to install.
|
||||||
Installation obeys all other flags, just like the installation of d2. For example,
|
Installation obeys all other flags, just like the installation of d2. For example,
|
||||||
the d2plugin-tala binary will be installed into /usr/local/bin/d2plugin-tala
|
the d2plugin-tala binary will be installed into /usr/local/bin/d2plugin-tala
|
||||||
|
warn: The version may not be obeyed with package manager installations. Use
|
||||||
|
--method=standalone to enforce the version.
|
||||||
|
|
||||||
--force:
|
--force:
|
||||||
Force installation over the existing version even if they match. It will attempt a
|
Force installation over the existing version even if they match. It will attempt a
|
||||||
|
|
@ -507,6 +546,7 @@ Flags:
|
||||||
as for installation. i.e if you used --method standalone you must again use --method
|
as for installation. i.e if you used --method standalone you must again use --method
|
||||||
standalone for uninstallation. With detect, the install script will try to use the OS
|
standalone for uninstallation. With detect, the install script will try to use the OS
|
||||||
package manager to uninstall instead.
|
package manager to uninstall instead.
|
||||||
|
note: tala will also be uninstalled if installed.
|
||||||
|
|
||||||
All downloaded archives are cached into ~/.cache/d2/release. use \$XDG_CACHE_HOME to change
|
All downloaded archives are cached into ~/.cache/d2/release. use \$XDG_CACHE_HOME to change
|
||||||
path of the cached assets. Release archives are unarchived into /usr/local/lib/d2/d2-<VERSION>
|
path of the cached assets. Release archives are unarchived into /usr/local/lib/d2/d2-<VERSION>
|
||||||
|
|
@ -519,9 +559,7 @@ EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
METHOD=standalone
|
while flag_parse "$@"; do
|
||||||
while :; do
|
|
||||||
flag_parse "$@"
|
|
||||||
case "$FLAG" in
|
case "$FLAG" in
|
||||||
h|help)
|
h|help)
|
||||||
help
|
help
|
||||||
|
|
@ -548,8 +586,6 @@ main() {
|
||||||
method)
|
method)
|
||||||
flag_nonemptyarg && shift "$FLAGSHIFT"
|
flag_nonemptyarg && shift "$FLAGSHIFT"
|
||||||
METHOD=$FLAGARG
|
METHOD=$FLAGARG
|
||||||
echoerr "$FLAGRAW is currently unimplemented"
|
|
||||||
return 1
|
|
||||||
;;
|
;;
|
||||||
prefix)
|
prefix)
|
||||||
flag_nonemptyarg && shift "$FLAGSHIFT"
|
flag_nonemptyarg && shift "$FLAGSHIFT"
|
||||||
|
|
@ -563,15 +599,12 @@ main() {
|
||||||
flag_noarg && shift "$FLAGSHIFT"
|
flag_noarg && shift "$FLAGSHIFT"
|
||||||
UNINSTALL=1
|
UNINSTALL=1
|
||||||
;;
|
;;
|
||||||
'')
|
|
||||||
shift "$FLAGSHIFT"
|
|
||||||
break
|
|
||||||
;;
|
|
||||||
*)
|
*)
|
||||||
flag_errusage "unrecognized flag $FLAGRAW"
|
flag_errusage "unrecognized flag $FLAGRAW"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
|
shift "$FLAGSHIFT"
|
||||||
|
|
||||||
if [ $# -gt 0 ]; then
|
if [ $# -gt 0 ]; then
|
||||||
flag_errusage "no arguments are accepted"
|
flag_errusage "no arguments are accepted"
|
||||||
|
|
@ -587,42 +620,79 @@ main() {
|
||||||
PREFIX=${PREFIX:-/usr/local}
|
PREFIX=${PREFIX:-/usr/local}
|
||||||
CACHE_DIR=$(cache_dir)
|
CACHE_DIR=$(cache_dir)
|
||||||
mkdir -p "$CACHE_DIR"
|
mkdir -p "$CACHE_DIR"
|
||||||
|
METHOD=${METHOD:-detect}
|
||||||
INSTALL_DIR=$PREFIX/lib/d2
|
INSTALL_DIR=$PREFIX/lib/d2
|
||||||
|
|
||||||
|
case $METHOD in
|
||||||
|
detect)
|
||||||
|
case "$OS" in
|
||||||
|
macos)
|
||||||
|
if command -v brew >/dev/null; then
|
||||||
|
log "detected macOS with homebrew, using homebrew for (un)installation"
|
||||||
|
METHOD=homebrew
|
||||||
|
else
|
||||||
|
warn "detected macOS without homebrew, falling back to --method=standalone"
|
||||||
|
METHOD=standalone
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
warn "unrecognized OS $OS, falling back to --method=standalone"
|
||||||
|
METHOD=standalone
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
standalone) ;;
|
||||||
|
homebrew) ;;
|
||||||
|
*)
|
||||||
|
echoerr "unknown (un)installation method $METHOD"
|
||||||
|
return 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
if [ -n "${UNINSTALL-}" ]; then
|
if [ -n "${UNINSTALL-}" ]; then
|
||||||
uninstall
|
uninstall
|
||||||
return 0
|
if [ -n "${DRY_RUN-}" ]; then
|
||||||
|
log "Rerun without --dry-run to execute printed commands and perform uninstall."
|
||||||
fi
|
fi
|
||||||
|
else
|
||||||
VERSION=${VERSION:-latest}
|
|
||||||
if [ "$VERSION" = latest ]; then
|
|
||||||
header "fetching latest release info"
|
|
||||||
fetch_release_info
|
|
||||||
fi
|
|
||||||
|
|
||||||
install
|
install
|
||||||
|
if [ -n "${DRY_RUN-}" ]; then
|
||||||
|
log "Rerun without --dry-run to execute printed commands and perform install."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
install() {
|
install() {
|
||||||
install_d2
|
case $METHOD in
|
||||||
|
standalone)
|
||||||
|
install_d2_standalone
|
||||||
if [ -n "${TALA-}" ]; then
|
if [ -n "${TALA-}" ]; then
|
||||||
# Run in subshell to avoid overwriting VERSION.
|
# Run in subshell to avoid overwriting VERSION.
|
||||||
TALA_VERSION="$( install_tala && echo "$VERSION" )"
|
TALA_VERSION="$( RELEASE_INFO= install_tala_standalone && echo "$VERSION" )"
|
||||||
fi
|
fi
|
||||||
|
;;
|
||||||
|
homebrew)
|
||||||
|
install_d2_brew
|
||||||
|
if [ -n "${TALA-}" ]; then install_tala_brew; fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
COLOR=2 header success
|
FGCOLOR=2 bigheader 'next steps'
|
||||||
|
case $METHOD in
|
||||||
|
standalone) install_post_standalone ;;
|
||||||
|
homebrew) install_post_brew ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
install_post_standalone() {
|
||||||
log "d2-$VERSION-$OS-$ARCH has been successfully installed into $PREFIX"
|
log "d2-$VERSION-$OS-$ARCH has been successfully installed into $PREFIX"
|
||||||
if [ -n "${TALA-}" ]; then
|
if [ -n "${TALA-}" ]; then
|
||||||
log "tala-$TALA_VERSION-$OS-$ARCH has been successfully installed into $PREFIX"
|
log "tala-$TALA_VERSION-$OS-$ARCH has been successfully installed into $PREFIX"
|
||||||
fi
|
fi
|
||||||
log "Rerun this install script with --uninstall to uninstall"
|
log "Rerun this install script with --uninstall to uninstall."
|
||||||
|
log
|
||||||
if ! echo "$PATH" | grep -qF "$PREFIX/bin"; then
|
if ! echo "$PATH" | grep -qF "$PREFIX/bin"; then
|
||||||
logcat >&2 <<EOF
|
logcat >&2 <<EOF
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
NEXT STEPS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Extend your \$PATH to use d2:
|
Extend your \$PATH to use d2:
|
||||||
export PATH=$PREFIX/bin:\$PATH
|
export PATH=$PREFIX/bin:\$PATH
|
||||||
Then run:
|
Then run:
|
||||||
|
|
@ -644,34 +714,59 @@ EOF
|
||||||
else
|
else
|
||||||
log "Run man d2 for detailed docs."
|
log "Run man d2 for detailed docs."
|
||||||
if [ -n "${TALA-}" ]; then
|
if [ -n "${TALA-}" ]; then
|
||||||
log " Run man d2plugin-tala for detailed docs."
|
log "Run man d2plugin-tala for detailed TALA docs."
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
logcat >&2 <<EOF
|
logcat >&2 <<EOF
|
||||||
|
|
||||||
Something not working? Please let us know:
|
Something not working? Please let us know:
|
||||||
https://github.com/terrastruct/d2/issues/new
|
https://github.com/terrastruct/d2/issues
|
||||||
|
https://github.com/terrastruct/d2/discussions
|
||||||
|
https://discord.gg/NF6X8K4eDq
|
||||||
EOF
|
EOF
|
||||||
}
|
}
|
||||||
|
|
||||||
install_d2() {
|
install_post_brew() {
|
||||||
|
log "d2 has been successfully installed with homebrew."
|
||||||
|
if [ -n "${TALA-}" ]; then
|
||||||
|
log "tala has been successfully installed with homebrew."
|
||||||
|
fi
|
||||||
|
log "Rerun this install script with --uninstall to uninstall."
|
||||||
|
log
|
||||||
|
log "Run ${TALA+D2_LAYOUT=tala }d2 --help for usage."
|
||||||
|
log "Run man d2 for detailed docs."
|
||||||
|
if [ -n "${TALA-}" ]; then
|
||||||
|
log "Run man d2plugin-tala for detailed TALA docs."
|
||||||
|
fi
|
||||||
|
logcat >&2 <<EOF
|
||||||
|
|
||||||
|
Something not working? Please let us know:
|
||||||
|
https://github.com/terrastruct/d2/issues
|
||||||
|
https://github.com/terrastruct/d2/discussions
|
||||||
|
https://discord.gg/NF6X8K4eDq
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
install_d2_standalone() {
|
||||||
|
VERSION=${VERSION:-latest}
|
||||||
|
header "installing d2-$VERSION"
|
||||||
|
|
||||||
|
if [ "$VERSION" = latest ]; then
|
||||||
|
fetch_release_info
|
||||||
|
fi
|
||||||
|
|
||||||
if command -v d2 >/dev/null; then
|
if command -v d2 >/dev/null; then
|
||||||
INSTALLED_VERSION="$(d2 version)"
|
INSTALLED_VERSION="$(d2 version)"
|
||||||
if [ ! "${FORCE-}" -a "$VERSION" = "$INSTALLED_VERSION" ]; then
|
if [ ! "${FORCE-}" -a "$VERSION" = "$INSTALLED_VERSION" ]; then
|
||||||
log "skipping installation as version $VERSION is already installed."
|
log "skipping installation as d2 $VERSION is already installed."
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
log "uninstalling $INSTALLED_VERSION to install $VERSION"
|
log "uninstalling d2 $INSTALLED_VERSION to install $VERSION"
|
||||||
if ! uninstall_d2; then
|
if ! uninstall_d2_standalone; then
|
||||||
warn "failed to uninstall $INSTALLED_VERSION"
|
warn "failed to uninstall d2 $INSTALLED_VERSION"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
header "installing d2-$VERSION"
|
|
||||||
install_standalone_d2
|
|
||||||
}
|
|
||||||
|
|
||||||
install_standalone_d2() {
|
|
||||||
ARCHIVE="d2-$VERSION-$OS-$ARCH.tar.gz"
|
ARCHIVE="d2-$VERSION-$OS-$ARCH.tar.gz"
|
||||||
log "installing standalone release $ARCHIVE from github"
|
log "installing standalone release $ARCHIVE from github"
|
||||||
|
|
||||||
|
|
@ -690,19 +785,38 @@ install_standalone_d2() {
|
||||||
"$sh_c" sh -c "'cd \"$INSTALL_DIR/d2-$VERSION\" && make install PREFIX=\"$PREFIX\"'"
|
"$sh_c" sh -c "'cd \"$INSTALL_DIR/d2-$VERSION\" && make install PREFIX=\"$PREFIX\"'"
|
||||||
}
|
}
|
||||||
|
|
||||||
install_tala() {
|
install_d2_brew() {
|
||||||
REPO="${REPO_TALA:-terrastruct/TALA}"
|
header "installing d2 with homebrew"
|
||||||
VERSION=$TALA
|
sh_c brew tap terrastruct/d2
|
||||||
RELEASE_INFO=
|
sh_c brew install d2
|
||||||
fetch_release_info
|
|
||||||
header "installing tala-$VERSION"
|
|
||||||
install_standalone_tala
|
|
||||||
}
|
}
|
||||||
|
|
||||||
install_standalone_tala() {
|
install_tala_standalone() {
|
||||||
|
REPO="${REPO_TALA:-terrastruct/tala}"
|
||||||
|
VERSION=$TALA
|
||||||
|
|
||||||
|
header "installing tala-$VERSION"
|
||||||
|
|
||||||
|
if [ "$VERSION" = latest ]; then
|
||||||
|
fetch_release_info
|
||||||
|
fi
|
||||||
|
|
||||||
|
if command -v d2plugin-tala >/dev/null; then
|
||||||
|
INSTALLED_VERSION="$(d2plugin-tala --version)"
|
||||||
|
if [ ! "${FORCE-}" -a "$VERSION" = "$INSTALLED_VERSION" ]; then
|
||||||
|
log "skipping installation as tala $VERSION is already installed."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
log "uninstalling tala $INSTALLED_VERSION to install $VERSION"
|
||||||
|
if ! uninstall_tala_standalone; then
|
||||||
|
warn "failed to uninstall tala $INSTALLED_VERSION"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
ARCHIVE="tala-$VERSION-$OS-$ARCH.tar.gz"
|
ARCHIVE="tala-$VERSION-$OS-$ARCH.tar.gz"
|
||||||
log "installing standalone release $ARCHIVE from github"
|
log "installing standalone release $ARCHIVE from github"
|
||||||
|
|
||||||
|
fetch_release_info
|
||||||
asset_line=$(sh_c 'cat "$RELEASE_INFO" | grep -n "$ARCHIVE" | cut -d: -f1 | head -n1')
|
asset_line=$(sh_c 'cat "$RELEASE_INFO" | grep -n "$ARCHIVE" | cut -d: -f1 | head -n1')
|
||||||
asset_url=$(sh_c 'sed -n $((asset_line-3))p "$RELEASE_INFO" | sed "s/^.*: \"\(.*\)\",$/\1/g"')
|
asset_url=$(sh_c 'sed -n $((asset_line-3))p "$RELEASE_INFO" | sed "s/^.*: \"\(.*\)\",$/\1/g"')
|
||||||
|
|
||||||
|
|
@ -718,36 +832,40 @@ install_standalone_tala() {
|
||||||
"$sh_c" sh -c "'cd \"$INSTALL_DIR/tala-$VERSION\" && make install PREFIX=\"$PREFIX\"'"
|
"$sh_c" sh -c "'cd \"$INSTALL_DIR/tala-$VERSION\" && make install PREFIX=\"$PREFIX\"'"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
install_tala_brew() {
|
||||||
|
header "installing tala with homebrew"
|
||||||
|
sh_c brew tap terrastruct/d2
|
||||||
|
sh_c brew install tala
|
||||||
|
}
|
||||||
|
|
||||||
uninstall() {
|
uninstall() {
|
||||||
|
# We uninstall tala first as package managers require that it be uninstalled before
|
||||||
|
# uninstalling d2 as TALA depends on d2.
|
||||||
|
if command -v d2plugin-tala >/dev/null; then
|
||||||
|
INSTALLED_VERSION="$(d2plugin-tala --version)"
|
||||||
|
header "uninstalling tala-$INSTALLED_VERSION"
|
||||||
|
case $METHOD in
|
||||||
|
standalone) uninstall_tala_standalone ;;
|
||||||
|
homebrew) uninstall_tala_brew ;;
|
||||||
|
esac
|
||||||
|
elif [ "${TALA-}" ]; then
|
||||||
|
warn "no version of tala installed"
|
||||||
|
fi
|
||||||
|
|
||||||
if ! command -v d2 >/dev/null; then
|
if ! command -v d2 >/dev/null; then
|
||||||
warn "no version of d2 installed"
|
warn "no version of d2 installed"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
INSTALLED_VERSION="$(d2 --version)"
|
INSTALLED_VERSION="$(d2 --version)"
|
||||||
if ! uninstall_d2; then
|
|
||||||
echoerr "failed to uninstall $INSTALLED_VERSION"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
if [ "${TALA-}" ]; then
|
|
||||||
if ! command -v d2plugin-tala >/dev/null; then
|
|
||||||
warn "no version of tala installed"
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
INSTALLED_VERSION="$(d2plugin-tala --version)"
|
|
||||||
if ! uninstall_tala; then
|
|
||||||
echoerr "failed to uninstall tala $INSTALLED_VERSION"
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
uninstall_d2() {
|
|
||||||
header "uninstalling d2-$INSTALLED_VERSION"
|
header "uninstalling d2-$INSTALLED_VERSION"
|
||||||
uninstall_standalone_d2
|
case $METHOD in
|
||||||
|
standalone) uninstall_d2_standalone ;;
|
||||||
|
homebrew) uninstall_d2_brew ;;
|
||||||
|
esac
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_standalone_d2() {
|
uninstall_d2_standalone() {
|
||||||
log "uninstalling standalone release of d2-$INSTALLED_VERSION"
|
log "uninstalling standalone release of d2-$INSTALLED_VERSION"
|
||||||
|
|
||||||
if [ ! -e "$INSTALL_DIR/d2-$INSTALLED_VERSION" ]; then
|
if [ ! -e "$INSTALL_DIR/d2-$INSTALLED_VERSION" ]; then
|
||||||
|
|
@ -765,12 +883,11 @@ uninstall_standalone_d2() {
|
||||||
"$sh_c" rm -rf "$INSTALL_DIR/d2-$INSTALLED_VERSION"
|
"$sh_c" rm -rf "$INSTALL_DIR/d2-$INSTALLED_VERSION"
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_tala() {
|
uninstall_d2_brew() {
|
||||||
header "uninstalling tala-$INSTALLED_VERSION"
|
sh_c brew remove d2
|
||||||
uninstall_standalone_tala
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uninstall_standalone_tala() {
|
uninstall_tala_standalone() {
|
||||||
log "uninstalling standalone release tala-$INSTALLED_VERSION"
|
log "uninstalling standalone release tala-$INSTALLED_VERSION"
|
||||||
|
|
||||||
if [ ! -e "$INSTALL_DIR/tala-$INSTALLED_VERSION" ]; then
|
if [ ! -e "$INSTALL_DIR/tala-$INSTALLED_VERSION" ]; then
|
||||||
|
|
@ -788,6 +905,10 @@ uninstall_standalone_tala() {
|
||||||
"$sh_c" rm -rf "$INSTALL_DIR/tala-$INSTALLED_VERSION"
|
"$sh_c" rm -rf "$INSTALL_DIR/tala-$INSTALLED_VERSION"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uninstall_tala_brew() {
|
||||||
|
sh_c brew remove tala
|
||||||
|
}
|
||||||
|
|
||||||
is_prefix_writable() {
|
is_prefix_writable() {
|
||||||
sh_c "mkdir -p '$INSTALL_DIR' 2>/dev/null" || true
|
sh_c "mkdir -p '$INSTALL_DIR' 2>/dev/null" || true
|
||||||
# The reason for checking whether $INSTALL_DIR is writable is that on macOS you have
|
# The reason for checking whether $INSTALL_DIR is writable is that on macOS you have
|
||||||
|
|
@ -843,4 +964,9 @@ fetch_gh() {
|
||||||
sh_c mv "$file.inprogress" "$file"
|
sh_c mv "$file.inprogress" "$file"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
brew() {
|
||||||
|
# Makes brew sane.
|
||||||
|
HOMEBREW_NO_INSTALL_CLEANUP=1 HOMEBREW_NO_AUTO_UPDATE=1 command brew "$@"
|
||||||
|
}
|
||||||
|
|
||||||
main "$@"
|
main "$@"
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package version
|
package version
|
||||||
|
|
||||||
// Pre-built binaries will have version set during build time.
|
// Pre-built binaries will have version set during build time.
|
||||||
var Version = "master (built from source)"
|
var Version = "????"
|
||||||
|
|
|
||||||
45
lib/xmain/flag_helpers.go
Normal file
45
lib/xmain/flag_helpers.go
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
// flag_helpers.go are private functions from pflag/flag.go
|
||||||
|
package xmain
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
func wrap(i, w int, s string) string {
|
||||||
|
if w == 0 {
|
||||||
|
return strings.Replace(s, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||||
|
}
|
||||||
|
wrap := w - i
|
||||||
|
var r, l string
|
||||||
|
if wrap < 24 {
|
||||||
|
i = 16
|
||||||
|
wrap = w - i
|
||||||
|
r += "\n" + strings.Repeat(" ", i)
|
||||||
|
}
|
||||||
|
if wrap < 24 {
|
||||||
|
return strings.Replace(s, "\n", r, -1)
|
||||||
|
}
|
||||||
|
slop := 5
|
||||||
|
wrap = wrap - slop
|
||||||
|
l, s = wrapN(wrap, slop, s)
|
||||||
|
r = r + strings.Replace(l, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||||
|
for s != "" {
|
||||||
|
var t string
|
||||||
|
t, s = wrapN(wrap, slop, s)
|
||||||
|
r = r + "\n" + strings.Repeat(" ", i) + strings.Replace(t, "\n", "\n"+strings.Repeat(" ", i), -1)
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
|
||||||
|
func wrapN(i, slop int, s string) (string, string) {
|
||||||
|
if i+slop > len(s) {
|
||||||
|
return s, ""
|
||||||
|
}
|
||||||
|
w := strings.LastIndexAny(s[:i], " \t\n")
|
||||||
|
if w <= 0 {
|
||||||
|
return s, ""
|
||||||
|
}
|
||||||
|
nlPos := strings.LastIndex(s[:i], "\n")
|
||||||
|
if nlPos > 0 && nlPos < w {
|
||||||
|
return s[:nlPos], s[nlPos+1:]
|
||||||
|
}
|
||||||
|
return s[:w], s[w+1:]
|
||||||
|
}
|
||||||
173
lib/xmain/opts.go
Normal file
173
lib/xmain/opts.go
Normal file
|
|
@ -0,0 +1,173 @@
|
||||||
|
package xmain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
"oss.terrastruct.com/cmdlog"
|
||||||
|
"oss.terrastruct.com/xos"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Opts struct {
|
||||||
|
Args []string
|
||||||
|
Flags *pflag.FlagSet
|
||||||
|
env *xos.Env
|
||||||
|
log *cmdlog.Logger
|
||||||
|
|
||||||
|
flagEnv map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewOpts(env *xos.Env, log *cmdlog.Logger, args []string) *Opts {
|
||||||
|
flags := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||||
|
flags.SortFlags = false
|
||||||
|
flags.Usage = func() {}
|
||||||
|
flags.SetOutput(io.Discard)
|
||||||
|
return &Opts{
|
||||||
|
Args: args,
|
||||||
|
Flags: flags,
|
||||||
|
env: env,
|
||||||
|
log: log,
|
||||||
|
flagEnv: make(map[string]string),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mostly copy pasted pasted from pflag.FlagUsagesWrapped
|
||||||
|
// with modifications for env var
|
||||||
|
func (o *Opts) Defaults() string {
|
||||||
|
buf := new(bytes.Buffer)
|
||||||
|
|
||||||
|
var lines []string
|
||||||
|
|
||||||
|
maxlen := 0
|
||||||
|
maxEnvLen := 0
|
||||||
|
o.Flags.VisitAll(func(flag *pflag.Flag) {
|
||||||
|
if flag.Hidden {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
line := ""
|
||||||
|
if flag.Shorthand != "" && flag.ShorthandDeprecated == "" {
|
||||||
|
line = fmt.Sprintf(" -%s, --%s", flag.Shorthand, flag.Name)
|
||||||
|
} else {
|
||||||
|
line = fmt.Sprintf(" --%s", flag.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
varname, usage := pflag.UnquoteUsage(flag)
|
||||||
|
if varname != "" {
|
||||||
|
line += " " + varname
|
||||||
|
}
|
||||||
|
if flag.NoOptDefVal != "" {
|
||||||
|
switch flag.Value.Type() {
|
||||||
|
case "string":
|
||||||
|
line += fmt.Sprintf("[=\"%s\"]", flag.NoOptDefVal)
|
||||||
|
case "bool":
|
||||||
|
if flag.NoOptDefVal != "true" {
|
||||||
|
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||||
|
}
|
||||||
|
case "count":
|
||||||
|
if flag.NoOptDefVal != "+1" {
|
||||||
|
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
line += fmt.Sprintf("[=%s]", flag.NoOptDefVal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
line += "\x00"
|
||||||
|
|
||||||
|
if len(line) > maxlen {
|
||||||
|
maxlen = len(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if e, ok := o.flagEnv[flag.Name]; ok {
|
||||||
|
line += fmt.Sprintf("$%s", e)
|
||||||
|
}
|
||||||
|
|
||||||
|
line += "\x01"
|
||||||
|
|
||||||
|
if len(line) > maxEnvLen {
|
||||||
|
maxEnvLen = len(line)
|
||||||
|
}
|
||||||
|
|
||||||
|
line += usage
|
||||||
|
if flag.Value.Type() == "string" {
|
||||||
|
line += fmt.Sprintf(" (default %q)", flag.DefValue)
|
||||||
|
} else {
|
||||||
|
line += fmt.Sprintf(" (default %s)", flag.DefValue)
|
||||||
|
}
|
||||||
|
if len(flag.Deprecated) != 0 {
|
||||||
|
line += fmt.Sprintf(" (DEPRECATED: %s)", flag.Deprecated)
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = append(lines, line)
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, line := range lines {
|
||||||
|
sidx1 := strings.Index(line, "\x00")
|
||||||
|
sidx2 := strings.Index(line, "\x01")
|
||||||
|
spacing1 := strings.Repeat(" ", maxlen-sidx1)
|
||||||
|
spacing2 := strings.Repeat(" ", (maxEnvLen-maxlen)-sidx2+sidx1)
|
||||||
|
fmt.Fprintln(buf, line[:sidx1], spacing1, line[sidx1+1:sidx2], spacing2, wrap(maxEnvLen+3, 0, line[sidx2+1:]))
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Opts) getEnv(flag, k string) string {
|
||||||
|
if k != "" {
|
||||||
|
o.flagEnv[flag] = k
|
||||||
|
return o.env.Getenv(k)
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Opts) Int64(envKey, flag, shortFlag string, defaultVal int64, usage string) (*int64, error) {
|
||||||
|
if env := o.getEnv(flag, envKey); env != "" {
|
||||||
|
envVal, err := strconv.ParseInt(env, 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf(`invalid environment variable %s. Expected int64. Found "%v".`, envKey, envVal)
|
||||||
|
}
|
||||||
|
defaultVal = envVal
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.Flags.Int64P(flag, shortFlag, defaultVal, usage), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Opts) String(envKey, flag, shortFlag string, defaultVal, usage string) *string {
|
||||||
|
if env := o.getEnv(flag, envKey); env != "" {
|
||||||
|
defaultVal = env
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.Flags.StringP(flag, shortFlag, defaultVal, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Opts) Bool(envKey, flag, shortFlag string, defaultVal bool, usage string) (*bool, error) {
|
||||||
|
if env := o.getEnv(flag, envKey); env != "" {
|
||||||
|
if !boolyEnv(env) {
|
||||||
|
return nil, fmt.Errorf(`invalid environment variable %s. Expected bool. Found "%s".`, envKey, env)
|
||||||
|
}
|
||||||
|
if truthyEnv(env) {
|
||||||
|
defaultVal = true
|
||||||
|
} else {
|
||||||
|
defaultVal = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return o.Flags.BoolP(flag, shortFlag, defaultVal, usage), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func boolyEnv(s string) bool {
|
||||||
|
return falseyEnv(s) || truthyEnv(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
func falseyEnv(s string) bool {
|
||||||
|
return s == "0" || s == "false"
|
||||||
|
}
|
||||||
|
|
||||||
|
func truthyEnv(s string) bool {
|
||||||
|
return s == "1" || s == "true"
|
||||||
|
}
|
||||||
|
|
@ -9,13 +9,11 @@ import (
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"strings"
|
|
||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"cdr.dev/slog"
|
"cdr.dev/slog"
|
||||||
"cdr.dev/slog/sloggers/sloghuman"
|
"cdr.dev/slog/sloggers/sloghuman"
|
||||||
"github.com/spf13/pflag"
|
|
||||||
|
|
||||||
"oss.terrastruct.com/xos"
|
"oss.terrastruct.com/xos"
|
||||||
|
|
||||||
|
|
@ -42,13 +40,9 @@ func Main(run RunFunc) {
|
||||||
Stderr: os.Stderr,
|
Stderr: os.Stderr,
|
||||||
|
|
||||||
Env: xos.NewEnv(os.Environ()),
|
Env: xos.NewEnv(os.Environ()),
|
||||||
FlagSet: pflag.NewFlagSet("", pflag.ContinueOnError),
|
|
||||||
Args: args,
|
|
||||||
}
|
}
|
||||||
ms.Log = cmdlog.Log(ms.Env, os.Stderr)
|
ms.Log = cmdlog.Log(ms.Env, os.Stderr)
|
||||||
ms.FlagSet.SortFlags = false
|
ms.Opts = NewOpts(ms.Env, ms.Log, args)
|
||||||
ms.FlagSet.Usage = func() {}
|
|
||||||
ms.FlagSet.SetOutput(io.Discard)
|
|
||||||
|
|
||||||
sigs := make(chan os.Signal, 1)
|
sigs := make(chan os.Signal, 1)
|
||||||
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
|
signal.Notify(sigs, os.Interrupt, syscall.SIGTERM)
|
||||||
|
|
@ -90,8 +84,7 @@ type State struct {
|
||||||
|
|
||||||
Log *cmdlog.Logger
|
Log *cmdlog.Logger
|
||||||
Env *xos.Env
|
Env *xos.Env
|
||||||
Args []string
|
Opts *Opts
|
||||||
FlagSet *pflag.FlagSet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *State) Main(ctx context.Context, sigs <-chan os.Signal, run func(context.Context, *State) error) error {
|
func (ms *State) Main(ctx context.Context, sigs <-chan os.Signal, run func(context.Context, *State) error) error {
|
||||||
|
|
@ -129,13 +122,6 @@ func (ms *State) Main(ctx context.Context, sigs <-chan os.Signal, run func(conte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *State) FlagHelp() string {
|
|
||||||
b := &strings.Builder{}
|
|
||||||
ms.FlagSet.SetOutput(b)
|
|
||||||
ms.FlagSet.PrintDefaults()
|
|
||||||
return b.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
type ExitError struct {
|
type ExitError struct {
|
||||||
Code int `json:"code"`
|
Code int `json:"code"`
|
||||||
Message string `json:"message"`
|
Message string `json:"message"`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue