#!/usr/bin/env python
# Copyright (c) 2012 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.


""" Apply a diff to patch a Skia checkout. """


from ast import literal_eval
from build_step import BuildStep, BuildStepFailure
from utils import shell_utils
import os
import sys
import tempfile


class ApplyPatch(BuildStep):
  def _Run(self):
    if self._args['patch'] == 'None':
      raise BuildStepFailure('No patch given!')
    if self._args['patch_root'] == 'None':
      raise BuildStepFailure('Problem with patch: no root specified!')

    # patch is a tuple of the form (int, str), where patch[0] is the "level" of
    # the patch and patch[1] is the diff.
    patch = literal_eval(self._args['patch'].decode())
    print 'Patch level: %d' % patch[0]
    print 'Diff:'
    print patch[1]

    patch_file = tempfile.NamedTemporaryFile()
    patch_file.write(patch[1])
    patch_file.flush()
    print 'Saved patch to %s' % patch_file.name

    # Make sure we're always in the right place to apply the patch.
    patch_root = self._args['patch_root'].replace('/', os.path.sep)
    os.chdir(os.pardir)
    if patch_root != 'svn':
      os.chdir(patch_root)
    try:
      shell_utils.Bash(['patch', '-p%d' % patch[0], '-i', patch_file.name])
    finally:
      # Closing a NamedTemporaryFile also deletes it.
      patch_file.close()


if '__main__' == __name__:
  sys.exit(BuildStep.RunBuildStep(ApplyPatch))
@@ -352,16 +352,30 @@
 port os%0A
+import shutil%0A
 import s
@@ -395,16 +395,222 @@
 pfile%0A%0A%0A
+WIN_PATCH = os.path.abspath(os.path.join(os.pardir, os.pardir, os.pardir,%0A                                         os.pardir, os.pardir, 'GnuWin32',%0A                                         'patch.exe'))%0A%0A%0A
 class Ap
@@ -1111,51 +1111,400 @@
     
+# Write the 
 patch
-_
+ 
 file 
-= tempfile.NamedTemporaryFile()%0A
+into a temporary directory. Unfortunately, temporary%0A    # files created by the tempfile module don't behave properly on Windows, so%0A    # we create a temporary directory and write the file inside it.%0A    temp_dir = tempfile.mkdtemp()%0A    try:%0A      patch_file_name = os.path.join(temp_dir, 'skiabot_patch')%0A      patch_file = open(patch_file_name, 'w')%0A      try:%0A    
     
@@ -1530,16 +1530,35 @@
 tch%5B1%5D)%0A
+      finally:%0A    
     patc
@@ -1568,16 +1568,18 @@
 ile.
-flush
+close
 ()%0A
+  
     
@@ -1622,17 +1622,179 @@
 le.name%0A
-%0A
+  %0A      # On Windows, use the patch.exe included in the checkout%0A      if os.name == 'nt':%0A        patcher = WIN_PATCH%0A      else:%0A        patcher = 'patch'%0A  %0A  
     # Ma
@@ -1853,24 +1853,26 @@
  patch.%0A    
+  
 patch_root =
@@ -1923,24 +1923,26 @@
 th.sep)%0A    
+  
 os.chdir(os.
@@ -1953,16 +1953,18 @@
 ir)%0A    
+ 
+ 
 if patch
@@ -1981,24 +1981,26 @@
 svn':%0A      
+  
 os.chdir(pat
@@ -2006,30 +2006,24 @@
 tch_root)%0A  
-  try:
 %0A      shell
@@ -2035,23 +2035,23 @@
 s.Bash(%5B
-'
 patch
-'
+er
 , '-p%25d'
@@ -2110,79 +2110,30 @@
     
-# Closing a NamedTemporaryFile also deletes it.%0A      patch_file.close(
+shutil.rmtree(temp_dir
 )%0A%0A%0A

Fix apply_patch for Windows Review URL: https://codereview.appspot.com/6965055