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"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
const (
|
||||
DefaultPackageName string = "main"
|
||||
DefaultVariableName string = "_resourceRcc"
|
||||
DefaultIsQt6 bool = false
|
||||
DefaultRccBinary string = "rcc"
|
||||
)
|
||||
|
||||
func RccExec() error {
|
||||
|
||||
// Parse arguments
|
||||
|
||||
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")
|
||||
packageName := flag.String("Package", "main", "Package to use in generated Go files")
|
||||
variableName := flag.String("VariableName", "_resourceRcc", "Temporary global variable name for loading embedded data")
|
||||
outputRcc := flag.String("OutputRcc", "", "(Optional) Path to .rcc output file. If omitted, inferred from the output Go file path")
|
||||
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()
|
||||
|
||||
// Check if input file exists
|
||||
|
||||
if _, err := os.Stat(*input); os.IsNotExist(err) {
|
||||
fmt.Fprintf(os.Stderr, "Input file '%s' not found\n", *input)
|
||||
os.Exit(1)
|
||||
return fmt.Errorf("Input file '%s' not found\n", *input)
|
||||
}
|
||||
|
||||
// Fill in default output names, if not specified
|
||||
|
||||
if *outputRcc == "" {
|
||||
*outputRcc = strings.TrimSuffix(*input, `.qrc`) + `.rcc`
|
||||
}
|
||||
if *outputGo == "" {
|
||||
*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
|
||||
|
||||
rccCmd := exec.Command(`rcc`, `--binary`, `-o`, *outputRcc, *input)
|
||||
rccCmd := exec.Command(*rccBinary, `--binary`, `-o`, *outputRcc, *input)
|
||||
rccCmd.Stderr = os.Stderr
|
||||
rccCmd.Stdout = os.Stdout
|
||||
err := rccCmd.Run()
|
||||
err = rccCmd.Run()
|
||||
if err != nil {
|
||||
fmt.Fprintf(os.Stderr, "rcc: %s\n", err.Error())
|
||||
os.Exit(1)
|
||||
return err
|
||||
}
|
||||
|
||||
// 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 := `
|
||||
package ` + *packageName + `
|
||||
|
||||
//go:generate miqt-rcc "` + strings.Join(os.Args[1:], `" "`) + `"
|
||||
//go:generate ` + generate + `
|
||||
|
||||
import (
|
||||
"embed"
|
||||
|
||||
"github.com/mappu/miqt/qt"
|
||||
` + miqtImport + `
|
||||
)
|
||||
|
||||
//go:embed ` + *outputRcc + `
|
||||
//go:embed ` + embedPath + `
|
||||
var ` + *variableName + ` []byte
|
||||
|
||||
func init() {
|
||||
@ -75,12 +118,21 @@ func init() {
|
||||
|
||||
outputData, err := format.Source([]byte(goSrcData))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
return err
|
||||
}
|
||||
|
||||
err = ioutil.WriteFile(*outputGo, outputData, 0644)
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,21 @@
|
||||
|
||||
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
|
||||
|
||||
|
@ -9,9 +9,14 @@ import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultIsQt6 = false
|
||||
)
|
||||
|
||||
func main() {
|
||||
inFile := flag.String("InFile", "", "Input .ui file")
|
||||
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")
|
||||
flag.Parse()
|
||||
|
||||
@ -31,7 +36,7 @@ func main() {
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
|
@ -490,7 +490,7 @@ func generateWidget(w UiWidget, parentName string, parentClass string) (string,
|
||||
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{}
|
||||
|
||||
@ -507,6 +507,11 @@ func generate(packageName string, goGenerateArgs string, u UiFile) ([]byte, erro
|
||||
|
||||
// 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
|
||||
// Qt Designer, and then run 'go generate'.
|
||||
//
|
||||
@ -515,7 +520,7 @@ func generate(packageName string, goGenerateArgs string, u UiFile) ([]byte, erro
|
||||
package ` + packageName + `
|
||||
|
||||
import (
|
||||
"github.com/mappu/miqt/qt"
|
||||
` + importPackage + `
|
||||
)
|
||||
|
||||
type ` + u.Class + `Ui struct {
|
||||
|
Loading…
x
Reference in New Issue
Block a user