chore: improve logging and add trace logging with --trace flag
This commit is contained in:
committed by
Mateusz Filipowicz
parent
399c5cde86
commit
f396b2f712
@@ -7,6 +7,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
log "github.com/sirupsen/logrus"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@@ -20,24 +21,6 @@ import (
|
|||||||
"github.com/xor-gate/ar"
|
"github.com/xor-gate/ar"
|
||||||
)
|
)
|
||||||
|
|
||||||
func sanitizeExtractedPath(filePath, destinationDir string) (string, error) {
|
|
||||||
absDestinationDir, err := filepath.Abs(destinationDir)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
absFilePath, err := filepath.Abs(filepath.Join(destinationDir, filePath))
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if !strings.HasPrefix(absFilePath, absDestinationDir) {
|
|
||||||
return "", fmt.Errorf("invalid file path: %s", filePath)
|
|
||||||
}
|
|
||||||
|
|
||||||
return absFilePath, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DownloadAndExtract(downloadUrl url.URL, outputDir string) error {
|
func DownloadAndExtract(downloadUrl url.URL, outputDir string) error {
|
||||||
targetInfo, err := os.Stat(outputDir)
|
targetInfo, err := os.Stat(outputDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -51,16 +34,19 @@ func DownloadAndExtract(downloadUrl url.URL, outputDir string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// download fields, create
|
// download fields, create
|
||||||
|
log.Debugf("downloading UniFi Controller package from: %s", downloadUrl.String())
|
||||||
jarFile, err := downloadJar(downloadUrl, outputDir)
|
jarFile, err := downloadJar(downloadUrl, outputDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("extracting JSON files with API structures from: %s to: %s", jarFile, outputDir)
|
||||||
err = extractJSON(jarFile, outputDir)
|
err = extractJSON(jarFile, outputDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.Debugf("JSON files extracted to: %s", outputDir)
|
||||||
targetInfo, err = os.Stat(outputDir)
|
targetInfo, err = os.Stat(outputDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -113,6 +99,7 @@ func downloadJar(downloadUrl url.URL, outputDir string) (string, error) {
|
|||||||
|
|
||||||
var aceJar *os.File
|
var aceJar *os.File
|
||||||
|
|
||||||
|
log.Debugln("extracting ace.jar from downloaded controller package")
|
||||||
for {
|
for {
|
||||||
header, err := tarReader.Next()
|
header, err := tarReader.Next()
|
||||||
if errors.Is(err, io.EOF) {
|
if errors.Is(err, io.EOF) {
|
||||||
@@ -142,10 +129,28 @@ func downloadJar(downloadUrl url.URL, outputDir string) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
defer aceJar.Close()
|
defer aceJar.Close()
|
||||||
|
log.Debugf("ace.jar extracted to: %s", aceJar.Name())
|
||||||
return aceJar.Name(), nil
|
return aceJar.Name(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sanitizeExtractedPath(filePath, destinationDir string) (string, error) {
|
||||||
|
absDestinationDir, err := filepath.Abs(destinationDir)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
absFilePath, err := filepath.Abs(filepath.Join(destinationDir, filepath.Base(filePath)))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.HasPrefix(absFilePath, absDestinationDir) {
|
||||||
|
return "", fmt.Errorf("invalid file path: %s", filePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
return absFilePath, nil
|
||||||
|
}
|
||||||
|
|
||||||
func extractJSON(jarFile, fieldsDir string) error {
|
func extractJSON(jarFile, fieldsDir string) error {
|
||||||
jarZip, err := zip.OpenReader(jarFile)
|
jarZip, err := zip.OpenReader(jarFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -153,6 +158,7 @@ func extractJSON(jarFile, fieldsDir string) error {
|
|||||||
}
|
}
|
||||||
defer jarZip.Close()
|
defer jarZip.Close()
|
||||||
|
|
||||||
|
log.Tracef("opened jar %s with %d files", jarFile, len(jarZip.File))
|
||||||
for _, f := range jarZip.File {
|
for _, f := range jarZip.File {
|
||||||
if !strings.HasPrefix(f.Name, "api/fields/") || path.Ext(f.Name) != ".json" {
|
if !strings.HasPrefix(f.Name, "api/fields/") || path.Ext(f.Name) != ".json" {
|
||||||
// skip file
|
// skip file
|
||||||
@@ -160,11 +166,11 @@ func extractJSON(jarFile, fieldsDir string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = func() error {
|
err = func() error {
|
||||||
|
log.Tracef("extracting %s", f.Name)
|
||||||
src, err := f.Open()
|
src, err := f.Open()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
dstPath, err := sanitizeExtractedPath(f.Name, fieldsDir)
|
dstPath, err := sanitizeExtractedPath(f.Name, fieldsDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -177,6 +183,7 @@ func extractJSON(jarFile, fieldsDir string) error {
|
|||||||
defer dst.Close()
|
defer dst.Close()
|
||||||
|
|
||||||
_, err = io.Copy(dst, src)
|
_, err = io.Copy(dst, src)
|
||||||
|
log.Debugf("extracted %s", f.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -202,18 +209,22 @@ func extractJSON(jarFile, fieldsDir string) error {
|
|||||||
return fmt.Errorf("unable to unmarshal settings: %w", err)
|
return fmt.Errorf("unable to unmarshal settings: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
for k, v := range settings {
|
log.Debugf("splitting Settings.json into individual setting files")
|
||||||
fileName := fmt.Sprintf("Setting%s.json", strcase.ToCamel(k))
|
for settingKey, settingValue := range settings {
|
||||||
|
settingName := strcase.ToCamel(settingKey)
|
||||||
|
fileName := fmt.Sprintf("Setting%s.json", settingName)
|
||||||
|
log.Tracef("splitting %s", fileName)
|
||||||
|
|
||||||
data, err := json.MarshalIndent(v, "", " ")
|
data, err := json.MarshalIndent(settingValue, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to marshal setting %q: %w", k, err)
|
return fmt.Errorf("unable to marshal setting %q: %w", settingKey, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
err = os.WriteFile(filepath.Join(fieldsDir, fileName), data, 0o755)
|
err = os.WriteFile(filepath.Join(fieldsDir, fileName), data, 0o755)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("unable to write new settings file: %w", err)
|
return fmt.Errorf("unable to write new settings file: %w", err)
|
||||||
}
|
}
|
||||||
|
log.Tracef("splitted %s into %s", settingKey, fileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cleanup JSON
|
// TODO: cleanup JSON
|
||||||
|
|||||||
@@ -278,7 +278,7 @@ func (r *Resource) fieldInfoFromValidation(name string, validation interface{})
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if validation != "" && normalized != "" {
|
if validation != "" && normalized != "" {
|
||||||
log.Debugf("normalize %q to %q", validation, normalized)
|
log.Tracef("normalize %q to %q", validation, normalized)
|
||||||
}
|
}
|
||||||
|
|
||||||
omitEmpty = omitEmpty || (!strings.Contains(validation, "^$") && !strings.HasSuffix(fieldName, "ID"))
|
omitEmpty = omitEmpty || (!strings.Contains(validation, "^$") && !strings.HasSuffix(fieldName, "ID"))
|
||||||
|
|||||||
@@ -18,13 +18,15 @@ func usage() {
|
|||||||
flag.PrintDefaults()
|
flag.PrintDefaults()
|
||||||
}
|
}
|
||||||
|
|
||||||
func setupLogging(debugEnabled bool) {
|
func setupLogging(debugEnabled, traceEnabled bool) {
|
||||||
log.SetFormatter(&log.TextFormatter{
|
log.SetFormatter(&log.TextFormatter{
|
||||||
DisableTimestamp: true,
|
DisableTimestamp: true,
|
||||||
DisableLevelTruncation: true,
|
DisableLevelTruncation: true,
|
||||||
FullTimestamp: false,
|
FullTimestamp: false,
|
||||||
})
|
})
|
||||||
if debugEnabled {
|
if traceEnabled {
|
||||||
|
log.SetLevel(log.TraceLevel)
|
||||||
|
} else if debugEnabled {
|
||||||
log.SetLevel(log.DebugLevel)
|
log.SetLevel(log.DebugLevel)
|
||||||
} else {
|
} else {
|
||||||
log.SetLevel(log.InfoLevel)
|
log.SetLevel(log.InfoLevel)
|
||||||
@@ -36,18 +38,19 @@ func main() {
|
|||||||
|
|
||||||
versionBaseDirFlag := flag.String("version-base-dir", ".", "The base directory for version JSON files")
|
versionBaseDirFlag := flag.String("version-base-dir", ".", "The base directory for version JSON files")
|
||||||
outputDirFlag := flag.String("output-dir", ".", "The output directory of the generated Go code")
|
outputDirFlag := flag.String("output-dir", ".", "The output directory of the generated Go code")
|
||||||
downloadOnly := flag.Bool("download-only", false, "Only download and build the fields JSON directory, do not generate")
|
downloadOnly := flag.Bool("download-only", false, "Only download and build the API structures JSON directory, do not generate")
|
||||||
debugFlag := flag.Bool("debug", false, "Enable debug logging")
|
debugFlag := flag.Bool("debug", false, "Enable debug logging")
|
||||||
|
traceFlag := flag.Bool("trace", false, "Enable trace logging")
|
||||||
|
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
setupLogging(*debugFlag)
|
setupLogging(*debugFlag, *traceFlag)
|
||||||
specifiedVersion := strings.TrimSpace(flag.Arg(0))
|
specifiedVersion := strings.TrimSpace(flag.Arg(0))
|
||||||
if specifiedVersion == "" {
|
if specifiedVersion == "" {
|
||||||
specifiedVersion = LatestVersionMarker // default to latest version
|
specifiedVersion = LatestVersionMarker // default to latest version
|
||||||
}
|
}
|
||||||
unifiVersion, err := determineUnifiVersion(specifiedVersion)
|
unifiVersion, err := determineUnifiVersion(specifiedVersion)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("unable to determine version and download URL for Unifi version %s", specifiedVersion)
|
log.Fatalf("unable to determine version and download URL for Unifi version %s: %s", specifiedVersion, err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -56,41 +59,40 @@ func main() {
|
|||||||
|
|
||||||
wd, err := os.Getwd()
|
wd, err := os.Getwd()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln("unable to determine working directory")
|
log.Fatalf("unable to determine working directory: %s", err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fieldsDir := filepath.Join(wd, *versionBaseDirFlag, fmt.Sprintf("v%s", unifiVersion.Version))
|
structuresDir := filepath.Join(wd, *versionBaseDirFlag, fmt.Sprintf("v%s", unifiVersion.Version))
|
||||||
log.Infoln("Downloading UniFi Controller field definitions...")
|
log.Infoln("Downloading UniFi Controller API structures definitions...")
|
||||||
err = DownloadAndExtract(*unifiVersion.DownloadUrl, fieldsDir)
|
err = DownloadAndExtract(*unifiVersion.DownloadUrl, structuresDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("unable to download and extract UniFi Controller field definitions: %s", err)
|
log.Fatalf("unable to download and extract UniFi Controller API structures definitions: %s", err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
log.Infof("Downloaded UniFi Controller field definitions in %s", fieldsDir)
|
log.Infof("Downloaded UniFi Controller API structures definitions in %s", structuresDir)
|
||||||
|
|
||||||
if *downloadOnly {
|
if *downloadOnly {
|
||||||
log.Infoln("Fields JSON ready!")
|
log.Infoln("Structure JSONs ready!")
|
||||||
os.Exit(0)
|
os.Exit(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infoln("Generating resources code...")
|
log.Infoln("Generating resources code...")
|
||||||
outDir := filepath.Join(wd, *outputDirFlag)
|
outDir := filepath.Join(wd, *outputDirFlag)
|
||||||
if err = generateCode(fieldsDir, outDir); err != nil {
|
if err = generateCode(structuresDir, outDir); err != nil {
|
||||||
log.Fatalln("unable to generate resources code")
|
log.Fatalf("unable to generate resources code: %s", err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Infof("Writing version file...")
|
log.Infof("Writing version file...")
|
||||||
if err = writeVersionFile(unifiVersion.Version, outDir); err != nil {
|
if err = writeVersionFile(unifiVersion.Version, outDir); err != nil {
|
||||||
log.Fatalf("failed to write version file to %s", outDir)
|
log.Fatalf("failed to write version file to %s: %s", outDir, err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
workingDir, _ := os.Getwd()
|
basepath := filepath.Dir(wd)
|
||||||
basepath := filepath.Dir(workingDir)
|
|
||||||
if err = writeVersionRepoMarkerFile(unifiVersion.Version, basepath); err != nil {
|
if err = writeVersionRepoMarkerFile(unifiVersion.Version, basepath); err != nil {
|
||||||
log.Fatalf("failed to write version file to %s", basepath)
|
log.Fatalf("failed to write version file to %s: %s", basepath, err)
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user