mirror of
https://github.com/mappu/miqt.git
synced 2025-02-08 22:10:23 +00:00
Merge pull request #167 from mappu/miqt-uic-rcc-updates
uic, rcc: Add -Qt6 flag, fix relative paths for embedding files
This commit is contained in:
commit
12df341a57
24
cmd/miqt-rcc/README.md
Normal file
24
cmd/miqt-rcc/README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
# miqt-rcc
|
||||||
|
|
||||||
|
The miqt-rcc program generates the necessary wrappers to use a Qt Designer `.qrc`
|
||||||
|
resource pack in MIQT `.go` files.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage of ./miqt-rcc:
|
||||||
|
-Input string
|
||||||
|
Path to .qrc input file
|
||||||
|
-OutputGo string
|
||||||
|
(Optional) Path to .go output file. If omitted, interred from the input file path
|
||||||
|
-OutputRcc string
|
||||||
|
(Optional) Path to .rcc output file. If omitted, inferred from the output Go file path
|
||||||
|
-Package string
|
||||||
|
Package to use in generated Go files (default "main")
|
||||||
|
-Qt6
|
||||||
|
Use Qt 6 instead of Qt 5
|
||||||
|
-RccBinary string
|
||||||
|
(Optional) Custom path to the Qt rcc program (default "rcc")
|
||||||
|
-VariableName string
|
||||||
|
Temporary global variable name for loading embedded data (default "_resourceRcc")
|
||||||
|
```
|
168
cmd/miqt-rcc/integration_test.go
Normal file
168
cmd/miqt-rcc/integration_test.go
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestRcc(t *testing.T) {
|
||||||
|
|
||||||
|
// Temporary directory
|
||||||
|
|
||||||
|
td := t.TempDir() // The go test package auto cleans this up
|
||||||
|
|
||||||
|
// Simulate working out of a Go module that has this miqt checkout as a
|
||||||
|
// local dependency
|
||||||
|
|
||||||
|
RccDir, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
fakeGoMod := `module miqt-rcc-integration-test
|
||||||
|
|
||||||
|
go 1.19
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/mappu/miqt v1.0.0
|
||||||
|
)
|
||||||
|
|
||||||
|
replace github.com/mappu/miqt => ` + filepath.Clean(RccDir+`/../../`) + `
|
||||||
|
`
|
||||||
|
err = ioutil.WriteFile(filepath.Join(td, `go.mod`), []byte(fakeGoMod), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add some test content
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(filepath.Join(td, "sample.data"), []byte("the quick brown fox jumps over the lazy dog"), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make a .qrc that includes this file
|
||||||
|
|
||||||
|
err = ioutil.WriteFile(filepath.Join(td, "resources.qrc"), []byte(
|
||||||
|
`<RCC>
|
||||||
|
<qresource prefix="/">
|
||||||
|
<file>sample.data</file>
|
||||||
|
</qresource>
|
||||||
|
</RCC>`), 0644)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build miqt-rcc and add it to our fake tools path
|
||||||
|
|
||||||
|
toolsDir := t.TempDir()
|
||||||
|
newPathEnv := "PATH=" + toolsDir + `:` + os.Getenv(`PATH`)
|
||||||
|
if runtime.GOOS == "windows" { // uses a different separator
|
||||||
|
newPathEnv = "PATH=" + toolsDir + `;` + os.Getenv(`PATH`)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("Compile miqt-rcc", func(t *testing.T) {
|
||||||
|
|
||||||
|
buildCmd := exec.Command(`go`, `build`, `-o`, filepath.Join(toolsDir, `miqt-rcc`))
|
||||||
|
buildCmd.Stderr = os.Stderr
|
||||||
|
buildCmd.Stdout = os.Stdout
|
||||||
|
err = buildCmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Initial build", func(t *testing.T) {
|
||||||
|
|
||||||
|
// Run miqt-rcc
|
||||||
|
|
||||||
|
rccCmd := exec.Command(filepath.Join(toolsDir, `miqt-rcc`), `-Input`, filepath.Join(td, `resources.qrc`), `-OutputGo`, filepath.Join(td, `resources.go`))
|
||||||
|
rccCmd.Stderr = os.Stderr
|
||||||
|
err = rccCmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that files are created
|
||||||
|
|
||||||
|
_, err = os.Stat(filepath.Join(td, `resources.rcc`))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("resources.rcc should exist: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
goResult, err := ioutil.ReadFile(filepath.Join(td, `resources.go`))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the go:embed line accurately used a relative path
|
||||||
|
|
||||||
|
if !strings.Contains(string(goResult), "//go:embed resources.rcc\n") {
|
||||||
|
t.Fatal("missing expected embed line")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the go:generate line matches our expectation
|
||||||
|
|
||||||
|
expect := `//go:generate miqt-rcc -Input "` + filepath.Join(td, `resources.qrc`) + `" -OutputGo "resources.go" -OutputRcc "resources.rcc"`
|
||||||
|
if !strings.Contains(string(goResult), expect) {
|
||||||
|
t.Fatal("missing expected generate line")
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("Go generate", func(t *testing.T) {
|
||||||
|
|
||||||
|
// Check timestamp before generation
|
||||||
|
|
||||||
|
fiBefore, err := os.Stat(filepath.Join(td, `resources.go`))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that `go generate` works
|
||||||
|
|
||||||
|
regenCmd := exec.Command(`go`, `generate`)
|
||||||
|
regenCmd.Env = []string{newPathEnv}
|
||||||
|
regenCmd.Dir = td
|
||||||
|
regenCmd.Stderr = os.Stderr
|
||||||
|
err = regenCmd.Run()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
goResult, err := ioutil.ReadFile(filepath.Join(td, `resources.go`))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify that the resources.go file was actually replaced
|
||||||
|
|
||||||
|
fiAfter, err := os.Stat(filepath.Join(td, `resources.go`))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fiAfter.ModTime().After(fiBefore.ModTime()) {
|
||||||
|
t.Errorf("expected mtime %v to be after original mtime %v", fiAfter.ModTime(), fiBefore.ModTime())
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the go:embed line accurately used a relative path
|
||||||
|
|
||||||
|
if !strings.Contains(string(goResult), "//go:embed resources.rcc\n") {
|
||||||
|
t.Fatal("missing expected embed line")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify the go:generate line matches our expectation
|
||||||
|
|
||||||
|
expect := `//go:generate miqt-rcc -Input "` + filepath.Join(td, `resources.qrc`) + `" -OutputGo "resources.go" -OutputRcc "resources.rcc"`
|
||||||
|
if !strings.Contains(string(goResult), expect) {
|
||||||
|
t.Fatal("missing expected generate line")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -9,61 +9,104 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
const (
|
||||||
|
DefaultPackageName string = "main"
|
||||||
|
DefaultVariableName string = "_resourceRcc"
|
||||||
|
DefaultIsQt6 bool = false
|
||||||
|
DefaultRccBinary string = "rcc"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RccExec() error {
|
||||||
|
|
||||||
// Parse arguments
|
// Parse arguments
|
||||||
|
|
||||||
input := flag.String("Input", "", "Path to .qrc input file")
|
input := flag.String("Input", "", "Path to .qrc input file")
|
||||||
outputRcc := flag.String("OutputRcc", "", "(Optional) Path to .rcc output file. If omitted, inferred from the input file path")
|
|
||||||
outputGo := flag.String("OutputGo", "", "(Optional) Path to .go output file. If omitted, interred from the input file path")
|
outputGo := flag.String("OutputGo", "", "(Optional) Path to .go output file. If omitted, interred from the input file path")
|
||||||
packageName := flag.String("Package", "main", "Package to use in generated Go files")
|
outputRcc := flag.String("OutputRcc", "", "(Optional) Path to .rcc output file. If omitted, inferred from the output Go file path")
|
||||||
variableName := flag.String("VariableName", "_resourceRcc", "Temporary global variable name for loading embedded data")
|
packageName := flag.String("Package", DefaultPackageName, "Package to use in generated Go files")
|
||||||
|
variableName := flag.String("VariableName", DefaultVariableName, "Temporary global variable name for loading embedded data")
|
||||||
|
useQt6 := flag.Bool("Qt6", DefaultIsQt6, "Use Qt 6 instead of Qt 5")
|
||||||
|
rccBinary := flag.String("RccBinary", DefaultRccBinary, "(Optional) Custom path to the Qt rcc program")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
// Check if input file exists
|
// Check if input file exists
|
||||||
|
|
||||||
if _, err := os.Stat(*input); os.IsNotExist(err) {
|
if _, err := os.Stat(*input); os.IsNotExist(err) {
|
||||||
fmt.Fprintf(os.Stderr, "Input file '%s' not found\n", *input)
|
return fmt.Errorf("Input file '%s' not found\n", *input)
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in default output names, if not specified
|
// Fill in default output names, if not specified
|
||||||
|
|
||||||
if *outputRcc == "" {
|
|
||||||
*outputRcc = strings.TrimSuffix(*input, `.qrc`) + `.rcc`
|
|
||||||
}
|
|
||||||
if *outputGo == "" {
|
if *outputGo == "" {
|
||||||
*outputGo = strings.TrimSuffix(*input, `.qrc`) + `.go`
|
*outputGo = strings.TrimSuffix(*input, `.qrc`) + `.go`
|
||||||
}
|
}
|
||||||
|
if *outputRcc == "" {
|
||||||
|
// Base this on the outputGo filename, not the input filename
|
||||||
|
*outputRcc = strings.TrimSuffix(*outputGo, `.go`) + `.rcc`
|
||||||
|
}
|
||||||
|
|
||||||
|
// The rcc output path must be relative to the output go file path
|
||||||
|
|
||||||
|
embedPath, err := filepath.Rel(filepath.Dir(*outputGo), *outputRcc)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Compile qrc to binary resource file
|
// Compile qrc to binary resource file
|
||||||
|
|
||||||
rccCmd := exec.Command(`rcc`, `--binary`, `-o`, *outputRcc, *input)
|
rccCmd := exec.Command(*rccBinary, `--binary`, `-o`, *outputRcc, *input)
|
||||||
rccCmd.Stderr = os.Stderr
|
rccCmd.Stderr = os.Stderr
|
||||||
rccCmd.Stdout = os.Stdout
|
rccCmd.Stdout = os.Stdout
|
||||||
err := rccCmd.Run()
|
err = rccCmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "rcc: %s\n", err.Error())
|
return err
|
||||||
os.Exit(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create Go file that loads the resource
|
// Figure out import statement
|
||||||
|
|
||||||
|
miqtImport := `"github.com/mappu/miqt/qt"`
|
||||||
|
if *useQt6 {
|
||||||
|
miqtImport = `qt "github.com/mappu/miqt/qt6"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Figure out regeneration command
|
||||||
|
|
||||||
|
generate := `miqt-rcc` +
|
||||||
|
` -Input ` + strconv.Quote(*input) +
|
||||||
|
` -OutputGo ` + strconv.Quote(filepath.Base(*outputGo)) +
|
||||||
|
` -OutputRcc ` + strconv.Quote(embedPath)
|
||||||
|
if *packageName != DefaultPackageName {
|
||||||
|
generate += ` -Package ` + strconv.Quote(*packageName)
|
||||||
|
}
|
||||||
|
if *variableName != DefaultVariableName {
|
||||||
|
generate += ` -Variable ` + strconv.Quote(*variableName)
|
||||||
|
}
|
||||||
|
if *useQt6 != DefaultIsQt6 {
|
||||||
|
generate += ` -Qt6`
|
||||||
|
}
|
||||||
|
if *rccBinary != DefaultRccBinary {
|
||||||
|
generate += ` -RccBinary ` + strconv.Quote(*rccBinary)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create Go file that loads the resource
|
||||||
|
|
||||||
goSrcData := `
|
goSrcData := `
|
||||||
package ` + *packageName + `
|
package ` + *packageName + `
|
||||||
|
|
||||||
//go:generate miqt-rcc "` + strings.Join(os.Args[1:], `" "`) + `"
|
//go:generate ` + generate + `
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
|
|
||||||
"github.com/mappu/miqt/qt"
|
` + miqtImport + `
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed ` + *outputRcc + `
|
//go:embed ` + embedPath + `
|
||||||
var ` + *variableName + ` []byte
|
var ` + *variableName + ` []byte
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@ -75,12 +118,21 @@ func init() {
|
|||||||
|
|
||||||
outputData, err := format.Source([]byte(goSrcData))
|
outputData, err := format.Source([]byte(goSrcData))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = ioutil.WriteFile(*outputGo, outputData, 0644)
|
err = ioutil.WriteFile(*outputGo, outputData, 0644)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "Writing to '%s': %s\n", *outputGo, err.Error())
|
return fmt.Errorf("Writing to '%s': %w", *outputGo, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
err := RccExec()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "rcc: %s\n", err.Error())
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,21 @@
|
|||||||
|
|
||||||
The miqt-uic program compiles Qt Designer `.ui` files into MIQT `.go` files.
|
The miqt-uic program compiles Qt Designer `.ui` files into MIQT `.go` files.
|
||||||
|
|
||||||
For usage information, see the `examples/uidesigner` folder.
|
## Usage
|
||||||
|
|
||||||
|
For example usage information, see the `examples/uidesigner` folder.
|
||||||
|
|
||||||
|
```
|
||||||
|
Usage of ./miqt-uic:
|
||||||
|
-InFile string
|
||||||
|
Input .ui file
|
||||||
|
-OutFile string
|
||||||
|
Output .go file, or - for stdout (default "-")
|
||||||
|
-Package string
|
||||||
|
Custom package name (default "main")
|
||||||
|
-Qt6
|
||||||
|
Use Qt 6 instead of Qt 5
|
||||||
|
```
|
||||||
|
|
||||||
## Architecture design
|
## Architecture design
|
||||||
|
|
||||||
|
@ -9,9 +9,14 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultIsQt6 = false
|
||||||
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
inFile := flag.String("InFile", "", "Input .ui file")
|
inFile := flag.String("InFile", "", "Input .ui file")
|
||||||
outFile := flag.String("OutFile", "-", "Output .go file, or - for stdout")
|
outFile := flag.String("OutFile", "-", "Output .go file, or - for stdout")
|
||||||
|
useQt6 := flag.Bool("Qt6", DefaultIsQt6, "Use Qt 6 instead of Qt 5")
|
||||||
packageName := flag.String("Package", "main", "Custom package name")
|
packageName := flag.String("Package", "main", "Custom package name")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
@ -31,7 +36,7 @@ func main() {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
gosrc, err := generate(*packageName, strings.Join(os.Args[1:], " "), parsed)
|
gosrc, err := generate(*packageName, strings.Join(os.Args[1:], " "), parsed, *useQt6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
@ -490,7 +490,7 @@ func generateWidget(w UiWidget, parentName string, parentClass string) (string,
|
|||||||
return ret.String(), nil
|
return ret.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generate(packageName string, goGenerateArgs string, u UiFile) ([]byte, error) {
|
func generate(packageName string, goGenerateArgs string, u UiFile, useQt6 bool) ([]byte, error) {
|
||||||
|
|
||||||
ret := strings.Builder{}
|
ret := strings.Builder{}
|
||||||
|
|
||||||
@ -507,6 +507,11 @@ func generate(packageName string, goGenerateArgs string, u UiFile) ([]byte, erro
|
|||||||
|
|
||||||
// Header
|
// Header
|
||||||
|
|
||||||
|
importPackage := `"github.com/mappu/miqt/qt"`
|
||||||
|
if useQt6 {
|
||||||
|
importPackage = `qt "github.com/mappu/miqt/qt6"`
|
||||||
|
}
|
||||||
|
|
||||||
ret.WriteString(`// Generated by miqt-uic. To update this file, edit the .ui file in
|
ret.WriteString(`// Generated by miqt-uic. To update this file, edit the .ui file in
|
||||||
// Qt Designer, and then run 'go generate'.
|
// Qt Designer, and then run 'go generate'.
|
||||||
//
|
//
|
||||||
@ -515,7 +520,7 @@ func generate(packageName string, goGenerateArgs string, u UiFile) ([]byte, erro
|
|||||||
package ` + packageName + `
|
package ` + packageName + `
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/mappu/miqt/qt"
|
` + importPackage + `
|
||||||
)
|
)
|
||||||
|
|
||||||
type ` + u.Class + `Ui struct {
|
type ` + u.Class + `Ui struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user