Введение
Сегодня мы рассмотрим небольшую, очень полезную библиотеку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выпускать!