1*635a8641SAndroid Build Coastguard Worker#!/usr/bin/env python 2*635a8641SAndroid Build Coastguard Worker# Copyright (c) 2016 The Chromium Authors. All rights reserved. 3*635a8641SAndroid Build Coastguard Worker# Use of this source code is governed by a BSD-style license that can be 4*635a8641SAndroid Build Coastguard Worker# found in the LICENSE file. 5*635a8641SAndroid Build Coastguard Worker"""Writes a file that contains a define that approximates the build date. 6*635a8641SAndroid Build Coastguard Worker 7*635a8641SAndroid Build Coastguard Workerbuild_type impacts the timestamp generated: 8*635a8641SAndroid Build Coastguard Worker- default: the build date is set to the most recent first Sunday of a month at 9*635a8641SAndroid Build Coastguard Worker 5:00am. The reason is that it is a time where invalidating the build cache 10*635a8641SAndroid Build Coastguard Worker shouldn't have major reprecussions (due to lower load). 11*635a8641SAndroid Build Coastguard Worker- official: the build date is set to the current date at 5:00am, or the day 12*635a8641SAndroid Build Coastguard Worker before if the current time is before 5:00am. 13*635a8641SAndroid Build Coastguard WorkerEither way, it is guaranteed to be in the past and always in UTC. 14*635a8641SAndroid Build Coastguard Worker 15*635a8641SAndroid Build Coastguard WorkerIt is also possible to explicitly set a build date to be used. 16*635a8641SAndroid Build Coastguard Worker""" 17*635a8641SAndroid Build Coastguard Worker 18*635a8641SAndroid Build Coastguard Workerimport argparse 19*635a8641SAndroid Build Coastguard Workerimport calendar 20*635a8641SAndroid Build Coastguard Workerimport datetime 21*635a8641SAndroid Build Coastguard Workerimport doctest 22*635a8641SAndroid Build Coastguard Workerimport os 23*635a8641SAndroid Build Coastguard Workerimport sys 24*635a8641SAndroid Build Coastguard Worker 25*635a8641SAndroid Build Coastguard Worker 26*635a8641SAndroid Build Coastguard Workerdef GetFirstSundayOfMonth(year, month): 27*635a8641SAndroid Build Coastguard Worker """Returns the first sunday of the given month of the given year. 28*635a8641SAndroid Build Coastguard Worker 29*635a8641SAndroid Build Coastguard Worker >>> GetFirstSundayOfMonth(2016, 2) 30*635a8641SAndroid Build Coastguard Worker 7 31*635a8641SAndroid Build Coastguard Worker >>> GetFirstSundayOfMonth(2016, 3) 32*635a8641SAndroid Build Coastguard Worker 6 33*635a8641SAndroid Build Coastguard Worker >>> GetFirstSundayOfMonth(2000, 1) 34*635a8641SAndroid Build Coastguard Worker 2 35*635a8641SAndroid Build Coastguard Worker """ 36*635a8641SAndroid Build Coastguard Worker weeks = calendar.Calendar().monthdays2calendar(year, month) 37*635a8641SAndroid Build Coastguard Worker # Return the first day in the first week that is a Sunday. 38*635a8641SAndroid Build Coastguard Worker return [date_day[0] for date_day in weeks[0] if date_day[1] == 6][0] 39*635a8641SAndroid Build Coastguard Worker 40*635a8641SAndroid Build Coastguard Worker 41*635a8641SAndroid Build Coastguard Workerdef GetBuildDate(build_type, utc_now): 42*635a8641SAndroid Build Coastguard Worker """Gets the approximate build date given the specific build type. 43*635a8641SAndroid Build Coastguard Worker 44*635a8641SAndroid Build Coastguard Worker >>> GetBuildDate('default', datetime.datetime(2016, 2, 6, 1, 2, 3)) 45*635a8641SAndroid Build Coastguard Worker 'Jan 03 2016 01:02:03' 46*635a8641SAndroid Build Coastguard Worker >>> GetBuildDate('default', datetime.datetime(2016, 2, 7, 5)) 47*635a8641SAndroid Build Coastguard Worker 'Feb 07 2016 05:00:00' 48*635a8641SAndroid Build Coastguard Worker >>> GetBuildDate('default', datetime.datetime(2016, 2, 8, 5)) 49*635a8641SAndroid Build Coastguard Worker 'Feb 07 2016 05:00:00' 50*635a8641SAndroid Build Coastguard Worker """ 51*635a8641SAndroid Build Coastguard Worker day = utc_now.day 52*635a8641SAndroid Build Coastguard Worker month = utc_now.month 53*635a8641SAndroid Build Coastguard Worker year = utc_now.year 54*635a8641SAndroid Build Coastguard Worker if build_type != 'official': 55*635a8641SAndroid Build Coastguard Worker first_sunday = GetFirstSundayOfMonth(year, month) 56*635a8641SAndroid Build Coastguard Worker # If our build is after the first Sunday, we've already refreshed our build 57*635a8641SAndroid Build Coastguard Worker # cache on a quiet day, so just use that day. 58*635a8641SAndroid Build Coastguard Worker # Otherwise, take the first Sunday of the previous month. 59*635a8641SAndroid Build Coastguard Worker if day >= first_sunday: 60*635a8641SAndroid Build Coastguard Worker day = first_sunday 61*635a8641SAndroid Build Coastguard Worker else: 62*635a8641SAndroid Build Coastguard Worker month -= 1 63*635a8641SAndroid Build Coastguard Worker if month == 0: 64*635a8641SAndroid Build Coastguard Worker month = 12 65*635a8641SAndroid Build Coastguard Worker year -= 1 66*635a8641SAndroid Build Coastguard Worker day = GetFirstSundayOfMonth(year, month) 67*635a8641SAndroid Build Coastguard Worker now = datetime.datetime( 68*635a8641SAndroid Build Coastguard Worker year, month, day, utc_now.hour, utc_now.minute, utc_now.second) 69*635a8641SAndroid Build Coastguard Worker return '{:%b %d %Y %H:%M:%S}'.format(now) 70*635a8641SAndroid Build Coastguard Worker 71*635a8641SAndroid Build Coastguard Worker 72*635a8641SAndroid Build Coastguard Workerdef main(): 73*635a8641SAndroid Build Coastguard Worker if doctest.testmod()[0]: 74*635a8641SAndroid Build Coastguard Worker return 1 75*635a8641SAndroid Build Coastguard Worker argument_parser = argparse.ArgumentParser( 76*635a8641SAndroid Build Coastguard Worker description=sys.modules[__name__].__doc__, 77*635a8641SAndroid Build Coastguard Worker formatter_class=argparse.RawDescriptionHelpFormatter) 78*635a8641SAndroid Build Coastguard Worker argument_parser.add_argument('output_file', help='The file to write to') 79*635a8641SAndroid Build Coastguard Worker argument_parser.add_argument( 80*635a8641SAndroid Build Coastguard Worker 'build_type', help='The type of build', choices=('official', 'default')) 81*635a8641SAndroid Build Coastguard Worker argument_parser.add_argument( 82*635a8641SAndroid Build Coastguard Worker 'build_date_override', nargs='?', 83*635a8641SAndroid Build Coastguard Worker help='Optional override for the build date. Format must be ' 84*635a8641SAndroid Build Coastguard Worker '\'Mmm DD YYYY HH:MM:SS\'') 85*635a8641SAndroid Build Coastguard Worker args = argument_parser.parse_args() 86*635a8641SAndroid Build Coastguard Worker 87*635a8641SAndroid Build Coastguard Worker if args.build_date_override: 88*635a8641SAndroid Build Coastguard Worker # Format is expected to be "Mmm DD YYYY HH:MM:SS". 89*635a8641SAndroid Build Coastguard Worker build_date = args.build_date_override 90*635a8641SAndroid Build Coastguard Worker else: 91*635a8641SAndroid Build Coastguard Worker now = datetime.datetime.utcnow() 92*635a8641SAndroid Build Coastguard Worker if now.hour < 5: 93*635a8641SAndroid Build Coastguard Worker # The time is locked at 5:00 am in UTC to cause the build cache 94*635a8641SAndroid Build Coastguard Worker # invalidation to not happen exactly at midnight. Use the same calculation 95*635a8641SAndroid Build Coastguard Worker # as the day before. 96*635a8641SAndroid Build Coastguard Worker # See //base/build_time.cc. 97*635a8641SAndroid Build Coastguard Worker now = now - datetime.timedelta(days=1) 98*635a8641SAndroid Build Coastguard Worker now = datetime.datetime(now.year, now.month, now.day, 5, 0, 0) 99*635a8641SAndroid Build Coastguard Worker build_date = GetBuildDate(args.build_type, now) 100*635a8641SAndroid Build Coastguard Worker 101*635a8641SAndroid Build Coastguard Worker output = ('// Generated by //build/write_build_date_header.py\n' 102*635a8641SAndroid Build Coastguard Worker '#ifndef BUILD_DATE\n' 103*635a8641SAndroid Build Coastguard Worker '#define BUILD_DATE "{}"\n' 104*635a8641SAndroid Build Coastguard Worker '#endif // BUILD_DATE\n'.format(build_date)) 105*635a8641SAndroid Build Coastguard Worker 106*635a8641SAndroid Build Coastguard Worker current_contents = '' 107*635a8641SAndroid Build Coastguard Worker if os.path.isfile(args.output_file): 108*635a8641SAndroid Build Coastguard Worker with open(args.output_file, 'r') as current_file: 109*635a8641SAndroid Build Coastguard Worker current_contents = current_file.read() 110*635a8641SAndroid Build Coastguard Worker 111*635a8641SAndroid Build Coastguard Worker if current_contents != output: 112*635a8641SAndroid Build Coastguard Worker with open(args.output_file, 'w') as output_file: 113*635a8641SAndroid Build Coastguard Worker output_file.write(output) 114*635a8641SAndroid Build Coastguard Worker return 0 115*635a8641SAndroid Build Coastguard Worker 116*635a8641SAndroid Build Coastguard Worker 117*635a8641SAndroid Build Coastguard Workerif __name__ == '__main__': 118*635a8641SAndroid Build Coastguard Worker sys.exit(main()) 119