Make fetch compatible with Python 3

The scripts still work with Python 2.
There are no intended behaviour changes.

Bug: 939847
Change-Id: Icada60c5b2cf351d62aead26b7364fcef2c2a3e5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/tools/depot_tools/+/1524486
Reviewed-by: Dirk Pranke <dpranke@chromium.org>
Commit-Queue: Raul Tambre <raul@tambre.ee>
diff --git a/fetch.py b/fetch.py
index d911c06..da4741d 100755
--- a/fetch.py
+++ b/fetch.py
@@ -18,6 +18,8 @@
 These parameters will be passed through to the config's main method.
 """
 
+from __future__ import print_function
+
 import json
 import optparse
 import os
@@ -62,7 +64,7 @@
     pass
 
   def run(self, cmd, return_stdout=False, **kwargs):
-    print 'Running: %s' % (' '.join(pipes.quote(x) for x in cmd))
+    print('Running: %s' % (' '.join(pipes.quote(x) for x in cmd)))
     if self.options.dry_run:
       return ''
     if return_stdout:
@@ -94,7 +96,7 @@
 class GitCheckout(Checkout):
 
   def run_git(self, *cmd, **kwargs):
-    print 'Running: git %s' % (' '.join(pipes.quote(x) for x in cmd))
+    print('Running: git %s' % (' '.join(pipes.quote(x) for x in cmd)))
     if self.options.dry_run:
       return ''
     return git_common.run(*cmd, **kwargs)
@@ -108,15 +110,16 @@
 
   def _format_spec(self):
     def _format_literal(lit):
-      if isinstance(lit, basestring):
+      if isinstance(lit, str) or (sys.version_info.major == 2 and
+                                  isinstance(lit, unicode)):
         return '"%s"' % lit
       if isinstance(lit, list):
         return '[%s]' % ', '.join(_format_literal(i) for i in lit)
       return '%r' % lit
     soln_strings = []
     for soln in self.spec['solutions']:
-      soln_string= '\n'.join('    "%s": %s,' % (key, _format_literal(value))
-                             for key, value in soln.iteritems())
+      soln_string = '\n'.join('    "%s": %s,' % (key, _format_literal(value))
+                              for key, value in soln.items())
       soln_strings.append('  {\n%s\n  },' % soln_string)
     gclient_spec = 'solutions = [\n%s\n]\n' % '\n'.join(soln_strings)
     extra_keys = ['target_os', 'target_os_only', 'cache_dir']
@@ -139,7 +142,7 @@
     # Configure git.
     wd = os.path.join(self.base, self.root)
     if self.options.dry_run:
-      print 'cd %s' % wd
+      print('cd %s' % wd)
     self.run_git(
         'submodule', 'foreach',
         'git config -f $toplevel/.git/config submodule.$name.ignore all',
@@ -172,9 +175,9 @@
 def usage(msg=None):
   """Print help and exit."""
   if msg:
-    print 'Error:', msg
+    print('Error:', msg)
 
-  print textwrap.dedent("""\
+  print(textwrap.dedent("""\
     usage: %s [options] <config> [--property=value [--property2=value2 ...]]
 
     This script can be used to download the Chromium sources. See
@@ -188,13 +191,13 @@
        -n, --dry-run      Don't run commands, only print them.
        --no-history       Perform shallow clones, don't fetch the full git history.
 
-    Valid fetch configs:""") % os.path.basename(sys.argv[0])
+    Valid fetch configs:""") % os.path.basename(sys.argv[0]))
 
   configs_dir = os.path.join(SCRIPT_PATH, 'fetch_configs')
   configs = [f[:-3] for f in os.listdir(configs_dir) if f.endswith('.py')]
   configs.sort()
   for fname in configs:
-    print '  ' + fname
+    print('  ' + fname)
 
   sys.exit(bool(msg))
 
@@ -251,7 +254,7 @@
   config_path = os.path.abspath(
       os.path.join(SCRIPT_PATH, 'fetch_configs', config))
   if not os.path.exists(config_path + '.py'):
-    print "Could not find a config for %s" % config
+    print("Could not find a config for %s" % config)
     sys.exit(1)
 
   cmd = [sys.executable, config_path + '.py', 'fetch'] + props
@@ -285,12 +288,12 @@
   except KeyError:
     return 1
   if not options.force and checkout.exists():
-    print 'Your current directory appears to already contain, or be part of, '
-    print 'a checkout. "fetch" is used only to get new checkouts. Use '
-    print '"gclient sync" to update existing checkouts.'
-    print
-    print 'Fetch also does not yet deal with partial checkouts, so if fetch'
-    print 'failed, delete the checkout and start over (crbug.com/230691).'
+    print('Your current directory appears to already contain, or be part of, ')
+    print('a checkout. "fetch" is used only to get new checkouts. Use ')
+    print('"gclient sync" to update existing checkouts.')
+    print()
+    print('Fetch also does not yet deal with partial checkouts, so if fetch')
+    print('failed, delete the checkout and start over (crbug.com/230691).')
     return 1
   return checkout.init()