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