forked from joejulian/gio-cmd
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2f88fad9ea |
@@ -3,26 +3,27 @@ module gioui.org/cmd
|
|||||||
go 1.24.1
|
go 1.24.1
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gioui.org v0.9.0
|
gioui.org v0.10.0
|
||||||
github.com/akavel/rsrc v0.10.1
|
github.com/akavel/rsrc v0.10.1
|
||||||
github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4
|
github.com/chromedp/cdproto v0.0.0-20250429231605-6ed5b53462d4
|
||||||
github.com/chromedp/chromedp v0.13.6
|
github.com/chromedp/chromedp v0.13.6
|
||||||
golang.org/x/image v0.26.0
|
golang.org/x/image v0.26.0
|
||||||
golang.org/x/sync v0.13.0
|
golang.org/x/sync v0.19.0
|
||||||
golang.org/x/text v0.24.0
|
golang.org/x/text v0.32.0
|
||||||
golang.org/x/tools v0.32.0
|
golang.org/x/tools v0.39.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
gioui.org/shader v1.0.8 // indirect
|
gioui.org/shader v1.0.8 // indirect
|
||||||
github.com/chromedp/sysutil v1.1.0 // indirect
|
github.com/chromedp/sysutil v1.1.0 // indirect
|
||||||
github.com/go-json-experiment/json v0.0.0-20250417205406-170dfdcf87d1 // indirect
|
github.com/go-json-experiment/json v0.0.0-20250417205406-170dfdcf87d1 // indirect
|
||||||
github.com/go-text/typesetting v0.3.0 // indirect
|
github.com/go-text/typesetting v0.3.4 // indirect
|
||||||
github.com/gobwas/httphead v0.1.0 // indirect
|
github.com/gobwas/httphead v0.1.0 // indirect
|
||||||
github.com/gobwas/pool v0.2.1 // indirect
|
github.com/gobwas/pool v0.2.1 // indirect
|
||||||
github.com/gobwas/ws v1.4.0 // indirect
|
github.com/gobwas/ws v1.4.0 // indirect
|
||||||
github.com/google/go-cmp v0.7.0 // indirect
|
github.com/google/go-cmp v0.7.0 // indirect
|
||||||
golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0 // indirect
|
||||||
golang.org/x/mod v0.24.0 // indirect
|
golang.org/x/mod v0.30.0 // indirect
|
||||||
golang.org/x/sys v0.33.0 // indirect
|
golang.org/x/net v0.48.0 // indirect
|
||||||
|
golang.org/x/sys v0.39.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY=
|
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d h1:ARo7NCVvN2NdhLlJE9xAbKweuI9L6UgfTbYb0YwPacY=
|
||||||
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA=
|
eliasnaur.com/font v0.0.0-20230308162249-dd43949cb42d/go.mod h1:OYVuxibdk9OSLX8vAqydtRPP87PyTFcT9uH3MlEGBQA=
|
||||||
gioui.org v0.9.0 h1:4u7XZwnb5kzQW91Nz/vR0wKD6LdW9CaVF96r3rfy4kc=
|
gioui.org v0.10.0 h1:kV6NKGbEp0JSPLtgoT/xk5dMexVDzvEOErXA40gUxrU=
|
||||||
gioui.org v0.9.0/go.mod h1:CjNig0wAhLt9WZxOPAusgFD8x8IRvqt26LdDBa3Jvao=
|
gioui.org v0.10.0/go.mod h1:MZJZsdEPkTBzChdqeE8CiiQhreUQBj43qusDxQNDf7k=
|
||||||
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
gioui.org/cpu v0.0.0-20210808092351-bfe733dd3334/go.mod h1:A8M0Cn5o+vY5LTMlnRoK3O5kG+rH0kWfJjeKd9QpBmQ=
|
||||||
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
|
gioui.org/shader v1.0.8 h1:6ks0o/A+b0ne7RzEqRZK5f4Gboz2CfG+mVliciy6+qA=
|
||||||
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
gioui.org/shader v1.0.8/go.mod h1:mWdiME581d/kV7/iEhLmUgUK5iZ09XR5XpduXzbePVM=
|
||||||
@@ -15,10 +15,10 @@ github.com/chromedp/sysutil v1.1.0 h1:PUFNv5EcprjqXZD9nJb9b/c9ibAbxiYo4exNWZyipw
|
|||||||
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
|
github.com/chromedp/sysutil v1.1.0/go.mod h1:WiThHUdltqCNKGc4gaU50XgYjwjYIhKWoHGPTUfWTJ8=
|
||||||
github.com/go-json-experiment/json v0.0.0-20250417205406-170dfdcf87d1 h1:+VexzzkMLb1tnvpuQdGT/DicIRW7MN8ozsXqBMgp0Hk=
|
github.com/go-json-experiment/json v0.0.0-20250417205406-170dfdcf87d1 h1:+VexzzkMLb1tnvpuQdGT/DicIRW7MN8ozsXqBMgp0Hk=
|
||||||
github.com/go-json-experiment/json v0.0.0-20250417205406-170dfdcf87d1/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
github.com/go-json-experiment/json v0.0.0-20250417205406-170dfdcf87d1/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M=
|
||||||
github.com/go-text/typesetting v0.3.0 h1:OWCgYpp8njoxSRpwrdd1bQOxdjOXDj9Rqart9ML4iF4=
|
github.com/go-text/typesetting v0.3.4 h1:YYurUOtEb9kGSOz4uE3k4OpBGsp1dDL8+fjCeaFamAU=
|
||||||
github.com/go-text/typesetting v0.3.0/go.mod h1:qjZLkhRgOEYMhU9eHBr3AR4sfnGJvOXNLt8yRAySFuY=
|
github.com/go-text/typesetting v0.3.4/go.mod h1:4qZCQphq4KSgGTAeI0uMEkVbROgfah8BuyF5LRYr7XY=
|
||||||
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066 h1:qCuYC+94v2xrb1PoS4NIDe7DGYtLnU2wWiQe9a1B1c0=
|
github.com/go-text/typesetting-utils v0.0.0-20260223113751-2d88ac90dae3 h1:drBZzMgdYPbmyXqOto4YhhJGrFIQCX94FpR4MzTCsos=
|
||||||
github.com/go-text/typesetting-utils v0.0.0-20241103174707-87a29e9e6066/go.mod h1:DDxDdQEnB70R8owOx3LVpEFvpMK9eeH1o2r0yZhFI9o=
|
github.com/go-text/typesetting-utils v0.0.0-20260223113751-2d88ac90dae3/go.mod h1:3/62I4La/HBRX9TcTpBj4eipLiwzf+vhI+7whTc9V7o=
|
||||||
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
|
||||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||||
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
|
||||||
@@ -37,14 +37,16 @@ golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0 h1:tMSqXTK+AQdW3LpCbfa
|
|||||||
golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
|
golang.org/x/exp/shiny v0.0.0-20250408133849-7e4ce0ab07d0/go.mod h1:ygj7T6vSGhhm/9yTpOQQNvuAUFziTH7RUiH74EoE2C8=
|
||||||
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
|
golang.org/x/image v0.26.0 h1:4XjIFEZWQmCZi6Wv8BoxsDhRU3RVnLX04dToTDAEPlY=
|
||||||
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
|
golang.org/x/image v0.26.0/go.mod h1:lcxbMFAovzpnJxzXS3nyL83K27tmqtKzIJpctK8YO5c=
|
||||||
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk=
|
||||||
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc=
|
||||||
golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610=
|
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||||
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
|
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||||
|
golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4=
|
||||||
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw=
|
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||||
golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||||
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ=
|
||||||
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ=
|
||||||
|
|||||||
+44
-156
@@ -50,8 +50,6 @@ type manifestData struct {
|
|||||||
AppName string
|
AppName string
|
||||||
Schemes []string
|
Schemes []string
|
||||||
PackageQueries []string
|
PackageQueries []string
|
||||||
ManifestSnip string
|
|
||||||
AppSnip string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -117,9 +115,7 @@ func buildAndroid(tmpDir string, bi *buildInfo) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
moduleRoot := moduleRootForDir(bi.pkgDir)
|
|
||||||
var extraJars []string
|
var extraJars []string
|
||||||
seenJars := make(map[string]bool)
|
|
||||||
visitedPkgs := make(map[string]bool)
|
visitedPkgs := make(map[string]bool)
|
||||||
var visitPkg func(*packages.Package) error
|
var visitPkg func(*packages.Package) error
|
||||||
visitPkg = func(p *packages.Package) error {
|
visitPkg = func(p *packages.Package) error {
|
||||||
@@ -127,17 +123,11 @@ func buildAndroid(tmpDir string, bi *buildInfo) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
dir := filepath.Dir(p.GoFiles[0])
|
dir := filepath.Dir(p.GoFiles[0])
|
||||||
jars, err := androidExtraJars(dir, moduleRoot)
|
jars, err := filepath.Glob(filepath.Join(dir, "*.jar"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
for _, jar := range jars {
|
extraJars = append(extraJars, jars...)
|
||||||
if seenJars[jar] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seenJars[jar] = true
|
|
||||||
extraJars = append(extraJars, jar)
|
|
||||||
}
|
|
||||||
switch {
|
switch {
|
||||||
case p.PkgPath == "net":
|
case p.PkgPath == "net":
|
||||||
perms = append(perms, "network")
|
perms = append(perms, "network")
|
||||||
@@ -432,10 +422,6 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
moduleRoot := moduleRootForDir(bi.pkgDir)
|
|
||||||
if err := copyTree(filepath.Join(moduleRoot, "android", "res"), resDir); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
resZip := filepath.Join(tmpDir, "resources.zip")
|
resZip := filepath.Join(tmpDir, "resources.zip")
|
||||||
aapt2 := filepath.Join(tools.buildtools, "aapt2")
|
aapt2 := filepath.Join(tools.buildtools, "aapt2")
|
||||||
_, err = runCmd(exec.Command(
|
_, err = runCmd(exec.Command(
|
||||||
@@ -461,15 +447,52 @@ func exeAndroid(tmpDir string, tools *androidTools, bi *buildInfo, extraJars, pe
|
|||||||
AppName: appName,
|
AppName: appName,
|
||||||
Schemes: bi.schemes,
|
Schemes: bi.schemes,
|
||||||
PackageQueries: bi.packageQueries,
|
PackageQueries: bi.packageQueries,
|
||||||
ManifestSnip: readOptionalText(filepath.Join(moduleRoot, "android", "manifest_snippets.xml")),
|
|
||||||
AppSnip: readOptionalText(filepath.Join(moduleRoot, "android", "application_snippets.xml")),
|
|
||||||
}
|
}
|
||||||
manifestBuffer, err := renderAndroidManifest(manifestSrc)
|
tmpl, err := template.New("test").Parse(
|
||||||
if err != nil {
|
`<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="{{.AppID}}"
|
||||||
|
android:versionCode="{{.Version.VersionCode}}"
|
||||||
|
android:versionName="{{.Version}}">
|
||||||
|
{{if .PackageQueries}}
|
||||||
|
<queries>
|
||||||
|
{{range .PackageQueries}}
|
||||||
|
<package android:name="{{.}}" />
|
||||||
|
{{end}}
|
||||||
|
</queries>
|
||||||
|
{{end}}
|
||||||
|
<uses-sdk android:minSdkVersion="{{.MinSDK}}" android:targetSdkVersion="{{.TargetSDK}}" />
|
||||||
|
{{range .Permissions}} <uses-permission android:name="{{.}}"/>
|
||||||
|
{{end}}{{range .Features}} <uses-feature android:{{.}} android:required="false"/>
|
||||||
|
{{end}} <application {{.IconSnip}} android:label="{{.AppName}}">
|
||||||
|
<activity android:name="org.gioui.GioActivity"
|
||||||
|
android:label="{{.AppName}}"
|
||||||
|
android:theme="@style/Theme.GioApp"
|
||||||
|
android:configChanges="screenSize|screenLayout|smallestScreenSize|orientation|keyboardHidden"
|
||||||
|
android:windowSoftInputMode="adjustResize"
|
||||||
|
android:launchMode="singleInstance"
|
||||||
|
android:exported="true">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
{{range .Schemes}}
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.VIEW"></action>
|
||||||
|
<category android:name="android.intent.category.DEFAULT"></category>
|
||||||
|
<category android:name="android.intent.category.BROWSABLE"></category>
|
||||||
|
<data android:scheme="{{.}}"></data>
|
||||||
|
</intent-filter>
|
||||||
|
{{end}}
|
||||||
|
</activity>
|
||||||
|
</application>
|
||||||
|
</manifest>`)
|
||||||
|
var manifestBuffer bytes.Buffer
|
||||||
|
if err := tmpl.Execute(&manifestBuffer, manifestSrc); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
manifest := filepath.Join(tmpDir, "AndroidManifest.xml")
|
manifest := filepath.Join(tmpDir, "AndroidManifest.xml")
|
||||||
if err := os.WriteFile(manifest, manifestBuffer, 0o660); err != nil {
|
if err := os.WriteFile(manifest, manifestBuffer.Bytes(), 0o660); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -734,141 +757,6 @@ func defaultAndroidKeystore(tmpDir string, bi *buildInfo) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func renderAndroidManifest(data manifestData) ([]byte, error) {
|
|
||||||
tmpl, err := template.New("test").Parse(
|
|
||||||
`<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
package="{{.AppID}}"
|
|
||||||
android:versionCode="{{.Version.VersionCode}}"
|
|
||||||
android:versionName="{{.Version}}">
|
|
||||||
{{if .PackageQueries}}
|
|
||||||
<queries>
|
|
||||||
{{range .PackageQueries}}
|
|
||||||
<package android:name="{{.}}" />
|
|
||||||
{{end}}
|
|
||||||
</queries>
|
|
||||||
{{end}}
|
|
||||||
<uses-sdk android:minSdkVersion="{{.MinSDK}}" android:targetSdkVersion="{{.TargetSDK}}" />
|
|
||||||
{{range .Permissions}} <uses-permission android:name="{{.}}"/>
|
|
||||||
{{end}}{{range .Features}} <uses-feature android:{{.}} android:required="false"/>
|
|
||||||
{{end}}{{.ManifestSnip}} <application {{.IconSnip}} android:label="{{.AppName}}">
|
|
||||||
{{.AppSnip}}
|
|
||||||
<activity android:name="org.gioui.GioActivity"
|
|
||||||
android:label="{{.AppName}}"
|
|
||||||
android:theme="@style/Theme.GioApp"
|
|
||||||
android:configChanges="screenSize|screenLayout|smallestScreenSize|orientation|keyboardHidden"
|
|
||||||
android:windowSoftInputMode="adjustResize"
|
|
||||||
android:launchMode="singleInstance"
|
|
||||||
android:exported="true">
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.MAIN" />
|
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
|
||||||
</intent-filter>
|
|
||||||
{{range .Schemes}}
|
|
||||||
<intent-filter>
|
|
||||||
<action android:name="android.intent.action.VIEW"></action>
|
|
||||||
<category android:name="android.intent.category.DEFAULT"></category>
|
|
||||||
<category android:name="android.intent.category.BROWSABLE"></category>
|
|
||||||
<data android:scheme="{{.}}"></data>
|
|
||||||
</intent-filter>
|
|
||||||
{{end}}
|
|
||||||
</activity>
|
|
||||||
</application>
|
|
||||||
</manifest>`)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
var manifestBuffer bytes.Buffer
|
|
||||||
if err := tmpl.Execute(&manifestBuffer, data); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return manifestBuffer.Bytes(), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func readOptionalText(path string) string {
|
|
||||||
data, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if len(data) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "\n" + string(data) + "\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
func copyTree(src, dst string) error {
|
|
||||||
info, err := os.Stat(src)
|
|
||||||
if err != nil {
|
|
||||||
if os.IsNotExist(err) {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if !info.IsDir() {
|
|
||||||
return fmt.Errorf("extra Android resources path is not a directory: %s", src)
|
|
||||||
}
|
|
||||||
return filepath.Walk(src, func(path string, entry os.FileInfo, walkErr error) error {
|
|
||||||
if walkErr != nil {
|
|
||||||
return walkErr
|
|
||||||
}
|
|
||||||
rel, err := filepath.Rel(src, path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if rel == "." {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
target := filepath.Join(dst, rel)
|
|
||||||
if entry.IsDir() {
|
|
||||||
return os.MkdirAll(target, 0o755)
|
|
||||||
}
|
|
||||||
if err := os.MkdirAll(filepath.Dir(target), 0o755); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
data, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return os.WriteFile(target, data, 0o660)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func androidExtraJars(dir, moduleRoot string) ([]string, error) {
|
|
||||||
var jars []string
|
|
||||||
patterns := []string{
|
|
||||||
filepath.Join(dir, "*.jar"),
|
|
||||||
filepath.Join(dir, "android", "*.jar"),
|
|
||||||
}
|
|
||||||
if moduleRoot != "" && moduleRoot != dir {
|
|
||||||
patterns = append(patterns,
|
|
||||||
filepath.Join(moduleRoot, "*.jar"),
|
|
||||||
filepath.Join(moduleRoot, "android", "*.jar"),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
for _, pattern := range patterns {
|
|
||||||
matches, err := filepath.Glob(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
jars = append(jars, matches...)
|
|
||||||
}
|
|
||||||
return jars, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func moduleRootForDir(dir string) string {
|
|
||||||
current := dir
|
|
||||||
for {
|
|
||||||
if _, err := os.Stat(filepath.Join(current, "go.mod")); err == nil {
|
|
||||||
return current
|
|
||||||
}
|
|
||||||
parent := filepath.Dir(current)
|
|
||||||
if parent == current {
|
|
||||||
return dir
|
|
||||||
}
|
|
||||||
current = parent
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func findNDK(androidHome string) (string, error) {
|
func findNDK(androidHome string) (string, error) {
|
||||||
ndks, err := filepath.Glob(filepath.Join(androidHome, "ndk", "*"))
|
ndks, err := filepath.Glob(filepath.Join(androidHome, "ndk", "*"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,193 +0,0 @@
|
|||||||
// SPDX-License-Identifier: Unlicense OR MIT
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestAndroidExtraJarsIncludesAndroidSubdirectory(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
dir := t.TempDir()
|
|
||||||
rootJar := filepath.Join(dir, "crew.jar")
|
|
||||||
androidJar := filepath.Join(dir, "android", "vault.jar")
|
|
||||||
writeTestFile(t, rootJar, "root")
|
|
||||||
writeTestFile(t, androidJar, "android")
|
|
||||||
|
|
||||||
got, err := androidExtraJars(dir, dir)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("androidExtraJars() error = %v", err)
|
|
||||||
}
|
|
||||||
want := []string{rootJar, androidJar}
|
|
||||||
for _, jar := range want {
|
|
||||||
if !containsString(got, jar) {
|
|
||||||
t.Fatalf("androidExtraJars() = %v, want %q included", got, jar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndroidExtraJarsIncludesModuleRootAndroidSubdirectory(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
dir := filepath.Join(root, "cmd", "keepassgo")
|
|
||||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll(%q) error = %v", dir, err)
|
|
||||||
}
|
|
||||||
moduleAndroidJar := filepath.Join(root, "android", "keepassgo-android.jar")
|
|
||||||
writeTestFile(t, moduleAndroidJar, "module-android")
|
|
||||||
|
|
||||||
got, err := androidExtraJars(dir, root)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("androidExtraJars() error = %v", err)
|
|
||||||
}
|
|
||||||
if !containsString(got, moduleAndroidJar) {
|
|
||||||
t.Fatalf("androidExtraJars() = %v, want %q included", got, moduleAndroidJar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAndroidExtraJarsDoesNotRepeatSharedModuleJarWhenCollectedAcrossPackages(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
moduleAndroidJar := filepath.Join(root, "android", "keepassgo-android.jar")
|
|
||||||
writeTestFile(t, filepath.Join(root, "go.mod"), "module example.invalid/crew\n")
|
|
||||||
writeTestFile(t, moduleAndroidJar, "module-android")
|
|
||||||
|
|
||||||
dirs := []string{
|
|
||||||
filepath.Join(root, "cmd", "keepassgo"),
|
|
||||||
filepath.Join(root, "internal", "appui"),
|
|
||||||
}
|
|
||||||
seen := make(map[string]bool)
|
|
||||||
var collected []string
|
|
||||||
for _, dir := range dirs {
|
|
||||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll(%q) error = %v", dir, err)
|
|
||||||
}
|
|
||||||
jars, err := androidExtraJars(dir, root)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("androidExtraJars(%q) error = %v", dir, err)
|
|
||||||
}
|
|
||||||
for _, jar := range jars {
|
|
||||||
if seen[jar] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
seen[jar] = true
|
|
||||||
collected = append(collected, jar)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
count := 0
|
|
||||||
for _, jar := range collected {
|
|
||||||
if jar == moduleAndroidJar {
|
|
||||||
count++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if count != 1 {
|
|
||||||
t.Fatalf("collected module jar count = %d, want 1 in %v", count, collected)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRenderAndroidManifestIncludesOptionalSnippets(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
manifest, err := renderAndroidManifest(manifestData{
|
|
||||||
AppID: "org.example.heist",
|
|
||||||
Version: Semver{Major: 1, Minor: 2, Patch: 3, VersionCode: 4},
|
|
||||||
MinSDK: 28,
|
|
||||||
TargetSDK: 35,
|
|
||||||
Permissions: []string{"android.permission.INTERNET"},
|
|
||||||
Features: []string{`name="android.hardware.fingerprint"`},
|
|
||||||
IconSnip: `android:icon="@mipmap/ic_launcher"`,
|
|
||||||
AppName: "Bellagio Crew",
|
|
||||||
ManifestSnip: "\n\t<uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n",
|
|
||||||
AppSnip: "\n\t\t<service android:name=\".CrewService\" />\n",
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("renderAndroidManifest() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
got := string(manifest)
|
|
||||||
for _, want := range []string{
|
|
||||||
`android.permission.POST_NOTIFICATIONS`,
|
|
||||||
`<service android:name=".CrewService" />`,
|
|
||||||
`android.permission.INTERNET`,
|
|
||||||
`android.hardware.fingerprint`,
|
|
||||||
} {
|
|
||||||
if !strings.Contains(got, want) {
|
|
||||||
t.Fatalf("renderAndroidManifest() missing %q in %s", want, got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCopyTreeCopiesNestedResources(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
src := filepath.Join(t.TempDir(), "android", "res")
|
|
||||||
dst := filepath.Join(t.TempDir(), "merged")
|
|
||||||
resourcePath := filepath.Join(src, "xml", "heist_service.xml")
|
|
||||||
writeTestFile(t, resourcePath, "<service />")
|
|
||||||
|
|
||||||
if err := copyTree(src, dst); err != nil {
|
|
||||||
t.Fatalf("copyTree() error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
got, err := os.ReadFile(filepath.Join(dst, "xml", "heist_service.xml"))
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ReadFile() error = %v", err)
|
|
||||||
}
|
|
||||||
if string(got) != "<service />" {
|
|
||||||
t.Fatalf("copyTree() copied %q, want %q", string(got), "<service />")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestModuleRootForDirFindsOwningModule(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
writeTestFile(t, filepath.Join(root, "go.mod"), "module example.invalid/crew\n")
|
|
||||||
dir := filepath.Join(root, "cmd", "keepassgo")
|
|
||||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll(%q) error = %v", dir, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := moduleRootForDir(dir); got != root {
|
|
||||||
t.Fatalf("moduleRootForDir(%q) = %q, want %q", dir, got, root)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestModuleRootForDirFallsBackToInputDir(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
dir := filepath.Join(t.TempDir(), "cmd", "keepassgo")
|
|
||||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll(%q) error = %v", dir, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := moduleRootForDir(dir); got != dir {
|
|
||||||
t.Fatalf("moduleRootForDir(%q) = %q, want %q", dir, got, dir)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeTestFile(t *testing.T, path, contents string) {
|
|
||||||
t.Helper()
|
|
||||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
if err := os.WriteFile(path, []byte(contents), 0o644); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsString(values []string, want string) bool {
|
|
||||||
for _, value := range values {
|
|
||||||
if value == want {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user