-
Notifications
You must be signed in to change notification settings - Fork 85
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
15 changed files
with
1,075 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
package export | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
|
||
"github.com/opencontrol/compliance-masonry/pkg/cli/clierrors" | ||
"github.com/opencontrol/compliance-masonry/tools/constants" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// docxtemplater boolean variable | ||
var docxtemplater bool | ||
|
||
// flatten boolean variable | ||
var flattenFlag bool | ||
|
||
// keys boolen flag | ||
var keysFlag bool | ||
|
||
// NewCmdGet gets all the compliance dependencies | ||
func NewCmdExport(out io.Writer) *cobra.Command { | ||
cmd := &cobra.Command{ | ||
Use: "export", | ||
Short: "Export to consolidated output", | ||
Run: func(cmd *cobra.Command, args []string) { | ||
err := RunExport(out, cmd, args) | ||
clierrors.CheckError(err) | ||
}, | ||
} | ||
cmd.Flags().StringP("opencontrol", "o", constants.DefaultDestination, "Set opencontrol directory") | ||
cmd.Flags().StringP("dest", "d", constants.DefaultJSONFile, "Destination file for output") | ||
cmd.Flags().BoolVarP(&flattenFlag, "flatten", "n", false, "Flatten results file") | ||
cmd.Flags().StringP("format", "f", constants.DefaultOutputFormat, "Output format for destination file") | ||
cmd.Flags().BoolVarP(&keysFlag, "keys", "k", false, "Keys to use when processing arrays while flattening") | ||
cmd.Flags().BoolVarP(&docxtemplater, "docxtemplater", "x", false, "Use docxtemplater format") | ||
cmd.Flags().StringP("separator", "s", constants.DefaultKeySeparator, "Separator to use when flattening keys") | ||
return cmd | ||
} | ||
|
||
func RunExport(out io.Writer, cmd *cobra.Command, args []string) error { | ||
if len(args) == 0 { | ||
return fmt.Errorf("certification type not specified") | ||
} | ||
|
||
// read parms | ||
parmOpencontrols := cmd.Flag("opencontrols").Value.String() | ||
parmDestination := cmd.Flag("destination").Value.String() | ||
parmOutputFormat := cmd.Flag("format").Value.String() | ||
parmFlatten := false | ||
parmInferKeys := false | ||
parmDocxtemplater := false | ||
parmKeySeparator := cmd.Flag("separator").Value.String() | ||
|
||
// convert to enum | ||
outputFormat, err := ToOutputFormat(parmOutputFormat) | ||
if err != nil { | ||
return clierrors.NewExitError(err.Error(), 1) | ||
} | ||
|
||
// --docxtemplater always forces --flatten | ||
if parmDocxtemplater { | ||
parmFlatten = true | ||
} | ||
|
||
// construct args | ||
config := Config{ | ||
Certification: args[0], | ||
OpencontrolDir: parmOpencontrols, | ||
DestinationFile: parmDestination, | ||
OutputFormat: outputFormat, | ||
Flatten: parmFlatten, | ||
InferKeys: parmInferKeys, | ||
Docxtemplater: parmDocxtemplater, | ||
KeySeparator: parmKeySeparator, | ||
} | ||
|
||
// invoke command | ||
errs := Export(config) | ||
if errs != nil && len(errs) > 0 { | ||
err := clierrors.NewMultiError(errs...) | ||
return clierrors.NewExitError(err.Error(), 1) | ||
} | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
package export | ||
|
||
import ( | ||
"bufio" | ||
"bytes" | ||
"encoding/json" | ||
"errors" | ||
"fmt" | ||
"gopkg.in/yaml.v2" | ||
"io" | ||
"log" | ||
"os" | ||
"strings" | ||
|
||
"github.com/opencontrol/compliance-masonry/pkg/lib" | ||
"github.com/opencontrol/compliance-masonry/pkg/lib/common" | ||
"github.com/opencontrol/compliance-masonry/tools/certifications" | ||
) | ||
|
||
//////////////////////////////////////////////////////////////////////// | ||
// Package functions | ||
|
||
// exportJSON - JSON output | ||
func exportJSON(config *Config, workspace common.Workspace, output *exportOutput, writer io.Writer) []error { | ||
// result | ||
var errors []error | ||
|
||
// work vars | ||
var byteSlice []byte | ||
var err error | ||
|
||
// do the work | ||
byteSlice, err = json.Marshal(output) | ||
if err != nil { | ||
return returnErrors(err) | ||
} | ||
|
||
// flatten output? | ||
if config.Flatten { | ||
if config.Debug { | ||
log.Println("JSON: Flatten") | ||
} | ||
|
||
// decode json first | ||
mapped := map[string]interface{}{} | ||
err = json.Unmarshal(byteSlice, &mapped) | ||
if err != nil { | ||
return returnErrors(err) | ||
} | ||
|
||
// flatten the JSON (recursive) | ||
var flattened = make(map[string]interface{}) | ||
var lkey string | ||
err := flatten(config, mapped, lkey, &flattened) | ||
if err != nil { | ||
return returnErrors(err) | ||
} | ||
var flattenedByteSlice []byte | ||
flattenedByteSlice, err = json.Marshal(flattened) | ||
if err != nil { | ||
return returnErrors(err) | ||
} | ||
writer.Write(flattenedByteSlice) | ||
} else { | ||
// direct output | ||
writer.Write(byteSlice) | ||
} | ||
|
||
return errors | ||
} | ||
|
||
// exportYAML - YAML output | ||
func exportYAML(config *Config, workspace common.Workspace, output *exportOutput, writer io.Writer) []error { | ||
// result | ||
var dummyErrors []error | ||
|
||
// work vars | ||
var byteSlice []byte | ||
var err error | ||
|
||
// do the work | ||
byteSlice, err = yaml.Marshal(output) | ||
if err != nil { | ||
return returnErrors(err) | ||
} | ||
|
||
// flatten output? | ||
if config.Flatten { | ||
// we do not support flatten for YAML - returns 'map[interface {}]interface {}' | ||
return returnErrors(errors.New("--flatten unsupported for YAML")) | ||
} | ||
// direct output | ||
writer.Write(byteSlice) | ||
|
||
// just so we can return an empty array (not nil) | ||
return dummyErrors | ||
} | ||
|
||
// internal - handle export | ||
func export(config *Config, workspace common.Workspace) []error { | ||
// sanity | ||
if len(strings.TrimSpace(config.DestinationFile)) == 0 { | ||
return returnErrors(errors.New("empty destination files")) | ||
} | ||
|
||
// create our work object | ||
var output exportOutput | ||
output.Config = config | ||
output.Data.Certification = workspace.GetCertification() | ||
output.Data.Components = workspace.GetAllComponents() | ||
output.Data.Standards = workspace.GetAllStandards() | ||
|
||
// handle output destination | ||
var writer io.Writer | ||
if config.DestinationFile == "-" { | ||
// send to stdout | ||
writer = os.Stdout | ||
} else if config.DestinationFile == "-str-" { | ||
// send to null buffer | ||
var b bytes.Buffer | ||
writer = bufio.NewWriter(&b) | ||
} else { | ||
// send to file | ||
file, err := os.Create(config.DestinationFile) | ||
if err != nil { | ||
return returnErrors(err) | ||
} | ||
writer = file | ||
defer file.Close() | ||
} | ||
|
||
// handle the output | ||
switch config.OutputFormat { | ||
case FormatJSON: | ||
return exportJSON(config, workspace, &output, writer) | ||
case FormatYAML: | ||
return exportYAML(config, workspace, &output, writer) | ||
default: | ||
return returnErrors(fmt.Errorf("unsupported OutputFormat '%s'", config.OutputFormat)) | ||
} | ||
} | ||
|
||
// Export loads the inventory and writes output to destinaation | ||
func Export(config Config) []error { | ||
// resolve the actual certification to use | ||
certificationPath, errs := certifications.GetCertification(config.OpencontrolDir, config.Certification) | ||
if errs != nil && len(errs) > 0 { | ||
return errs | ||
} | ||
|
||
// load all workspace data | ||
workspace, errs := lib.LoadData(config.OpencontrolDir, certificationPath) | ||
if errs != nil && len(errs) > 0 { | ||
return errs | ||
} | ||
|
||
// retrieve workspace data and write to output | ||
return export(&config, workspace) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package export | ||
|
||
import ( | ||
"bytes" | ||
"encoding/json" | ||
|
||
lib_certifications "github.com/opencontrol/compliance-masonry/pkg/lib/certifications" | ||
"github.com/opencontrol/compliance-masonry/pkg/lib/common" | ||
) | ||
|
||
//////////////////////////////////////////////////////////////////////// | ||
// Package structures | ||
|
||
// Config contains settings for this object | ||
type Config struct { | ||
Debug bool | ||
// remainder are configuration settings local to Export | ||
Certification string | ||
OpencontrolDir string | ||
DestinationFile string | ||
OutputFormat OutputFormat | ||
Flatten bool | ||
InferKeys bool | ||
Docxtemplater bool | ||
KeySeparator string | ||
} | ||
|
||
// internal - structure for JSON / YAML output | ||
type exportData struct { | ||
Certification common.Certification | ||
Components []common.Component | ||
Standards []common.Standard | ||
} | ||
|
||
// MarshalJSON provides JSON support | ||
func (p *exportData) MarshalJSON() (b []byte, e error) { | ||
// start the output | ||
buffer := bytes.NewBufferString("{") | ||
|
||
// certification | ||
buffer.WriteString("\"certification\":") | ||
bytesJSON, err := lib_certifications.MarshalJSON(p.Certification) | ||
if err != nil { | ||
return nil, err | ||
} | ||
buffer.WriteString(string(bytesJSON)) | ||
|
||
// iterate over components | ||
if len(p.Components) > 0 { | ||
buffer.WriteString(",\"components\":[") | ||
for i, v := range p.Components { | ||
bytesJSON, err := json.Marshal(v) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if i > 0 { | ||
buffer.WriteString(",") | ||
} | ||
buffer.WriteString(string(bytesJSON)) | ||
} | ||
buffer.WriteString("]") | ||
} | ||
|
||
// iterate over standards | ||
if len(p.Standards) > 0 { | ||
buffer.WriteString(",\"standards\":[") | ||
for i, v := range p.Standards { | ||
bytesJSON, err := json.Marshal(v) | ||
if err != nil { | ||
return nil, err | ||
} | ||
if i > 0 { | ||
buffer.WriteString(",") | ||
} | ||
buffer.WriteString(string(bytesJSON)) | ||
} | ||
buffer.WriteString("]") | ||
} | ||
|
||
// finish json | ||
buffer.WriteString("}") | ||
return buffer.Bytes(), nil | ||
} | ||
|
||
// internal - structure for all exported data | ||
type exportOutput struct { | ||
Config *Config | ||
Data exportData | ||
} | ||
|
||
// MarshalJSON provides JSON support | ||
func (p *exportOutput) MarshalJSON() (b []byte, e error) { | ||
// start the output | ||
buffer := bytes.NewBufferString("{") | ||
|
||
// config section | ||
buffer.WriteString("\"config\":") | ||
bytesConfig, err := json.Marshal(p.Config) | ||
if err != nil { | ||
return nil, err | ||
} | ||
buffer.WriteString(string(bytesConfig)) | ||
|
||
// data section | ||
buffer.WriteString(",\"data\":") | ||
bytesData, err := json.Marshal(&p.Data) | ||
if err != nil { | ||
return nil, err | ||
} | ||
buffer.WriteString(string(bytesData)) | ||
|
||
// close output | ||
buffer.WriteString("}") | ||
return buffer.Bytes(), nil | ||
} |
Oops, something went wrong.