Compare commits

..

No commits in common. "master" and "1.0.0" have entirely different histories.

27 changed files with 13 additions and 966 deletions

1
.gitignore vendored
View File

@ -1 +0,0 @@
/cmd/

10
go.mod
View File

@ -1,3 +1,11 @@
module git.tswf.io/incredible-go/incredible-go-core
go 1.20
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
//)

View File

@ -6,10 +6,3 @@ func NewArrayList[T any]() *ArrayList[T] {
size: 0,
}
}
func NewArrayListWithContent[T any](content ...T) *ArrayList[T] {
result := NewArrayList[T]()
result.AddAllS(&content)
return result
}

View File

@ -1,20 +0,0 @@
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
}

View File

@ -3,9 +3,6 @@ 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) {
@ -18,42 +15,21 @@ 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
indexFromMove = index + 1
break
}
}
self.RemoveByIndex(indexFromMove)
}
func (self *ArrayList[T]) RemoveByIndex(index int) {
contentSize := len(self.content)
if index >= 0 {
for i := index + 1; i < contentSize; i++ {
if indexFromMove >= 0 {
for i := indexFromMove; i < contentSize; i++ {
self.content[i-1] = self.content[i]
}
@ -101,22 +77,6 @@ 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 {
@ -167,67 +127,3 @@ 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
}

View File

@ -1,20 +0,0 @@
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
}

View File

@ -1,20 +0,0 @@
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
}

View File

@ -1,6 +0,0 @@
package optional
type Optional[T any] struct {
Present bool
Value T
}

View File

@ -1,23 +0,0 @@
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)
}
}

View File

@ -1,59 +0,0 @@
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()
}

View File

@ -1,37 +0,0 @@
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)
}

View File

@ -1,77 +0,0 @@
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)
}

View File

@ -1,17 +0,0 @@
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
}

View File

@ -1,10 +0,0 @@
package files
import (
"os"
)
func MkdirsAutoPerm(dirLocation string) error {
perm := GetPermForDir(dirLocation)
return os.MkdirAll(dirLocation, perm)
}

View File

@ -1,43 +0,0 @@
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
}

View File

@ -1,22 +0,0 @@
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+"/")
}

View File

@ -1,84 +0,0 @@
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
}

View File

@ -1,15 +0,0 @@
package files
import (
"os"
)
func OpenFileForWriting(fileLocation string) (*os.File, error) {
err := MkdirParent(fileLocation)
if err != nil {
return nil, err
}
return os.Create(fileLocation)
}

View File

@ -1,8 +0,0 @@
package files
import "os"
const (
DirUserPermitted os.FileMode = 0755
DirAllPermitted = os.ModePerm
)

View File

@ -1,93 +0,0 @@
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
}

View File

@ -1,14 +0,0 @@
package files
func MkdirParent(fileLocation string) error {
parentDir := GetParentDir(fileLocation)
if parentDir != "" {
parentDirCreationErr := MkdirsAutoPerm(parentDir)
if parentDirCreationErr != nil {
return parentDirCreationErr
}
}
return nil
}

View File

@ -1,16 +0,0 @@
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 ""
}

View File

@ -1,58 +0,0 @@
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
}

View File

@ -1,84 +0,0 @@
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 + "=")
}

View File

@ -1,24 +0,0 @@
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
}

View File

@ -1,85 +0,0 @@
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
}

View File

@ -1,14 +0,0 @@
package string_utils
import "runtime"
func GetLineSeparator() string {
switch runtime.GOOS {
case "windows":
return "\r\n"
case "darwin":
return "\r"
default:
return "\n"
}
}