From 693f23e08609fc57fef7bd263d9dc576aba02274 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sun, 7 Aug 2022 14:46:46 -0500 Subject: [PATCH 1/7] chore: Add nix shell for simple development setup This enables contributors using Nix to set up their environment with ease. --- .envrc | 1 + coderd/util/tz/tz_linux.go | 16 ++++----- docs/CONTRIBUTING.md | 3 ++ flake.lock | 66 ++++++++++++++++++++++++++++++++++++ flake.nix | 57 +++++++++++++++++++++++++++++++ provisionersdk/agent_test.go | 3 ++ scripts/build_go_slim.sh | 4 +-- shell.nix | 7 ++++ 8 files changed, 147 insertions(+), 10 deletions(-) create mode 100644 .envrc create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 shell.nix diff --git a/.envrc b/.envrc new file mode 100644 index 0000000000000..1d953f4bd7359 --- /dev/null +++ b/.envrc @@ -0,0 +1 @@ +use nix diff --git a/coderd/util/tz/tz_linux.go b/coderd/util/tz/tz_linux.go index 06d7bfe648a2c..5aa3ddf8312b4 100644 --- a/coderd/util/tz/tz_linux.go +++ b/coderd/util/tz/tz_linux.go @@ -29,16 +29,16 @@ func TimezoneIANA() (*time.Location, error) { return nil, xerrors.Errorf("lookup timezone from env: %w", err) } - lp, err := filepath.EvalSymlinks(etcLocaltime) - if err != nil { - return nil, xerrors.Errorf("read location of %s: %w", etcLocaltime, err) + location, err := filepath.EvalSymlinks(etcLocaltime) + if err == nil { + location = strings.Replace(location, zoneInfoPath, "", -1) + location = strings.TrimPrefix(location, string(filepath.Separator)) + } else { + location, _ = time.Now().Zone() } - - stripped := strings.Replace(lp, zoneInfoPath, "", -1) - stripped = strings.TrimPrefix(stripped, string(filepath.Separator)) - loc, err = time.LoadLocation(stripped) + loc, err = time.LoadLocation(location) if err != nil { - return nil, xerrors.Errorf("invalid location %q guessed from %s: %w", stripped, lp, err) + return nil, xerrors.Errorf("invalid location %q guessed from %s: %w", location, location, err) } return loc, nil } diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index c9abc3d0d1e9d..6d3a749ac50aa 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -4,6 +4,9 @@ Coder requires Go 1.18+, Node 14+, and GNU Make. +> **Note**: +> Use [Nix](https://nix.dev/) for a one-command setup: `nix-shell` + ### Development workflow Use the following `make` commands and scripts in development: diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000000000..d322207cd6512 --- /dev/null +++ b/flake.lock @@ -0,0 +1,66 @@ +{ + "nodes": { + "drpc": { + "inputs": { + "flake-utils": [ + "flake-utils" + ], + "nixpkgs": [ + "nixpkgs-unstable" + ] + }, + "locked": { + "lastModified": 1655921719, + "narHash": "sha256-F5CUCcoHd8vWMJyjt3FRgj3TglvF95hgVqWpugVer/M=", + "owner": "storj", + "repo": "drpc", + "rev": "9206537a4db76809da6ec768a0c5e45ddb618ef5", + "type": "github" + }, + "original": { + "owner": "storj", + "repo": "drpc", + "type": "github" + } + }, + "flake-utils": { + "locked": { + "lastModified": 1659877975, + "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c0e246b9b83f637f4681389ecabcb2681b4f3af0", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs-unstable": { + "locked": { + "lastModified": 1659803779, + "narHash": "sha256-+5zkHlbcbFyN5f3buO1RAZ9pH1wXLxCesUJ0vFmLr9Y=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "f44884060cb94240efbe55620f38a8ec8d9af601", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "ref": "nixos-unstable", + "type": "indirect" + } + }, + "root": { + "inputs": { + "drpc": "drpc", + "flake-utils": "flake-utils", + "nixpkgs-unstable": "nixpkgs-unstable" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000000000..fbf3bdcc53243 --- /dev/null +++ b/flake.nix @@ -0,0 +1,57 @@ +{ + description = "Development environments on your infrastructure"; + + inputs = { + nixpkgs-unstable.url = "nixpkgs/nixos-unstable"; + flake-utils.url = "github:numtide/flake-utils"; + drpc = { + url = "github:storj/drpc"; + inputs = { + nixpkgs.follows = "nixpkgs-unstable"; + flake-utils.follows = "flake-utils"; + }; + }; + }; + + outputs = { self, nixpkgs-unstable, flake-utils, drpc }: + flake-utils.lib.eachDefaultSystem (system: + with nixpkgs-unstable.legacyPackages.${system}; rec { + devShell = + let devtools = {}; + in mkShell { + buildInputs = [ + drpc.defaultPackage.${system} + ]; + nativeBuildInputs = [ + go_1_19 + gopls + nodejs + ripgrep + exa + bat + typos + git + nfpm + openssl + protoc-gen-go + go-migrate + gotestsum + goreleaser + sqlc + shfmt + terraform + shellcheck + golangci-lint + yarn + postgresql + helm + jq + zstd + zip + openssh + nodePackages.typescript + nodePackages.typescript-language-server + ]; + }; + }); +} diff --git a/provisionersdk/agent_test.go b/provisionersdk/agent_test.go index 43fe411954cd9..305813719f6c9 100644 --- a/provisionersdk/agent_test.go +++ b/provisionersdk/agent_test.go @@ -46,6 +46,9 @@ func TestAgentScript(t *testing.T) { } script = strings.ReplaceAll(script, "${ACCESS_URL}", srvURL.String()+"/") script = strings.ReplaceAll(script, "${AUTH_TYPE}", "token") + // In certain distributions "echo" is a part of coreutils, and determines + // it's functionality based on the exec path name. + script = strings.ReplaceAll(script, "BINARY_NAME=coder", "BINARY_NAME=echo") // This is intentionally ran in single quotes to mimic how a customer may // embed our script. Our scripts should not include any single quotes. // nolint:gosec diff --git a/scripts/build_go_slim.sh b/scripts/build_go_slim.sh index 21d70b9918b8c..3ecc9b5740dc9 100755 --- a/scripts/build_go_slim.sh +++ b/scripts/build_go_slim.sh @@ -58,7 +58,7 @@ done # Check dependencies dependencies go if [[ $compress != 0 ]]; then - dependencies shasum tar zstd + dependencies openssl tar zstd zip if [[ $compress != [0-9]* ]] || [[ $compress -gt 22 ]] || [[ $compress -lt 1 ]]; then error "Invalid value for compress, must in in the range of [1, 22]" @@ -114,7 +114,7 @@ if [[ $compress != 0 ]]; then sha_file=coder.sha1 sha_dest="$dest_dir/$sha_file" log "--- Generating SHA1 for coder-slim binaries ($sha_dest)" - shasum -b -a 1 coder-* | tee $sha_file + openssl dgst -r -sha1 coder-* | cut -c1-40 | tee $sha_file echo "$sha_dest" log log diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000000000..61a66c55ba636 --- /dev/null +++ b/shell.nix @@ -0,0 +1,7 @@ +(import ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/12c64ca55c1014cdc1b16ed5a804aa8576601ff2.tar.gz"; + sha256 = "0jm6nzb83wa6ai17ly9fzpqc40wg1viib8klq8lby54agpl213w5"; } +) { + src = ./.; +}).shellNix From 98a015f832d8d87b545eb6df596fc0f2df8fcad4 Mon Sep 17 00:00:00 2001 From: Charlie Moog Date: Sun, 7 Aug 2022 16:53:01 -0500 Subject: [PATCH 2/7] improve nix style, flake output schema --- flake.lock | 58 ++++++++++++++++++++++++++--------- flake.nix | 89 ++++++++++++++++++++++++++---------------------------- shell.nix | 17 ++++++----- 3 files changed, 95 insertions(+), 69 deletions(-) diff --git a/flake.lock b/flake.lock index d322207cd6512..a9a9007753fae 100644 --- a/flake.lock +++ b/flake.lock @@ -2,28 +2,40 @@ "nodes": { "drpc": { "inputs": { - "flake-utils": [ - "flake-utils" - ], - "nixpkgs": [ - "nixpkgs-unstable" - ] + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1655921719, - "narHash": "sha256-F5CUCcoHd8vWMJyjt3FRgj3TglvF95hgVqWpugVer/M=", + "lastModified": 1655479430, + "narHash": "sha256-ZQgJFlrddH2uQDQepDFYy3C+Ik/geMQgGWkLVhA9wss=", "owner": "storj", "repo": "drpc", - "rev": "9206537a4db76809da6ec768a0c5e45ddb618ef5", + "rev": "0a6ae7bccab6f01ca6390a7a5bf9abeee71624d2", "type": "github" }, "original": { "owner": "storj", + "ref": "v0.0.32", "repo": "drpc", "type": "github" } }, "flake-utils": { + "locked": { + "lastModified": 1634851050, + "narHash": "sha256-N83GlSGPJJdcqhUxSCS/WwW5pksYf3VP1M13cDRTSVA=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c91f3de5adaf1de973b797ef7485e441a65b8935", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { "locked": { "lastModified": 1659877975, "narHash": "sha256-zllb8aq3YO3h8B/U0/J1WBgAL8EX5yWf5pMj3G0NAmc=", @@ -38,26 +50,42 @@ "type": "github" } }, - "nixpkgs-unstable": { + "nixpkgs": { + "locked": { + "lastModified": 1635797866, + "narHash": "sha256-e3vqt720wyb1PPNcGXej8wwip2/tgO1JsSGYK1NptSw=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6751e7428f20328fed076acfcbb340d0f4aa0c07", + "type": "github" + }, + "original": { + "owner": "NixOS", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1659803779, "narHash": "sha256-+5zkHlbcbFyN5f3buO1RAZ9pH1wXLxCesUJ0vFmLr9Y=", - "owner": "NixOS", + "owner": "nixos", "repo": "nixpkgs", "rev": "f44884060cb94240efbe55620f38a8ec8d9af601", "type": "github" }, "original": { - "id": "nixpkgs", + "owner": "nixos", "ref": "nixos-unstable", - "type": "indirect" + "repo": "nixpkgs", + "type": "github" } }, "root": { "inputs": { "drpc": "drpc", - "flake-utils": "flake-utils", - "nixpkgs-unstable": "nixpkgs-unstable" + "flake-utils": "flake-utils_2", + "nixpkgs": "nixpkgs_2" } } }, diff --git a/flake.nix b/flake.nix index fbf3bdcc53243..b6935f967ef7e 100644 --- a/flake.nix +++ b/flake.nix @@ -2,56 +2,51 @@ description = "Development environments on your infrastructure"; inputs = { - nixpkgs-unstable.url = "nixpkgs/nixos-unstable"; + nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; flake-utils.url = "github:numtide/flake-utils"; - drpc = { - url = "github:storj/drpc"; - inputs = { - nixpkgs.follows = "nixpkgs-unstable"; - flake-utils.follows = "flake-utils"; - }; - }; + drpc.url = "github:storj/drpc/v0.0.32"; }; - outputs = { self, nixpkgs-unstable, flake-utils, drpc }: + outputs = { self, nixpkgs, flake-utils, drpc }: flake-utils.lib.eachDefaultSystem (system: - with nixpkgs-unstable.legacyPackages.${system}; rec { - devShell = - let devtools = {}; - in mkShell { - buildInputs = [ - drpc.defaultPackage.${system} - ]; - nativeBuildInputs = [ - go_1_19 - gopls - nodejs - ripgrep - exa - bat - typos - git - nfpm - openssl - protoc-gen-go - go-migrate - gotestsum - goreleaser - sqlc - shfmt - terraform - shellcheck - golangci-lint - yarn - postgresql - helm - jq - zstd - zip - openssh - nodePackages.typescript - nodePackages.typescript-language-server - ]; + let + pkgs = nixpkgs.legacyPackages.${system}; + in + { + formatter = pkgs.nixpkgs-fmt; + devShells.default = pkgs.mkShell { + buildInputs = with pkgs; [ + bat + drpc.defaultPackage.${system} + exa + git + go-migrate + go_1_19 + golangci-lint + gopls + goreleaser + gotestsum + helm + jq + nfpm + nodePackages.typescript + nodePackages.typescript-language-server + nodejs + openssh + openssl + postgresql + protoc-gen-go + ripgrep + shellcheck + shfmt + sqlc + terraform + typos + yarn + zip + zstd + ]; }; - }); + } + ); } diff --git a/shell.nix b/shell.nix index 61a66c55ba636..a3a8864c7d5e1 100644 --- a/shell.nix +++ b/shell.nix @@ -1,7 +1,10 @@ -(import ( - fetchTarball { - url = "https://github.com/edolstra/flake-compat/archive/12c64ca55c1014cdc1b16ed5a804aa8576601ff2.tar.gz"; - sha256 = "0jm6nzb83wa6ai17ly9fzpqc40wg1viib8klq8lby54agpl213w5"; } -) { - src = ./.; -}).shellNix +(import + ( + fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/b4a34015c698c7793d592d66adbab377907a2be8.tar.gz"; + sha256 = "1qc703yg0babixi6wshn5wm2kgl5y1drcswgszh4xxzbrwkk9sv7"; + } + ) + { + src = ./.; + }).shellNix From a07030d1f468110cb840f018d5fc479e6d2df60c Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sun, 7 Aug 2022 17:04:54 -0500 Subject: [PATCH 3/7] fix error message --- coderd/util/tz/tz_linux.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/util/tz/tz_linux.go b/coderd/util/tz/tz_linux.go index 5aa3ddf8312b4..20128c6fdcff5 100644 --- a/coderd/util/tz/tz_linux.go +++ b/coderd/util/tz/tz_linux.go @@ -38,7 +38,7 @@ func TimezoneIANA() (*time.Location, error) { } loc, err = time.LoadLocation(location) if err != nil { - return nil, xerrors.Errorf("invalid location %q guessed from %s: %w", location, location, err) + return nil, xerrors.Errorf("invalid location from %q: %w", location, err) } return loc, nil } From c02d6f88e95f08357b3562343f6405c22f601b1b Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 8 Aug 2022 10:15:46 -0500 Subject: [PATCH 4/7] Update scripts/build_go_slim.sh Co-authored-by: Mathias Fredriksson --- scripts/build_go_slim.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_go_slim.sh b/scripts/build_go_slim.sh index 3ecc9b5740dc9..8296146d9d6af 100755 --- a/scripts/build_go_slim.sh +++ b/scripts/build_go_slim.sh @@ -114,7 +114,7 @@ if [[ $compress != 0 ]]; then sha_file=coder.sha1 sha_dest="$dest_dir/$sha_file" log "--- Generating SHA1 for coder-slim binaries ($sha_dest)" - openssl dgst -r -sha1 coder-* | cut -c1-40 | tee $sha_file + openssl dgst -r -sha1 coder-* | tee $sha_file echo "$sha_dest" log log From 26ca21c238b494a8c8028036c27403f5881988dd Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 8 Aug 2022 10:15:57 -0500 Subject: [PATCH 5/7] Update scripts/build_go_slim.sh Co-authored-by: Mathias Fredriksson --- scripts/build_go_slim.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/build_go_slim.sh b/scripts/build_go_slim.sh index 8296146d9d6af..753b71987283b 100755 --- a/scripts/build_go_slim.sh +++ b/scripts/build_go_slim.sh @@ -58,7 +58,7 @@ done # Check dependencies dependencies go if [[ $compress != 0 ]]; then - dependencies openssl tar zstd zip + dependencies openssl tar zstd if [[ $compress != [0-9]* ]] || [[ $compress -gt 22 ]] || [[ $compress -lt 1 ]]; then error "Invalid value for compress, must in in the range of [1, 22]" From 44503c6a706bc419f615b7106017828cdb7127f9 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 8 Aug 2022 10:30:05 -0500 Subject: [PATCH 6/7] Add UTC default for timezone and remove unnecessary goreleaser dependency --- .envrc | 1 - coderd/util/tz/tz_linux.go | 3 ++- flake.nix | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 .envrc diff --git a/.envrc b/.envrc deleted file mode 100644 index 1d953f4bd7359..0000000000000 --- a/.envrc +++ /dev/null @@ -1 +0,0 @@ -use nix diff --git a/coderd/util/tz/tz_linux.go b/coderd/util/tz/tz_linux.go index 20128c6fdcff5..d7acb9b0b7559 100644 --- a/coderd/util/tz/tz_linux.go +++ b/coderd/util/tz/tz_linux.go @@ -34,7 +34,8 @@ func TimezoneIANA() (*time.Location, error) { location = strings.Replace(location, zoneInfoPath, "", -1) location = strings.TrimPrefix(location, string(filepath.Separator)) } else { - location, _ = time.Now().Zone() + // Go's local time parsing implementation defaults to UTC if none is set! + location = "UTC" } loc, err = time.LoadLocation(location) if err != nil { diff --git a/flake.nix b/flake.nix index b6935f967ef7e..d3ce80f9562f8 100644 --- a/flake.nix +++ b/flake.nix @@ -24,7 +24,6 @@ go_1_19 golangci-lint gopls - goreleaser gotestsum helm jq From 873f0da549b116231bf16bfbdb29278bf27f896c Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 8 Aug 2022 10:38:37 -0500 Subject: [PATCH 7/7] Skip TZ test if localtime does not exist --- cli/util.go | 12 ++++++------ coderd/util/tz/tz_linux.go | 16 +++++++--------- coderd/util/tz/tz_test.go | 6 ++++++ 3 files changed, 19 insertions(+), 15 deletions(-) diff --git a/cli/util.go b/cli/util.go index aac8888b977ec..c7c75ae1c06bd 100644 --- a/cli/util.go +++ b/cli/util.go @@ -16,11 +16,11 @@ var errInvalidTimeFormat = xerrors.New("Start time must be in the format hh:mm[a var errUnsupportedTimezone = xerrors.New("The location you provided looks like a timezone. Check https://ipinfo.io for your location.") // durationDisplay formats a duration for easier display: -// * Durations of 24 hours or greater are displays as Xd -// * Durations less than 1 minute are displayed as <1m -// * Duration is truncated to the nearest minute -// * Empty minutes and seconds are truncated -// * The returned string is the absolute value. Use sign() +// - Durations of 24 hours or greater are displays as Xd +// - Durations less than 1 minute are displayed as <1m +// - Duration is truncated to the nearest minute +// - Empty minutes and seconds are truncated +// - The returned string is the absolute value. Use sign() // if you need to indicate if the duration is positive or // negative. func durationDisplay(d time.Duration) string { @@ -114,7 +114,7 @@ func parseCLISchedule(parts ...string) (*schedule.Schedule, error) { if loc == nil { loc, err = tz.TimezoneIANA() if err != nil { - return nil, xerrors.Errorf("Could not automatically determine your timezone") + loc = time.UTC } } diff --git a/coderd/util/tz/tz_linux.go b/coderd/util/tz/tz_linux.go index d7acb9b0b7559..0f4d0d7c73e7a 100644 --- a/coderd/util/tz/tz_linux.go +++ b/coderd/util/tz/tz_linux.go @@ -29,17 +29,15 @@ func TimezoneIANA() (*time.Location, error) { return nil, xerrors.Errorf("lookup timezone from env: %w", err) } - location, err := filepath.EvalSymlinks(etcLocaltime) - if err == nil { - location = strings.Replace(location, zoneInfoPath, "", -1) - location = strings.TrimPrefix(location, string(filepath.Separator)) - } else { - // Go's local time parsing implementation defaults to UTC if none is set! - location = "UTC" + lp, err := filepath.EvalSymlinks(etcLocaltime) + if err != nil { + return nil, xerrors.Errorf("read location of %s: %w", etcLocaltime, err) } - loc, err = time.LoadLocation(location) + stripped := strings.Replace(lp, zoneInfoPath, "", -1) + stripped = strings.TrimPrefix(stripped, string(filepath.Separator)) + loc, err = time.LoadLocation(stripped) if err != nil { - return nil, xerrors.Errorf("invalid location from %q: %w", location, err) + return nil, xerrors.Errorf("invalid location %q guessed from %s: %w", stripped, lp, err) } return loc, nil } diff --git a/coderd/util/tz/tz_test.go b/coderd/util/tz/tz_test.go index 35f64843e4782..cc7d9b69b413e 100644 --- a/coderd/util/tz/tz_test.go +++ b/coderd/util/tz/tz_test.go @@ -2,6 +2,7 @@ package tz_test import ( "os" + "runtime" "testing" "github.com/stretchr/testify/assert" @@ -25,6 +26,11 @@ func Test_TimezoneIANA(t *testing.T) { //nolint:paralleltest // UnsetEnv t.Run("NoEnv", func(t *testing.T) { + _, err := os.Stat("/etc/localtime") + if runtime.GOOS == "linux" && err != nil { + // Not all Linux operating systems are guaranteed to have localtime! + t.Skip("localtime doesn't exist!") + } oldEnv, found := os.LookupEnv("TZ") if found { require.NoError(t, os.Unsetenv("TZ"))