pull file
Some checks failed
CodeQL / Analyze (csharp) (push) Has been cancelled
Close Stale Issues / close_stale_issues (push) Has been cancelled
repo-sync / repo-sync (push) Has been cancelled
auto-deploy-tencent-scf / pre-check (push) Has been cancelled
auto-deploy-tencent-scf / deploy serverless (push) Has been cancelled

This commit is contained in:
2026-02-11 23:32:56 +08:00
commit e519cac94e
656 changed files with 45058 additions and 0 deletions

39
krew/pkg/cmd/cmd.go Normal file
View File

@@ -0,0 +1,39 @@
package cmd
import (
"log"
"github.com/spf13/cobra"
"k8s.io/cli-runtime/pkg/genericclioptions"
)
const (
biliproDesc = `Manage and deploy bilibili pro tools on k8s`
kubeconfig = "kubeconfig"
)
var (
confPath string
rootCmd = &cobra.Command{
Use: "bilipro",
Long: biliproDesc,
SilenceUsage: true,
}
)
func init() {
rootCmd.PersistentFlags().StringVar(&confPath, kubeconfig, "", "Custom kubeconfig path")
log.SetFlags(log.Ldate | log.Ltime | log.Lshortfile)
}
// New creates a new root command for kubectl-bilipro
func NewExecutor(streams genericclioptions.IOStreams) *cobra.Command {
cobra.EnableCommandSorting = false
rootCmd.AddCommand(newInitCmd(rootCmd.OutOrStdout(), rootCmd.ErrOrStderr()))
// If you want to update, just init again
rootCmd.AddCommand(newGetCmd(rootCmd.OutOrStdout(), rootCmd.ErrOrStderr()))
rootCmd.AddCommand(newDeleteCmd(rootCmd.OutOrStdout(), rootCmd.ErrOrStderr()))
rootCmd.AddCommand(newVersionCmd(rootCmd.OutOrStdout(), rootCmd.ErrOrStderr()))
return rootCmd
}

130
krew/pkg/cmd/delete.go Normal file
View File

@@ -0,0 +1,130 @@
package cmd
import (
"fmt"
"io"
"os/exec"
"strings"
"sigs.k8s.io/kustomize/api/krusty"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/yaml"
"github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils"
"github.com/spf13/cobra"
)
const (
deleteDesc = `
'delete' command delete bilibilipro tool.`
deleteExample = ` kubectl bilipro delete <--name deployment_name>`
)
type deleteCmd struct {
out io.Writer
errOut io.Writer
output bool
deployOpts options.DeployOptions
}
func newDeleteCmd(out io.Writer, errOut io.Writer) *cobra.Command {
o := &deleteCmd{out: out, errOut: errOut}
cmd := &cobra.Command{
Use: "delete",
Short: "Delete bilibilipro",
Long: deleteDesc,
Example: deleteExample,
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
err := o.run(out)
if err != nil {
fmt.Println(err)
return err
}
fmt.Println("bilibili tool is removed from your cluster")
return nil
},
}
f := cmd.Flags()
f.StringVarP(&o.deployOpts.Namespace, "namespace", "n", "bilipro", "namespace scope for this request")
f.StringVarP(&o.deployOpts.Name, "name", "", "bilibilipro", "name of deployment to delete")
return cmd
}
func (o *deleteCmd) run(writer io.Writer) error {
inDiskSys, err := helper.GetResourceFileSys()
if err != nil {
return err
}
// remove namespace files lastly
resources := []string{"base/bilibiliPro/deployment.yaml"}
// write the kustomization file
kustomizationYaml := types.Kustomization{
TypeMeta: types.TypeMeta{
Kind: "Kustomization",
APIVersion: "kustomize.config.k8s.io/v1beta1",
},
Resources: resources,
}
if o.deployOpts.Namespace != "" {
kustomizationYaml.Namespace = o.deployOpts.Namespace
}
// Compile the kustomization to a file and create on the in memory filesystem
kustYaml, err := yaml.Marshal(kustomizationYaml)
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
kustFile, err := inDiskSys.Create("./bilipro/kustomization.yaml")
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
_, err = kustFile.Write(kustYaml)
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
// kustomize build the target location
k := krusty.MakeKustomizer(
krusty.MakeDefaultOptions(),
)
m, err := k.Run(inDiskSys, "./bilipro")
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
yml, err := m.AsYaml()
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
if o.output {
_, err = writer.Write(yml)
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
// do kubectl delete
cmd := exec.Command("kubectl", "delete", "-f", "-")
if err := helper.Run(cmd, strings.NewReader(string(yml))); err != nil {
return err
}
// delete the namespace
cmd = exec.Command("kubectl", "delete", "ns", o.deployOpts.Namespace)
if err := helper.Run(cmd, nil); err != nil {
return err
}
return nil
}

61
krew/pkg/cmd/get.go Normal file
View File

@@ -0,0 +1,61 @@
package cmd
import (
"fmt"
"io"
"os/exec"
"github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils"
"github.com/spf13/cobra"
)
const (
getDesc = `
'get' command get bilibilipro tool deployment.`
getExample = ` kubectl bilipro get <--name deployment_name --namespace namespace_name>`
)
type getCmd struct {
out io.Writer
errOut io.Writer
deployOpts options.DeployOptions
}
func newGetCmd(out io.Writer, errOut io.Writer) *cobra.Command {
o := &getCmd{out: out, errOut: errOut}
cmd := &cobra.Command{
Use: "get",
Short: "Get bilibilipro",
Long: getDesc,
Example: getExample,
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
err := o.run(out)
if err != nil {
fmt.Println(err)
return err
}
return nil
},
}
f := cmd.Flags()
f.StringVarP(&o.deployOpts.Namespace, "namespace", "n", "bilipro", "namespace scope for this request")
f.StringVarP(&o.deployOpts.Name, "name", "", "bilibilipro", "name of deployment to get")
return cmd
}
func (o *getCmd) run(writer io.Writer) error {
// do kubectl get
cmd := exec.Command("kubectl", "get", "deploy", o.deployOpts.Name, "-n", o.deployOpts.Namespace)
if err := helper.Run(cmd, nil); err != nil {
return err
}
return nil
}

286
krew/pkg/cmd/init.go Normal file
View File

@@ -0,0 +1,286 @@
package cmd
import (
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"strings"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/kustomize/kyaml/resid"
"sigs.k8s.io/yaml"
"sigs.k8s.io/kustomize/api/types"
"github.com/spf13/cobra"
"github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/options"
helper "github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/utils"
"sigs.k8s.io/kustomize/api/krusty"
)
const (
initDesc = `
'init' command creates BilibiliPro deployment along with all the dependencies.`
initExample = ` kubectl bilipro init --config <config-file>`
)
type initCmd struct {
out io.Writer
errOut io.Writer
output bool
login bool
deployOpts options.DeployOptions
}
func newInitCmd(out io.Writer, errOut io.Writer) *cobra.Command {
o := &initCmd{out: out, errOut: errOut}
cmd := &cobra.Command{
Use: "init",
Short: "Initialize bilipro",
Long: initDesc,
Example: initExample,
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
err := o.run(out)
if err != nil {
fmt.Println(err)
return err
}
return nil
},
}
f := cmd.Flags()
f.StringVarP(&o.deployOpts.Image, "image", "i", "zai7lou/bilibili_tool_pro:2.0.1", "bilibilipro image")
f.StringVarP(&o.deployOpts.Namespace, "namespace", "n", "bilipro", "namespace scope for this request")
f.StringVar(&o.deployOpts.ImagePullSecret, "image-pull-secret", "", "image pull secret to be used for pulling bilibilipro image")
f.StringVarP(&o.deployOpts.ConfigFilePath, "config", "c", "", "the config file contanis the environment variables")
f.BoolVarP(&o.output, "output", "o", false, "dry run this command and generate requisite yaml")
f.BoolVarP(&o.login, "login", "l", false, "scan QR login code")
return cmd
}
type opStr struct {
Op string `json:"op"`
Path string `json:"path"`
Value string `json:"value"`
}
type opInterface struct {
Op string `json:"op"`
Path string `json:"path"`
Value interface{} `json:"value"`
}
type normalEnvVars struct {
Name string `json:"name"`
Value string `json:"value"`
}
// run initializes local config and installs BiliBiliPro tool to Kubernetes Cluster.
func (o *initCmd) run(writer io.Writer) error {
inDiskSys, err := helper.GetResourceFileSys()
if err != nil {
return err
}
// TODO: All about paths are a little bit tricky should give it more thoughts
fmt.Println("Creating the kustomization file")
// if the bilibili tool is deployed under system/pre-defined namespace, ignore the namespace file
var resources []string // nolint: go-staticcheck
if o.deployOpts.Namespace == "default" || o.deployOpts.Namespace == "kube-system" || o.deployOpts.Namespace == "kube-public" {
resources = []string{"base/bilibiliPro/deployment.yaml"}
} else {
resources = []string{"base/ns/namespace.yaml", "base/bilibiliPro/deployment.yaml"}
}
// write the kustomization file
kustomizationYaml := types.Kustomization{
TypeMeta: types.TypeMeta{
Kind: "Kustomization",
APIVersion: "kustomize.config.k8s.io/v1beta1",
},
Resources: resources,
PatchesJson6902: []types.Patch{},
}
var deployDepPatches []interface{}
// create patches for the supplied arguments
if o.deployOpts.Image != "" {
deployDepPatches = append(deployDepPatches, opStr{
Op: "replace",
Path: "/spec/template/spec/containers/0/image",
Value: o.deployOpts.Image,
})
}
// create patches for the env
content, err := os.ReadFile(o.deployOpts.ConfigFilePath)
if err != nil {
return helper.GenErrorMsg(helper.FILE_ERROR, err.Error())
}
envs := []normalEnvVars{}
err = yaml.Unmarshal(content, &envs)
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
deployDepPatches = append(deployDepPatches, opInterface{
Op: "add",
Path: "/spec/template/spec/containers/0/env",
Value: envs,
})
if o.deployOpts.ImagePullSecret != "" {
deployDepPatches = append(deployDepPatches, opInterface{
Op: "add",
Path: "/spec/template/spec/imagePullSecrets",
Value: []corev1.LocalObjectReference{{Name: o.deployOpts.ImagePullSecret}},
})
}
// attach the patches to the kustomization file
if len(deployDepPatches) > 0 {
kustomizationYaml.PatchesJson6902 = append(kustomizationYaml.PatchesJson6902, types.Patch{
Patch: o.serializeJSONPatchOps(deployDepPatches),
Target: &types.Selector{
ResId: resid.ResId{
Gvk: resid.Gvk{
Group: "apps",
Version: "v1",
Kind: "Deployment",
},
Name: "bilibilipro",
Namespace: o.deployOpts.Namespace,
},
},
})
}
// Not deploying in kube-* namespace
if o.deployOpts.Namespace == "kube-system" || o.deployOpts.Namespace == "kube-public" {
fmt.Println("better not deployed under system namesapce")
}
if o.deployOpts.Namespace != "" {
kustomizationYaml.Namespace = o.deployOpts.Namespace
}
// Compile the kustomization to a file and create on the in memory filesystem
kustYaml, err := yaml.Marshal(kustomizationYaml)
if err != nil {
return err
}
kustFile, err := inDiskSys.Create("./bilipro/kustomization.yaml")
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
_, err = kustFile.Write(kustYaml)
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
// kustomize build the target location
k := krusty.MakeKustomizer(
krusty.MakeDefaultOptions(),
)
m, err := k.Run(inDiskSys, "./bilipro")
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
yml, err := m.AsYaml()
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
if o.output {
_, err = writer.Write(yml)
if err != nil {
return helper.GenErrorMsg(helper.TEMPLATE_ERROR, err.Error())
}
}
fmt.Println("Applying the kustomization file")
// do kubectl apply
// make sure kubectl is under your PATH
cmd := exec.Command("kubectl", "apply", "-f", "-")
if err := helper.Run(cmd, strings.NewReader(string(yml))); err != nil {
return err
}
// if there is login required, exectue the login command as the last step
if o.login {
fmt.Println("please login...")
client, _, err := helper.GetK8sClient()
if err != nil {
return err
}
// get the pod name
podName, err := helper.GetBiliName(client, o.deployOpts.Namespace, "bilibilipro")
if err != nil {
return err
}
fmt.Println("wait for the deployment to be ready")
// Wait for the deployment ready
checkCmdArgs := []string{
"rollout",
"status",
"deployment/bilibilipro",
"-n",
o.deployOpts.Namespace,
}
checkCmd := exec.Command("kubectl", checkCmdArgs...)
for {
if err := checkCmd.Start(); err != nil {
fmt.Printf("deployment is not ready yet, current status: %v\n", err)
continue
}
err := checkCmd.Wait()
if err == nil {
fmt.Printf("deployment is ready\n")
break
}
fmt.Printf("deployment is not ready yet, current status: %v\n", err)
}
fmt.Println("please scan the QR code")
// Exec the login command
args := []string{
"exec",
podName,
"-n",
o.deployOpts.Namespace,
"--",
"dotnet",
"Ray.BiliBiliTool.Console.dll",
"--runTasks=Login",
}
cmd := exec.Command("kubectl", args...)
if err := helper.Run(cmd, nil); err != nil {
return err
}
}
return nil
}
func (o *initCmd) serializeJSONPatchOps(jp []interface{}) string {
jpJSON, _ := json.Marshal(jp)
return string(jpJSON)
}

50
krew/pkg/cmd/version.go Normal file
View File

@@ -0,0 +1,50 @@
package cmd
import (
"fmt"
"io"
"github.com/spf13/cobra"
)
// version provides the version of this plugin
var version = "NO.VERSION"
const (
versionDesc = `
'version' command displays the kubectl plugin version.`
versionExample = ` kubectl bilipro version`
)
type versionCmd struct {
out io.Writer
errOut io.Writer
}
func newVersionCmd(out io.Writer, errOut io.Writer) *cobra.Command {
o := &versionCmd{out: out, errOut: errOut}
cmd := &cobra.Command{
Use: "version",
Short: "Display plugin version",
Long: versionDesc,
Example: versionExample,
Args: cobra.MaximumNArgs(0),
RunE: func(cmd *cobra.Command, args []string) error {
err := o.run()
if err != nil {
fmt.Println(err)
return err
}
return nil
},
}
return cmd
}
// run initializes local config and installs BilibiliPro Plugin to Kubernetes cluster.
func (o *versionCmd) run() error {
fmt.Println(version)
return nil
}

View File

@@ -0,0 +1,10 @@
package options
// DeployOptions encapsulates the CLI options for a BiliBiliPro
type DeployOptions struct {
Name string
Image string
Namespace string
ImagePullSecret string
ConfigFilePath string
}

View File

@@ -0,0 +1,13 @@
package resources
import (
"embed"
)
//go:embed *
var fs embed.FS
// GetStaticResources returns the fs with the embedded assets
func GetStaticResources() embed.FS {
return fs
}

View File

@@ -0,0 +1,26 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: bilibilipro
spec:
selector:
matchLabels:
app: bilibilipro
template:
metadata:
labels:
app: bilibilipro
spec:
containers:
- name: bilibilipro
image: zai7lou/bilibili_tool_pro:2.0.1
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: 80m
memory: 100M
limits:
cpu: 100m
memory: 120M

View File

@@ -0,0 +1,5 @@
apiVersion: v1
kind: Namespace
metadata:
name: bilipro

73
krew/pkg/utils/client.go Normal file
View File

@@ -0,0 +1,73 @@
package utils
import (
"context"
"fmt"
"os"
"path/filepath"
"time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/clientcmd"
)
func GetK8sClient() (*kubernetes.Clientset, *rest.Config, error) {
var kubeconfig string
envKubeConfig := os.Getenv("KUBECONFIG")
if envKubeConfig == "" {
home, err := os.UserHomeDir()
if err != nil {
return nil, nil, GenErrorMsg(SERVER_ERROR, err.Error())
}
kubeconfig = filepath.Join(home, ".kube", "config")
} else {
kubeconfig = envKubeConfig
}
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", kubeconfig)
if err != nil {
return nil, nil, GenErrorMsg(SERVER_ERROR, err.Error())
}
config.QPS = float32(10.0)
config.Burst = 20
// create the clientset
clientset, err := kubernetes.NewForConfig(config)
if err != nil {
return nil, config, GenErrorMsg(SERVER_ERROR, err.Error())
}
return clientset, config, nil
}
func GetBiliName(client *kubernetes.Clientset, namespace, deploymentName string) (string, error) {
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Minute)
defer cancel()
deployment, err := client.AppsV1().Deployments(namespace).Get(ctx, deploymentName, metav1.GetOptions{})
if err != nil {
return "", GenErrorMsg(SERVER_ERROR, err.Error())
}
// we dont do much checks here
selector := deployment.Spec.Selector.MatchLabels
if len(selector) == 0 {
return "", GenErrorMsg(SERVER_ERROR, "deployment doesn't have any selectors, please check the deploy template")
}
listOptions := metav1.ListOptions{
LabelSelector: labels.Set(selector).String(),
}
pods, err := client.CoreV1().Pods(namespace).List(ctx, listOptions)
if err != nil {
return "", GenErrorMsg(SERVER_ERROR, "cannot list the pods with deploy selectors")
}
if len(pods.Items) != 1 {
return "", GenErrorMsg(SERVER_ERROR, fmt.Sprintf("pod number is expected to be 1, currently %d", len(pods.Items)))
}
// only one pod is supposed to be existing, soft constraint
return pods.Items[0].ObjectMeta.GetName(), nil
}

View File

@@ -0,0 +1,19 @@
package utils
import (
"testing"
)
func TestGetK8sClient(t *testing.T) {
client, _, err := GetK8sClient()
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
if client == nil {
t.Logf("test failed for returned client is empty, this should not happen")
t.FailNow()
}
}

38
krew/pkg/utils/cmd.go Normal file
View File

@@ -0,0 +1,38 @@
package utils
import (
"bufio"
"fmt"
"io"
"os/exec"
)
func Run(cmd *exec.Cmd, in io.Reader) error {
cmd.Stdin = in
stdoutReader, _ := cmd.StdoutPipe()
stdoutScanner := bufio.NewScanner(stdoutReader)
go func() {
for stdoutScanner.Scan() {
fmt.Println(stdoutScanner.Text())
}
}()
stderrReader, _ := cmd.StderrPipe()
stderrScanner := bufio.NewScanner(stderrReader)
go func() {
for stderrScanner.Scan() {
fmt.Println(stderrScanner.Text())
}
}()
err := cmd.Start()
if err != nil {
return GenErrorMsg(EXEC_ERROR, err.Error())
}
// Stuck here until there are out and err
err = cmd.Wait()
if err != nil {
return GenErrorMsg(EXEC_ERROR, err.Error())
}
return nil
}

View File

@@ -0,0 +1,17 @@
package utils
import (
"os/exec"
"testing"
)
func TestRun(t *testing.T) {
// Just make sure there is no error...
testCmd := exec.Command("ls")
err := Run(testCmd, nil)
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
}

22
krew/pkg/utils/error.go Normal file
View File

@@ -0,0 +1,22 @@
package utils
import (
"errors"
"fmt"
)
const (
// For errors about kustomize
TEMPLATE_ERROR = "template error"
// For errors about file system
FILE_ERROR = "file system error"
// For errors about create/delete/... resources in cluster
SERVER_ERROR = "cluster operation error"
// For exec errors
EXEC_ERROR = "exec error"
)
func GenErrorMsg(errType, customMsg string) error {
errorMsg := fmt.Sprintf("[ERROR] %s: %s", errType, customMsg)
return errors.New(errorMsg)
}

View File

@@ -0,0 +1,38 @@
package utils
import (
"strings"
"testing"
)
func TestServerGenErrorMsg(t *testing.T) {
expectedErr := GenErrorMsg(SERVER_ERROR, "test for server")
if !strings.Contains(expectedErr.Error(), SERVER_ERROR) {
t.Logf("server error generate failed")
t.FailNow()
}
}
func TestTemplateGenErrorMsg(t *testing.T) {
expectedErr := GenErrorMsg(TEMPLATE_ERROR, "test for template")
if !strings.Contains(expectedErr.Error(), TEMPLATE_ERROR) {
t.Logf("template error generate failed")
t.FailNow()
}
}
func TestExecGenErrorMsg(t *testing.T) {
expectedErr := GenErrorMsg(EXEC_ERROR, "test for exec")
if !strings.Contains(expectedErr.Error(), EXEC_ERROR) {
t.Logf("error error generate failed")
t.FailNow()
}
}
func TestFileGenErrorMsg(t *testing.T) {
expectedErr := GenErrorMsg(FILE_ERROR, "test for file")
if !strings.Contains(expectedErr.Error(), FILE_ERROR) {
t.Logf("file error generate failed")
t.FailNow()
}
}

83
krew/pkg/utils/fileSys.go Normal file
View File

@@ -0,0 +1,83 @@
package utils
import (
"io"
"io/fs"
"path"
"strings"
"github.com/RayWangQvQ/BiliBiliToolPro/krew/pkg/resources"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
var assetFS = resources.GetStaticResources()
// GetResourceFileSys file
func GetResourceFileSys() (filesys.FileSystem, error) {
inDiskSys := filesys.MakeFsOnDisk()
// copy from the resources into the target folder on the in memory FS
if err := copyDirtoDiskFS(".", "bilipro", inDiskSys); err != nil {
return nil, GenErrorMsg(FILE_ERROR, err.Error())
}
return inDiskSys, nil
}
func copyFileToDiskFS(src, dst string, diskFS filesys.FileSystem) error {
// skip all .go files
if strings.HasSuffix(src, ".go") {
return nil
}
var err error
var srcFileDesc fs.File
var dstFileDesc filesys.File
if srcFileDesc, err = assetFS.Open(src); err != nil {
return GenErrorMsg(FILE_ERROR, err.Error())
}
defer srcFileDesc.Close()
if dstFileDesc, err = diskFS.Create(dst); err != nil {
return GenErrorMsg(FILE_ERROR, err.Error())
}
defer dstFileDesc.Close()
// Note: I had to read the whole string, for some reason io.Copy was not copying the whole content
input, err := io.ReadAll(srcFileDesc)
if err != nil {
return GenErrorMsg(FILE_ERROR, err.Error())
}
_, err = dstFileDesc.Write(input)
if err != nil {
return GenErrorMsg(FILE_ERROR, err.Error())
}
return nil
}
func copyDirtoDiskFS(src string, dst string, diskFS filesys.FileSystem) error {
var err error
var fds []fs.DirEntry
if err = diskFS.MkdirAll(dst); err != nil {
return GenErrorMsg(FILE_ERROR, err.Error())
}
if fds, err = assetFS.ReadDir(src); err != nil {
return GenErrorMsg(FILE_ERROR, err.Error())
}
for _, fd := range fds {
srcfp := path.Join(src, fd.Name())
dstfp := path.Join(dst, fd.Name())
if fd.IsDir() {
if err = copyDirtoDiskFS(srcfp, dstfp, diskFS); err != nil {
return GenErrorMsg(FILE_ERROR, err.Error())
}
} else {
if err = copyFileToDiskFS(srcfp, dstfp, diskFS); err != nil {
return GenErrorMsg(FILE_ERROR, err.Error())
}
}
}
return nil
}

View File

@@ -0,0 +1,88 @@
package utils
import (
"io"
"os"
"path/filepath"
"testing"
"sigs.k8s.io/kustomize/kyaml/filesys"
)
func TestCopyFiletoDiskFS(t *testing.T) {
expectedFile, err := assetFS.Open("base/ns/namespace.yaml")
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
expectedOutput, err := io.ReadAll(expectedFile)
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
dir, err := os.Getwd()
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
inDiskSys := filesys.MakeFsOnDisk()
err = copyFileToDiskFS("base/ns/namespace.yaml", filepath.Join(dir, "fixtures/testNamespace.yaml"), inDiskSys)
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
actualOutput, err := os.ReadFile(filepath.Join(dir, "fixtures/testNamespace.yaml"))
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
if string(expectedOutput) != string(actualOutput) {
t.Logf("test failed due to copy file failed")
t.FailNow()
}
}
func TestCopyDirtoDiskFS(t *testing.T) {
expectedFile, err := assetFS.Open("base/bilibiliPro/deployment.yaml")
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
expectedOutput, err := io.ReadAll(expectedFile)
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
dir, err := os.Getwd()
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
inDiskSys := filesys.MakeFsOnDisk()
err = copyDirtoDiskFS("base/bilibiliPro", filepath.Join(dir, "fixtures"), inDiskSys)
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
actualOutput, err := os.ReadFile(filepath.Join(dir, "fixtures/deployment.yaml"))
if err != nil {
t.Logf("test failed due to %s", err.Error())
t.FailNow()
}
if string(expectedOutput) != string(actualOutput) {
t.Logf("test failed due to copy file failed")
t.FailNow()
}
}