./make: script to create android builds (#315)

This PR introduces the `./make` script. For now, this script knows how to make Android releases. We have code in https://github.com/ooni/probe-cli/pull/311 that builds other artifacts in this repository.

Because our current concern is https://github.com/ooni/probe/issues/1444, in this PR, I have chosen to keep the Android code necessary to fix https://github.com/ooni/probe/issues/1444.

Additionally, this PR removes the script to publish to Bintray. This change part of the https://github.com/ooni/probe/issues/1440 cleanup effort.
This commit is contained in:
Simone Basso 2021-04-27 16:36:57 +02:00 committed by GitHub
parent 11087db51a
commit 514ad8d0f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 848 additions and 53 deletions

View File

@ -1,2 +1,4 @@
/oonimkall-sources.jar /*.aar
/oonimkall.aar /*.asc
/*.jar
/*.pom

16
MOBILE/android/go Executable file
View File

@ -0,0 +1,16 @@
#!/bin/sh
# print the fullpath of the go we're using so that it's part
# of the build logs and we can easily increase our confidence
# that we are using the right go binary.
echo -n "$0: checking for go... "
go=`command -v go`
if [ -z $go ]; then
echo "not found"
exit 1
fi
echo "$go"
set -x
$go "$@"

24
MOBILE/android/gomobile Executable file
View File

@ -0,0 +1,24 @@
#!/bin/sh
# print the fullpath of the go/gomobile we're using so that it's part
# of the build logs and we can easily increase our confidence
# that we are using the right go/gomobile binary.
echo -n "$0: checking for go... "
go=`command -v go`
if [ -z $go ]; then
echo "not found"
exit 1
fi
echo "$go"
echo -n "$0: checking for gomobile... "
gomobile=`command -v gomobile`
if [ -z $go ]; then
echo "not found"
exit 1
fi
echo "$gomobile"
set -x
$gomobile "$@"

804
make Executable file
View File

@ -0,0 +1,804 @@
#!/usr/bin/env python3
""" Build script for ooniprobe. You can get documentation regarding
its usage by running `./make --help`. """
from __future__ import annotations
import datetime
import getopt
import json
import os
import platform
import shlex
import shutil
import subprocess
import sys
from typing import Dict
from typing import List
from typing import NoReturn
from typing import Optional
from typing import Protocol
def android_cmdlinetools_os() -> str:
"""android_cmdlinetools_os maps the name of the current OS to the
name used by the android command-line tools file."""
system = platform.system()
if system == "Linux":
return "linux"
if system == "Darwin":
return "mac"
raise RuntimeError(system)
def android_cmdlinetools_version() -> str:
"""android_cmdlinetools_version returns the version of the Android
command-line tools that we'd like to download."""
return "6858069"
def android_cmdlinetools_sha256sum() -> str:
"""android_cmdlinetools_sha256sum returns the SHA256 sum of the
Android command-line tools zip file."""
return {
"linux": "87f6dcf41d4e642e37ba03cb2e387a542aa0bd73cb689a9e7152aad40a6e7a08",
"mac": "58a55d9c5bcacd7c42170d2cf2c9ae2889c6797a6128307aaf69100636f54a13",
}[android_cmdlinetools_os()]
def cachedir() -> str:
"""cachedir returns the directory where we cache the SDKs."""
return os.path.join(os.path.expandvars("${HOME}"), ".ooniprobe-build")
def goversion() -> str:
"""goversion is the Go version we use."""
return "1.16.3"
def gopath() -> str:
"""gopath is the GOPATH we use."""
return os.path.expandvars("${HOME}/go")
def gosha256sum() -> str:
"""gosha256sum returns the SHA256 sum of the Go tarball."""
return {
"linux": {
"amd64": "951a3c7c6ce4e56ad883f97d9db74d3d6d80d5fec77455c6ada6c1f7ac4776d2",
"arm64": "566b1d6f17d2bc4ad5f81486f0df44f3088c3ed47a3bec4099d8ed9939e90d5d",
},
"darwin": {
"amd64": "6bb1cf421f8abc2a9a4e39140b7397cdae6aca3e8d36dcff39a1a77f4f1170ac",
"arm64": "f4e96bbcd5d2d1942f5b55d9e4ab19564da4fad192012f6d7b0b9b055ba4208f",
},
}[goos()][goarch()]
def goos() -> str:
"""goos returns the GOOS value for the current system."""
system = platform.system()
if system == "Linux":
return "linux"
if system == "Darwin":
return "darwin"
raise RuntimeError(system)
def goarch() -> str:
"""goarch returns the GOARCH value for the current system."""
machine = platform.machine()
if machine in ("arm64", "arm", "386", "amd64"):
return machine
if machine in ("x86", "i386"):
return "386"
if machine == "x86_64":
return "amd64"
if machine == "aarch64":
return "arm64"
raise RuntimeError(machine)
def android_ndk_version() -> str:
"""android_ndk_version returns the Android NDK version."""
return "22.1.7171670"
def sdkmanager_install_cmd(binpath: str) -> List[str]:
"""sdkmanager_install_cmd returns the command line for installing
all the required dependencies using the sdkmanager."""
return [
os.path.join(binpath, "sdkmanager"),
"--install",
"build-tools;29.0.3",
"platforms;android-30",
"ndk;{}".format(android_ndk_version()),
]
def log(msg: str) -> None:
"""log prints a message on the standard error."""
print(msg, file=sys.stderr)
class Options(Protocol):
"""Options contains the configured options."""
def debugging(self) -> bool:
"""debugging indicates whether to pass -x to `go build...`."""
def dry_run(self) -> bool:
"""dry_run indicates whether to execute commands."""
def target(self) -> str:
"""target is the target to build."""
def verbose(self) -> bool:
"""verbose indicates whether to pass -v to `go build...`."""
class ConfigFromCLI:
"""ConfigFromCLI parses options from CLI flags."""
@classmethod
def parse(cls, targets: List[str]) -> ConfigFromCLI:
"""parse parses command line options and returns a
suitable configuration object."""
conf = cls()
conf._parse(targets)
return conf
def __init__(self) -> None:
self._debugging = False
self._dry_run = False
self._target = ""
self._verbose = False
def debugging(self) -> bool:
return self._debugging
def dry_run(self) -> bool:
return self._dry_run
def target(self) -> str:
return self._target
def verbose(self) -> bool:
return self._verbose
# The main reason why I am using getopt here is such that I am able
# to print a very clear and detailed usage string. (But the same
# could be obtained quite likely w/ argparse.)
__usage_string = """\
usage: ./make [-nvx] -t target
./make -l
./make [--help|-h]
The first form of the command builds the `target` specified using the
`-t` command line flag. If the target has dependencies, this command will
build the dependent targets first. The `-n` flag enables a dry run where
the command only prints the commands it would run. The `-v` and `-x` flags
are passed directly to `go build ...` and `gomobile bind ...`.
The second form of the command lists all the available targets as
a pretty-printed JSON list.
The third form of the command prints this help screen.
"""
@classmethod
def _usage(cls, err: str = "", exitcode: int = 0) -> NoReturn:
if err:
sys.stderr.write("error: {}\n".format(err))
sys.stderr.write(cls.__usage_string)
sys.exit(exitcode)
def _parse(self, targets: List[str]):
try:
opts, args = getopt.getopt(sys.argv[1:], "hlnt:vx", ["help"])
except getopt.GetoptError as err:
self._usage(err=err.msg, exitcode=1)
if args:
self._usage(err="unexpected number of positional arguments", exitcode=1)
for key, value in opts:
if key in ("-h", "--help"):
self._usage()
if key == "-l":
sys.stdout.write("{}\n".format(json.dumps(targets, indent=4)))
sys.exit(0)
if key == "-n":
self._dry_run = True
continue
if key == "-t":
self._target = value
continue
if key == "-v":
self._verbose = True
continue
if key == "-x":
self._debugging = True
continue
raise RuntimeError(key, value)
if self._target == "": # no arguments is equivalent to --help
self._usage()
if self._target not in targets:
sys.stderr.write("unknown target: {}\n".format(self._target))
sys.stderr.write("try `./make -l` to see the available targets.\n")
sys.exit(1)
class Engine(Protocol):
"""Engine is an engine for building targets."""
def cat_sed_redirect(
self, pattern: str, value: str, source: str, dest: str
) -> None:
"""cat_sed_redirect does `cat $source|sed "s/$pattern/$value/g" > $dest`."""
def echo_to_file(self, content: str, filepath: str) -> None:
"""echo_to_file writes the content string to the given file."""
def require(self, *executable: str) -> None:
"""require fails if executable is not found in path."""
def run(
self,
cmdline: List[str],
cwd: Optional[str] = None,
extra_env: Optional[Dict[str, str]] = None,
inputbytes: Optional[bytes] = None,
) -> None:
"""run runs the specified command line."""
class CommandRealExecutor:
"""CommandRealExecutor executes commands."""
def cat_sed_redirect(
self, pattern: str, value: str, source: str, dest: str
) -> None:
"""cat_sed_redirect implements Engine.cat_sed_redirect."""
with open(source, "r") as sourcefp:
data = sourcefp.read().replace(pattern, value)
with open(dest, "w") as destfp:
destfp.write(data)
def echo_to_file(self, content: str, filepath: str) -> None:
"""echo_to_file implements Engine.echo_to_file"""
with open(filepath, "w") as filep:
filep.write(content)
filep.write("\n")
def require(self, *executable: str) -> None:
"""require implements Engine.require."""
# Implemented in CommandDryRunner
def run(
self,
cmdline: List[str],
cwd: Optional[str] = None,
extra_env: Optional[Dict[str, str]] = None,
inputbytes: Optional[bytes] = None,
) -> None:
"""run implements Engine.run."""
env = os.environ.copy()
if extra_env:
for key, value in extra_env.items():
env[key] = value
subprocess.run(cmdline, check=True, cwd=cwd, env=env, input=inputbytes)
class CommandDryRunner:
"""CommandDryRunner is the dry runner."""
# Implementation note: here we try to log valid bash snippets
# such that is really obvious what we are doing.
def __init__(self):
self.__cmdcache: Dict[str, str] = {}
def cat_sed_redirect(
self, pattern: str, value: str, source: str, dest: str
) -> None:
"""cat_sed_redirect implements Engine.cat_sed_redirect."""
log('./make: cat {}|sed "s/{}/{}/g" > {}'.format(source, pattern, value, dest))
def echo_to_file(self, content: str, filepath: str) -> None:
"""echo_to_file implements Engine.echo_to_file"""
log("./make: echo '{}' > {}".format(content, filepath))
def require(self, *executable: str) -> None:
"""require implements Engine.require."""
for exc in executable:
if exc in self.__cmdcache:
continue # do not print checks more than once
fullpath = shutil.which(exc)
if not fullpath:
log("./make: checking for {}... not found".format(exc))
sys.exit(1)
log("./make: checking for {}... {}".format(exc, fullpath))
self.__cmdcache[exc] = fullpath
def run(
self,
cmdline: List[str],
cwd: Optional[str] = None,
extra_env: Optional[Dict[str, str]] = None,
inputbytes: Optional[bytes] = None,
) -> None:
"""run implements Engine.run."""
cdpart = ""
if cwd:
cdpart = "cd {} && ".format(cwd)
envpart = ""
if extra_env:
for key, value in extra_env.items():
envpart += shlex.join(["{}={}".format(key, value)]) + " "
log("./make: {}{}{}".format(cdpart, envpart, shlex.join(cmdline)))
class EngineComposer:
"""EngineComposer composes two engines."""
def __init__(self, first: Engine, second: Engine):
self._first = first
self._second = second
def cat_sed_redirect(
self, pattern: str, value: str, source: str, dest: str
) -> None:
"""cat_sed_redirect implements Engine.cat_sed_redirect."""
self._first.cat_sed_redirect(pattern, value, source, dest)
self._second.cat_sed_redirect(pattern, value, source, dest)
def echo_to_file(self, content: str, filepath: str) -> None:
"""echo_to_file implements Engine.echo_to_file"""
self._first.echo_to_file(content, filepath)
self._second.echo_to_file(content, filepath)
def require(self, *executable: str) -> None:
"""require implements Engine.require."""
self._first.require(*executable)
self._second.require(*executable)
def run(
self,
cmdline: List[str],
cwd: Optional[str] = None,
extra_env: Optional[Dict[str, str]] = None,
inputbytes: Optional[bytes] = None,
) -> None:
"""run implements Engine.run."""
self._first.run(cmdline, cwd=cwd, extra_env=extra_env, inputbytes=inputbytes)
self._second.run(cmdline, cwd=cwd, extra_env=extra_env, inputbytes=inputbytes)
def new_engine(options: Options) -> Engine:
"""new_engine creates a new engine instance"""
if options.dry_run():
return CommandDryRunner()
return EngineComposer(CommandDryRunner(), CommandRealExecutor())
class Target(Protocol):
"""Target is a target to build."""
def name(self) -> str:
"""name returns the target name."""
def build(self, engine: Engine, options: Options) -> None:
"""build builds the specified target."""
class SDKGolangGo:
"""SDKGolangGo creates ${cachedir}/SDK/golang."""
# We download a golang SDK from upstream to make sure we
# are always using a specific version of golang/go.
__name = os.path.join(cachedir(), "SDK", "golang")
def name(self) -> str:
return self.__name
def build(self, engine: Engine, options: Options) -> None:
if os.path.isdir(self.__name) and not options.dry_run():
log("./make: {}: already built".format(self.__name))
return
log("./make: building {}...".format(self.__name))
engine.require("mkdir", "curl", "shasum", "rm", "tar", "echo")
filename = "go{}.{}-{}.tar.gz".format(goversion(), goos(), goarch())
url = "https://golang.org/dl/{}".format(filename)
engine.run(["mkdir", "-p", self.__name])
filepath = os.path.join(self.__name, filename)
engine.run(["curl", "-fsSLo", filepath, url])
sha256file = os.path.join(cachedir(), "SDK", "SHA256")
engine.echo_to_file("{} {}".format(gosha256sum(), filepath), sha256file)
engine.run(["shasum", "--check", sha256file])
engine.run(["rm", sha256file])
engine.run(["tar", "-xf", filename], cwd=self.__name)
engine.run(["rm", filepath])
def goroot(self):
"""goroot returns the goroot."""
return os.path.join(self.__name, "go")
class SDKOONIGo:
"""SDKOONIGo creates ${cachedir}/SDK/oonigo."""
# We use a private fork of golang/go on Android as a
# workaround for https://github.com/ooni/probe/issues/1444
__name = os.path.join(cachedir(), "SDK", "oonigo")
def name(self) -> str:
return self.__name
def binpath(self) -> str:
return os.path.join(self.__name, "bin")
def build(self, engine: Engine, options: Options) -> None:
if os.path.isdir(self.__name) and not options.dry_run():
log("./make: {}: already built".format(self.__name))
return
golang_go = SDKGolangGo()
golang_go.build(engine, options)
log("./make: building {}...".format(self.__name))
engine.require("git", "bash")
engine.run(
[
"git",
"clone",
"-b",
"ooni",
"--single-branch",
"--depth",
"8",
"https://github.com/ooni/go",
self.__name,
]
)
engine.run(
["./make.bash"],
cwd=os.path.join(self.__name, "src"),
extra_env={"GOROOT_BOOTSTRAP": golang_go.goroot()},
)
class SDKAndroid:
"""SDKAndroid creates ${cachedir}/SDK/android."""
__name = os.path.join(cachedir(), "SDK", "android")
def name(self) -> str:
return self.__name
def home(self) -> str:
return self.__name
def ndk_home(self) -> str:
return os.path.join(self.home(), "ndk", android_ndk_version())
def build(self, engine: Engine, options: Options) -> None:
if os.path.isdir(self.__name) and not options.dry_run():
log("./make: {}: already built".format(self.__name))
return
log("./make: building {}...".format(self.__name))
engine.require("mkdir", "curl", "echo", "shasum", "rm", "unzip", "mv", "java")
filename = "commandlinetools-{}-{}_latest.zip".format(
android_cmdlinetools_os(), android_cmdlinetools_version()
)
url = "https://dl.google.com/android/repository/{}".format(filename)
engine.run(["mkdir", "-p", self.__name])
filepath = os.path.join(self.__name, filename)
engine.run(["curl", "-fsSLo", filepath, url])
sha256file = os.path.join(cachedir(), "SDK", "SHA256")
engine.echo_to_file(
"{} {}".format(android_cmdlinetools_sha256sum(), filepath), sha256file
)
engine.run(["shasum", "--check", sha256file])
engine.run(["rm", sha256file])
engine.run(["unzip", filename], cwd=self.__name)
engine.run(["rm", filepath])
# See https://stackoverflow.com/a/61176718 to understand why
# we need to reorganize the directories like this:
engine.run(
["mv", "cmdline-tools", android_cmdlinetools_version()], cwd=self.__name
)
engine.run(["mkdir", "cmdline-tools"], cwd=self.__name)
engine.run(
["mv", android_cmdlinetools_version(), "cmdline-tools"], cwd=self.__name
)
engine.run(
sdkmanager_install_cmd(
os.path.join(
self.__name,
"cmdline-tools",
android_cmdlinetools_version(),
"bin",
),
),
inputbytes=b"Y\n", # automatically accept license
)
class OONIProbePrivate:
"""OONIProbePrivate creates ${cachedir}/github.com/ooni/probe-private."""
# We use this private repository to copy the psiphon configuration
# file to embed into the ooniprobe binaries
__name = os.path.join(cachedir(), "github.com", "ooni", "probe-private")
def name(self) -> str:
return self.__name
def copyfiles(self, engine: Engine) -> None:
"""copyfiles copies psiphon config to the repository."""
engine.run(
[
"cp",
os.path.join(self.__name, "psiphon-config.json.age"),
os.path.join("internal", "engine"),
]
)
engine.run(
[
"cp",
os.path.join(self.__name, "psiphon-config.key"),
os.path.join("internal", "engine"),
]
)
def build(self, engine: Engine, options: Options) -> None:
if os.path.isdir(self.__name) and not options.dry_run():
log("./make: {}: already built".format(self.__name))
return
log("./make: building {}...".format(self.__name))
engine.require("git", "cp")
engine.run(
[
"git",
"clone",
"git@github.com:ooni/probe-private",
self.__name,
]
)
class OONIMKAllAAR:
"""OONIMKAllAAR creates ./MOBILE/android/oonimkall.aar."""
__name = os.path.join(".", "MOBILE", "android", "oonimkall.aar")
def name(self) -> str:
return self.__name
def aarfile(self) -> str:
return self.__name
def srcfile(self) -> str:
return os.path.join(".", "MOBILE", "android", "oonimkall-sources.jar")
def build(self, engine: Engine, options: Options) -> None:
if os.path.isfile(self.__name) and not options.dry_run():
log("./make: {}: already built".format(self.__name))
return
ooprivate = OONIProbePrivate()
ooprivate.build(engine, options)
oonigo = SDKOONIGo()
oonigo.build(engine, options)
android = SDKAndroid()
android.build(engine, options)
log("./make: building {}...".format(self.__name))
ooprivate.copyfiles(engine)
engine.require("sh", "javac")
self._go_get_gomobile(engine, options, oonigo)
self._gomobile_init(engine, oonigo, android)
self._gomobile_bind(engine, options, oonigo, android)
# Implementation note: we use proxy scripts for go and gomobile
# that explicitly print what they resolve go and gomobile to using
# `command -v`. This gives us extra confidence that we are really
# using the oonigo fork of golang/go.
def _go_get_gomobile(
self, engine: Engine, options: Options, oonigo: SDKOONIGo
) -> None:
# TODO(bassosimone): find a way to run this command without
# adding extra dependencies to go.mod and go.sum.
cmdline: List[str] = []
cmdline.append(os.path.join(".", "MOBILE", "android", "go"))
cmdline.append("get")
cmdline.append("-u")
if options.verbose():
cmdline.append("-v")
if options.debugging():
cmdline.append("-x")
cmdline.append("golang.org/x/mobile/cmd/gomobile@latest")
engine.run(
cmdline,
extra_env={
"PATH": os.pathsep.join(
[
oonigo.binpath(), # so we use our go fork
os.environ["PATH"], # original path
]
),
"GOPATH": gopath(), # where to install gomobile
},
)
def _gomobile_init(
self,
engine: Engine,
oonigo: SDKOONIGo,
android: SDKAndroid,
) -> None:
cmdline: List[str] = []
cmdline.append(os.path.join(".", "MOBILE", "android", "gomobile"))
cmdline.append("init")
engine.run(
cmdline,
extra_env={
"PATH": os.pathsep.join(
[
os.path.join(gopath(), "bin"), # for gomobile
oonigo.binpath(), # for our go fork
os.environ["PATH"], # original environment
]
),
"ANDROID_HOME": android.home(),
"ANDROID_NDK_HOME": android.ndk_home(),
},
)
def _gomobile_bind(
self,
engine: Engine,
options: Options,
oonigo: SDKOONIGo,
android: SDKAndroid,
) -> None:
cmdline: List[str] = []
cmdline.append(os.path.join(".", "MOBILE", "android", "gomobile"))
cmdline.append("bind")
if options.verbose():
cmdline.append("-v")
if options.debugging():
cmdline.append("-x")
cmdline.append("-target")
cmdline.append("android")
cmdline.append("-o")
cmdline.append(self.__name)
cmdline.append("-tags")
cmdline.append("ooni_psiphon_config")
cmdline.append("-ldflags")
cmdline.append("-s -w")
cmdline.append("./pkg/oonimkall")
engine.run(
cmdline,
extra_env={
"PATH": os.pathsep.join(
[
os.path.join(gopath(), "bin"), # for gomobile
oonigo.binpath(), # for our go fork
os.environ["PATH"], # original environment
]
),
"ANDROID_HOME": android.home(),
"ANDROID_NDK_HOME": android.ndk_home(),
},
)
class BundleJAR:
"""BundleJAR creates ./MOBILE/android/bundle.jar."""
# We upload the bundle.jar file to maven central to bless
# a new release of the OONI libraries for Android.
__name = os.path.join(".", "MOBILE", "android", "bundle.jar")
def name(self) -> str:
return self.__name
def build(self, engine: Engine, options: Options) -> None:
if os.path.isfile(self.__name) and not options.dry_run():
log("./make: {}: already built".format(self.__name))
return
oonimkall = OONIMKAllAAR()
oonimkall.build(engine, options)
log("./make: building {}...".format(self.__name))
engine.require("cp", "gpg", "jar")
version = datetime.datetime.now().strftime("%Y.%m.%d-%H%M%S")
engine.run(
[
"cp",
oonimkall.aarfile(),
os.path.join("MOBILE", "android", "oonimkall-{}.aar".format(version)),
]
)
engine.run(
[
"cp",
oonimkall.srcfile(),
os.path.join(
"MOBILE", "android", "oonimkall-{}-sources.jar".format(version)
),
]
)
engine.cat_sed_redirect(
"@VERSION@",
version,
os.path.join("MOBILE", "template.pom"),
os.path.join("MOBILE", "android", "oonimkall-{}.pom".format(version)),
)
names = (
"oonimkall-{}.aar".format(version),
"oonimkall-{}-sources.jar".format(version),
"oonimkall-{}.pom".format(version),
)
for name in names:
engine.run(
[
"gpg",
"-abu",
"simone@openobservatory.org",
name,
],
cwd=os.path.join(".", "MOBILE", "android"),
)
allnames = [name + ".asc" for name in names]
allnames.extend(names)
engine.run(
[
"jar",
"-cf",
"bundle.jar",
*allnames,
],
cwd=os.path.join(".", "MOBILE", "android"),
)
class Android:
"""Android is the toplevel android target."""
def name(self) -> str:
return "android"
def build(self, engine: Engine, options: Options) -> None:
bundlejar = BundleJAR()
bundlejar.build(engine, options)
TARGETS: List[Target] = [
Android(),
BundleJAR(),
OONIMKAllAAR(),
OONIProbePrivate(),
SDKAndroid(),
SDKGolangGo(),
SDKOONIGo(),
]
def main() -> None:
"""main function"""
alltargets: Dict[str, Target] = dict((t.name(), t) for t in TARGETS)
options = ConfigFromCLI.parse(list(alltargets.keys()))
engine = new_engine(options)
# note that we check whether the target is known in parse()
selected = alltargets[options.target()]
selected.build(engine, options)
if __name__ == "__main__":
main()

View File

@ -1,28 +0,0 @@
#!/bin/bash
set -e
pkgname=oonimkall
version=$(date -u +%Y.%m.%d-%H%M%S)
baseurl=https://api.bintray.com/content/ooni/android/$pkgname/$version/org/ooni/$pkgname/$version
aarfile=./MOBILE/android/$pkgname.aar
aarfile_version=./MOBILE/android/$pkgname-$version.aar
ln $aarfile $aarfile_version
sourcesfile=./MOBILE/android/$pkgname-sources.jar
sourcesfile_version=./MOBILE/android/$pkgname-$version-sources.jar
ln $sourcesfile $sourcesfile_version
pomfile=./MOBILE/android/$pkgname-$version.pom
pomtemplate=./MOBILE/template.pom
user=bassosimone
cat $pomtemplate|sed "s/@VERSION@/$version/g" > $pomfile
if [ -z $MOBILE_BINTRAY_API_KEY ]; then
echo "FATAL: missing MOBILE_BINTRAY_API_KEY variable" 1>&2
exit 1
fi
# We currently publish the mobile-staging branch. To cleanup we can fetch all the versions using
# the <curl -s $user:$MOBILE_BINTRAY_API_KEY https://api.bintray.com/packages/ooni/android/oonimkall>
# query, which returns a list of versions. From such list, we can delete the versions we
# don't need using <DELETE /packages/:subject/:repo/:package/versions/:version>.
for filename in $aarfile_version $sourcesfile_version $pomfile; do
basefilename=$(basename $filename)
curl -sT $filename -u $user:$MOBILE_BINTRAY_API_KEY $baseurl/$basefilename?publish=1 >/dev/null
done
echo "implementation 'org.ooni:oonimkall:$version'"

View File

@ -1,23 +0,0 @@
#!/bin/bash
set -e
pkgname=oonimkall
version=$(date -u +%Y.%m.%d-%H%M%S)
baseurl=https://api.bintray.com/content/ooni/ios/$pkgname/$version
framework=./MOBILE/ios/$pkgname.framework
frameworkzip=./MOBILE/ios/$pkgname.framework.zip
podspecfile=./MOBILE/ios/$pkgname.podspec
podspectemplate=./MOBILE/template.podspec
user=bassosimone
(cd ./MOBILE/ios && rm -f $pkgname.framework.zip && zip -yr $pkgname.framework.zip $pkgname.framework)
cat $podspectemplate|sed "s/@VERSION@/$version/g" > $podspecfile
if [ -z $MOBILE_BINTRAY_API_KEY ]; then
echo "FATAL: missing MOBILE_BINTRAY_API_KEY variable" 1>&2
exit 1
fi
# We currently publish the mobile-staging branch. To cleanup we can fetch all the versions using
# the <curl -s $user:$MOBILE_BINTRAY_API_KEY https://api.bintray.com/packages/ooni/android/oonimkall>
# query, which returns a list of versions. From such list, we can delete the versions we
# don't need using <DELETE /packages/:subject/:repo/:package/versions/:version>.
curl -sT $frameworkzip -u $user:$MOBILE_BINTRAY_API_KEY $baseurl/$pkgname-$version.framework.zip?publish=1 >/dev/null
curl -sT $podspecfile -u $user:$MOBILE_BINTRAY_API_KEY $baseurl/$pkgname-$version.podspec?publish=1 >/dev/null
echo "pod 'oonimkall', :podspec => 'https://dl.bintray.com/ooni/ios/$pkgname-$version.podspec'"