Skip to content

Commit 1df4611

Browse files
committed
feat: add support for build log output
1 parent 25033fc commit 1df4611

File tree

8 files changed

+88
-139
lines changed

8 files changed

+88
-139
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,6 @@ dist/
4242
# SIMPL+
4343
SPlsWork/
4444
*.ush
45+
46+
# Log files
47+
*.log

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ test:
5252
@go test ./...
5353

5454
test-coverage:
55-
@go test -race -coverprofile=coverage.out ./...
55+
# @go test -race -coverprofile=coverage.out ./...
5656
@go tool cover -html=coverage.out -o coverage.html
5757
@go tool cover -func=coverage.out | tail -1
5858

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ spc [command] [options] <file> [file...]
1515

1616
- `-t, --target string`: Target series to compile for (e.g., 3, 34, 234)
1717
- `-v, --verbose`: Verbose output
18+
- `-o, --out string`: Output file for compilation logs
1819
- `--version`: Show version information
1920

2021
### Examples

cmd/build.go

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010

1111
"github.com/spf13/cobra"
1212
"github.com/spf13/viper"
13+
14+
"github.com/Norgate-AV/spc/internal/codes"
1315
)
1416

1517
var buildCmd = &cobra.Command{
@@ -72,6 +74,8 @@ func runBuild(cmd *cobra.Command, args []string) error {
7274
// bind flag
7375
_ = viper.BindPFlag("target", cmd.Flags().Lookup("target"))
7476
_ = viper.BindPFlag("verbose", cmd.Flags().Lookup("verbose"))
77+
_ = viper.BindPFlag("silent", cmd.Flags().Lookup("silent"))
78+
_ = viper.BindPFlag("out", cmd.Flags().Lookup("out"))
7579
target := viper.GetString("target")
7680
if target == "" {
7781
return fmt.Errorf("target series not specified")
@@ -89,7 +93,7 @@ func runBuild(cmd *cobra.Command, args []string) error {
8993
cmdArgs = append(cmdArgs, "/target")
9094
cmdArgs = append(cmdArgs, series...)
9195
cmdArgs = append(cmdArgs, "/rebuild")
92-
96+
9397
for _, file := range args {
9498
absFile, err := filepath.Abs(file)
9599
if err != nil {
@@ -99,23 +103,41 @@ func runBuild(cmd *cobra.Command, args []string) error {
99103
cmdArgs = append(cmdArgs, absFile)
100104
}
101105

106+
out := viper.GetString("out")
107+
if out != "" {
108+
absOut, err := filepath.Abs(out)
109+
if err != nil {
110+
return fmt.Errorf("failed to resolve absolute path for output file: %w", err)
111+
}
112+
cmdArgs = append(cmdArgs, "/out", absOut)
113+
}
114+
115+
silent := viper.GetBool("silent")
116+
if silent {
117+
cmdArgs = append(cmdArgs, "/silent")
118+
}
119+
102120
if verbose {
103-
fmt.Printf("Compiler: %s\nTarget: %s\nSeries: %v\nFiles: %v\nCommand: %s %s\n", compiler, target, series, args, compiler, strings.Join(cmdArgs, " "))
121+
fmt.Printf("Compiler: %s\nTarget: %s\nSeries: %v\nFiles: %v\nOut: %s\nCommand: %s %s\n", compiler, target, series, args, out, compiler, strings.Join(cmdArgs, " "))
104122
}
105123

106124
c := execCommand(compiler, cmdArgs...)
107125
if cmd, ok := c.(*exec.Cmd); ok {
108126
cmd.Stdout = os.Stdout
109127
cmd.Stderr = os.Stderr
110128
}
111-
112129
err = c.Run()
113130
if err != nil {
114-
if exitErr, ok := err.(*exec.ExitError); ok && exitErr.ExitCode() == 116 {
115-
// Crestron compiler success code
116-
return nil
117-
}
131+
if exitErr, ok := err.(*exec.ExitError); ok {
132+
code := exitErr.ExitCode()
133+
if codes.IsSuccess(code) {
134+
// Crestron compiler success (may have warnings)
135+
return nil
136+
}
118137

138+
// Print descriptive error message
139+
fmt.Fprintf(os.Stderr, "Compilation failed (exit code %d): %s\n", code, codes.GetErrorMessage(code))
140+
}
119141
return err
120142
}
121143

cmd/root.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
var rootCmd = &cobra.Command{
1212
Use: "spc",
1313
Short: "Crestron SIMPL+ compiler wrapper",
14-
Long: `A CLI wrapper for the Crestron SIMPL+ compiler tool.`,
14+
Long: `A CLI wrapper for the Crestron SIMPL+ compiler`,
1515
RunE: runBuild,
1616
SilenceUsage: true,
1717
Args: cobra.ArbitraryArgs,
@@ -27,6 +27,8 @@ func Execute() {
2727
func init() {
2828
rootCmd.Version = fmt.Sprintf("%s (%s) %s", version.Version, version.Commit, version.BuildTime)
2929
rootCmd.PersistentFlags().StringP("target", "t", "", "Target series to compile for (e.g., 3, 34, 234)")
30+
rootCmd.PersistentFlags().BoolP("silent", "s", false, "Suppress console output from the SIMPL+ compiler")
3031
rootCmd.PersistentFlags().BoolP("verbose", "v", false, "Verbose output")
32+
rootCmd.PersistentFlags().StringP("out", "o", "", "Output file for compilation logs")
3133
rootCmd.AddCommand(buildCmd)
3234
}

example/example.usp

Lines changed: 0 additions & 130 deletions
Original file line numberDiff line numberDiff line change
@@ -1,130 +0,0 @@
1-
/*******************************************************************************************
2-
Compiler Directives
3-
(Uncomment and declare compiler directives as needed)
4-
*******************************************************************************************/
5-
// #ENABLE_DYNAMIC
6-
// #SYMBOL_NAME
7-
// #HINT ""
8-
// #DEFINE_CONSTANT
9-
// #CATEGORY
10-
#PRINT_TO_TRACE
11-
// #DIGITAL_EXPAND
12-
// #ANALOG_SERIAL_EXPAND
13-
// #OUTPUT_SHIFT
14-
// #HELP_PDF_FILE ""
15-
#DEFAULT_VOLATILE
16-
#ENABLE_STACK_CHECKING
17-
#ENABLE_TRACE
18-
#ENCODING_ASCII
19-
// #ENCODING_UTF16
20-
// #ENCODING_INHERIT_FROM_PARENT
21-
// #ENCODING_INHERIT_FROM_PROGRAM
22-
/*
23-
#HELP_BEGIN
24-
(add additional lines of help lines)
25-
#HELP_END
26-
*/
27-
28-
/*******************************************************************************************
29-
Include Libraries
30-
(Uncomment and include additional libraries as needed)
31-
*******************************************************************************************/
32-
// #CRESTRON_LIBRARY ""
33-
// #USER_LIBRARY ""
34-
35-
/*******************************************************************************************
36-
DIGITAL, ANALOG and SERIAL INPUTS and OUTPUTS
37-
(Uncomment and declare inputs and outputs as needed)
38-
*******************************************************************************************/
39-
// DIGITAL_INPUT
40-
// ANALOG_INPUT
41-
// STRING_INPUT
42-
// BUFFER_INPUT
43-
44-
// DIGITAL_OUTPUT
45-
// ANALOG_OUTPUT
46-
// STRING_OUTPUT
47-
48-
/*******************************************************************************************
49-
SOCKETS
50-
(Uncomment and define socket definitions as needed)
51-
*******************************************************************************************/
52-
// TCP_CLIENT
53-
// TCP_SERVER
54-
// UDP_SOCKET
55-
56-
/*******************************************************************************************
57-
Parameters
58-
(Uncomment and declare parameters as needed)
59-
*******************************************************************************************/
60-
// INTEGER_PARAMETER
61-
// SIGNED_INTEGER_PARAMETER
62-
// LONG_INTEGER_PARAMETER
63-
// SIGNED_LONG_INTEGER_PARAMETER
64-
// STRING_PARAMETER
65-
66-
/*******************************************************************************************
67-
Parameter Properties
68-
(Uncomment and declare parameter properties as needed)
69-
*******************************************************************************************/
70-
/*
71-
#BEGIN_PARAMETER_PROPERTIES parameter_variable, parameter_variable, ...
72-
// propValidUnits = // unitString or unitDecimal|unitHex|unitPercent|unitCharacter|unitTime|unitTicks;
73-
// propDefaultUnit = // unitString, unitDecimal, unitHex, unitPercent, unitCharacter, unitTime or unitTicks;
74-
// propBounds = lower_bound , upper_bound;
75-
// propDefaultValue = ; // or, propDefaultValue = "";
76-
// propList = // { "value" , "label" } , { "value" , "label" } , ... ;
77-
// propShortDescription = "status_bar_hint_text";
78-
// #BEGIN_PROP_FULL_DESCRIPTION line_1... line_2... line_n #END_PROP_FULL_DESCRIPTION
79-
// #BEGIN_PROP_NOTES line_1... line_2... line_n #END_PROP_NOTES
80-
#END_PARAMETER_PROPERTIES
81-
*/
82-
83-
/*******************************************************************************************
84-
Structure Definitions
85-
(Uncomment and define structure definitions as needed)
86-
Note: Be sure to initialize all declared STRING variables as needed
87-
For example, in Function Main: struct.myString = "";
88-
*******************************************************************************************/
89-
/*
90-
STRUCTURE MyStruct1
91-
{
92-
};
93-
94-
MyStruct1 struct;
95-
*/
96-
97-
/*******************************************************************************************
98-
Global Variables
99-
(Uncomment and declare global variables as needed)
100-
Note: Be sure to initialize all declared STRING variables as needed
101-
For example, in Function Main: myString = "";
102-
*******************************************************************************************/
103-
// INTEGER
104-
// LONG_INTEGER
105-
// SIGNED_INTEGER
106-
// SIGNED_LONG_INTEGER
107-
// STRING
108-
109-
/*******************************************************************************************
110-
Functions
111-
(Add any additional functions here)
112-
Note: Functions must be physically placed before the location in
113-
the code that calls them.
114-
*******************************************************************************************/
115-
116-
117-
/*******************************************************************************************
118-
Event Handlers
119-
(Uncomment and declare additional event handlers as needed)
120-
*******************************************************************************************/
121-
122-
123-
/*******************************************************************************************
124-
Main()
125-
Uncomment and place one-time startup code here
126-
(This code will get called when the system starts up)
127-
*******************************************************************************************/
128-
Function Main() {
129-
130-
}

internal/.gitkeep

Whitespace-only changes.

internal/codes/codes.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package codes
2+
3+
// ErrorCodes maps Crestron SIMPL+ compiler exit codes to their descriptions
4+
var ErrorCodes = map[int]string{
5+
0: "Success",
6+
100: "General failure",
7+
101: "Cannot open module",
8+
102: "Cannot create new makefile",
9+
103: "Cannot create new globals.h",
10+
104: "Cannot open master makefile",
11+
105: "Cannot write new makefile",
12+
106: "Compile errors",
13+
107: "Link errors",
14+
108: "Cannot copy output file to LinkMakeFileDir",
15+
109: "Cannot copy gnu files to LinkMakeFileDir",
16+
110: "Cannot launch gnu compiler",
17+
111: "Cannot retrieve total number of NVRam in module",
18+
112: "GNU not installed",
19+
113: "System.CodeDom.Compiler wrapper can not be instantiated",
20+
114: "The CompilerObj instance is invalid",
21+
115: "Invalid compiler results object",
22+
116: "The system.CodeDom.Compiler finished successfully, but with errors",
23+
117: "CompilerResult class is NULL or there is a problem with it",
24+
118: "Error extracting reference files from Include.dat",
25+
119: ".cs file doesn't exist",
26+
120: "Error launching NVRAM utility",
27+
121: "NVRAM Utility ran - no output generated",
28+
122: "Error saving temporary certificate file",
29+
123: "Invalid writer object",
30+
124: "Unable to create temporary file",
31+
125: "Unable to translate the certificate hex string to byte array",
32+
126: "Signing process failed",
33+
127: "Cleanup of the temp file failed",
34+
128: "The registry key for signing assemblies does not exist.",
35+
129: "CAPICOM is either not installed properly or not registered!",
36+
130: "Error found while signing. Unable to cleanup unsigned assembly.",
37+
}
38+
39+
// IsSuccess returns true if the exit code indicates successful compilation
40+
func IsSuccess(code int) bool {
41+
return code == 0 || code == 116
42+
}
43+
44+
// GetErrorMessage returns the error message for a given exit code, or a generic message if unknown
45+
func GetErrorMessage(code int) string {
46+
if msg, ok := ErrorCodes[code]; ok {
47+
return msg
48+
}
49+
50+
return "Unknown error"
51+
}

0 commit comments

Comments
 (0)