aboutsummaryrefslogtreecommitdiff
path: root/pkg/prompt
diff options
context:
space:
mode:
authorStefan Majewsky <majewsky@gmx.net>2020-03-28 13:53:10 +0100
committerStefan Majewsky <majewsky@gmx.net>2020-03-28 13:53:10 +0100
commited2b9374599cc00467b1c27121318748cc0d3f49 (patch)
tree65e3200a0b69817b24ae772223d1d852a52458af /pkg/prompt
parent1ff86053ddef8de3247909434e0bd7000c060f2a (diff)
downloadgofu-ed2b9374599cc00467b1c27121318748cc0d3f49.tar.gz
rename pkg/ to internal/
Diffstat (limited to 'pkg/prompt')
-rw-r--r--pkg/prompt/cloud.go83
-rw-r--r--pkg/prompt/git.go138
-rw-r--r--pkg/prompt/login.go66
-rw-r--r--pkg/prompt/main.go123
-rw-r--r--pkg/prompt/misc.go43
-rw-r--r--pkg/prompt/pwd.go157
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")
-}