Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Reports/output.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Name,Spdxid,Version,License,Copyright
glibc,SPDXRef-Package,2.11.1,(LGPL-2.0-only OR LicenseRef-3),Copyright 2008-2010 John Smith
Apache Commons Lang,SPDXRef-fromDoap-1,,NOASSERTION,NOASSERTION
Jena,SPDXRef-fromDoap-0,,NOASSERTION,NOASSERTION
Saxon,SPDXRef-Saxon,8.8,MPL-1.0,Copyright Saxonica Ltd
57 changes: 57 additions & 0 deletions Reports/output.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

<!DOCTYPE html>
<html>
<head>
<title>SPDX Export</title>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid black; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>SPDX Data Export</h1>
<table>
<tr>
<th>Name</th>
<th>Spdxid</th>
<th>Version</th>
<th>License</th>
<th>Copyright</th>
</tr>

<tr>
<td>glibc</td>
<td>SPDXRef-Package</td>
<td>2.11.1</td>
<td>(LGPL-2.0-only OR LicenseRef-3)</td>
<td>Copyright 2008-2010 John Smith</td>
</tr>

<tr>
<td>Apache Commons Lang</td>
<td>SPDXRef-fromDoap-1</td>
<td></td>
<td>NOASSERTION</td>
<td>NOASSERTION</td>
</tr>

<tr>
<td>Jena</td>
<td>SPDXRef-fromDoap-0</td>
<td></td>
<td>NOASSERTION</td>
<td>NOASSERTION</td>
</tr>

<tr>
<td>Saxon</td>
<td>SPDXRef-Saxon</td>
<td>8.8</td>
<td>MPL-1.0</td>
<td>Copyright Saxonica Ltd</td>
</tr>

</table>
</body>
</html>
88 changes: 88 additions & 0 deletions cmd/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
// Copyright © 2023 Dinesh Ravi dineshr93@gmail.com
// SPDX-FileCopyrightText: 2023 Dinesh Ravi
//
// SPDX-License-Identifier: Apache-2.0

package cmd

import (
"fmt"
"os"
"path/filepath"
"strings"
"github.com/dineshr93/sq/model"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var exportCmd = &cobra.Command{
Use: "export",
Short: "Export SPDX data to different formats",
Long: `Export SPDX data in different formats

For Ex:
To export as CSV : ./sq export -f csv -o output.csv
To export as HTML : ./sq export -f html -o output.html`,
Run: func(cmd *cobra.Command, args []string) {
dataFile := string(viper.ConfigFileUsed())
s := &model.SPDX{}
if err := s.Load(dataFile); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}

format, _ := cmd.Flags().GetString("format")
output, _ := cmd.Flags().GetString("output")

// Create Reports directory if it doesn't exist
reportsDir := "Reports"
if err := os.MkdirAll(reportsDir, 0755); err != nil {
fmt.Fprintln(os.Stderr, "Error creating Reports directory:", err)
os.Exit(1)
}

// Construct full path with Reports directory
output = filepath.Join(reportsDir, output)

if !isValidOutputFile(output, format) {
fmt.Fprintf(os.Stderr, "Error: Output file extension doesn't match format %s\n", format)
os.Exit(1)
}

switch format {
case "csv":
if err := s.ExportToCSV(output); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
fmt.Printf("Successfully exported to CSV: %s\n", output)
case "html":
if err := s.ExportToHTML(output); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
os.Exit(1)
}
fmt.Printf("Successfully exported to HTML: %s\n", output)
default:
fmt.Fprintf(os.Stderr, "unsupported format: %s\n", format)
os.Exit(1)
}
},
}

func init() {
rootCmd.AddCommand(exportCmd)
exportCmd.Flags().StringP("format", "f", "csv", "Export format (csv/html)")
exportCmd.Flags().StringP("output", "o", "export.csv", "Output file path")
}

func isValidOutputFile(outputFile, format string) bool {
ext := filepath.Ext(strings.TrimSpace(outputFile))
switch format {
case "csv":
return ext == ".csv"
case "html":
return ext == ".html"
default:
return false
}
}
124 changes: 124 additions & 0 deletions model/export.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright © 2023 Dinesh Ravi dineshr93@gmail.com
// SPDX-FileCopyrightText: 2023 Dinesh Ravi
//
// SPDX-License-Identifier: Apache-2.0

package model

import (
"encoding/csv"
"html/template"
"os"
"github.com/alexeyco/simpletable"
)

// ExportToCSV exports SPDX data to CSV format
func (s *SPDX) ExportToCSV(filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()

writer := csv.NewWriter(file)
defer writer.Flush()

// Write headers
headers := []string{"Name", "Spdxid", "Version", "License", "Copyright"}
if err := writer.Write(headers); err != nil {
return err
}

// Write package data
for _, pkg := range s.Packages {
row := []string{
pkg.Name,
pkg.Spdxid,
pkg.VersionInfo,
pkg.LicenseConcluded,
pkg.CopyrightText,
}
if err := writer.Write(row); err != nil {
return err
}
}
return nil
}

// ExportToHTML exports SPDX data to HTML format
func (s *SPDX) ExportToHTML(filename string) error {
file, err := os.Create(filename)
if err != nil {
return err
}
defer file.Close()

// Create preview table
table := simpletable.New()
table.Header = &simpletable.Header{
Cells: []*simpletable.Cell{
{Text: "Name"},
{Text: "Spdxid"},
{Text: "Version"},
{Text: "License"},
{Text: "Copyright"},
},
}

// Initialize table body
table.Body = &simpletable.Body{
Cells: make([][]*simpletable.Cell, 0),
}

for _, pkg := range s.Packages {
row := []*simpletable.Cell{
{Text: pkg.Name},
{Text: pkg.Spdxid},
{Text: pkg.VersionInfo},
{Text: pkg.LicenseConcluded},
{Text: pkg.CopyrightText},
}
table.Body.Cells = append(table.Body.Cells, row)
}

const htmlTemplate = `
<!DOCTYPE html>
<html>
<head>
<title>SPDX Export</title>
<style>
table { border-collapse: collapse; width: 100%; }
th, td { border: 1px solid black; padding: 8px; text-align: left; }
th { background-color: #f2f2f2; }
</style>
</head>
<body>
<h1>SPDX Data Export</h1>
<table>
<tr>
<th>Name</th>
<th>Spdxid</th>
<th>Version</th>
<th>License</th>
<th>Copyright</th>
</tr>
{{range .Packages}}
<tr>
<td>{{.Name}}</td>
<td>{{.Spdxid}}</td>
<td>{{.VersionInfo}}</td>
<td>{{.LicenseConcluded}}</td>
<td>{{.CopyrightText}}</td>
</tr>
{{end}}
</table>
</body>
</html>`

tmpl, err := template.New("export").Parse(htmlTemplate)
if err != nil {
return err
}

return tmpl.Execute(file, s)
}