]> scripts.mit.edu Git - wizard.git/blobdiff - wizard/scripts.py
Add support for a working dir in wizard.shell
[wizard.git] / wizard / scripts.py
index 35b9ba942db0905aa5ab8e37ac03b9188cde4c97..9092f268d0be2a96cbe33344fba7c701e8bde536 100644 (file)
+"""
+This is ostensibly the place where Scripts specific code should live.
+"""
+
 import os
+import shlex
+import errno
+import logging
+import urlparse
+import time
+import errno
 
-from wizard import shell
+import wizard
+from wizard import shell, util
 
-def get_sql_credentials():
+def fill_url(dir, url=None, old_style=False):
     """
-    Attempts to determine a user's MySQL credentials.  They are
-    returned as a three-tuple (host, user, password).
+    Attempts to determine the URL a directory would be web-accessible at.
+    If ``url`` is specified, automatically use it.
     """
-    sh = shell.Shell()
-    host = os.getenv("WIZARD_MYSQL_HOST")
-    user = os.getenv("WIZARD_MYSQL_USER")
-    password = os.getenv("WIZARD_MYSQL_PASSWORD")
-    if host is not None and user is not None and password is not None:
-        return (host, user, password)
-    try:
-        return sh.eval("/mit/scripts/sql/bin/get-password").split()
-    except CallError:
-        return None
+    if url:
+        return url
 
-def get_web_host_and_path(dir=None):
-    """
-    Attempts to determine webhost and path for the current directory
-    as it would be accessible from the web.  Works only for scripts
-    servers.  Returns a tuple web_host, web_path, or None if it failed.
-    """
-    # XXX: THIS CODE SUCKS
+    # hook hook
+
+    # try the directory
+    homedir, _, web_path = dir.partition("/web_scripts")
+    if web_path:
+        if old_style:
+            return urlparse.ParseResult(
+                    "http",
+                    "scripts.mit.edu",
+                    "/~" + util.get_dir_owner(homedir) + web_path.rstrip('/'),
+                    "", "", "")
+        else:
+            return urlparse.ParseResult(
+                    "http",
+                    util.get_dir_owner(homedir) + ".scripts.mit.edu",
+                    web_path.rstrip('/'),
+                    "", "", "")
+
+    # try the environment
     host = os.getenv("WIZARD_WEB_HOST")
     path = os.getenv("WIZARD_WEB_PATH")
     if host is not None and path is not None:
-        return (host, path)
-    if not dir:
+        return urlparse.ParseResult(
+                "http",
+                host,
+                path.rstrip('/'),
+                "", "", "")
+
+    return None
+
+def get_quota_usage_and_limit(dir=None):
+    """
+    Returns a tuple (quota usage, quota limit).  Works only for scripts
+    servers.  Values are in KiB.  Returns ``(0, None)`` if we couldn't figure it out.
+    """
+    end = 2
+    # sometimes the volume is busy; so we try several times
+    for i in range(0, end + 1):
+        try:
+            return _get_quota_usage_and_limit(dir)
+        except QuotaParseError as e:
+            if i == end:
+                raise e
+            time.sleep(3) # give it a chance to unbusy
+    assert False # should not get here
+
+def _get_quota_usage_and_limit(dir=None):
+    # XXX: The correct way is to implement Python modules implementing
+    # bindings for all the appropriate interfaces
+    def parse_last_quote(ret):
+        return ret.rstrip('\'').rpartition('\'')[2]
+    if dir is None:
         dir = os.getcwd()
-    _, _, web_path = dir.partition("/web_scripts")
-    if not web_path:
-        return None
-    return (util.get_dir_owner(dir) + ".scripts.mit.edu", web_path)
+    sh = shell.Shell()
+    try:
+        cell = parse_last_quote(sh.eval("fs", "whichcell", "-path", dir))
+    except shell.CallError:
+        return (0, None)
+    except OSError as e:
+        if e.errno == errno.ENOENT:
+            return (0, None)
+        raise
+    mount = None
+    while dir:
+        try:
+            volume = parse_last_quote(sh.eval("fs", "lsmount", dir))[1:]
+            break
+        except shell.CallError:
+            dir = os.path.dirname(dir)
+        except OSError as e:
+            if e.errno == errno.ENOENT:
+                return (0, None)
+            raise
+    if not volume: return (0, None)
+    try:
+        result = sh.eval("vos", "examine", "-id", volume, "-cell", cell).splitlines()
+    except OSError:
+        try:
+            result = sh.eval("/usr/sbin/vos", "examine", "-id", volume, "-cell", cell).splitlines()
+        except OSError:
+            return (0, None)
+    except shell.CallError:
+        return (0, None)
+    try:
+        usage = int(result[0].split()[3])
+        limit = int(result[3].split()[1]) # XXX: FRAGILE
+    except ValueError:
+        raise QuotaParseError("vos examine output was:\n\n" + "\n".join(result))
+    return (usage, limit)
+
+# XXX: Possibly in the wrong module
+def get_disk_usage(dir=None, excluded_dir=".git"):
+    """
+    Recursively determines the disk usage of a directory, excluding
+    .git directories.  Value is in bytes.
+    """
+    if dir is None: dir = os.getcwd()
+    sum_sizes = 0
+    for root, _, files in os.walk(dir):
+        for name in files:
+            if not os.path.join(root, name).startswith(dir + excluded_dir):
+                file = os.path.join(root, name)
+                try:
+                    if os.path.islink(file): continue
+                    sum_sizes += os.path.getsize(file)
+                except OSError as e:
+                    if e.errno == errno.ENOENT:
+                        logging.warning("%s disappeared before we could stat", file)
+                    else:
+                        raise
+    return sum_sizes
+
+class QuotaParseError(wizard.Error):
+    """Could not parse quota information."""
+    def __init__(self, msg):
+        self.msg = msg
+    def __str__(self):
+        return """
 
+ERROR: Could not parse quota. %s
+""" % self.msg