def __init__(self): self.new_manifest = None self.manifest = None self.args = "" self.onInstall = None self.runningAction = False self.detector = Detector() self.os = self.detector.getOperatingSystem() if self.isDevMode(): directory = "install-debug" if not os.path.exists(directory): os.mkdir(directory) os.chdir(directory) # Setup feedback mechanism global feedback if options.interface == FeedbackMechanisms.CMD: g.feedback = ConsoleFeedback() elif options.interface == FeedbackMechanisms.UI: self.ui = True g.feedback = QTUIFeedback(self) else: # Not specified, need something to stop errors, so us this g.feedback = FeedbackBase() # Setup min log level if hasattr(options, "min_log_level"): g.feedback.minLogLevel = LogLevels.getLevelFromString(options.min_log_level) else: g.feedback.minLogLevel = LogLevels.getLevelFromString(LogLevels.INFO) # Create PID file self.createPidFile() self.logSystemInfo() g.os = self.os self.arch = self.detector.getArchitecture(self.os) self.osver = self.detector.getOperatingSystemVersion(self.os) g.feedback.log( LogLevels.INFO, "Started up. OS: %s; Architecture: %s; Version: %s" % (OperatingSystem().getOperatingSystem(self.os), Architecture().getArchitecture(self.arch), self.osver), )
class Jinn(FileSystemHelper): # Header for messages header = """ .---. | | '---'.--. _..._ _..._ .---.|__| .' '. .' '. | |.--.. .-. .. .-. . | || || ' ' || ' ' | | || || | | || | | | | || || | | || | | | | || || | | || | | | | ||__|| | | || | | | __.' ' | | | || | | | | ' | | | || | | | |____.' '--' '--''--' '--' A multi-platform installer""" def __init__(self): self.new_manifest = None self.manifest = None self.args = "" self.onInstall = None self.runningAction = False self.detector = Detector() self.os = self.detector.getOperatingSystem() if self.isDevMode(): directory = "install-debug" if not os.path.exists(directory): os.mkdir(directory) os.chdir(directory) # Setup feedback mechanism global feedback if options.interface == FeedbackMechanisms.CMD: g.feedback = ConsoleFeedback() elif options.interface == FeedbackMechanisms.UI: self.ui = True g.feedback = QTUIFeedback(self) else: # Not specified, need something to stop errors, so us this g.feedback = FeedbackBase() # Setup min log level if hasattr(options, "min_log_level"): g.feedback.minLogLevel = LogLevels.getLevelFromString(options.min_log_level) else: g.feedback.minLogLevel = LogLevels.getLevelFromString(LogLevels.INFO) # Create PID file self.createPidFile() self.logSystemInfo() g.os = self.os self.arch = self.detector.getArchitecture(self.os) self.osver = self.detector.getOperatingSystemVersion(self.os) g.feedback.log( LogLevels.INFO, "Started up. OS: %s; Architecture: %s; Version: %s" % (OperatingSystem().getOperatingSystem(self.os), Architecture().getArchitecture(self.arch), self.osver), ) def logSystemInfo(self): # str() casting necessary here as sometimes returns None g.feedback.log(LogLevels.INFO, "Herein follows the system information") g.feedback.log(LogLevels.INFO, "sys.version\t\t\t\t%s" % str(sys.version.split("\n"))) g.feedback.log(LogLevels.INFO, "platform.dist\t\t\t\t%s" % str(platform.dist())) g.feedback.log(LogLevels.INFO, "platform.system\t\t\t\t%s" % str(platform.system())) g.feedback.log(LogLevels.INFO, "platform.machine\t\t\t%s" % str(platform.machine())) g.feedback.log(LogLevels.INFO, "platform.processor\t\t\t%s" % str(platform.processor())) g.feedback.log(LogLevels.INFO, "platform.platform\t\t\t%s" % str(platform.platform())) g.feedback.log(LogLevels.INFO, "platform.platform\t\t\t%s" % str(platform.release())) g.feedback.log(LogLevels.INFO, "platform.uname\t\t\t\t%s" % str(platform.uname())) g.feedback.log(LogLevels.INFO, "platform.version\t\t\t%s" % str(platform.version())) g.feedback.log(LogLevels.INFO, "platform.win32_ver\t\t\t%s" % str(platform.win32_ver())) g.feedback.log(LogLevels.INFO, "platform.mac_ver\t\t\t%s" % str(platform.mac_ver())) try: g.feedback.log(LogLevels.INFO, "platform.linux_distribution\t\t%s" % str(platform.linux_distribution())) except: g.feedback.log(LogLevels.INFO, "platform.linux_distribution\t\tnot available") g.feedback.log(LogLevels.INFO, "locale.getdefaultlocale\t\t\t%s" % str(locale.getdefaultlocale())) g.feedback.log(LogLevels.INFO, "os.name\t\t\t\t\t%s" % str(os.name)) g.feedback.log(LogLevels.INFO, "sys.argv\t\t\t\t%s" % str(sys.argv)) g.feedback.log(LogLevels.INFO, "System information complete") """ Called when the Jinn is finished Whether that is running, installing, updating, etc. This has to be the last thing before the program quits """ def done(self): self.deletePidFile() if self.os is OperatingSystem.OSX: # Run the launch service command cmd = [ "/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/Support/lsregister", "-f", ".." + os.sep + "..", ] g.feedback.log(LogLevels.DEBUG, "Updating launch services: %s" % cmd) StartSubprocess(cmd) return True def run(self): g.feedback.finished(self.do()) """ Loads the manifest file """ def loadManifest(self): installed = self.isInstalled() g.feedback.log(LogLevels.INFO, "Loading new manifest from %s" % options.manifest) self.new_manifest = Manifest(self.os, self.arch, self.osver, installed, options.manifest) if installed: self.manifest = Manifest(self.os, self.arch, self.osver, True, None) else: g.feedback.log(LogLevels.INFO, "Loading manifest from new manifest, as not installed") self.manifest = self.new_manifest """ A helper which sets up the system before a run """ def setupSystem(self): g.feedback.log(LogLevels.INFO, "Setting up the system") self.loadManifest() # If there is an old .tmp binary, delete it self.delete(self.getInstallTargetFile() + ".tmp") if platform.system() == "Darwin": self.delete(self.getInstallTargetFile() + "tmp.pkg") """ Create a PID file """ def createPidFile(self): if not self.makeDirectory(self.pidsDir()): raise "Cannot create pids directory" # this also tidies up dead pid files self.countRunningInstances() print "Creating pid file" self.saveToFile(self.getPidFile(), "RUNNING") """ Delete this program's PID file """ def deletePidFile(self): if os.path.exists(self.getPidFile()): print "Deleting pid file" if self.exists(self.getPidFile()): self.delete(self.getPidFile()) else: print "Pid file already gone" def getPidFile(self, pid=os.getpid()): f = os.sep.join([self.pidsDir(), str(pid)]) print "PID file: %s" % os.path.abspath(f) return f def countRunningInstances(self): # if theres not pids directory then there will be no running instances if not os.path.exists(self.pidsDir()): return 0 # GetExitCodeProcess uses a special exit code to indicate that the process is # still running. _STILL_ACTIVE = 259 def is_pid_running(pid): try: return ( _is_pid_running_on_windows(pid) if platform.system() == "Windows" else _is_pid_running_on_unix(pid) ) except Exception as e: print "Can't work out if a pid is running, presuming yes: %s" % e return False def _is_pid_running_on_unix(pid): try: os.kill(pid, 0) except OSError: return False return True def _is_pid_running_on_windows(pid): import ctypes.wintypes kernel32 = ctypes.windll.kernel32 handle = kernel32.OpenProcess(1, 0, pid) if handle == 0: return False # If the process exited recently, a pid may still exist for the handle. # So, check if we can get the exit code. exit_code = ctypes.wintypes.DWORD() is_running = kernel32.GetExitCodeProcess(handle, ctypes.byref(exit_code)) == 0 kernel32.CloseHandle(handle) # See if we couldn't get the exit code or the exit code indicates that the # process is still running. return is_running or exit_code.value == _STILL_ACTIVE i = 0 for pid in os.listdir(self.pidsDir()): try: pid = int(pid) except: pass g.feedback.log(LogLevels.DEBUG, "Checking PID %s" % pid) if is_pid_running(pid): i = i + 1 else: f = self.getPidFile(pid) print "PID dead, removing %s" % f os.remove(f) return i def pidsDir(self): return "pids" """ Runs action in UI mode """ def runActionThread(self, action): ret = 1 try: ret = self._runAction(action) except Exception as e: traceback.print_exc() g.feedback.userMessage("ERROR", "Unexpected error: %s" % e) finally: self.finished(ret) """ Runs a specific action within the jinn """ def runAction(self, action=None): self.runningAction = True if not self.isInstalled(): g.feedback.log(LogLevels.INFO, "We aren't installed, so installing") def onInstall(): cmd = copy.copy(sys.argv) g.feedback.log(LogLevels.DEBUG, "Run command: %s" % cmd) self.done() StartProcess(cmd) self.onInstall = lambda: onInstall() self.doInstall() return if self.ui: return g.feedback.startUI("RUN", "Running") else: return self._runAction(action) def _runAction(self, action=None): self.checkAndDoUpdate() g.feedback.log(LogLevels.INFO, "Running %s action" % action) g.feedback.log(LogLevels.DEBUG, "Run action %s" % action) # this will close the wizard UI g.feedback.hide(4) if platform.system() == "Darwin" and self.ui: # we need to still listen for url open events while we're running this action import argv_emulation def spawn(x): print "Got event %s" % x if self.manifest.runDefaultAction(x) != 0: g.feedback.onUnexpectedExit() def onEvent(x): thread = Thread(target=spawn, args=[x]) thread.start() def run(): print "Hiding dock icon" setOSXProcessType(4) # lsuielement print "Waiting for argv timeout" # wait the default amount of time that the argv timeout is time.sleep(10) print "Listening for events......" argv_emulation.listen(onEvent) thread = Thread(target=run) thread.setDaemon(True) thread.start() try: if action is None: res = self.manifest.runDefaultAction(self.args) else: res = self.manifest.runAction(action, self.args) if res != 0: g.feedback.log(LogLevels.INFO, "Running action %s successfully completed" % action) return 1 return 0 except Exception as e: g.feedback.log(LogLevels.ERROR, "Running action %s threw exception %s" % (action, e)) return 1 """ Are we in dev mode? """ def isDevMode(self): isDev = options.version is "DEV" return isDev """ Checks whether an update is available. If so and eligible, starts the update """ def checkAndDoUpdate(self): g.feedback.log(LogLevels.DEBUG, "Starting update procedure") g.feedback.userMessage("MSG", "Checking for updates") # Check the PID files if self.countRunningInstances() != 1: g.feedback.log(LogLevels.DEBUG, "Won't update because multiple instances") return True # at this point if there is a critical message set for this OS we need to display it to the user criticalMessage = self.manifest.criticalMessage if criticalMessage != None: g.feedback.userMessage("INFO", "Please read carefully: %s" % criticalMessage) self.finished(0) return False return self.doUpdate() """ Checks the manifests for updates """ def doUpdate(self): # Check platforms if not self.new_manifest.platformSupported(): g.feedback.userMessage("ERROR", "Your platform is not supported by this update.%s" % self.getOutputExtras()) return False # Check to see if there is a change in the binary, but not in dev mode if ( self.new_manifest.hasNewBinary(self.manifest.jinn.getBinary(self.os, self.arch, self.osver)) and not self.isDevMode() ): return self.doBinaryUpdate() g.feedback.log(LogLevels.DEBUG, "Setting installation status across manifests") g.feedback.userMessage("MSG", "Setting installation status across manifests") g.feedback.log(LogLevels.INFO, "Installing new resources") g.feedback.userMessage("MSG", "Installing new resources") # First, install resources that are new if not self.new_manifest.installNewResources(self.manifest.resources): g.feedback.log(LogLevels.ERROR, "Failed to install new resources") return False g.feedback.log(LogLevels.INFO, "Uninstalling removed resources") g.feedback.userMessage("MSG", "Uninstalling removed resources") # Second, uninstall resources that are gone if not self.new_manifest.uninstallRemovedResources(self.manifest.resources): g.feedback.log(LogLevels.ERROR, "Removing resources failed") return False g.feedback.log(LogLevels.INFO, "Updating changed resources") g.feedback.userMessage("MSG", "Updating changed resources") # Third, update resources that are new version if not self.new_manifest.updateResources(self.manifest.resources): g.feedback.log(LogLevels.ERROR, "Updating changed resources failed") return False g.feedback.log(LogLevels.DEBUG, "Saving manifest") g.feedback.userMessage("MSG", "Saving manifest") # Finally, transition the manifest over to the new one self.manifest = self.new_manifest if not self.manifest.save(): g.feedback.log(LogLevels.ERROR, "Unable to save updated manifest") return False # Done! g.feedback.log(LogLevels.DEBUG, "Update complete") return True """ Does a binary update of jinn binary """ def doBinaryUpdate(self): g.feedback.userMessage("MSG", "A binary update is available. Downloading...") fileUrl = self.new_manifest.jinn.getBinary(self.os, self.arch, self.osver) g.feedback.log(LogLevels.DEBUG, "Downloading file from %s" % fileUrl) downloader = UrlDownloader(fileUrl) downloadTarget = self.getInstallTargetFile() + ".tmp" if self.os == OperatingSystem().OSX: downloadTarget = self.getInstallTargetFile() + ".pkg.tmp" filename = downloader.download(downloadTarget) if self.os is OperatingSystem().OSX: filename = self.getInstallTargetFile() g.feedback.log(LogLevels.DEBUG, "File downloaded to %s" % filename) if platform.system() == "Darwin": # if on os x we also need the pkg file downloader = UrlDownloader(fileUrl + ".pkg") filename = downloader.download(self.getInstallTargetFile() + ".tmp.pkg") g.feedback.log(LogLevels.DEBUG, "File downloaded to %s" % filename) if self.os is not OperatingSystem().OSX: if not self.makeExecutable(filename): g.feedback.log(LogLevels.ERROR, "Unable to make filename %s executable" % filename) args = copy.copy(sys.argv) args.pop(0) new_args = [filename, "-binaryupdate", self.getCurrentFile()] if args is not None and len(args) > 0: new_args.extend(args) g.feedback.log(LogLevels.DEBUG, "Sys args: %s" % sys.argv) g.feedback.log(LogLevels.DEBUG, "New args: %s" % new_args) if not self.new_manifest.save(): g.feedback.log(LogLevels.ERROR, "Unable to save new manifest file") self.done() self.finished(1) return g.feedback.userMessage("MSG", "Binary update complete.") if type(g.feedback) == QTUIFeedback: self.finished(-2) # tell the UI to completely quit self.done() StartProcess(new_args) sys.exit() """ Does a binary replace,calls the new binary, then exits """ def doBinaryReplace(self): # wait for the old process to exit time.sleep(1) filename = copy.copy(sys.argv[2]) oldFile = filename newFile = self.getCurrentFile() if self.os == OperatingSystem().OSX: newFile = newFile + ".tmp" filename = filename.replace(".pkg", "") if not self.delete(oldFile): g.feedback.log(LogLevels.ERROR, "Unable to delete old file, %s" % filename) self.done() self.finished(1) return if not self.copyFile(newFile, oldFile): g.feedback.log(LogLevels.ERROR, "Unable to copy to %s" % filename) self.done() self.finished(1) return if platform.system() == "Darwin": if not self.copyFile(self.getCurrentFile() + ".pkg", filename + ".pkg"): g.feedback.log(LogLevels.ERROR, "Unable to copy to %s" % filename) self.done() self.finished(1) return args = copy.copy(sys.argv) args.pop(0) args.pop(0) args.pop(0) new_args = [filename] if args is not None and len(args) > 0: new_args.extend(args) g.feedback.log(LogLevels.DEBUG, "Sys args: %s" % sys.argv) g.feedback.log(LogLevels.DEBUG, "New args: %s" % new_args) self.done() time.sleep(1) StartProcess(new_args) time.sleep(1) sys.exit() """ Copy this executable to the target directory, then run it """ def doCopy(self, debug=False): g.feedback.log(LogLevels.DEBUG, "We are not in the correct directory, so installing to the correct location") g.feedback.userMessage("MSG", "Copying install files") if self.os is OperatingSystem.OSX: g.feedback.log(LogLevels.DEBUG, "Copying in OS X mode") targetDir = self.getInstallTargetDirectory() copyTargetDir = targetDir.rsplit("/", 2)[0] currentDir = self.getCurrentDirectory() + os.sep + ".." + os.sep + ".." executable = targetDir + os.sep + self.getExecutableName() g.feedback.log(LogLevels.DEBUG, "Target executable: %s" % executable) if not self.exists(executable): g.feedback.log(LogLevels.DEBUG, "Target executable does not exist, copying") if not self.delete(copyTargetDir): return 1 if not self.makeDirectory(copyTargetDir): return 1 if not self.copyDir(currentDir, copyTargetDir): return 1 else: g.feedback.log(LogLevels.DEBUG, "Target executable exists, so running it") cmd = copy.copy(sys.argv) cmd[0] = "--args" # make quiet if not already if len(cmd) > 1 and cmd[1] != "-quiet": cmd.insert(1, "-quiet") cmd.insert(0, self.getInstallTargetDirectory() + os.sep + ".." + os.sep + "..") cmd.insert(0, "open") g.feedback.log(LogLevels.DEBUG, "Executing command: %s" % cmd) if type(g.feedback) == QTUIFeedback: self.finished(-1) # tell the UI to disappear silently res = StartSubprocessWithDir(cmd, targetDir) if res < 1: g.feedback.log(LogLevels.DEBUG, "Executed command successfully") return 0 else: g.feedback.log(LogLevels.ERROR, "Executing command %s failed with code %s" % (cmd, res)) return 1 else: g.feedback.log(LogLevels.DEBUG, "Copying in Windows / Linux mode") targetFile = self.getInstallTargetFile(debug) g.feedback.log(LogLevels.DEBUG, "Target file is %s" % targetFile) d = self.getInstallTargetDirectory(debug) g.feedback.log(LogLevels.DEBUG, "Target directory is %s" % d) if not self.exists(targetFile): # Make the jinn install directory if not self.makeDirectory(d): g.feedback.log(LogLevels.ERROR, "Unable to make directory %s to install to" % d) return 1 # Copy this binary into it frm = self.getCurrentFile() to = targetFile g.feedback.log(LogLevels.DEBUG, "Copying from %s to %s" % (frm, to)) if not self.copyFile(frm, to): g.feedback.log(LogLevels.ERROR, "Unable to copy %s to %s" % (frm, to)) return 1 if not self.makeExecutable(targetFile): g.feedback.log(LogLevels.ERROR, "Unable to make %s executable" % targetFile) return 1 # Run the new executable g.feedback.log(LogLevels.DEBUG, "Code copied to %s, executing" % targetFile) cmd = copy.copy(sys.argv) cmd[0] = self.getInstallTargetDirectory() + os.sep + self.getExecutableName() # make quiet if not already if len(cmd) > 1 and cmd[1] == "-quiet": pass else: cmd.insert(1, "-quiet") g.feedback.log(LogLevels.DEBUG, "Run command: %s" % cmd) if type(g.feedback) == QTUIFeedback: self.finished(-1) # tell the UI to disappear silently print "FORK in %s: %s" % (d, cmd) if debug: return 0 # can't check for success StartProcess(cmd) return 0 def doMove(self, debug=False): if self.isDevMode() and not debug: return True ret = self.doCopy(debug) if ret != 0: return ret return self._doUninstall() """ Runs installtion in UI mode """ def doInstallThread(self): ret = 1 try: ret = self._doInstall() if self.runningAction: self.finished(-1) except Exception as e: traceback.print_exc() g.feedback.userMessage("ERROR", "Unexpected error: %s" % e) finally: self.finished(ret) """ Runs an installation of this jinn """ def doInstall(self): if self.ui: return g.feedback.startUI("INSTALL", "Beginning installation") else: return self._doInstall() def _doInstall(self): if self.countRunningInstances() > 1: g.feedback.userMessage("ERROR", "Installer already running") return 1 g.feedback.log(LogLevels.INFO, "Beginning installation") g.feedback.userMessage("MSG", "Beginning installation") # We need the manifest first of all self.loadManifest() # Check we are a supported platform if not self.manifest.platformSupported(): g.feedback.userMessage( "ERROR", "Your platform is not supported by this application.%s" % self.getOutputExtras() ) return 1 # Hard code here to not happen for dev correctDir = self.isCorrectDirectory() g.feedback.log(LogLevels.DEBUG, "Are we in correct directory? %s" % correctDir) if not correctDir and not self.isDevMode(): ret = self.doCopy() if ret != 0: g.feedback.log(LogLevels.ERROR, "Failed to copy") g.feedback.userMessage( "ERROR", "Installation failed - failed to copy resources.%s" % self.getOutputExtras() ) return ret # Make sure we are in the right directory installDir = self.getInstallTargetDirectory() g.feedback.log(LogLevels.DEBUG, "Target install dir is %s" % installDir) if not self.changeDirectory(installDir) and not self.isDevMode(): g.feedback.log(LogLevels.ERROR, "Unable to change to where we thought we were installed, %s" % installDir) return 1 if self.isInstalled(): g.feedback.log(LogLevels.ERROR, "This jinn is already installed") g.feedback.userMessage( "ERROR", "Installation failed with error code (3) - already installed!%s" % self.getOutputExtras() ) return 1 g.feedback.log(LogLevels.DEBUG, "Installing") g.feedback.userMessage("MSG", "Installing. Please wait...") if not self.makeDirectory(".jinn"): g.feedback.log(LogLevels.ERROR, "Unable to make .jinn directory") return 1 try: if self.manifest.installResources(): g.feedback.log(LogLevels.DEBUG, "Install resources succeeded") if not self.manifest.save(): g.feedback.log(LogLevels.ERROR, "Unable to save the manifest") return 1 if self.onInstall != None: self.onInstall() return 0 else: g.feedback.log(LogLevels.ERROR, "Install resources failed") return 1 except Exception as e: traceback.print_exc() g.feedback.log(LogLevels.ERROR, "Unable to install resources: %s" % e) g.feedback.userMessage("ERROR", "Unable to install resources: %s" % e) return 1 """ Runs uninstalltion in UI mode """ def doUninstallThread(self): ret = 1 try: ret = self._doUninstall() except Exception as e: traceback.print_exc() g.feedback.userMessage("ERROR", "Unexpected error: %s" % e) finally: self.finished(ret) def finished(self, ret): g.feedback.log(LogLevels.DEBUG, "Exiting UI Thread with status: %s" % ret) g.feedback.finished(ret) """ Runs uninstallation """ def doUninstall(self): if self.ui: return g.feedback.startUI("UNINSTALL", "Beginning uninstallation") else: return self._doUninstall() def _doUninstall(self): g.feedback.log(LogLevels.INFO, "Doing uninstallation") if self.countRunningInstances() > 1: g.feedback.userMessage("ERROR", "Please shut all instances before trying to uninstall.") return 1 if not self.isInstalled(): msg = "This is not installed, so cannot be uninstalled." g.feedback.log(LogLevels.ERROR, msg) g.feedback.userMessage("ERROR", msg) return 1 g.feedback.log(LogLevels.DEBUG, "Uninstalling") self.loadManifest() try: if self.manifest.uninstallResources(): # remove cache directory self.delete(".cache") if self.delete(".jinn"): if (self.os == OperatingSystem().LIN or self.os == OperatingSystem().OSX) and not self.isDevMode(): self.delete(self.getCurrentDirectory()) g.feedback.userMessage("MSG", "Uninstallation finished.") return 0 else: g.feedback.log(LogLevels.ERROR, "Failed to delete .jinn directory, will think its still installed") return 1 else: g.feedback.log(LogLevels.ERROR, "Uninstallation failed") return 1 except Exception as e: g.feedback.log(LogLevels.ERROR, "Unable to uninstall: %s" % e) return 1 """ Returns the install target directory """ def getInstallTargetDirectory(self, debug=False): if self.isDevMode() and not debug: return self.getCurrentDirectory() elif self.os is OperatingSystem.OSX: return os.sep.join( [ self.getHomeDirectory(), "Library", "Application Support", self.manifest.jinn.name + ".app", "Contents", "Resources", ] ) elif self.os is OperatingSystem.LIN: return os.sep.join([self.getHomeDirectory(), ".%s" % self.manifest.jinn.name]) else: return os.sep.join([os.environ["APPDATA"], self.manifest.jinn.name]) """ Returns the install target directory """ def getLogFile(self): if self.os is OperatingSystem.OSX: return os.sep.join([self.getHomeDirectory(), "Library", "Application Support", "jinn", "jinn.log"]) elif self.os is OperatingSystem.LIN: return os.sep.join([self.getHomeDirectory(), ".jinn", "jinn.log"]) else: return os.sep.join([os.environ["APPDATA"], "jinn", "jinn.log"]) """ Get the name of the executable """ def getExecutableName(self): if self.os == OperatingSystem.WIN: return self.manifest.jinn.name + ".exe" elif self.os == OperatingSystem.LIN: return self.manifest.jinn.name + ".jinn" elif self.os == OperatingSystem.OSX: return "jinn" return None """ Get the file we wish to install to """ def getInstallTargetFile(self, debug=False): return os.sep.join([self.getInstallTargetDirectory(debug), self.getExecutableName()]) """ Check whether or not we are running from the right place """ def isCorrectDirectory(self, debug=False): currentdir = self.getCurrentDirectory() targetdir = self.getInstallTargetDirectory(debug) g.feedback.log(LogLevels.DEBUG, "Current directory: %s" % currentdir) g.feedback.log(LogLevels.DEBUG, "Target dir: %s" % targetdir) return targetdir == currentdir """ Take the sys args and turn them into a string stored on the object for later use. Offset is how many to skip off the front. Automatically skips the first one, the current script """ def processArgs(self, offset=0): args = copy.copy(sys.argv) # remove unwanteds i = 0 while i < offset: args.pop(0) i += 1 self.args = " ".join(map(str, args)) g.feedback.log(LogLevels.DEBUG, "System args: %s" % self.args) """ Check whether or not this jinn is currently installed """ def isInstalled(self): return self.directoryExists(".jinn") and self.exists(manifest.Manifest.getManifestFile()) """ Provide some useful output for help, version calls etc """ def getOutputExtras(self): extras = "" if self.isInstalled(): self.loadManifest() developer = self.manifest.jinn.getDeveloperMessage("You can contact the developer") version = self.manifest.jinn.version name = self.manifest.jinn.name extras = """ This Jinn is installed: %s version %s %s """ % ( name, version, developer, ) return extras """ Output the version information """ def doVersion(self): def cb(): g.feedback.userMessage( "INFO", """ %s Version: %s %s""" % (self.header, options.version, self.getOutputExtras()), ) g.feedback.finished(0) g.feedback.startUI("INFO", "Info", cb) return 0 """ List the actions available to the installed application """ def listActions(self): if not self.isInstalled(): def cbt(): g.feedback.userMessage("ERROR", "This jinn is not installed, so can't list actions") g.feedback.finished(0) g.feedback.startUI("INFO", "Info", cbt) return False self.loadManifest() actionListing = "Actions: " for action in self.manifest.actions: actionListing = ( actionListing + """ %s: %s: %s """ % (action.id, action.name, action.description) ) def cb(): g.feedback.userMessage( "INFO", """ %s Created by import.io %s %s """ % (self.header, actionListing, self.getOutputExtras()), ) g.feedback.finished(0) g.feedback.startUI("INFO", "Info", cb) return 0 """ Output the help content """ def doHelp(self): def cb(): g.feedback.userMessage( "INFO", """ %s Created by import.io Startup arguments: %s Options: ./jinn Run the jinn with the default action ./jinn -install Run the jinn installation ./jinn -uninstall Uninstall the jinn ./jinn -help Display this helpful help dialog ./jinn -action (actionname) Run the jinn action specified by (actionname) ./jinn -version Print the version string ./jinn -actions List all of the available actions and their descriptions %s """ % (self.header, sys.argv, self.getOutputExtras()), ) g.feedback.finished(0) g.feedback.startUI("INFO", "Info", cb) return 0 """ Runs the jinn feature we need to perform """ def do(self): self.setupSystem() debug = False installed = self.isInstalled() idx = 1 if (hasattr(options, "quiet") and options.quiet) or (len(sys.argv) > 1 and sys.argv[1] == "-quiet"): g.feedback.quiet() idx = 2 # We want to skip over the move if we are part way through a binary update if ( installed and not self.isCorrectDirectory(debug) and not (len(sys.argv) >= idx + 1 and sys.argv[idx] == "-binaryupdate") ): ret = self.doMove(debug) if ret != 0: g.feedback.log(LogLevels.ERROR, "Failed to move executable to correct location") g.feedback.userMessage( "ERROR", "Installation failed - failed to move to new location.%s" % self.getOutputExtras() ) return ret # Analyse the sys args to figure out what to do if len(sys.argv) < idx + 1: # No extra args, if we are installed we want to run the default action. # Otherwise this is the first run from download, so do install if self.isInstalled(): return self.runAction() else: return self.doInstall() elif sys.argv[idx] == "-binaryupdate": return self.doBinaryReplace() elif sys.argv[idx] == "-install": idx = idx + 1 if len(sys.argv) > idx and sys.argv[idx] == "-quiet": g.feedback.quiet() return self.doInstall() elif sys.argv[idx] == "-uninstall": return self.doUninstall() elif sys.argv[idx] == "-help": return self.doHelp() elif sys.argv[idx] == "-version": return self.doVersion() elif sys.argv[idx] == "-actions": return self.listActions() elif sys.argv[idx] == "-action": idx = idx + 1 if not len(sys.argv) > idx: g.feedback.userMessage("ERROR", "For -action, you must specify an action - try -help") return 1 self.processArgs(idx + 1) return self.runAction(sys.argv[idx]) else: # There are some args, we don't recognise the first, so must want to run default action with some args self.processArgs(idx) return self.runAction()