diff options
| author | Bennett Goble <signal@lindenlab.com> | 2021-06-05 22:02:54 -0700 | 
|---|---|---|
| committer | Signal Linden <signal@lindenlab.com> | 2021-12-10 14:42:49 -0800 | 
| commit | f729cfc33f258781c5fd85a3d8773bf6149d12db (patch) | |
| tree | b4d9e9657f64b1ba46d8522f5c2196acefa3ae77 /indra/newview | |
| parent | cbaba2df56c66926e051d50b6cb02955c81c2a6c (diff) | |
SL-15742: Convert build scripts to Python 3
This changeset makes it possible to build the Second Life viewer using
Python 3. It is designed to be used with an equivalent Autobuild branch
so that a developer can compile without needing Python 2 on their
machine.
Breaking change: Python 2 support ending
Rather than supporting two versions of Python, including one that was
discontinued at the beginning of the year, this branch focuses on
pouring future effort into Python 3 only. As a result, scripts do not
need to be backwards compatible. This means that build environments,
be they on personal computers and on build agents, need to have a
compatible interpreter.
Notes
- SLVersionChecker will still use Python 2 on macOS
- Fixed the message template url used by template_verifier.py
Diffstat (limited to 'indra/newview')
| -rwxr-xr-x | indra/newview/build_win32_appConfig.py | 2 | ||||
| -rw-r--r-- | indra/newview/llappviewer.cpp | 1 | ||||
| -rwxr-xr-x | indra/newview/tests/test_llxmlrpc_peer.py | 6 | ||||
| -rwxr-xr-x | indra/newview/viewer_manifest.py | 109 | 
4 files changed, 59 insertions, 59 deletions
| diff --git a/indra/newview/build_win32_appConfig.py b/indra/newview/build_win32_appConfig.py index 9fdceee1be..d18d7b88cb 100755 --- a/indra/newview/build_win32_appConfig.py +++ b/indra/newview/build_win32_appConfig.py @@ -38,7 +38,7 @@ def munge_binding_redirect_version(src_manifest_name, src_config_name, dst_confi      comment = config_dom.createComment("This file is automatically generated by the build. see indra/newview/build_win32_appConfig.py")      config_dom.insertBefore(comment, config_dom.childNodes[0]) -    print "Writing: " + dst_config_name +    print("Writing: " + dst_config_name)      f = open(dst_config_name, 'w')      config_dom.writexml(f)      f.close() diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 69606793db..d65cbbe3a5 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -1194,6 +1194,7 @@ bool LLAppViewer::init()  	updater.executable = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, updater_file);  #elif LL_DARWIN  	// explicitly run the system Python interpreter on SLVersionChecker.py +	// Keep using python2 until SLVersionChecker is converted to python3.  	updater.executable = "python";  	updater_file = "SLVersionChecker.py";  	updater.args.add(gDirUtilp->add(gDirUtilp->getAppRODataDir(), "updater", updater_file)); diff --git a/indra/newview/tests/test_llxmlrpc_peer.py b/indra/newview/tests/test_llxmlrpc_peer.py index cff40aa4c2..365848b819 100755 --- a/indra/newview/tests/test_llxmlrpc_peer.py +++ b/indra/newview/tests/test_llxmlrpc_peer.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  """\  @file   test_llxmlrpc_peer.py  @author Nat Goodspeed @@ -31,7 +31,7 @@ $/LicenseInfo$  import os  import sys -from SimpleXMLRPCServer import SimpleXMLRPCServer +from xmlrpc.server import SimpleXMLRPCServer  mydir = os.path.dirname(__file__)       # expected to be .../indra/newview/tests/  sys.path.insert(0, os.path.join(mydir, os.pardir, os.pardir, "llmessage", "tests")) @@ -85,7 +85,7 @@ if __name__ == "__main__":          # "Then there's Windows"          # Instantiate a TestServer on the first free port in the specified          # port range. -        xmlrpcd, port = freeport(xrange(8000, 8020), make_server) +        xmlrpcd, port = freeport(range(8000, 8020), make_server)      # Pass the selected port number to the subject test program via the      # environment. We don't want to impose requirements on the test program's diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py index b932f43141..d6f5e4985b 100755 --- a/indra/newview/viewer_manifest.py +++ b/indra/newview/viewer_manifest.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3  """\  @file viewer_manifest.py  @author Ryan Williams @@ -76,7 +76,7 @@ class ViewerManifest(LLManifest):                  # include the extracted list of contributors                  contributions_path = "../../doc/contributions.txt"                  contributor_names = self.extract_names(contributions_path) -                self.put_in_file(contributor_names, "contributors.txt", src=contributions_path) +                self.put_in_file(contributor_names.encode(), "contributors.txt", src=contributions_path)                  # ... and the default camera position settings                  self.path("camera") @@ -115,17 +115,17 @@ class ViewerManifest(LLManifest):                  if sourceid:                      settings_install['sourceid'] = settings_template['sourceid'].copy()                      settings_install['sourceid']['Value'] = sourceid -                    print "Set sourceid in settings_install.xml to '%s'" % sourceid +                    print("Set sourceid in settings_install.xml to '%s'" % sourceid)                  if self.args.get('channel_suffix'):                      settings_install['CmdLineChannel'] = settings_template['CmdLineChannel'].copy()                      settings_install['CmdLineChannel']['Value'] = self.channel_with_pkg_suffix() -                    print "Set CmdLineChannel in settings_install.xml to '%s'" % self.channel_with_pkg_suffix() +                    print("Set CmdLineChannel in settings_install.xml to '%s'" % self.channel_with_pkg_suffix())                  if self.args.get('grid'):                      settings_install['CmdLineGridChoice'] = settings_template['CmdLineGridChoice'].copy()                      settings_install['CmdLineGridChoice']['Value'] = self.grid() -                    print "Set CmdLineGridChoice in settings_install.xml to '%s'" % self.grid() +                    print("Set CmdLineGridChoice in settings_install.xml to '%s'" % self.grid())                  # put_in_file(src=) need not be an actual pathname; it                  # only needs to be non-empty @@ -191,7 +191,7 @@ class ViewerManifest(LLManifest):              #we likely no longer need the test, since we will throw an exception above, but belt and suspenders and we get the              #return code for free.              if not self.path2basename(os.pardir, "build_data.json"): -                print "No build_data.json file" +                print("No build_data.json file")      def finish_build_data_dict(self, build_data_dict):          return build_data_dict @@ -270,13 +270,13 @@ class ViewerManifest(LLManifest):          return "icons/" + self.channel_type()      def extract_names(self,src): +        """Extract contributor names from source file, returns string"""          try: -            contrib_file = open(src,'r') +            with open(src, 'r') as contrib_file:  +                lines = contrib_file.readlines()          except IOError: -            print "Failed to open '%s'" % src +            print("Failed to open '%s'" % src)              raise -        lines = contrib_file.readlines() -        contrib_file.close()          # All lines up to and including the first blank line are the file header; skip them          lines.reverse() # so that pop will pull from first to last line @@ -312,7 +312,7 @@ class ViewerManifest(LLManifest):          """          Like ln -sf, but uses os.symlink() instead of running ln. This creates          a symlink at 'dst' that points to 'src' -- see: -        https://docs.python.org/2/library/os.html#os.symlink +        https://docs.python.org/3/library/os.html#os.symlink          If you omit 'dst', this creates a symlink with basename(src) at          get_dst_prefix() -- in other words: put a symlink to this pathname @@ -374,11 +374,11 @@ class ViewerManifest(LLManifest):                          os.remove(dst)                          os.symlink(src, dst)                  elif os.path.isdir(dst): -                    print "Requested symlink (%s) exists but is a directory; replacing" % dst +                    print("Requested symlink (%s) exists but is a directory; replacing" % dst)                      shutil.rmtree(dst)                      os.symlink(src, dst)                  elif os.path.exists(dst): -                    print "Requested symlink (%s) exists but is a file; replacing" % dst +                    print("Requested symlink (%s) exists but is a file; replacing" % dst)                      os.remove(dst)                      os.symlink(src, dst)                  else: @@ -386,8 +386,8 @@ class ViewerManifest(LLManifest):                      raise          except Exception as err:              # report -            print "Can't symlink %r -> %r: %s: %s" % \ -                  (dst, src, err.__class__.__name__, err) +            print("Can't symlink %r -> %r: %s: %s" % \ +                  (dst, src, err.__class__.__name__, err))              # if caller asked us not to catch, re-raise this exception              if not catch:                  raise @@ -448,7 +448,7 @@ class WindowsManifest(ViewerManifest):              else:                  raise Exception("Directories are not supported by test_CRT_and_copy_action()")          else: -            print "Doesn't exist:", src +            print("Doesn't exist:", src)      def test_for_no_msvcrt_manifest_and_copy_action(self, src, dst):          # This is used to test that no manifest for the msvcrt exists. @@ -477,7 +477,7 @@ class WindowsManifest(ViewerManifest):              else:                  raise Exception("Directories are not supported by test_CRT_and_copy_action()")          else: -            print "Doesn't exist:", src +            print("Doesn't exist:", src)      def construct(self):          super(WindowsManifest, self).construct() @@ -515,8 +515,8 @@ class WindowsManifest(ViewerManifest):              try:                  self.path("glod.dll")              except RuntimeError as err: -                print err.message -                print "Skipping GLOD library (assumming linked statically)" +                print(err.message) +                print("Skipping GLOD library (assumming linked statically)")              # Get fmodstudio dll if needed              if self.args['fmodstudio'] == 'ON': @@ -698,8 +698,7 @@ class WindowsManifest(ViewerManifest):          result = ""          dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]          # sort deepest hierarchy first -        dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b)) -        dest_files.reverse() +        dest_files.sort(key=lambda f: (f.count(os.path.sep), f), reverse=True)          out_path = None          for pkg_file in dest_files:              rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,'')) @@ -722,8 +721,7 @@ class WindowsManifest(ViewerManifest):              for d in deleted_file_dirs:                  deleted_dirs.extend(path_ancestors(d))              # sort deepest hierarchy first -            deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b)) -            deleted_dirs.reverse() +            deleted_dirs.sort(key=lambda f: (f.count(os.path.sep), f), reverse=True)              prev = None              for d in deleted_dirs:                  if d != prev:   # skip duplicates @@ -809,19 +807,19 @@ class WindowsManifest(ViewerManifest):          installer_created=False          nsis_attempts=3          nsis_retry_wait=15 -        for attempt in xrange(nsis_attempts): +        for attempt in range(nsis_attempts):              try:                  self.run_command([NSIS_path, '/V2', self.dst_path_of(tempfile)])              except ManifestError as err:                  if attempt+1 < nsis_attempts: -                    print >> sys.stderr, "nsis failed, waiting %d seconds before retrying" % nsis_retry_wait +                    print("nsis failed, waiting %d seconds before retrying" % nsis_retry_wait, file=sys.stderr)                      time.sleep(nsis_retry_wait)                      nsis_retry_wait*=2              else:                  # NSIS worked! Done!                  break          else: -            print >> sys.stderr, "Maximum nsis attempts exceeded; giving up" +            print("Maximum nsis attempts exceeded; giving up", file=sys.stderr)              raise          self.sign(installer_file) @@ -833,10 +831,10 @@ class WindowsManifest(ViewerManifest):          python  = os.environ.get('PYTHON', sys.executable)          if os.path.exists(sign_py):              dst_path = self.dst_path_of(exe) -            print "about to run signing of: ", dst_path +            print("about to run signing of: ", dst_path)              self.run_command([python, sign_py, dst_path])          else: -            print "Skipping code signing of %s %s: %s not found" % (self.dst_path_of(exe), exe, sign_py) +            print("Skipping code signing of %s %s: %s not found" % (self.dst_path_of(exe), exe, sign_py))      def escape_slashes(self, path):          return path.replace('\\', '\\\\\\\\') @@ -880,14 +878,15 @@ class DarwinManifest(ViewerManifest):              if bugsplat_db:                  # Inject BugsplatServerURL into Info.plist if provided.                  Info_plist = self.dst_path_of("Info.plist") -                Info = plistlib.readPlist(Info_plist) -                # https://www.bugsplat.com/docs/platforms/os-x#configuration -                Info["BugsplatServerURL"] = \ -                    "https://{}.bugsplat.com/".format(bugsplat_db) -                self.put_in_file( -                    plistlib.writePlistToString(Info), -                    os.path.basename(Info_plist), -                    "Info.plist") +                with open(Info_plist, 'rb') as f: +                    Info = plistlib.load(f) +                    # https://www.bugsplat.com/docs/platforms/os-x#configuration +                    Info["BugsplatServerURL"] = \ +                        "https://{}.bugsplat.com/".format(bugsplat_db) +                    self.put_in_file( +                        plistlib.dumps(Info), +                        os.path.basename(Info_plist), +                        "Info.plist")              # CEF framework goes inside Contents/Frameworks.              # Remember where we parked this car. @@ -1013,10 +1012,10 @@ class DarwinManifest(ViewerManifest):                          added = [os.path.relpath(d, self.get_dst_prefix())                                   for s, d in self.file_list[oldlen:]]                      except MissingError as err: -                        print >> sys.stderr, "Warning: "+err.msg +                        print("Warning: "+err.msg, file=sys.stderr)                          added = []                      if not added: -                        print "Skipping %s" % dst +                        print("Skipping %s" % dst)                      return added                  # dylibs is a list of all the .dylib files we expect to need @@ -1208,7 +1207,7 @@ class DarwinManifest(ViewerManifest):          # mount the image and get the name of the mount point and device node          try: -            hdi_output = subprocess.check_output(['hdiutil', 'attach', '-private', sparsename]) +            hdi_output = subprocess.check_output(['hdiutil', 'attach', '-private', sparsename], text=True)          except subprocess.CalledProcessError as err:              sys.exit("failed to mount image at '%s'" % sparsename) @@ -1233,11 +1232,11 @@ class DarwinManifest(ViewerManifest):              if not os.path.exists (self.src_path_of(dmg_template)):                  dmg_template = os.path.join ('installers', 'darwin', 'release-dmg') -            for s,d in {self.get_dst_prefix():app_name + ".app", +            for s,d in list({self.get_dst_prefix():app_name + ".app",                          os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns",                          os.path.join(dmg_template, "background.jpg"): "background.jpg", -                        os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items(): -                print "Copying to dmg", s, d +                        os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items()): +                print("Copying to dmg", s, d)                  self.copy_action(self.src_path_of(s), os.path.join(volpath, d))              # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit) @@ -1262,7 +1261,7 @@ class DarwinManifest(ViewerManifest):              # and invalidate the signatures.              if 'signature' in self.args:                  app_in_dmg=os.path.join(volpath,self.app_name()+".app") -                print "Attempting to sign '%s'" % app_in_dmg +                print("Attempting to sign '%s'" % app_in_dmg)                  identity = self.args['signature']                  if identity == '':                      identity = 'Developer ID Application' @@ -1313,11 +1312,11 @@ class DarwinManifest(ViewerManifest):                              signed=True # if no exception was raised, the codesign worked                          except ManifestError as err:                              if sign_attempts: -                                print >> sys.stderr, "codesign failed, waiting %d seconds before retrying" % sign_retry_wait +                                print("codesign failed, waiting %d seconds before retrying" % sign_retry_wait, file=sys.stderr)                                  time.sleep(sign_retry_wait)                                  sign_retry_wait*=2                              else: -                                print >> sys.stderr, "Maximum codesign attempts exceeded; giving up" +                                print("Maximum codesign attempts exceeded; giving up", file=sys.stderr)                                  raise                      self.run_command(['spctl', '-a', '-texec', '-vvvv', app_in_dmg])                      self.run_command([self.src_path_of("installers/darwin/apple-notarize.sh"), app_in_dmg]) @@ -1326,7 +1325,7 @@ class DarwinManifest(ViewerManifest):              # Unmount the image even if exceptions from any of the above               self.run_command(['hdiutil', 'detach', '-force', devfile]) -        print "Converting temp disk image to final disk image" +        print("Converting temp disk image to final disk image")          self.run_command(['hdiutil', 'convert', sparsename, '-format', 'UDZO',                            '-imagekey', 'zlib-level=9', '-o', finalname])          # get rid of the temp file @@ -1383,7 +1382,7 @@ class LinuxManifest(ViewerManifest):          # Get the icons based on the channel type          icon_path = self.icon_path() -        print "DEBUG: icon_path '%s'" % icon_path +        print("DEBUG: icon_path '%s'" % icon_path)          with self.prefix(src=icon_path) :              self.path("secondlife_256.png","secondlife_icon.png")              with self.prefix(dst="res-sdl") : @@ -1404,7 +1403,7 @@ class LinuxManifest(ViewerManifest):          # llcommon          if not self.path("../llcommon/libllcommon.so", "lib/libllcommon.so"): -            print "Skipping llcommon.so (assuming llcommon was linked statically)" +            print("Skipping llcommon.so (assuming llcommon was linked statically)")          self.path("featuretable_linux.txt") @@ -1439,14 +1438,14 @@ class LinuxManifest(ViewerManifest):                                    '--numeric-owner', '-cjf',                                   tempname + '.tar.bz2', installer_name])              else: -                print "Skipping %s.tar.bz2 for non-Release build (%s)" % \ -                      (installer_name, self.args['buildtype']) +                print("Skipping %s.tar.bz2 for non-Release build (%s)" % \ +                      (installer_name, self.args['buildtype']))          finally:              self.run_command(["mv", tempname, realname])      def strip_binaries(self):          if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer(): -            print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build" +            print("* Going strip-crazy on the packaged binaries, since this is a RELEASE build")              # makes some small assumptions about our packaged dir structure              self.run_command(                  ["find"] + @@ -1513,7 +1512,7 @@ class Linux_i686_Manifest(LinuxManifest):                  self.path("libtcmalloc.so*") #formerly called google perf tools                  pass              except: -                print "tcmalloc files not found, skipping" +                print("tcmalloc files not found, skipping")                  pass              if self.args['fmodstudio'] == 'ON': @@ -1523,7 +1522,7 @@ class Linux_i686_Manifest(LinuxManifest):                      self.path("libfmod.so")                      pass                  except: -                    print "Skipping libfmod.so - not found" +                    print("Skipping libfmod.so - not found")                      pass          # Vivox runtimes @@ -1552,9 +1551,9 @@ class Linux_x86_64_Manifest(LinuxManifest):  if __name__ == "__main__":      # Report our own command line so that, in case of trouble, a developer can      # manually rerun the same command. -    print('%s \\\n%s' % +    print(('%s \\\n%s' %            (sys.executable, -           ' '.join((("'%s'" % arg) if ' ' in arg else arg) for arg in sys.argv))) +           ' '.join((("'%s'" % arg) if ' ' in arg else arg) for arg in sys.argv))))      # fmodstudio and openal can be used simultaneously and controled by environment      extra_arguments = [          dict(name='bugsplat', description="""BugSplat database to which to post crashes, | 
