# -*- coding: utf-8 -*-
#
# Copyright (C) 2009-2012 Sebastien Helleu <flashcode@flashtux.org>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#
# WeeChat scripts manager.
# (this script requires WeeChat >= 0.3.0 and python >= 2.6)
#
# History:
#
# 2012-02-05, Sebastien Helleu <flashcode@flashtux.org>:
# version 1.6: use URL transfer from API (for WeeChat >= 0.3.7)
# 2012-01-03, Sebastien Helleu <flashcode@flashtux.org>:
# version 1.5: make script compatible with Python 3.x
# 2011-03-25, Sebastien Helleu <flashcode@flashtux.org>:
# version 1.4: add completion with installed scripts for action "remove"
# 2011-03-10, Sebastien Helleu <flashcode@flashtux.org>:
# version 1.3: add script extension in script name completion and a new
# completion with tags for actions "list" and "listinstalled"
# 2011-02-13, Sebastien Helleu <flashcode@flashtux.org>:
# version 1.2: use new help format for command arguments
# 2010-11-08, Sebastien Helleu <flashcode@flashtux.org>:
# version 1.1: get python 2.x binary for hook_process (fix problem
# when python 3.x is default python version, requires
# WeeChat >= 0.3.4)
# 2010-02-22, Blake Winton <bwinton@latte.ca>:
# version 1.0: add action "listinstalled" for command /weeget
# 2010-01-25, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.9: fix "running" status of scripts with /weeget check
# 2009-09-30, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.8: fix bugs and add missing info in "/weeget show",
# display warning if url for plugins.xml.gz is old site
# 2009-09-07, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.7: update weechat site with new URL
# 2009-05-02, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.6: sync with last API changes
# 2009-04-15, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.5: display missing module(s) when import failed
# 2009-04-11, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.4: use new completion for command arguments
# 2009-04-07, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.3: fix bug with install/upgrade when weeget is updated with
# other scripts: ensure that weeget is always the last
# installed script
# 2009-04-07, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.2: add author's mail in script description
# 2009-04-05, Sebastien Helleu <flashcode@flashtux.org>:
# version 0.1: initial release
#
SCRIPT_NAME = "weeget"
SCRIPT_AUTHOR = "Sebastien Helleu <flashcode@flashtux.org>"
SCRIPT_VERSION = "1.6"
SCRIPT_LICENSE = "GPL3"
SCRIPT_DESC = "WeeChat scripts manager"
SCRIPT_COMMAND = "weeget"
import_ok = True
try:
import weechat
except ImportError:
print("This script must be run under WeeChat.")
print("Get WeeChat now at: http://www.weechat.org/")
import_ok = False
try:
import sys, os, stat, time, gzip, hashlib, xml.dom.minidom
except ImportError as message:
print("Missing package(s) for %s: %s" % (SCRIPT_NAME, message))
import_ok = False
CONFIG_FILE_NAME = "wg"
SCRIPT_EXTENSION = {
"perl" : "pl",
"python": "py",
"ruby" : "rb",
"lua" : "lua",
"tcl" : "tcl",
}
# timeout for download of plugins.xml.gz
TIMEOUT_UPDATE = 60 * 1000
# timeout for download of a script
TIMEOUT_SCRIPT = 60 * 1000
# config file and options
wg_config_file = ""
wg_config_option = {}
# action (install, remove, ..) and arguments
wg_action = ""
wg_action_args = ""
# loaded scripts
wg_loaded_scripts = {}
# hook process and stdout
wg_hook_process = { "update": "", "script": "" }
wg_stdout = { "update": "", "script": "" }
# scripts read from plugins.xml.gz
wg_scripts = {}
# list of script to install, and script currently installing
wg_scripts_to_install = []
wg_current_script_install = {}
# =================================[ config ]=================================
def wg_config_init():
"""
Initialization of configuration file.
Sections: color, scripts.
"""
global wg_config_file, wg_config_option
wg_config_file = weechat.config_new(CONFIG_FILE_NAME,
"wg_config_reload_cb", "")
if wg_config_file == "":
return
# section "color"
section_color = weechat.config_new_section(
wg_config_file, "color", 0, 0, "", "", "", "", "", "", "", "", "", "")
if section_color == "":
weechat.config_free(wg_config_file)
return
wg_config_option["color_script"] = weechat.config_new_option(
wg_config_file, section_color,
"script", "color", "Color for script names", "", 0, 0,
"cyan", "cyan", 0, "", "", "", "", "", "")
wg_config_option["color_installed"] = weechat.config_new_option(
wg_config_file, section_color,
"installed", "color", "Color for \"installed\" indicator", "", 0, 0,
"yellow", "yellow", 0, "", "", "", "", "", "")
wg_config_option["color_running"] = weechat.config_new_option(
wg_config_file, section_color,
"running", "color", "Color for \"running\" indicator", "", 0, 0,
"lightgreen", "lightgreen", 0, "", "", "", "", "", "")
wg_config_option["color_obsolete"] = weechat.config_new_option(
wg_config_file, section_color,
"obsolete", "color", "Color for \"obsolete\" indicator", "", 0, 0,
"lightmagenta", "lightmagenta", 0, "", "", "", "", "", "")
wg_config_option["color_unknown"] = weechat.config_new_option(
wg_config_file, section_color,
"unknown", "color", "Color for \"unknown status\" indicator", "", 0, 0,
"lightred", "lightred", 0, "", "", "", "", "", "")
wg_config_option["color_language"] = weechat.config_new_option(
wg_config_file, section_color,
"language", "color", "Color for language names", "", 0, 0,
"lightblue", "lightblue", 0, "", "", "", "", "", "")
# section "scripts"
section_scripts = weechat.config_new_section(
wg_config_file, "scripts", 0, 0, "", "", "", "", "", "", "", "", "", "")
if section_scripts == "":
weechat.config_free(wg_config_file)
return
wg_config_option["scripts_url"] = weechat.config_new_option(
wg_config_file, section_scripts,
"url", "string", "URL for file with list of plugins", "", 0, 0,
"http://www.weechat.org/files/plugins.xml.gz",
"http://www.weechat.org/files/plugins.xml.gz", 0, "", "", "", "", "", "")
wg_config_option["scripts_dir"] = weechat.config_new_option(
wg_config_file, section_scripts,
"dir", "string", "Local cache directory for" + SCRIPT_NAME, "", 0, 0,
"%h/" + SCRIPT_NAME, "%h/" + SCRIPT_NAME, 0, "", "", "", "", "", "")
wg_config_option["scripts_cache_expire"] = weechat.config_new_option(
wg_config_file, section_scripts,
"cache_expire", "integer", "Local cache expiration time, in minutes "
"(-1 = never expires, 0 = always expires)", "",
-1, 60*24*365, "60", "60", 0, "", "", "", "", "", "")
def wg_config_reload_cb(data, config_file):
""" Reload configuration file. """
return weechat.config_read(config_file)
def wg_config_read():
""" Read configuration file. """
global wg_config_file
return weechat.config_read(wg_config_file)
def wg_config_write():
""" Write configuration file. """
global wg_config_file
return weechat.config_write(wg_config_file)
def wg_config_color(color):
""" Get a color from configuration. """
global wg_config_option
option = wg_config_option.get("color_" + color, "")
if option == "":
return ""
return weechat.color(weechat.config_string(option))
def wg_config_get_dir():
""" Return weeget directory, with expanded WeeChat home dir. """
global wg_config_option
return weechat.config_string(
wg_config_option["scripts_dir"]).replace("%h",
weechat.info_get("weechat_dir", ""))
def wg_config_create_dir():
""" Create weeget directory. """
dir = wg_config_get_dir()
if not os.path.isdir(dir):
os.makedirs(dir, mode=0o700)
def wg_config_get_cache_filename():
""" Get local cache filename, based on URL. """
global wg_config_option
return wg_config_get_dir() + os.sep + \
os.path.basename(weechat.config_string(wg_config_option["scripts_url"]))
# =============================[ download file ]==============================
def wg_download_file(url, filename, timeout, callback, callback_data):
"""Download a file with an URL. Return hook_process created."""
version = weechat.info_get("version_number", "") or 0
if int(version) >= 0x00030700:
return weechat.hook_process_hashtable("url:%s" % url,
{ "file_out": filename },
timeout,
callback, callback_data)
else:
script = [ "import sys",
"try:",
" if sys.version_info >= (3,):",
" import urllib.request",
" response = urllib.request.urlopen('%s')" % url,
" else:",
" import urllib2",
" response = urllib2.urlopen(urllib2.Request('%s'))" % url,
" f = open('%s', 'wb')" % filename,
" f.write(response.read())",
" response.close()",
" f.close()",
"except Exception as e:",
" print('error:' + str(e))" ]
return weechat.hook_process("python -c \"%s\"" % "\n".join(script),
timeout,
callback, callback_data)
# ================================[ scripts ]=================================
def wg_search_script_by_name(name):
"""
Search a script in list by name.
Name can be short name ('weeget') or full name ('weeget.py').
"""
global wg_scripts
for id, script in wg_scripts.items():
if script["name"] == name or script["full_name"] == name:
return script
return None
def wg_get_loaded_scripts():
"""
Get python dictionary with loaded scripts.
Keys are filenames and values are path to script, for example:
'weeget.py': '/home/xxx/.weechat/python/weeget.py'
"""
global wg_loaded_scripts
wg_loaded_scripts = {}
for language in SCRIPT_EXTENSION.keys():
infolist = weechat.infolist_get(language + "_script", "", "")
while weechat.infolist_next(infolist):
filename = weechat.infolist_string(infolist, "filename")
if filename != "":
wg_loaded_scripts[os.path.basename(filename)] = filename
weechat.infolist_free(infolist)
def wg_is_local_script_loaded(filename):
""" Check if a script filename (like 'python/weeget.py') is loaded. """
global wg_loaded_scripts
filename2 = filename
if filename2.startswith("autoload/"):
filename2 = filename2[9:]
for name, path in wg_loaded_scripts.items():
if path.endswith(filename) or path.endswith(filename2):
return True
return False
def wg_get_local_script_status(script):
"""
Check if a script is installed.
'script' is a dictionary retrieved from scripts xml list.
"""
global wg_loaded_scripts
status = { "installed": "", "obsolete": "", "running": "" }
local_dir = weechat.info_get("weechat_dir", "") + os.sep + script["language"]
local_name = local_dir + os.sep + "autoload" + os.sep + script["full_name"]
if not os.path.isfile(local_name):
local_name = local_dir + os.sep + script["full_name"]
if os.path.isfile(local_name):
status["installed"] = "1"
f = open(local_name, "rb")
md5 = hashlib.md5()
md5.update(f.read())
f.close()
local_md5 = md5.hexdigest()
if local_md5 != script["md5sum"]:
status["obsolete"] = "1"
if script["full_name"] in wg_loaded_scripts.keys():
status["running"] = "1"
return status
def wg_get_local_scripts():
"""
Get list of all local scripts (in languages and autoload dirs).
Return a dictionary with language as key and list of paths as value,
with autoloaded scripts at beginning of list, for example:
{ 'perl': [ 'autoload/buffers.pl',
'autoload/weetris.pl',
'beep.pl',
'launcher.pl' ],
'python': [ 'autoload/weeget.py',
'go.py',
'vdm.py' ]
}
"""
files = {}
for language in SCRIPT_EXTENSION.keys():
files[language] = []
autoloaded_files = []
rootdir = weechat.info_get("weechat_dir", "") + os.sep + language
for root, dirs, listfiles in os.walk(rootdir):
if root == rootdir:
files[language] = listfiles
elif root == rootdir + os.sep + "autoload":
autoloaded_files = listfiles
for file in autoloaded_files:
if file in files[language]:
files[language].remove(file)
files[language].insert(0, "autoload" + os.sep + file)
return files
def wg_get_local_scripts_status():
"""
Return list of all local scripts with status (unknown/obsolete/running).
For example:
[ 'perl/weetris.pl': { 'unknown': '', 'obsolete': '1', 'running': '' },
'python/weeget.py': { 'unknown': '', 'obsolete': '', 'running': '1' }
]
"""
local_scripts_status = []
local_scripts = wg_get_local_scripts()
if len(local_scripts) > 0:
for language, files in local_scripts.items():
for file in files:
script_status = { "unknown": "", "obsolete": "", "running": "" }
name_with_ext = os.path.basename(file)
script = wg_search_script_by_name(os.path.basename(file))
if script == None:
script_status["unknown"] = "1"
else:
status = wg_get_local_script_status(script)
if status["obsolete"]:
script_status["obsolete"] = "1"
if wg_is_local_script_loaded(file):
script_status["running"] = "1"
local_scripts_status.append((language + os.sep + file,
script_status))
return local_scripts_status
def wg_search_scripts(search):
""" Search word in scripts, return list of matching scripts. """
global wg_scripts
if search == "":
return wg_scripts
scripts_matching = {}
for id, script in wg_scripts.items():
if script["name"].lower().find(search) >= 0 \
or script["language"].lower().find(search) >= 0 \
or script["desc_en"].lower().find(search) >= 0 \
or script["desc_fr"].lower().find(search) >= 0 \
or script["tags"].lower().find(search) >= 0:
scripts_matching[id] = script
return scripts_matching
def wg_list_scripts(search, installed=False):
"""
List all scripts (with optional search string).
If installed == True, then list only installed scripts.
For each script, display status (installed/running/new version available),
name of script, language and description.
For example:
ir buffers pl Sidebar with list of buffers.
i N go py Quick jump to buffers.
i weetris pl Tetris-like game.
"""
global wg_scripts
search = search.strip().lower()
scripts_matching = wg_search_scripts(search)
if len(scripts_matching) == 0:
weechat.prnt("", "%s: no script found" % SCRIPT_NAME)
else:
weechat.prnt("", "")
if search != "":
if installed:
weechat.prnt("", "Scripts installed matching \"%s\":" % search)
else:
weechat.prnt("", "Scripts for WeeChat %s matching \"%s\":"
% (weechat.info_get("version", ""),
search))
else:
if installed:
weechat.prnt("", "Scripts installed:")
else:
weechat.prnt("", "Scripts for WeeChat %s:"
% weechat.info_get("version", ""))
sorted_scripts = sorted(scripts_matching.items(),
key=lambda s: s[1]["name"])
length_max_name = 0
for item in sorted_scripts:
length = len(item[1]["name"])
if length > length_max_name:
length_max_name = length
str_format = "%%s%%s%%s%%s%%s%%s%%s %%s%%-%ds %%s%%-3s %%s%%s" \
% length_max_name
for item in sorted_scripts:
script = item[1]
str_installed = " "
str_running = " "
str_obsolete = " "
status = wg_get_local_script_status(script)
if installed and not status["installed"]:
continue
if status["installed"]:
str_installed = "i"
if status["running"]:
str_running = "r"
if status["obsolete"]:
str_obsolete = "N"
weechat.prnt("", str_format
% (wg_config_color("installed"),
str_installed,
wg_config_color("running"),
str_running,
wg_config_color("obsolete"),
str_obsolete,
weechat.color("chat"),
wg_config_color("script"),
script["name"],
wg_config_color("language"),
SCRIPT_EXTENSION[script["language"]],
weechat.color("chat"),
script["desc_en"]))
def wg_show_script(name):
"""
Show detailed info about a script (in repository).
For example:
Script: weeget.py, version 0.7, license: GPL3
Author: Sebastien Helleu <flashcode [at] flashtux [dot] org>
Status: installed, running
Date: added: 2009-04-05, updated: 2009-09-07
URL: http://www.weechat.org/files/scripts/weeget.py
MD5: 4b0458dd5cc5c9a09ba8078f89830869
Desc: Scripts manager.
Tags: scripts
Requires: python 2.5
Min: 0.3.0
"""
if len(wg_scripts) == 0:
return
script = wg_search_script_by_name(name)
if script == None:
weechat.prnt("", "%s: script \"%s%s%s\" not found"
% (SCRIPT_NAME,
wg_config_color("script"),
name,
weechat.color("chat")))
else:
weechat.prnt("", "")
weechat.prnt("", " Script: %s%s%s, version %s, license: %s"
% (wg_config_color("script"),
script["full_name"],
weechat.color("chat"),
script["version"],
script["license"]))
weechat.prnt("", " Author: %s <%s>" % (script["author"], script["mail"]))
status = wg_get_local_script_status(script)
str_status = "not installed"
if status["installed"]:
str_status = "installed"
if status["running"]:
str_status += ", running"
else:
str_status += ", not running"
if status["obsolete"]:
str_status += " (new version available)"
weechat.prnt("", " Status: %s" % str_status)
date_added = script.get("added", "")[:10]
str_updated = script.get("updated", "")
if str_updated != "":
date_updated = script["updated"][:10]
if date_updated == "0000-00-00" or date_updated == date_added:
str_updated = ""
if str_updated != "":
weechat.prnt("", " Date: added: %s, updated: %s"
% (date_added, date_updated))
else:
weechat.prnt("", " Date: added: %s" % date_added)
weechat.prnt("", " URL: %s" % script.get("url", ""))
weechat.prnt("", " MD5: %s" % script.get("md5sum", ""))
weechat.prnt("", " Desc: %s" % script.get("desc_en", ""))
weechat.prnt("", " Tags: %s" % script.get("tags", ""))
str_requires = script.get("requirements", "")
if str_requires == "":
str_requires = "(nothing)"
weechat.prnt("", "Requires: %s" % str_requires)
vmin = script.get("min_weechat", "")
vmax = script.get("max_weechat", "")
if vmin != "":
weechat.prnt("", " Min: %s" % vmin)
if vmax != "":
weechat.prnt("", " Max: %s" % vmax)
def wg_install_next_script():
"""
Install first script in list wg_scripts_to_install and remove it from
list.
"""
global wg_scripts, wg_scripts_to_install, wg_current_script_install
global wg_hook_process
if len(wg_scripts) == 0:
return
# be sure weeget is ALWAYS last script to install/update
# otherwise we'll lose end of list when weeget is unloaded by WeeChat
if SCRIPT_NAME in wg_scripts_to_install:
wg_scripts_to_install.remove(SCRIPT_NAME)
wg_scripts_to_install.append(SCRIPT_NAME)
# loop until a script is installed, or end if list is empty
while len(wg_scripts_to_install) > 0:
name = wg_scripts_to_install.pop(0)
script = wg_search_script_by_name(name)
if script == None:
weechat.prnt("", "%s: script \"%s%s%s\" not found"
% (SCRIPT_NAME,
wg_config_color("script"),
name,
weechat.color("chat")))
else:
status = wg_get_local_script_status(script)
if status["installed"] and not status["obsolete"]:
weechat.prnt("",
"%s: script \"%s%s%s\" is already "
"installed and up to date"
% (SCRIPT_NAME,
wg_config_color("script"),
script["full_name"],
weechat.color("chat")))
else:
weechat.prnt("", "%s: downloading \"%s%s%s\"..."
% (SCRIPT_NAME,
wg_config_color("script"),
script["full_name"],
weechat.color("chat")))
if wg_hook_process["script"] != "":
weechat.unhook(wg_hook_process["script"])
wg_hook_process["script"] = ""
wg_current_script_install = script
filename = wg_config_get_dir() + os.sep + script["full_name"]
wg_hook_process["script"] = wg_download_file(script["url"], filename, TIMEOUT_SCRIPT,
"wg_process_script_cb", "")
# this function will be called again when script will be
# downloaded
return
def wg_install_scripts(names):
""" Install scripts. """
global wg_scripts_to_install
for name in names.split(" "):
wg_scripts_to_install.append(name)
wg_install_next_script()
def wg_process_script_cb(data, command, rc, stdout, stderr):
""" Callback when reading a script from website. """
global wg_hook_process, wg_stdout, wg_current_script_install, wg_loaded_scripts
if stdout != "":
wg_stdout["script"] += stdout
if stderr != "":
wg_stdout["script"] += stderr
if int(rc) >= 0:
if wg_stdout["script"].startswith("error:"):
weechat.prnt("", "%s%s: error downloading script (%s)"
% (weechat.prefix("error"), SCRIPT_NAME,
wg_stdout["update"][6:].strip()))
else:
# ask C plugin to install/load script
weechat.hook_signal_send(wg_current_script_install["language"] + "_script_install",
weechat.WEECHAT_HOOK_SIGNAL_STRING,
wg_config_get_dir() + os.sep + wg_current_script_install["full_name"])
wg_hook_process["script"] = ""
wg_install_next_script()
return weechat.WEECHAT_RC_OK
def wg_check_scripts():
"""
Check status of local script(s).
For each script found, display status (unknown/running/new version available).
For example:
r python/autoload/vdm.py
?r python/autoload/dummy.py
rN python/shell.py
perl/buffers.pl
"""
local_scripts_status = wg_get_local_scripts_status()
if len(local_scripts_status) == 0:
return
weechat.prnt("", "")
weechat.prnt("", "Local scripts:")
for file, status in local_scripts_status:
str_unknown = " "
str_running = " "
str_obsolete = " "
if status["unknown"]:
str_unknown = "?"
if status["running"]:
str_running = "r"
if status["obsolete"]:
str_obsolete = "N"
weechat.prnt("", "%s%s%s%s%s%s%s %s%s%s%s"
% (wg_config_color("unknown"), str_unknown,
wg_config_color("running"), str_running,
wg_config_color("obsolete"), str_obsolete,
weechat.color("chat"),
os.path.dirname(file),
os.sep,
wg_config_color("script"),
os.path.basename(file)))
def wg_upgrade_scripts():
""" Upgrade scripts. """
global wg_scripts, wg_scripts_to_install
if len(wg_scripts) == 0:
return
scripts_to_upgrade = []
for id, script in wg_scripts.items():
status = wg_get_local_script_status(script)
if status["installed"] and status["obsolete"]:
scripts_to_upgrade.append(script["name"])
if len(scripts_to_upgrade) == 0:
weechat.prnt("", "%s: all scripts are up to date" % SCRIPT_NAME)
else:
wg_scripts_to_install.extend(scripts_to_upgrade)
wg_install_next_script()
def wg_remove_scripts(names):
""" Remove scripts. """
if len(wg_scripts) == 0:
return
list_names = names.split(" ")
scripts_to_remove = {}
for language in SCRIPT_EXTENSION.keys():
scripts_to_remove[language] = []
for name in list_names:
script = wg_search_script_by_name(name)
if script == None:
weechat.prnt("", "%s: script \"%s%s%s\" not found"
% (SCRIPT_NAME,
wg_config_color("script"),
name,
weechat.color("chat")))
else:
if script["full_name"] not in scripts_to_remove[script["language"]]:
scripts_to_remove[script["language"]].append(script["full_name"])
for language in SCRIPT_EXTENSION.keys():
if len(scripts_to_remove[language]) > 0:
# ask C plugin to remove script file(s)
weechat.hook_signal_send(language + "_script_remove",
weechat.WEECHAT_HOOK_SIGNAL_STRING,
",".join(scripts_to_remove[language]))
# ==================================[ xml ]===================================
def wg_execute_action():
""" Execute action. """
global wg_action, wg_action_args, wg_loaded_scripts
if wg_action != "":
wg_get_loaded_scripts()
if wg_action == "list":
wg_list_scripts(wg_action_args)
elif wg_action == "listinstalled":
wg_list_scripts(wg_action_args, installed=True)
elif wg_action == "show":
wg_show_script(wg_action_args)
elif wg_action == "install":
wg_install_scripts(wg_action_args)
elif wg_action == "check":
wg_check_scripts()
elif wg_action == "upgrade":
wg_upgrade_scripts()
elif wg_action == "remove":
wg_remove_scripts(wg_action_args)
else:
weechat.prnt("", "%s%s: unknown action \"%s\""
% (weechat.prefix("error"), SCRIPT_NAME, wg_action))
# reset action
wg_action = ""
wg_action_args = ""
wg_loaded_scripts = {}
def wg_check_version(script):
""" Check if a script is designed for current running WeeChat version."""
version = weechat.info_get("version", "")
version = version.split("-", 1)[0]
vmin = script.get("min_weechat", "")
vmax = script.get("max_weechat", "")
if vmin != "" and version < vmin:
return False
if vmax != "" and version > vmax:
return False
return True
def wg_parse_xml():
"""
Parse XML scripts list and return dictionary with list, with key 'id'.
Example of item return in dictionary :
'119': { 'name' : 'weeget',
'version' : '0.1',
'url' : 'http://www.weechat.org/files/scripts/weeget.py',
'language' : 'python',
'license' : 'GPL3',
'md5sum' : 'd500714fc19b0e10cc4e339e70739e4ad500714fc19b0e10cc4e339e70739e4a',
'tags' : 'scripts',
'desc_en' : 'Scripts manager.',
'desc_fr' : 'Gestionnaire de scripts.',
'requirements': 'python 2.5',
'min_weechat' : '0.3.0',
'max_weechat' : '',
'author' : 'FlashCode',
'mail' : 'flashcode [at] flashtux [dot] org',
'added' : '2009-04-05 22:39:18',
'updated' : '0000-00-00 00:00:00' }
"""
global wg_scripts, wg_action, wg_action_args
wg_scripts = {}
try:
f = gzip.open(wg_config_get_cache_filename(), "rb")
string = f.read()
f.close()
except:
weechat.prnt("", "%s%s: unable to read xml file"
% (weechat.prefix("error"), SCRIPT_NAME))
else:
try:
dom = xml.dom.minidom.parseString(string)
except:
weechat.prnt("",
"%s%s: unable to parse xml list of scripts"
% (weechat.prefix("error"), SCRIPT_NAME))
# discard action
wg_action = ""
wg_action_args = ""
else:
for scriptNode in dom.getElementsByTagName("plugin"):
id = scriptNode.getAttribute("id")
script = {}
for node in scriptNode.childNodes:
if node.nodeType == node.ELEMENT_NODE:
if node.firstChild != None:
nodename = node.nodeName
value = node.firstChild.data
if sys.version_info < (3,):
# python 2.x: convert unicode to str (in python 3.x, id and text are already strings)
nodename = nodename.encode("utf-8")
value = value.encode("utf-8")
script[nodename] = value
if script["language"] in SCRIPT_EXTENSION:
script["full_name"] = script["name"] + "." + SCRIPT_EXTENSION[script["language"]]
if wg_check_version(script):
wg_scripts[id] = script
wg_execute_action()
def wg_process_update_cb(data, command, rc, stdout, stderr):
""" Callback when reading XML cache file from website. """
global wg_hook_process, wg_stdout, wg_scripts
if stdout != "":
wg_stdout["update"] += stdout
if stderr != "":
wg_stdout["update"] += stderr
if int(rc) >= 0:
if wg_stdout["update"].startswith("error:"):
weechat.prnt("", "%s%s: error downloading scripts (%s)"
% (weechat.prefix("error"), SCRIPT_NAME,
wg_stdout["update"][6:].strip()))
else:
weechat.prnt("", "%s: scripts downloaded" % SCRIPT_NAME)
wg_parse_xml()
wg_hook_process["update"] = ""
return weechat.WEECHAT_RC_OK
def wg_update_cache():
""" Download list of scripts and update local cache. """
global wg_config_option, wg_hook_process, wg_stdout
# get data from website, via hook_process
if wg_hook_process["update"] != "":
weechat.unhook(wg_hook_process["update"])
wg_hook_process["update"] = ""
weechat.prnt("", "%s: downloading list of scripts..." % SCRIPT_NAME)
wg_stdout["update"] = ""
wg_config_create_dir()
url = weechat.config_string(wg_config_option["scripts_url"])
filename = wg_config_get_cache_filename()
wg_hook_process["update"] = wg_download_file(url, filename, TIMEOUT_UPDATE,
"wg_process_update_cb", "")
def wg_read_scripts(download_list=True):
""" Read scripts list (download list if needed and asked). """
global wg_scripts
cache_file = wg_config_get_cache_filename()
if os.path.isfile(cache_file):
# check if local cache file is too old
cache_expire = weechat.config_integer(wg_config_option["scripts_cache_expire"]) * 60
if cache_expire >= 0:
diff_time = time.time() - os.stat(cache_file)[stat.ST_MTIME]
if download_list and diff_time >= cache_expire:
os.unlink(cache_file)
wg_scripts.clear()
if len(wg_scripts) > 0:
wg_execute_action()
else:
if os.path.isfile(cache_file):
wg_parse_xml()
elif download_list:
wg_update_cache()
# ================================[ command ]=================================
def wg_cmd(data, buffer, args):
""" Callback for /weeget command. """
global wg_action, wg_action_args
if args == "":
weechat.command("", "/help %s" % SCRIPT_COMMAND)
return weechat.WEECHAT_RC_OK
argv = args.strip().split(" ", 1)
if len(argv) == 0:
return weechat.WEECHAT_RC_OK
wg_action = ""
wg_action_args = ""
# check arguments
if len(argv) < 2:
if argv[0] == "show" or \
argv[0] == "install" or \
argv[0] == "remove":
weechat.prnt("", "%s: too few arguments for action \"%s\""
% (SCRIPT_NAME, argv[0]))
return weechat.WEECHAT_RC_OK
# execute asked action
if argv[0] == "update":
wg_update_cache()
else:
wg_action = argv[0]
wg_action_args = ""
if len(argv) > 1:
wg_action_args = argv[1]
wg_read_scripts()
return weechat.WEECHAT_RC_OK
def wg_completion_scripts_cb(data, completion_item, buffer, completion):
""" Complete with known script names, for command '/weeget'. """
global wg_scripts
wg_read_scripts(download_list=False)
if len(wg_scripts) > 0:
for id, script in wg_scripts.items():
weechat.hook_completion_list_add(completion, script["full_name"],
0, weechat.WEECHAT_LIST_POS_SORT)
return weechat.WEECHAT_RC_OK
def wg_completion_scripts_installed_cb(data, completion_item, buffer, completion):
""" Complete with names of scripts installed, for command '/weeget'. """
global wg_scripts
wg_read_scripts(download_list=False)
if len(wg_scripts) > 0:
for id, script in wg_scripts.items():
status = wg_get_local_script_status(script)
if status["installed"]:
weechat.hook_completion_list_add(completion, script["full_name"],
0, weechat.WEECHAT_LIST_POS_SORT)
return weechat.WEECHAT_RC_OK
def wg_completion_scripts_tags_cb(data, completion_item, buffer, completion):
""" Complete with known tags, for command '/weeget'. """
global wg_scripts
wg_read_scripts(download_list=False)
if len(wg_scripts) > 0:
for id, script in wg_scripts.items():
if script["tags"]:
for tag in script["tags"].split(","):
weechat.hook_completion_list_add(completion, tag,
0, weechat.WEECHAT_LIST_POS_SORT)
return weechat.WEECHAT_RC_OK
# ==================================[ main ]==================================
if __name__ == "__main__" and import_ok:
if weechat.register(SCRIPT_NAME, SCRIPT_AUTHOR, SCRIPT_VERSION, SCRIPT_LICENSE,
SCRIPT_DESC, "wg_unload_script", ""):
wg_config_init()
wg_config_read()
if weechat.config_string(wg_config_option["scripts_url"]).find("weechat.flashtux.org") >= 0:
weechat.prnt("", "%sWarning: old site still used in URL for plugins.xml.gz, you should do: /unset wg.scripts.url"
% weechat.prefix("error"))
str_installed = wg_config_color("installed") + "i" + weechat.color("chat")
str_unknown = wg_config_color("unknown") + "?" + weechat.color("chat")
str_running = wg_config_color("running") + "r" + weechat.color("chat")
str_obsolete = wg_config_color("obsolete") + "N" + weechat.color("chat")
weechat.hook_command(SCRIPT_COMMAND,
"WeeChat scripts manager",
"list|listinstalled [<text>|<tag>] || show <script>"
" || install|remove <script> [<script>...] || check|update|upgrade",
" list: list scripts (search text if given)\n"
"listinstalled: list installed scripts (search text if given)\n"
" show: show detailed information about a script (in repository)\n"
" install: install/upgrade script(s)\n"
" check: check if local scripts needs upgrade\n"
" update: update local scripts cache\n"
" upgrade: upgrade all local scripts if they are obsolete\n"
" remove: remove script(s)\n\n"
"Indicators in lists (first column):\n"
" " + str_installed + " script is installed\n"
" " + str_unknown + " unknown script\n"
" " + str_running + " script is running (loaded)\n"
" " + str_obsolete + " script is obsolete (new version available)\n\n"
"Examples:\n"
" /" + SCRIPT_COMMAND + " list => list all scripts\n"
" /" + SCRIPT_COMMAND + " list game => list all scripts with text/tag \"game\"\n"
" /" + SCRIPT_COMMAND + " install beep.pl => install script beep.pl\n"
" /" + SCRIPT_COMMAND + " remove beep.pl => remove script beep.pl",
"list %(weeget_scripts_tags)"
" || listinstalled %(weeget_scripts_tags)"
" || show %(weeget_scripts)"
" || install %(weeget_scripts)|%*"
" || remove %(weeget_scripts_installed)|%*"
" || check"
" || update"
" || upgrade",
"wg_cmd", "")
weechat.hook_completion("weeget_scripts", "list of scripts in repository",
"wg_completion_scripts_cb", "")
weechat.hook_completion("weeget_scripts_installed", "list of scripts installed",
"wg_completion_scripts_installed_cb", "")
weechat.hook_completion("weeget_scripts_tags", "tags of scripts in repository",
"wg_completion_scripts_tags_cb", "")
# ==================================[ end ]===================================
def wg_unload_script():
""" Function called when script is unloaded. """
wg_config_write()
return weechat.WEECHAT_RC_OK