Skip to content

Commit 7303d6c

Browse files
Merge pull request #219 from azar-writes-code/feat-xmlconvert
feat: command `xmlconvert` and `customLicense` added to compage cli
2 parents 0ac2096 + bb0c053 commit 7303d6c

File tree

9 files changed

+365
-256
lines changed

9 files changed

+365
-256
lines changed

cmd/customLicense.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package cmd
2+
3+
import (
4+
"github.com/intelops/compage/cmd/subcommand/customLicense"
5+
"github.com/sirupsen/logrus"
6+
)
7+
8+
func init() {
9+
// Create the logger instance
10+
logger := logrus.New()
11+
logger.SetFormatter(&logrus.TextFormatter{
12+
FullTimestamp: true,
13+
TimestampFormat: "2006-01-02 15:04:05",
14+
})
15+
16+
// Create the instance for customlicense
17+
customlicense := customLicense.NewCustomLicenseCmd(logger)
18+
19+
// Add Subcommand for the root command
20+
rootCmd.AddCommand(customlicense.Execute())
21+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package customLicense
2+
3+
const exampleCommand = `
4+
# Convert XML file to JSON and YAML with the file path provided in the command line
5+
compage customLicense path=https://raw.githubusercontent.com/licenses/license-templates/master/templates/apache.txt projectPath=/some/local/path/LICENSE
6+
`
7+
var (
8+
path = "https://raw.githubusercontent.com/licenses/license-templates/master/templates/apache.txt"
9+
projectPath = "LICENSE"
10+
)
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
package customLicense
2+
3+
import (
4+
"io"
5+
"net/http"
6+
"os"
7+
"path/filepath"
8+
9+
"github.com/sirupsen/logrus"
10+
"github.com/spf13/cobra"
11+
)
12+
13+
type CustomLicenseCmd struct {
14+
logger *logrus.Logger
15+
}
16+
17+
func NewCustomLicenseCmd(logger *logrus.Logger) *CustomLicenseCmd {
18+
return &CustomLicenseCmd{
19+
logger: logger,
20+
}
21+
}
22+
23+
// Execute runs the xmlconvert command
24+
func (cl *CustomLicenseCmd) Execute() *cobra.Command {
25+
// Create a new cobra command for xmlconvert
26+
customLicenseCmd := &cobra.Command{
27+
Use: "customLicense",
28+
Short: "customLicense takes the public url of the license file and stores it in the specified path of the project",
29+
Long: `The 'customLicense' command retrieves a license file from a specified public URL and stores it in a designated path within your project. By default, it uses 'config.xml' for the license URL and 'config.yaml' for the project path, ensuring easy integration and updates of license files. This command includes pre-run validation and customizable flags for flexible usage.`,
30+
Example: exampleCommand,
31+
PreRun: cl.preRun, // Define a pre-run function
32+
Run: cl.run, // Define the run function
33+
}
34+
35+
// Define the flags for the xmlconvert command
36+
customLicenseCmd.Flags().StringVar(&path, "path", path, "please specify the public url of the license file. The default path is ``")
37+
customLicenseCmd.Flags().StringVar(&projectPath, "projectPath", projectPath, "Provide the project path to store the license file. The default path is ``")
38+
39+
return customLicenseCmd
40+
}
41+
42+
func (cl *CustomLicenseCmd) preRun(cmd *cobra.Command, args []string) {
43+
// Do any pre-run setup here
44+
yellow := "\033[33m"
45+
reset := "\033[0m"
46+
text := "WARNING: This command is in alpha version and may need some changes."
47+
cl.logger.Println(yellow + text + reset)
48+
}
49+
50+
func (cl *CustomLicenseCmd) run(cmd *cobra.Command, args []string) {
51+
// Ensure path is set
52+
if path == "" {
53+
cl.logger.Fatal("Path to the license file URL must be specified")
54+
}
55+
56+
// Use the current working directory if projectPath is not provided
57+
if projectPath == "" {
58+
cwd, err := os.Getwd()
59+
if err != nil {
60+
cl.logger.Fatalf("Failed to get the current working directory: %v", err)
61+
}
62+
projectPath = filepath.Join(cwd, "LICENSE")
63+
}
64+
65+
// Log the start of the process
66+
cl.logger.Println("Starting to download the license file from:", path)
67+
68+
// Create the HTTP request to fetch the license file
69+
response, err := http.Get(path)
70+
if err != nil {
71+
cl.logger.Fatalf("Failed to download the license file: %v", err)
72+
}
73+
defer response.Body.Close()
74+
75+
// Check if the HTTP request was successful
76+
if response.StatusCode != http.StatusOK {
77+
cl.logger.Fatalf("Failed to download the license file, HTTP Status: %s", response.Status)
78+
}
79+
80+
// Create the destination directory if it does not exist
81+
err = os.MkdirAll(filepath.Dir(projectPath), os.ModePerm)
82+
if err != nil {
83+
cl.logger.Fatalf("Failed to create the destination directory: %v", err)
84+
}
85+
86+
// Create the destination file
87+
outFile, err := os.Create(projectPath)
88+
if err != nil {
89+
cl.logger.Fatalf("Failed to create the destination file: %v", err)
90+
}
91+
defer outFile.Close()
92+
93+
// Copy the content from the response to the file
94+
_, err = io.Copy(outFile, response.Body)
95+
if err != nil {
96+
cl.logger.Fatalf("Failed to save the license file: %v", err)
97+
}
98+
99+
// Log the success of the operation
100+
cl.logger.Println("License file successfully downloaded and stored at:", projectPath)
101+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package xmlconvert
2+
3+
// xmlFile is the default path to the XML configuration file.
4+
var xmlFile = "config.xml"
5+
6+
// outputFiles is the default list of output file paths.
7+
var outputFiles = []string{
8+
"config.yaml",
9+
"config.json",
10+
}
11+
12+
var exampleCommand = `
13+
# Convert XML file to JSON and YAML with the file path provided in the command line
14+
compage xmlconvert --xmlFile config.xml
15+
16+
# Convert XML file to JSON and YAML with the provided output files with path name specified
17+
compage xmlconvert --xmlFile config.xml --outputFiles filename.yaml,filename.json
18+
`
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package xmlconvert
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"io"
7+
"os"
8+
9+
"github.com/clbanning/mxj/v2"
10+
"gopkg.in/yaml.v2"
11+
)
12+
13+
// ReadXML reads the XML file from the provided path and unmarshals it into a generic map.
14+
func ReadXML(filePath string) (map[string]interface{}, error) {
15+
// Open the XML file.
16+
xmlFile, err := os.Open(filePath)
17+
if err != nil {
18+
return nil, fmt.Errorf("failed to open XML file: %v", err)
19+
}
20+
defer xmlFile.Close()
21+
22+
// Read the XML file into a byte slice.
23+
byteValue, _ := io.ReadAll(xmlFile)
24+
25+
// Convert the XML file into a generic map.
26+
result, err := mxj.NewMapXml(byteValue)
27+
if err != nil {
28+
return nil, fmt.Errorf("failed to unmarshal XML: %v", err)
29+
}
30+
31+
return result, nil
32+
}
33+
34+
// WriteJSON writes the given data to a JSON file at the specified path.
35+
func WriteJSON(data map[string]interface{}, filePath string) error {
36+
// Marshal the data into a JSON byte slice with indentation.
37+
jsonData, err := json.MarshalIndent(data, "", " ")
38+
if err != nil {
39+
return fmt.Errorf("failed to marshal JSON: %v", err)
40+
}
41+
42+
// Write the JSON data to the specified file path.
43+
err = os.WriteFile(filePath, jsonData, 0644)
44+
if err != nil {
45+
return fmt.Errorf("failed to write JSON file: %v", err)
46+
}
47+
48+
return nil
49+
}
50+
51+
// WriteYAML writes the given data to a YAML file at the specified path.
52+
func WriteYAML(data map[string]interface{}, filePath string) error {
53+
// Marshal the data into a YAML byte slice.
54+
yamlData, err := yaml.Marshal(data)
55+
if err != nil {
56+
return fmt.Errorf("failed to marshal YAML: %v", err)
57+
}
58+
59+
// Write the YAML data to the specified file path.
60+
err = os.WriteFile(filePath, yamlData, 0644)
61+
if err != nil {
62+
return fmt.Errorf("failed to write YAML file: %v", err)
63+
}
64+
65+
return nil
66+
}
67+
68+
// CreateFile writes the given data to a file at the specified path based on the file extension.
69+
// Supported file extensions are "json" and "yaml".
70+
func CreateFile(data map[string]interface{}, filePath string, extension string) error {
71+
// Determine the file type based on the extension.
72+
switch extension {
73+
case "json":
74+
return WriteJSON(data, filePath)
75+
case "yaml":
76+
return WriteYAML(data, filePath)
77+
default:
78+
return fmt.Errorf("invalid file extension: %s", extension)
79+
}
80+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package xmlconvert
2+
3+
import (
4+
"strings"
5+
6+
"github.com/sirupsen/logrus"
7+
"github.com/spf13/cobra"
8+
)
9+
10+
// XMLConvertCmd represents the structure of the xmlconvert command
11+
type XMLConvertCmd struct {
12+
logger *logrus.Logger
13+
}
14+
15+
// NewXMLConvertCmd returns a new instance of XMLConvertCmd
16+
func NewXMLConvertCmd(logger *logrus.Logger) *XMLConvertCmd {
17+
return &XMLConvertCmd{
18+
logger: logger,
19+
}
20+
}
21+
22+
// Execute runs the xmlconvert command
23+
func (xml *XMLConvertCmd) Execute() *cobra.Command {
24+
// Create a new cobra command for xmlconvert
25+
xmlConvertCmd := &cobra.Command{
26+
Use: "xmlconvert",
27+
Short: "Convert XML to JSON and YAML",
28+
Long: "`xmlconvert` converts XML file provided in the command line arguments to JSON and YAML format. It can be used to convert XML file to JSON and YAML file.",
29+
Example: exampleCommand,
30+
PreRun: xml.preRun, // Define a pre-run function
31+
Run: xml.run, // Define the run function
32+
}
33+
34+
// Define the flags for the xmlconvert command
35+
xmlConvertCmd.Flags().StringVar(&xmlFile, "xmlFile", xmlFile, "provide xml file path to convert. The default path is `config.xml`")
36+
xmlConvertCmd.Flags().StringArrayVar(&outputFiles, "outputFiles", outputFiles, "returns converted output file. The default path is `config.yaml`")
37+
38+
return xmlConvertCmd
39+
}
40+
41+
// preRun is a pre-run function that logs a warning message
42+
func (xml *XMLConvertCmd) preRun(cmd *cobra.Command, args []string) {
43+
yellow := "\033[33m"
44+
reset := "\033[0m"
45+
text := "WARNING: This command is in alpha version and may need some changes."
46+
xml.logger.Println(yellow + text + reset)
47+
}
48+
49+
// run is the function that will be called when the xmlconvert command is executed
50+
func (xml *XMLConvertCmd) run(cmd *cobra.Command, args []string) {
51+
xmlData, err := ReadXML(xmlFile)
52+
if err != nil {
53+
xml.logger.Fatal(err)
54+
}
55+
xml.logger.Info("output files: ", outputFiles)
56+
57+
// Check if only two output files are supported
58+
if len(outputFiles) > 2 {
59+
xml.logger.Fatal("only two output file extensions are supported: json and yaml")
60+
}
61+
62+
// Check if output files are provided
63+
if len(outputFiles) == 0 {
64+
xml.logger.Fatal("please provide output file")
65+
}
66+
67+
// Check if only one output file is provided
68+
if len(outputFiles) == 1 {
69+
fileExtension := strings.Split(outputFiles[0], ".")[len(strings.Split(outputFiles[0], "."))-1]
70+
CreateFile(xmlData, outputFiles[0], fileExtension)
71+
} else {
72+
for _, file := range outputFiles {
73+
fileExtension := strings.Split(file, ".")[len(strings.Split(file, "."))-1]
74+
CreateFile(xmlData, file, fileExtension)
75+
}
76+
}
77+
}

cmd/xmlconvert.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package cmd
2+
3+
import (
4+
"github.com/intelops/compage/cmd/subcommand/xmlconvert"
5+
"github.com/sirupsen/logrus"
6+
)
7+
8+
func init() {
9+
// Create the logger instance
10+
logger := logrus.New()
11+
logger.SetFormatter(&logrus.TextFormatter{
12+
FullTimestamp: true,
13+
TimestampFormat: "2006-01-02 15:04:05",
14+
})
15+
16+
// Create the instance for xmlconvert
17+
xmlConvert := xmlconvert.NewXMLConvertCmd(logger)
18+
19+
// Add Subcommand for the root command
20+
rootCmd.AddCommand(xmlConvert.Execute())
21+
}

go.mod

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/intelops/compage
33
go 1.22
44

55
require (
6+
github.com/clbanning/mxj/v2 v2.7.0
67
github.com/fatih/color v1.16.0
78
github.com/gertd/go-pluralize v0.2.1
89
github.com/go-git/go-git/v5 v5.12.0
@@ -23,6 +24,7 @@ require (
2324
golang.org/x/text v0.14.0
2425
google.golang.org/grpc v1.62.1
2526
google.golang.org/protobuf v1.33.0
27+
gopkg.in/yaml.v2 v2.4.0
2628
gopkg.in/yaml.v3 v3.0.1
2729
oras.land/oras-go/v2 v2.5.0
2830
)
@@ -86,7 +88,6 @@ require (
8688
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
8789
github.com/cespare/xxhash/v2 v2.2.0 // indirect
8890
github.com/chrismellard/docker-credential-acr-env v0.0.0-20230304212654-82a0ddb27589 // indirect
89-
github.com/clbanning/mxj/v2 v2.7.0 // indirect
9091
github.com/cloudflare/circl v1.3.7 // indirect
9192
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
9293
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be // indirect
@@ -161,15 +162,13 @@ require (
161162
github.com/mailru/easyjson v0.7.7 // indirect
162163
github.com/mattn/go-colorable v0.1.13 // indirect
163164
github.com/mattn/go-isatty v0.0.20 // indirect
164-
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
165165
github.com/miekg/pkcs11 v1.1.1 // indirect
166166
github.com/mitchellh/go-homedir v1.1.0 // indirect
167167
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
168168
github.com/mitchellh/mapstructure v1.5.0 // indirect
169169
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
170170
github.com/modern-go/reflect2 v1.0.2 // indirect
171171
github.com/mozillazg/docker-credential-acr-helper v0.3.0 // indirect
172-
github.com/mpvl/unique v0.0.0-20150818121801-cbe035fff7de // indirect
173172
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
174173
github.com/nozzle/throttler v0.0.0-20180817012639-2ea982251481 // indirect
175174
github.com/oklog/ulid v1.3.1 // indirect
@@ -242,11 +241,9 @@ require (
242241
google.golang.org/appengine v1.6.8 // indirect
243242
google.golang.org/genproto/googleapis/api v0.0.0-20240401170217-c3f982113cda // indirect
244243
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
245-
gopkg.in/go-jose/go-jose.v2 v2.6.3 // indirect
246244
gopkg.in/inf.v0 v0.9.1 // indirect
247245
gopkg.in/ini.v1 v1.67.0 // indirect
248246
gopkg.in/warnings.v0 v0.1.2 // indirect
249-
gopkg.in/yaml.v2 v2.4.0 // indirect
250247
k8s.io/api v0.29.3 // indirect
251248
k8s.io/apimachinery v0.29.3 // indirect
252249
k8s.io/client-go v0.29.3 // indirect

0 commit comments

Comments
 (0)