1// +build ignore
2
3/*
4Copyright 2017 The Perkeep Authors.
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10     http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17*/
18
19// This program builds the Perkeep Android application. It is meant to be run
20// within the relevant docker container.
21package main
22
23import (
24	"bufio"
25	"flag"
26	"fmt"
27	"io/ioutil"
28	"log"
29	"os"
30	"os/exec"
31	"path/filepath"
32	"regexp"
33	"strings"
34)
35
36var flagRelease = flag.Bool("release", false, "Whether to assemble the release build, instead of the debug build.")
37
38// TODO(mpl): not sure if the version in app/build.gradle should have anything
39// to do with the version we want to use here. look into that later.
40const appVersion = "0.7"
41
42var (
43	camliDir   = filepath.Join(os.Getenv("GOPATH"), "src/perkeep.org")
44	projectDir = filepath.Join(os.Getenv("GOPATH"), "src/perkeep.org/clients/android")
45	pkputBin   = filepath.Join(projectDir, "app/build/generated/assets/pk-put.arm")
46	assetsDir  = filepath.Join(projectDir, "app/src/main/assets")
47)
48
49func main() {
50	flag.Parse()
51	if !inDocker() {
52		fmt.Fprintf(os.Stderr, "Usage error: this program should be run within a docker container\n")
53		os.Exit(2)
54	}
55	buildCamput()
56	writeVersion()
57	buildApp()
58}
59
60func buildApp() {
61	cmd := exec.Command("./gradlew", "assembleDebug")
62	if *flagRelease {
63		cmd = exec.Command("./gradlew", "assembleRelease")
64	}
65	cmd.Stdout = os.Stdout
66	cmd.Stderr = os.Stderr
67	if err := cmd.Run(); err != nil {
68		log.Fatalf("Error building Android app: %v", err)
69	}
70}
71
72func writeVersion() {
73	if err := ioutil.WriteFile(filepath.Join(assetsDir, "pk-put-version.txt"), []byte(version()), 0600); err != nil {
74		log.Fatalf("Error writing app version file: %v", err)
75	}
76}
77
78func buildCamput() {
79	os.Setenv("GOARCH", "arm")
80	os.Setenv("GOARM", "7")
81	cmd := exec.Command("go", "build", "-o", pkputBin, "perkeep.org/cmd/pk-put")
82	cmd.Stdout = os.Stdout
83	cmd.Stderr = os.Stderr
84	if err := cmd.Run(); err != nil {
85		log.Fatalf("Error building pk-put for Android: %v", err)
86	}
87
88	if err := os.Rename(pkputBin, filepath.Join(assetsDir, "pk-put.arm")); err != nil {
89		log.Fatalf("Error moving pk-put to assets dir: %v", err)
90	}
91}
92
93func version() string {
94	return "app " + appVersion + " pk-put " + getVersion() + " " + goVersion()
95}
96
97func goVersion() string {
98	out, err := exec.Command("go", "version").Output()
99	if err != nil {
100		log.Fatalf("Error getting Go version with the 'go' command: %v", err)
101	}
102	return string(out)
103}
104
105// getVersion returns the version of Perkeep. Either from a VERSION file at the root,
106// or from git.
107func getVersion() string {
108	slurp, err := ioutil.ReadFile(filepath.Join(camliDir, "VERSION"))
109	if err == nil {
110		return strings.TrimSpace(string(slurp))
111	}
112	return gitVersion()
113}
114
115var gitVersionRx = regexp.MustCompile(`\b\d\d\d\d-\d\d-\d\d-[0-9a-f]{10,10}\b`)
116
117// gitVersion returns the git version of the git repo at camRoot as a
118// string of the form "yyyy-mm-dd-xxxxxxx", with an optional trailing
119// '+' if there are any local uncommitted modifications to the tree.
120func gitVersion() string {
121	cmd := exec.Command("git", "rev-list", "--max-count=1", "--pretty=format:'%ad-%h'",
122		"--date=short", "--abbrev=10", "HEAD")
123	cmd.Dir = camliDir
124	out, err := cmd.Output()
125	if err != nil {
126		log.Fatalf("Error running git rev-list in %s: %v", camliDir, err)
127	}
128	v := strings.TrimSpace(string(out))
129	if m := gitVersionRx.FindStringSubmatch(v); m != nil {
130		v = m[0]
131	} else {
132		panic("Failed to find git version in " + v)
133	}
134	cmd = exec.Command("git", "diff", "--exit-code")
135	cmd.Dir = camliDir
136	if err := cmd.Run(); err != nil {
137		v += "+"
138	}
139	return v
140}
141
142func inDocker() bool {
143	r, err := os.Open("/proc/self/cgroup")
144	if err != nil {
145		log.Fatalf(`can't open "/proc/self/cgroup": %v`, err)
146	}
147	defer r.Close()
148	sc := bufio.NewScanner(r)
149	for sc.Scan() {
150		l := sc.Text()
151		fields := strings.SplitN(l, ":", 3)
152		if len(fields) != 3 {
153			log.Fatal(`unexpected line in "/proc/self/cgroup"`)
154		}
155		if !(strings.HasPrefix(fields[2], "/docker/") ||
156			strings.HasPrefix(fields[2], "/system.slice/docker.service")) {
157			return false
158		}
159	}
160	if err := sc.Err(); err != nil {
161		log.Fatal(err)
162	}
163	return true
164}
165