1*8975f5c5SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*8975f5c5SAndroid Build Coastguard Worker# Copyright 2018 The Chromium Authors 3*8975f5c5SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*8975f5c5SAndroid Build Coastguard Worker# found in the LICENSE file. 5*8975f5c5SAndroid Build Coastguard Worker"""Returns a timestamp that approximates the build date. 6*8975f5c5SAndroid Build Coastguard Worker 7*8975f5c5SAndroid Build Coastguard Workerbuild_type impacts the timestamp generated, both relative to the date of the 8*8975f5c5SAndroid Build Coastguard Workerlast recent commit: 9*8975f5c5SAndroid Build Coastguard Worker- default: the build date is set to the most recent first Sunday of a month at 10*8975f5c5SAndroid Build Coastguard Worker 5:00am. The reason is that it is a time where invalidating the build cache 11*8975f5c5SAndroid Build Coastguard Worker shouldn't have major repercussions (due to lower load). 12*8975f5c5SAndroid Build Coastguard Worker- official: the build date is set to the time of the most recent commit. 13*8975f5c5SAndroid Build Coastguard WorkerEither way, it is guaranteed to be in the past and always in UTC. 14*8975f5c5SAndroid Build Coastguard Worker""" 15*8975f5c5SAndroid Build Coastguard Worker 16*8975f5c5SAndroid Build Coastguard Worker# The requirements for the timestamp: 17*8975f5c5SAndroid Build Coastguard Worker# (1) for the purposes of continuous integration, longer duration 18*8975f5c5SAndroid Build Coastguard Worker# between cache invalidation is better, but >=1mo is preferable. 19*8975f5c5SAndroid Build Coastguard Worker# (2) for security purposes, timebombs would ideally be as close to 20*8975f5c5SAndroid Build Coastguard Worker# the actual time of the build as possible. It must be in the past. 21*8975f5c5SAndroid Build Coastguard Worker# (3) HSTS certificate pinning is valid for 70 days. To make CI builds enforce 22*8975f5c5SAndroid Build Coastguard Worker# HTST pinning, <=1mo is preferable. 23*8975f5c5SAndroid Build Coastguard Worker# 24*8975f5c5SAndroid Build Coastguard Worker# On Windows, the timestamp is also written in the PE/COFF file header of 25*8975f5c5SAndroid Build Coastguard Worker# executables of dlls. That timestamp and the executable's file size are 26*8975f5c5SAndroid Build Coastguard Worker# the only two pieces of information that identify a given executable on 27*8975f5c5SAndroid Build Coastguard Worker# the symbol server, so rarely changing timestamps can cause conflicts there 28*8975f5c5SAndroid Build Coastguard Worker# as well. We only upload symbols for official builds to the symbol server. 29*8975f5c5SAndroid Build Coastguard Worker 30*8975f5c5SAndroid Build Coastguard Worker 31*8975f5c5SAndroid Build Coastguard Workerimport argparse 32*8975f5c5SAndroid Build Coastguard Workerimport calendar 33*8975f5c5SAndroid Build Coastguard Workerimport datetime 34*8975f5c5SAndroid Build Coastguard Workerimport doctest 35*8975f5c5SAndroid Build Coastguard Workerimport os 36*8975f5c5SAndroid Build Coastguard Workerimport sys 37*8975f5c5SAndroid Build Coastguard Worker 38*8975f5c5SAndroid Build Coastguard Worker 39*8975f5c5SAndroid Build Coastguard WorkerTHIS_DIR = os.path.abspath(os.path.dirname(__file__)) 40*8975f5c5SAndroid Build Coastguard Worker 41*8975f5c5SAndroid Build Coastguard Worker 42*8975f5c5SAndroid Build Coastguard Workerdef GetFirstSundayOfMonth(year, month): 43*8975f5c5SAndroid Build Coastguard Worker """Returns the first sunday of the given month of the given year. 44*8975f5c5SAndroid Build Coastguard Worker 45*8975f5c5SAndroid Build Coastguard Worker >>> GetFirstSundayOfMonth(2016, 2) 46*8975f5c5SAndroid Build Coastguard Worker 7 47*8975f5c5SAndroid Build Coastguard Worker >>> GetFirstSundayOfMonth(2016, 3) 48*8975f5c5SAndroid Build Coastguard Worker 6 49*8975f5c5SAndroid Build Coastguard Worker >>> GetFirstSundayOfMonth(2000, 1) 50*8975f5c5SAndroid Build Coastguard Worker 2 51*8975f5c5SAndroid Build Coastguard Worker """ 52*8975f5c5SAndroid Build Coastguard Worker weeks = calendar.Calendar().monthdays2calendar(year, month) 53*8975f5c5SAndroid Build Coastguard Worker # Return the first day in the first week that is a Sunday. 54*8975f5c5SAndroid Build Coastguard Worker return [date_day[0] for date_day in weeks[0] if date_day[1] == 6][0] 55*8975f5c5SAndroid Build Coastguard Worker 56*8975f5c5SAndroid Build Coastguard Worker 57*8975f5c5SAndroid Build Coastguard Workerdef GetUnofficialBuildDate(build_date): 58*8975f5c5SAndroid Build Coastguard Worker """Gets the approximate build date given the specific build type. 59*8975f5c5SAndroid Build Coastguard Worker 60*8975f5c5SAndroid Build Coastguard Worker >>> GetUnofficialBuildDate(datetime.datetime(2016, 2, 6, 1, 2, 3)) 61*8975f5c5SAndroid Build Coastguard Worker datetime.datetime(2016, 1, 3, 5, 0) 62*8975f5c5SAndroid Build Coastguard Worker >>> GetUnofficialBuildDate(datetime.datetime(2016, 2, 7, 5)) 63*8975f5c5SAndroid Build Coastguard Worker datetime.datetime(2016, 2, 7, 5, 0) 64*8975f5c5SAndroid Build Coastguard Worker >>> GetUnofficialBuildDate(datetime.datetime(2016, 2, 8, 5)) 65*8975f5c5SAndroid Build Coastguard Worker datetime.datetime(2016, 2, 7, 5, 0) 66*8975f5c5SAndroid Build Coastguard Worker """ 67*8975f5c5SAndroid Build Coastguard Worker 68*8975f5c5SAndroid Build Coastguard Worker if build_date.hour < 5: 69*8975f5c5SAndroid Build Coastguard Worker # The time is locked at 5:00 am in UTC to cause the build cache 70*8975f5c5SAndroid Build Coastguard Worker # invalidation to not happen exactly at midnight. Use the same calculation 71*8975f5c5SAndroid Build Coastguard Worker # as the day before. 72*8975f5c5SAndroid Build Coastguard Worker # See //base/build_time.cc. 73*8975f5c5SAndroid Build Coastguard Worker build_date = build_date - datetime.timedelta(days=1) 74*8975f5c5SAndroid Build Coastguard Worker build_date = datetime.datetime(build_date.year, build_date.month, 75*8975f5c5SAndroid Build Coastguard Worker build_date.day, 5, 0, 0) 76*8975f5c5SAndroid Build Coastguard Worker 77*8975f5c5SAndroid Build Coastguard Worker day = build_date.day 78*8975f5c5SAndroid Build Coastguard Worker month = build_date.month 79*8975f5c5SAndroid Build Coastguard Worker year = build_date.year 80*8975f5c5SAndroid Build Coastguard Worker first_sunday = GetFirstSundayOfMonth(year, month) 81*8975f5c5SAndroid Build Coastguard Worker # If our build is after the first Sunday, we've already refreshed our build 82*8975f5c5SAndroid Build Coastguard Worker # cache on a quiet day, so just use that day. 83*8975f5c5SAndroid Build Coastguard Worker # Otherwise, take the first Sunday of the previous month. 84*8975f5c5SAndroid Build Coastguard Worker if day >= first_sunday: 85*8975f5c5SAndroid Build Coastguard Worker day = first_sunday 86*8975f5c5SAndroid Build Coastguard Worker else: 87*8975f5c5SAndroid Build Coastguard Worker month -= 1 88*8975f5c5SAndroid Build Coastguard Worker if month == 0: 89*8975f5c5SAndroid Build Coastguard Worker month = 12 90*8975f5c5SAndroid Build Coastguard Worker year -= 1 91*8975f5c5SAndroid Build Coastguard Worker day = GetFirstSundayOfMonth(year, month) 92*8975f5c5SAndroid Build Coastguard Worker return datetime.datetime( 93*8975f5c5SAndroid Build Coastguard Worker year, month, day, build_date.hour, build_date.minute, build_date.second) 94*8975f5c5SAndroid Build Coastguard Worker 95*8975f5c5SAndroid Build Coastguard Worker 96*8975f5c5SAndroid Build Coastguard Workerdef main(): 97*8975f5c5SAndroid Build Coastguard Worker if doctest.testmod()[0]: 98*8975f5c5SAndroid Build Coastguard Worker return 1 99*8975f5c5SAndroid Build Coastguard Worker argument_parser = argparse.ArgumentParser() 100*8975f5c5SAndroid Build Coastguard Worker argument_parser.add_argument( 101*8975f5c5SAndroid Build Coastguard Worker 'build_type', help='The type of build', choices=('official', 'default')) 102*8975f5c5SAndroid Build Coastguard Worker args = argument_parser.parse_args() 103*8975f5c5SAndroid Build Coastguard Worker 104*8975f5c5SAndroid Build Coastguard Worker # The mtime of the revision in build/util/LASTCHANGE is stored in a file 105*8975f5c5SAndroid Build Coastguard Worker # next to it. Read it, to get a deterministic time close to "now". 106*8975f5c5SAndroid Build Coastguard Worker # That date is then modified as described at the top of the file so that 107*8975f5c5SAndroid Build Coastguard Worker # it changes less frequently than with every commit. 108*8975f5c5SAndroid Build Coastguard Worker # This intentionally always uses build/util/LASTCHANGE's commit time even if 109*8975f5c5SAndroid Build Coastguard Worker # use_dummy_lastchange is set. 110*8975f5c5SAndroid Build Coastguard Worker lastchange_file = os.path.join(THIS_DIR, 'util', 'LASTCHANGE.committime') 111*8975f5c5SAndroid Build Coastguard Worker last_commit_timestamp = int(open(lastchange_file).read()) 112*8975f5c5SAndroid Build Coastguard Worker build_date = datetime.datetime.fromtimestamp(last_commit_timestamp, 113*8975f5c5SAndroid Build Coastguard Worker datetime.timezone.utc) 114*8975f5c5SAndroid Build Coastguard Worker 115*8975f5c5SAndroid Build Coastguard Worker # For official builds we want full fidelity time stamps because official 116*8975f5c5SAndroid Build Coastguard Worker # builds are typically added to symbol servers and Windows symbol servers 117*8975f5c5SAndroid Build Coastguard Worker # use the link timestamp as the prime differentiator, but for unofficial 118*8975f5c5SAndroid Build Coastguard Worker # builds we do lots of quantization to avoid churn. 119*8975f5c5SAndroid Build Coastguard Worker offset = 0 120*8975f5c5SAndroid Build Coastguard Worker if args.build_type == 'official': 121*8975f5c5SAndroid Build Coastguard Worker if os.name == 'nt': 122*8975f5c5SAndroid Build Coastguard Worker version_path = os.path.join(THIS_DIR, os.pardir, 'chrome', 'VERSION') 123*8975f5c5SAndroid Build Coastguard Worker with open(version_path) as f: 124*8975f5c5SAndroid Build Coastguard Worker patch_line = f.readlines()[3].strip() 125*8975f5c5SAndroid Build Coastguard Worker # Use the patch number as an offset to the build date so that multiple 126*8975f5c5SAndroid Build Coastguard Worker # versions with different patch numbers built from the same source code 127*8975f5c5SAndroid Build Coastguard Worker # will get different build_date values. This is critical for Windows 128*8975f5c5SAndroid Build Coastguard Worker # symbol servers, to avoid collisions. 129*8975f5c5SAndroid Build Coastguard Worker assert patch_line.startswith('PATCH=') 130*8975f5c5SAndroid Build Coastguard Worker offset = int(patch_line[6:]) 131*8975f5c5SAndroid Build Coastguard Worker else: 132*8975f5c5SAndroid Build Coastguard Worker build_date = GetUnofficialBuildDate(build_date) 133*8975f5c5SAndroid Build Coastguard Worker print(offset + int(calendar.timegm(build_date.utctimetuple()))) 134*8975f5c5SAndroid Build Coastguard Worker return 0 135*8975f5c5SAndroid Build Coastguard Worker 136*8975f5c5SAndroid Build Coastguard Worker 137*8975f5c5SAndroid Build Coastguard Workerif __name__ == '__main__': 138*8975f5c5SAndroid Build Coastguard Worker sys.exit(main()) 139