<commit_before>// Copyright 2015 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"archive/zip"
	"fmt"
	"go/build"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
)

func goAndroidBind(pkg *build.Package) error {
	if sdkDir := os.Getenv("ANDROID_HOME"); sdkDir == "" {
		return fmt.Errorf("this command requires ANDROID_HOME environment variable (path to the Android SDK)")
	}

	binder, err := newBinder(pkg)
	if err != nil {
		return err
	}

	if err := binder.GenGo(tmpdir); err != nil {
		return err
	}

	mainFile := filepath.Join(tmpdir, "androidlib/main.go")
	err = writeFile(mainFile, func(w io.Writer) error {
		return androidMainTmpl.Execute(w, "../go_"+binder.pkg.Name())
	})
	if err != nil {
		return fmt.Errorf("failed to create the main package for android: %v", err)
	}

	androidDir := filepath.Join(tmpdir, "android")

	err = goBuild(
		mainFile,
		androidArmEnv,
		"-buildmode=c-shared",
		"-o="+filepath.Join(androidDir, "src/main/jniLibs/armeabi-v7a/libgojni.so"),
	)
	if err != nil {
		return err
	}

	p, err := ctx.Import("golang.org/x/mobile/bind", cwd, build.ImportComment)
	if err != nil {
		return fmt.Errorf(`"golang.org/x/mobile/bind" is not found; run go get golang.org/x/mobile/bind`)
	}
	repo := filepath.Clean(filepath.Join(p.Dir, "..")) // golang.org/x/mobile directory.

	pkgpath := strings.Replace(bindJavaPkg, ".", "/", -1)
	if bindJavaPkg == "" {
		pkgpath = "go/" + binder.pkg.Name()
	}
	if err := binder.GenJava(filepath.Join(androidDir, "src/main/java/"+pkgpath)); err != nil {
		return err
	}

	dst := filepath.Join(androidDir, "src/main/java/go/LoadJNI.java")
	genLoadJNI := func(w io.Writer) error {
		_, err := io.WriteString(w, loadSrc)
		return err
	}
	if err := writeFile(dst, genLoadJNI); err != nil {
		return err
	}

	src := filepath.Join(repo, "bind/java/Seq.java")
	dst = filepath.Join(androidDir, "src/main/java/go/Seq.java")
	rm(dst)
	if err := symlink(src, dst); err != nil {
		return err
	}

	return buildAAR(androidDir, pkg)
}

var loadSrc = `package go;

public class LoadJNI {
	static {
		System.loadLibrary("gojni");
	}
}
`

var androidMainTmpl = template.Must(template.New("android.go").Parse(`
package main

import (
	_ "golang.org/x/mobile/bind/java"
	_ "{{.}}"
)

func main() {}
`))

// AAR is the format for the binary distribution of an Android Library Project
// and it is a ZIP archive with extension .aar.
// http://tools.android.com/tech-docs/new-build-system/aar-format
//
// These entries are directly at the root of the archive.
//
//	AndroidManifest.xml (mandatory)
// 	classes.jar (mandatory)
//	assets/ (optional)
//	jni/<abi>/libgojni.so
//	R.txt (mandatory)
//	res/ (mandatory)
//	libs/*.jar (optional, not relevant)
//	proguard.txt (optional)
//	lint.jar (optional, not relevant)
//	aidl (optional, not relevant)
//
// javac and jar commands are needed to build classes.jar.
func buildAAR(androidDir string, pkg *build.Package) (err error) {
	var out io.Writer = ioutil.Discard
	if buildO == "" {
		buildO = pkg.Name + ".aar"
	}
	if !strings.HasSuffix(buildO, ".aar") {
		return fmt.Errorf("output file name %q does not end in '.aar'", buildO)
	}
	if !buildN {
		f, err := os.Create(buildO)
		if err != nil {
			return err
		}
		defer func() {
			if cerr := f.Close(); err == nil {
				err = cerr
			}
		}()
		out = f
	}

	aarw := zip.NewWriter(out)
	aarwcreate := func(name string) (io.Writer, error) {
		if buildV {
			fmt.Fprintf(os.Stderr, "aar: %s\n", name)
		}
		return aarw.Create(name)
	}
	w, err := aarwcreate("AndroidManifest.xml")
	if err != nil {
		return err
	}
	const manifestFmt = `<manifest xmlns:android="http://schemas.android.com/apk/res/android" package=%q />`
	fmt.Fprintf(w, manifestFmt, "go."+pkg.Name+".gojni")

	w, err = aarwcreate("proguard.txt")
	if err != nil {
		return err
	}
	fmt.Fprintln(w, `-keep class go.** { *; }`)

	w, err = aarwcreate("classes.jar")
	if err != nil {
		return err
	}
	src := filepath.Join(androidDir, "src/main/java")
	if err := buildJar(w, src); err != nil {
		return err
	}

	assetsDir := filepath.Join(pkg.Dir, "assets")
	assetsDirExists := false
	if fi, err := os.Stat(assetsDir); err == nil {
		assetsDirExists = fi.IsDir()
	} else if !os.IsNotExist(err) {
		return err
	}

	if assetsDirExists {
		err := filepath.Walk(
			assetsDir, func(path string, info os.FileInfo, err error) error {
				if err != nil {
					return err
				}<commit_msg>cmd/gomobile: specify minSdkVersion for .aar file.<commit_after>// Copyright 2015 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"archive/zip"
	"fmt"
	"go/build"
	"io"
	"io/ioutil"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"text/template"
)

func goAndroidBind(pkg *build.Package) error {
	if sdkDir := os.Getenv("ANDROID_HOME"); sdkDir == "" {
		return fmt.Errorf("this command requires ANDROID_HOME environment variable (path to the Android SDK)")
	}

	binder, err := newBinder(pkg)
	if err != nil {
		return err
	}

	if err := binder.GenGo(tmpdir); err != nil {
		return err
	}

	mainFile := filepath.Join(tmpdir, "androidlib/main.go")
	err = writeFile(mainFile, func(w io.Writer) error {
		return androidMainTmpl.Execute(w, "../go_"+binder.pkg.Name())
	})
	if err != nil {
		return fmt.Errorf("failed to create the main package for android: %v", err)
	}

	androidDir := filepath.Join(tmpdir, "android")

	err = goBuild(
		mainFile,
		androidArmEnv,
		"-buildmode=c-shared",
		"-o="+filepath.Join(androidDir, "src/main/jniLibs/armeabi-v7a/libgojni.so"),
	)
	if err != nil {
		return err
	}

	p, err := ctx.Import("golang.org/x/mobile/bind", cwd, build.ImportComment)
	if err != nil {
		return fmt.Errorf(`"golang.org/x/mobile/bind" is not found; run go get golang.org/x/mobile/bind`)
	}
	repo := filepath.Clean(filepath.Join(p.Dir, "..")) // golang.org/x/mobile directory.

	pkgpath := strings.Replace(bindJavaPkg, ".", "/", -1)
	if bindJavaPkg == "" {
		pkgpath = "go/" + binder.pkg.Name()
	}
	if err := binder.GenJava(filepath.Join(androidDir, "src/main/java/"+pkgpath)); err != nil {
		return err
	}

	dst := filepath.Join(androidDir, "src/main/java/go/LoadJNI.java")
	genLoadJNI := func(w io.Writer) error {
		_, err := io.WriteString(w, loadSrc)
		return err
	}
	if err := writeFile(dst, genLoadJNI); err != nil {
		return err
	}

	src := filepath.Join(repo, "bind/java/Seq.java")
	dst = filepath.Join(androidDir, "src/main/java/go/Seq.java")
	rm(dst)
	if err := symlink(src, dst); err != nil {
		return err
	}

	return buildAAR(androidDir, pkg)
}

var loadSrc = `package go;

public class LoadJNI {
	static {
		System.loadLibrary("gojni");
	}
}
`

var androidMainTmpl = template.Must(template.New("android.go").Parse(`
package main

import (
	_ "golang.org/x/mobile/bind/java"
	_ "{{.}}"
)

func main() {}
`))

// AAR is the format for the binary distribution of an Android Library Project
// and it is a ZIP archive with extension .aar.
// http://tools.android.com/tech-docs/new-build-system/aar-format
//
// These entries are directly at the root of the archive.
//
//	AndroidManifest.xml (mandatory)
// 	classes.jar (mandatory)
//	assets/ (optional)
//	jni/<abi>/libgojni.so
//	R.txt (mandatory)
//	res/ (mandatory)
//	libs/*.jar (optional, not relevant)
//	proguard.txt (optional)
//	lint.jar (optional, not relevant)
//	aidl (optional, not relevant)
//
// javac and jar commands are needed to build classes.jar.
func buildAAR(androidDir string, pkg *build.Package) (err error) {
	var out io.Writer = ioutil.Discard
	if buildO == "" {
		buildO = pkg.Name + ".aar"
	}
	if !strings.HasSuffix(buildO, ".aar") {
		return fmt.Errorf("output file name %q does not end in '.aar'", buildO)
	}
	if !buildN {
		f, err := os.Create(buildO)
		if err != nil {
			return err
		}
		defer func() {
			if cerr := f.Close(); err == nil {
				err = cerr
			}
		}()
		out = f
	}

	aarw := zip.NewWriter(out)
	aarwcreate := func(name string) (io.Writer, error) {
		if buildV {
			fmt.Fprintf(os.Stderr, "aar: %s\n", name)
		}
		return aarw.Create(name)
	}
	w, err := aarwcreate("AndroidManifest.xml")
	if err != nil {
		return err
	}
	const manifestFmt = `<manifest xmlns:android="http://schemas.android.com/apk/res/android" package=%q>
<uses-sdk android:minSdkVersion=%q/></manifest>`
	fmt.Fprintf(w, manifestFmt, "go."+pkg.Name+".gojni", minAndroidAPI)

	w, err = aarwcreate("proguard.txt")
	if err != nil {
		return err
	}
	fmt.Fprintln(w, `-keep class go.** { *; }`)

	w, err = aarwcreate("classes.jar")
	if err != nil {
		return err
	}
	src := filepath.Join(androidDir, "src/main/java")
	if err := buildJar(w, src); err != nil {
		return err
	}

	assetsDir := filepath.Join(pkg.Dir, "assets")
	assetsDirExists := false
	if fi, err := os.Stat(assetsDir); err == nil {
		assetsDirExists = fi.IsDir()
	} else if !os.IsNotExist(err) {
		return err
	}

	if assetsDirExists {
		err := filepath.Walk(
			assetsDir, func(path string, info os.FileInfo, err error) error {
				if err != nil {
					return err
				}
{'fraction_non_alphanumeric': 0.1645955962502725, 'fraction_numerical': 0.0013080444735120995, 'mean_word_length': 3.460379192999514, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5913900', 'n_tokens_mistral': 3667, 'n_tokens_neox': 3471, 'n_words': 858}