mirror of
https://codeberg.org/forgejo/forgejo.git
synced 2024-11-24 08:57:03 -05:00
145 lines
3.3 KiB
Go
145 lines
3.3 KiB
Go
// Copyright 2013 com authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License"): you may
|
|
// not use this file except in compliance with the License. You may obtain
|
|
// a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
package com
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"math"
|
|
"os"
|
|
"path"
|
|
)
|
|
|
|
// Storage unit constants.
|
|
const (
|
|
Byte = 1
|
|
KByte = Byte * 1024
|
|
MByte = KByte * 1024
|
|
GByte = MByte * 1024
|
|
TByte = GByte * 1024
|
|
PByte = TByte * 1024
|
|
EByte = PByte * 1024
|
|
)
|
|
|
|
func logn(n, b float64) float64 {
|
|
return math.Log(n) / math.Log(b)
|
|
}
|
|
|
|
func humanateBytes(s uint64, base float64, sizes []string) string {
|
|
if s < 10 {
|
|
return fmt.Sprintf("%dB", s)
|
|
}
|
|
e := math.Floor(logn(float64(s), base))
|
|
suffix := sizes[int(e)]
|
|
val := float64(s) / math.Pow(base, math.Floor(e))
|
|
f := "%.0f"
|
|
if val < 10 {
|
|
f = "%.1f"
|
|
}
|
|
|
|
return fmt.Sprintf(f+"%s", val, suffix)
|
|
}
|
|
|
|
// HumaneFileSize calculates the file size and generate user-friendly string.
|
|
func HumaneFileSize(s uint64) string {
|
|
sizes := []string{"B", "KB", "MB", "GB", "TB", "PB", "EB"}
|
|
return humanateBytes(s, 1024, sizes)
|
|
}
|
|
|
|
// FileMTime returns file modified time and possible error.
|
|
func FileMTime(file string) (int64, error) {
|
|
f, err := os.Stat(file)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return f.ModTime().Unix(), nil
|
|
}
|
|
|
|
// FileSize returns file size in bytes and possible error.
|
|
func FileSize(file string) (int64, error) {
|
|
f, err := os.Stat(file)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
return f.Size(), nil
|
|
}
|
|
|
|
// Copy copies file from source to target path.
|
|
func Copy(src, dest string) error {
|
|
// Gather file information to set back later.
|
|
si, err := os.Lstat(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Handle symbolic link.
|
|
if si.Mode()&os.ModeSymlink != 0 {
|
|
target, err := os.Readlink(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
// NOTE: os.Chmod and os.Chtimes don't recoganize symbolic link,
|
|
// which will lead "no such file or directory" error.
|
|
return os.Symlink(target, dest)
|
|
}
|
|
|
|
sr, err := os.Open(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer sr.Close()
|
|
|
|
dw, err := os.Create(dest)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer dw.Close()
|
|
|
|
if _, err = io.Copy(dw, sr); err != nil {
|
|
return err
|
|
}
|
|
|
|
// Set back file information.
|
|
if err = os.Chtimes(dest, si.ModTime(), si.ModTime()); err != nil {
|
|
return err
|
|
}
|
|
return os.Chmod(dest, si.Mode())
|
|
}
|
|
|
|
// WriteFile writes data to a file named by filename.
|
|
// If the file does not exist, WriteFile creates it
|
|
// and its upper level paths.
|
|
func WriteFile(filename string, data []byte) error {
|
|
os.MkdirAll(path.Dir(filename), os.ModePerm)
|
|
return ioutil.WriteFile(filename, data, 0655)
|
|
}
|
|
|
|
// IsFile returns true if given path is a file,
|
|
// or returns false when it's a directory or does not exist.
|
|
func IsFile(filePath string) bool {
|
|
f, e := os.Stat(filePath)
|
|
if e != nil {
|
|
return false
|
|
}
|
|
return !f.IsDir()
|
|
}
|
|
|
|
// IsExist checks whether a file or directory exists.
|
|
// It returns false when the file or directory does not exist.
|
|
func IsExist(path string) bool {
|
|
_, err := os.Stat(path)
|
|
return err == nil || os.IsExist(err)
|
|
}
|