diff options
22 files changed, 0 insertions, 3520 deletions
diff --git a/indra/viewer_components/manager/InstallerError.py b/indra/viewer_components/manager/InstallerError.py deleted file mode 100644 index 3b199ea231..0000000000 --- a/indra/viewer_components/manager/InstallerError.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - -"""\ -@file InstallerError.py -@author coyot -@date 2016-05-16 -@brief custom exception class for VMP - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -""" -usage: - ->>> import InstallerError ->>> import os ->>> try: -...    os.mkdir('/tmp') -... except OSError, oe: -...    ie = InstallerError.InstallerError(oe, "foo") -...    raise ie - -Traceback (most recent call last): -  File "<stdin>", line 5, in <module> -InstallerError.InstallerError: [Errno [Errno 17] File exists: '/tmp'] foo -""" - -class InstallerError(OSError): -    def __init___(self, message): -        Exception.__init__(self, message) diff --git a/indra/viewer_components/manager/InstallerUserMessage.py b/indra/viewer_components/manager/InstallerUserMessage.py deleted file mode 100644 index 8002399659..0000000000 --- a/indra/viewer_components/manager/InstallerUserMessage.py +++ /dev/null @@ -1,316 +0,0 @@ -#!/usr/bin/env python - -# $LicenseInfo:firstyear=2016&license=internal$ -#  -# Copyright (c) 2016, Linden Research, Inc. -#  -# The following source code is PROPRIETARY AND CONFIDENTIAL. Use of -# this source code is governed by the Linden Lab Source Code Disclosure -# Agreement ("Agreement") previously entered between you and Linden -# Lab. By accessing, using, copying, modifying or distributing this -# software, you acknowledge that you have been informed of your -# obligations under the Agreement and agree to abide by those obligations. -#  -# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -# COMPLETENESS OR PERFORMANCE. -# $LicenseInfo:firstyear=2013&license=viewerlgpl$ -# Copyright (c) 2013, Linden Research, Inc. -# $/LicenseInfo$ - -""" -@file   InstallerUserMessage.py -@author coyot -@date   2016-05-16 -""" - -""" -This does everything the old updater/scripts/darwin/messageframe.py script did and some more bits.   -Pushed up the manager directory to be multiplatform. -""" - -import os -import Queue -import threading -import time -import Tkinter as tk -import ttk - - -class InstallerUserMessage(tk.Tk): -    #Goals for this class: -    #  Provide a uniform look and feel -    #  Provide an easy to use convenience class for other scripts -    #  Provide windows that automatically disappear when done (for differing notions of done) -    #  Provide a progress bar that isn't a glorified spinner, but based on download progress -    #Non-goals: -    #  No claim to threadsafety is made or warranted.  Your mileage may vary.  -    #     Please consult a doctor if you experience thread pain. - -    #Linden standard green color, from Marketing -    linden_green = "#487A7B" - -    def __init__(self, text="", title="", width=500, height=200, wraplength = 400, icon_name = None, icon_path = None): -        tk.Tk.__init__(self) -        self.grid() -        self.title(title) -        self.choice = tk.BooleanVar() -        self.config(background = 'black') -        # background="..." doesn't work on MacOS for radiobuttons or progress bars -        # http://tinyurl.com/tkmacbuttons -        ttk.Style().configure('Linden.TLabel', foreground=InstallerUserMessage.linden_green, background='black') -        ttk.Style().configure('Linden.TButton', foreground=InstallerUserMessage.linden_green, background='black') -        ttk.Style().configure("black.Horizontal.TProgressbar", foreground=InstallerUserMessage.linden_green, background='black') - -        #This bit of configuration centers the window on the screen -        # The constants below are to adjust for typical overhead from the -        # frame borders. -        self.xp = (self.winfo_screenwidth()  / 2) - (width  / 2) - 8 -        self.yp = (self.winfo_screenheight() / 2) - (height / 2) - 20 -        self.geometry('{0}x{1}+{2}+{3}'.format(width, height, self.xp, self.yp)) - -        #find a few things -        self.script_dir = os.path.dirname(os.path.realpath(__file__)) -        self.contents_dir = os.path.dirname(self.script_dir) -        self.icon_dir = os.path.abspath(os.path.join(self.contents_dir, 'Resources/vmp_icons')) - -        #finds the icon and creates the widget -        self.find_icon(icon_path, icon_name) - -        #defines what to do when window is closed -        self.protocol("WM_DELETE_WINDOW", self._delete_window) -         -        #callback id -        self.id = -1 - -    def _delete_window(self): -        #capture and discard all destroy events before the choice is set -        if not ((self.choice == None) or (self.choice == "")): -            try: -                #initialized value.  If we have an outstanding callback, kill it before killing ourselves -                if self.id != -1: -                    self.after_cancel(self.id) -                self.destroy() -            except: -                #tk may try to destroy the same object twice -                pass - -    def set_colors(self, widget): -        # #487A7B is "Linden Green" -        widget.config(foreground = InstallerUserMessage.linden_green) -        widget.config(background='black')  - -    def find_icon(self, icon_path = None, icon_name = None): -        #we do this in each message, let's do it just once instead. -        if not icon_path: -            icon_path = self.icon_dir -        icon_path = os.path.join(icon_path, icon_name) -        print icon_path -        if os.path.exists(icon_path): -            icon = tk.PhotoImage(file=icon_path) -            self.image_label = tk.Label(image = icon) -            self.image_label.image = icon -        else: -            #default to text if image not available -            self.image_label = tk.Label(text = "Second Life") - -    def auto_resize(self, row_count = 0, column_count = 0, heavy_row = None, heavy_column = None): -        #auto resize window to fit all rows and columns -        #"heavy" gets extra weight -        for x in range(column_count): -            if x == heavy_column: -                self.columnconfigure(x, weight = 2) -            else: -                self.columnconfigure(x, weight=1) - -        for y in range(row_count): -            if y == heavy_row: -                self.rowconfigure(y, weight = 2) -            else: -                self.rowconfigure(x, weight=1) - -    def basic_message(self, message): -        #message: text to be displayed -        #icon_path: directory holding the icon, defaults to icons subdir of script dir -        #icon_name: filename of icon to be displayed -        self.choice.set(True) -        self.text_label = tk.Label(text = message) -        self.set_colors(self.text_label) -        self.set_colors(self.image_label) -        #pad, direction and weight are all experimentally derived by retrying various values -        self.image_label.grid(row = 1, column = 1, sticky = 'W') -        self.text_label.grid(row = 1, column = 2, sticky = 'W', padx =100) -        self.auto_resize(row_count = 1, column_count = 2) -        self.mainloop() - -    def binary_choice_message(self, message, true = 'Yes', false = 'No'): -        #true: first option, returns True -        #false: second option, returns False -        #usage is kind of opaque and relies on this object persisting after the window destruction to pass back choice -        #usage: -        #   frame = InstallerUserMessage.InstallerUserMessage( ... ) -        #   frame = frame.binary_choice_message( ... ) -        #   (wait for user to click) -        #   value = frame.choice.get() - -        self.text_label = tk.Label(text = message) -        #command registers the callback to the method named.  We want the frame to go away once clicked. -        #button 1 returns True/1, button 2 returns False/0 -        self.button_one = ttk.Radiobutton(text = true, variable = self.choice, value = True,  -            command = self._delete_window, style = 'Linden.TButton') -        self.button_two = ttk.Radiobutton(text = false, variable = self.choice, value = False,  -            command = self._delete_window, style = 'Linden.TButton') -        self.set_colors(self.text_label) -        self.set_colors(self.image_label) -        #pad, direction and weight are all experimentally derived by retrying various values -        self.image_label.grid(row = 1, column = 1, rowspan = 3, sticky = 'W') -        self.text_label.grid(row = 1, column = 2, rowspan = 3) -        self.button_one.grid(row = 1, column = 3, sticky = 'W', pady = 40) -        self.button_two.grid(row = 2, column = 3, sticky = 'W', pady = 0) -        self.auto_resize(row_count = 2, column_count = 3, heavy_column = 3) -        #self.button_two.deselect() -        self.update() -        self.mainloop() - -    def trinary_choice_message(self, message, one = 1, two = 2, three = 3): -        #one: first option, returns 1 -        #two: second option, returns 2 -        #three: third option, returns 3 -        #usage is kind of opaque and relies on this object persisting after the window destruction to pass back choice -        #usage: -        #   frame = InstallerUserMessage.InstallerUserMessage( ... ) -        #   frame = frame.binary_choice_message( ... ) -        #   (wait for user to click) -        #   value = frame.choice.get() - -        self.text_label = tk.Label(text = message) -        #command registers the callback to the method named.  We want the frame to go away once clicked. -        self.button_one = ttk.Radiobutton(text = one, variable = self.choice, value = 1,  -            command = self._delete_window, style = 'Linden.TButton') -        self.button_two = ttk.Radiobutton(text = two, variable = self.choice, value = 2,  -            command = self._delete_window, style = 'Linden.TButton') -        self.button_three = ttk.Radiobutton(text = three, variable = self.choice, value = 3,  -            command = self._delete_window, style = 'Linden.TButton') -        self.set_colors(self.text_label) -        self.set_colors(self.image_label) -        #pad, direction and weight are all experimentally derived by retrying various values -        self.image_label.grid(row = 1, column = 1, rowspan = 4, sticky = 'W') -        self.text_label.grid(row = 1, column = 2, rowspan = 4, padx = 5) -        self.button_one.grid(row = 1, column = 3, sticky = 'W', pady = 5) -        self.button_two.grid(row = 2, column = 3, sticky = 'W', pady = 5) -        self.button_three.grid(row = 3, column = 3, sticky = 'W', pady = 5) -        self.auto_resize(row_count = 3, column_count = 3, heavy_column = 3) -        #self.button_two.deselect() -        self.update() -        self.mainloop() - -    def progress_bar(self, message = None, size = 0, interval = 100, pb_queue = None): -        #Best effort attempt at a real progress bar -        #  This is what Tk calls "determinate mode" rather than "indeterminate mode" -        #size: denominator of percent complete -        #interval: frequency, in ms, of how often to poll the file for progress -        #pb_queue: queue object used to send updates to the bar -        self.text_label = tk.Label(text = message) -        self.set_colors(self.text_label) -        self.set_colors(self.image_label) -        self.image_label.grid(row = 1, column = 1, sticky = 'NSEW') -        self.text_label.grid(row = 2, column = 1, sticky = 'NSEW') -        self.progress = ttk.Progressbar(self, style = 'black.Horizontal.TProgressbar', orient="horizontal", length=100, mode="determinate") -        self.progress.grid(row = 3, column = 1, sticky = 'NSEW') -        self.value = 0 -        self.progress["maximum"] = size -        self.auto_resize(row_count = 1, column_count = 3) -        self.queue = pb_queue -        self.check_scheduler() - -    def check_scheduler(self): -        try: -            if self.value < self.progress["maximum"]: -                self.check_queue()             -                self.id = self.after(100, self.check_scheduler) -            else: -                #prevent a race condition between polling and the widget destruction -                self.after_cancel(self.id) -        except tk.TclError: -            #we're already dead, just die quietly -            pass - -    def check_queue(self): -        while self.queue.qsize(): -            try: -                msg = float(self.queue.get(0)) -                #custom signal, time to tear down -                if msg == -1: -                    self.choice.set(True) -                    self.destroy() -                else: -                    self.progress.step(msg) -                    self.value = msg -            except Queue.Empty: -                #nothing to do -                return - -class ThreadedClient(threading.Thread): -    #for test only, not part of the functional code -    def __init__(self, queue): -        threading.Thread.__init__(self) -        self.queue = queue - -    def run(self): -        for x in range(1, 90, 10): -            time.sleep(1) -            print "run " + str(x) -            self.queue.put(10) -        #tkk progress bars wrap at exactly 100 percent, look full at 99% -        print "leftovers" -        self.queue.put(9) -        time.sleep(5) -        # -1 is a custom signal to the progress_bar to quit -        self.queue.put(-1) - -if __name__ == "__main__": -    #When run as a script, just test the InstallUserMessage.   -    #To proceed with the test, close the first window, select on the second and fourth.  The third will close by itself. -    import sys -    import tempfile - -    def set_and_check(frame, value): -        print "value: " + str(value) -        frame.progress.step(value) -        if frame.progress["value"] < frame.progress["maximum"]: -            print "In Progress" -        else: -            print "Over now" - -    #basic message window test -    frame2 = InstallerUserMessage(text = "Something in the way she moves....", title = "Beatles Quotes for 100", icon_name="head-sl-logo.gif") -    print frame2.contents_dir -    print frame2.icon_dir -    frame2.basic_message(message = "...attracts me like no other.") -    print "Destroyed!" -    sys.stdout.flush() - -    #binary choice test.  User destroys window when they select. -    frame3 = InstallerUserMessage(text = "Something in the way she knows....", title = "Beatles Quotes for 200", icon_name="head-sl-logo.gif") -    frame3.binary_choice_message(message = "And all I have to do is think of her.",  -        true = "Don't want to leave her now", false = 'You know I believe and how') -    print frame3.choice.get() -    sys.stdout.flush() - -    #progress bar -    queue = Queue.Queue() -    thread = ThreadedClient(queue) -    thread.start() -    print "thread started" - -    frame4 = InstallerUserMessage(text = "Something in the way she knows....", title = "Beatles Quotes for 300", icon_name="head-sl-logo.gif") -    frame4.progress_bar(message = "You're asking me will my love grow", size = 100, pb_queue = queue) -    print "frame defined" -    frame4.mainloop() - -    #trinary choice test.  User destroys window when they select. -    frame3a = InstallerUserMessage(text = "Something in the way she knows....", title = "Beatles Quotes for 200", icon_name="head-sl-logo.gif") -    frame3a.trinary_choice_message(message = "And all I have to do is think of her.",  -        one = "Don't want to leave her now", two = 'You know I believe and how', three = 'John is Dead') -    print frame3a.choice.get() -    sys.stdout.flush() diff --git a/indra/viewer_components/manager/SL_Launcher b/indra/viewer_components/manager/SL_Launcher deleted file mode 100755 index 257543187c..0000000000 --- a/indra/viewer_components/manager/SL_Launcher +++ /dev/null @@ -1,199 +0,0 @@ -#!/usr/bin/env python - -# $LicenseInfo:firstyear=2016&license=internal$ -#  -# Copyright (c) 2016, Linden Research, Inc. -#  -# The following source code is PROPRIETARY AND CONFIDENTIAL. Use of -# this source code is governed by the Linden Lab Source Code Disclosure -# Agreement ("Agreement") previously entered between you and Linden -# Lab. By accessing, using, copying, modifying or distributing this -# software, you acknowledge that you have been informed of your -# obligations under the Agreement and agree to abide by those obligations. -#  -# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -# COMPLETENESS OR PERFORMANCE. -# $/LicenseInfo$ -# Copyright (c) 2013, Linden Research, Inc. - -import os -import sys - -#module globals -log_file_handle = None -cwd = os.path.dirname(os.path.realpath(__file__)) -sys.path.insert(0, os.path.join(cwd, 'llbase')) - -import argparse -import collections -import InstallerUserMessage -#NOTA BENE:  -#   For POSIX platforms, llsd.py will be imported from the same directory.   -#   For Windows, llsd.py will be compiled into the executable by pyinstaller -try: -   from llbase import llsd -except: -   #if Windows, this is expected, if not, we're dead -   if os.name == 'nt': -      pass -import platform -import subprocess -import update_manager - - -def silent_write(log_file_handle, text): -   #if we have a log file, write.  If not, do nothing. -   #this is so we don't have to keep trapping for an exception with a None handle -   #oh and because it is best effort, it is also a holey_write ;) -   if (log_file_handle): -      #prepend text for easy grepping -      timestamp = datetime.utcnow().strftime("%Y-%m-%D %H:%M:%S") -      log_file_handle.write(timestamp + " LAUNCHER: " + text + "\n") -   -def get_cmd_line(): -   platform_name = platform.system() -   #find the parent of the logs and user_settings directories -   if (platform_name == 'Darwin'): -      settings_file = os.path.join(os.path.dirname(os.path.dirname(os.path.realpath(__file__))), 'Resources/app_settings/cmd_line.xml') -   elif (platform_name == 'Linux'):  -      settings_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'app_settings/cmd_line.xml') -   #using list format of join is important here because the Windows pathsep in a string escapes the next char -   elif (platform_name == 'Windows'): -      settings_file = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'app_settings/cmd_line.xml') -   else: -      settings_file = None -       -   try: -      cmd_line = llsd.parse((open(settings_file)).read()) -   except: -      silent_write(log_file_handle, "Could not parse settings file %s" % settings_file) -      cmd_line = None -    -   return cmd_line - -def get_settings(): -   #return the settings file parsed into a dict -   try: -      settings_file = os.path.abspath(os.path.join(parent_dir,'user_settings','settings.xml')) -      settings = llsd.parse((open(settings_file)).read()) -   except llsd.LLSDParseError as lpe: -      silent_write(log_file_handle, "Could not parse settings file %s" % lpe) -      return None -   return settings - -def capture_vmp_args(arg_list = None, cmd_line = None): -   #expected input format: arg_list = ['--set', 'foo', 'bar', '-X', '-Y', 'qux'] -   #take a copy of the viewer parameters that are of interest to VMP. -   #the regex for a parameter is --<param> {opt1} {opt2} -   cli_overrides = {}    -   cmd_line = get_cmd_line() -    -   vmp_params = {'--channel':'channel', '--settings':'settings', '--update-service':'update-service', '--set':'set'} -   #the settings set with --set.  All such settings have only one argument. -   vmp_setters = ('UpdaterMaximumBandwidth', 'UpdaterServiceCheckPeriod', 'UpdaterServicePath', 'UpdaterServiceSetting', 'UpdaterServiceURL', 'UpdaterWillingToTest')    -    -   #Here turn the list into a queue, popping off the left as we go. Note that deque() makes a copy by value, not by reference -   #Because of the complexity introduced by the uncertainty of how many options a parameter can take, this is far less complicated code than the more -   #pythonic (x,y) = <some generator> since we will sometimes have (x), sometimes (x,y) and sometimes (x,y,z) -   #also, because the pop is destructive, we prevent ourselves from iterating back over list elements that iterator methods would peek ahead at -   vmp_queue = collections.deque(arg_list) -   while (len(vmp_queue)): -      param = vmp_queue.popleft() -      #if it is not one of ours, pop through args until we get to the next parameter -      if param in vmp_params.keys(): -         if param == '--set': -            setting_name = vmp_queue.popleft() -            setting_value = vmp_queue.popleft() -            if setting_name in vmp_setters: -               cli_overrides[vmp_params[param]] = (setting_name, setting_value) -         else: -            #find out how many args this parameter has -            no_dashes = vmp_params[param] -            count = cmd_line[no_dashes]['count'] -            param_args = [] -            if count > 0: -               for argh in range(0,count): -                  param_args.append(vmp_queue.popleft()) -            #the parameter name is the key, the (possibly empty) list of args is the value -            cli_overrides[vmp_params[param]] = param_args -             -   #to prevent KeyErrors on missing keys, set the remainder to None -   for key in vmp_params: -      if key != '--set': -         try: -            cli_overrides[key] -         except KeyError: -            cli_overrides[key] = None -      else: -         cli_overrides["--set"] = {} -         for arg in vmp_setters: -            try: -               cli_overrides[key][arg] -            except KeyError: -               cli_overrides[key][arg] = None -   return cli_overrides -    -#main entry point    -#this and a few other update manager methods really should be refactored into a util lib -parent_dir = update_manager.get_parent_path(update_manager.get_platform_key()) -log_file_handle = update_manager.get_log_file_handle(parent_dir, 'launcher.log') - -executable_name = "" -if sys.platform.startswith('darwin'): -   executable_name = "Second Life" -elif sys.platform.startswith("win") or sys.platform.startswith("cyg"): -   if os.path.isfile(os.path.join(cwd,"SecondLifeViewer.exe")): -      executable_name = "SecondLifeViewer.exe" -   elif os.path.isfile(os.path.join(cwd,"SecondLifeTest.exe")): -      executable_name = "SecondLifeTest.exe" -   else: -      sys.exit("Can't find Windows viewer binary") -elif sys.platform.startswith("linux"): -   executable_name = "secondlife" -else: -   #SL doesn't run on VMS or punch cards -   sys.exit("Unsupported platform") -    -#find the viewer to be lauched -viewer_binary = os.path.join(os.path.dirname(os.path.abspath(sys.argv[0])),executable_name)  - -parser = argparse.ArgumentParser() -args = parser.parse_known_args(sys.argv) -#args[1] looks like ['./SL_Launcher', '--set', 'foo', 'bar', '-X', '-Y', 'qux'], dump the progname -args_list_to_pass = args[1][1:] -vmp_args = capture_vmp_args(args_list_to_pass) -#make a copy by value, not by reference -command = list(args_list_to_pass) - -(success, state, condition) = update_manager.update_manager(vmp_args) -# From update_manager: -#  (False, 'setup', None): error occurred before we knew what the update was (e.g., in setup or parsing) -#  (False, 'download', version): we failed to download the new version -#  (False, 'apply', version): we failed to apply the new version -#  (True, None, None): No update found -#  (True, 'in place', True): update applied in place -#  (True, 'in place', path_to_new_launcher): Update applied by a new install to a new location -#  (True, 'background', True): background download initiated -#These boil down three cases: -#  Success is False, then pop up a message and launch the current viewer -#  No update, update succeeded in place in foreground, or background update started: silently launch the current viewer channel -#  Updated succeed to a different channel, launch that viewer and exit -if not success: -   msg = 'Update failed in the %s process.  Please check logs.  Viewer will launch starting momentarily.' % state -   update_manager.after_frame(msg) -   command.insert(0,viewer_binary) -   viewer_process = subprocess.Popen(command) -   #at the moment, we just exit here.  Later, the crash monitor will be launched at this point -elif (success == True and  -      (state == None  -       or (state ==  'background' and condition == True) -       or (state == 'in_place' and condition == True))): -   command.insert(0,viewer_binary) -   viewer_process = subprocess.Popen(command) -   #at the moment, we just exit here.  Later, the crash monitor will be launched at this point -else: -   #'condition' is the path to the new launcher. -   command.insert(0,condition) -   viewer_process = subprocess.Popen(command) -   sys.exit(0) diff --git a/indra/viewer_components/manager/apply_update.py b/indra/viewer_components/manager/apply_update.py deleted file mode 100755 index 643e4ad2bc..0000000000 --- a/indra/viewer_components/manager/apply_update.py +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2016, Linden Research, Inc. -#  -# The following source code is PROPRIETARY AND CONFIDENTIAL. Use of -# this source code is governed by the Linden Lab Source Code Disclosure -# Agreement ("Agreement") previously entered between you and Linden -# Lab. By accessing, using, copying, modifying or distributing this -# software, you acknowledge that you have been informed of your -# obligations under the Agreement and agree to abide by those obligations. -#  -# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -# COMPLETENESS OR PERFORMANCE. -# $LicenseInfo:firstyear=2016&license=viewerlgpl$ -# Copyright (c) 2016, Linden Research, Inc. -# $/LicenseInfo$ - -""" -@file   apply_update.py -@author coyot -@date   2016-06-28 -""" - -""" -Applies an already downloaded update. -""" - -import argparse -import errno -import fnmatch -import InstallerUserMessage as IUM -import os -import os.path -import plistlib -import re -import shutil -import subprocess -import sys -import tarfile -import tempfile - -#Module level variables - -#fnmatch expressions -LNX_REGEX = '*' + '.bz2' -MAC_REGEX = '*' + '.dmg' -MAC_APP_REGEX = '*' + '.app' -WIN_REGEX = '*' + '.exe' - -#which install the updater is run from -INSTALL_DIR = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) - -#whether the update is to the INSTALL_DIR or not.  Most of the time this is the case. -IN_PLACE = True - -BUNDLE_IDENTIFIER = "com.secondlife.indra.viewer" -# Magic OS directory name that causes Cocoa viewer to crash on OS X 10.7.5 -# (see MAINT-3331) -STATE_DIR = os.path.join(os.environ["HOME"], "Library", "Saved Application State", -    BUNDLE_IDENTIFIER + ".savedState") - -def silent_write(log_file_handle, text): -    #if we have a log file, write.  If not, do nothing. -    if (log_file_handle): -        #prepend text for easy grepping -        log_file_handle.write("APPLY UPDATE: " + text + "\n") - -def get_filename(download_dir = None): -    #given a directory that supposedly has the download, find the installable -    #if you are on platform X and you give the updater a directory with an installable   -    #for platform Y, you are either trying something fancy or get what you deserve -    #or both -    for filename in os.listdir(download_dir): -        if (fnmatch.fnmatch(filename, LNX_REGEX)  -          or fnmatch.fnmatch(filename, MAC_REGEX)  -          or fnmatch.fnmatch(filename, WIN_REGEX)):             -            return os.path.join(download_dir, filename) -    #someone gave us a bad directory -    return None   -           -def try_dismount(log_file_handle = None, installable = None, tmpdir = None): -    #best effort cleanup try to dismount the dmg file if we have mounted one -    #the French judge gave it a 5.8 -    try: -        #use the df command to find the device name -        #Filesystem   512-blocks   Used Available Capacity iused  ifree %iused  Mounted on -        #/dev/disk1s2    2047936 643280   1404656    32%   80408 175582   31%   /private/tmp/mnt/Second Life Installer -        command = ["df", os.path.join(tmpdir, "Second Life Installer")] -        output = subprocess.check_output(command) -        #first word of second line of df output is the device name -        mnt_dev = output.split('\n')[1].split()[0] -        #do the dismount -        command = ["hdiutil", "detach", "-force", mnt_dev] -        output = subprocess.check_output(command) -        silent_write(log_file_handle, "hdiutil detach succeeded") -        silent_write(log_file_handle, output) -    except Exception, e: -        silent_write(log_file_handle, "Could not detach dmg file %s.  Error messages: %s" % (installable, e.message))     - -def apply_update(download_dir = None, platform_key = None, log_file_handle = None, in_place = True): -    #for lnx and mac, returns path to newly installed viewer -    #for win, return the name of the executable -    #returns None on failure for all three -    #throws an exception if it can't find an installable at all -     -    IN_PLACE = in_place -     -    installable = get_filename(download_dir) -    if not installable: -        #could not find the download -        raise ValueError("Could not find installable in " + download_dir) -     -    #apply update using the platform specific tools -    if platform_key == 'lnx': -        installed = apply_linux_update(installable, log_file_handle) -    elif platform_key == 'mac': -        installed = apply_mac_update(installable, log_file_handle) -    elif platform_key == 'win': -        installed = apply_windows_update(installable, log_file_handle) -    else: -        #wtf? -        raise ValueError("Unknown Platform: " + platform_key) -     -    if not installed: -        #only mark the download as done when everything is done -        done_filename = os.path.join(os.path.dirname(installable), ".done") -        open(done_filename, 'w+').close() -         -    return installed -     -def apply_linux_update(installable = None, log_file_handle = None): -    try: -        #untar to tmpdir -        tmpdir = tempfile.mkdtemp() -        tar = tarfile.open(name = installable, mode="r:bz2") -        tar.extractall(path = tmpdir) -        if IN_PLACE: -            #rename current install dir -            shutil.move(INSTALL_DIR,install_dir + ".bak") -        #mv new to current -        shutil.move(tmpdir, INSTALL_DIR) -        #delete tarball on success -        os.remove(installable) -    except Exception, e: -        silent_write(log_file_handle, "Update failed due to " + repr(e)) -        return None -    return INSTALL_DIR - -def apply_mac_update(installable = None, log_file_handle = None): -    #INSTALL_DIR is something like /Applications/Second Life Viewer.app/Contents/MacOS, need to jump up two levels for the install base -    install_base = os.path.dirname(INSTALL_DIR) -    install_base = os.path.dirname(install_base) -     -    #verify dmg file -    try: -        output = subprocess.check_output(["hdiutil", "verify", installable], stderr=subprocess.STDOUT) -        silent_write(log_file_handle, "dmg verification succeeded") -        silent_write(log_file_handle, output) -    except Exception, e: -        silent_write(log_file_handle, "Could not verify dmg file %s.  Error messages: %s" % (installable, e.message)) -        return None -    #make temp dir and mount & attach dmg -    tmpdir = tempfile.mkdtemp() -    try: -        output = subprocess.check_output(["hdiutil", "attach", installable, "-mountroot", tmpdir]) -        silent_write(log_file_handle, "hdiutil attach succeeded") -        silent_write(log_file_handle, output) -    except Exception, e: -        silent_write(log_file_handle, "Could not attach dmg file %s.  Error messages: %s" % (installable, e.message)) -        return None -    #verify plist -    mounted_appdir = None -    for top_dir in os.listdir(tmpdir): -        for appdir in os.listdir(os.path.join(tmpdir, top_dir)): -            appdir = os.path.join(os.path.join(tmpdir, top_dir), appdir) -            if fnmatch.fnmatch(appdir, MAC_APP_REGEX): -                try: -                    plist = os.path.join(appdir, "Contents", "Info.plist") -                    CFBundleIdentifier = plistlib.readPlist(plist)["CFBundleIdentifier"] -                    mounted_appdir = appdir -                except: -                    #there is no except for this try because there are multiple directories that legimately don't have what we are looking for -                    pass -    if not mounted_appdir: -        silent_write(log_file_handle, "Could not find app bundle in dmg %s." % (installable,)) -        return None         -    if CFBundleIdentifier != BUNDLE_IDENTIFIER: -        silent_write(log_file_handle, "Wrong or null bundle identifier for dmg %s.  Bundle identifier: %s" % (installable, CFBundleIdentifier)) -        try_dismount(log_file_handle, installable, tmpdir)                    -        return None -    #do the install, finally -    if IN_PLACE: -        #  swap out old install directory -        bundlename = os.path.basename(mounted_appdir) -        silent_write(log_file_handle, "Updating %s" % bundlename) -        swapped_out = os.path.join(tmpdir, INSTALL_DIR.lstrip('/')) -        shutil.move(install_base, swapped_out)                -    else: -        silent_write(log_file_handle, "Installing %s" % install_base) -         -    #   copy over the new bits     -    try: -        shutil.copytree(mounted_appdir, install_base, symlinks=True) -        retcode = 0 -    except Exception, e: -        # try to restore previous viewer -        if os.path.exists(swapped_out): -            silent_write(log_file_handle, "Install of %s failed, rolling back to previous viewer." % installable) -            shutil.move(swapped_out, installed_test) -            retcode = 1 -    finally: -        try_dismount(log_file_handle, installable, tmpdir) -        if retcode: -            return None -     -    #see MAINT-3331         -    try: -        shutil.rmtree(STATE_DIR)   -    except Exception, e: -        #if we fail to delete something that isn't there, that's okay -        if e[0] == errno.ENOENT: -            pass -        else: -            raise e -     -    os.remove(installable) -    return install_base -     -def apply_windows_update(installable = None, log_file_handle = None): -    #the windows install is just running the NSIS installer executable -    #from VMP's perspective, it is a black box -    try: -        output = subprocess.check_output(installable, stderr=subprocess.STDOUT) -        silent_write(log_file_handle, "Install of %s succeeded." % installable) -        silent_write(log_file_handle, output) -    except subprocess.CalledProcessError, cpe: -        silent_write(log_file_handle, "%s failed with return code %s. Error messages: %s." %  -                     (cpe.cmd, cpe.returncode, cpe.message)) -        return None -    #Due to the black box nature of the install, we have to derive the application path from the -    #name of the installable.  This is essentially reverse-engineering app_name()/app_name_oneword() -    #in viewer_manifest.py -    #the format of the filename is:  Second_Life_{Project Name}_A-B-C-XXXXXX_i686_Setup.exe -    #which deploys to C:\Program Files (x86)\SecondLifeProjectName\ -    #so we want all but the last four phrases and tack on Viewer if there is no project -    if re.search('Project', installable): -        winstall = os.path.join("C:\\Program Files (x86)\\", "".join(installable.split("_")[:-3])) -    else: -        winstall = os.path.join("C:\\Program Files (x86)\\", "".join(installable.split("_")[:-3])+"Viewer") -    return winstall - -def main(): -    parser = argparse.ArgumentParser("Apply Downloaded Update") -    parser.add_argument('--dir', dest = 'download_dir', help = 'directory to find installable', required = True) -    parser.add_argument('--pkey', dest = 'platform_key', help =' OS: lnx|mac|win', required = True) -    parser.add_argument('--in_place', action = 'store_false', help = 'This upgrade is for a different channel', default = True) -    parser.add_argument('--log_file', dest = 'log_file', default = None, help = 'file to write messages to') -    args = parser.parse_args() -     -    if args.log_file: -        try: -            f = open(args.log_file,'w+')  -        except: -            print "%s could not be found or opened" % args.log_file -            sys.exit(1) -     -    IN_PLACE = args.in_place -    result = apply_update(download_dir = args.download_dir, platform_key = args.platform_key, log_file_handle = f) -    if not result: -        sys.exit("Update failed") -    else: -        sys.exit(0) - - -if __name__ == "__main__": -    main() diff --git a/indra/viewer_components/manager/download_update.py b/indra/viewer_components/manager/download_update.py deleted file mode 100755 index a5e365fa37..0000000000 --- a/indra/viewer_components/manager/download_update.py +++ /dev/null @@ -1,105 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2016, Linden Research, Inc. -#  -# The following source code is PROPRIETARY AND CONFIDENTIAL. Use of -# this source code is governed by the Linden Lab Source Code Disclosure -# Agreement ("Agreement") previously entered between you and Linden -# Lab. By accessing, using, copying, modifying or distributing this -# software, you acknowledge that you have been informed of your -# obligations under the Agreement and agree to abide by those obligations. -#  -# ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO -# WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, -# COMPLETENESS OR PERFORMANCE. -# $LicenseInfo:firstyear=2016&license=viewerlgpl$ -# Copyright (c) 2016, Linden Research, Inc. -# $/LicenseInfo$ - -""" -@file   download_update.py -@author coyot -@date   2016-06-23 -""" - -""" -Performs a download of an update.  In a separate script from update_manager so that we can -call it with subprocess. -""" - -import argparse -import InstallerUserMessage as IUM -import os -import Queue -import requests -import threading - -#module default -CHUNK_SIZE = 1024 - -def download_update(url = None, download_dir = None, size = None, progressbar = False, chunk_size = CHUNK_SIZE): -    #url to download from -    #download_dir to download to -    #total size (for progressbar) of download -    #progressbar: whether to display one (not used for background downloads) -    #chunk_size is in bytes, amount to download at once -     -    queue = Queue.Queue() -    if not os.path.exists(download_dir): -        os.makedirs(download_dir) -    #the url split provides the basename of the filename -    filename = os.path.join(download_dir, url.split('/')[-1]) -    req = requests.get(url, stream=True) -    down_thread = ThreadedDownload(req, filename, chunk_size, progressbar, queue) -    down_thread.start() -     -    if progressbar: -        frame = IUM.InstallerUserMessage(title = "Second Life Downloader", icon_name="head-sl-logo.gif") -        frame.progress_bar(message = "Download Progress", size = size, pb_queue = queue) -        frame.mainloop() -    else: -        #nothing for the main thread to do -        down_thread.join() - -class ThreadedDownload(threading.Thread): -    def __init__(self, req, filename, chunk_size, progressbar, in_queue): -        #req is a python request object -        #target filename to download to -        #chunk_size is in bytes, amount to download at once -        #progressbar: whether to display one (not used for background downloads) -        #in_queue mediates communication between this thread and the progressbar -        threading.Thread.__init__(self) -        self.req = req -        self.filename = filename -        self.chunk_size = int(chunk_size) -        self.progressbar = progressbar -        self.in_queue = in_queue -         -    def run(self): -        with open(self.filename, 'wb') as fd: -            #keep downloading until we run out of chunks, then download the last bit -            for chunk in self.req.iter_content(self.chunk_size): -                fd.write(chunk) -                if self.progressbar: -                    #this will increment the progress bar by len(chunk)/size units -                    self.in_queue.put(len(chunk))   -            #signal value saying to the progress bar that it is done and can destroy itself -            #if len(chunk) is ever -1, we get to file a bug against Python -            self.in_queue.put(-1) - -def main(): -    #main method is for standalone use such as support and QA -    #VMP will import this module and run download_update directly -    parser = argparse.ArgumentParser("Download URI to directory") -    parser.add_argument('--url', dest='url', help='URL of file to be downloaded', required=True) -    parser.add_argument('--dir', dest='download_dir', help='directory to be downloaded to', required=True) -    parser.add_argument('--pb', dest='progressbar', help='whether or not to show a progressbar', action="store_true", default = False) -    parser.add_argument('--size', dest='size', help='size of download for progressbar') -    parser.add_argument('--chunk_size', dest='chunk_size', default=CHUNK_SIZE, help='max portion size of download to be loaded in memory in bytes.') -    args = parser.parse_args() - -    download_update(url = args.url, download_dir = args.download_dir, size = args.size, progressbar = args.progressbar, chunk_size = args.chunk_size) - - -if __name__ == "__main__": -    main() diff --git a/indra/viewer_components/manager/tests/data/settings.xml b/indra/viewer_components/manager/tests/data/settings.xml deleted file mode 100644 index 07e420dcb3..0000000000 --- a/indra/viewer_components/manager/tests/data/settings.xml +++ /dev/null @@ -1,1184 +0,0 @@ -<llsd> -    <map> -    <key>AllowMultipleViewers</key> -        <map> -        <key>Comment</key> -            <string>Allow multiple viewers.</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>1</integer> -        </map> -    <key>AllowTapTapHoldRun</key> -        <map> -        <key>Comment</key> -            <string>Tapping a direction key twice and holding it down makes avatar run</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>0</integer> -        </map> -    <key>AppearanceCameraMovement</key> -        <map> -        <key>Comment</key> -            <string>When entering appearance editing mode, camera zooms in on currently selected portion of avatar</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>0</integer> -        </map> -    <key>AudioLevelMedia</key> -        <map> -        <key>Comment</key> -            <string>Audio level of Quicktime movies</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.699999988079071044921875</real> -        </map> -    <key>AudioLevelMic</key> -        <map> -        <key>Comment</key> -            <string>Audio level of microphone input</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.1749999970197677612304688</real> -        </map> -    <key>AudioLevelMusic</key> -        <map> -        <key>Comment</key> -            <string>Audio level of streaming music</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0</real> -        </map> -    <key>AudioLevelSFX</key> -        <map> -        <key>Comment</key> -            <string>Audio level of in-world sound effects</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.699999988079071044921875</real> -        </map> -    <key>AudioLevelVoice</key> -        <map> -        <key>Comment</key> -            <string>Audio level of voice chat</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>1</real> -        </map> -    <key>AudioStreamingMedia</key> -        <map> -        <key>Comment</key> -            <string>Enable streaming</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>0</integer> -        </map> -    <key>AvatarAxisDeadZone0</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 0 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.1000000014901161193847656</real> -        </map> -    <key>AvatarAxisDeadZone1</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 1 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.1000000014901161193847656</real> -        </map> -    <key>AvatarAxisDeadZone2</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 2 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.1000000014901161193847656</real> -        </map> -    <key>AvatarAxisDeadZone3</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 3 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>1</real> -        </map> -    <key>AvatarAxisDeadZone4</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 4 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.01999999955296516418457031</real> -        </map> -    <key>AvatarAxisDeadZone5</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 5 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>AvatarAxisScale3</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 3 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0</real> -        </map> -    <key>AvatarAxisScale4</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 4 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>2</real> -        </map> -    <key>AvatarAxisScale5</key> -        <map> -        <key>Comment</key> -            <string>Avatar axis 5 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>2</real> -        </map> -    <key>AvatarFeathering</key> -        <map> -        <key>Comment</key> -            <string>Avatar feathering (less is softer)</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>6</real> -        </map> -    <key>AvatarFileName</key> -        <map> -        <key>Comment</key> -            <string>Alternative avatar file name</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>avatar_lad_tentacles.xml</string> -        </map> -    <key>BuildAxisDeadZone0</key> -        <map> -        <key>Comment</key> -            <string>Build axis 0 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>BuildAxisDeadZone1</key> -        <map> -        <key>Comment</key> -            <string>Build axis 1 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>BuildAxisDeadZone2</key> -        <map> -        <key>Comment</key> -            <string>Build axis 2 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>BuildAxisDeadZone3</key> -        <map> -        <key>Comment</key> -            <string>Build axis 3 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>BuildAxisDeadZone4</key> -        <map> -        <key>Comment</key> -            <string>Build axis 4 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>BuildAxisDeadZone5</key> -        <map> -        <key>Comment</key> -            <string>Build axis 5 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>BuildAxisScale0</key> -        <map> -        <key>Comment</key> -            <string>Build axis 0 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>6</real> -        </map> -    <key>BuildAxisScale1</key> -        <map> -        <key>Comment</key> -            <string>Build axis 1 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>6</real> -        </map> -    <key>BuildAxisScale2</key> -        <map> -        <key>Comment</key> -            <string>Build axis 2 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>6</real> -        </map> -    <key>BuildAxisScale3</key> -        <map> -        <key>Comment</key> -            <string>Build axis 3 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>6</real> -        </map> -    <key>BuildAxisScale4</key> -        <map> -        <key>Comment</key> -            <string>Build axis 4 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>6</real> -        </map> -    <key>BuildAxisScale5</key> -        <map> -        <key>Comment</key> -            <string>Build axis 5 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>6</real> -        </map> -    <key>BuildFeathering</key> -        <map> -        <key>Comment</key> -            <string>Build feathering (less is softer)</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>12</real> -        </map> -    <key>BulkChangeEveryoneCopy</key> -        <map> -        <key>Comment</key> -            <string>Bulk changed objects can be copied by everyone</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>BulkChangeNextOwnerCopy</key> -        <map> -        <key>Comment</key> -            <string>Bulk changed objects can be copied by next owner</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>BulkChangeNextOwnerModify</key> -        <map> -        <key>Comment</key> -            <string>Bulk changed objects can be modified by next owner</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>BulkChangeShareWithGroup</key> -        <map> -        <key>Comment</key> -            <string>Bulk changed objects are shared with the currently active group</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>CacheValidateCounter</key> -        <map> -        <key>Comment</key> -            <string>Used to distribute cache validation</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>122</integer> -        </map> -    <key>CameraPosOnLogout</key> -        <map> -        <key>Comment</key> -            <string>Camera position when last logged out (global coordinates)</string> -        <key>Type</key> -            <string>Vector3D</string> -        <key>Value</key> -            <array> -                <real>288290.4477181434631347656</real> -                <real>275988.5277819633483886719</real> -                <real>49.10921102762222290039062</real> -            </array> -        </map> -    <key>ClickToWalk</key> -        <map> -        <key>Comment</key> -            <string>Click in world to walk to location</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>ConversationSortOrder</key> -        <map> -        <key>Comment</key> -            <string>Specifies sort key for conversations</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>0</integer> -        </map> -    <key>CurrentGrid</key> -        <map> -        <key>Comment</key> -            <string>Currently Selected Grid</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>util.agni.lindenlab.com</string> -        </map> -    <key>Cursor3D</key> -        <map> -        <key>Comment</key> -            <string>Treat Joystick values as absolute positions (not deltas).</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>FirstLoginThisInstall</key> -        <map> -        <key>Comment</key> -            <string>Specifies that you have not logged in with the viewer since you performed a clean install</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>FirstRunThisInstall</key> -        <map> -        <key>Comment</key> -            <string>Specifies that you have not run the viewer since you performed a clean install</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>FlycamAxisDeadZone0</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 0 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>FlycamAxisDeadZone1</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 1 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>FlycamAxisDeadZone2</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 2 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>FlycamAxisDeadZone3</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 3 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>FlycamAxisDeadZone4</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 4 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>FlycamAxisDeadZone5</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 5 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0.009999999776482582092285156</real> -        </map> -    <key>FlycamAxisDeadZone6</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 6 dead zone.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>1</real> -        </map> -    <key>FlycamAxisScale0</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 0 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>42</real> -        </map> -    <key>FlycamAxisScale1</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 1 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>40</real> -        </map> -    <key>FlycamAxisScale2</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 2 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>40</real> -        </map> -    <key>FlycamAxisScale3</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 3 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0</real> -        </map> -    <key>FlycamAxisScale4</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 4 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>2</real> -        </map> -    <key>FlycamAxisScale5</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 5 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>3</real> -        </map> -    <key>FlycamAxisScale6</key> -        <map> -        <key>Comment</key> -            <string>Flycam axis 6 scaler.</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>0</real> -        </map> -    <key>FlycamFeathering</key> -        <map> -        <key>Comment</key> -            <string>Flycam feathering (less is softer)</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>5</real> -        </map> -    <key>FocusPosOnLogout</key> -        <map> -        <key>Comment</key> -            <string>Camera focus point when last logged out (global coordinates)</string> -        <key>Type</key> -            <string>Vector3D</string> -        <key>Value</key> -            <array> -                <real>288287.8830481640761718154</real> -                <real>275991.5973855691263452172</real> -                <real>47.96361158013021963597566</real> -            </array> -        </map> -    <key>ForceShowGrid</key> -        <map> -        <key>Comment</key> -            <string>Always show grid dropdown on login screen</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>1</integer> -        </map> -    <key>HttpProxyType</key> -        <map> -        <key>Comment</key> -            <string>Proxy type to use for HTTP operations</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>None</string> -        </map> -    <key>JoystickInitialized</key> -        <map> -        <key>Comment</key> -            <string>Whether or not a joystick has been detected and initiailized.</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>UnknownDevice</string> -        </map> -    <key>LSLFindCaseInsensitivity</key> -        <map> -        <key>Comment</key> -            <string>Use case insensitivity when searching in LSL editor</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>1</integer> -        </map> -    <key>LastFeatureVersion</key> -        <map> -        <key>Comment</key> -            <string>[DO NOT MODIFY] Feature Table Version number for tracking rendering system changes</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>37</integer> -        </map> -    <key>LastGPUString</key> -        <map> -        <key>Comment</key> -            <string>[DO NOT MODIFY] previous GPU id string for tracking hardware changes</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>NVIDIA Corporation NVIDIA GeForce GT 750M OpenGL Engine</string> -        </map> -    <key>LastPrefTab</key> -        <map> -        <key>Comment</key> -            <string>Last selected tab in preferences window</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>1</integer> -        </map> -    <key>LastRunVersion</key> -        <map> -        <key>Comment</key> -            <string>Version number of last instance of the viewer that you ran</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>Second Life Project Bento 5.0.0.315657</string> -        </map> -    <key>LocalCacheVersion</key> -        <map> -        <key>Comment</key> -            <string>Version number of cache</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>7</integer> -        </map> -    <key>LoginLocation</key> -        <map> -        <key>Comment</key> -            <string>Default Login location ('last', 'home') preference</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>home</string> -        </map> -    <key>MapScale</key> -        <map> -        <key>Comment</key> -            <string>World map zoom level (pixels per region)</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>256</real> -        </map> -    <key>MaxJointsPerMeshObject</key> -        <map> -        <key>Comment</key> -            <string>Maximum joints per rigged mesh object</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <real>51</real> -        </map> -    <key>MediaEnablePopups</key> -        <map> -        <key>Comment</key> -            <string>If true, enable targeted links and javascript in media to open new media browser windows without a prompt.</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>MediaShowOnOthers</key> -        <map> -        <key>Comment</key> -            <string>Whether or not to show media on other avatars</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>1</integer> -        </map> -    <key>MigrateCacheDirectory</key> -        <map> -        <key>Comment</key> -            <string>Check for old version of disk cache to migrate to current location</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>NavBarShowParcelProperties</key> -        <map> -        <key>Comment</key> -            <string>Show parcel property icons in navigation bar</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>NextLoginLocation</key> -        <map> -        <key>Comment</key> -            <string>Location to log into for this session - set from command line or the login panel, cleared following a successfull login.</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>home</string> -        </map> -    <key>NotificationConferenceIMOptions</key> -        <map> -        <key>Comment</key> -            <string> -        Specifies how the UI responds to Conference IM Notifications. -        Allowed values: [openconversations,toast,flash,noaction] -      </string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>none</string> -        </map> -    <key>NotificationFriendIMOptions</key> -        <map> -        <key>Comment</key> -            <string> -        Specifies how the UI responds to Friend IM Notifications. -        Allowed values: [openconversations,toast,flash,noaction] -      </string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>openconversations</string> -        </map> -    <key>NotificationGroupChatOptions</key> -        <map> -        <key>Comment</key> -            <string> -        Specifies how the UI responds to Group Chat Notifications. -        Allowed values: [openconversations,toast,flash,noaction] -      </string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>none</string> -        </map> -    <key>NotificationNearbyChatOptions</key> -        <map> -        <key>Comment</key> -            <string> -        Specifies how the UI responds to Nearby Chat Notifications. -        Allowed values: [openconversations,toast,flash,noaction] -      </string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>none</string> -        </map> -    <key>NotificationNonFriendIMOptions</key> -        <map> -        <key>Comment</key> -            <string> -        Specifies how the UI responds to Non Friend IM Notifications. -        Allowed values: [openconversations,toast,flash,noaction] -      </string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>openconversations</string> -        </map> -    <key>NumSessions</key> -        <map> -        <key>Comment</key> -            <string>Number of successful logins to Second Life</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>1674</integer> -        </map> -    <key>PlayTypingAnim</key> -        <map> -        <key>Comment</key> -            <string>Your avatar plays the typing animation whenever you type in the chat bar</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>0</integer> -        </map> -    <key>PoolSizeExpCache</key> -        <map> -        <key>Comment</key> -            <string>Coroutine Pool size for ExpCache</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>5</integer> -        </map> -    <key>PreferredBrowserBehavior</key> -        <map> -        <key>Comment</key> -            <string>Use system browser for any links (0), use builtin browser for SL links and system one for others (1) or use builtin browser only (2).</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <string>0</string> -        </map> -    <key>PreferredMaturity</key> -        <map> -        <key>Comment</key> -            <string>Setting for the user's preferred maturity level (consts in indra_constants.h)</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>42</integer> -        </map> -    <key>PresetGraphicActive</key> -        <map> -        <key>Comment</key> -            <string>Name of currently selected preference</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>Default</string> -        </map> -    <key>ProbeHardwareOnStartup</key> -        <map> -        <key>Comment</key> -            <string>Query current hardware configuration on application startup</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>QAMode</key> -        <map> -        <key>Comment</key> -            <string>Enable Testing Features.</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>RenderAnisotropic</key> -        <map> -        <key>Comment</key> -            <string>Render textures using anisotropic filtering</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>RenderAvatarCloth</key> -        <map> -        <key>Comment</key> -            <string>Controls if avatars use wavy cloth</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>RenderAvatarLODFactor</key> -        <map> -        <key>Comment</key> -            <string>Controls level of detail of avatars (multiplier for current screen area when calculated level of detail)</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>1</real> -        </map> -    <key>RenderFSAASamples</key> -        <map> -        <key>Comment</key> -            <string>Number of samples to use for FSAA (0 = no AA).</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>2</integer> -        </map> -    <key>RenderFarClip</key> -        <map> -        <key>Comment</key> -            <string>Distance of far clip plane from camera (meters)</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>128</real> -        </map> -    <key>RenderMaxPartCount</key> -        <map> -        <key>Comment</key> -            <string>Maximum number of particles to display on screen</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <real>2048</real> -        </map> -    <key>RenderQualityPerformance</key> -        <map> -        <key>Comment</key> -            <string>Which graphics settings you've chosen</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <real>4</real> -        </map> -    <key>RenderReflectionDetail</key> -        <map> -        <key>Comment</key> -            <string>Detail of reflection render pass.</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>0</integer> -        </map> -    <key>RenderTerrainLODFactor</key> -        <map> -        <key>Comment</key> -            <string>Controls level of detail of terrain (multiplier for current screen area when calculated level of detail)</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>2</real> -        </map> -    <key>RenderVBOEnable</key> -        <map> -        <key>Comment</key> -            <string>Use GL Vertex Buffer Objects</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>RenderVolumeLODFactor</key> -        <map> -        <key>Comment</key> -            <string>Controls level of detail of primitives (multiplier for current screen area when calculated level of detail)</string> -        <key>Type</key> -            <string>F32</string> -        <key>Value</key> -            <real>1.125</real> -        </map> -    <key>ShowAdvancedGraphicsSettings</key> -        <map> -        <key>Comment</key> -            <string>Show advanced graphics settings</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>1</integer> -        </map> -    <key>ShowBanLines</key> -        <map> -        <key>Comment</key> -            <string>Show in-world ban/access borders</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>ShowStartLocation</key> -        <map> -        <key>Comment</key> -            <string>Display starting location menu on login screen</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>SkeletonFileName</key> -        <map> -        <key>Comment</key> -            <string>Alternative skeleton file name</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>avatar_skeleton_tentacles.xml</string> -        </map> -    <key>SkyPresetName</key> -        <map> -        <key>Comment</key> -            <string>Sky preset to use. May be superseded by region settings or by a day cycle (see DayCycleName).</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>Sunset</string> -        </map> -    <key>SnapshotConfigURL</key> -        <map> -        <key>Comment</key> -            <string>URL to fetch Snapshot Sharing configuration data from.</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>http://photos.apps.avatarsunited.com/viewer_config</string> -        </map> -    <key>SnapshotFormat</key> -        <map> -        <key>Comment</key> -            <string>Save snapshots in this format (0 = PNG, 1 = JPEG, 2 = BMP)</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>1</integer> -        </map> -    <key>SnapshotQuality</key> -        <map> -        <key>Comment</key> -            <string>Quality setting of postcard JPEGs (0 = worst, 100 = best)</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>100</integer> -        </map> -    <key>SpellCheck</key> -        <map> -        <key>Comment</key> -            <string>Enable spellchecking on line and text editors</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <integer>0</integer> -        </map> -    <key>SpellCheckDictionary</key> -        <map> -        <key>Comment</key> -            <string>Current primary and secondary dictionaries used for spell checking</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>English (United States)</string> -        </map> -    <key>TextureMemory</key> -        <map> -        <key>Comment</key> -            <string>Amount of memory to use for textures in MB (0 = autodetect)</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>256</integer> -        </map> -    <key>UseDayCycle</key> -        <map> -        <key>Comment</key> -            <string>Whether to use use a day cycle or a fixed sky.</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>UseDebugMenus</key> -        <map> -        <key>Comment</key> -            <string>Turns on "Debug" menu</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>UseEnvironmentFromRegion</key> -        <map> -        <key>Comment</key> -            <string>Choose whether to use the region's environment settings, or override them with the local settings.</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>0</boolean> -        </map> -    <key>VFSOldSize</key> -        <map> -        <key>Comment</key> -            <string>[DO NOT MODIFY] Controls resizing of local file cache</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>102</integer> -        </map> -    <key>VFSSalt</key> -        <map> -        <key>Comment</key> -            <string>[DO NOT MODIFY] Controls local file caching behavior</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>260093998</integer> -        </map> -    <key>VersionChannelName</key> -        <map> -        <key>Comment</key> -            <string>Version information generated by running the viewer</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>Second Life Release</string> -        </map> -    <key>VertexShaderEnable</key> -        <map> -        <key>Comment</key> -            <string>Enable/disable all GLSL shaders (debug)</string> -        <key>Type</key> -            <string>Boolean</string> -        <key>Value</key> -            <boolean>1</boolean> -        </map> -    <key>VoiceInputAudioDevice</key> -        <map> -        <key>Comment</key> -            <string>Audio input device to use for voice</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>C-Media USB Audio Device</string> -        </map> -    <key>VoiceOutputAudioDevice</key> -        <map> -        <key>Comment</key> -            <string>Audio output device to use for voice</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <string>C-Media USB Audio Device</string> -        </map> -    <key>WLSkyDetail</key> -        <map> -        <key>Comment</key> -            <string>Controls vertex detail on the WindLight sky.  Lower numbers will give better performance and uglier skies.</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>48</integer> -        </map> -    <key>WebProfileFloaterRect</key> -        <map> -        <key>Comment</key> -            <string>Web profile floater dimensions</string> -        <key>Type</key> -            <string>Rect</string> -        <key>Value</key> -            <array> -                <integer>1189</integer> -                <integer>957</integer> -                <integer>1674</integer> -                <integer>277</integer> -            </array> -        </map> -    <key>WindowHeight</key> -        <map> -        <key>Comment</key> -            <string>SL viewer window height</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>1000</integer> -        </map> -    <key>WindowWidth</key> -        <map> -        <key>Comment</key> -            <string>SL viewer window width</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <integer>1626</integer> -        </map> -    <key>WindowX</key> -        <map> -        <key>Comment</key> -            <string>X coordinate of upper left corner of SL viewer window, relative to upper left corner of primary display (pixels)</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>50</integer> -        </map> -    <key>WindowY</key> -        <map> -        <key>Comment</key> -            <string>Y coordinate of upper left corner of SL viewer window, relative to upper left corner of primary display (pixels)</string> -        <key>Type</key> -            <string>S32</string> -        <key>Value</key> -            <integer>50</integer> -        </map> -    </map> -</llsd> diff --git a/indra/viewer_components/manager/tests/summary.json b/indra/viewer_components/manager/tests/summary.json deleted file mode 100644 index b78859d427..0000000000 --- a/indra/viewer_components/manager/tests/summary.json +++ /dev/null @@ -1 +0,0 @@ -{"Type":"viewer","Version":"4.0.5.315117","Channel":"Second Life Release"} diff --git a/indra/viewer_components/manager/tests/test_InstallerError.py b/indra/viewer_components/manager/tests/test_InstallerError.py deleted file mode 100644 index 9139447932..0000000000 --- a/indra/viewer_components/manager/tests/test_InstallerError.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python - -"""\ -@file   test_InstallerError.py -@author coyot -@date   2016-06-01 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - - -from nose.tools import assert_equal - -import InstallerError -import os - -def test_InstallerError(): -    try: -        #try to make our own homedir, this will fail on all three platforms -        homedir = os.path.abspath(os.path.expanduser('~')) -        os.mkdir(homedir) -    except OSError, oe: -        ie = InstallerError.InstallerError(oe, "Installer failed to create a homedir that already exists.") - -    assert_equal( str(ie),  -        "[Errno [Errno 17] File exists: '%s'] Installer failed to create a homedir that already exists." % homedir) diff --git a/indra/viewer_components/manager/tests/test_check_for_completed_download.py b/indra/viewer_components/manager/tests/test_check_for_completed_download.py deleted file mode 100644 index bcaaef4c3f..0000000000 --- a/indra/viewer_components/manager/tests/test_check_for_completed_download.py +++ /dev/null @@ -1,59 +0,0 @@ -#!/usr/bin/env python - - -""" -@file   test_check_for_completed_download.py -@author coyot -@date   2016-06-03 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * -from nose import with_setup - -import os -import shutil -import tempfile -import update_manager -import with_setup_args - -def check_for_completed_download_setup(): -    tmpdir1 = tempfile.mkdtemp(prefix = 'test1') -    tmpdir2 = tempfile.mkdtemp(prefix = 'test2') -    tempfile.mkstemp(suffix = '.done', dir = tmpdir1) - -    return [tmpdir1,tmpdir2], {} - -def check_for_completed_download_teardown(tmpdir1,tmpdir2): -    shutil.rmtree(tmpdir1, ignore_errors = True) -    shutil.rmtree(tmpdir2, ignore_errors = True) - -@with_setup_args.with_setup_args(check_for_completed_download_setup, check_for_completed_download_teardown) -def test_completed_check_for_completed_download(tmpdir1,tmpdir2): -    assert_equal(update_manager.check_for_completed_download(tmpdir1), 'done'), "Failed to find completion marker" - -@with_setup_args.with_setup_args(check_for_completed_download_setup, check_for_completed_download_teardown) -def test_incomplete_check_for_completed_download(tmpdir1,tmpdir2): -    #should return False -    incomplete = not update_manager.check_for_completed_download(tmpdir2) -    assert incomplete, "False positive, should not mark complete without a marker" diff --git a/indra/viewer_components/manager/tests/test_convert_version_file_style.py b/indra/viewer_components/manager/tests/test_convert_version_file_style.py deleted file mode 100644 index 244c22c458..0000000000 --- a/indra/viewer_components/manager/tests/test_convert_version_file_style.py +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env python - -"""\ -@file   test_convert_version_file_style.py -@author coyot -@date   2016-06-01 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - - -from nose.tools import assert_equal - -import update_manager - -def test_normal_form(): -    version = '1.2.3.456789' -    golden = '1_2_3_456789' -    converted = update_manager.convert_version_file_style(version) -     -    assert_equal(golden, converted) - -def test_short_form(): -    version = '1.23' -    golden = '1_23' -    converted = update_manager.convert_version_file_style(version) -     -    assert_equal(golden, converted) - -def test_idempotent(): -    version = '123' -    golden = '123' -    converted = update_manager.convert_version_file_style(version) -     -    assert_equal(golden, converted) - -def test_none(): -    version = None -    golden = None -    converted = update_manager.convert_version_file_style(version) -     -    assert_equal(golden, converted) diff --git a/indra/viewer_components/manager/tests/test_get_filename.py b/indra/viewer_components/manager/tests/test_get_filename.py deleted file mode 100644 index efb6349374..0000000000 --- a/indra/viewer_components/manager/tests/test_get_filename.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python - - -""" -@file   test_get_filename.py -@author coyot -@date   2016-06-30 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * -from nose import with_setup - -import os -import shutil -import tempfile -import apply_update -import with_setup_args - -def get_filename_setup(): -    tmpdir1 = tempfile.mkdtemp(prefix = 'lnx') -    tmpdir2 = tempfile.mkdtemp(prefix = 'mac') -    tmpdir3 = tempfile.mkdtemp(prefix = 'win') -    tmpdir4 = tempfile.mkdtemp(prefix = 'bad') -    tempfile.mkstemp(suffix = '.bz2', dir = tmpdir1) -    tempfile.mkstemp(suffix = '.dmg', dir = tmpdir2) -    tempfile.mkstemp(suffix = '.exe', dir = tmpdir3) - -    return [tmpdir1,tmpdir2, tmpdir3, tmpdir4], {} - -def get_filename_teardown(tmpdir1,tmpdir2, tmpdir3, tmpdir4): -    shutil.rmtree(tmpdir1, ignore_errors = True) -    shutil.rmtree(tmpdir2, ignore_errors = True) -    shutil.rmtree(tmpdir3, ignore_errors = True) -    shutil.rmtree(tmpdir4, ignore_errors = True) - -@with_setup_args.with_setup_args(get_filename_setup, get_filename_teardown) -def test_get_filename(tmpdir1, tmpdir2, tmpdir3, tmpdir4): -    assert_is_not_none(apply_update.get_filename(tmpdir1)), "Failed to find installable" -    assert_is_not_none(apply_update.get_filename(tmpdir2)), "Failed to find installable" -    assert_is_not_none(apply_update.get_filename(tmpdir3)), "Failed to find installable" - -@with_setup_args.with_setup_args(get_filename_setup, get_filename_teardown) -def test_missing_get_filename(tmpdir1, tmpdir2, tmpdir3, tmpdir4): -    not_found = not apply_update.get_filename(tmpdir4) -    assert not_found, "False positive, should not find an installable in an empty dir" diff --git a/indra/viewer_components/manager/tests/test_get_log_file_handle.py b/indra/viewer_components/manager/tests/test_get_log_file_handle.py deleted file mode 100644 index 5ea821acf7..0000000000 --- a/indra/viewer_components/manager/tests/test_get_log_file_handle.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python - -""" -@file   test_get_log_file_handle.py -@author coyot -@date   2016-06-08 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * - -import os -import shutil -import tempfile -import update_manager -import with_setup_args - -def get_log_file_handle_setup(): -    tmpdir1 = tempfile.mkdtemp(prefix = 'test1') -    tmpdir2 = tempfile.mkdtemp(prefix = 'test2') -    log_file_path = os.path.abspath(os.path.join(tmpdir1,"update_manager.log")) -    #not using tempfile because we want a particular filename -    open(log_file_path, 'w+').close - -    return [tmpdir1,tmpdir2,log_file_path], {} - -def get_log_file_handle_teardown(tmpdir1,tmpdir2,log_file_path): -    shutil.rmtree(tmpdir1, ignore_errors = True) -    shutil.rmtree(tmpdir2, ignore_errors = True) -     -@with_setup_args.with_setup_args(get_log_file_handle_setup, get_log_file_handle_teardown) -def test_existing_get_log_file_handle(tmpdir1,tmpdir2,log_file_path): -    handle = update_manager.get_log_file_handle(tmpdir1) -    if not handle: -        print "Failed to find existing log file" -        assert False -    elif not os.path.exists(os.path.abspath(log_file_path+".old")): -        print "Failed to rotate update manager log" -        assert False -    assert True -     -@with_setup_args.with_setup_args(get_log_file_handle_setup, get_log_file_handle_teardown) -def test_missing_get_log_file_handle(tmpdir1,tmpdir2,log_file_path): -    handle = update_manager.get_log_file_handle(tmpdir2) -    if not os.path.exists(log_file_path): -        print "Failed to touch new log file" -        assert False -    assert True diff --git a/indra/viewer_components/manager/tests/test_get_parent_path.py b/indra/viewer_components/manager/tests/test_get_parent_path.py deleted file mode 100644 index 6e4b9dfaff..0000000000 --- a/indra/viewer_components/manager/tests/test_get_parent_path.py +++ /dev/null @@ -1,83 +0,0 @@ -#!/usr/bin/env python - - -""" -@file   test_get_parent_path.py -@author coyot -@date   2016-06-02 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * -from nose import with_setup - -import os -import shutil -import update_manager -import with_setup_args - -def get_parent_path_setup(): -    key = update_manager.get_platform_key() -    try: -        if key == 'mac': -            settings_dir = os.path.join(os.path.expanduser('~'),'Library','Application Support','SecondLife') -        elif key == 'lnx': -            settings_dir = os.path.join(os.path.expanduser('~'),'.secondlife') -        elif key == 'win': -            settings_dir = os.path.join(os.path.expanduser('~'),'AppData','Roaming','SecondLife') -        else: -            raise Exception("Invalid Platform Key") - -        #preserve existing settings dir if any -        if os.path.exists(settings_dir): -            old_dir = settings_dir + ".tmp"  -            if os.path.exists(old_dir): -                shutil.rmtree(old_dir, ignore_errors = True) -            os.rename(settings_dir, old_dir) -        os.makedirs(settings_dir) -    except Exception, e: -        print "get_parent_path_setup failed due to: %s" % str(e) -        assert False - -    #this is we don't have to rediscover settings_dir for test and teardown -    return [settings_dir], {} -  -def get_parent_path_teardown(settings_dir): -    try: -        shutil.rmtree(settings_dir, ignore_errors = True) -        #restore previous settings dir if any -        old_dir = settings_dir + ".tmp" -        if os.path.exists(old_dir): -            os.rename(old_dir, settings_dir) -    except: -        #cleanup is best effort -        pass - -@with_setup_args.with_setup_args(get_parent_path_setup, get_parent_path_teardown) -def test_get_parent_path(settings_dir): -    key = update_manager.get_platform_key() -    got_settings_dir = update_manager.get_parent_path(key) -     -    assert settings_dir, "test_get_parent_path failed to obtain parent path" - -    assert_equal(settings_dir, got_settings_dir) diff --git a/indra/viewer_components/manager/tests/test_get_platform_key.py b/indra/viewer_components/manager/tests/test_get_platform_key.py deleted file mode 100644 index eeaca1dff7..0000000000 --- a/indra/viewer_components/manager/tests/test_get_platform_key.py +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env python - -""" -@file   test_get_platform_key.py -@author coyot -@date   2016-06-01 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import assert_equal - -import platform -import update_manager - -def test_get_platform_key(): -    key = update_manager.get_platform_key() -    if key == 'mac': -        assert_equal(platform.system(),'Darwin') -    elif key == 'lnx': -        assert_equal(platform.system(),'Linux') -    elif key == 'win': -        assert_equal(platform.system(),'Windows') -    else: -        assert_equal(key, None) diff --git a/indra/viewer_components/manager/tests/test_get_settings.py b/indra/viewer_components/manager/tests/test_get_settings.py deleted file mode 100644 index 7efcf62673..0000000000 --- a/indra/viewer_components/manager/tests/test_get_settings.py +++ /dev/null @@ -1,87 +0,0 @@ -#!/usr/bin/env python - - -""" -@file   test_get_settings.py -@author coyot -@date   2016-06-03 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * -from nose import with_setup - -import os -import shutil -import update_manager -import with_setup_args - -def get_settings_setup(): -    try: -        key = update_manager.get_platform_key() -        settings_dir = os.path.join(update_manager.get_parent_path(key), "user_settings") -        print settings_dir - -        #preserve existing settings dir if any -        if os.path.exists(settings_dir): -            old_dir = settings_dir + ".tmp" -            if os.path.exists(old_dir): -                shutil.rmtree(old_dir, ignore_errors = True) -            os.rename(settings_dir, old_dir)   -        os.makedirs(settings_dir) - -        #the data subdir of the tests dir that this script is in -        data_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "data") -        #the test settings file -        settings_file = os.path.join(data_dir, "settings.xml") -        shutil.copyfile(settings_file, os.path.join(settings_dir, "settings.xml")) - -    except Exception, e: -        print "get_settings_setup failed due to: %s" % str(e) -        assert False - -    #this is we don't have to rediscover settings_dir for test and teardown -    return [settings_dir], {} -  -def get_settings_teardown(settings_dir): -    try: -        shutil.rmtree(settings_dir, ignore_errors = True) -        #restore previous settings dir if any -        old_dir = settings_dir + ".tmp" -        if os.path.exists(old_dir): -            os.rename(old_dir, settings_dir) -    except: -        #cleanup is best effort -        pass - -@with_setup_args.with_setup_args(get_settings_setup, get_settings_teardown) -def test_get_settings(settings_dir): -    key = update_manager.get_platform_key() -    parent = update_manager.get_parent_path(key) -    log_file = update_manager.get_log_file_handle(parent) -    got_settings = update_manager.get_settings(log_file, parent) - -    assert got_settings, "test_get_settings failed to find a settings.xml file" - -    #test one key just to make sure it parsed -    assert_equal(got_settings['CurrentGrid']['Value'], 'util.agni.lindenlab.com') diff --git a/indra/viewer_components/manager/tests/test_make_VVM_UUID_hash.py b/indra/viewer_components/manager/tests/test_make_VVM_UUID_hash.py deleted file mode 100644 index 5939e5806a..0000000000 --- a/indra/viewer_components/manager/tests/test_make_VVM_UUID_hash.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - - -""" -@file   test_make_VVM_UUID_hash.py -@author coyot -@date   2016-06-03 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * - -import update_manager - -def test_make_VVM_UUID_hash(): -    #because the method returns different results on different hosts -    #it is not easy to unit test it reliably.   -    #About the best we can do is check for the exception from subprocess -    key = update_manager.get_platform_key() -    try: -        UUID_hash = update_manager.make_VVM_UUID_hash(key) -    except Exception, e: -        print "Test failed due to: %s" % str(e) -        assert False - -    #make_UUID_hash returned None -    assert UUID_hash, "make_UUID_hash failed to make a hash." diff --git a/indra/viewer_components/manager/tests/test_make_download_dir.py b/indra/viewer_components/manager/tests/test_make_download_dir.py deleted file mode 100644 index e3f9cb83fe..0000000000 --- a/indra/viewer_components/manager/tests/test_make_download_dir.py +++ /dev/null @@ -1,47 +0,0 @@ -#!/usr/bin/env python - -""" -@file   test_make_download_dir.py -@author coyot -@date   2016-06-03 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * - -import update_manager - -def test_make_download_dir(): -    key = update_manager.get_platform_key() -    path = update_manager.get_parent_path(key) -    version = '1.2.3.456789' -    try: -        download_dir = update_manager.make_download_dir(path, version) -    except OSError, e: -        print "make_download_dir failed to eat OSError %s" % str(e) -        assert False -    except Exception, e: -        print "make_download_dir raised an unexpected exception %s" % str(e) -        assert False - -    assert download_dir, "make_download_dir returned None for path %s and version %s" % (path, version) diff --git a/indra/viewer_components/manager/tests/test_query_vvm.py b/indra/viewer_components/manager/tests/test_query_vvm.py deleted file mode 100644 index 79c8ede480..0000000000 --- a/indra/viewer_components/manager/tests/test_query_vvm.py +++ /dev/null @@ -1,73 +0,0 @@ -#!/usr/bin/env python - - -""" -@file   test_query_vvm.py -@author coyot -@date   2016-06-08 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * - -import os -import re -import shutil -import tempfile -import update_manager -import with_setup_args - -def query_vvm_setup(): -    tmpdir1 = tempfile.mkdtemp(prefix = 'test1') -    handle = update_manager.get_log_file_handle(tmpdir1) - -    return [tmpdir1,handle], {} - -def query_vvm_teardown(tmpdir1, handle): -    shutil.rmtree(tmpdir1, ignore_errors = True) - -@with_setup_args.with_setup_args(query_vvm_setup, query_vvm_teardown) -def test_query_vvm(tmpdir1, handle): -    key = update_manager.get_platform_key() -    parent = update_manager.get_parent_path(key) -    settings = update_manager.get_settings(handle, parent) -    launcher_path = os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(__file__)))) -    summary = update_manager.get_summary(key, launcher_path) - -    #for unit testing purposes, just testing a value from results.  If no update, then None and it falls through -    #for formal QA see: -    #   https://docs.google.com/document/d/1WNjOPdKlq0j_7s7gdNe_3QlyGnQDa3bFNvtyVM6Hx8M/edit -    #   https://wiki.lindenlab.com/wiki/Login_Test#Test_Viewer_Updater -    #for test plans on all cases, as it requires setting up a fake VVM service - -    try: -        results = update_manager.query_vvm(handle, key, settings, summary) -    except Exception, e: -        print "query_vvm threw unexpected exception %s" % str(e) -        assert False - -    if results: -        pattern = re.compile('Second Life') -        assert pattern.search(results['channel']), "Bad results returned %s" % str(results) -         -    assert True diff --git a/indra/viewer_components/manager/tests/test_silent_write.py b/indra/viewer_components/manager/tests/test_silent_write.py deleted file mode 100644 index ad286787e2..0000000000 --- a/indra/viewer_components/manager/tests/test_silent_write.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python - - -""" -@file   test_silent_write.py -@author coyot -@date   2016-06-02 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * - -import tempfile -import update_manager - -def test_silent_write_to_file():  -    test_log = tempfile.TemporaryFile() -    try: -        update_manager.silent_write(test_log, "This is a test.") -    except Exception, e: -        print "Test failed due to: %s" % str(e) -        assert False - -def test_silent_write_to_null():  -    try: -        update_manager.silent_write(None, "This is a test.") -    except Exception, e: -        print "Test failed due to: %s" % str(e) -        assert False diff --git a/indra/viewer_components/manager/tests/test_summary.py b/indra/viewer_components/manager/tests/test_summary.py deleted file mode 100644 index f2f2af7347..0000000000 --- a/indra/viewer_components/manager/tests/test_summary.py +++ /dev/null @@ -1,45 +0,0 @@ -#!/usr/bin/env python - - -""" -@file   test_summary.py -@author coyot -@date   2016-06-02 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -from nose.tools import * - -import os.path -import tempfile -import update_manager - -def test_get_summary(): -    key = update_manager.get_platform_key() -    #launcher is one dir above tests -    launcher_path = os.path.dirname(os.path.dirname(os.path.abspath(os.path.realpath(__file__)))) -    summary_json = update_manager.get_summary(key, launcher_path) - -    #we aren't testing the JSON library, one key pair is enough -    #so we will use the one pair that is actually a constant -    assert_equal(summary_json['Type'],'viewer') diff --git a/indra/viewer_components/manager/tests/with_setup_args.py b/indra/viewer_components/manager/tests/with_setup_args.py deleted file mode 100644 index 94d33aa5fe..0000000000 --- a/indra/viewer_components/manager/tests/with_setup_args.py +++ /dev/null @@ -1,68 +0,0 @@ -#!/usr/bin/env python - -""" -@file   with_setup_args.py -@author garyvdm -@date   2016-06-02 - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -def with_setup_args(setup, teardown=None): -    """Decorator to add setup and/or teardown methods to a test function:: -      @with_setup_args(setup, teardown) -      def test_something(): -          " ... " -    The setup function should return (args, kwargs) which will be passed to -    test function, and teardown function. -    Note that `with_setup_args` is useful *only* for test functions, not for test -    methods or inside of TestCase subclasses. -    """ -    def decorate(func): -        args = [] -        kwargs = {} - -        def test_wrapped(): -            func(*args, **kwargs) - -        test_wrapped.__name__ = func.__name__ - -        def setup_wrapped(): -            a, k = setup() -            args.extend(a) -            kwargs.update(k) -            if hasattr(func, 'setup'): -                func.setup() -        test_wrapped.setup = setup_wrapped - -        if teardown: -            def teardown_wrapped(): -                if hasattr(func, 'teardown'): -                    func.teardown() -                teardown(*args, **kwargs) - -            test_wrapped.teardown = teardown_wrapped -        else: -            if hasattr(func, 'teardown'): -                test_wrapped.teardown = func.teardown() -        return test_wrapped -    return decorate diff --git a/indra/viewer_components/manager/update_manager.py b/indra/viewer_components/manager/update_manager.py deleted file mode 100755 index 7962568119..0000000000 --- a/indra/viewer_components/manager/update_manager.py +++ /dev/null @@ -1,547 +0,0 @@ -#!/usr/bin/env python - -"""\ -@file update_manager.py -@author coyot -@date 2016-05-16 -@brief executes viewer update checking and manages downloading and applying of updates - -$LicenseInfo:firstyear=2016&license=viewerlgpl$ -Second Life Viewer Source Code -Copyright (C) 2016, Linden Research, Inc. - -This library is free software; you can redistribute it and/or -modify it under the terms of the GNU Lesser General Public -License as published by the Free Software Foundation; -version 2.1 of the License only. - -This library is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU -Lesser General Public License for more details. - -You should have received a copy of the GNU Lesser General Public -License along with this library; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA - -Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA -$/LicenseInfo$ -""" - -import os - -#NOTA BENE:  -#   For POSIX platforms, llbase will be imported from the same directory.   -#   For Windows, llbase will be compiled into the executable by pyinstaller -try: -    from llbase import llrest -    from llbase.llrest import RESTError -    from llbase import llsd     -except: -    #if Windows, this is expected, if not, we're dead -    if os.name == 'nt': -        pass - -from copy import deepcopy -from datetime import datetime -from urlparse import urljoin - -import apply_update -import download_update -import errno -import fnmatch -import hashlib -import InstallerUserMessage -import json -import platform -import re -import shutil -import subprocess -import sys -import tempfile -import thread -import urllib - -def silent_write(log_file_handle, text): -    #if we have a log file, write.  If not, do nothing. -    #this is so we don't have to keep trapping for an exception with a None handle -    #oh and because it is best effort, it is also a holey_write ;) -    if (log_file_handle): -        #prepend text for easy grepping -        timestamp = datetime.utcnow().strftime("%Y-%m-%D %H:%M:%S") -        log_file_handle.write(timestamp + " UPDATE MANAGER: " + text + "\n") - -def after_frame(message, timeout = 10000): -    #pop up a InstallerUserMessage.basic_message that kills itself after timeout milliseconds -    #note that this blocks the caller for the duration of timeout -    frame = InstallerUserMessage.InstallerUserMessage(title = "Second Life Installer", icon_name="head-sl-logo.gif") -    #this is done before basic_message so that we aren't blocked by mainloop() -    #frame.after(timeout, lambda: frame._delete_window) -    frame.after(timeout, lambda: frame.destroy()) -    frame.basic_message(message = message) - -def convert_version_file_style(version): -    #converts a version string a.b.c.d to a_b_c_d as used in downloaded filenames -    #re will throw a TypeError if it gets None, just return that. -    try: -        pattern = re.compile('\.') -        return pattern.sub('_', version) -    except TypeError, te: -        return None - -def get_platform_key(): -    #this is the name that is inserted into the VVM URI -    #and carried forward through the rest of the updater to determine -    #platform specific actions as appropriate -    platform_dict = {'Darwin':'mac', 'Linux':'lnx', 'Windows':'win'} -    platform_uname = platform.system() -    try: -        return platform_dict[platform_uname] -    except KeyError: -        return None - -def get_summary(platform_name, launcher_path): -    #get the contents of the summary.json file. -    #for linux and windows, this file is in the same directory as the script -    #for mac, the script is in ../Contents/MacOS/ and the file is in ../Contents/Resources/ -    script_dir = os.path.abspath(os.path.dirname(os.path.realpath(__file__))) -    if (platform_name == 'mac'): -        summary_dir = os.path.abspath(os.path.join(script_dir, "../Resources")) -    else: -        summary_dir = script_dir -    summary_file = os.path.join(summary_dir,"summary.json") -    with open(summary_file) as summary_handle: -        return json.load(summary_handle) - -def get_parent_path(platform_name): -    #find the parent of the logs and user_settings directories -    if (platform_name == 'mac'): -        settings_dir = os.path.join(os.path.expanduser('~'),'Library','Application Support','SecondLife') -    elif (platform_name == 'lnx'):  -        settings_dir = os.path.join(os.path.expanduser('~'),'.secondlife') -    #using list format of join is important here because the Windows pathsep in a string escapes the next char -    elif (platform_name == 'win'): -        settings_dir = os.path.join(os.path.expanduser('~'),'AppData','Roaming','SecondLife') -    else: -        settings_dir = None -    return settings_dir - -def make_download_dir(parent_dir, new_version): -    #make a canonical download dir if it does not already exist -    #format: ../user_settings/downloads/1.2.3.456789 -    #we do this so that multiple viewers on the same host can update separately -    #this also functions as a getter -    try: -        download_dir = os.path.join(parent_dir, "downloads", new_version) -        os.makedirs(download_dir) -    except OSError, hell: -        #Directory already exists, that's okay.  Other OSErrors are not okay. -        if hell[0] == errno.EEXIST:   -            pass -        else: -            raise hell -    return download_dir - -def check_for_completed_download(download_dir): -    #there will be two files on completion, the download and a marker file called "".done"" -    #for optional upgrades, there may also be a .skip file to skip this particular upgrade  -    #or .next to install on next run -    completed = None -    marker_regex = '*' + '.done' -    skip_regex = '*' + '.skip' -    next_regex = '*' + '.next' -    for filename in os.listdir(download_dir): -        if fnmatch.fnmatch(filename, marker_regex): -            completed = 'done' -        elif fnmatch.fnmatch(filename, skip_regex): -            completed = 'skip' -        elif fnmatch.fnmatch(filename, next_regex): -            #so we don't skip infinitely -            os.remove(filename) -            completed = 'next' -    if not completed: -        #cleanup -        shutil.rmtree(download_dir) -    return completed   - -def get_settings(log_file_handle, parent_dir): -    #return the settings file parsed into a dict -    try: -        settings_file = os.path.abspath(os.path.join(parent_dir,'user_settings','settings.xml')) -        #this happens when the path to settings file happens on the command line -        #we get a full path and don't need to munge it -        if not os.path.exists(settings_file): -            settings_file = parent_dir -        settings = llsd.parse((open(settings_file)).read()) -    except llsd.LLSDParseError as lpe: -        silent_write(log_file_handle, "Could not parse settings file %s" % lpe) -        return None -    return settings - -def get_log_file_handle(parent_dir, filename = None): -    #return a write handle on the log file -    #plus log rotation and not dying on failure -    if not filename: -        return None -    log_file = os.path.join(parent_dir, filename) -    old_file = log_file + '.old' -    #if someone's log files are present but not writable, they've screwed up their install. -    if os.access(log_file, os.W_OK): -        if os.access(old_file, os.W_OK): -            os.unlink(old_file) -        os.rename(log_file, old_file) -    elif not os.path.exists(log_file): -        #reimplement TOUCH(1) in Python -        #perms default to 644 which is fine -        open(log_file, 'w+').close() -    try: -        f = open(log_file,'w+') -    except Exception as e: -        #we don't have a log file to write to, make a best effort and sally onward -        print "Could not open update manager log file %s" % log_file -        f = None -    return f - -def make_VVM_UUID_hash(platform_key): -    #NOTE: There is no python library support for a persistent machine specific UUID -    #      AND all three platforms do this a different way, so exec'ing out is really the best we can do -    #Lastly, this is a best effort service.  If we fail, we should still carry on with the update  -    uuid = None -    if (platform_key == 'lnx'): -        uuid = subprocess.check_output(['/usr/bin/hostid']).rstrip() -    elif (platform_key == 'mac'): -        #this is absurdly baroque -        #/usr/sbin/system_profiler SPHardwareDataType | fgrep 'Serial' | awk '{print $NF}' -        uuid = subprocess.check_output(["/usr/sbin/system_profiler", "SPHardwareDataType"]) -        #findall[0] does the grep for the value we are looking for: "Serial Number (system): XXXXXXXX" -        #split(:)[1] gets us the XXXXXXX part -        #lstrip shaves off the leading space that was after the colon -        uuid = re.split(":", re.findall('Serial Number \(system\): \S*', uuid)[0])[1].lstrip() -    elif (platform_key == 'win'): -        # wmic csproduct get UUID | grep -v UUID -        uuid = subprocess.check_output(['wmic','csproduct','get','UUID']) -        #outputs in two rows: -        #UUID -        #XXXXXXX-XXXX... -        uuid = re.split('\n',uuid)[1].rstrip() -    if uuid is not None: -        return hashlib.md5(uuid).hexdigest() -    else: -        #fake it -        return hashlib.md5(str(uuid.uuid1())).hexdigest() - -def query_vvm(log_file_handle = None, platform_key = None, settings = None, summary_dict = None, UpdaterServiceURL = None, UpdaterWillingToTest = None): -    result_data = None -    baseURI = None -    #URI template /update/v1.1/channelname/version/platformkey/platformversion/willing-to-test/uniqueid -    #https://wiki.lindenlab.com/wiki/Viewer_Version_Manager_REST_API#Viewer_Update_Query -    #note that the only two valid options are: -    # # version-phx0.damballah.lindenlab.com -    # # version-qa.secondlife-staging.com -    print "updater service host: " + repr(UpdaterServiceURL) -    if UpdaterServiceURL: -        #we can't really expect the users to put the protocol or base dir on, they will give us a host -        base_URI = urljoin('https://' + UpdaterServiceURL[0], '/update/') -    else: -        base_URI = 'https://update.secondlife.com/update/' -    channelname = summary_dict['Channel'] -    #this is kind of a mess because the settings value is a) in a map and b) is both the cohort and the version in one string -    version = summary_dict['Version'] -    #we need to use the dotted versions of the platform versions in order to be compatible with VVM rules and arithmetic -    if platform_key == 'win': -        platform_version = platform.win32_ver()[1] -    elif platform_key == 'mac': -        platform_version = platform.mac_ver()[0] -    else: -        platform_version = platform.release() -    #this will always return something usable, error handling in method -    UUID = str(make_VVM_UUID_hash(platform_key)) -    #note that this will not normally be in a settings.xml file and is only here for test builds. -    #for test builds, add this key to the ../user_settings/settings.xml -    """ -        <key>test</key> -        <map> -        <key>Comment</key> -            <string>Tell update manager you aren't willing to test.</string> -        <key>Type</key> -            <string>String</string> -        <key>Value</key> -            <integer>testno</integer> -        </map> -    </map> -    """ -    if UpdaterWillingToTest is not None: -        if UpdaterWillingToTest: -            test_ok = 'testok' -        else: -            test_ok = 'testno' -    else:    -        try: -            test_ok = settings['test']['Value'] -        except KeyError: -            #normal case, no testing key -            test_ok = 'testok' -    #because urljoin can't be arsed to take multiple elements -    #channelname is a list because although it is only one string, it is a kind of argument and viewer args can take multiple keywords. -    query_string =  urllib.quote('v1.0/' + channelname[0] + '/' + version + '/' + platform_key + '/' + platform_version + '/' + test_ok + '/' + UUID) -    silent_write(log_file_handle, "About to query VVM: %s" % base_URI + query_string) -    VVMService = llrest.SimpleRESTService(name='VVM', baseurl=base_URI) -    try: -        result_data = VVMService.get(query_string) -    except RESTError as re: -        silent_write(log_file_handle, "Failed to query VVM using %s failed as %s" % (urljoin(base_URI,query_string), re)) -        return None -    return result_data - -def download(url = None, version = None, download_dir = None, size = 0, background = False, chunk_size = None, log_file_handle = None): -    download_tries = 0 -    download_success = False -    if not chunk_size: -        chunk_size = 1024 -    #for background execution -    path_to_downloader = os.path.join(os.path.dirname(os.path.realpath(__file__)), "download_update.py") -    #three strikes and you're out -    while download_tries < 3 and not download_success: -        #323: Check for a partial update of the required update; in either event, display an alert that a download is required, initiate the download, and then install and launch -        if download_tries == 0: -            after_frame(message = "Downloading new version " + version + " Please wait.", timeout = 5000) -        else: -            after_frame(message = "Trying again to download new version " + version + " Please wait.", timeout = 5000) -        if not background: -            try: -                download_update.download_update(url = url, download_dir = download_dir, size = size, progressbar = True, chunk_size = chunk_size) -                download_success = True -            except Exception, e: -                download_tries += 1     -                silent_write(log_file_handle, "Failed to download new version " + version + ". Trying again.") -                silent_write(log_file_handle, "Logging download exception: %s" % e.message) -        else: -            try: -                #Python does not have a facility to multithread a method, so we make the method a standalone -                #and subprocess that -                subprocess.call(path_to_downloader, "--url = %s --dir = %s --pb --size = %s --chunk_size = %s" % (url, download_dir, size, chunk_size)) -                download_success = True -            except: -                download_tries += 1 -                silent_write(log_file_handle, "Failed to download new version " + version + ". Trying again.") -    if not download_success: -        silent_write(log_file_handle, "Failed to download new version " + version) -        after_frame(message = "Failed to download new version " + version + " Please check connectivity.") -        return False -    return True - -def install(platform_key = None, download_dir = None, log_file_handle = None, in_place = None, downloaded = None): -    #user said no to this one -    if downloaded != 'skip': -        after_frame(message = "New version downloaded.  Installing now, please wait.") -        success = apply_update.apply_update(download_dir, platform_key, log_file_handle, in_place) -        version = download_dir.split('/')[-1] -        if success: -            silent_write(log_file_handle, "successfully updated to " + version) -            shutil.rmtree(download_dir) -            #this is either True for in place or the path to the new install for not in place -            return success -        else: -            after_frame(message = "Failed to apply " + version) -            silent_write(log_file_handle, "Failed to update viewer to " + version) -            return False -         -def download_and_install(downloaded = None, url = None, version = None, download_dir = None, size = None,  -                         platform_key = None, log_file_handle = None, in_place = None, chunk_size = 1024): -    #extracted to a method because we do it twice in update_manager() and this makes the logic clearer -    if not downloaded: -        #do the download, exit if we fail -        if not download(url = url, version = version, download_dir = download_dir, size = size, chunk_size = chunk_size, log_file_handle = log_file_handle):  -            return (False, 'download', version)   -    #do the install -    path_to_new_launcher = install(platform_key = platform_key, download_dir = download_dir,  -                                   log_file_handle = log_file_handle, in_place = in_place, downloaded = downloaded) -    if path_to_new_launcher: -        #if we succeed, propagate the success type upwards -        if in_place: -            return (True, 'in place', True) -        else: -            return (True, 'in place', path_to_new_launcher) -    else: -        #propagate failure -        return (False, 'apply', version)     -             -def update_manager(cli_overrides = None): -    #cli_overrides is a dict where the keys are specific parameters of interest and the values are the arguments to  -    #comments that begin with '323:' are steps taken from the algorithm in the description of SL-323.  -    #  Note that in the interest of efficiency, such as determining download success once at the top -    #  The code does follow precisely the same order as the algorithm. -    #return values rather than exit codes.  All of them are to communicate with launcher -    #we print just before we return so that __main__ outputs something - returns are swallowed -    #  (False, 'setup', None): error occurred before we knew what the update was (e.g., in setup or parsing) -    #  (False, 'download', version): we failed to download the new version -    #  (False, 'apply', version): we failed to apply the new version -    #  (True, None, None): No update found -    #  (True, 'in place, True): update applied in place -    #  (True, 'in place', path_to_new_launcher): Update applied by a new install to a new location -    #  (True, 'background', True): background download initiated - -    #setup and getting initial parameters -    platform_key = get_platform_key() -    parent_dir = get_parent_path(platform_key) -    log_file_handle = get_log_file_handle(parent_dir, 'update_manager.log') -    settings = None - -    #check to see if user has install rights -    #get the owner of the install and the current user -    script_owner_id = os.stat(os.path.realpath(__file__)).st_uid -    user_id = os.geteuid() -    #if we are on lnx or mac, we can pretty print the IDs as names using the pwd module -    #win does not provide this support and Python will throw an ImportError there, so just use raw IDs -    if script_owner_id != user_id: -        if platform_key != 'win': -            import pwd -            script_owner_name = pwd.getpwuid(script_owner_id)[0] -            username = pwd.getpwuid(user_id)[0] -        else: -            username = user_id -            script_owner_name = script_owner_id -        silent_write(log_file_handle, "Upgrade notification attempted by userid " + username)     -        frame = InstallerUserMessage(title = "Second Life Installer", icon_name="head-sl-logo.gif") -        frame.binary_choice_message(message = "Second Life was installed by userid " + script_owner_name  -            + ".  Do you have privileges to install?", true = "Yes", false = 'No') -        if not frame.choice.get(): -            silent_write(log_file_handle, "Upgrade attempt declined by userid " + username) -            after_frame(message = "Please find a system admin to upgrade Second Life") -            print "Update manager exited with (%s, %s, %s)" % (False, 'setup', None) -            return (False, 'setup', None) - -    if cli_overrides is not None:  -        if 'settings' in cli_overrides.keys(): -            if cli_overrides['settings'] is not None: -                settings = get_settings(log_file_handle, cli_overrides['settings'][0]) -        else: -            settings = get_settings(log_file_handle, parent_dir)    -         -    if settings is None: -        silent_write(log_file_handle, "Failed to load viewer settings") -        print "Update manager exited with (%s, %s, %s)" % (False, 'setup', None) -        return (False, 'setup', None) - -    #323: If a complete download of that update is found, check the update preference: -    #settings['UpdaterServiceSetting'] = 0 is manual install -    """ -    <key>UpdaterServiceSetting</key> -        <map> -        <key>Comment</key> -            <string>Configure updater service.</string> -        <key>Type</key> -            <string>U32</string> -        <key>Value</key> -            <string>0</string> -        </map> -    """ -    if cli_overrides is not None:  -        if 'set' in cli_overrides.keys(): -            if 'UpdaterServiceSetting' in cli_overrides['set'].keys(): -                install_automatically = cli_overrides['set']['UpdaterServiceSetting'] -    else: -        try: -            install_automatically = settings['UpdaterServiceSetting']['Value'] -        #because, for some godforsaken reason, we delete the setting rather than changing the value -        except KeyError: -            install_automatically = 1 -     -    #use default chunk size if none is given      -    if cli_overrides is not None:  -        if 'set' in cli_overrides.keys(): -            if 'UpdaterMaximumBandwidth' in cli_overrides['set'].keys():     -                chunk_size = cli_overrides['set']['UpdaterMaximumBandwidth'] -        else: -            chunk_size = 1024 -    else: -        chunk_size = 1024 - -    #get channel and version -    try: -        summary_dict = get_summary(platform_key, os.path.abspath(os.path.realpath(__file__))) -        #we send the override to the VVM, but retain the summary.json version for in_place computations -        channel_override_summary = deepcopy(summary_dict)         -        if cli_overrides is not None: -            if 'channel' in cli_overrides.keys(): -                channel_override_summary['Channel'] = cli_overrides['channel'] -    except Exception, e: -        silent_write(log_file_handle, "Could not obtain channel and version, exiting.") -        silent_write(log_file_handle, e.message) -        print "Update manager exited with (%s, %s, %s)" % (False, 'setup', None) -        return (False, 'setup', None)         - -    #323: On launch, the Viewer Manager should query the Viewer Version Manager update api. -    if cli_overrides is not None: -        if 'update-service' in cli_overrides.keys(): -            UpdaterServiceURL = cli_overrides['update-service'] -        else: -            #tells query_vvm to use the default -            UpdaterServiceURL = None -    else: -        UpdaterServiceURL = None -    result_data = query_vvm(log_file_handle, platform_key, settings, channel_override_summary, UpdaterServiceURL) -     -    #nothing to do or error -    if not result_data: -        silent_write(log_file_handle, "No update found.") -        print "Update manager exited with (%s, %s, %s)" % (True, None, None) -        return (True, None, None) - -    #get download directory, if there are perm issues or similar problems, give up -    try: -        download_dir = make_download_dir(parent_dir, result_data['version']) -    except Exception, e: -        print "Update manager exited with (%s, %s, %s)" % (False, 'setup', None) -        return (False, 'setup', None) -     -    #if the channel name of the response is the same as the channel we are launched from, the update is "in place" -    #and launcher will launch the viewer in this install location.  Otherwise, it will launch the Launcher from  -    #the new location and kill itself. -    in_place = (summary_dict['Channel'] == result_data['channel']) -    print "summary %s, result %s, in_place %s" % (summary_dict['Channel'], result_data['channel'], in_place) -     -    #determine if we've tried this download before -    downloaded = check_for_completed_download(download_dir) - -    #323: If the response indicates that there is a required update:  -    if result_data['required'] or (not result_data['required'] and install_automatically): -        #323: Check for a completed download of the required update; if found, display an alert, install the required update, and launch the newly installed viewer. -        #323: If [optional download and] Install Automatically: display an alert, install the update and launch updated viewer. -        return download_and_install(downloaded = downloaded, url = result_data['url'], version = result_data['version'], download_dir = download_dir,  -                                    size = result_data['size'], platform_key = platform_key, log_file_handle = log_file_handle, in_place = in_place, chunk_size = chunk_size) -    else: -        #323: If the update response indicates that there is an optional update:  -        #323: Check to see if the optional update has already been downloaded. -        #323: If a complete download of that update is found, check the update preference:  -        #note: automatic install handled above as the steps are the same as required upgrades -        #323: If Install Manually: display a message with the update information and ask the user whether or not to install the update with three choices: -        #323: Skip this update: create a marker that subsequent launches should not prompt for this update as long as it is optional,  -        #     but leave the download in place so that if it becomes required it will be there. -        #323: Install next time: create a marker that skips the prompt and installs on the next launch -        #323: Install and launch now: do it. -        if downloaded is not None and downloaded != 'skip': -            frame = InstallerUserMessage(title = "Second Life Installer", icon_name="head-sl-logo.gif") -            #The choices are reordered slightly to encourage immediate install and slightly discourage skipping -            frame.trinary_message(message = "Please make a selection",  -                one = "Install new version now.", two = 'Install the next time the viewer is launched.', three = 'Skip this update.') -            choice = frame.choice.get() -            if choice == 1: -                return download_and_install(downloaded = downloaded, url = result_data['url'], version = result_data['version'], download_dir = download_dir,  -                                    size = result_data['size'], platform_key = platform_key, log_file_handle = log_file_handle, in_place = in_place, chunk_size = chunk_size) -            elif choice == 2: -                tempfile.mkstmp(suffix = ".next", dir = download_dir) -                return (True, None, None) -            else: -                tempfile.mkstmp(suffix = ".skip", dir = download_dir) -                return (True, None, None) -        else: -            #multithread a download -            download(url = result_data['url'], version = result_data['version'], download_dir = download_dir, size = result_data['size'], background = True, log_file_handle = log_file_handle) -            print "Update manager exited with (%s, %s, %s)" % (True, 'background', True) -            return (True, 'background', True)                   - - -if __name__ == '__main__': -    #there is no argument parsing or other main() work to be done -    update_manager()  | 
