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