def openCommand(option, files, path): sublime_path = get_current_sublime_install_path() if not exists(as_url(sublime_path)): show_alert('Invalid Sublime Text path: ' + sublime_path) choice = show_alert('Update Path to Sublime Text?', buttons=YES | NO) if choice == YES: if not set_sublime_install_path(): # user failed to set sublime install path. bail. show_alert( 'command failed because no valid path to Sublime Text given' ) return else: # no path to use, user doesnt want to set one now. bail. show_alert( 'command failed because no valid path to Sublime Text given') return _SUBLIMETEXTPATH = sublime_path args = [to_path(x) for x in files] cmd = [_SUBLIMETEXTPATH] + option + args env = create_clean_environment() Popen(cmd, shell=False, cwd=path, stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL, env=env)
def __call__(self): # check file under cursor current_file = self.pane.get_file_under_cursor() # simply checking the file extension if re.compile(r'\.lnk$').search(current_file): # ok, let's receive the real folder containing the target of that shortcut shellscript = os.path.dirname(__file__) + "\link_target.ps1 " command = "powershell -ExecutionPolicy Bypass -NoLogo -Noninteractive -noprofile" command += ' -file "' + shellscript + '"' command += ' -link "' + as_human_readable(current_file) + '"' #show_status_message("Command: " + command) # temporary target = as_url(os.popen(command).read().strip()) show_status_message("Target: " + target, 2) # what did we get? if False == exists(target): # target is not reachable... show_alert(target + " doesn't exist.") elif is_dir(target): # target is a folder, we go to it self.pane.set_path(target) else: # target is a file, we go to its directory self.pane.set_path(dirname(target)) else: # nope, wrong thing show_alert(current_file + " is not a shortcut.")
def get_current_tortoisesvnproc_install_path(): settings = load_json(_TORTOISEPROCCONFIGFILE, default={'path': _TORTOISEPROCPATHDEFAULT}) if settings['path'] and exists(as_url(settings['path'])): return settings['path'] else: return _TORTOISEPROCPATHDEFAULT
def get_current_sublime_install_path(): settings = load_json(_SUBLIMETEXTCONFIGFILE, default={'path': _SUBLIMETEXTPATHDEFAULT}) if settings['path'] and exists(as_url(settings['path'])): return settings['path'] else: return _SUBLIMETEXTPATHDEFAULT
def move(self, src_url, dst_url): # Rename on same server src_scheme, src_path = splitscheme(src_url) dst_scheme, dst_path = splitscheme(dst_url) if src_scheme == dst_scheme and commonprefix([src_path, dst_path]): # TODO avoid second connection with FtpWrapper(src_url) as src_ftp, \ FtpWrapper(dst_url) as dst_ftp: src_ftp.conn.rename(src_ftp.path, dst_ftp.path) return fs.copy(src_url, dst_url) if fs.exists(src_url): fs.delete(src_url)
def set_tortoisesvnproc_install_path(): new_tortoisesvnproc_filepath, ok = show_prompt( 'Enter full path to TortoiseSVNProc.exe program here', default=get_current_tortoisesvnproc_install_path(), selection_start=0, selection_end=None) if not ok: return False if not exists(as_url(new_tortoisesvnproc_filepath)): show_alert('Path to TortoiseSVNProc given is invalid') return False _TORTOISEPROCPATH = new_tortoisesvnproc_filepath save_json(_TORTOISEPROCCONFIGFILE, {'path': new_tortoisesvnproc_filepath}) return True
def set_sublime_install_path(): new_sublime_filepath, ok = show_prompt( 'Enter full path to Sublime Text program here', default=get_current_sublime_install_path(), selection_start=0, selection_end=None) if not ok: return False if not exists(as_url(new_sublime_filepath)): show_alert('Path to Sublime Text given is invalid') return False _SUBLIMETEXTPATH = new_sublime_filepath save_json(_SUBLIMETEXTCONFIGFILE, {'path': new_sublime_filepath}) return True
def openCommand(option, files, path): tortoisesvnproc_path = get_current_tortoisesvnproc_install_path() if not exists(as_url(tortoisesvnproc_path)): show_alert('Invalid TortoiseSVNProc.exe path: ' + tortoisesvnproc_path) choice = show_alert('Update Path to TortoiseSVNProc.exe?', buttons=YES | NO) if choice == YES: if not set_tortoisesvnproc_install_path(): # user failed to set sublime install path. bail. show_alert( 'command failed because no valid path to TortoiseSVNProc.exe given' ) return else: # no path to use, user doesnt want to set one now. bail. show_alert( 'command failed because no valid path to TortoiseSVNProc.exe given' ) return # _TORTOISEPROCPATH = as_human_readable('file://'+ tortoisesvnproc_path) _TORTOISEPROCPATH = tortoisesvnproc_path # TODO: Check if quoting is working for other platforms args = [shlex.quote(to_path(x)) for x in files] cmd = _TORTOISEPROCPATH + " " + option + " ".join(args) env = create_clean_environment() Popen(cmd, shell=False, cwd=path, stdin=DEVNULL, stdout=DEVNULL, stderr=DEVNULL, env=env)
def __call__(self): # get as list of all chosen filenames that need to be attached chosenFiles = self.get_chosen_files() # create the string for the attachment attachment_string = '' for it in chosenFiles: # human readable file name ithr = as_human_readable(it) foldername = ithr.split('/')[-1] # check if folder, if so, create a zip file of the folder and add that one to the filename list! if is_dir(it): # create zipname zipname = 'zip://' + ithr + '.zip' # make sure the sip file does not exist yet if exists(zipname): choice = show_alert( 'The zip file already exists. Do you want to overwrite it?', buttons=YES | NO, default_button=NO) if choice == NO: return # create a zip file, pack the folder into the zip file copy(it, zipname + '/' + foldername) # inform fman that the zip file exists now notify_file_added(zipname) # now we want to add the zip file instead of the selected file, so change it before adding it to the string ithr = zipname.replace('zip://', '') # attach the file to the string of what to attach to the e-mail message attachment_string += ithr if it is not chosenFiles[-1]: attachment_string += ',' # set up the command to start a new e-mail message and attach it cmd = 'thunderbird -compose \"attachment=\'' + attachment_string + '\'\"' # print the command - untoggle for checking before sending # show_alert(cmd) # send the command os.system(cmd)
def __call__(self, url=None): sourceDirUrl = self.pane.get_path() archiveName = basename(sourceDirUrl) + '.7z' oppositePane = _get_opposite_pane(self.pane) oppositePaneUrl = oppositePane.get_path() archiveUrl = join(oppositePaneUrl, archiveName) sourceDir = as_human_readable(sourceDirUrl) archive = as_human_readable(archiveUrl) if exists(archiveUrl): if is_dir(archiveUrl): message = archiveName + " exists and is a directory, aborting!" show_alert(message) return choice = show_alert("Archive exists!\nReplace?", buttons=YES | CANCEL, default_button=CANCEL) if choice == YES: try: move_to_trash(archiveUrl) except NotImplementedError: show_alert("Failed to delete archive, aborting!") return elif choice == CANCEL: return submit_task(CreateArchive(archive, sourceDir)) oppositePane.reload() return
_CHECK_EXTENSION = True _COMPRESS_ARGS = ['a'] _HASH = 'sha256' settings = load_json('SevenZipTools.json', default={}) result = settings.get('7zip', {}) with open('R:/out.txt', 'w') as myfile: myfile.write(str(settings) + '\n') if result: try: exePath = result['path'] except (KeyError, TypeError): pass else: exePathUrl = as_url(exePath) if exists(exePathUrl) and not is_dir(exePathUrl): _USER_7ZIP = exePath _SUPPORTED_EXTENSIONS += ['.rar'] result = settings.get('additional extensions', []) if result and isinstance(result, list): _SUPPORTED_EXTENSIONS += result result = settings.get('ignore extension', None) if result: _CHECK_EXTENSION = False result = settings.get('compress args', []) if result and isinstance(result, list): _COMPRESS_ARGS += result
from fman import DirectoryPaneCommand, show_alert, show_prompt, load_json, save_json, YES, NO from fman.fs import is_dir, exists from fman.url import splitscheme, as_url, as_human_readable from subprocess import DEVNULL, Popen import os import shlex _TORTOISEPROCPATHDEFAULT = 'C:/Program Files/TortoiseSVN/bin/TortoiseProc.exe' _TORTOISEPROCCONFIGFILE = 'TortoiseSVNHelper Config.json' _TORTOISEPROCPATH = '' settings = load_json(_TORTOISEPROCCONFIGFILE, default={'path': _TORTOISEPROCPATHDEFAULT}) if settings['path'] and exists(as_url(settings['path'])): _TORTOISEPROCPATH = settings['path'] else: _TORTOISEPROCPATH = _TORTOISEPROCPATHDEFAULT class SVNSwtich(DirectoryPaneCommand): aliases = ('Svn: Switch', 'SVN: SWITCH') def __call__(self): url = self.pane.get_path() scheme, path = splitscheme(url) paths = [] paths.append(as_url(path))
def __call__(self, url=None): # This will get set if the automagically determined destination # directory exists, and will always be the default name when prompted # to manually choose a destination directory name. originalName = None if url is None: workingFile = self.pane.get_file_under_cursor() if workingFile: url = workingFile fileName = basename(url) if _CHECK_EXTENSION: try: extension = fileName[fileName.rindex('.'):] except ValueError: show_alert("Failed to determine extension, aborting!") return if not extension in _SUPPORTED_EXTENSIONS: show_alert("Unsupported extension, aborting!") return newDirName = fileName[0:fileName.rindex('.')] else: try: newDirName = fileName[0:fileName.rindex('.')] except ValueError: message = "Archive has no extension.\n" message += "Click 'YES' to enter a name " message += "for the destination directory.\n" message += "Click 'NO' to use the archive name.\n" message += "Click 'ABORT' to abort extraction." choice = show_alert(message, buttons=YES | NO | ABORT, default_button=ABORT) if choice == YES: newDirName, ok = show_prompt("Destination directory:", default=fileName) if not (newDirName and ok): return elif choice == NO: newDirName = fileName else: return oppositePane = _get_opposite_pane(self.pane) oppositePaneUrl = oppositePane.get_path() oppositePaneScheme, _ = splitscheme(resolve(oppositePaneUrl)) if oppositePaneScheme != 'file://': show_alert("Can't extract to %s, aborting!" % oppositeScheme) return newDirUrl = join(oppositePaneUrl, newDirName) while exists(newDirUrl): if not originalName: originalName = newDirName message = newDirName + " already exists!\nEnter a different name?" choice = show_alert(message, buttons=YES | ABORT, default_button=ABORT) if choice == YES: newDirName, ok = show_prompt("Destination directory:", default=newDirName) if not (newDirName and ok): continue else: newDirUrl = join(oppositePaneUrl, newDirName) try: mkdir(newDirUrl) except (FileNotFoundError, NotImplementedError): message = "Failed to create directory '" message += newDirName + "', aborting!" show_alert(message) return archive = as_human_readable(url) destDir = as_human_readable(newDirUrl) submit_task(ExtractArchive(archive, destDir)) return
def loadConfig(cls): """Check StatusBarExtended.json for consistency/completeness, restore defaults on fail""" msg_t = cls.msgTimeout if hasattr(cls, 'locked_update'): show_status_message( "StatusBarExtended: waiting for the config files to be updated, try again later..." ) return None, 'UpdateInProgress' cls.locked_update = True # ensure globally unique 'loadConfig' run so that e.g. we don't ask a user multiple times to delete corrupted configs cfgCurrent = load_json( 'StatusBarExtended.json' ) # within one fman session, it is guaranteed that multiple calls to load_json(...) with the same JSON name always return the same object, so save {} when deleting the files to force reload if type(cfgCurrent) not in (type(dict()), type(None)): # delete config files, fman's save_json can't replace types config_files = ['StatusBarExtended.json'] config_files.append('StatusBarExtended (' + PLATFORM + ').json') user_settings_url = join(as_url(DATA_DIRECTORY), 'Plugins', 'User', 'Settings') user_input_allow = '' prompt_msg_full = '' corrupt_config = [] for f in config_files: f_url = join(user_settings_url, f) f_path = as_path(f_url) if not exists(f_url): continue excerpt = str(load_json(f_path))[:100] prompt_msg = f_path \ + "\n that begins with:"\ + "\n " + excerpt corrupt_config.append({}) corrupt_config[-1]['url'] = f_url corrupt_config[-1]['path'] = f_path corrupt_config[-1]['prompt_msg'] = prompt_msg corrupt_count = len(corrupt_config) if corrupt_count: # delete corrupt config files with the user's permission prompt_msg_full += "Please enter 'y' or 'yes' or '1' (without the quotes) to delete " + str(corrupt_count) + " corrupt plugin config file" \ + ("\n" if corrupt_count==1 else "s\n") \ + "with incompatible data type " + str(type(cfgCurrent)) + '\n'\ + "(all settings will be reset to their defaults)\n" for corrupt_file_dict in corrupt_config: prompt_msg_full += '\n' + corrupt_file_dict[ 'prompt_msg'] + '\n' user_input_allow, ok = show_prompt(prompt_msg_full, default=user_input_allow) if ok and user_input_allow in ('y', 'yes', '1'): _reset = False for corrupt_file_dict in corrupt_config: f_url = corrupt_file_dict['url'] f_path = corrupt_file_dict['path'] try: move_to_trash(f_url) except Exception as e: show_status_message( "StatusBarExtended: failed to move to trash — " + f_path + " — with exception " + repr(e), msg_t) pass if not exists(f_url): show_status_message( "StatusBarExtended: moved to trash — " + f_path, msg_t) _reset = True else: show_status_message( "StatusBarExtended: failed to move to trash, deleting — " + f_path, msg_t) try: delete(f_url) except Exception as e: show_status_message( "StatusBarExtended: failed to delete — " + f_path + " — with exception " + repr(e), msg_t) pass if not exists(f_url): show_status_message( "StatusBarExtended: deleted — " + f_path, msg_t) _reset = True else: show_alert( "StatusBarExtended: failed to move to trash or delete — " + f_path + "\nPlease, delete it manually") del cls.locked_update return None, 'ConfigDeleteFail' if _reset == True: # can save_json only when both files are deleted, otherwise there is a format mismatch ValueError cls.saveConfig({}) cfgCurrent = load_json('StatusBarExtended.json') else: # user canceled or didn't enter y/1 show_status_message( "StatusBarExtended: you canceled the deletion of the corrupted config files", msg_t) del cls.locked_update return None, 'Canceled' else: # can't find the config files show_alert("StatusBarExtended: can't find the corrupt config files:\n" \ + str(config_files) + "\n @ " + as_path(user_settings_url) \ + "\nMaybe their default location changed, please, delete them manually") del cls.locked_update return None, 'CorruptConfigNotFound' reload = False if (cfgCurrent is None) or ( cfgCurrent == {} ): # empty file or empty dictionary (corrupt configs deleted and replaced with {}), save defaults to the config file cfgCurrent = dict() for key in cls.Default: cfgCurrent[key] = cls.Default[key] reload = True if type(cfgCurrent) is dict: for key in cls.Default: # Fill in missing default values (e.g. in older installs) if key not in cfgCurrent: cfgCurrent[key] = cls.Default[key] reload = True if reload: cls.saveConfig(cfgCurrent) cfgCurrent = load_json('StatusBarExtended.json') if type(cfgCurrent) is dict: # check for still missing keys missing_keys = [] for key in cls.Default: if key in cfgCurrent: continue missing_keys.append(key) if len(missing_keys): show_status_message( "StatusBarExtended: config files are missing some required keys:" + str(missing_keys) + " Maybe try to reload?", msg_t) del cls.locked_update return None, 'MissingKeys' else: del cls.locked_update return cfgCurrent, 'Success' else: show_status_message( "StatusBarExtended: couldn't fix config files, maybe try to reload?", msg_t) del cls.locked_update return None, 'UnknownError'