diff --git a/.github/workflows/go-test.yml b/.github/workflows/go-test.yml index 3c40c02..c5e7a02 100644 --- a/.github/workflows/go-test.yml +++ b/.github/workflows/go-test.yml @@ -13,7 +13,7 @@ jobs: name: go-test strategy: matrix: - go-version: [1.20.x, 1.21.x] + go-version: [1.21.x, 1.22.x] platform: [ubuntu-latest, macos-latest] runs-on: ${{ matrix.platform }} steps: diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 257f2a6..91db8dd 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -50,7 +50,7 @@ jobs: - uses: actions/checkout@v4 - uses: actions/setup-go@v5 with: - go-version: 1.20.x + go-version: 1.21.x - name: Build binary run: GOOS=${{ matrix.os }} GOARCH=${{ matrix.arch }} make build - name: Upload release asset diff --git a/cmd/cardano-up/main.go b/cmd/cardano-up/main.go index 0808302..cf89723 100644 --- a/cmd/cardano-up/main.go +++ b/cmd/cardano-up/main.go @@ -1,4 +1,4 @@ -// Copyright 2023 Blink Labs Software +// Copyright 2024 Blink Labs Software // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ package main import ( + "log/slog" "os" "github.com/spf13/cobra" @@ -25,6 +26,10 @@ const ( ) func main() { + globalFlags := struct { + debug bool + }{} + rootCmd := &cobra.Command{ Use: programName, /* @@ -36,11 +41,27 @@ func main() { This application is a tool to generate the needed files to quickly create a Cobra application.`, */ + PersistentPreRun: func(cmd *cobra.Command, args []string) { + // Configure default logger + logLevel := slog.LevelInfo + if globalFlags.debug { + logLevel = slog.LevelDebug + } + logger := slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{ + Level: logLevel, + })) + slog.SetDefault(logger) + }, } + // Global flags + rootCmd.PersistentFlags().BoolVarP(&globalFlags.debug, "debug", "D", false, "enable debug logging") + // Add subcommands rootCmd.AddCommand( versionCommand(), + // TODO: remove me + testCommand(), ) if err := rootCmd.Execute(); err != nil { diff --git a/cmd/cardano-up/test.go b/cmd/cardano-up/test.go new file mode 100644 index 0000000..9cfee86 --- /dev/null +++ b/cmd/cardano-up/test.go @@ -0,0 +1,39 @@ +// Copyright 2023 Blink Labs Software +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package main + +import ( + "fmt" + "log/slog" + "os" + + "github.com/blinklabs-io/cardano-up/pkgmgr" + "github.com/spf13/cobra" +) + +func testCommand() *cobra.Command { + return &cobra.Command{ + Use: "test", + Short: "Test subcommand for development work (TODO: remove me)", + Run: func(cmd *cobra.Command, args []string) { + pm, err := pkgmgr.NewDefaultPackageManager() + if err != nil { + slog.Error(fmt.Sprintf("failed to create package manager: %s", err)) + os.Exit(1) + } + slog.Debug(fmt.Sprintf("pm = %#v", pm)) + }, + } +} diff --git a/go.mod b/go.mod index c2cd72f..1929b70 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/blinklabs-io/cardano-up -go 1.20 +go 1.21 require github.com/spf13/cobra v1.8.0 diff --git a/pkgmgr/config.go b/pkgmgr/config.go new file mode 100644 index 0000000..97ebc94 --- /dev/null +++ b/pkgmgr/config.go @@ -0,0 +1,57 @@ +// Copyright 2024 Blink Labs Software +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pkgmgr + +import ( + "fmt" + "log/slog" + "os" + "path/filepath" +) + +type Config struct { + ConfigDir string + CacheDir string + Logger *slog.Logger +} + +func NewDefaultConfig() (Config, error) { + userConfigDir, err := os.UserConfigDir() + if err != nil { + return Config{}, fmt.Errorf( + "could not determine user config directory: %s", + err, + ) + } + userCacheDir, err := os.UserCacheDir() + if err != nil { + return Config{}, fmt.Errorf( + "could not determine user cache directory: %s", + err, + ) + } + ret := Config{ + ConfigDir: filepath.Join( + userConfigDir, + "cardano-up", + ), + CacheDir: filepath.Join( + userCacheDir, + "cardano-up", + ), + Logger: slog.Default(), + } + return ret, nil +} diff --git a/pkgmgr/config_test.go b/pkgmgr/config_test.go new file mode 100644 index 0000000..5a9cdd1 --- /dev/null +++ b/pkgmgr/config_test.go @@ -0,0 +1,124 @@ +package pkgmgr_test + +import ( + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/blinklabs-io/cardano-up/pkgmgr" +) + +func TestNewDefaultConfig(t *testing.T) { + testHome := "/path/to/user/home" + expectedCacheDir := filepath.Join(testHome, ".cache/cardano-up") + expectedConfigDir := filepath.Join(testHome, ".config/cardano-up") + origEnvVars := setEnvVars( + map[string]string{ + "HOME": testHome, + "XDG_CONFIG_HOME": "", + "XDG_CACHE_HOME": "", + }, + ) + defer func() { + setEnvVars(origEnvVars) + }() + cfg, err := pkgmgr.NewDefaultConfig() + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + if cfg.CacheDir != expectedCacheDir { + t.Fatalf( + "did not get expected cache dir, got %q, expected %q", + cfg.CacheDir, + expectedCacheDir, + ) + } + if cfg.ConfigDir != expectedConfigDir { + t.Fatalf( + "did not get expected config dir, got %q, expected %q", + cfg.ConfigDir, + expectedConfigDir, + ) + } +} + +func TestNewDefaultConfigXdgConfigCacheEnvVars(t *testing.T) { + testHome := "/path/to/user/home" + testXdgCacheHome := filepath.Join(testHome, ".cache-test") + testXdgConfigHome := filepath.Join(testHome, ".config-test") + expectedCacheDir := filepath.Join(testXdgCacheHome, "cardano-up") + expectedConfigDir := filepath.Join(testXdgConfigHome, "cardano-up") + origEnvVars := setEnvVars( + map[string]string{ + "HOME": testHome, + "XDG_CONFIG_HOME": testXdgConfigHome, + "XDG_CACHE_HOME": testXdgCacheHome, + }, + ) + defer func() { + setEnvVars(origEnvVars) + }() + cfg, err := pkgmgr.NewDefaultConfig() + if err != nil { + t.Fatalf("unexpected error: %s", err) + } + if cfg.CacheDir != expectedCacheDir { + t.Fatalf( + "did not get expected cache dir, got %q, expected %q", + cfg.CacheDir, + expectedCacheDir, + ) + } + if cfg.ConfigDir != expectedConfigDir { + t.Fatalf( + "did not get expected config dir, got %q, expected %q", + cfg.ConfigDir, + expectedConfigDir, + ) + } +} + +func TestNewDefaultConfigEmptyHome(t *testing.T) { + expectedErrs := map[string]string{ + "linux": "could not determine user config directory: neither $XDG_CONFIG_HOME nor $HOME are defined", + "darwin": "could not determine user config directory: $HOME is not defined", + } + origEnvVars := setEnvVars( + map[string]string{ + "HOME": "", + "XDG_CONFIG_HOME": "", + "XDG_CACHE_HOME": "", + }, + ) + defer func() { + setEnvVars(origEnvVars) + }() + _, err := pkgmgr.NewDefaultConfig() + expectedErr, ok := expectedErrs[runtime.GOOS] + if !ok { + t.Fatalf("unsupported OS: %s", runtime.GOOS) + } + if err == nil || err.Error() != expectedErr { + t.Fatalf( + "did not get expected error, got %q, expected %q", + err.Error(), + expectedErr, + ) + } +} + +func setEnvVar(envVar string, path string) string { + oldVal := os.Getenv(envVar) + os.Setenv(envVar, path) + return oldVal +} + +func setEnvVars(envVars map[string]string) map[string]string { + origVars := map[string]string{} + for k, v := range envVars { + origVars[k] = os.Getenv(k) + os.Setenv(k, v) + } + return origVars +} diff --git a/pkgmgr/pkgmgr.go b/pkgmgr/pkgmgr.go new file mode 100644 index 0000000..5e25787 --- /dev/null +++ b/pkgmgr/pkgmgr.go @@ -0,0 +1,44 @@ +// Copyright 2024 Blink Labs Software +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package pkgmgr + +type PackageManager struct { + config Config + // TODO +} + +func NewPackageManager(cfg Config) (*PackageManager, error) { + p := &PackageManager{ + config: cfg, + } + if err := p.init(); err != nil { + return nil, err + } + return p, nil +} + +func NewDefaultPackageManager() (*PackageManager, error) { + pmCfg, err := NewDefaultConfig() + if err != nil { + return nil, err + } + return NewPackageManager(pmCfg) +} + +func (p *PackageManager) init() error { + // TODO: create config/cache dirs + p.config.Logger.Debug("initializing package manager") + return nil +}