-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
[v3] Fix Linux Desktop Template & Windows NSIS Template Added #4510
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
d093ca2
b29f23b
5d0a77a
f244854
b2f289b
6eba4b1
5df53c3
f490768
6435b57
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,267 @@ | ||
| package commands | ||
|
|
||
| import ( | ||
| "os" | ||
| "path/filepath" | ||
| "testing" | ||
|
|
||
| "gopkg.in/yaml.v3" | ||
| ) | ||
|
|
||
| func TestGenerateBuildAssets(t *testing.T) { | ||
| // Create a temporary directory for testing | ||
| tempDir, err := os.MkdirTemp("", "wails-build-assets-test-*") | ||
| if err != nil { | ||
| t.Fatalf("Failed to create temp directory: %v", err) | ||
| } | ||
| defer os.RemoveAll(tempDir) | ||
|
|
||
| tests := []struct { | ||
| name string | ||
| options *BuildAssetsOptions | ||
| wantErr bool | ||
| }{ | ||
| { | ||
| name: "Basic build assets generation", | ||
| options: &BuildAssetsOptions{ | ||
| Dir: "testbuild", | ||
| Name: "TestApp", | ||
| BinaryName: "", | ||
| ProductName: "Test Application", | ||
| ProductDescription: "A test application", | ||
| ProductVersion: "1.0.0", | ||
| ProductCompany: "Test Company", | ||
| ProductCopyright: "© 2024 Test Company", | ||
| ProductComments: "Test comments", | ||
| ProductIdentifier: "", | ||
| Silent: true, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "Build assets with custom binary name", | ||
| options: &BuildAssetsOptions{ | ||
| Dir: "testbuild2", | ||
| Name: "Custom App", | ||
| BinaryName: "custom-binary", | ||
| ProductName: "Custom Application", | ||
| ProductDescription: "A custom application", | ||
| ProductVersion: "2.0.0", | ||
| ProductCompany: "Custom Company", | ||
| ProductIdentifier: "com.custom.app", | ||
| Silent: true, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "Build assets with MSIX options", | ||
| options: &BuildAssetsOptions{ | ||
| Dir: "testbuild3", | ||
| Name: "MSIX App", | ||
| ProductName: "MSIX Application", | ||
| ProductDescription: "An MSIX application", | ||
| ProductVersion: "3.0.0", | ||
| ProductCompany: "MSIX Company", | ||
| Publisher: "CN=MSIX Company", | ||
| ProcessorArchitecture: "x64", | ||
| ExecutablePath: "msix-app.exe", | ||
| ExecutableName: "msix-app.exe", | ||
| OutputPath: "msix-app.msix", | ||
| Silent: true, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "Build assets with TypeScript", | ||
| options: &BuildAssetsOptions{ | ||
| Dir: "testbuild4", | ||
| Name: "TypeScript App", | ||
| ProductName: "TypeScript Application", | ||
| ProductDescription: "A TypeScript application", | ||
| ProductVersion: "4.0.0", | ||
| ProductCompany: "TypeScript Company", | ||
| Typescript: true, | ||
| Silent: true, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| // Set the directory to be under our temp directory | ||
| buildDir := filepath.Join(tempDir, tt.options.Dir) | ||
| tt.options.Dir = buildDir | ||
|
|
||
| err := GenerateBuildAssets(tt.options) | ||
| if (err != nil) != tt.wantErr { | ||
| t.Errorf("GenerateBuildAssets() error = %v, wantErr %v", err, tt.wantErr) | ||
| return | ||
| } | ||
|
|
||
| if !tt.wantErr { | ||
| // Verify that the build directory was created | ||
| if _, err := os.Stat(buildDir); os.IsNotExist(err) { | ||
| t.Errorf("Build directory %s was not created", buildDir) | ||
| } | ||
|
|
||
| // List all files that were actually created for debugging | ||
| files, err := os.ReadDir(buildDir) | ||
| if err != nil { | ||
| t.Errorf("Failed to read build directory: %v", err) | ||
| } else { | ||
| t.Logf("Files created in %s:", buildDir) | ||
| for _, file := range files { | ||
| t.Logf(" - %s", file.Name()) | ||
| } | ||
| } | ||
|
|
||
| // Verify some expected files were created - check what actually exists | ||
| expectedFiles := []string{ | ||
| "config.yml", | ||
| "appicon.png", | ||
| "Taskfile.yml", | ||
| } | ||
|
|
||
| for _, file := range expectedFiles { | ||
| filePath := filepath.Join(buildDir, file) | ||
| if _, err := os.Stat(filePath); os.IsNotExist(err) { | ||
| t.Errorf("Expected file %s was not created", file) | ||
| } | ||
| } | ||
|
|
||
| // Test that defaults were applied correctly | ||
| if tt.options.ProductIdentifier == "" && tt.options.Name != "" { | ||
| expectedIdentifier := "com.wails." + normaliseName(tt.options.Name) | ||
| // We can't easily check this without modifying the function to return the config | ||
| // but we know the logic is there | ||
| _ = expectedIdentifier | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| } | ||
|
|
||
| func TestUpdateBuildAssets(t *testing.T) { | ||
| // Create a temporary directory for testing | ||
| tempDir, err := os.MkdirTemp("", "wails-update-assets-test-*") | ||
| if err != nil { | ||
| t.Fatalf("Failed to create temp directory: %v", err) | ||
| } | ||
| defer os.RemoveAll(tempDir) | ||
|
|
||
| // Create a sample wails config file | ||
| configDir := filepath.Join(tempDir, "config") | ||
| err = os.MkdirAll(configDir, 0755) | ||
| if err != nil { | ||
| t.Fatalf("Failed to create config directory: %v", err) | ||
| } | ||
|
|
||
| configFile := filepath.Join(configDir, "wails.yaml") | ||
| config := WailsConfig{ | ||
| Info: struct { | ||
| CompanyName string `yaml:"companyName"` | ||
| ProductName string `yaml:"productName"` | ||
| ProductIdentifier string `yaml:"productIdentifier"` | ||
| Description string `yaml:"description"` | ||
| Copyright string `yaml:"copyright"` | ||
| Comments string `yaml:"comments"` | ||
| Version string `yaml:"version"` | ||
| }{ | ||
| CompanyName: "Config Company", | ||
| ProductName: "Config Product", | ||
| ProductIdentifier: "com.config.product", | ||
| Description: "Config Description", | ||
| Copyright: "© 2024 Config Company", | ||
| Comments: "Config Comments", | ||
| Version: "1.0.0", | ||
| }, | ||
| FileAssociations: []FileAssociation{ | ||
| { | ||
| Ext: ".test", | ||
| Name: "Test File", | ||
| Description: "Test file association", | ||
| IconName: "test-icon", | ||
| Role: "Editor", | ||
| MimeType: "application/test", | ||
| }, | ||
| }, | ||
| Protocols: []ProtocolConfig{ | ||
| { | ||
| Scheme: "testapp", | ||
| Description: "Test App Protocol", | ||
| }, | ||
| }, | ||
| } | ||
|
|
||
| configBytes, err := yaml.Marshal(config) | ||
| if err != nil { | ||
| t.Fatalf("Failed to marshal config: %v", err) | ||
| } | ||
|
|
||
| err = os.WriteFile(configFile, configBytes, 0644) | ||
| if err != nil { | ||
| t.Fatalf("Failed to write config file: %v", err) | ||
| } | ||
|
|
||
| tests := []struct { | ||
| name string | ||
| options *UpdateBuildAssetsOptions | ||
| wantErr bool | ||
| }{ | ||
| { | ||
| name: "Update with config file", | ||
| options: &UpdateBuildAssetsOptions{ | ||
| Dir: "updatebuild1", | ||
| Name: "UpdateApp", | ||
| Config: configFile, | ||
| Silent: true, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "Update without config file", | ||
| options: &UpdateBuildAssetsOptions{ | ||
| Dir: "updatebuild2", | ||
| Name: "UpdateApp2", | ||
| ProductName: "Update Application 2", | ||
| ProductDescription: "An update application 2", | ||
| ProductVersion: "2.0.0", | ||
| ProductCompany: "Update Company 2", | ||
| Silent: true, | ||
| }, | ||
| wantErr: false, | ||
| }, | ||
| { | ||
| name: "Update with non-existent config file", | ||
| options: &UpdateBuildAssetsOptions{ | ||
| Dir: "updatebuild3", | ||
| Name: "UpdateApp3", | ||
| Config: "non-existent-config.yaml", | ||
| Silent: true, | ||
| }, | ||
| wantErr: true, | ||
| }, | ||
| } | ||
|
|
||
| for _, tt := range tests { | ||
| t.Run(tt.name, func(t *testing.T) { | ||
| // Set the directory to be under our temp directory | ||
| updateDir := filepath.Join(tempDir, tt.options.Dir) | ||
| tt.options.Dir = updateDir | ||
|
|
||
| err := UpdateBuildAssets(tt.options) | ||
| if (err != nil) != tt.wantErr { | ||
| t.Errorf("UpdateBuildAssets() error = %v, wantErr %v", err, tt.wantErr) | ||
| return | ||
| } | ||
|
|
||
| if !tt.wantErr { | ||
| // Verify that the update directory was created | ||
| if _, err := os.Stat(updateDir); os.IsNotExist(err) { | ||
| t.Errorf("Update directory %s was not created", updateDir) | ||
| } | ||
| } | ||
| }) | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -215,4 +215,32 @@ RequestExecutionLevel "${REQUEST_EXECUTION_LEVEL}" | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| !insertmacro APP_UNASSOCIATE "{{.Ext}}" "{{.Name}}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Delete "$INSTDIR\{{.IconName}}.ico" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {{end}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macroend | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macro CUSTOM_PROTOCOL_ASSOCIATE PROTOCOL DESCRIPTION ICON COMMAND | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" "" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macroend | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macro CUSTOM_PROTOCOL_UNASSOCIATE PROTOCOL | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macroend | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+220
to
+233
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Use SHCTX for registry root (or define SHELL_CONTEXT) to ensure correct per-user/all-users context NSIS supports the SHCTX root, which respects SetShellVarContext. Using unrecognized roots can break builds. This file’s earlier macros also use SHELL_CONTEXT; if that isn’t defined elsewhere, builds may fail. Two options:
Minimal global alias (outside the selected range; add near the top after includes): Alternatively, change within this block: - DeleteRegKey SHELL_CONTEXT "Software\Classes\${PROTOCOL}"
- WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}"
- WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}" "URL Protocol" ""
- WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}"
- WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell" "" ""
- WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open" "" ""
- WriteRegStr SHELL_CONTEXT "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}"
+ DeleteRegKey SHCTX "Software\Classes\${PROTOCOL}"
+ WriteRegStr SHCTX "Software\Classes\${PROTOCOL}" "" "${DESCRIPTION}"
+ WriteRegStr SHCTX "Software\Classes\${PROTOCOL}" "URL Protocol" ""
+ WriteRegStr SHCTX "Software\Classes\${PROTOCOL}\DefaultIcon" "" "${ICON}"
+ WriteRegStr SHCTX "Software\Classes\${PROTOCOL}\shell" "" ""
+ WriteRegStr SHCTX "Software\Classes\${PROTOCOL}\shell\open" "" ""
+ WriteRegStr SHCTX "Software\Classes\${PROTOCOL}\shell\open\command" "" "${COMMAND}"📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macro wails.associateCustomProtocols | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ; Create custom protocols associations | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {{range .Protocols}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !insertmacro CUSTOM_PROTOCOL_ASSOCIATE "{{.Scheme}}" "{{.Description}}" "$INSTDIR\${PRODUCT_EXECUTABLE},0" "$INSTDIR\${PRODUCT_EXECUTABLE} $\"%1$\"" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {{end}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macroend | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macro wails.unassociateCustomProtocols | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ; Delete app custom protocol associations | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {{range .Protocols}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !insertmacro CUSTOM_PROTOCOL_UNASSOCIATE "{{.Scheme}}" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| {{end}} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| !macroend | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
Tolfx marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Quote macro parameters with backticks to safely handle spaces and special chars
The existing APP_ASSOCIATE macro uses backticks when writing
${DESCRIPTION},${ICON},${COMMAND}. Mirror that here to avoid issues with spaces/quotes in descriptions or paths.Apply this diff:
If you adopt SHCTX per the previous comment, replace SHELL_CONTEXT with SHCTX accordingly in the same diff.
📝 Committable suggestion
🤖 Prompt for AI Agents