Введение
Сегодня мы рассмотрим небольшую, очень полезную библиотекуgo-homedir. Как подсказывает название,go-homedirИспользуется для получения домашнего каталога пользователя.
На самом деле, используя стандартную библиотекуos/userМы также можем получить эту информацию:
package main
import (
"fmt"
"log"
"os/user"
)
func main() {
u, err := user.Current()
if err != nil {
log.Fatal(err)
}
fmt.Println("Home dir:", u.HomeDir)
}
Так почему дажеgo-homedirбиблиотека?
В системах Darwin стандартная библиотекаos/userиспользование требует cgo. Итак, любое использованиеos/userКод не может быть кросс-компилирован.
Однако большинство людей используютos/userЦель состоит в том, чтобы просто получить домашний каталог. следовательно,go-homedirПоявилась библиотека.
быстрый в использовании
go-homedirЭто сторонний пакет, который необходимо установить перед использованием:
$ go get github.com/mitchellh/go-homedir
Его очень просто использовать:
package main
import (
"fmt"
"log"
"github.com/mitchellh/go-homedir"
)
func main() {
dir, err := homedir.Dir()
if err != nil {
log.Fatal(err)
}
fmt.Println("Home dir:", dir)
dir = "~/golang/src"
expandedDir, err := homedir.Expand(dir)
if err != nil {
log.Fatal(err)
}
fmt.Printf("Expand of %s is: %s\n", dir, expandedDir)
}
go-homedirЕсть две функции:
-
Dir: получить домашний каталог пользователя; -
Expand: поставить первый в пути~Расширяется до домашнего каталога пользователя.
Расширенное использование
потому чтоDirВызов может включать некоторые системные вызовы и внешние команды выполнения, а несколько вызовов могут стоить производительности. такgo-homedirОбеспечивает функцию кэширования. По умолчанию кэширование включено.
Мы также можем поставитьDisableCacheУстановить какfalseчтобы закрыть его.
package main
import (
"fmt"
"log"
"github.com/mitchellh/go-homedir"
)
func main() {
homedir.DisableCache = false
dir, err := homedir.Dir()
if err != nil {
log.Fatal(err)
}
fmt.Println("Home dir:", dir)
}
При использовании кеша, если домашний каталог изменяется во время работы программы, вызовите его сноваDirИли вернуться в предыдущий каталог. Если вам нужно получить последний домашний каталог, вы можете сначала позвонитьResetочистить кэш.
выполнить
go-homedirИсходный код - это только один файлhomedir.go, посмотрим сегодняDirРеализация, удаление кода, связанного с кешем:
func Dir() (string, error) {
var result string
var err error
if runtime.GOOS == "windows" {
result, err = dirWindows()
} else {
// Unix-like system, so just assume Unix
result, err = dirUnix()
}
if err != nil {
return "", err
}
return result, nil
}
Определить, является ли текущая системаwindowsИли Unix-подобный вызов различных методов соответственно. Сначала взгляните на окна, это относительно просто:
func dirWindows() (string, error) {
// First prefer the HOME environmental variable
if home := os.Getenv("HOME"); home != "" {
return home, nil
}
// Prefer standard environment variable USERPROFILE
if home := os.Getenv("USERPROFILE"); home != "" {
return home, nil
}
drive := os.Getenv("HOMEDRIVE")
path := os.Getenv("HOMEPATH")
home := drive + path
if drive == "" || path == "" {
return "", errors.New("HOMEDRIVE, HOMEPATH, or USERPROFILE are blank")
}
return home, nil
}
Процесс выглядит следующим образом:
- читать переменные окружения
HOME, если не пусто, вернуть это значение; - читать переменные окружения
USERPROFILE, если не пусто, вернуть это значение; - читать переменные окружения
HOMEDRIVEа такжеHOMEPATH, если ни одно из них не пусто, объедините два значения и вернитесь.
Реализация на Unix-подобных системах немного сложнее:
func dirUnix() (string, error) {
homeEnv := "HOME"
if runtime.GOOS == "plan9" {
// On plan9, env vars are lowercase.
homeEnv = "home"
}
// First prefer the HOME environmental variable
if home := os.Getenv(homeEnv); home != "" {
return home, nil
}
var stdout bytes.Buffer
// If that fails, try OS specific commands
if runtime.GOOS == "darwin" {
cmd := exec.Command("sh", "-c", `dscl -q . -read /Users/"$(whoami)" NFSHomeDirectory | sed 's/^[^ ]*: //'`)
cmd.Stdout = &stdout
if err := cmd.Run(); err == nil {
result := strings.TrimSpace(stdout.String())
if result != "" {
return result, nil
}
}
} else {
cmd := exec.Command("getent", "passwd", strconv.Itoa(os.Getuid()))
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
// If the error is ErrNotFound, we ignore it. Otherwise, return it.
if err != exec.ErrNotFound {
return "", err
}
} else {
if passwd := strings.TrimSpace(stdout.String()); passwd != "" {
// username:password:uid:gid:gecos:home:shell
passwdParts := strings.SplitN(passwd, ":", 7)
if len(passwdParts) > 5 {
return passwdParts[5], nil
}
}
}
}
// If all else fails, try the shell
stdout.Reset()
cmd := exec.Command("sh", "-c", "cd && pwd")
cmd.Stdout = &stdout
if err := cmd.Run(); err != nil {
return "", err
}
result := strings.TrimSpace(stdout.String())
if result == "" {
return "", errors.New("blank output when reading home directory")
}
return result, nil
}
Процесс выглядит следующим образом:
- Сначала прочитайте переменные среды
HOME(Обратите внимание, что в системах plan9 этоhome), если не пусто, вернуть это значение; - использовать
getnetкоманда для просмотра соответствующих записей в базе данных системы, мы знаемpasswdИнформация о пользователе хранится в файле, включая домашний каталог пользователя. использоватьgetentвид командыpasswdЗапись текущего пользователя в , а затем найдите часть домашнего каталога и верните ее; - Если предыдущий шаг не удался, мы знаем
cdПосле того, как параметры переключаются непосредственно на домашнюю директорию пользователя,pwdТекущий каталог может быть отображен. Затем вы можете объединить эти две команды, чтобы вернуться в домашний каталог.
Анализ исходного кода здесь не означает, что вы должны быть знакомы с его исходным кодом при использовании какой-либо библиотеки, ведь использование библиотеки делается для удобства разработки. Но исходный код — это очень важный для нас способ учиться и совершенствоваться. У нас также есть возможность найти причину из документации или даже исходного кода, когда мы сталкиваемся с проблемами с библиотекой.
Ссылаться на
- home-dirРепозиторий GitHub
я
Добро пожаловать, чтобы обратить внимание на мою общедоступную учетную запись WeChat [GoUpUp], учитесь вместе и добивайтесь прогресса вместе ~
Эта статья опубликована в блогеOpenWriteвыпускать!