# vim: filetype=yaml sw=2
debug: '[% GET ! ENV.RBM_NO_DEBUG %]'
compress_tar: gz
output_dir: "out/[% project %]"
tmp_dir: '[% c("basedir") %]/tmp'
build_log: '[% GET ENV.RBM_LOGS_DIR ? ENV.RBM_LOGS_DIR : "logs" %]/[% project %][% IF c("var/osname") %]-[% c("var/osname") %][% END %].log'

pkg_type: build

steps:
  src-tarballs:
    compress_tar: xz
    src-tarballs: |
      #!/bin/bash
      set -e
      mkdir -p '[% dest_dir %]'
      mv -vf '[% project %]-[% c("version") %].tar.xz' '[% dest_dir %]/[% c("filename") %]'

  list_toolchain_updates:
    build_log: '-'
    list_toolchain_updates: '[% INCLUDE list_toolchain_updates %]'

  cargo_vendor:
    output_dir: "out/[% project %]/cargo_vendor"
    var:
      container:
        suite: bullseye
        arch: amd64
      pre_pkginst: ''
      deps:
        - patch
        - bzip2
    cargo_vendor: |
      #!/bin/bash
      [% c("var/set_default_env") %]
      mkdir /var/tmp/dist
      # NOTE: since different projects need different rust versions, 
      # we use the version of cargo produced by the rust project
      # build rather than the build container's debian package.
      # Thus, any project that wants to run a `cargo_vendor` step
      # must be sure to provide the rust project as an `input_file`.
      # See, e.g.,`application-services/config.steps.cargo_vendor.input_files`.
      tar -C /var/tmp/dist -xf [% c('input_files_by_name/rust') %]
      export PATH="/var/tmp/dist/rust/bin:$PATH"
      tar -xf [% project %]-[% c('version') %].tar.gz
      cd [% project %]-[% c('version') %]
      [% c("var/pre_cargo_vendor") %]
      cargo vendor vendor [% c("var/cargo_vendor_opts") %]
      [% c('tar', {
        tar_src => [ 'vendor' ],
        tar_args => '-caf ' _ dest_dir _ '/' _ c('filename'),
        }) %]
      cd [% dest_dir %]
      fname="out/[% project %]/cargo_vendor/[% c('filename') %]"
      echo
      echo "Finished creating $fname"
      sha256sum "[% c('filename') %]"
      echo "You can upload it with:"
      echo "  scp -p $fname people.torproject.org:public_html/mirrors/sources"

# buildconf contains build options that the user can change in rbm.local.conf
# When adding a new option to buildconf, a default value should be defined
# in var/build_id, so that changing this option does not affect the build_id.
buildconf:
  num_procs: '[% GET ENV.RBM_NUM_PROCS ? ENV.RBM_NUM_PROCS : "4" %]'
  git_signtag_opt: '-s'

var:
  torbrowser_version: '11.5a9'
  torbrowser_build: 'build1'
  torbrowser_incremental_from:
    - 11.5a8
  project_name: tor-browser
  multi_lingual: 0
  build_mar: 1
  # By default, we sort the list of installed packages. This allows sharing
  # containers with identical list of packages, even if they are not listed
  # in the same order. In the cases where the installation order is
  # important, sort_deps should be set to 0.
  sort_deps: 1
  build_id: '[% sha256(c("var/build_id_txt", { buildconf => { num_procs => 4 } })).substr(0, 6) %]'
  build_id_txt: |
    [% c("version") %]
    [% IF c("git_hash") || c("hg_hash"); GET c("abbrev"); END; %]
    [% IF c("var/container/use_container") && ! c("var/container/global_disable") -%]
    [% c("var/container/suite") %]
    [% c("var/container/arch") %]
    [% END -%]
    input_files: [% c("input_files_id") %]
    build:
    [% SET step = c("step") -%]
    [% c(step, { filename => 'f', output_dir => '/out', norec => {} }) %]
  container:
    dir: '[% c("rbm_tmp_dir") %]/rbm-containers/[% sha256(c("build_id")) %]'
    user: rbm
    disable_network:
      # disable network in the build scripts
      build: 1
  input_files_list: |
    [% FOREACH file IN c("input_files_by_name").keys.sort -%]
    [% c("input_files_by_name/" _ file) %]
    [% END -%]

  faketime: "faketime -f \"[% USE date; GET date.format(c('timestamp'), format = '%Y-%m-%d %H:%M:%S') %]\""
  touch: "[% USE date %]touch -m -t [% date.format(c('timestamp'), format = '%Y%m%d%H%M') %]"

  locale_ja: ja
  locales:
    - ar
    - ca
    - cs
    - da
    - de
    - el
    - es-AR
    - es-ES
    - fa
    - fr
    - ga-IE
    - he
    - hu
    - id
    - is
    - it
    - '[% c("var/locale_ja") %]'
    - ka
    - ko
    - lt
    - mk
    - ms
    - my
    - nb-NO
    - nl
    - pl
    - pt-BR
    - ro
    - ru
    - sv-SE
    - th
    - tr
    - vi
    - zh-CN
    - zh-TW
  locales_mobile:
    - ar
    - ca
    - cs
    - da
    - de
    - el
    - es-rAR
    - es-rES
    - fa
    - fr
    - ga-rIE
    - hu
    - in
    - is
    - it
    - iw
    - ja
    - ka
    - ko
    - lt
    - my
    - nb-rNO
    - nl
    - pl
    - pt-rBR
    - ro
    - ru
    - sv-rSE
    - th
    - tr
    - vi
    - zh-rCN
    - zh-rTW

  sign_build: '[% ENV.RBM_SIGN_BUILD %]'
  sign_build_gpg_opts: '[% ENV.RBM_GPG_OPTS %]'

  rezip: |
    rezip_tmpdir=$(mktemp -d)
    mkdir -p "$rezip_tmpdir/z"
    unzip -d "$rezip_tmpdir/z" -- [% c("rezip_file") %] || [ $? -lt 3 ]
    pushd "$rezip_tmpdir/z"
    [% c("zip", {
      zip_src => [ '.' ],
      zip_args => '$rezip_tmpdir/new.zip',
    }) %]
    popd
    mv -f -- "$rezip_tmpdir/new.zip" [% c("rezip_file") %]
    rm -Rf "$rezip_tmpdir"

  set_default_env: |
    set -e
    [% FOREACH env = c('ENV') -%]
    export [% env.key %]="[% env.value %]"
    [% END -%]
    rootdir=$(pwd)
    export SHELL=/bin/bash
    export HOME=$rootdir
    umask 0022
    [% IF c("var/container/global_disable") -%]
      rm -Rf /var/tmp/build /var/tmp/dist
    [% END -%]

  DOCSDIR_project: '[% project %]'
  set_PTDIR_DOCSDIR: |
    PTDIR="$distdir/TorBrowser/Tor/PluggableTransports"
    DOCSDIR="$distdir/TorBrowser/Docs/[% c("var/DOCSDIR_project") %]"

targets:
  notarget: linux-x86_64
  noint:
    debug: 0

  release:
    var:
      release: 1
      channel: release
  alpha:
    var:
      alpha: 1
      channel: alpha
  nightly:
    fetch: 1
    var:
      nightly: 1
      channel: nightly
      torbrowser_version: |
        [%
           IF ENV.TORBROWSER_NIGHTLY_VERSION;
                GET ENV.TORBROWSER_NIGHTLY_VERSION;
           ELSIF c("var/testbuild");
                GET "testbuild";
           ELSE;
                GET c("var_p/nightly_torbrowser_version");
           END;
        -%]
      # For nightly builds, we support updates for a limited set of locales
      mar_locales:
        - de
        - es-ES
        - fr
        - ru
      max_torbrowser_incremental_from: 2
      build_infos_json: 1

  torbrowser-testbuild:
    - testbuild
    - alpha
  testbuild:
    var:
      testbuild: 1
      # Don't create mar files to save time
      build_mar: 0

  torbrowser-android-armv7:
    - android-armv7
    - android
  android-armv7:
    arch: armv7
    var:
      android-armv7: 1
      osname: android-armv7
      toolchain_arch: arm
      abi: armeabi-v7a
      cross_prefix: armv7a-linux-androideabi
  torbrowser-android-x86:
    - android-x86
    - android
  android-x86:
    arch: x86
    var:
      android-x86: 1
      osname: android-x86
      toolchain_arch: x86
      abi: x86
      cross_prefix: i686-linux-android
  torbrowser-android-x86_64:
    - android-x86_64
    - android
  android-x86_64:
    arch: x86_64
    var:
      android-x86_64: 1
      osname: android-x86_64
      toolchain_arch: x86_64
      abi: x86_64
      cross_prefix: x86_64-linux-android
  torbrowser-android-aarch64:
    - android-aarch64
    - android
  android-aarch64:
    arch: aarch64
    var:
      android-aarch64: 1
      osname: android-aarch64
      toolchain_arch: arm64
      abi: arm64-v8a
      cross_prefix: aarch64-linux-android
  android:
    var:
      android: 1
      compiler: android-toolchain
      android_min_api: '[% GET c("var/android_min_api_" _ c("arch")) %]'
      CC: '[% c("var/cross_prefix") %][% c("var/android_min_api") %]-clang'
      CXX: '[% c("var/cross_prefix") %][% c("var/android_min_api") %]-clang'
      # API 21 is the minimum we currently support on Android
      android_min_api_armv7: 21
      android_min_api_x86: 21
      android_min_api_x86_64: 21
      android_min_api_aarch64: 21
      container:
        suite: bullseye
        arch: amd64
        disable_network:
          # Disable network in the script for merging GeckoView .aar files
          merge_aars: 1
      deps:
        - build-essential
        - python3
        - python3-distutils
        - automake
        - libtool
        - zip
        - unzip
        - libtinfo5
      configure_opt: '--host=[% c("var/cross_prefix") %] CC=[% c("var/CC") %] [% c("var/configure_opt_project") %]'

      pre_pkginst: |
          SNAPSHOT_VERSION=20191201T212855Z
          OPENJDK_URL=https://snapshot.debian.org/archive/debian/$SNAPSHOT_VERSION/pool/main/o/openjdk-8
          JDK_VERSION=8u232-b09-1~deb9u1_amd64
          apt-get install -y -q wget ca-certificates-java
          wget $OPENJDK_URL/openjdk-8-jdk-headless_$JDK_VERSION.deb
          wget $OPENJDK_URL/openjdk-8-jre-headless_$JDK_VERSION.deb
          echo 92b4f8fb77d793a86e0b03b3b0750592b40a26a5d75956d10dd984a7b3aad4c9 openjdk-8-jdk-headless_$JDK_VERSION.deb | sha256sum -c
          echo 84bf52b6cce20ead08b0d5b9fd9b81b4aa3da385ca951b313fe11d5cb1aa4d17 openjdk-8-jre-headless_$JDK_VERSION.deb | sha256sum -c
          apt-get install -y -q ./openjdk-8-jre-headless_$JDK_VERSION.deb ./openjdk-8-jdk-headless_$JDK_VERSION.deb
  torbrowser-linux-x86_64:
    - linux-x86_64
    - linux
  torbrowser-linux-x86_64-asan:
    - linux-asan
    - linux-x86_64
    - linux
  torbrowser-linux-i686:
    - linux-i686
    - linux
  torbrowser-linux-arm:
    - linux-arm
    - linux-cross
    - linux
  torbrowser-linux-ppc64le:
    - linux-ppc64le
    - linux-cross
    - linux
  torbrowser-linux-ppc64:
    - linux-ppc64
    - linux-cross
    - linux
  torbrowser-linux-ppc:
    - linux-ppc
    - linux-cross
    - linux
  linux-x86_64:
    arch: x86_64
    var:
      linux-x86_64: 1
      osname: linux-x86_64
      linux-cross: 0
      arch_debian: amd64
      arch_kernel: x86
      # We only support RLBox on the nightly channel and x86_64 for now
      rlbox: 0
  linux-i686:
    arch: i686
    var:
      linux-i686: 1
      osname: linux-i686
      linux-cross: 0
      configure_opt: '--host=i686-linux-gnu CFLAGS=-m32 CXXFLAGS=-m32 LDFLAGS=-m32 [% c("var/configure_opt_project") %]'
      arch_debian: i386
      arch_kernel: x86
  linux-arm:
    arch: arm
    var:
      linux-arm: 1
      osname: linux-arm
      crosstarget: arm-linux-gnueabihf
      arch_debian: armhf
      arch_kernel: arm
  linux-ppc64le:
    arch: ppc64le
    var:
      linux-ppc64le: 1
      osname: linux-ppc64le
      crosstarget: powerpc64le-linux-gnu
      configure_opt: '--host=powerpc64le-linux-gnu [% c("var/configure_opt_project") %]'
      arch_debian: ppc64el
      arch_kernel: powerpc
  linux-ppc64:
    arch: ppc64
    var:
      linux-ppc64: 1
      osname: linux-ppc64
      crosstarget: powerpc64-linux-gnu
      configure_opt: '--host=powerpc64-linux-gnu [% c("var/configure_opt_project") %]'
      arch_debian: ppc64
      arch_kernel: powerpc
  linux-ppc:
    arch: ppc
    var:
      linux-ppc: 1
      osname: linux-ppc
      crosstarget: powerpc-linux-gnu
      configure_opt: '--host=powerpc-linux-gnu [% c("var/configure_opt_project") %]'
      arch_debian: powerpc
      arch_kernel: powerpc
  linux-cross:
    var:
      linux-cross: 1
      container:
        arch: amd64
      configure_opt: '--host=[% c("var/crosstarget") %] [% c("var/configure_opt_project") %]'
  linux:
    var:
      linux: 1
      compiler: gcc
      configure_opt: '[% c("var/configure_opt_project") %]'
      # Only build Namecoin for linux on nightly
      namecoin: '[% c("var/nightly") %]'
      container:
        suite: jessie
        arch: amd64
      pre_pkginst: dpkg --add-architecture i386
      deps:
        - libc6-dev-i386
        - lib32stdc++6
        - build-essential
        - python
        - bison
        - hardening-wrapper
        - automake
        - libtool
        - zip
        - unzip
  linux-asan:
    var:
      asan: 1
      # RLBox needs clang to create .wasm files but we use mostly GCC for our
      # ASan builds. Thus, the compilation currently breaks with RLBox enabled.
      # See: tor-browser-build#40063.
      rlbox: 0

  torbrowser-windows-i686:
    - windows-i686
    - windows
  torbrowser-windows-x86_64:
    - windows-x86_64
    - windows
  windows-x86_64:
    arch: x86_64
    var:
      windows-x86_64: 1
      windows-i686: 0
      osname: windows-x86_64
      # HEASLR is 64 bit only (see bug 12968)
      flag_HEASLR: '-Wl,--high-entropy-va'
  windows-i686:
    arch: i686
    var:
      windows-i686: 1
      windows-x86_64: 0
      osname: windows-i686
      # mingw-w64 does not support SEH on 32bit systems. Be explicit about that.
      flag_noSEH: '-Wl,--no-seh'
  windows:
    var:
      windows: 1
      container:
        suite: bullseye
        arch: amd64
      configure_opt: '--host=[% c("arch") %]-w64-mingw32 CFLAGS="[% c("var/CFLAGS") %]" LDFLAGS="[% c("var/LDFLAGS") %]" [% c("var/configure_opt_project") %]'
      CFLAGS: '-fstack-protector-strong -fno-strict-overflow -Wno-missing-field-initializers -Wformat -Wformat-security [% c("var/flag_mwindows") %]'
      LDFLAGS: '-Wl,--dynamicbase -Wl,--nxcompat -Wl,--enable-reloc-section -Wl,--no-insert-timestamp -lssp -L$gcclibs [% c("var/flag_HEASLR") %] [% c("var/flag_noSEH") %] [% c("var/flag_mwindows") %]'
      flag_mwindows: '-mwindows'
      compiler: mingw-w64
      faketime_path: /usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
      deps:
        - build-essential
        - python3
        - python3-distutils
        - bison
        - automake
        - libtool
        - zip
        - unzip

  torbrowser-osx-x86_64:
    - osx-x86_64
  osx-x86_64:
    arch: x86_64
    var:
      osx: 1
      osname: osx-x86_64
      container:
        suite: bullseye
        arch: amd64
      compiler: 'macosx-toolchain'
      configure_opt: '--host=x86_64-apple-darwin CC="x86_64-apple-darwin-clang [% c("var/FLAGS") %]" CXX="x86_64-apple-darwin-clang++ [% c("var/FLAGS") %]" [% c("var/configure_opt_project") %]'
      FLAGS: "-target x86_64-apple-darwin -B $cctoolsdir -isysroot $sysrootdir"
      LDFLAGS: "-Wl,-syslibroot,$sysrootdir -Wl,-dead_strip -Wl,-pie"
      macosx_deployment_target: '10.12'
      locale_ja: ja-JP-mac
      rlbox: 0
      deps:
        - build-essential
        - python3
        - python3-distutils
        - automake
        - libtool
        - zip
        - unzip
      faketime_path: /usr/lib/x86_64-linux-gnu/faketime/libfaketime.so.1
      set_PTDIR_DOCSDIR: |
        PTDIR="$distdir/Contents/MacOS/Tor/PluggableTransports"
        DOCSDIR="$distdir/Contents/Resources/TorBrowser/Docs/[% c("var/DOCSDIR_project") %]"

  # The no_build_id target can be useful if you want to quickly display
  # a build template or other option but don't want to spend time to
  # compute the various build ids
  no_build_id:
    # The defaut timestamp value will use the commit time of the
    # selected commit for the project, which will require cloning the
    # git repository if it is not present. When we use the no_build_id
    # target to display a script, we usually don't care about such
    # details, so we set timestamp to 0 to avoid unnecessary cloning.
    timestamp: 0
    var:
      build_id: 1

  no_containers:
    var:
      container:
        global_disable: 1

# change the default gpg_wrapper to allow git tag signed using an
# expired key.
# https://bugs.torproject.org/19737
gpg_wrapper: |
  #!/bin/bash
  export LC_ALL=C
  [%
      IF c('gpg_keyring');
          SET gpg_kr = '--keyring ' _ path(c('gpg_keyring'), path(c('gpg_keyring_dir'))) _ ' --no-default-keyring';
      END;
  -%]
  gpg_verify=0
  for opt in "$@"
  do
    test "$opt" = '--verify' && gpg_verify=1
  done
  if [ $gpg_verify = 1 ]
  then
        [% c('gpg_bin') %] [% c('gpg_args') %] --with-fingerprint [% gpg_kr %] "$@" | sed 's/^\[GNUPG:\] EXPKEYSIG /\[GNUPG:\] GOODSIG /'
        exit ${PIPESTATUS[0]}
  else
        exec [% c('gpg_bin') %] [% c('gpg_args') %] --with-fingerprint [% gpg_kr %] "$@"
  fi

remote_start: '[% IF c("var/container/use_container") && ! c("var/container/global_disable") %][% c("container/remote_start") %][% END %]'
remote_exec: '[% IF c("var/container/use_container") && ! c("var/container/global_disable") %][% c("container/remote_exec") %][% END %]'
remote_put: '[% IF c("var/container/use_container") && ! c("var/container/global_disable") %][% c("container/remote_put") %][% END %]'
remote_get: '[% IF c("var/container/use_container") && ! c("var/container/global_disable") %][% c("container/remote_get") %][% END %]'
remote_finish: '[% IF c("var/container/use_container") && ! c("var/container/global_disable") %][% c("container/remote_finish") %][% END %]'

container:
  remote_start: |
    #!/bin/sh
    set -e
    if [ $(ls -1 '[% c("remote_srcdir", { error_if_undef => 1 }) %]/container-image_'* | wc -l) -ne 1 ]
    then
      echo "Can't find container image in input files" >&2
      ls -l '[% c("remote_srcdir") %]' >&2
      exit 1
    fi
    [% c("rbmdir") %]/container extract '[% c("var/container/dir") %]' '[% c("remote_srcdir", { error_if_undef => 1 }) %]/container-image_'*
    test -d '[% c("var/container/dir") %]'/home/rbm || \
      [% c("rbmdir") %]/container run --chroot='[% c("var/container/dir") %]' -- /usr/sbin/useradd -m [% c("var/container/user") %]

  remote_exec: |
    #!/bin/sh
    set -e
    [% IF c("interactive") -%]
      echo Container directory: [% shell_quote(c("var/container/dir")) %]
    [% END -%]
    mkdir -p '[% c("var/container/dir", { error_if_undef => 1 }) %]'/rbm
    echo '#!/bin/sh' > '[% c("var/container/dir") %]'/rbm/cmd
    echo [% shell_quote(c('exec_cmd')) %] >> '[% c("var/container/dir") %]'/rbm/cmd
    echo '#!/bin/sh' > '[% c("var/container/dir") %]'/rbm/run
    [% IF c("var/container/disable_network/" _ c("exec_name")) -%]
      # Some programs such as gradle need the lo interface to be up.
      # See for example tor-browser#31293
      echo 'ip link set lo up' >> '[% c("var/container/dir") %]'/rbm/run
    [% END -%]
    [% IF c('exec_as_root'); SET user = 'root'; ELSE; SET user = c("var/container/user", { error_if_undef => 1 }); END; %]
    echo 'su - [% user %] -c /rbm/cmd' >> '[% c("var/container/dir") %]'/rbm/run
    chmod +x '[% c("var/container/dir") %]'/rbm/cmd
    chmod +x '[% c("var/container/dir") %]'/rbm/run
    [%
       IF c("var/container/disable_network/" _ c("exec_name"));
         SET disable_network = '--disable-network';
       ELSE;
         SET disable_network = '';
       END;
    -%]
    [% c("rbmdir") %]/container run [% disable_network %] --chroot='[% c("var/container/dir") %]' -- /rbm/run

  remote_put: |
    #!/bin/sh
    set -e
    [%
      SET src = shell_quote(c('put_src', { error_if_undef => 1 }));
      SET dst = shell_quote(c('put_dst', { error_if_undef => 1 }));
    -%]
    [% c("rbmdir") %]/container put '[% c("var/container/dir") %]' [% src %] [% dst %] [% c("var/container/user") %]

  remote_get: |
    #!/bin/sh
    set -e
    [%
      SET src = shell_quote(c('get_src', { error_if_undef => 1 }));
      SET dst = shell_quote(c('get_dst', { error_if_undef => 1 }));
    -%]
    [% c("rbmdir") %]/container get '[% c("var/container/dir") %]' [% src %] [% dst %]

  remote_finish: |
    #!/bin/sh
    set -e
    [% c("rbmdir") %]/container remove '[% c("var/container/dir") %]'

ENV:
  TZ: UTC
  LC_ALL: C
--- |
  # This part of the file contains options written in perl
  use IO::CaptureOutput qw(capture_exec);
  (
    var_p => {
      nightly_torbrowser_version => sub {
        state $version = '';
        return $version if $version;
        my (undef, undef, undef, $day, $mon, $year) = gmtime;
        $version = sprintf("tbb-nightly.%u.%02u.%02u", $year + 1900, $mon + 1, $day);
        return $version;
      },
      nightly_torbrowser_incremental_from => sub {
        my ($project, $options) = @_;
        my $nightly_dir = project_config($project, 'basedir', $options) . '/nightly';
        my $current_version = project_config($project, 'var/torbrowser_version', $options);
        use Path::Tiny;
        return [] unless -d $nightly_dir;
        my @dirs = sort map { $_->basename } path($nightly_dir)->children(qr/^tbb-nightly\./);
        my $nb_incr = project_config($project, ['var', 'max_torbrowser_incremental_from'], $options);
        my @res;
        while ($nb_incr > 0) {
          my $dir = pop @dirs;
          last unless $dir;
          next if $dir eq $current_version;
          $nb_incr--;
          push @res, $dir;
        }
        return [@res];
      },
    },
  )
