Copyright (c) 2024 Huawei Technologies Co., Ltd.
openFuyao is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
package utils
import (
"fmt"
"io"
"log"
"os"
"path/filepath"
"reflect"
"strconv"
"strings"
"sync"
)
var (
globalLogger *log.Logger
logWriter io.Writer
promptLogger *log.Logger
)
const (
DefaultCmdTimeoutSeconds = 10
FileModeOnlyOwnerReadWrite = 0600
FileModeOnlyOwnerReadExec = 0700
FileModeOwnerReadWriteExec = 0750
DirModeOwnerReadWriteExec = 0750
FileModeExecutable = 0111
NumBase10 = 10
NumBites64 = 64
logFlags = log.Ldate | log.Ltime | log.Lmicroseconds | log.Lmsgprefix
)
func init() {
logWriter = &syncWriter{Writer: os.Stderr}
globalLogger = GetLogger("")
promptLogger = GetLogger("Prompt")
}
func InitLogFile(logFilePath string) func() {
if len(logFilePath) == 0 {
return func() {}
}
baseDir := filepath.Dir(logFilePath)
if err := os.MkdirAll(baseDir, DirModeOwnerReadWriteExec); err != nil {
globalLogger.Printf("Failed to create log directory: %s, error: %s", baseDir, err.Error())
return func() {}
}
fullLogPath, err := filepath.Abs(logFilePath)
if err != nil {
globalLogger.Printf("Failed to get absolute path for log file: %s, error: %s", logFilePath, err.Error())
return func() {}
}
tmpWriter, err := os.OpenFile(fullLogPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, FileModeOnlyOwnerReadWrite)
if err != nil {
globalLogger.Printf("Failed to open log file: %s, error: %s", fullLogPath, err.Error())
return func() {}
}
syncWriter := &syncWriter{Writer: tmpWriter}
logWriter = syncWriter
globalLogger.SetOutput(syncWriter)
promptLogger = GetLogger("Prompt")
return func() {
CloseAll(globalLogger, tmpWriter)
}
}
type syncWriter struct {
logMutex sync.Mutex
io.Writer
}
func (w *syncWriter) Write(p []byte) (int, error) {
w.logMutex.Lock()
defer w.logMutex.Unlock()
return w.Writer.Write(p)
}
func ParseInt10Base(value string) (int64, error) {
if len(value) == 0 {
return 0, fmt.Errorf("value is empty")
}
value = strings.TrimSpace(value)
if len(value) == 0 {
return 0, fmt.Errorf("value is empty after trim")
}
intValue, err := strconv.ParseInt(value, NumBase10, NumBites64)
if err != nil {
return 0, fmt.Errorf("failed to parse value: %s, error: %s", value, err.Error())
}
return intValue, nil
}
func GetDefaultLogger() *log.Logger {
return GetLogger("")
}
func GetLogger(name string) *log.Logger {
if len(name) == 0 {
if globalLogger == nil {
globalLogger = log.New(logWriter, name, logFlags)
}
return globalLogger
} else {
return log.New(logWriter, fmt.Sprintf("[%s] ", name), logFlags)
}
}
func PromptMsg(format string, args ...any) {
if len(format) > 0 {
promptLogger.Printf(format, args...)
fmt.Printf(format+"\n", args...)
}
}
func CloseAll(logger *log.Logger, closers ...io.Closer) {
for _, closer := range closers {
if reflect.ValueOf(closer).IsNil() {
continue
}
err := closer.Close()
if err != nil && logger != nil {
logger.Printf("failed to close closer: %v", err)
}
}
}
func CreateFile(path string, mode os.FileMode, createParentDir bool) (*os.File, error) {
if createParentDir {
if err := os.MkdirAll(filepath.Dir(path), DirModeOwnerReadWriteExec); err != nil {
return nil, fmt.Errorf("failed to create parent directory: %s, error: %s", filepath.Dir(path), err.Error())
}
}
if _, err := os.Stat(path); err == nil {
return nil, fmt.Errorf("file already exists: %s", path)
}
file, err := os.Create(path)
if err != nil {
return nil, err
}
err = file.Chmod(mode)
if err != nil {
CloseAll(nil, file)
return nil, err
}
return file, nil
}
func GetStartDir() string {
var startDir = "./"
execPath, err := os.Executable()
if err == nil {
startDir = filepath.Dir(execPath)
}
absStartDir, err := filepath.Abs(startDir)
if err == nil {
return absStartDir
}
return startDir
}