tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

versionCode.gradle (3893B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 import java.text.SimpleDateFormat
      6 
      7 /**
      8 * Generates a "unique" versionCode for release builds.
      9 *
     10 * The resulting versionCode depends on the local timezone of the machine running this script.
     11 * This is OK because we only use this for release builds on CI, where the timezone is fixed.
     12 *
     13 * Format: byDDDHHmm
     14 *   - b    = base / epoch digit
     15 *            Historically hardcoded to "3". This digit is incremented when the year-derived
     16 *            component overflows its single digit (e.g., in 2026).
     17 *   - y    = 1 digit derived from (two-digit year - 16), modulo 10
     18 *   - DDD  = day of year (001–366), zero-padded to 3 digits
     19 *   - HHmm = 24h time (00–23)(00–59)
     20 *
     21 * Example:
     22 *   Sept 6, 2017 @ 09:41
     23 *     year = 17 - 16 = 1
     24 *     base = 3
     25 *     -> 3-1-249-09-41 -> 312490941
     26 *
     27 * Historical note:
     28 *   Focus first shipped in 2017. The original scheme unconditionally used (yy - 16) which
     29 *   only fit in a single digit from 2017–2025.
     30 *
     31 * 2026 rollover:
     32 *   In 2026, (yy - 16) became 10. Allowing this to grow to two digits breaks the intended
     33 *   byDDDHHmm layout and can exceed Play / int limits.
     34 *
     35 *   To preserve:
     36 *     - a single-digit `y`
     37 *     - monotonic versionCodes across year boundaries
     38 *
     39 *   we keep `y` as (yearOffset % 10) and carry overflow into the base digit:
     40 *     2025 -> base=3, y=9 -> 39DDDHHmm
     41 *     2026 -> base=4, y=0 -> 40DDDHHmm
     42 */
     43 ext {
     44    // "Epoch" digit(s). Historically this was "3".
     45    // We bump it by +1 each time (yy - 16) crosses another multiple of 10 (i.e., 2026, 2036, ...).
     46    def epochDigit = 3
     47 
     48    def today = new Date()
     49 
     50    def yy = (new SimpleDateFormat("yy").format(today) as int)
     51    def yearOffset = yy - 16 // 2017 -> 1, 2025 -> 9, 2026 -> 10, etc.
     52    if (yearOffset < 0) {
     53        throw new GradleException(
     54            "versionCode yearOffset underflow: yearOffset=$yearOffset (yy=$yy)."
     55        )
     56    }
     57 
     58    // Keep the "y" component as one digit, and carry overflow into the epoch digit.
     59    def carry = (int) (yearOffset / 10)
     60    def yearDigit = (int) (yearOffset % 10)
     61 
     62    def epoch = epochDigit + carry
     63    if (epoch >= 10) {
     64        throw new GradleException(
     65            "versionCode epoch overflow: epoch=$epoch (yy=$yy). Update versionCode scheme."
     66        )
     67    }
     68 
     69    // We use the day in the Year (e.g. 248) as opposed to month + day (0510) because it's one digit shorter.
     70    // If needed we pad with zeros (e.g. 25 -> 025)
     71    def day = String.format("%03d", (new SimpleDateFormat("D").format(today) as int))
     72 
     73    // We append the hour in day (24h) and minute in hour (7:26 pm -> 1926). We do not append
     74    // seconds. This assumes that we do not need to build multiple release(!) builds the same
     75    // minute.
     76    def time = new SimpleDateFormat("HHmm").format(today)
     77 
     78    // Build the final versionCode using the previously-calculated inputs.
     79    def versionCode = ("${epoch}${yearDigit}${day}${time}" as long)
     80 
     81    // The Play Console has historically enforced a 2,100,000,000 cap. Keep a defensive ceiling here.
     82    // Even without this, Android requires versionCode to fit in a signed 32-bit int.
     83    def MAX_VERSION_CODE = 2_100_000_000
     84    if (versionCode > MAX_VERSION_CODE) {
     85        throw new GradleException(
     86            "Generated versionCode exceeds MAX_VERSION_CODE ($MAX_VERSION_CODE): $versionCode (from $versionCodeStr)"
     87        )
     88    }
     89    if (versionCode > Integer.MAX_VALUE) {
     90        throw new GradleException(
     91            "Generated versionCode exceeds Integer.MAX_VALUE: $versionCode (from $versionCodeStr)"
     92        )
     93    }
     94 
     95    generatedVersionCode = (versionCode as int)
     96    println("Generated versionCode: $generatedVersionCode")
     97    println()
     98 }