diff options
| author | Stefan Majewsky <majewsky@gmx.net> | 2020-03-28 13:53:10 +0100 |
|---|---|---|
| committer | Stefan Majewsky <majewsky@gmx.net> | 2020-03-28 13:53:10 +0100 |
| commit | ed2b9374599cc00467b1c27121318748cc0d3f49 (patch) | |
| tree | 65e3200a0b69817b24ae772223d1d852a52458af /pkg/prompt | |
| parent | 1ff86053ddef8de3247909434e0bd7000c060f2a (diff) | |
| download | gofu-ed2b9374599cc00467b1c27121318748cc0d3f49.tar.gz | |
rename pkg/ to internal/
Diffstat (limited to 'pkg/prompt')
| -rw-r--r-- | pkg/prompt/cloud.go | 83 | ||||
| -rw-r--r-- | pkg/prompt/git.go | 138 | ||||
| -rw-r--r-- | pkg/prompt/login.go | 66 | ||||
| -rw-r--r-- | pkg/prompt/main.go | 123 | ||||
| -rw-r--r-- | pkg/prompt/misc.go | 43 | ||||
| -rw-r--r-- | pkg/prompt/pwd.go | 157 |
6 files changed, 0 insertions, 610 deletions
diff --git a/pkg/prompt/cloud.go b/pkg/prompt/cloud.go deleted file mode 100644 index 72bd6f9..0000000 --- a/pkg/prompt/cloud.go +++ /dev/null @@ -1,83 +0,0 @@ -/******************************************************************************* -* -* Copyright 2017 Stefan Majewsky <majewsky@gmx.net> -* -* This program is free software: you can redistribute it and/or modify it under -* the terms of the GNU General Public License as published by the Free Software -* Foundation, either version 3 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT ANY -* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -* A PARTICULAR PURPOSE. See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License along with -* this program. If not, see <http://www.gnu.org/licenses/>. -* -*******************************************************************************/ - -package prompt - -import ( - "io/ioutil" - "os" - "path/filepath" - "strings" - - yaml "gopkg.in/yaml.v2" -) - -func getKubernetesField() string { - configPaths := filepath.SplitList(os.Getenv("KUBECONFIG")) - - var context string - for _, configPath := range configPaths { - context = getKubernetesContext(configPath) - if context != "" { - break - } - } - if context == "" { - return "" - } - - namespaceBytes, err := ioutil.ReadFile(filepath.Join(os.Getenv("HOME"), ".kubectl-namespace")) - namespace := strings.TrimSpace(string(namespaceBytes)) - if err != nil { - if !os.IsNotExist(err) { - handleError(err) - } - namespace = "" - } - if namespace != "" { - context += "/" + namespace - } - - return withType("kube", context) -} - -func getKubernetesContext(configPath string) string { - buf, err := ioutil.ReadFile(configPath) - if err != nil { - //non-existence is acceptable, just make the caller continue with the next configPath - if !os.IsNotExist(err) { - handleError(err) - } - return "" - } - - var data struct { - CurrentContext string `yaml:"current-context"` - } - err = yaml.Unmarshal(buf, &data) - handleError(err) - return strings.TrimSpace(data.CurrentContext) -} - -func getOpenstackField() string { - cloudName := os.Getenv("CURRENT_OS_CLOUD") - if cloudName == "" { - return "" - } - return withType("cloud", cloudName) -} diff --git a/pkg/prompt/git.go b/pkg/prompt/git.go deleted file mode 100644 index 8393c3e..0000000 --- a/pkg/prompt/git.go +++ /dev/null @@ -1,138 +0,0 @@ -/******************************************************************************* -* -* Copyright 2017 Stefan Majewsky <majewsky@gmx.net> -* -* This program is free software: you can redistribute it and/or modify it under -* the terms of the GNU General Public License as published by the Free Software -* Foundation, either version 3 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT ANY -* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -* A PARTICULAR PURPOSE. See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License along with -* this program. If not, see <http://www.gnu.org/licenses/>. -* -*******************************************************************************/ - -package prompt - -import ( - "fmt" - "io/ioutil" - "os" - "path/filepath" - "strings" -) - -type gitRepo struct { - RootPath string - GitDir string -} - -//Returns two empty strings if `path` is not inside a Git repo. -func findRepo(path string) (*gitRepo, error) { - //find .git directory or file - gitEntry := filepath.Join(path, ".git") - fi, err := os.Stat(gitEntry) - switch { - case err == nil: - //found - continue below with further checks - case !os.IsNotExist(err): - return nil, err - case path == "/": - return nil, nil - default: - return findRepo(filepath.Dir(path)) - } - - //found .git - what is it? - if fi.Mode().IsDir() { - //normal case - .git is a directory - return &gitRepo{RootPath: path, GitDir: gitEntry}, nil - } - - //.git is a file (e.g. for submodules) - it contains a line like "gitdir: path/to/gitdir" - bytes, err := ioutil.ReadFile(gitEntry) - if err != nil { - return nil, err - } - for _, line := range strings.Split(string(bytes), "\n") { - line = strings.TrimSpace(line) - if strings.HasPrefix(line, "gitdir:") { - return &gitRepo{ - RootPath: path, - GitDir: filepath.Join(path, strings.TrimSpace(strings.TrimPrefix(line, "gitdir:"))), - }, nil - } - } - - return nil, fmt.Errorf("read %s: missing gitdir directive", gitEntry) -} - -func getRepoStatusField(repo *gitRepo) string { - if repo == nil { - return "" - } - - bytes, err := ioutil.ReadFile(filepath.Join(repo.GitDir, "HEAD")) - if err != nil { - handleError(err) - return withType("git", withColor("1;41", "unknown")) - } - refSpec := strings.TrimSpace(string(bytes)) - - //is current HEAD detached? - if !strings.HasPrefix(refSpec, "ref: refs/") { - return formatRepoStatusField(withColor("1;41", "detached"), refSpec) - } - - //current HEAD is a ref - refSpec = strings.TrimPrefix(refSpec, "ref: ") - refSpecDisplay := strings.TrimPrefix(refSpec, "refs/") - refSpecDisplay = strings.TrimPrefix(refSpecDisplay, "heads/") - - //read file corresponding to refspec to find commit ID - bytes, err = ioutil.ReadFile(filepath.Join(repo.GitDir, refSpec)) - commitID := strings.TrimSpace(string(bytes)) - if err != nil { - if os.IsNotExist(err) { - commitID = tryReadFromPackedRefs(repo, refSpec) - if commitID == "" { - commitID = withColor("37", "blank") - } - } else { - handleError(err) - commitID = withColor("1;41", "unknown") - } - } - - return formatRepoStatusField(refSpecDisplay, commitID) -} - -func tryReadFromPackedRefs(repo *gitRepo, refSpec string) string { - bytes, err := ioutil.ReadFile(filepath.Join(repo.GitDir, "packed-refs")) - if err != nil { - return "" - } - for _, line := range strings.Split(string(bytes), "\n") { - line = strings.TrimSpace(line) - if line == "" || strings.HasPrefix(line, "#") { - continue - } - fields := strings.Fields(line) - if len(fields) == 2 && fields[1] == refSpec { - return fields[0] - } - } - return "" -} - -func formatRepoStatusField(refSpec, commitID string) string { - //shorten plain commit IDs from 40 to 10 bytes - if len(commitID) == 40 && !strings.Contains(commitID, "\x1B") { - commitID = commitID[0:10] - } - return withType("git", refSpec+"/"+commitID) -} diff --git a/pkg/prompt/login.go b/pkg/prompt/login.go deleted file mode 100644 index 92cc270..0000000 --- a/pkg/prompt/login.go +++ /dev/null @@ -1,66 +0,0 @@ -/******************************************************************************* -* -* Copyright 2017 Stefan Majewsky <majewsky@gmx.net> -* -* This program is free software: you can redistribute it and/or modify it under -* the terms of the GNU General Public License as published by the Free Software -* Foundation, either version 3 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT ANY -* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -* A PARTICULAR PURPOSE. See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License along with -* this program. If not, see <http://www.gnu.org/licenses/>. -* -*******************************************************************************/ - -package prompt - -import "os" - -//#include <sys/types.h> -//#include <pwd.h> -//#include <unistd.h> -import "C" - -func getLoginField() string { - var result string - - //show user name - userName := getUserName() - commonUser := getenvOrDefault("PRETTYPROMPT_COMMONUSER", "stefan") - if commonUser != userName { - color := "0" - if userName == "root" { - color = "1;41" - } - result = withColor(color, userName) + "@" - } - - //show hostname - hostname, err := os.Hostname() - if err != nil { - handleError(err) - hostname = "<unknown>" - } - return result + withColor( - getenvOrDefault("PRETTYPROMPT_HOSTCOLOR", "0;33"), - hostname, - ) -} - -func getUserName() string { - //try to find username via getpwuid(getuid()) - pw, err := C.getpwuid(C.getuid()) - if err == nil { - return C.GoString(pw.pw_name) - } - //fallback to $USER, if set - if name := os.Getenv("USER"); name != "" { - return name - } - handleError(err) - return "<unknown>" -} diff --git a/pkg/prompt/main.go b/pkg/prompt/main.go deleted file mode 100644 index 1fc60d9..0000000 --- a/pkg/prompt/main.go +++ /dev/null @@ -1,123 +0,0 @@ -/******************************************************************************* -* -* Copyright 2017 Stefan Majewsky <majewsky@gmx.net> -* -* This program is free software: you can redistribute it and/or modify it under -* the terms of the GNU General Public License as published by the Free Software -* Foundation, either version 3 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT ANY -* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -* A PARTICULAR PURPOSE. See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License along with -* this program. If not, see <http://www.gnu.org/licenses/>. -* -*******************************************************************************/ - -package prompt - -import ( - "fmt" - "os" - "strings" - - "golang.org/x/crypto/ssh/terminal" - - "github.com/majewsky/gofu/pkg/cli" -) - -//Exec executes the prettyprompt applet and returns an exit code (0 for -//success, >0 for error). -func Exec(args []string) int { - fields := []string{ - getLoginField(), - } - cwd := CurrentDirectory() - fields = appendUnlessEmpty(fields, getDirectoryField(cwd)) - fields = appendUnlessEmpty(fields, getDeletedMessageField(cwd)) - fields = appendUnlessEmpty(fields, getRepoStatusField(cwd.Repo)) - fields = appendUnlessEmpty(fields, getTerminalField()) - fields = appendUnlessEmpty(fields, getOpenstackField()) - fields = appendUnlessEmpty(fields, getKubernetesField()) - //this field should always be last - if len(args) > 0 { - fields = appendUnlessEmpty(fields, getExitCodeField(args[0])) - } - - line := strings.Join(fields, " ") - lineWidth := getPrintableLength(line) - - //add dashes to expand `line` to fill the terminal's width - termWidth, _, err := terminal.GetSize(0) - if err != nil { - termWidth = 80 - } - if termWidth > lineWidth { - line += " " - lineWidth++ - } - if termWidth > lineWidth { - dashes := make([]byte, termWidth-lineWidth) - for idx := range dashes { - dashes[idx] = '-' - } - line += withColor("1", string(dashes)) - } - - os.Stdout.Write([]byte(line + "\n")) - - //print second line: a letter identifying the shell, and the final "$ ") - shellIdent := "" - switch os.Getenv("PRETTYPROMPT_SHELL") { - case "zsh": - shellIdent = "Z" - case "bash": - shellIdent = "B" - } - os.Stdout.Write([]byte(shellIdent + "$ ")) - - return 0 -} - -func getenvOrDefault(key, defaultValue string) (value string) { - value = os.Getenv(key) - if value == "" { - value = defaultValue - } - return -} - -func appendUnlessEmpty(list []string, val string) []string { - if val == "" { - return list - } - return append(list, val) -} - -func handleError(err error) { - if err != nil { - os.Stderr.Write([]byte("\x1B[1;31mPrompt error: " + err.Error() + "\x1B[0m\n")) - } -} - -func getPrintableLength(text string) int { - return len(cli.AnsiColorCodeRx.ReplaceAllString(text, "")) -} - -//withColor adds ANSI escape sequences to the string to display it with a -//certain color. The color is given as the semicolon-separated list of -//arguments to the ANSI escape sequence SGR, e.g. "1;41" for bold with red -//background. -func withColor(color, text string) string { - if color == "0" { - return text - } - return fmt.Sprintf("\x1B[%sm%s\x1B[0m", color, text) -} - -//withType adds a type annotation with a standardized format to the text. -func withType(typeStr, text string) string { - return fmt.Sprintf("\x1B[37m%s:\x1B[0m%s", typeStr, text) -} diff --git a/pkg/prompt/misc.go b/pkg/prompt/misc.go deleted file mode 100644 index 124015a..0000000 --- a/pkg/prompt/misc.go +++ /dev/null @@ -1,43 +0,0 @@ -/******************************************************************************* -* -* Copyright 2017 Stefan Majewsky <majewsky@gmx.net> -* -* This program is free software: you can redistribute it and/or modify it under -* the terms of the GNU General Public License as published by the Free Software -* Foundation, either version 3 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT ANY -* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -* A PARTICULAR PURPOSE. See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License along with -* this program. If not, see <http://www.gnu.org/licenses/>. -* -*******************************************************************************/ - -package prompt - -import ( - "os" - "strconv" -) - -func getTerminalField() string { - termName := os.Getenv("TERM") - if termName == "xterm-256color" { - return "" - } - if termName == "" { - termName = withColor("1;41", "not set") - } - return withType("term", termName) -} - -func getExitCodeField(arg string) string { - exitCode, err := strconv.Atoi(arg) - if err == nil && exitCode > 0 { - return withColor("1;31", "exit:"+arg) - } - return "" -} diff --git a/pkg/prompt/pwd.go b/pkg/prompt/pwd.go deleted file mode 100644 index 1b93987..0000000 --- a/pkg/prompt/pwd.go +++ /dev/null @@ -1,157 +0,0 @@ -/******************************************************************************* -* -* Copyright 2017 Stefan Majewsky <majewsky@gmx.net> -* -* This program is free software: you can redistribute it and/or modify it under -* the terms of the GNU General Public License as published by the Free Software -* Foundation, either version 3 of the License, or (at your option) any later -* version. -* -* This program is distributed in the hope that it will be useful, but WITHOUT ANY -* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR -* A PARTICULAR PURPOSE. See the GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License along with -* this program. If not, see <http://www.gnu.org/licenses/>. -* -*******************************************************************************/ - -package prompt - -import ( - "os" - "path/filepath" - "strings" -) - -//Directory contains all data about a directory that the prompt needs. -type Directory struct { - Path string - DisplayPath string - InBuildTree bool - InRepoTree bool - Repo *gitRepo - NearestAccessiblePath string -} - -//CurrentDirectory prepares a Directory struct for the current working -//directory. -func CurrentDirectory() Directory { - cwd, err := os.Getwd() - if err != nil { - cwd = filepath.Clean(os.Getenv("PWD")) - } - return NewDirectory(cwd) -} - -//NewDirectory prepares a Directory struct for the given path. -func NewDirectory(path string) (dir Directory) { - dir.Path = path - dir.DisplayPath = path - - //check if path actually exists - dir.NearestAccessiblePath = findNearestAccessiblePath(dir.Path) - if dir.NearestAccessiblePath == dir.Path { - //marks that everything is okay existence-wise - dir.NearestAccessiblePath = "" - - //display tag if below /x/build - if buildPath := os.Getenv("BUILD_ROOT"); buildPath != "" { - rel, _ := filepath.Rel(buildPath, dir.DisplayPath) - if !strings.HasPrefix(rel, "..") && rel != "." { - dir.InBuildTree = true - dir.DisplayPath = filepath.Join("/", rel) - } - } - - //display tag if below /x/src - if gopath := os.Getenv("GOPATH"); gopath != "" { - repoPath := filepath.Join(gopath, "src") - rel, _ := filepath.Rel(repoPath, dir.DisplayPath) - if !strings.HasPrefix(rel, "..") && rel != "." { - dir.InRepoTree = true - dir.DisplayPath = rel - } - } - - //strip $HOME prefix if applicable and desirable - dir.stripHomeDirFromDisplay() - - //check if we are inside a Git repository - var err error - dir.Repo, err = findRepo(dir.Path) - handleError(err) - } - - return -} - -//This part can benefit from a "return" in the middle, so it's in a separate function. -func (dir *Directory) stripHomeDirFromDisplay() { - if !strings.HasPrefix(dir.DisplayPath, "/") { - return - } - - homePath := os.Getenv("HOME") - if homePath == "" { - return - } - - rel, _ := filepath.Rel(homePath, dir.DisplayPath) - if rel == "." { - //do not display an empty DisplayPath if tags are displayed - if dir.InBuildTree || dir.InRepoTree { - return - } - rel = "" - } - if !strings.HasPrefix(rel, "..") { - dir.DisplayPath = rel - } -} - -func findNearestAccessiblePath(path string) string { - _, err := os.Stat(path) - if err == nil { - return path - } - return findNearestAccessiblePath(filepath.Dir(path)) -} - -func getDirectoryField(dir Directory) string { - if dir.DisplayPath == "" { - return "" - } - - txt := withColor("1;36", dir.DisplayPath) - if dir.NearestAccessiblePath == "" { - //cwd accessible -> highlight path elements inside the repo (if any) - if dir.Repo != nil && dir.Repo.RootPath != dir.Path { - rel, _ := filepath.Rel(dir.Repo.RootPath, dir.Path) - if strings.HasSuffix(dir.DisplayPath, rel) { - base := strings.TrimSuffix(dir.DisplayPath, rel) - txt = withColor("0;36", base) + withColor("1;36", rel) - } - } - } else { - //cwd inaccessible -> highlight inaccessible path elements - rel, _ := filepath.Rel(dir.NearestAccessiblePath, dir.Path) - txt = withColor("1;36", dir.NearestAccessiblePath+"/") + withColor("1;31", rel) - } - - //apply tags - if dir.InRepoTree { - txt = withType("repo", txt) - } - if dir.InBuildTree { - txt = withType("build", txt) - } - return txt -} - -func getDeletedMessageField(dir Directory) string { - if dir.NearestAccessiblePath == "" { - return "" - } - return withColor("1;41", "cannot stat cwd") -} |
