github.com/pojntfx/hydrapp/hydrapp@v0.0.0-20240516002902-d08759d6ca9f/pkg/builders/apk/builder.go (about) 1 package apk 2 3 import ( 4 "context" 5 "encoding/base64" 6 "io" 7 "io/ioutil" 8 "os" 9 "path/filepath" 10 "strings" 11 "time" 12 13 "github.com/docker/docker/client" 14 "github.com/pojntfx/hydrapp/hydrapp/pkg/builders" 15 "github.com/pojntfx/hydrapp/hydrapp/pkg/executors" 16 "github.com/pojntfx/hydrapp/hydrapp/pkg/renderers" 17 "github.com/pojntfx/hydrapp/hydrapp/pkg/renderers/apk" 18 "github.com/pojntfx/hydrapp/hydrapp/pkg/utils" 19 ) 20 21 const ( 22 Image = "ghcr.io/pojntfx/hydrapp-build-apk" 23 ) 24 25 func NewBuilder( 26 ctx context.Context, 27 cli *client.Client, 28 29 image string, // OCI image to use 30 pull bool, // Whether to pull the image or not 31 src, // Input directory 32 dst string, // Output directory 33 onID func(id string), // Callback to handle container ID 34 stdout io.Writer, // Writer to handle container output 35 appID string, // Android app ID to use 36 javaKeystore []byte, // Android cert contents 37 javaKeystorePassword string, // Password for the Android keystore 38 javaCertificatePassword string, // Password for the Android certificate 39 pgpKey []byte, // PGP key contents 40 pgpKeyPassword string, // Password for the PGP key 41 baseURL, // Base URL where the repo is to be hosted 42 appName string, // App name 43 releases []renderers.Release, // App releases 44 overwrite bool, // Overwrite files even if they exist 45 branchID, // Branch ID 46 branchName string, // Branch name 47 branchTimestamp time.Time, // Branch timestamp 48 goMain, // Directory with the main package to build 49 goFlags, // Flags to pass to the Go command 50 goGenerate string, // Command to execute go generate with 51 ) *Builder { 52 return &Builder{ 53 ctx, 54 cli, 55 56 image, 57 pull, 58 src, 59 dst, 60 onID, 61 stdout, 62 appID, 63 base64.StdEncoding.EncodeToString(javaKeystore), 64 javaKeystorePassword, 65 javaCertificatePassword, 66 base64.StdEncoding.EncodeToString(pgpKey), 67 pgpKeyPassword, 68 baseURL, 69 appName, 70 releases, 71 overwrite, 72 branchID, 73 branchName, 74 branchTimestamp, 75 goMain, 76 goFlags, 77 goGenerate, 78 } 79 } 80 81 type Builder struct { 82 ctx context.Context 83 cli *client.Client 84 85 image string 86 pull bool 87 src, 88 dst string 89 onID func(id string) 90 stdout io.Writer 91 appID, 92 javaKeystore, 93 javaKeystorePassword, 94 javaCertificatePassword, 95 pgpKey, 96 pgpKeyPassword, 97 baseURL, 98 appName string 99 releases []renderers.Release 100 overwrite bool 101 branchID, 102 branchName string 103 branchTimestamp time.Time 104 goMain, 105 goFlags, 106 goGenerate string 107 } 108 109 func (b *Builder) Render(workdir string, ejecting bool) error { 110 appID := builders.GetAppIDForBranch(b.appID, b.branchID) 111 appName := builders.GetAppNameForBranch(b.appName, b.branchName) 112 113 if strings.TrimSpace(b.branchID) != "" { 114 jniBindingsPath := filepath.Join(workdir, b.goMain, "android.go") 115 116 stableJNIBindingsContent, err := os.ReadFile(jniBindingsPath) 117 if err != nil { 118 return err 119 } 120 121 stableJavaID := strings.Replace(b.appID, ".", "_", -1) 122 mainJavaID := strings.Replace(appID, ".", "_", -1) 123 124 if !ejecting || b.overwrite { 125 if !strings.Contains(string(stableJNIBindingsContent), mainJavaID) { 126 if err := ioutil.WriteFile(jniBindingsPath, []byte(strings.Replace(string(stableJNIBindingsContent), stableJavaID, mainJavaID, -1)), 0664); err != nil { 127 return err 128 } 129 } 130 } 131 } 132 133 return utils.WriteRenders( 134 filepath.Join(workdir, b.goMain), 135 []renderers.Renderer{ 136 apk.NewManifestRenderer( 137 appID, 138 appName, 139 b.releases, 140 b.branchTimestamp, 141 ), 142 apk.NewActivityRenderer( 143 appID, 144 ), 145 apk.NewHeaderRenderer(), 146 apk.NewImplementationRenderer(), 147 }, 148 b.overwrite, 149 ejecting, 150 ) 151 } 152 153 func (b *Builder) Build() error { 154 dst := builders.GetFilepathForBranch(b.dst, b.branchID) 155 appID := builders.GetAppIDForBranch(b.appID, b.branchID) 156 baseURL := builders.GetPathForBranch(b.baseURL, b.branchID, "") + "/repo" // F-Droid requires the path to end with `/repo`: `CRITICAL: repo_url needs to end with /repo` 157 158 return executors.DockerRunImage( 159 b.ctx, 160 b.cli, 161 162 b.image, 163 b.pull, 164 false, 165 b.src, 166 dst, 167 b.onID, 168 b.stdout, 169 map[string]string{ 170 "APP_ID": appID, 171 "JAVA_KEYSTORE": b.javaKeystore, 172 "JAVA_KEYSTORE_PASSWORD": b.javaKeystorePassword, 173 "JAVA_CERTIFICATE_PASSWORD": b.javaCertificatePassword, 174 "PGP_KEY": b.pgpKey, 175 "PGP_KEY_PASSWORD": b.pgpKeyPassword, 176 "BASE_URL": baseURL, 177 "GOMAIN": b.goMain, 178 "GOFLAGS": b.goFlags, 179 "GOGENERATE": b.goGenerate, 180 }, 181 b.Render, 182 []string{}, 183 ) 184 }