From ed20d843c2d6b88706b7ee5ebf871be605ae5331 Mon Sep 17 00:00:00 2001 From: Martyn R Date: Wed, 29 Dec 2021 12:00:51 +0000 Subject: [PATCH] Initial golang implementation by-the-docs --- base/base.go | 2 +- go.mod | 2 + go.sum | 2 + printall.go | 59 ++++++++++++++++ project/project.go | 145 ++++++++++++++++++++++++++++++++++++++ user/user.go | 170 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 379 insertions(+), 1 deletion(-) create mode 100644 go.sum create mode 100644 printall.go create mode 100644 project/project.go create mode 100644 user/user.go diff --git a/base/base.go b/base/base.go index 5a10f8b..e905bb1 100644 --- a/base/base.go +++ b/base/base.go @@ -17,7 +17,7 @@ func Cache() (string, error) { } func Config() (string, error) { - dir, err := os.UserCacheDir() + dir, err := os.UserConfigDir() return dir, err } diff --git a/go.mod b/go.mod index 993c836..0e5eb90 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,5 @@ module git.martyn.berlin/martyn/golang-directories go 1.17 + +require golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d95688d --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= +golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/printall.go b/printall.go new file mode 100644 index 0000000..f340ecf --- /dev/null +++ b/printall.go @@ -0,0 +1,59 @@ +package main + +import ( + "fmt" + "reflect" + "runtime" + "strings" + + "git.martyn.berlin/martyn/golang-directories/base" + "git.martyn.berlin/martyn/golang-directories/project" + "git.martyn.berlin/martyn/golang-directories/user" +) + +func GetFunctionName(i interface{}) string { + fullName := strings.Split(runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name(), "/") + funcName := fullName[len(fullName)-1] + return funcName +} + +func printOne(f func() (string, error)) { + result, e := f() + if e != nil { + fmt.Printf("%s() : ERROR : %s\n", GetFunctionName(f), e.Error()) + return + } + fmt.Printf("%s() : %s\n", GetFunctionName(f), result) +} + +func printall() { + printOne(base.Home) + printOne(base.Cache) + printOne(base.Config) + printOne(base.Data) + printOne(base.DataLocal) + printOne(base.Executable) + printOne(base.Preferences) + printOne(base.Runtime) + printOne(base.State) + printOne(user.Home) + printOne(user.Audio) + printOne(user.Desktop) + printOne(user.Documents) + printOne(user.Downloads) + printOne(user.Fonts) + printOne(user.Pictures) + printOne(user.Public) + printOne(user.Templates) + printOne(user.Videos) + project.SetProjectName("example", "org.example.example", "Example Corp.", "Example App") + printOne(project.Cache) + printOne(project.Config) + printOne(project.Data) + printOne(project.DataLocal) + printOne(project.Preferences) +} + +func main() { + printall() +} diff --git a/project/project.go b/project/project.go new file mode 100644 index 0000000..39b0919 --- /dev/null +++ b/project/project.go @@ -0,0 +1,145 @@ +package project + +import ( + "errors" + "runtime" + "strings" + + "git.martyn.berlin/martyn/golang-directories/base" +) + +var projectNameShort string +var projectNameReverse string +var projectNameOrg string +var projectNameProject string + +// setProjectName sets the project name up and has the following components: +// short: a short name for the project, all lowercased +// reverse: a java-like reverse-domain-name style +// organisation: the name of the organisation which this project is under +// project: the "normal" project name +// example : +// setProjectName("notepad++","org.notepad-plus-plus.notepad-plus-plus","Don Ho","Notepad++") +// This is used for basing folder structures on. +func SetProjectName(short, reverse, organisation, project string) error { + projectNameShort = short + projectNameReverse = reverse + projectNameOrg = organisation + projectNameProject = project + if len(projectNameShort) < 1 || len(projectNameReverse) < 1 || + len(projectNameProject) < 1 || len(projectNameProject) < 1 { + return errors.New("to use the directories/project package, you must call project.SetProjectName() with all four arguments set") + } + return nil +} + +func projectPath() string { + switch runtime.GOOS { + case "linux": + return strings.ToLower(strings.ReplaceAll(projectNameShort, " ", "-")) + case "windows": + return projectNameOrg + "\\" + projectNameProject + case "darwin": + return projectNameReverse + } + return "" +} + +func Cache() (string, error) { + if len(projectNameShort) < 1 || len(projectNameReverse) < 1 || + len(projectNameProject) < 1 || len(projectNameProject) < 1 { + return "", errors.New("to use the directories/project package, you must call project.SetProjectName() with all four arguments set") + } + c, e := base.Cache() + if e != nil { + return "", e + } + switch runtime.GOOS { + case "linux": + return c + "/" + projectPath(), nil + case "windows": + return c + "\\" + projectPath() + "\\cache", nil + case "darwin": + return c + "/" + projectPath(), nil + } + return "", errors.New("could not determine location for Cache()") +} + +func Config() (string, error) { + if len(projectNameShort) < 1 || len(projectNameReverse) < 1 || + len(projectNameProject) < 1 || len(projectNameProject) < 1 { + return "", errors.New("to use the directories/project package, you must call project.SetProjectName() with all four arguments set") + } + c, e := base.Config() + if e != nil { + return "", e + } + switch runtime.GOOS { + case "linux": + return c + "/" + projectPath(), nil + case "windows": + return c + "\\" + projectPath() + "\\config", nil + case "darwin": + return c + "/" + projectPath(), nil + } + return "", errors.New("could not determine location for Config()") +} + +func Data() (string, error) { + if len(projectNameShort) < 1 || len(projectNameReverse) < 1 || + len(projectNameProject) < 1 || len(projectNameProject) < 1 { + return "", errors.New("to use the directories/project package, you must call project.SetProjectName() with all four arguments set") + } + c, e := base.Data() + if e != nil { + return "", e + } + switch runtime.GOOS { + case "linux": + return c + "/" + projectPath(), nil + case "windows": + return c + "\\" + projectPath() + "\\data", nil + case "darwin": + return c + "/" + projectPath(), nil + } + return "", errors.New("could not determine location for Data()") +} + +func DataLocal() (string, error) { + if len(projectNameShort) < 1 || len(projectNameReverse) < 1 || + len(projectNameProject) < 1 || len(projectNameProject) < 1 { + return "", errors.New("to use the directories/project package, you must call project.SetProjectName() with all four arguments set") + } + c, e := base.DataLocal() + if e != nil { + return "", e + } + switch runtime.GOOS { + case "linux": + return c + "/" + projectPath(), nil + case "windows": + return c + "\\" + projectPath() + "\\data", nil + case "darwin": + return c + "/" + projectPath(), nil + } + return "", errors.New("could not determine location for DataLocal()") +} +func Preferences() (string, error) { + if len(projectNameShort) < 1 || len(projectNameReverse) < 1 || + len(projectNameProject) < 1 || len(projectNameProject) < 1 { + return "", errors.New("to use the directories/project package, you must call project.SetProjectName() with all four arguments set") + } + c, e := base.Preferences() + if e != nil { + return "", e + } + switch runtime.GOOS { + case "linux": + return c + "/" + projectPath(), nil + case "windows": + return c + "\\" + projectPath() + "\\config", nil + case "darwin": + return c + "/" + projectPath(), nil + } + return "", errors.New("could not determine location for Preferences()") +} diff --git a/user/user.go b/user/user.go new file mode 100644 index 0000000..51994f9 --- /dev/null +++ b/user/user.go @@ -0,0 +1,170 @@ +package user + +import ( + "errors" + "os" + "runtime" + + "golang.org/x/sys/windows" + + "git.martyn.berlin/martyn/golang-directories/base" +) + +func Home() (string, error) { + return base.Home() +} + +func Audio() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_MUSIC_DIR") + if ok { + return e, nil + } + case "windows": + path, err := windows.KnownFolderPath(windows.FOLDERID_Music, 0) + return path, err + case "darwin": + h, err := Home() + return h + "/Music", err + } + return "", errors.New("could not determine location for Audio()") +} + +func Desktop() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_DESKTOP_DIR") + if ok { + return e, nil + } + case "windows": + path, err := windows.KnownFolderPath(windows.FOLDERID_Desktop, 0) + return path, err + case "darwin": + h, err := Home() + return h + "/Desktop", err + } + return "", errors.New("could not determine location for Desktop()") +} + +func Documents() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_DOCUMENTS_DIR") + if ok { + return e, nil + } + case "windows": + path, err := windows.KnownFolderPath(windows.FOLDERID_Documents, 0) + return path, err + case "darwin": + h, err := Home() + return h + "/Documents", err + } + return "", errors.New("could not determine location for Documents()") +} + +func Downloads() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_DOWNLOAD_DIR") + if ok { + return e, nil + } + case "windows": + path, err := windows.KnownFolderPath(windows.FOLDERID_Downloads, 0) + return path, err + case "darwin": + h, err := Home() + return h + "/Downloads", err + } + return "", errors.New("could not determine location for Downloads()") +} + +func Fonts() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_DATA_HOME" + "/fonts") + if ok { + return e, nil + } else { + h, err := Home() + return h + "/.local/share/fonts", err + } + case "windows": + return "", errors.New("windows has no per-user fonts dir") + case "darwin": + h, err := Home() + return h + "/Library/Fonts", err + } + return "", errors.New("could not determine location for Fonts()") +} + +func Pictures() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_PICTURES_DIR") + if ok { + return e, nil + } + case "windows": + path, err := windows.KnownFolderPath(windows.FOLDERID_Pictures, 0) + return path, err + case "darwin": + h, err := Home() + return h + "/Pictures", err + } + return "", errors.New("could not determine location for Pictures()") +} + +func Public() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_PUBLICSHARE_DIR") + if ok { + return e, nil + } + case "windows": + path, err := windows.KnownFolderPath(windows.FOLDERID_Public, 0) + return path, err + case "darwin": + h, err := Home() + return h + "/Public", err + } + return "", errors.New("could not determine location for Public()") +} + +func Templates() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_TEMPLATES_DIR") + if ok { + return e, nil + } + case "windows": + path, err := windows.KnownFolderPath(windows.FOLDERID_Templates, 0) + return path, err + case "darwin": + h, err := Home() + return h + "/Templates", err + } + return "", errors.New("could not determine location for Templates()") +} + +func Videos() (string, error) { + switch runtime.GOOS { + case "linux": + e, ok := os.LookupEnv("XDG_VIDEOS_DIR") + if ok { + return e, nil + } + case "windows": + path, err := windows.KnownFolderPath(windows.FOLDERID_Videos, 0) + return path, err + case "darwin": + h, err := Home() + return h + "/Videos", err + } + return "", errors.New("could not determine location for Videos()") +}