Compare commits
34 Commits
Author | SHA1 | Date | |
---|---|---|---|
dd34bd7595 | |||
0b2540924b | |||
4a3e5818a1 | |||
6215b4e87f | |||
67d71f2eef | |||
cf8adf9059 | |||
1fe9bae942 | |||
7c0e31aec7 | |||
b6c6436cee | |||
f043233031 | |||
525c37d8e3 | |||
194898b8a0 | |||
a26b61975d | |||
e6ee7860b3 | |||
ac8c18e754 | |||
dd83b872db | |||
bbe979b97b | |||
18f289fe90 | |||
b5430036f9 | |||
574f36e64e | |||
85f15eee46 | |||
c97d758a6a | |||
7cad10126c | |||
33bc425e90 | |||
e85baa72f6 | |||
6019beffe5 | |||
f8094df331 | |||
be72ffec43 | |||
34e5061740 | |||
b244663a4d | |||
67744fd4a1 | |||
167f79ab24 | |||
72cc77ef77 | |||
e89429a93c |
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/cmd/
|
10
go.mod
10
go.mod
@ -1,11 +1,3 @@
|
||||
module git.tswf.io/incredible-go/incredible-go-core
|
||||
|
||||
go 1.22.0
|
||||
|
||||
//replace (
|
||||
// "git.tswf.io/incredible-go/incredible-go-core" lateswhict => "C:\Soft\intellij\workspaces\golang\go-workspace\library\incredible-go\incredible-go-core"
|
||||
//)
|
||||
//
|
||||
//require (
|
||||
// "git.tswf.io/incredible-go/incredible-go-core" latest
|
||||
//)
|
||||
go 1.20
|
@ -6,3 +6,10 @@ func NewArrayList[T any]() *ArrayList[T] {
|
||||
size: 0,
|
||||
}
|
||||
}
|
||||
|
||||
func NewArrayListWithContent[T any](content ...T) *ArrayList[T] {
|
||||
result := NewArrayList[T]()
|
||||
result.AddAllS(&content)
|
||||
|
||||
return result
|
||||
}
|
||||
|
20
pkg/collections/array_list/array_list_json.go
Normal file
20
pkg/collections/array_list/array_list_json.go
Normal file
@ -0,0 +1,20 @@
|
||||
package array_list
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func (a *ArrayList[T]) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(a.content[:a.size])
|
||||
}
|
||||
|
||||
func (a *ArrayList[T]) UnmarshalJSON(data []byte) error {
|
||||
var content []T
|
||||
if err := json.Unmarshal(data, &content); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.content = content
|
||||
a.size = len(content)
|
||||
return nil
|
||||
}
|
@ -3,6 +3,9 @@ package array_list
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
|
||||
"git.tswf.io/incredible-go/incredible-go-core/pkg/container/optional"
|
||||
)
|
||||
|
||||
func (self *ArrayList[T]) Add(element T) {
|
||||
@ -15,21 +18,42 @@ func (self *ArrayList[T]) Add(element T) {
|
||||
self.size++
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) RemoveIf(filter func(T) bool) {
|
||||
index := 0
|
||||
for {
|
||||
if index >= self.size {
|
||||
break
|
||||
}
|
||||
|
||||
element := self.content[index]
|
||||
shouldRemove := filter(element)
|
||||
|
||||
if shouldRemove {
|
||||
self.RemoveByIndex(index)
|
||||
} else {
|
||||
index++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) Remove(element T) {
|
||||
indexFromMove := -1
|
||||
for index, value := range self.content {
|
||||
|
||||
if any(value) == any(element) {
|
||||
indexFromMove = index + 1
|
||||
indexFromMove = index
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
self.RemoveByIndex(indexFromMove)
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) RemoveByIndex(index int) {
|
||||
contentSize := len(self.content)
|
||||
|
||||
if indexFromMove >= 0 {
|
||||
|
||||
for i := indexFromMove; i < contentSize; i++ {
|
||||
if index >= 0 {
|
||||
for i := index + 1; i < contentSize; i++ {
|
||||
self.content[i-1] = self.content[i]
|
||||
}
|
||||
|
||||
@ -77,6 +101,22 @@ func (self *ArrayList[T]) AddAll(list *ArrayList[T]) {
|
||||
})
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) AddAllS(slice *[]T) {
|
||||
for _, v := range *slice {
|
||||
self.Add(v)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) SetAll(list *ArrayList[T]) {
|
||||
self.Clear()
|
||||
self.AddAll(list)
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) SetAllS(list *[]T) {
|
||||
self.Clear()
|
||||
self.AddAllS(list)
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) Any(test func(T) bool) bool {
|
||||
for index, value := range self.content {
|
||||
if index >= self.size {
|
||||
@ -127,3 +167,67 @@ func (self *ArrayList[T]) IsEmpty() bool {
|
||||
func (self *ArrayList[T]) String() string {
|
||||
return fmt.Sprintf("%v", self.content)
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) Clear() {
|
||||
self.content = self.content[:0]
|
||||
self.size = 0
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) GetLast() T {
|
||||
if self.IsEmpty() {
|
||||
panic(any(errors.New("trying to get last element from empty array list")))
|
||||
}
|
||||
|
||||
return self.Get(self.Size() - 1)
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) GetFirst() T {
|
||||
if self.IsEmpty() {
|
||||
panic(any(errors.New("trying to get first element from empty array list")))
|
||||
}
|
||||
|
||||
return self.Get(0)
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) ToSlice() []T {
|
||||
result := slices.Clone(self.content)[:self.size]
|
||||
return result
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) ToSliceUnsafe() []T {
|
||||
return self.content[:self.size]
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) Find(filter func(T) bool) *optional.Optional[T] {
|
||||
for index, value := range self.content {
|
||||
if index >= self.size {
|
||||
break
|
||||
}
|
||||
|
||||
passed := filter(value)
|
||||
|
||||
if passed {
|
||||
return optional.OfAny(value)
|
||||
}
|
||||
}
|
||||
|
||||
return optional.Empty[T]()
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) Filter(filter func(T) bool) *ArrayList[T] {
|
||||
return self.FilterTo(filter, NewArrayList[T]())
|
||||
}
|
||||
|
||||
func (self *ArrayList[T]) FilterTo(filter func(T) bool, resultList *ArrayList[T]) *ArrayList[T] {
|
||||
if resultList == nil {
|
||||
panic(fmt.Errorf("can not filter %v to nil list", self))
|
||||
}
|
||||
|
||||
self.ForEach(func(value T) {
|
||||
if filter(value) {
|
||||
resultList.Add(value)
|
||||
}
|
||||
})
|
||||
|
||||
return resultList
|
||||
}
|
||||
|
20
pkg/collections/array_list/array_list_xml.go
Normal file
20
pkg/collections/array_list/array_list_xml.go
Normal file
@ -0,0 +1,20 @@
|
||||
package array_list
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func (a *ArrayList[T]) MarshalXML() ([]byte, error) {
|
||||
return json.Marshal(a.content[:a.size])
|
||||
}
|
||||
|
||||
func (a *ArrayList[T]) UnmarshalXML(data []byte) error {
|
||||
var content []T
|
||||
if err := json.Unmarshal(data, &content); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.content = content
|
||||
a.size = len(content)
|
||||
return nil
|
||||
}
|
20
pkg/collections/array_list/array_list_yaml.go
Normal file
20
pkg/collections/array_list/array_list_yaml.go
Normal file
@ -0,0 +1,20 @@
|
||||
package array_list
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func (a *ArrayList[T]) MarshalYAML() ([]byte, error) {
|
||||
return json.Marshal(a.content[:a.size])
|
||||
}
|
||||
|
||||
func (a *ArrayList[T]) UnmarshalYAML(data []byte) error {
|
||||
var content []T
|
||||
if err := json.Unmarshal(data, &content); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a.content = content
|
||||
a.size = len(content)
|
||||
return nil
|
||||
}
|
6
pkg/container/optional/optional.go
Normal file
6
pkg/container/optional/optional.go
Normal file
@ -0,0 +1,6 @@
|
||||
package optional
|
||||
|
||||
type Optional[T any] struct {
|
||||
Present bool
|
||||
Value T
|
||||
}
|
23
pkg/container/optional/optional_factories.go
Normal file
23
pkg/container/optional/optional_factories.go
Normal file
@ -0,0 +1,23 @@
|
||||
package optional
|
||||
|
||||
func Empty[T any]() *Optional[T] {
|
||||
return &Optional[T]{
|
||||
Present: false,
|
||||
}
|
||||
}
|
||||
|
||||
func OfAny[T any](value T) *Optional[T] {
|
||||
return &Optional[T]{
|
||||
Present: true,
|
||||
Value: value,
|
||||
}
|
||||
}
|
||||
|
||||
func OfNonDefault[T comparable](value T) *Optional[T] {
|
||||
var defaultValue T
|
||||
if value != defaultValue {
|
||||
return Empty[T]()
|
||||
} else {
|
||||
return OfAny[T](value)
|
||||
}
|
||||
}
|
59
pkg/container/optional/optional_methods.go
Normal file
59
pkg/container/optional/optional_methods.go
Normal file
@ -0,0 +1,59 @@
|
||||
package optional
|
||||
|
||||
import "log"
|
||||
|
||||
func (self *Optional[T]) IfPresent(action func(T)) {
|
||||
if self.Present {
|
||||
action(self.Value)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Optional[T]) OrElsePanic(err error) T {
|
||||
return self.OrElsePanicF(func() error {
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Optional[T]) OrElsePanicF(errorSupplier func() error) T {
|
||||
if self.Present {
|
||||
return self.Value
|
||||
}
|
||||
|
||||
err := errorSupplier()
|
||||
panic(err)
|
||||
}
|
||||
|
||||
func (self *Optional[T]) OrElseFatal(err error) T {
|
||||
return self.OrElseFatalF(func() error {
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Optional[T]) OrElseFatalF(errorSupplier func() error) T {
|
||||
if self.Present {
|
||||
return self.Value
|
||||
}
|
||||
|
||||
err := errorSupplier()
|
||||
var returnStub T
|
||||
log.Fatal(err)
|
||||
|
||||
// Компилятор без return не пропустит, но сюда никогда не дойдет из-за фатала выше.
|
||||
return returnStub
|
||||
}
|
||||
|
||||
func (self *Optional[T]) OrElse(defaultValue T) T {
|
||||
if self.Present {
|
||||
return self.Value
|
||||
}
|
||||
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
func (self *Optional[T]) OrElseGet(defaultValueSupplier func() T) T {
|
||||
if self.Present {
|
||||
return self.Value
|
||||
}
|
||||
|
||||
return defaultValueSupplier()
|
||||
}
|
37
pkg/io/copy/progress/progress_listener.go
Normal file
37
pkg/io/copy/progress/progress_listener.go
Normal file
@ -0,0 +1,37 @@
|
||||
package progress
|
||||
|
||||
import "io"
|
||||
|
||||
type WriteProgressCallback func(uint64, uint64)
|
||||
|
||||
type WriteProgressListener struct {
|
||||
BytesWritten uint64
|
||||
ProgressCallback WriteProgressCallback
|
||||
}
|
||||
|
||||
func (self *WriteProgressListener) Write(p []byte) (int, error) {
|
||||
n := len(p)
|
||||
newTotal := self.BytesWritten + uint64(n)
|
||||
|
||||
if self.ProgressCallback != nil {
|
||||
self.ProgressCallback(self.BytesWritten, newTotal)
|
||||
}
|
||||
|
||||
self.BytesWritten = newTotal
|
||||
return n, nil
|
||||
}
|
||||
|
||||
func (self *WriteProgressListener) WrapReader(reader io.Reader) io.Reader {
|
||||
return io.TeeReader(reader, self)
|
||||
}
|
||||
|
||||
func NewProgressListener(callback WriteProgressCallback) *WriteProgressListener {
|
||||
return &WriteProgressListener{
|
||||
BytesWritten: 0,
|
||||
ProgressCallback: callback,
|
||||
}
|
||||
}
|
||||
|
||||
func WrapReader(reader io.Reader, callback WriteProgressCallback) io.Reader {
|
||||
return NewProgressListener(callback).WrapReader(reader)
|
||||
}
|
77
pkg/io/crypto/hasher/hasher.go
Normal file
77
pkg/io/crypto/hasher/hasher.go
Normal file
@ -0,0 +1,77 @@
|
||||
package hasher
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"hash"
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
type Hasher struct {
|
||||
HashSupplier func() hash.Hash
|
||||
}
|
||||
|
||||
func NewSha256Hasher() *Hasher {
|
||||
return NewHasher(func() hash.Hash {
|
||||
return sha256.New()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func NewMd5Hasher() *Hasher {
|
||||
return NewHasher(func() hash.Hash {
|
||||
return md5.New()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
func NewHasher(hashSupplier func() hash.Hash) *Hasher {
|
||||
return &Hasher{
|
||||
HashSupplier: hashSupplier,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *Hasher) GetFileHashString(fileLocation string) (string, error) {
|
||||
bytes, err := self.GetFileHashBytes(fileLocation)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return convertBytesToString(bytes), nil
|
||||
}
|
||||
|
||||
func (self *Hasher) GetFileHashBytes(fileLocation string) ([]byte, error) {
|
||||
file, err := os.Open(fileLocation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
return self.GetHashBytes(file)
|
||||
}
|
||||
|
||||
func (self *Hasher) GetHashString(reader io.Reader) (string, error) {
|
||||
bytes, err := self.GetHashBytes(reader)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return convertBytesToString(bytes), nil
|
||||
}
|
||||
|
||||
func (self *Hasher) GetHashBytes(reader io.Reader) ([]byte, error) {
|
||||
hasher := self.HashSupplier()
|
||||
_, err := io.Copy(hasher, reader)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return hasher.Sum(nil), nil
|
||||
}
|
||||
|
||||
func convertBytesToString(bytes []byte) string {
|
||||
return hex.EncodeToString(bytes)
|
||||
}
|
17
pkg/io/files/auto_file_perm.go
Normal file
17
pkg/io/files/auto_file_perm.go
Normal file
@ -0,0 +1,17 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func GetPermForDir(dirLocation string) os.FileMode {
|
||||
userHome, err := os.UserHomeDir()
|
||||
|
||||
if err == nil {
|
||||
if IsFileLocatedIn(dirLocation, userHome) {
|
||||
return DirUserPermitted
|
||||
}
|
||||
}
|
||||
|
||||
return DirAllPermitted
|
||||
}
|
10
pkg/io/files/dir_creator.go
Normal file
10
pkg/io/files/dir_creator.go
Normal file
@ -0,0 +1,10 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func MkdirsAutoPerm(dirLocation string) error {
|
||||
perm := GetPermForDir(dirLocation)
|
||||
return os.MkdirAll(dirLocation, perm)
|
||||
}
|
43
pkg/io/files/file_exists_checker.go
Normal file
43
pkg/io/files/file_exists_checker.go
Normal file
@ -0,0 +1,43 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func IsFileExists(fileLocation string) bool {
|
||||
if _, err := os.Stat(fileLocation); errors.Is(err, os.ErrNotExist) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func GetFirstIndexedNonExistingFilePath(parentDir string, fileBaseName string) string {
|
||||
filePath := filepath.Join(parentDir, fileBaseName)
|
||||
|
||||
if !IsFileExists(filePath) {
|
||||
return filePath
|
||||
}
|
||||
|
||||
fileIndex := 0
|
||||
fileBaseNameWithoutExtension := GetSimpleNameWithoutExtension(fileBaseName)
|
||||
fileExtension := GetExtension(fileBaseName)
|
||||
if fileExtension != "" {
|
||||
fileExtension = "." + fileExtension
|
||||
}
|
||||
|
||||
for {
|
||||
if !IsFileExists(filePath) {
|
||||
break
|
||||
}
|
||||
|
||||
fileIndex++
|
||||
|
||||
filePath = filepath.Join(parentDir, fmt.Sprintf("%s-%d%s", fileBaseNameWithoutExtension, fileIndex, fileExtension))
|
||||
}
|
||||
|
||||
return filePath
|
||||
}
|
22
pkg/io/files/file_located_in_checker.go
Normal file
22
pkg/io/files/file_located_in_checker.go
Normal file
@ -0,0 +1,22 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func IsFileLocatedIn(fileToCheck string, dirInWhichLocated string) bool {
|
||||
fileToCheck = TryAbs(fileToCheck)
|
||||
dirInWhichLocated = TryAbs(dirInWhichLocated)
|
||||
|
||||
if runtime.GOOS == "windows" {
|
||||
fileToCheck = strings.ToLower(fileToCheck)
|
||||
dirInWhichLocated = strings.ToLower(dirInWhichLocated)
|
||||
}
|
||||
|
||||
fileToCheck = filepath.ToSlash(fileToCheck)
|
||||
dirInWhichLocated = filepath.ToSlash(dirInWhichLocated)
|
||||
|
||||
return strings.HasPrefix(fileToCheck, dirInWhichLocated+"/")
|
||||
}
|
84
pkg/io/files/file_name_utils.go
Normal file
84
pkg/io/files/file_name_utils.go
Normal file
@ -0,0 +1,84 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"git.tswf.io/incredible-go/incredible-go-core/pkg/collections/array_list"
|
||||
)
|
||||
|
||||
var RestrictedFilepathCharactersReplacements = map[string]string{
|
||||
"<": "<",
|
||||
">": ">",
|
||||
":": ":",
|
||||
"\"": """,
|
||||
"/": "/",
|
||||
"\\": "\",
|
||||
"|": "|",
|
||||
"?": "?",
|
||||
"*": "*",
|
||||
}
|
||||
|
||||
func GetSimpleName(filePath string) string {
|
||||
return SplitFileName(filePath).GetLast()
|
||||
}
|
||||
|
||||
func GetExtension(filePath string) string {
|
||||
split := strings.Split(filePath, ".")
|
||||
if len(split) == 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return split[len(split)-1]
|
||||
}
|
||||
|
||||
func GetSimpleNameWithoutExtension(filePath string) string {
|
||||
simpleName := GetSimpleName(filePath)
|
||||
split := slices.DeleteFunc(strings.Split(simpleName, "."), func(s string) bool {
|
||||
return s == ""
|
||||
})
|
||||
|
||||
if len(split) == 1 {
|
||||
return filePath
|
||||
}
|
||||
|
||||
return strings.Join(split[:len(split)-1], "")
|
||||
}
|
||||
|
||||
func SplitFileName(filePath string) *array_list.ArrayList[string] {
|
||||
filePath = filepath.ToSlash(filePath)
|
||||
split := strings.Split(filePath, "/")
|
||||
|
||||
return array_list.NewArrayListWithContent[string](split...)
|
||||
}
|
||||
|
||||
func ReplaceAllRestrictedCharacters(filePath string) string {
|
||||
for k, v := range RestrictedFilepathCharactersReplacements {
|
||||
filePath = strings.ReplaceAll(filePath, k, v)
|
||||
}
|
||||
|
||||
return filePath
|
||||
}
|
||||
|
||||
func ReplaceAllRestrictedCharactersNoSlashes(filePath string) string {
|
||||
for k, v := range RestrictedFilepathCharactersReplacements {
|
||||
if k == "\\" || k == "/" {
|
||||
continue
|
||||
}
|
||||
filePath = strings.ReplaceAll(filePath, k, v)
|
||||
}
|
||||
|
||||
return filePath
|
||||
}
|
||||
|
||||
func TryAbs(filePath string) string {
|
||||
if !filepath.IsAbs(filePath) {
|
||||
abs, err := filepath.Abs(filePath)
|
||||
if err == nil {
|
||||
return abs
|
||||
}
|
||||
}
|
||||
|
||||
return filePath
|
||||
}
|
15
pkg/io/files/file_open_helper.go
Normal file
15
pkg/io/files/file_open_helper.go
Normal file
@ -0,0 +1,15 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func OpenFileForWriting(fileLocation string) (*os.File, error) {
|
||||
err := MkdirParent(fileLocation)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return os.Create(fileLocation)
|
||||
}
|
8
pkg/io/files/file_perm.go
Normal file
8
pkg/io/files/file_perm.go
Normal file
@ -0,0 +1,8 @@
|
||||
package files
|
||||
|
||||
import "os"
|
||||
|
||||
const (
|
||||
DirUserPermitted os.FileMode = 0755
|
||||
DirAllPermitted = os.ModePerm
|
||||
)
|
93
pkg/io/files/fle_copier.go
Normal file
93
pkg/io/files/fle_copier.go
Normal file
@ -0,0 +1,93 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
func CopyDir(src, dst string) error {
|
||||
src = filepath.Clean(src)
|
||||
dst = filepath.Clean(dst)
|
||||
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !si.IsDir() {
|
||||
return fmt.Errorf("source is not a directory")
|
||||
}
|
||||
|
||||
_, err = os.Stat(dst)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
if err == nil {
|
||||
return fmt.Errorf("destination already exists")
|
||||
}
|
||||
|
||||
err = os.MkdirAll(dst, si.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcPath := filepath.Join(src, entry.Name())
|
||||
dstPath := filepath.Join(dst, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
err = CopyDir(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
err = CopyFile(srcPath, dstPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func CopyFile(src, dst string) error {
|
||||
srcFile, err := os.Open(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer srcFile.Close()
|
||||
|
||||
dstFile, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer dstFile.Close()
|
||||
|
||||
_, err = io.Copy(dstFile, srcFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = dstFile.Sync()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
si, err := os.Stat(src)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = os.Chmod(dst, si.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
14
pkg/io/files/parent_dir_creator.go
Normal file
14
pkg/io/files/parent_dir_creator.go
Normal file
@ -0,0 +1,14 @@
|
||||
package files
|
||||
|
||||
func MkdirParent(fileLocation string) error {
|
||||
parentDir := GetParentDir(fileLocation)
|
||||
if parentDir != "" {
|
||||
parentDirCreationErr := MkdirsAutoPerm(parentDir)
|
||||
|
||||
if parentDirCreationErr != nil {
|
||||
return parentDirCreationErr
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
16
pkg/io/files/parent_dir_utils.go
Normal file
16
pkg/io/files/parent_dir_utils.go
Normal file
@ -0,0 +1,16 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func GetParentDir(fileLocation string) string {
|
||||
fileLocation = filepath.ToSlash(fileLocation)
|
||||
indexOfSlash := strings.LastIndex(fileLocation, "/")
|
||||
if indexOfSlash > 0 {
|
||||
return fileLocation[:indexOfSlash]
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
58
pkg/io/files/subfile_finder.go
Normal file
58
pkg/io/files/subfile_finder.go
Normal file
@ -0,0 +1,58 @@
|
||||
package files
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"git.tswf.io/incredible-go/incredible-go-core/pkg/collections/array_list"
|
||||
)
|
||||
|
||||
type FileFilter func(fileInfo os.FileInfo, fileName string) bool
|
||||
|
||||
func ListFiles(dirPath string) (*array_list.ArrayList[string], error) {
|
||||
dirInfo, err := os.Stat(dirPath)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !dirInfo.IsDir() {
|
||||
return nil, fmt.Errorf("'%s' is not directory", dirPath)
|
||||
}
|
||||
|
||||
dirEntries, err := os.ReadDir(dirPath)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := array_list.NewArrayList[string]()
|
||||
|
||||
if len(dirEntries) > 0 {
|
||||
for _, dirEntry := range dirEntries {
|
||||
result.Add(dirEntry.Name())
|
||||
}
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func FindSubFilesByFilter(rootPath string, filter FileFilter) (*array_list.ArrayList[string], error) {
|
||||
result := array_list.NewArrayList[string]()
|
||||
|
||||
err := filepath.Walk(rootPath, func(path string, info fs.FileInfo, err error) error {
|
||||
if err == nil && filter(info, path) {
|
||||
result.Add(path)
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
84
pkg/os/process/process_environment/process_environment.go
Normal file
84
pkg/os/process/process_environment/process_environment.go
Normal file
@ -0,0 +1,84 @@
|
||||
package process_environment
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"git.tswf.io/incredible-go/incredible-go-core/pkg/collections/array_list"
|
||||
)
|
||||
|
||||
var PathEnvironmentVariableName = "PATH"
|
||||
|
||||
func AppendPath(cmd *exec.Cmd, newElements ...string) {
|
||||
pathEntries := array_list.NewArrayList[string]()
|
||||
for _, newPathEntry := range newElements {
|
||||
if !pathEntries.Contains(newPathEntry) {
|
||||
pathEntries.Add(newPathEntry)
|
||||
}
|
||||
}
|
||||
|
||||
pathEntries.AddAll(GetPath(cmd))
|
||||
|
||||
SetPath(cmd, pathEntries.ToSliceUnsafe()...)
|
||||
}
|
||||
|
||||
func SetPath(cmd *exec.Cmd, entries ...string) {
|
||||
pathEntries := GetPath(cmd)
|
||||
for _, entry := range entries {
|
||||
if !pathEntries.Contains(entry) {
|
||||
pathEntries.Add(entry)
|
||||
}
|
||||
}
|
||||
|
||||
newPathEnvValue := strings.Join(pathEntries.ToSliceUnsafe(), string(os.PathListSeparator))
|
||||
SetEnvironmentVariable(cmd, PathEnvironmentVariableName, newPathEnvValue)
|
||||
}
|
||||
|
||||
func GetPath(cmd *exec.Cmd) *array_list.ArrayList[string] {
|
||||
oldPathEnvValue := GetEnvironmentVariable(cmd, PathEnvironmentVariableName)
|
||||
pathListSeparatorString := string(os.PathListSeparator)
|
||||
|
||||
oldPathEnvEntries := array_list.NewArrayListWithContent(strings.Split(oldPathEnvValue, pathListSeparatorString)...)
|
||||
|
||||
oldPathEnvEntries.RemoveIf(func(s string) bool {
|
||||
return s == ""
|
||||
})
|
||||
|
||||
return oldPathEnvEntries
|
||||
}
|
||||
|
||||
func SetEnvironmentVariable(cmd *exec.Cmd, envName string, envValue string) *exec.Cmd {
|
||||
envPrefix := getEnvironmentVariablePrefix(envName)
|
||||
cmd.Env = slices.DeleteFunc(cmd.Env, func(s string) bool {
|
||||
return strings.HasPrefix(strings.ToLower(s), envPrefix)
|
||||
})
|
||||
|
||||
cmd.Env = append(cmd.Env, envPrefix+envValue)
|
||||
|
||||
return cmd
|
||||
}
|
||||
|
||||
func GetEnvironmentVariable(cmd *exec.Cmd, envName string) string {
|
||||
envPrefix := getEnvironmentVariablePrefix(envName)
|
||||
for _, env := range cmd.Env {
|
||||
if strings.HasPrefix(strings.ToLower(env), envPrefix) {
|
||||
split := strings.SplitN(env, "=", 2)
|
||||
if len(split) < 2 {
|
||||
log.Printf("%v is not valid split for env '%s'", cmd.Env, env)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func IsEnvironmentVariablePresent(cmd *exec.Cmd, envName string) bool {
|
||||
return GetEnvironmentVariable(cmd, envName) != ""
|
||||
}
|
||||
|
||||
func getEnvironmentVariablePrefix(envName string) string {
|
||||
return strings.ToLower(envName + "=")
|
||||
}
|
24
pkg/os/process/process_execution/process_execution.go
Normal file
24
pkg/os/process/process_execution/process_execution.go
Normal file
@ -0,0 +1,24 @@
|
||||
package process_execution
|
||||
|
||||
import "os/exec"
|
||||
|
||||
func ExecuteAndGetOutput(command string, args ...string) (string, error) {
|
||||
return ExecuteAndGetOutputC(nil, command, args...)
|
||||
}
|
||||
|
||||
func ExecuteAndGetOutputC(cfg func(*exec.Cmd), command string, args ...string) (string, error) {
|
||||
process := exec.Command(command, args...)
|
||||
|
||||
if cfg != nil {
|
||||
cfg(process)
|
||||
}
|
||||
|
||||
outputBytes, err := process.CombinedOutput()
|
||||
outputString := ""
|
||||
|
||||
if outputBytes != nil && len(outputBytes) > 0 {
|
||||
outputString = string(outputBytes)
|
||||
}
|
||||
|
||||
return outputString, err
|
||||
}
|
85
pkg/serialize/json_io/json_io.go
Normal file
85
pkg/serialize/json_io/json_io.go
Normal file
@ -0,0 +1,85 @@
|
||||
package json_io
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"git.tswf.io/incredible-go/incredible-go-core/pkg/io/files"
|
||||
)
|
||||
|
||||
func ReadFromJsonBytes[T any](jsonBytes []byte) (*T, error) {
|
||||
var result T
|
||||
|
||||
err := json.Unmarshal(jsonBytes, &result)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
func WriteToJsonBytes[T any](value *T) ([]byte, error) {
|
||||
content, err := json.Marshal(value)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return content, nil
|
||||
}
|
||||
|
||||
func ReadFromJsonString[T any](jsonString string) (*T, error) {
|
||||
return ReadFromJsonBytes[T]([]byte(jsonString))
|
||||
}
|
||||
|
||||
func WriteToJsonString[T any](value *T) (string, error) {
|
||||
jsonBytes, err := WriteToJsonBytes(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(jsonBytes), nil
|
||||
}
|
||||
|
||||
func ReadFromJsonFile[T any](jsonFileLocation string) (*T, error) {
|
||||
fileInfo, err := os.Stat(jsonFileLocation)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if fileInfo.IsDir() {
|
||||
return nil, fmt.Errorf("json file '%s' can not be a directory", jsonFileLocation)
|
||||
}
|
||||
|
||||
jsonFileContentBytes, err := os.ReadFile(jsonFileLocation)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ReadFromJsonBytes[T](jsonFileContentBytes)
|
||||
}
|
||||
|
||||
func WriteToJsonFile[T any](jsonFileLocation string, value *T) ([]byte, error) {
|
||||
jsonBytes, err := WriteToJsonBytes(value)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
file, err := files.OpenFileForWriting(jsonFileLocation)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_, err = file.Write(jsonBytes)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return jsonBytes, nil
|
||||
}
|
14
pkg/string/string_utils/line_separator_provider.go
Normal file
14
pkg/string/string_utils/line_separator_provider.go
Normal file
@ -0,0 +1,14 @@
|
||||
package string_utils
|
||||
|
||||
import "runtime"
|
||||
|
||||
func GetLineSeparator() string {
|
||||
switch runtime.GOOS {
|
||||
case "windows":
|
||||
return "\r\n"
|
||||
case "darwin":
|
||||
return "\r"
|
||||
default:
|
||||
return "\n"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user