Compare commits
No commits in common. "0a5f44eca765b8cc4c626a6b00ca0c62d2c37f7d" and "7ca8158a1c55bc19ffa61a760bbb7719c16c607f" have entirely different histories.
0a5f44eca7
...
7ca8158a1c
|
@ -1,374 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// ppsep is used as the replacement for slashes in path
|
|
||||||
// ex: ~/bin => ~bin
|
|
||||||
// ex: ~/bin => home~bin
|
|
||||||
// ex: ~/.local/opt/foo/bin => ~.local»opt»foo»bin
|
|
||||||
// other patterns considered:
|
|
||||||
// ~/.local/opt/foo/bin => ~.local·opt·foo·bin
|
|
||||||
// ~/.local/opt/foo/bin => home¬.local¬opt¬foo¬bin
|
|
||||||
// ~/.local/opt/foo/bin => home».local»opt»foo»bin
|
|
||||||
// ~/.local/opt/foo/bin => HOME•.local•opt•foo•bin
|
|
||||||
// ~/.local/opt/foo/bin => HOME_.local_opt_foo_bin
|
|
||||||
// ~/.local/opt/foo/bin => HOME·.local·opt·foo·bin
|
|
||||||
const ppsep = "-"
|
|
||||||
|
|
||||||
func usage() {
|
|
||||||
//fmt.Fprintf(os.Stderr, "Usage: envpath show|add|append|remove <path>\n")
|
|
||||||
fmt.Fprintf(os.Stderr, "Usage: envpath show|add|remove <path>\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
// TODO --system to add to the system PATH rather than the user PATH
|
|
||||||
|
|
||||||
// Usage:
|
|
||||||
if len(os.Args) < 2 {
|
|
||||||
usage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
action := os.Args[1]
|
|
||||||
|
|
||||||
paths := Paths()
|
|
||||||
|
|
||||||
if "show" == action {
|
|
||||||
if len(os.Args) > 2 {
|
|
||||||
usage()
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
for i := range paths {
|
|
||||||
fmt.Println("\t" + paths[i])
|
|
||||||
}
|
|
||||||
fmt.Println()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(os.Args) < 3 {
|
|
||||||
usage()
|
|
||||||
os.Exit(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
pathentry := os.Args[2]
|
|
||||||
if "remove" != action {
|
|
||||||
stat, err := os.Stat(pathentry)
|
|
||||||
if nil != err {
|
|
||||||
// TODO --force
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
if !stat.IsDir() {
|
|
||||||
fmt.Fprintf(os.Stderr, "%q is not a directory (folder)\n", pathentry)
|
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
switch action {
|
|
||||||
default:
|
|
||||||
usage()
|
|
||||||
os.Exit(1)
|
|
||||||
/*
|
|
||||||
case "append":
|
|
||||||
newpath, _, err := addPath(pathentry, appendOrder)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println("New sessions will have " + pathentry + " in their PATH.")
|
|
||||||
fmt.Println("To update this session run\n")
|
|
||||||
//fmt.Println("\tsource", pathfile)
|
|
||||||
fmt.Printf(`%sexport PATH="$PATH:%s"%s`, "\t", newpath, "\n")
|
|
||||||
*/
|
|
||||||
case "add":
|
|
||||||
_, pathfile, err := addPath(pathentry, prependOrder)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println("\nRun this command (or open a new shell) to finish:\n")
|
|
||||||
fmt.Printf("\tsource %s\n\n", pathfile)
|
|
||||||
//fmt.Printf(`%sexport PATH="%s:$PATH"%s`, "\t", newpath, "\n\n")
|
|
||||||
case "remove":
|
|
||||||
msg, err := removePath(pathentry)
|
|
||||||
if nil != err {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
fmt.Println(msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Paths returns the slice of PATHs from the Environment
|
|
||||||
func Paths() []string {
|
|
||||||
// ":" on *nix
|
|
||||||
return strings.Split(os.Getenv("PATH"), string(os.PathListSeparator))
|
|
||||||
}
|
|
||||||
|
|
||||||
type setOrder bool
|
|
||||||
|
|
||||||
const prependOrder setOrder = true
|
|
||||||
const appendOrder setOrder = false
|
|
||||||
|
|
||||||
// returns newpath, error
|
|
||||||
func addPath(oldpathentry string, order setOrder) (string, string, error) {
|
|
||||||
home, err := os.UserHomeDir()
|
|
||||||
if nil != err {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
home = filepath.ToSlash(home)
|
|
||||||
|
|
||||||
pathentry, fname, err := normalizeEntryAndFile(home, oldpathentry)
|
|
||||||
if nil != err {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
envpathd := filepath.Join(home, ".config/envpath/path.d")
|
|
||||||
err = os.MkdirAll(envpathd, 0755)
|
|
||||||
if nil != err {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = initializeShells(home)
|
|
||||||
if nil != err {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes, err := ioutil.ReadDir(envpathd)
|
|
||||||
if nil != err {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var priority int
|
|
||||||
if prependOrder == order {
|
|
||||||
// Counter-intuitively later PATHs, prepended are placed earlier
|
|
||||||
priority, err = getOrder(nodes, pathentry, fname, envpathd, sortForward)
|
|
||||||
} else {
|
|
||||||
// Counter-intuitively earlier PATHs are placed later
|
|
||||||
priority, err = getOrder(nodes, pathentry, fname, envpathd, sortBackward)
|
|
||||||
}
|
|
||||||
if nil != err {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if index, ok := isInPath(home, pathentry); ok {
|
|
||||||
return "", "", fmt.Errorf(
|
|
||||||
"%q is in your PATH at position %d and must be removed manually to re-order\n",
|
|
||||||
pathentry,
|
|
||||||
index,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ex: 100-opt»foo»bin.sh
|
|
||||||
// ex: 105-home»bar»bin.sh
|
|
||||||
pathfile := fmt.Sprintf("%03d-%s", priority, fname)
|
|
||||||
|
|
||||||
fullname := filepath.Join(envpathd, pathfile)
|
|
||||||
export := []byte(fmt.Sprintf("# Generated for envpath. Do not edit.\nexport PATH=\"%s:$PATH\"\n", pathentry))
|
|
||||||
err = ioutil.WriteFile(fullname, export, 0755)
|
|
||||||
if nil != err {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
// If we change from having the user source the path directory
|
|
||||||
// then we should uncomment this so the user knows where the path files are
|
|
||||||
//fmt.Printf("Wrote %s\n", fullname)
|
|
||||||
|
|
||||||
return pathentry, fullname, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func removePath(oldpathentry string) (string, error) {
|
|
||||||
home, err := os.UserHomeDir()
|
|
||||||
if nil != err {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
home = filepath.ToSlash(home)
|
|
||||||
|
|
||||||
pathentry, fname, err := normalizeEntryAndFile(home, oldpathentry)
|
|
||||||
if nil != err {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
envpathd := filepath.Join(home, ".config/envpath/path.d")
|
|
||||||
err = os.MkdirAll(envpathd, 0755)
|
|
||||||
if nil != err {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
nodes, err := ioutil.ReadDir(envpathd)
|
|
||||||
if nil != err {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
var fullname string
|
|
||||||
for i := range nodes {
|
|
||||||
node := nodes[i]
|
|
||||||
// 000-foo-bin.sh vs foo-bin.sh
|
|
||||||
if strings.HasSuffix(node.Name(), "-"+fname) {
|
|
||||||
if len(strings.Split(node.Name(), "-"))-1 == len(strings.Split(fname, "-")) {
|
|
||||||
fullname = node.Name()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
paths := Paths()
|
|
||||||
index, exists := isInPath(home, pathentry)
|
|
||||||
|
|
||||||
if "" == fullname {
|
|
||||||
if exists {
|
|
||||||
return "", fmt.Errorf("%q is in your PATH, but is NOT managed by envpath", pathentry)
|
|
||||||
}
|
|
||||||
return "", fmt.Errorf("%q is NOT in your PATH, and NOT managed by envpath", pathentry)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = os.Remove(filepath.Join(envpathd, fullname))
|
|
||||||
if nil != err {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !exists {
|
|
||||||
return fmt.Sprintf("Removed %s", filepath.Join(envpathd, fullname)), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
newpaths := []string{}
|
|
||||||
for i := range paths {
|
|
||||||
if i == index {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
newpaths = append(newpaths, paths[i])
|
|
||||||
}
|
|
||||||
return fmt.Sprintf(
|
|
||||||
"Removed %s. To update the current shell re-export the new PATH:\n\n"+
|
|
||||||
"\texport PATH=%q\n",
|
|
||||||
fullname,
|
|
||||||
strings.Join(newpaths, ":"),
|
|
||||||
), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func isInPath(home, pathentry string) (int, bool) {
|
|
||||||
paths := Paths()
|
|
||||||
|
|
||||||
index := -1
|
|
||||||
for i := range paths {
|
|
||||||
entry, _ := normalizePathEntry(home, paths[i])
|
|
||||||
if pathentry == entry {
|
|
||||||
index = i
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if index >= 0 {
|
|
||||||
return index, true
|
|
||||||
}
|
|
||||||
return -1, false
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizeEntryAndFile(home, pathentry string) (string, string, error) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
pathentry, err = normalizePathEntry(home, pathentry)
|
|
||||||
if nil != err {
|
|
||||||
return "", "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we split and rejoin the paths as a unique name
|
|
||||||
// ex: /opt/foo/bin/ => opt/foo/bin => [opt foo bin]
|
|
||||||
// ex: ~/bar/bin/ => bar/bin => [bar bin]
|
|
||||||
names := strings.Split(strings.Trim(filepath.ToSlash(pathentry), "/"), "/")
|
|
||||||
if strings.HasPrefix(pathentry, "$HOME/") {
|
|
||||||
// ~/bar/bin/ => [home bar bin]
|
|
||||||
names[0] = "home"
|
|
||||||
}
|
|
||||||
|
|
||||||
// ex: /opt/foo/bin/ => opt»foo»bin.sh
|
|
||||||
fname := strings.Join(names, ppsep) + ".sh"
|
|
||||||
|
|
||||||
return pathentry, fname, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func normalizePathEntry(home, pathentry string) (string, error) {
|
|
||||||
var err error
|
|
||||||
|
|
||||||
// We add the slashes so that we don't get false matches
|
|
||||||
// ex: foo should match foo/bar, but should NOT match foobar
|
|
||||||
home, err = filepath.Abs(home)
|
|
||||||
if nil != err {
|
|
||||||
// I'm not sure how it's possible to get an error with Abs...
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
home += "/"
|
|
||||||
pathentry, err = filepath.Abs(pathentry)
|
|
||||||
if nil != err {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
pathentry += "/"
|
|
||||||
|
|
||||||
// Next we make the path relative to / or ~/
|
|
||||||
// ex: /Users/me/.local/bin/ => .local/bin/
|
|
||||||
if strings.HasPrefix(pathentry, home) {
|
|
||||||
pathentry = "$HOME/" + strings.TrimPrefix(pathentry, home)
|
|
||||||
}
|
|
||||||
|
|
||||||
return pathentry, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortForward(priority, n int) int {
|
|
||||||
// Pick a number such that 99 > newpriority > priority
|
|
||||||
if n >= priority {
|
|
||||||
m := n % 5
|
|
||||||
if 0 == m {
|
|
||||||
priority += 5
|
|
||||||
} else {
|
|
||||||
priority += (5 - m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return priority
|
|
||||||
}
|
|
||||||
|
|
||||||
func sortBackward(priority, n int) int {
|
|
||||||
// Pick a number such that 0 < newpriority < priority
|
|
||||||
if n <= priority {
|
|
||||||
m := n % 5
|
|
||||||
if 0 == m {
|
|
||||||
m = 5
|
|
||||||
}
|
|
||||||
priority -= m
|
|
||||||
}
|
|
||||||
|
|
||||||
return priority
|
|
||||||
}
|
|
||||||
|
|
||||||
type sorter = func(int, int) int
|
|
||||||
|
|
||||||
func getOrder(nodes []os.FileInfo, pathentry, fname, envpathd string, fn sorter) (int, error) {
|
|
||||||
// assuming people will append more often than prepend
|
|
||||||
// default the priority to less than halfway
|
|
||||||
priority := 100
|
|
||||||
for i := range nodes {
|
|
||||||
f := nodes[i]
|
|
||||||
name := f.Name()
|
|
||||||
if !strings.HasSuffix(name, ".sh") {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if strings.HasSuffix(name, "-"+fname) {
|
|
||||||
return 0, fmt.Errorf(
|
|
||||||
"Error: %s already exports %s",
|
|
||||||
filepath.Join("~/.config/envpath/path.d", f.Name()),
|
|
||||||
pathentry,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
n, err := strconv.Atoi(strings.Split(name, "-")[0])
|
|
||||||
if nil != err {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
priority = fn(priority, n)
|
|
||||||
}
|
|
||||||
|
|
||||||
return priority, nil
|
|
||||||
}
|
|
|
@ -1,248 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"runtime"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
type envConfig struct {
|
|
||||||
shell string
|
|
||||||
shellDesc string
|
|
||||||
home string
|
|
||||||
rcFile string
|
|
||||||
rcScript string
|
|
||||||
loadFile string
|
|
||||||
loadScript string
|
|
||||||
}
|
|
||||||
|
|
||||||
var confs []*envConfig
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
home, err := os.UserHomeDir()
|
|
||||||
if nil != err {
|
|
||||||
panic(err) // Must get home directory
|
|
||||||
}
|
|
||||||
home = filepath.ToSlash(home)
|
|
||||||
|
|
||||||
confs = []*envConfig{
|
|
||||||
&envConfig{
|
|
||||||
home: home,
|
|
||||||
shell: "bash",
|
|
||||||
shellDesc: "bourne-compatible shell (bash)",
|
|
||||||
rcFile: ".bashrc",
|
|
||||||
rcScript: "[ -s \"$HOME/.config/envpath/load.sh\" ] && source \"$HOME/.config/envpath/load.sh\"\n",
|
|
||||||
loadFile: ".config/envpath/load.sh",
|
|
||||||
loadScript: "for x in ~/.config/envpath/path.d/*.sh; do\n\tsource \"$x\"\ndone\n",
|
|
||||||
},
|
|
||||||
&envConfig{
|
|
||||||
home: home,
|
|
||||||
shell: "zsh",
|
|
||||||
shellDesc: "bourne-compatible shell (zsh)",
|
|
||||||
rcFile: ".zshrc",
|
|
||||||
rcScript: "[ -s \"$HOME/.config/envpath/load.sh\" ] && source \"$HOME/.config/envpath/load.sh\"\n",
|
|
||||||
loadFile: ".config/envpath/load.sh",
|
|
||||||
loadScript: "for x in ~/.config/envpath/path.d/*.sh; do\n\tsource \"$x\"\ndone\n",
|
|
||||||
},
|
|
||||||
&envConfig{
|
|
||||||
home: home,
|
|
||||||
shell: "fish",
|
|
||||||
shellDesc: "fish shell",
|
|
||||||
rcFile: ".config/fish/config.fish",
|
|
||||||
rcScript: "test -s \"$HOME/.config/envpath/load.fish\"; and source \"$HOME/.config/envpath/load.fish\"\n",
|
|
||||||
loadFile: ".config/envpath/load.fish",
|
|
||||||
loadScript: "for x in ~/.config/envpath/path.d/*.sh\n\tsource \"$x\"\nend\n",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func initializeShells(home string) error {
|
|
||||||
var hasRC bool
|
|
||||||
var nativeMatch *envConfig
|
|
||||||
for i := range confs {
|
|
||||||
c := confs[i]
|
|
||||||
|
|
||||||
if os.Getenv("SHELL") == c.shell {
|
|
||||||
nativeMatch = c
|
|
||||||
}
|
|
||||||
|
|
||||||
_, err := os.Stat(filepath.Join(home, c.rcFile))
|
|
||||||
if nil != err {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
hasRC = true
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure rc
|
|
||||||
if !hasRC {
|
|
||||||
if nil == nativeMatch {
|
|
||||||
return fmt.Errorf(
|
|
||||||
"%q is not a recognized shell and found none of .bashrc, .zshrc, .config/fish/config.fish",
|
|
||||||
os.Getenv("SHELL"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// touch the rc file
|
|
||||||
f, err := os.OpenFile(filepath.Join(home, nativeMatch.rcFile), os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := f.Close(); nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MacOS is special. It *requires* .bash_profile in order to read .bashrc
|
|
||||||
if "darwin" == runtime.GOOS && "bash" == os.Getenv("SHELL") {
|
|
||||||
if err := ensureBashProfile(home); nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Bash (sh, dash, zsh, ksh)
|
|
||||||
//
|
|
||||||
// http://www.joshstaiger.org/archives/2005/07/bash_profile_vs.html
|
|
||||||
for i := range confs {
|
|
||||||
c := confs[i]
|
|
||||||
err := c.maybeInitializeShell()
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *envConfig) maybeInitializeShell() error {
|
|
||||||
if _, err := os.Stat(filepath.Join(c.home, c.rcFile)); nil != err {
|
|
||||||
if !os.IsNotExist(err) {
|
|
||||||
fmt.Fprintf(os.Stderr, "%s\n", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
changed, err := c.initializeShell()
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if changed {
|
|
||||||
fmt.Printf(
|
|
||||||
"Detected %s shell and updated ~/%s\n",
|
|
||||||
c.shellDesc,
|
|
||||||
strings.TrimPrefix(c.rcFile, c.home),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *envConfig) initializeShell() (bool, error) {
|
|
||||||
if err := c.ensurePathsLoader(); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current config
|
|
||||||
// ex: ~/.bashrc
|
|
||||||
// ex: ~/.config/fish/config.fish
|
|
||||||
b, err := ioutil.ReadFile(filepath.Join(c.home, c.rcFile))
|
|
||||||
if nil != err {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// For Windows, just in case
|
|
||||||
s := strings.Replace(string(b), "\r\n", "\n", -1)
|
|
||||||
|
|
||||||
// Looking to see if loader script has been added to rc file
|
|
||||||
lines := strings.Split(strings.TrimSpace(s), "\n")
|
|
||||||
for i := range lines {
|
|
||||||
line := lines[i]
|
|
||||||
if line == strings.TrimSpace(c.rcScript) {
|
|
||||||
// indicate that it was not neccesary to change the rc file
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Open rc file to append and write
|
|
||||||
f, err := os.OpenFile(filepath.Join(c.home, c.rcFile), os.O_APPEND|os.O_WRONLY, 0644)
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate our script
|
|
||||||
script := fmt.Sprintf("# Generated for envpath. Do not edit.\n%s\n", c.rcScript)
|
|
||||||
|
|
||||||
// If there's not a newline before our template,
|
|
||||||
// include it in the template. We want nice things.
|
|
||||||
n := len(lines)
|
|
||||||
if "" != strings.TrimSpace(lines[n-1]) {
|
|
||||||
script = "\n" + script
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write and close the rc file
|
|
||||||
if _, err := f.Write([]byte(script)); err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
if err := f.Close(); err != nil {
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// indicate that we have changed the rc file
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *envConfig) ensurePathsLoader() error {
|
|
||||||
loadFile := filepath.Join(c.home, c.loadFile)
|
|
||||||
|
|
||||||
if _, err := os.Stat(loadFile); nil != err {
|
|
||||||
// Write the loop file. For example:
|
|
||||||
// $HOME/.config/envpath/load.sh
|
|
||||||
// $HOME/.config/envpath/load.fish
|
|
||||||
// TODO maybe don't write every time
|
|
||||||
if err := ioutil.WriteFile(
|
|
||||||
loadFile,
|
|
||||||
[]byte(fmt.Sprintf("# Generated for envpath. Do not edit.\n%s\n", c.loadScript)),
|
|
||||||
os.FileMode(0755),
|
|
||||||
); nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("Created %s\n", "~/"+c.loadFile)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// I think this issue only affects darwin users with bash as the default shell
|
|
||||||
func ensureBashProfile(home string) error {
|
|
||||||
profileFile := filepath.Join(home, ".bash_profile")
|
|
||||||
|
|
||||||
// touch the profile file
|
|
||||||
f, err := os.OpenFile(profileFile, os.O_CREATE|os.O_WRONLY, 0644)
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := f.Close(); nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
b, err := ioutil.ReadFile(profileFile)
|
|
||||||
if !bytes.Contains(b, []byte(".bashrc")) {
|
|
||||||
f, err := os.OpenFile(profileFile, os.O_APPEND|os.O_WRONLY, 0644)
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
sourceBashRC := "[ -s \"$HOME/.bashrc\" ] && source \"$HOME/.bashrc\"\n"
|
|
||||||
b := []byte(fmt.Sprintf("# Generated for MacOS bash. Do not edit.\n%s\n", sourceBashRC))
|
|
||||||
_, err = f.Write(b)
|
|
||||||
if nil != err {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
fmt.Printf("Updated ~/.bash_profile to source ~/.bashrc\n")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
Loading…
Reference in New Issue