🏗️ move make sub-cmd to sub-dir
This commit is contained in:
144
pkg/extractor/extractor.go
Normal file
144
pkg/extractor/extractor.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package extractor
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"gitea.loveuer.com/yizhisec/pkg3/logger"
|
||||
)
|
||||
|
||||
type Options struct {
|
||||
OnProgress func(filename string, index int, total int)
|
||||
IsGzipped *bool
|
||||
}
|
||||
|
||||
type Option func(*Options)
|
||||
|
||||
func WithProgress(callback func(filename string, index int, total int)) Option {
|
||||
return func(o *Options) {
|
||||
o.OnProgress = callback
|
||||
}
|
||||
}
|
||||
|
||||
func WithGzipCompression(isGzipped bool) Option {
|
||||
return func(o *Options) {
|
||||
o.IsGzipped = &isGzipped
|
||||
}
|
||||
}
|
||||
|
||||
func Extract(ctx context.Context, src, destDir string, opts ...Option) error {
|
||||
options := &Options{}
|
||||
for _, opt := range opts {
|
||||
opt(options)
|
||||
}
|
||||
|
||||
logger.Debug("开始解压: %s -> %s", src, destDir)
|
||||
|
||||
f, err := os.Open(src)
|
||||
if err != nil {
|
||||
logger.Debug("打开源文件失败 %s: %v", src, err)
|
||||
return fmt.Errorf("failed to open source file: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
var reader io.Reader = f
|
||||
var isGzipped bool
|
||||
|
||||
if options.IsGzipped != nil {
|
||||
isGzipped = *options.IsGzipped
|
||||
} else {
|
||||
isGzipped = strings.HasSuffix(strings.ToLower(src), ".tar.gz") || strings.HasSuffix(strings.ToLower(src), ".tgz")
|
||||
}
|
||||
|
||||
if isGzipped {
|
||||
gzReader, err := gzip.NewReader(f)
|
||||
if err != nil {
|
||||
logger.Debug("创建 gzip reader 失败: %v", err)
|
||||
return fmt.Errorf("failed to create gzip reader: %w", err)
|
||||
}
|
||||
defer gzReader.Close()
|
||||
reader = gzReader
|
||||
}
|
||||
|
||||
if err := extractTar(ctx, reader, destDir, options); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Debug("解压完成: %s", src)
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractTar(ctx context.Context, r io.Reader, destDir string, options *Options) error {
|
||||
tarReader := tar.NewReader(r)
|
||||
fileCount := 0
|
||||
totalFiles := 0
|
||||
|
||||
for {
|
||||
if ctx.Err() != nil {
|
||||
return ctx.Err()
|
||||
}
|
||||
|
||||
header, err := tarReader.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
logger.Debug("读取 tar 条目失败: %v", err)
|
||||
return fmt.Errorf("failed to read tar header: %w", err)
|
||||
}
|
||||
|
||||
target := filepath.Join(destDir, header.Name)
|
||||
logger.Debug("解压文件: %s", header.Name)
|
||||
|
||||
if options.OnProgress != nil {
|
||||
options.OnProgress(header.Name, fileCount, totalFiles)
|
||||
}
|
||||
|
||||
switch header.Typeflag {
|
||||
case tar.TypeDir:
|
||||
if err := os.MkdirAll(target, os.FileMode(header.Mode)); err != nil {
|
||||
logger.Debug("创建目录失败 %s: %v", target, err)
|
||||
return fmt.Errorf("failed to create directory %s: %w", target, err)
|
||||
}
|
||||
case tar.TypeReg:
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
logger.Debug("创建父目录失败 %s: %v", filepath.Dir(target), err)
|
||||
return fmt.Errorf("failed to create parent directory: %w", err)
|
||||
}
|
||||
outFile, err := os.OpenFile(target, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.FileMode(header.Mode))
|
||||
if err != nil {
|
||||
logger.Debug("创建文件失败 %s: %v", target, err)
|
||||
return fmt.Errorf("failed to create file %s: %w", target, err)
|
||||
}
|
||||
if _, err := io.Copy(outFile, tarReader); err != nil {
|
||||
outFile.Close()
|
||||
logger.Debug("写入文件失败 %s: %v", target, err)
|
||||
return fmt.Errorf("failed to write file %s: %w", target, err)
|
||||
}
|
||||
outFile.Close()
|
||||
fileCount++
|
||||
case tar.TypeSymlink:
|
||||
if err := os.MkdirAll(filepath.Dir(target), 0755); err != nil {
|
||||
logger.Debug("创建符号链接父目录失败 %s: %v", filepath.Dir(target), err)
|
||||
return fmt.Errorf("failed to create parent directory for symlink: %w", err)
|
||||
}
|
||||
os.Remove(target)
|
||||
if err := os.Symlink(header.Linkname, target); err != nil {
|
||||
logger.Debug("创建符号链接失败 %s -> %s: %v", target, header.Linkname, err)
|
||||
return fmt.Errorf("failed to create symlink %s -> %s: %w", target, header.Linkname, err)
|
||||
}
|
||||
fileCount++
|
||||
default:
|
||||
logger.Debug("跳过不支持的文件类型: %s (type: %v)", header.Name, header.Typeflag)
|
||||
}
|
||||
}
|
||||
|
||||
logger.Debug("解压完成,共 %d 个文件", fileCount)
|
||||
return nil
|
||||
}
|
||||
98
pkg/resource/seafile.yaml
Normal file
98
pkg/resource/seafile.yaml
Normal file
@@ -0,0 +1,98 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: seafile
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: memcached
|
||||
namespace: seafile
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: memcached
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: memcached
|
||||
spec:
|
||||
containers:
|
||||
- name: memcached
|
||||
image: hub.yizhisec.com/product/hybridscope/memcached
|
||||
args: ["-m", "256"]
|
||||
ports:
|
||||
- containerPort: 11211
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: memcached
|
||||
namespace: seafile
|
||||
spec:
|
||||
selector:
|
||||
app: memcached
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 11211
|
||||
targetPort: 11211
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: seafile
|
||||
namespace: seafile
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: seafile
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: seafile
|
||||
spec:
|
||||
containers:
|
||||
- name: seafile
|
||||
image: hub.yizhisec.com/product/hybridscope/seafile-mc:latest
|
||||
imagePullPolicy: IfNotPresent
|
||||
env:
|
||||
- name: DB_HOST
|
||||
value: "mysql-cluster-mysql-master.db-mysql"
|
||||
- name: DB_ROOT_PASSWD
|
||||
value: "L0hMysql." #db's password
|
||||
- name: TIME_ZONE
|
||||
value: "Asia/Shanghai"
|
||||
- name: SEAFILE_ADMIN_EMAIL
|
||||
value: "admin@yizhisec.com" #admin email
|
||||
- name: SEAFILE_ADMIN_PASSWORD
|
||||
value: "asecret" #admin password
|
||||
- name: SEAFILE_SERVER_LETSENCRYPT
|
||||
value: "false"
|
||||
- name: SEAFILE_SERVER_HOSTNAME
|
||||
value: "cloud.hybridscope.com" #hostname
|
||||
ports:
|
||||
- containerPort: 80
|
||||
volumeMounts:
|
||||
- name: seafile-data
|
||||
mountPath: /shared
|
||||
volumes:
|
||||
- name: seafile-data
|
||||
persistentVolumeClaim:
|
||||
claimName: seafile-data
|
||||
restartPolicy: Always
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: seafile-data
|
||||
namespace: seafile
|
||||
spec:
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
storageClassName: longhorn
|
||||
resources:
|
||||
requests:
|
||||
storage: 10Gi
|
||||
13
pkg/tool/random/str.go
Normal file
13
pkg/tool/random/str.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package random
|
||||
|
||||
import "math/rand"
|
||||
|
||||
const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
|
||||
func RandomString(length int) string {
|
||||
b := make([]byte, length)
|
||||
for i := range b {
|
||||
b[i] = charset[rand.Intn(len(charset))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
26
pkg/tool/random/str_test.go
Normal file
26
pkg/tool/random/str_test.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package random_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"yizhisec.com/hsv2/forge/pkg/tool/random"
|
||||
)
|
||||
|
||||
func TestRandomString(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string // description of this test case
|
||||
// Named input parameters for target function.
|
||||
length int
|
||||
want string
|
||||
}{
|
||||
// TODO: Add test cases.
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got := random.RandomString(tt.length)
|
||||
// TODO: update the condition below to compare got with tt.want.
|
||||
if true {
|
||||
t.Errorf("RandomString() = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user