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