commit d8092fc9d51d96f3cc53d02d09a32e078bd4ed5e Author: omicron Date: Thu May 1 00:08:43 2025 +0200 Initial commit Basic project layout, some initial code diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5e56e04 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/bin diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..c0d882d --- /dev/null +++ b/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2025 omicron + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..84b0c70 --- /dev/null +++ b/Makefile @@ -0,0 +1,30 @@ +BINARY_DIR = bin +BINARIES = $(patsubst cmd/%/,%,$(wildcard cmd/*/)) + +.PHONY: all build test validate clean run $(BINARIES) + +all: build + + +build: $(BINARIES) + + +$(BINARY_DIR): + mkdir -p $(BINARY_DIR) + +$(BINARIES): %: $(BINARY_DIR) + go build -o $(BINARY_DIR)/$@ ./cmd/$@/ + +test: + go test ./... + +validate: + @test -z "$(shell gofmt -l .)" || (echo "Incorrect formatting in:"; gofmt -l .; exit 1) + go vet ./... + +clean: + rm -rf $(BINARY_DIR) + go clean + +run: $(LINKSERV) + $(LINKSERV) diff --git a/cmd/linkctl/main.go b/cmd/linkctl/main.go new file mode 100644 index 0000000..7564554 --- /dev/null +++ b/cmd/linkctl/main.go @@ -0,0 +1,15 @@ +package main + +import "fmt" +import "git.omicron.one/omicron/linkshare/internal/util" + +func main() { + paths, err := util.FindDirectories("") + if err != nil { + fmt.Println(err) + } + + fmt.Println("Paths:") + fmt.Println(" Schema:", paths.SchemaDir) + fmt.Println(" Database:", paths.DatabaseFile) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..ffc716f --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.omicron.one/omicron/linkshare + +go 1.24 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29 diff --git a/internal/util/directories.go b/internal/util/directories.go new file mode 100644 index 0000000..ac113ea --- /dev/null +++ b/internal/util/directories.go @@ -0,0 +1,118 @@ +package util + +import ( + "os" + "path/filepath" +) + +type AppPaths struct { + SchemaDir string + DatabaseFile string +} + +func executableDir() (string, error) { + myExecutable, err := os.Executable() + if err != nil { + return "", err + } + + myExecutable, err = filepath.EvalSymlinks(myExecutable) + if err != nil { + return "", err + } + return filepath.Dir(myExecutable), nil +} + +func isSystemInstall(myDir string) (bool, error) { + if myDir != "/bin" && myDir != "/usr/bin" { + return false, nil + } + return true, nil +} + +func isSystemLocalInstall(myDir string) (bool, error) { + if myDir != "/usr/local/bin" { + return false, nil + } + return true, nil +} + +func isUserLocalInstall(myDir string) (bool, error) { + home, err := os.UserHomeDir() + if err != nil { + return false, err + } + + if myDir != filepath.Join(home, ".local/bin") { + return false, nil + } + return true, nil +} + +func findDefaultDirectories() (*AppPaths, error) { + myDir, err := executableDir() + if err != nil { + return nil, err + } + + if system, err := isSystemInstall(myDir); err != nil { + return nil, err + } else if system { + return &AppPaths{ + SchemaDir: "/usr/share/linkshare/schema", + DatabaseFile: "/var/lib/linkshare/linkshare.db", + }, nil + } + + if local, err := isSystemLocalInstall(myDir); err != nil { + return nil, err + } else if local { + return &AppPaths{ + SchemaDir: "/usr/local/share/linkshare/schema", + DatabaseFile: "/var/lib/linkshare/linkshare.db", + }, nil + } + + if user, err := isUserLocalInstall(myDir); err != nil { + return nil, err + } else if user { + return &AppPaths{ + SchemaDir: filepath.Join(myDir, "../share/linkshare/"), + DatabaseFile: filepath.Join(myDir, "../var/lib/linkshare/linkshare.db"), + }, nil + } + + return &AppPaths{ + SchemaDir: filepath.Join(myDir, "../schema"), + DatabaseFile: filepath.Join(myDir, "../linkshare.db"), + }, nil +} + +// FindDirectories will find all relevant directories. +// It checks where the binary is installed and based on that it will decide +// where to look for other static data. +// +// Parameters: +// - dbPath: the explicit db path passed on the command line. If this contains +// a non-empty string the db returned database file will always be this one. +// If this contains an empty string a default database file will be picked +// based on where the binary is installed. +func FindDirectories(dbPath string) (*AppPaths, error) { + paths, err := findDefaultDirectories() + if err != nil { + return nil, err + } + if dbPath != "" { + paths.DatabaseFile = dbPath + } + return paths, nil +} + +// CreateDirectories ensures all application managed directories are created +func CreateDirectories(paths *AppPaths) error { + err := os.MkdirAll(filepath.Dir(paths.DatabaseFile), 0750) + if err != nil { + return err + } + return nil +}