<commit_before>import sublime
import sublime_plugin
import subprocess
import os
import codecs
import platform

class Jfile:
    def __init__(self, fpath, encoding="utf-8"):
        self.encoding = encoding
        self.fpath = fpath

    def load(self, default=[]):
        self.fdir = os.path.dirname(self.fpath)
        if not os.path.isdir(self.fdir):
            os.makedirs(self.fdir)
        if os.path.exists(self.fpath):
            f = codecs.open(self.fpath, "r+", encoding=self.encoding)
            content = f.read()
            try:
                data = sublime.decode_value(content)
            except:
                data = default
            f.close()
        else:
            f = codecs.open(self.fpath, "w+", encoding=self.encoding)
            data = default
            f.close()
        return data

    def save(self, data, indent=4):
        self.fdir = os.path.dirname(self.fpath)
        if not os.path.isdir(self.fdir):
            os.makedirs(self.fdir)
        f = codecs.open(self.fpath, "w+", encoding=self.encoding)
        f.write(sublime.encode_value(data, True))
        f.close()

    def remove(self):
        if os.path.exists(self.fpath):
            os.remove(self.fpath)

def subl(args=[]):
    # learnt from SideBarEnhancements
    executable_path = sublime.executable_path()
    if sublime.platform() == 'osx':
        app_path = executable_path[:executable_path.rfind(".app/") + 5]
        executable_path = app_path + "Contents/SharedSupport/bin/subl"
    subprocess.Popen([executable_path] + args)

def pabs(folder, project_file):
    root = os.path.dirname(project_file)
    if not os.path.isabs(folder):
        folder = os.path.abspath(os.path.join(root, folder))
    return folder

def get_node():
    if sublime.platform() == "osx":
        node = subprocess.check_output(["scutil", "--get", "ComputerName"]).decode().strip()
    else:
        node = platform.node().split(".")[0]
    return node

class Manager:
    def __init__(self, window):
        self.window = window
        settings_file = 'pm.sublime-settings'
        self.settings = sublime.load_settings(settings_file)
        default_projects_dir = os.path.join(sublime.packages_path(), "User", "Projects")
        self.projects_fpath = self.settings.get(
            "projects_fpath", [self.settings.get("projects_dir", default_projects_dir)])
        self.primary_dir = self.projects_fpath[0]

        node = get_node()
        if self.settings.get("use_local_projects_dir", False):
            self.projects_fpath = \
                [d + " - " + node for d in self.projects_fpath] + self.projects_fpath

        self.projects_info = self.get_projects_info()

    def get_projects_info(self):
        ret = {}
        for pdir in self.projects_fpath:
            pfiles = []
            j = Jfile(os.path.join(pdir, "library.json"))
            for f in j.load([]):
                if os.path.exists(f) and f not in pfiles:
                    pfiles.append(f)
            pfiles.sort()
            j.save(pfiles)
            for path, dirs, files in os.walk(pdir):
                for f in files:
                    f = os.path.join(path, f)
                    if f.endswith(".sublime-project") and f not in pfiles:
                        pfiles.append(f)
                # remove empty directories
                for d in dirs:
                    d = os.path.join(path, d)
                    if len(os.listdir(d)) == 0:
                        os.rmdir(d)

        for f in pfiles:
            pdir = self.which_projects_dir(f)
            if pdir:
                pname = os.path.relpath(f, pdir).replace(".sublime-project", "")
            else:
                pname = os.path.basename(f).replace(".sublime-project", "")
            pd = Jfile(f).load()
            if pd and "folders" in pd and pd["folders"]:
                folder = pd["folders"][0].get("path", "")
            else:
                folder = ""
            star = False
            for w in sublime.windows():
                if w.project_file_name() == f:
                    star = True
                    break
            ret[pname] = {
                "folder": pabs(folder, f),
                "file": f,
                "star": star
            }
        return ret

    def which_projects_dir(self, pfile):
        for pdir in self.projects_fpath:
            if os.path.dirname(pfile).startswith(pdir+os.path.sep):
                return pdir
        return None

    def display_projects(self):
        ret = [[key, key + "*" if value["star"] else key, value["folder"]]
               for key, value in self.projects_info.items()]
        ret = sorted(ret)
        count = 0
        for i in range(len(ret)):
            if ret[i][0] is not ret[i][1]:
                ret.insert(count, ret.pop(i))
                count = count + 1
        return [[item[0] for item in ret], [[item[1], item[2]] for item in ret]]

    def project_file_name(self, project):
        return self.projects_info[project]["file"]

    def project_workspace(self, project):
        return self.project_file_name(project).replace(".sublime-project", ".sublime-workspace")

    def add_project(self):
        pd = self.window.project_data()
        if not pd:
            self.window.run_command("prompt_add_project")
            delay = 300
        else:
            delay = 1

        def on_add(project):
            pd = self.window.project_data()
            f = os.path.join(self.primary_dir, "%s.sublime-project" % project)
            Jfile(f).save(pd)
            Jfile(f.replace(".sublime-project", ".sublime-workspace")).save({})
            self.window.run_command("close_workspace")
            self.window.run_command("close_project")
            for v in self.window.views():
                if not v.is_dirty():
                    self.window.focus_view(v)
                    self.window.run_command("close")

            # reload projects info
            self.__init__(self.window)
            self.switch_project(project)

        def show_input_panel():
            pd = self.window.project_data()
            pf = self.window.project_file_name()
            if pd:
                if pf:
                    project = os.path.basename(pabs(pd["folders"][0]["path"], pf))
                else:
                    project = os.path.basename(pd["folders"][0]["path"])
                v = self.window.show_input_panel("Project name:", project, on_add, None, None)
                v.run_command("select_all")

        sublime.set_timeout(show_input_panel, delay)

    def import_sublime_project(self):
        pfile = self.window.project_file_name()
        if not pfile:
            sublime.message_dialog("Project file not found!")
            return
        if self.which_projects_dir(pfile):
            sublime.message_dialog("This project was created by Project Manager!")
            return
        ok = sublime.ok_cancel_dialog("Import %s?" % os.path.basename(pfile))
        if ok:
            j = Jfile(os.path.join(self.primary_dir, "library.json"))
            data = j.load([])
            if pfile not in data:
                data.append(pfile)
                j.save(data)

    def get_project_data(self, project):
        return Jfile(self.project_file_name(project)).load()

    def check_project(self, project):
        wsfile = self.project_workspace(project)
        if not os.path.exists(wsfile):
            Jfile(wsfile).save({})

    def close_project(self, project):
        for w in sublime.windows():
            if w.project_file_name() == self.project_file_name(project):
                w.run_command("close_workspace")
                w.run_command("close_window")
                return True
        return False

    def append_project(self, project):
        pd = self.get_project_data(project)
        paths = [pabs(f.get("path"), self.project_file_name(project)) for f in pd.get("folders")]
        subl(["-a"] + paths)

    def switch_project(self, project):
        self.window.run_command("close_workspace")
        self.check_project(project)
        if self.close_project(project):
            sublime.set_timeout_async(lambda: subl([self.project_file_name(project)]), 500)
            return

        if len(self.window.views()) == 0:
            sublime.set_timeout_async(lambda: subl([self.project_file_name(project)]), 500)
        else:
            sublime.set_timeout_async(lambda: subl(["-n", self.project_file_name(project)]), 500)

    def open_in_new_window(self, project):
        self.check_project(project)
        self.close_project(project)
        sublime.set_timeout_async(lambda: subl(["-n", self.project_file_name(project)]), 500)

    def remove_project(self, project):
        ok = sublime.ok_cancel_dialog("Remove project %s from Project Manager?" % project)
        if ok:
            pfile = self.project_file_name(project)
            if self.which_projects_dir(pfile):
                self.close_project(project)
                os.unlink(self.project_file_name(project))
                os.unlink(self.project_workspace(project))
            else:
                for pdir in self.projects_fpath:
                    j = Jfile(os.path.join(pdir, "library.json"))
                    data = j.load([])
                    if pfile in data:
                        data.remove(pfile)
                        j.save(data)

    def edit_project(self, project):
        def on_open():
            self.window.open_file(self.project_file_name(project))
        sublime.set_timeout_async(on_open, 100)

    def rename_project(self, project):
        def on_rename(new_project):
            if project == new_project:
                return
            pfile = self.project_file_name(project)
            wsfile = self.project_workspace(project)
            pdir = self.which_projects_dir(pfile)
            if not pdir:
                pdir = os.path.dirname(pfile)
            new_pfile = os.path.join(pdir, "%s.sublime-project" % new_project)
            new_wsfile = new_pfile.replace(".sublime-project", ".sublime-workspace")

            reopen = self.close_project(project)
            os.rename(pfile, new_pfile)
            os.rename(wsfile, new_wsfile)

            j = Jfile(new_wsfile)
            data = j.load({})
            if "project" in data:
                data["project"] = "%s.sublime-project" % os.path.basename(new_project)
            j.save(data)

            if not self.which_projects_dir(pfile):
                for pdir in self.projects_fpath:
                    j = Jfile(os.path.join(pdir, "library.json"))
                    data = j.load([])
                    if pfile in data:
                        data.remove(pfile)
                        data.append(new_pfile)
                        j.save(data)

            if reopen:
                # reload projects info
                self.__init__(self.window)
                self.open_in_new_window(new_project)

        v = self.window.show_input_panel("New project name:", project, on_rename, None, None)
        v.run_command("select_all")

class ProjectManager(sublime_plugin.WindowCommand):

    def show_quick_panel(self, items, on_done):
        sublime.set_timeout(
            lambda: self.window.show_quick_panel(items, on_done),
            10)

    def run(self, action=None):
        self.manager = Manager(self.window)
        self.projects, display = self.manager.display_projects()
        self.options = [
            ["[-] Project Manager", "More options"],
            ["[-] Add Project", "Add Project to Project Manager"],
            ["[-] Import .sublime-project", "Import .sublime-project file"]
        ]
        if action is not None:
            sublime.set_timeout(lambda: self.on_open(action), 10)
        else:
            self.show_quick_panel(self.options + display, self.on_open)

    def on_open(self, action):
        if action < 0:
            return

        elif action == 0:
            items = [
                ["Open Project in New Window", "Open project in a new window"],
                ["Append Project", "Append project to current window"],
                ["Edit Project", "Edit project settings"],
                ['Rename Project', "Rename project"],
                ["Remove Project", "Remove from Project Manager"]
            ]

            def callback(a):
                if a < 0:
                    sublime.set_timeout(self.run, 10)
                    return
                else:
                    actions = ["new", "append", "edit", "rename", "remove"]
                    self.window.run_command(
                        "project_manager_list",
                        args={"action": actions[a], "caller": "manager"}
                    )

            self.show_quick_panel(items, callback)

        elif action == 1:
            self.manager.add_project()

        elif action == 2:
            self.manager.import_sublime_project()

        elif action >= len(self.options):
            action = action-len(self.options)
            self.manager.switch_project(self.projects[action])

class ProjectManagerAddFolder(sublime_plugin.WindowCommand):

    def run(self):
        self.manager = Manager(self.window)
        self.manager.add_project()

class ProjectManagerList(sublime_plugin.WindowCommand):

    def show_quick_panel(self, items, on_done):
        sublime.set_timeout(
            lambda: self.window.show_quick_panel(items, on_done),
            10)

    def run(self, action, caller=None):
        self.caller = caller
        callback = eval("self.on_" + action)
        self.manager = Manager(self.window)
        self.projects, display = self.manager.display_projects()
        self.show_quick_panel(display, callback)

    def on_new(self, action):
        if action >= 0:
            self.manager.open_in_new_window(self.projects[action])
        elif action < 0:
            sublime.set_timeout(self.on_cancel, 10)

    def on_switch(self, action):
        if action >= 0:
            self.manager.switch_project(self.projects[action])
        elif action < 0:
            self.on_cancel()

    def on_append(self, action):
        if action >= 0:
            self.manager.append_project(self.projects[action])
        elif action < 0:
            self.on_cancel()

    def on_remove(self, action):
        if action >= 0:
            sublime.set_timeout(lambda: self.manager.remove_project(self.projects[action]),
                                10)
        elif action < 0:
            self.on_cancel()

    def on_edit(self, action):
        if action >= 0:
            self.manager.edit_project(self.projects[action])
        elif action < 0:
            self.on_cancel()

    def on_rename(self, action):
        if action >= 0:
            sublime.set_timeout(lambda: self.manager.rename_project(self.projects[action]),
                                10)
        elif action < 0:
            self.on_cancel()

    def on_cancel(self):
        if self.caller == "manager":
            self.window.run_command("project_manager", args={"action": 0})
<commit_msg>fix #22<commit_after>import sublime
import sublime_plugin
import subprocess
import os
import codecs
import platform

class Jfile:
    def __init__(self, fpath, encoding="utf-8"):
        self.encoding = encoding
        self.fpath = fpath

    def load(self, default=[]):
        self.fdir = os.path.dirname(self.fpath)
        if not os.path.isdir(self.fdir):
            os.makedirs(self.fdir)
        if os.path.exists(self.fpath):
            f = codecs.open(self.fpath, "r+", encoding=self.encoding)
            content = f.read()
            try:
                data = sublime.decode_value(content)
            except:
                data = default
            f.close()
        else:
            f = codecs.open(self.fpath, "w+", encoding=self.encoding)
            data = default
            f.close()
        return data

    def save(self, data, indent=4):
        self.fdir = os.path.dirname(self.fpath)
        if not os.path.isdir(self.fdir):
            os.makedirs(self.fdir)
        f = codecs.open(self.fpath, "w+", encoding=self.encoding)
        f.write(sublime.encode_value(data, True))
        f.close()

    def remove(self):
        if os.path.exists(self.fpath):
            os.remove(self.fpath)

def subl(args=[]):
    # learnt from SideBarEnhancements
    executable_path = sublime.executable_path()
    if sublime.platform() == 'osx':
        app_path = executable_path[:executable_path.rfind(".app/") + 5]
        executable_path = app_path + "Contents/SharedSupport/bin/subl"
    subprocess.Popen([executable_path] + args)

def pabs(folder, project_file):
    root = os.path.dirname(project_file)
    if not os.path.isabs(folder):
        folder = os.path.abspath(os.path.join(root, folder))
    return folder

def get_node():
    if sublime.platform() == "osx":
        node = subprocess.check_output(["scutil", "--get", "ComputerName"]).decode().strip()
    else:
        node = platform.node().split(".")[0]
    return node

class Manager:
    def __init__(self, window):
        self.window = window
        settings_file = 'pm.sublime-settings'
        self.settings = sublime.load_settings(settings_file)
        default_projects_dir = os.path.join(sublime.packages_path(), "User", "Projects")
        self.projects_fpath = self.settings.get(
            "projects_fpath", [self.settings.get("projects_dir", default_projects_dir)])

        node = get_node()
        if self.settings.get("use_local_projects_dir", False):
            self.projects_fpath = \
                [d + " - " + node for d in self.projects_fpath] + self.projects_fpath

        self.primary_dir = self.projects_fpath[0]
        self.projects_info = self.get_projects_info()

    def get_projects_info(self):
        ret = {}
        for pdir in self.projects_fpath:
            pfiles = []
            j = Jfile(os.path.join(pdir, "library.json"))
            for f in j.load([]):
                if os.path.exists(f) and f not in pfiles:
                    pfiles.append(f)
            pfiles.sort()
            j.save(pfiles)
            for path, dirs, files in os.walk(pdir):
                for f in files:
                    f = os.path.join(path, f)
                    if f.endswith(".sublime-project") and f not in pfiles:
                        pfiles.append(f)
                # remove empty directories
                for d in dirs:
                    d = os.path.join(path, d)
                    if len(os.listdir(d)) == 0:
                        os.rmdir(d)

        for f in pfiles:
            pdir = self.which_projects_dir(f)
            if pdir:
                pname = os.path.relpath(f, pdir).replace(".sublime-project", "")
            else:
                pname = os.path.basename(f).replace(".sublime-project", "")
            pd = Jfile(f).load()
            if pd and "folders" in pd and pd["folders"]:
                folder = pd["folders"][0].get("path", "")
            else:
                folder = ""
            star = False
            for w in sublime.windows():
                if w.project_file_name() == f:
                    star = True
                    break
            ret[pname] = {
                "folder": pabs(folder, f),
                "file": f,
                "star": star
            }
        return ret

    def which_projects_dir(self, pfile):
        for pdir in self.projects_fpath:
            if os.path.dirname(pfile).startswith(pdir+os.path.sep):
                return pdir
        return None

    def display_projects(self):
        ret = [[key, key + "*" if value["star"] else key, value["folder"]]
               for key, value in self.projects_info.items()]
        ret = sorted(ret)
        count = 0
        for i in range(len(ret)):
            if ret[i][0] is not ret[i][1]:
                ret.insert(count, ret.pop(i))
                count = count + 1
        return [[item[0] for item in ret], [[item[1], item[2]] for item in ret]]

    def project_file_name(self, project):
        return self.projects_info[project]["file"]

    def project_workspace(self, project):
        return self.project_file_name(project).replace(".sublime-project", ".sublime-workspace")

    def add_project(self):
        pd = self.window.project_data()
        if not pd:
            self.window.run_command("prompt_add_project")
            delay = 300
        else:
            delay = 1

        def on_add(project):
            pd = self.window.project_data()
            f = os.path.join(self.primary_dir, "%s.sublime-project" % project)
            Jfile(f).save(pd)
            Jfile(f.replace(".sublime-project", ".sublime-workspace")).save({})
            self.window.run_command("close_workspace")
            self.window.run_command("close_project")
            for v in self.window.views():
                if not v.is_dirty():
                    self.window.focus_view(v)
                    self.window.run_command("close")

            # reload projects info
            self.__init__(self.window)
            self.switch_project(project)

        def show_input_panel():
            pd = self.window.project_data()
            pf = self.window.project_file_name()
            if pd:
                if pf:
                    project = os.path.basename(pabs(pd["folders"][0]["path"], pf))
                else:
                    project = os.path.basename(pd["folders"][0]["path"])
                v = self.window.show_input_panel("Project name:", project, on_add, None, None)
                v.run_command("select_all")

        sublime.set_timeout(show_input_panel, delay)

    def import_sublime_project(self):
        pfile = self.window.project_file_name()
        if not pfile:
            sublime.message_dialog("Project file not found!")
            return
        if self.which_projects_dir(pfile):
            sublime.message_dialog("This project was created by Project Manager!")
            return
        ok = sublime.ok_cancel_dialog("Import %s?" % os.path.basename(pfile))
        if ok:
            j = Jfile(os.path.join(self.primary_dir, "library.json"))
            data = j.load([])
            if pfile not in data:
                data.append(pfile)
                j.save(data)

    def get_project_data(self, project):
        return Jfile(self.project_file_name(project)).load()

    def check_project(self, project):
        wsfile = self.project_workspace(project)
        if not os.path.exists(wsfile):
            Jfile(wsfile).save({})

    def close_project(self, project):
        for w in sublime.windows():
            if w.project_file_name() == self.project_file_name(project):
                w.run_command("close_workspace")
                w.run_command("close_window")
                return True
        return False

    def append_project(self, project):
        pd = self.get_project_data(project)
        paths = [pabs(f.get("path"), self.project_file_name(project)) for f in pd.get("folders")]
        subl(["-a"] + paths)

    def switch_project(self, project):
        self.window.run_command("close_workspace")
        self.check_project(project)
        if self.close_project(project):
            sublime.set_timeout_async(lambda: subl([self.project_file_name(project)]), 500)
            return

        if len(self.window.views()) == 0:
            sublime.set_timeout_async(lambda: subl([self.project_file_name(project)]), 500)
        else:
            sublime.set_timeout_async(lambda: subl(["-n", self.project_file_name(project)]), 500)

    def open_in_new_window(self, project):
        self.check_project(project)
        self.close_project(project)
        sublime.set_timeout_async(lambda: subl(["-n", self.project_file_name(project)]), 500)

    def remove_project(self, project):
        ok = sublime.ok_cancel_dialog("Remove project %s from Project Manager?" % project)
        if ok:
            pfile = self.project_file_name(project)
            if self.which_projects_dir(pfile):
                self.close_project(project)
                os.unlink(self.project_file_name(project))
                os.unlink(self.project_workspace(project))
            else:
                for pdir in self.projects_fpath:
                    j = Jfile(os.path.join(pdir, "library.json"))
                    data = j.load([])
                    if pfile in data:
                        data.remove(pfile)
                        j.save(data)

    def edit_project(self, project):
        def on_open():
            self.window.open_file(self.project_file_name(project))
        sublime.set_timeout_async(on_open, 100)

    def rename_project(self, project):
        def on_rename(new_project):
            if project == new_project:
                return
            pfile = self.project_file_name(project)
            wsfile = self.project_workspace(project)
            pdir = self.which_projects_dir(pfile)
            if not pdir:
                pdir = os.path.dirname(pfile)
            new_pfile = os.path.join(pdir, "%s.sublime-project" % new_project)
            new_wsfile = new_pfile.replace(".sublime-project", ".sublime-workspace")

            reopen = self.close_project(project)
            os.rename(pfile, new_pfile)
            os.rename(wsfile, new_wsfile)

            j = Jfile(new_wsfile)
            data = j.load({})
            if "project" in data:
                data["project"] = "%s.sublime-project" % os.path.basename(new_project)
            j.save(data)

            if not self.which_projects_dir(pfile):
                for pdir in self.projects_fpath:
                    j = Jfile(os.path.join(pdir, "library.json"))
                    data = j.load([])
                    if pfile in data:
                        data.remove(pfile)
                        data.append(new_pfile)
                        j.save(data)

            if reopen:
                # reload projects info
                self.__init__(self.window)
                self.open_in_new_window(new_project)

        v = self.window.show_input_panel("New project name:", project, on_rename, None, None)
        v.run_command("select_all")

class ProjectManager(sublime_plugin.WindowCommand):

    def show_quick_panel(self, items, on_done):
        sublime.set_timeout(
            lambda: self.window.show_quick_panel(items, on_done),
            10)

    def run(self, action=None):
        self.manager = Manager(self.window)
        self.projects, display = self.manager.display_projects()
        self.options = [
            ["[-] Project Manager", "More options"],
            ["[-] Add Project", "Add Project to Project Manager"],
            ["[-] Import .sublime-project", "Import .sublime-project file"]
        ]
        if action is not None:
            sublime.set_timeout(lambda: self.on_open(action), 10)
        else:
            self.show_quick_panel(self.options + display, self.on_open)

    def on_open(self, action):
        if action < 0:
            return

        elif action == 0:
            items = [
                ["Open Project in New Window", "Open project in a new window"],
                ["Append Project", "Append project to current window"],
                ["Edit Project", "Edit project settings"],
                ['Rename Project', "Rename project"],
                ["Remove Project", "Remove from Project Manager"]
            ]

            def callback(a):
                if a < 0:
                    sublime.set_timeout(self.run, 10)
                    return
                else:
                    actions = ["new", "append", "edit", "rename", "remove"]
                    self.window.run_command(
                        "project_manager_list",
                        args={"action": actions[a], "caller": "manager"}
                    )

            self.show_quick_panel(items, callback)

        elif action == 1:
            self.manager.add_project()

        elif action == 2:
            self.manager.import_sublime_project()

        elif action >= len(self.options):
            action = action-len(self.options)
            self.manager.switch_project(self.projects[action])

class ProjectManagerAddFolder(sublime_plugin.WindowCommand):

    def run(self):
        self.manager = Manager(self.window)
        self.manager.add_project()

class ProjectManagerList(sublime_plugin.WindowCommand):

    def show_quick_panel(self, items, on_done):
        sublime.set_timeout(
            lambda: self.window.show_quick_panel(items, on_done),
            10)

    def run(self, action, caller=None):
        self.caller = caller
        callback = eval("self.on_" + action)
        self.manager = Manager(self.window)
        self.projects, display = self.manager.display_projects()
        self.show_quick_panel(display, callback)

    def on_new(self, action):
        if action >= 0:
            self.manager.open_in_new_window(self.projects[action])
        elif action < 0:
            sublime.set_timeout(self.on_cancel, 10)

    def on_switch(self, action):
        if action >= 0:
            self.manager.switch_project(self.projects[action])
        elif action < 0:
            self.on_cancel()

    def on_append(self, action):
        if action >= 0:
            self.manager.append_project(self.projects[action])
        elif action < 0:
            self.on_cancel()

    def on_remove(self, action):
        if action >= 0:
            sublime.set_timeout(lambda: self.manager.remove_project(self.projects[action]),
                                10)
        elif action < 0:
            self.on_cancel()

    def on_edit(self, action):
        if action >= 0:
            self.manager.edit_project(self.projects[action])
        elif action < 0:
            self.on_cancel()

    def on_rename(self, action):
        if action >= 0:
            sublime.set_timeout(lambda: self.manager.rename_project(self.projects[action]),
                                10)
        elif action < 0:
            self.on_cancel()

    def on_cancel(self):
        if self.caller == "manager":
            self.window.run_command("project_manager", args={"action": 0})
<|endoftext|>


<commit_before>#!/usr/bin/env python

import os
import os.path
import io
import re
import time
import shutil
import codecs
import logging
from datetime import datetime
from multiprocessing import Process
from configparser import RawConfigParser
import baker
import markdown
import pystache

__author__ = "Alex Musayev"
__email__ = "alex.musayev@gmail.com"
__copyright__ = "Copyright 2012, %s <http://alex.musayev.com>" % __author__
__license__ = "MIT"
__version_info__ = (0, 2, 0)
__version__ = ".".join(map(str, __version_info__))
__status__ = "Development"
__url__ = "http://github.com/dreikanter/public-static"

SCRIPT_NAME = os.path.splitext(os.path.basename(__file__))[0]
DEFAULT_CONF = "%s.ini" % SCRIPT_NAME
DEFAULT_LOG = "%s.log" % SCRIPT_NAME

CONF = {
    # Default port value (overridable with command line param)
    'port': '8000',

    # Amount of seconds between starting local web server
    # and opening a browser
    'browser_opening_delay': '2.0',

    'pages_path': './pages',
    'static_path': './static',
    'build_path': './www',
    'templates_path': './templates',

    # Default template neme (overridable with page header 'template' parameter)
    'template': 'default',

    # Default author name (overridable with page header 'author' parmeter)
    'author': '',

    'minify_js': 'y',
    'minify_css': 'y',

    # Minification command templates for str.format() function.
    # {source} is used in both for source file and {dest} is for processed result.
    'minify_js_cmd': "yuicompressor --type js --nomunge -o {dest} {source}",
    'minify_css_cmd': "yuicompressor --type css -o {dest} {source}",

    'publish_cmd': '',
    'generator': "{name} {version}",
}

COMMON_PARAMS = {
    "config": "Configuration file",
    "section": "Configuration file section",
    "logfile": "Log file",
    "verbose": "Enable detailed logging"
}

COMMON_SHORTOPS = {
    "config": "c",
    "section": "s",
    "logfile": "l",
    "verbose": "v"
}

TRUE_VALUES = ['1', 'true', 'yes', 'y']
TEMPLATE_FILE_NAME = "%s.mustache.html"
LOG_CONSOLE_FORMAT = ('%(asctime)s %(levelname)s: %(message)s', '%H:%M:%S')
LOG_FILE_FORMAT = ('%(asctime)s %(levelname)s: %(message)s', '%Y/%m/%d %H:%M:%S')
TIME_FORMAT = "%Y/%m/%d %H:%M:%S"
RE_FLAGS = re.I | re.M | re.U
PARAM_PATTERN = re.compile(r"^\s*([\w\d_-]+)\s*[:=]{1}(.*)", RE_FLAGS)
MD = markdown.Markdown(extensions=['nl2br', 'grid'])

log = logging.getLogger(SCRIPT_NAME)
conf = {}

# Initialization =============================================================

def init(conf_file, section, log_file, verbose=False):
    """Gets the configuration values or termanates execution in case of errors"""
    init_logging(log_file, verbose)

    try:
        global conf
        conf = CONF
        log.info("Using configuration from %s [%s]" % (conf_file, section))

        conf.update(get_params(conf_file, section))
        purify_conf()
        verify_conf()

        # Dumping configuration to debug log
        for param in conf:
            log.debug("%s = [%s]" % (param, conf[param]))
    except Exception as e:
        log.exception("Error reading configuration")
        log.info("Use --help parameter for command line help")
        exit(1)

def init_logging(log_file, verbose):
    try:
        global log
        log.setLevel(logging.DEBUG)

        channel = logging.StreamHandler()
        channel.setLevel(logging.DEBUG if verbose else logging.INFO)
        channel.setFormatter(logging.Formatter(LOG_CONSOLE_FORMAT[0], LOG_CONSOLE_FORMAT[1]))
        log.addHandler(channel)

        if log_file:
            dir_path = os.path.dirname(log_file)
            if dir_path:
                ensure_dir_exists(dir_path)
            channel = logging.FileHandler(log_file)
            channel.setLevel(logging.DEBUG)
            channel.setFormatter(logging.Formatter(LOG_FILE_FORMAT[0], LOG_FILE_FORMAT[1]))
            log.addHandler(channel)
    except Exception as e:
        print("Error initializing loggign: " + str(e))
        exit(1)

def purify_conf():
    """Updates configuration parameters requiring processing."""
    conf['pages_path'] = os.path.abspath(conf['pages_path'])
    conf['static_path'] = os.path.abspath(conf['static_path'])
    conf['build_path'] = os.path.abspath(conf['build_path'])
    conf['templates_path'] = os.path.abspath(conf['templates_path'])
    conf['browser_opening_delay'] = float(conf['browser_opening_delay'])
    conf['generator'] = conf['generator'].strip().format(name=SCRIPT_NAME, version=__version__)
    conf['minify_js'] = get_bool(conf['minify_js'])
    conf['minify_css'] = get_bool(conf['minify_css'])
    conf['minify_js_cmd'] = conf['minify_js_cmd'].strip()
    conf['minify_css_cmd'] = conf['minify_css_cmd'].strip()
    conf['publish_cmd'] = conf['publish_cmd'].strip()
    conf['port'] = int(conf['port'])

def verify_conf():
    """Checks if configuration is correct."""
    if conf['minify_js'] and not conf['minify_js_cmd']:
        log.warn("JS minification enabled but [minify_js_cmd] is not defined by configuration.")
    if conf['minify_css'] and not conf['minify_css_cmd']:
        log.warn("CSS minification enabled but [minify_css_cmd] is not defined by configuration.")
    if not conf['publish_cmd']:
        log.warn("Publishing command (publish_cmd) is not defined by configuration.")

# Website building ============================================================

def process_files():
    """Walk through source files and process one by one."""
    process_dir("static files", conf['static_path'])
    process_dir("pages", conf['pages_path'])

def process_dir(message, source_root):
    log.info("Processing %s from [%s]..." % (message, source_root))

    for cur_dir, dirs, files in os.walk(source_root):
        rel_path = cur_dir[len(source_root):].strip("\\/")
        dest_path = os.path.join(conf['build_path'], rel_path)
        ensure_dir_exists(dest_path)

        for file_name in files:
            process_file(source_root, os.path.join(cur_dir, file_name))

def process_file(source_root, source_file):
    """Process single file."""
    rel_source = os.path.relpath(source_file, source_root)
    base, ext = os.path.splitext(rel_source)
    rel_dest = base + ('.html' if ext == '.md' else ext)
    dest_file = os.path.join(conf['build_path'], rel_dest)

    if ext == '.md':
        log.info(" * Building page: %s => %s" % (rel_source, rel_dest))
        build_page(source_file, dest_file, conf['templates_path'])

    elif ext == '.css' and conf['minify_css'] and conf['minify_css_cmd']:
        log.info(' * Minifying CSS: ' + rel_source)
        execute(conf['minify_css_cmd'].format(source=source_file, dest=dest_file))

    elif ext == '.js' and conf['minify_js'] and conf['minify_js_cmd']:
        log.info(' * Minifying JS: ' + rel_source)
        execute(conf['minify_js_cmd'].format(source=source_file, dest=dest_file))

    else:
        log.info(' * Copying: ' + rel_source)
        shutil.copyfile(source_file, dest_file)

def build_page(source_file, dest_file, templates_path):
    """Builds a page from markdown source amd mustache template."""
    try:
        page = read_page_source(source_file)
        with codecs.open(dest_file, mode='w', encoding='utf8') as f:
            f.write(pystache.render(get_template(page['template'], templates_path), page))
    except Exception as e:
        log.exception("Content processing error")

def read_page_source(source_file):
    """Reads a page file to dictionary.

    TODO: Describe page format here."""
    try:
        page = {}
        with codecs.open(source_file, mode='r', encoding='utf8') as f:
            # Extract page metadata if there are some header lines
            lines = f.readlines()
            for num, line in enumerate(lines):
                match = PARAM_PATTERN.match(line)
                if match:
                    page[match.group(1)] = match.group(2).strip()
                else:
                    page['content'] = ''.join(lines[num:])
                    break

        page['title'] = page.get('title', get_md_h1(page['content'])).strip()
        page['template'] = page.get('template', conf['template']).strip()
        page['author'] = page.get('author', conf['author']).strip()
        page['content'] = MD.convert(page.get('content', '').strip())

        # Take date/time from file system if not explicitly defined
        purify_time(page, 'ctime', os.path.getctime(source_file))
        purify_time(page, 'mtime', os.path.getmtime(source_file))

        return page

    except Exception as e:
        log.exception("Page source parsing error [%s]" % source_file)
        return {}

def get_template(tpl_name, templates_path):
    file_name = os.path.join(templates_path, TEMPLATE_FILE_NAME % tpl_name)
    if os.path.exists(file_name):
        with codecs.open(file_name, mode='r', encoding='utf8') as f:
            return f.read()

    raise Exception("Error reading template: %s (%s)" % (tpl_name, file_name))

# General helpers =============================================================

def get_params(conf_file, section):
    print("Configuration: %s [%s]" % (conf_file, section or "default"))

    parser = RawConfigParser()
    with codecs.open(conf_file, mode='r', encoding='utf8') as f:
        parser.readfp(f)

    if section and not section in parser.sections():
        raise Exception("%s not found" % (("section [%s]" % section) if section else "first section"))

    try:
        section = section if section else parser.sections()[0]
        return {item[0]: item[1] for item in parser.items(section)}
    except:
        raise Exception(("section [%s] not found" % section) if section else "no sections defined")

def get_bool(bool_str):
    return True if bool_str.lower() in TRUE_VALUES else False

def get_pwd(pwd_str):
    file_prefix = 'file://'
    if pwd_str.startswith(file_prefix):
        with open(pwd_str[len(file_prefix):], 'rt') as f:
            return f.readline().strip()
    return pwd_str

def joind(d1, d2):
    """Joins two dictionaries"""
    return dict(d1.items() + d2.items())

def ensure_dir_exists(dir_path):
    """Creates directory if it not exists"""
    if not os.path.exists(dir_path):
        os.makedirs(dir_path)

def execute(cmd):
    """Execute system command."""
    try:
        log.debug("Executing '%s'" % cmd)
        os.system(cmd)

    except Exception as e:
        print("Error executing system command: " + str(e))

def delayed_execute(cmd, delay):
    """This function intended to execute system command asyncronously."""
    time.sleep(delay)
    execute(cmd)

def check_build_is_done(build_path):
    """Check if the web content was built and exit if it isn't."""
    if not os.path.isdir(build_path):
        log.exception("Web content directory not exists: [%s]" % build_path)
        exit(1)

def drop_build_dir(build_path, create_new=False):
    """Drops the build if it exists."""
    if os.path.isdir(build_path):
        shutil.rmtree(build_path, ignore_errors=True)
    if create_new and not os.path.isdir(build_path):
        os.makedirs(build_path)

def get_md_h1(text):
    """Extracts the first h1-header from markdown text."""
    matches = re.search(r"^\s*#\s*(.*)\s*", text, RE_FLAGS)
    return matches.group(1) if matches else ""

def purify_time(page, time_parm, default):
    """Returns time value from page dict. If there is no
    specified value, default will be returned."""
    if time_parm in page:
        page[time_parm] = time.strptime(page[time_parm], TIME_FORMAT)
    else:
        page[time_parm] = datetime.fromtimestamp(default)

# Baker commands ==============================================================

@baker.command(shortopts=COMMON_SHORTOPS, params=COMMON_PARAMS, default=True)
def build(config=DEFAULT_CONF, section=None, logfile=DEFAULT_LOG, verbose=False):
    """Generate web content"""
    init(config, section, logfile, verbose)

    try:
        drop_build_dir(conf['build_path'])
        log.info("Building path: [%s]" % conf['build_path'])
        process_files()
        log.info("Done")
    except Exception as e:
        log.exception(e)

@baker.command(shortopts=joind(COMMON_SHORTOPS, {"browse": "b", "port": "p"}),
               params=joind(COMMON_PARAMS, {"browse": "Open in default browser", "port": "Port for local HTTP server"}))
def preview(config=DEFAULT_CONF, section=None, logfile=DEFAULT_LOG, verbose=False, browse=False, port=None):
    """Run local web server to preview generated web site"""
    init(config, section, logfile, verbose)

    check_build_is_done(conf['build_path'])
    prev_cwd = os.getcwd()
    os.chdir(conf['build_path'])
    port = port or conf['port']
    log.info("Running HTTP server on port %d..." % port)

    try:
        import SimpleHTTPServer
        import SocketServer

        handler = SimpleHTTPServer.SimpleHTTPRequestHandler
        httpd = SocketServer.TCPServer(("", port), handler)

        if browse:
            cmd = conf['run_browser_cmd'].format(url=("http://localhost:%s/" % port))
            log.info("Opening browser in %g seconds. Command: [%s]" % (conf['browser_opening_delay'], cmd))
            log.info("Use Ctrl-Break to stop webserver")
            p = Process(target=delayed_execute, args=(cmd, conf['browser_opening_delay']))
            p.start()

        httpd.serve_forever()

    except KeyboardInterrupt:
        log.info("Server was stopped by user")
    finally:
        os.chdir(prev_cwd)

# TODO: Add --dry-run mode.
@baker.command(shortopts=COMMON_SHORTOPS, params=COMMON_PARAMS)
def publish(config=DEFAULT_CONF, section=None, logfile=DEFAULT_LOG, verbose=False):
    """Synchronize remote web server with generated content."""
    init(config, section, logfile, verbose)
    check_build_is_done(conf['build_path'])

    if conf['publish_cmd']:
        try:
            log.info("Publishing...")
            execute(conf['publish_cmd'].format(path=conf['build_path']))
            log.info("Done")
        except Exception as e:
            log.exception("Publishing error")
    else:
        log.error("Publishing command (publish_cmd) is not defined by configuration")

@baker.command(shortopts=COMMON_SHORTOPS, params=COMMON_PARAMS)
def clean(config=DEFAULT_CONF, section=None, logfile=DEFAULT_LOG, verbose=False):
    """Delete all generated web content"""
    init(config, section, logfile, verbose)

    try:
        log.info("Cleaning output...")
        drop_build_dir(conf['build_path'])
        log.info("Done")
    except Exception as e:
        log.exception(e)

if __name__ == '__main__':
    try:
        baker.run()
    except Exception as e:
        print("Error: " + str(e))
        exit(1)
<commit_msg>Minor updates and cleanup.<commit_after>#!/usr/bin/env python

import os
import os.path
import io
import re
import time
import shutil
import codecs
import logging
from datetime import datetime
from multiprocessing import Process
from configparser import RawConfigParser
import baker
import markdown
import pystache

__author__ = "Alex Musayev"
__email__ = "alex.musayev@gmail.com"
__copyright__ = "Copyright 2012, %s <http://alex.musayev.com>" % __author__
__license__ = "MIT"
__version_info__ = (0, 2, 0)
__version__ = ".".join(map(str, __version_info__))
__status__ = "Development"
__url__ = "http://github.com/dreikanter/public-static"

SCRIPT_NAME = os.path.splitext(os.path.basename(__file__))[0]
DEFAULT_CONF = "%s.ini" % SCRIPT_NAME
DEFAULT_LOG = "%s.log" % SCRIPT_NAME

CONF = {
    # Default port value (overridable with command line param)
    'port': '8000',

    # Amount of seconds between starting local web server
    # and opening a browser
    'browser_opening_delay': '2.0',

    'pages_path': './pages',
    'static_path': './static',
    'build_path': './www',
    'templates_path': './templates',

    # Default template neme (overridable with page header 'template' parameter)
    'template': 'default',

    # Default author name (overridable with page header 'author' parmeter)
    'author': '',

    'minify_js': 'y',
    'minify_css': 'y',

    # Minification command templates for str.format() function.
    # {source} is used in both for source file and {dest} is for processed result.
    'minify_js_cmd': "yuicompressor --type js --nomunge -o {dest} {source}",
    'minify_css_cmd': "yuicompressor --type css -o {dest} {source}",

    'publish_cmd': '',
    'generator': "{name} {version}",
}

COMMON_PARAMS = {
    "config": "Configuration file",
    "section": "Configuration file section",
    "logfile": "Log file",
    "verbose": "Enable detailed logging"
}

COMMON_SHORTOPS = {
    "config": "c",
    "section": "s",
    "logfile": "l",
    "verbose": "v"
}

TRUE_VALUES = ['1', 'true', 'yes', 'y']
TEMPLATE_FILE_NAME = "%s.mustache.html"
LOG_CONSOLE_FORMAT = ('%(asctime)s %(levelname)s: %(message)s', '%H:%M:%S')
LOG_FILE_FORMAT = ('%(asctime)s %(levelname)s: %(message)s', '%Y/%m/%d %H:%M:%S')
TIME_FORMAT = "%Y/%m/%d %H:%M:%S"
RE_FLAGS = re.I | re.M | re.U
PARAM_PATTERN = re.compile(r"^\s*([\w\d_-]+)\s*[:=]{1}(.*)", RE_FLAGS)
MD = markdown.Markdown(extensions=['nl2br', 'grid'])

log = logging.getLogger(SCRIPT_NAME)
conf = {}

# Initialization =============================================================

def init(conf_file, section, log_file, verbose=False):
    """Gets the configuration values."""
    init_logging(log_file, verbose)

    try:
        global conf
        conf = CONF
        log.info("Using configuration from %s [%s]" % (conf_file, section))

        conf.update(get_params(conf_file, section))
        purify_conf()
        verify_conf()

        from pprint import pprint
        pprint(conf)

        # Dumping configuration to debug log
        for param in conf:
            log.debug("%s = [%s]" % (param, conf[param]))
    except Exception as e:
        log.exception("Error reading configuration")
        log.info("Use --help parameter for command line help")
        exit(1)

def init_logging(log_file, verbose):
    try:
        global log
        log.setLevel(logging.DEBUG)

        channel = logging.StreamHandler()
        channel.setLevel(logging.DEBUG if verbose else logging.INFO)
        fmt = logging.Formatter(LOG_CONSOLE_FORMAT[0], LOG_CONSOLE_FORMAT[1])
        channel.setFormatter(fmt)
        log.addHandler(channel)

        if log_file:
            ensure_dir_exists(os.path.dirname(log_file))
            channel = logging.FileHandler(log_file)
            channel.setLevel(logging.DEBUG)
            fmt = logging.Formatter(LOG_FILE_FORMAT[0], LOG_FILE_FORMAT[1])
            channel.setFormatter(fmt)
            log.addHandler(channel)
    except Exception as e:
        print("Error initializing loggign: " + str(e))
        exit(1)

def purify_conf():
    """Updates configuration parameters requiring processing."""
    conf['pages_path'] = os.path.abspath(conf['pages_path'])
    conf['static_path'] = os.path.abspath(conf['static_path'])
    conf['build_path'] = os.path.abspath(conf['build_path'])
    conf['templates_path'] = os.path.abspath(conf['templates_path'])
    conf['browser_opening_delay'] = float(conf['browser_opening_delay'])
    conf['generator'] = conf['generator'].strip().format(name=SCRIPT_NAME, version=__version__)
    conf['minify_js'] = get_bool(conf['minify_js'])
    conf['minify_css'] = get_bool(conf['minify_css'])
    conf['minify_js_cmd'] = conf['minify_js_cmd'].strip()
    conf['minify_css_cmd'] = conf['minify_css_cmd'].strip()
    conf['publish_cmd'] = conf['publish_cmd'].strip()
    conf['port'] = int(conf['port'])

def verify_conf():
    """Checks if configuration is correct."""
    if conf['minify_js'] and not conf['minify_js_cmd']:
        log.warn("JS minification enabled but [minify_js_cmd] is not defined by configuration.")
    if conf['minify_css'] and not conf['minify_css_cmd']:
        log.warn("CSS minification enabled but [minify_css_cmd] is not defined by configuration.")
    if not conf['publish_cmd']:
        log.warn("Publishing command (publish_cmd) is not defined by configuration.")

# Website building ============================================================

def process_files():
    """Walk through source files and process one by one."""
    process_dir("static files", conf['static_path'])
    process_dir("pages", conf['pages_path'])

def process_dir(message, source_root):
    log.info("Processing %s from [%s]..." % (message, source_root))

    for cur_dir, dirs, files in os.walk(source_root):
        rel_path = cur_dir[len(source_root):].strip("\\/")
        dest_path = os.path.join(conf['build_path'], rel_path)
        ensure_dir_exists(dest_path)

        for file_name in files:
            process_file(source_root, os.path.join(cur_dir, file_name))

def process_file(source_root, source_file):
    """Process single file."""
    rel_source = os.path.relpath(source_file, source_root)
    base, ext = os.path.splitext(rel_source)
    rel_dest = base + ('.html' if ext == '.md' else ext)
    dest_file = os.path.join(conf['build_path'], rel_dest)

    if ext == '.md':
        log.info(" * Building page: %s => %s" % (rel_source, rel_dest))
        build_page(source_file, dest_file, conf['templates_path'])

    elif ext == '.css' and conf['minify_css'] and conf['minify_css_cmd']:
        log.info(' * Minifying CSS: ' + rel_source)
        execute(conf['minify_css_cmd'].format(source=source_file, dest=dest_file))

    elif ext == '.js' and conf['minify_js'] and conf['minify_js_cmd']:
        log.info(' * Minifying JS: ' + rel_source)
        execute(conf['minify_js_cmd'].format(source=source_file, dest=dest_file))

    else:
        log.info(' * Copying: ' + rel_source)
        shutil.copyfile(source_file, dest_file)

def build_page(source_file, dest_file, templates_path):
    """Builds a page from markdown source amd mustache template."""
    try:
        page = read_page_source(source_file)
        with codecs.open(dest_file, mode='w', encoding='utf8') as f:
            f.write(pystache.render(get_template(page['template'], templates_path), page))
    except Exception as e:
        log.exception("Content processing error")

def read_page_source(source_file):
    """Reads a page file to dictionary.

    TODO: Describe page format here."""
    try:
        page = {}
        with codecs.open(source_file, mode='r', encoding='utf8') as f:
            # Extract page metadata if there are some header lines
            lines = f.readlines()
            for num, line in enumerate(lines):
                match = PARAM_PATTERN.match(line)
                if match:
                    page[match.group(1)] = match.group(2).strip()
                else:
                    page['content'] = ''.join(lines[num:])
                    break

        page['title'] = page.get('title', get_md_h1(page['content'])).strip()
        page['template'] = page.get('template', conf['template']).strip()
        page['author'] = page.get('author', conf['author']).strip()
        page['content'] = MD.convert(page.get('content', '').strip())

        # Take date/time from file system if not explicitly defined
        purify_time(page, 'ctime', os.path.getctime(source_file))
        purify_time(page, 'mtime', os.path.getmtime(source_file))

        return page

    except Exception as e:
        log.exception("Page source parsing error [%s]" % source_file)
        return {}

def get_template(tpl_name, templates_path):
    file_name = os.path.join(templates_path, TEMPLATE_FILE_NAME % tpl_name)
    if os.path.exists(file_name):
        with codecs.open(file_name, mode='r', encoding='utf8') as f:
            return f.read()

    raise Exception("Error reading template: %s (%s)" % (tpl_name, file_name))

# General helpers =============================================================

def get_params(conf_file, section):
    print("Configuration: %s [%s]" % (conf_file, section or "default"))

    parser = RawConfigParser()
    with codecs.open(conf_file, mode='r', encoding='utf8') as f:
        parser.readfp(f)

    if section and not section in parser.sections():
        raise Exception("%s not found" % (("section [%s]" % section) if section else "first section"))

    try:
        section = section if section else parser.sections()[0]
        return {item[0]: item[1] for item in parser.items(section)}
    except:
        raise Exception(("section [%s] not found" % section) if section else "no sections defined")

def get_bool(bool_str):
    return True if bool_str.lower() in TRUE_VALUES else False

def get_pwd(pwd_str):
    file_prefix = 'file://'
    if pwd_str.startswith(file_prefix):
        with open(pwd_str[len(file_prefix):], 'rt') as f:
            return f.readline().strip()
    return pwd_str

def joind(d1, d2):
    """Joins two dictionaries"""
    return dict(d1.items() + d2.items())

def ensure_dir_exists(dir_path):
    """Creates directory if it not exists"""
    if dir_path and not os.path.exists(dir_path):
        os.makedirs(dir_path)

def execute(cmd):
    """Execute system command."""
    try:
        log.debug("Executing '%s'" % cmd)
        os.system(cmd)

    except Exception as e:
        print("Error executing system command: " + str(e))

def delayed_execute(cmd, delay):
    """This function intended to execute system command asyncronously."""
    time.sleep(delay)
    execute(cmd)

def check_build_is_done(build_path):
    """Check if the web content was built and exit if it isn't."""
    if not os.path.isdir(build_path):
        log.exception("Web content directory not exists: [%s]" % build_path)
        exit(1)

def drop_build_dir(build_path, create_new=False):
    """Drops the build if it exists."""
    if os.path.isdir(build_path):
        shutil.rmtree(build_path, ignore_errors=True)
    if create_new and not os.path.isdir(build_path):
        os.makedirs(build_path)

def get_md_h1(text):
    """Extracts the first h1-header from markdown text."""
    matches = re.search(r"^\s*#\s*(.*)\s*", text, RE_FLAGS)
    return matches.group(1) if matches else ""

def purify_time(page, time_parm, default):
    """Returns time value from page dict. If there is no
    specified value, default will be returned."""
    if time_parm in page:
        page[time_parm] = time.strptime(page[time_parm], TIME_FORMAT)
    else:
        page[time_parm] = datetime.fromtimestamp(default)

# Baker commands ==============================================================

@baker.command(shortopts=COMMON_SHORTOPS, params=COMMON_PARAMS, default=True)
def build(config=DEFAULT_CONF, section=None, logfile=DEFAULT_LOG, verbose=False):
    """Generate web content"""
    init(config, section, logfile, verbose)

    try:
        drop_build_dir(conf['build_path'])
        log.info("Building path: [%s]" % conf['build_path'])
        process_files()
        log.info("Done")
    except Exception as e:
        log.exception(e)

@baker.command(shortopts=joind(COMMON_SHORTOPS, {"browse": "b", "port": "p"}),
               params=joind(COMMON_PARAMS, {"browse": "Open in default browser", "port": "Port for local HTTP server"}))
def preview(config=DEFAULT_CONF, section=None, logfile=DEFAULT_LOG, verbose=False, browse=False, port=None):
    """Run local web server to preview generated web site"""
    init(config, section, logfile, verbose)

    check_build_is_done(conf['build_path'])
    prev_cwd = os.getcwd()
    os.chdir(conf['build_path'])
    port = port or conf['port']
    log.info("Running HTTP server on port %d..." % port)

    try:
        import SimpleHTTPServer
        import SocketServer

        handler = SimpleHTTPServer.SimpleHTTPRequestHandler
        httpd = SocketServer.TCPServer(("", port), handler)

        if browse:
            cmd = conf['run_browser_cmd'].format(url=("http://localhost:%s/" % port))
            log.info("Opening browser in %g seconds. Command: [%s]" % (conf['browser_opening_delay'], cmd))
            log.info("Use Ctrl-Break to stop webserver")
            p = Process(target=delayed_execute, args=(cmd, conf['browser_opening_delay']))
            p.start()

        httpd.serve_forever()

    except KeyboardInterrupt:
        log.info("Server was stopped by user")
    finally:
        os.chdir(prev_cwd)

# TODO: Add --dry-run mode.
@baker.command(shortopts=COMMON_SHORTOPS, params=COMMON_PARAMS)
def publish(config=DEFAULT_CONF, section=None, logfile=DEFAULT_LOG, verbose=False):
    """Synchronize remote web server with generated content."""
    init(config, section, logfile, verbose)
    check_build_is_done(conf['build_path'])

    if conf['publish_cmd']:
        try:
            log.info("Publishing...")
            execute(conf['publish_cmd'].format(path=conf['build_path']))
            log.info("Done")
        except Exception as e:
            log.exception("Publishing error")
    else:
        log.error("Publishing command (publish_cmd) is not defined by configuration")

@baker.command(shortopts=COMMON_SHORTOPS, params=COMMON_PARAMS)
def clean(config=DEFAULT_CONF, section=None, logfile=DEFAULT_LOG, verbose=False):
    """Delete all generated web content"""
    init(config, section, logfile, verbose)

    try:
        log.info("Cleaning output...")
        drop_build_dir(conf['build_path'])
        log.info("Done")
    except Exception as e:
        log.exception(e)

if __name__ == '__main__':
    try:
        baker.run()
    except Exception as e:
        print("Error: " + str(e))
        exit(1)
<|endoftext|>


<commit_before>#!/usr/bin/env python

import os, sys, argparse
from report import *
from show_report import *

def custom_filter(S):
    S = S.filter(lambda s: s.average >= 3.7 or '+p' in s.tags)
    S = S.filter(lambda s: not '+n' in s.tags)
    S = S.filter(lambda s: not '+C' in s.tags)
    S = S.filter(lambda s: not s.accepted)

    # Half talks
    #S = S.filter(lambda s: "half" in s.tags or "+C" in s.tags)
    #S = S.filter(lambda s: "+n" in s.tags)
    #S = S.filter(lambda s: "+p" in s.tags)

    return S

def add_custom_command(subparsers):
    def run(S, args):
        G = custom_filter(S)
        ids = map(lambda s: s.id, G.subs)
        not_lost = set([])
        lost = set([])
        for s in S.subs:
            is_lost = not s.id in ids
            if args.info_type == "tags":
                if is_lost:
                    lost.update(s.tags)
                else:
                    not_lost.update(s.tags)
            elif args.info_type == "projects":
                if is_lost:
                    lost.update(s.projects)
                else:
                    not_lost.update(s.projects)
            elif args.info_type == "companies":
                if is_lost:
                    lost.add(s.company)
                else:
                    not_lost.add(s.company)
            else:
                raise Exception("Unknown aggregate info, should be one of (tags/projects/companies)")

        for l in sorted(lost.difference(not_lost)):
            if l:
                print l

    parser_custom = subparsers.add_parser("custom")
    parser_custom.add_argument('info_type', metavar='INFO_TYPE', help='tags, projects, or companies')
    parser_custom.set_defaults(func=run)

def print_subs(S):
    S.print_subs()

def print_summary(S, min_vote):
    show_report(S, min_vote=min_vote)

def filter_min_vote_count(S, min_vote_count):
    return S.filter(lambda s: s.count >= min_vote_count)

def filter_min_vote(S, min_vote):
    return S.filter(lambda s: s.average >= min_vote)

def filter_max_vote(S, max_vote):
    return S.filter(lambda s: s.average < max_vote)

def add_all_command(subparsers):
    def run(S, args):
        return S
    parser_all = subparsers.add_parser("all")
    parser_all.set_defaults(func=run)

def add_tag_command(subparsers):
    def run(S, args):
        tags = args.tags
        merged = Submissions([])
        for tag in tags:
            merged = merged.union(S.find_tag(tag))
        return merged
    parser_tag = subparsers.add_parser("tag")
    parser_tag.add_argument('tags', metavar='TAGS', nargs='+',
                   help='Tags to query')
    parser_tag.set_defaults(func=run)

def add_tags_command(subparsers):
    def run(S, args):
        print "Tag          \t\tSubmission Count"

        for (tag, count) in sorted(S.tag_count().items(), key=lambda (x, _): x):
            if tag:
                print "%s\t\t%s" % (tag.ljust(20), count)

    parser_tags = subparsers.add_parser("tags")
    parser_tags.set_defaults(func=run)

def add_project_command(subparsers):
    def run(S, args):
        projects = args.projects
        merged = Submissions([])
        for project in projects:
            merged = merged.union(S.find_project(project))
        return merged
    parser_project = subparsers.add_parser("project")
    parser_project.add_argument('projects', metavar='PROJECTS', nargs='+',
                   help='Projects to query')
    parser_project.set_defaults(func=run)

def add_projects_command(subparsers):
    def run(S, args):
        print "Project      \t\tSubmission Count"

        for (project, count) in S.project_count().items():
            if project:
                print "%s\t\t%s" % (project.ljust(20), count)

    parser_project = subparsers.add_parser("projects")
    parser_project.set_defaults(func=run)

def add_language_command(subparsers):
    def run(S, args):
        languages = args.languages
        merged = Submissions([])
        for language in languages:
            merged = merged.union(S.find_language(language))
        return merged
    parser_language = subparsers.add_parser("language")
    parser_language.add_argument('languages', metavar='LANGUAGES', nargs='+',
                   help='Languages to query')
    parser_language.set_defaults(func=run)

def add_languages_command(subparsers):
    def run(S, args):
        print "Language      \t\tSubmission Count"

        for (language, count) in S.language_count().items():
            if language:
                print "%s\t\t%s" % (language.ljust(20), count)

    parser_language = subparsers.add_parser("languages")
    parser_language.set_defaults(func=run)

def add_track_command(subparsers):
    def run(S, args):
        tracks = args.tracks
        merged = Submissions([])
        for track in tracks:
            merged = merged.union(S.find_track(track))
        return merged
    parser_track = subparsers.add_parser("track")
    parser_track.add_argument('tracks', metavar='TRACKS', nargs='+',
                   help='Tracks to query')
    parser_track.set_defaults(func=run)

def add_tracks_command(subparsers):
    def run(S, args):
        print "Track      \t\tSubmission Count"

        for (track, count) in S.track_count().items():
            if track:
                print "%s\t\t%s" % (track.ljust(20), count)

    parser_track = subparsers.add_parser("tracks")
    parser_track.set_defaults(func=run)

def add_company_command(subparsers):
    def run(S, args):
        companys = args.companys
        merged = Submissions([])
        for company in companys:
            merged = merged.union(S.find_company(company))
        return merged
    parser_company = subparsers.add_parser("company")
    parser_company.add_argument('companys', metavar='COMPANYS', nargs='+',
                   help='Companys to query')
    parser_company.set_defaults(func=run)

def add_companies_command(subparsers):
    def run(S, args):
        print "Company Count\t\tSubmission Count"

        for (company, count) in S.company_count().items():
            if company:
                print "%s\t\t%s" % (company.ljust(20), count)

    parser_company = subparsers.add_parser("companies")
    parser_company.set_defaults(func=run)

def add_speaker_command(subparsers):
    def run(S, args):
        speakers = args.speakers
        merged = Submissions([])
        for speaker in speakers:
            merged = merged.union(S.find_speaker(speaker))
        return merged
    parser_speaker = subparsers.add_parser("speaker")
    parser_speaker.add_argument('speakers', metavar='SPEAKERS', nargs='+',
                   help='Speakers to query')
    parser_speaker.set_defaults(func=run)

def add_speakers_command(subparsers):
    def run(S, args):
        print "Speaker Count\t\tSubmission Count"

        for (speaker, count) in S.speaker_count().items():
            if speaker and count > 1:
                print "%s\t\t%s" % (speaker.ljust(20), count)

    parser_speaker = subparsers.add_parser("speakers")
    parser_speaker.set_defaults(func=run)

def add_id_command(subparsers):
    def run(S, args):
        return S.filter(lambda s: s.id in args.ids)
    parser_speaker = subparsers.add_parser("id")
    parser_speaker.add_argument('ids', metavar='IDS', nargs='+',
                   help='List of node ids to include')
    parser_speaker.set_defaults(func=run)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    # Filters
    parser.add_argument('-m', "--min", type=float, default=os.environ.get('FOSS4G_MIN_VOTE', 0.0), help="Minimum vote to consider (inclusive)")
    parser.add_argument('-M', "--max", type=float, default=5.1, help="Maximum vote to consider (non-inclusive)")
    parser.add_argument('-v', "--votecount", type=int, default=0, help="Minimum vote count from PC to consider.")

    # Actions
    parser.add_argument('-x', "--accepted", action='store_true')
    parser.add_argument('-o', "--open", action='store_true')
    parser.add_argument('-s', "--save", default="")
    parser.add_argument('-f', "--force", action='store_true')
    parser.add_argument('-a', "--all", action='store_true', help="Print each individual submission results (default for under 10 results).")
    parser.add_argument('-r', "--report", action='store_true', help="Print summary report (default for 10 or more results).")
    parser.add_argument('-t', "--tutorials", action='store_true', help="Show tutorials instead of standard talks.")
    parser.add_argument('-p', "--poc", action='store_true', help="Filter for isPOC.")
    parser.add_argument('-w', "--woman", action='store_true', help="Filter for isWoman.")
    parser.add_argument("--custom", action='store_true', help="Custom filter.")

    subparsers = parser.add_subparsers()

    # Add subparsers
    add_all_command(subparsers)
    add_custom_command(subparsers)
    add_tag_command(subparsers)
    add_tags_command(subparsers)
    add_project_command(subparsers)
    add_projects_command(subparsers)
    add_language_command(subparsers)
    add_languages_command(subparsers)
    add_track_command(subparsers)
    add_tracks_command(subparsers)
    add_company_command(subparsers)
    add_companies_command(subparsers)
    add_speaker_command(subparsers)
    add_speakers_command(subparsers)
    add_id_command(subparsers)

    args = parser.parse_args()

    # Filter submissions
    S = ALL
    if args.tutorials:
        S = S.tutorials()
    else:
        S = S.standard()

    if args.custom:
        S = custom_filter(S)
    else:
        S = filter_min_vote_count(S, args.votecount)
        S = filter_min_vote(S, args.min)
        S = filter_max_vote(S, args.max)

    if args.poc:
        S = S.filter(lambda x: x.isPOC)

    if args.woman:
        S = S.filter(lambda x: x.isWoman)

    if args.accepted:
        S = S.filter(lambda s: s.accepted)

    # Execute query type
    S = args.func(S, args)

    print map(lambda x: x.id, S.subs)

    # If we returned results, potentially do things to them
    if S:
      # Perform any actions
      if args.all or (len(S.subs) < 10 and not args.report):
          print_subs(S)
      else:
          print_summary(S, args.min)

      if args.save:
          S.save_subs(args.save)

      if args.open:
          S.open_links(args.force)
<commit_msg>Fix indentation warnings<commit_after>#!/usr/bin/env python

import os, sys, argparse
from report import *
from show_report import *

def custom_filter(S):
    S = S.filter(lambda s: s.average >= 3.7 or '+p' in s.tags)
    S = S.filter(lambda s: not '+n' in s.tags)
    S = S.filter(lambda s: not '+C' in s.tags)
    S = S.filter(lambda s: not s.accepted)

    # Half talks
    # S = S.filter(lambda s: "half" in s.tags or "+C" in s.tags)
    # S = S.filter(lambda s: "+n" in s.tags)
    # S = S.filter(lambda s: "+p" in s.tags)

    return S

def add_custom_command(subparsers):
    def run(S, args):
        G = custom_filter(S)
        ids = map(lambda s: s.id, G.subs)
        not_lost = set([])
        lost = set([])
        for s in S.subs:
            is_lost = not s.id in ids
            if args.info_type == "tags":
                if is_lost:
                    lost.update(s.tags)
                else:
                    not_lost.update(s.tags)
            elif args.info_type == "projects":
                if is_lost:
                    lost.update(s.projects)
                else:
                    not_lost.update(s.projects)
            elif args.info_type == "companies":
                if is_lost:
                    lost.add(s.company)
                else:
                    not_lost.add(s.company)
            else:
                raise Exception("Unknown aggregate info, should be one of (tags/projects/companies)")

        for l in sorted(lost.difference(not_lost)):
            if l:
                print l

    parser_custom = subparsers.add_parser("custom")
    parser_custom.add_argument('info_type', metavar='INFO_TYPE', help='tags, projects, or companies')
    parser_custom.set_defaults(func=run)

def print_subs(S):
    S.print_subs()

def print_summary(S, min_vote):
    show_report(S, min_vote=min_vote)

def filter_min_vote_count(S, min_vote_count):
    return S.filter(lambda s: s.count >= min_vote_count)

def filter_min_vote(S, min_vote):
    return S.filter(lambda s: s.average >= min_vote)

def filter_max_vote(S, max_vote):
    return S.filter(lambda s: s.average < max_vote)

def add_all_command(subparsers):
    def run(S, args):
        return S
    parser_all = subparsers.add_parser("all")
    parser_all.set_defaults(func=run)

def add_tag_command(subparsers):
    def run(S, args):
        tags = args.tags
        merged = Submissions([])
        for tag in tags:
            merged = merged.union(S.find_tag(tag))
        return merged
    parser_tag = subparsers.add_parser("tag")
    parser_tag.add_argument('tags', metavar='TAGS', nargs='+',
                   help='Tags to query')
    parser_tag.set_defaults(func=run)

def add_tags_command(subparsers):
    def run(S, args):
        print "Tag          \t\tSubmission Count"

        for (tag, count) in sorted(S.tag_count().items(), key=lambda (x, _): x):
            if tag:
                print "%s\t\t%s" % (tag.ljust(20), count)

    parser_tags = subparsers.add_parser("tags")
    parser_tags.set_defaults(func=run)

def add_project_command(subparsers):
    def run(S, args):
        projects = args.projects
        merged = Submissions([])
        for project in projects:
            merged = merged.union(S.find_project(project))
        return merged
    parser_project = subparsers.add_parser("project")
    parser_project.add_argument('projects', metavar='PROJECTS', nargs='+',
                   help='Projects to query')
    parser_project.set_defaults(func=run)

def add_projects_command(subparsers):
    def run(S, args):
        print "Project      \t\tSubmission Count"

        for (project, count) in S.project_count().items():
            if project:
                print "%s\t\t%s" % (project.ljust(20), count)

    parser_project = subparsers.add_parser("projects")
    parser_project.set_defaults(func=run)

def add_language_command(subparsers):
    def run(S, args):
        languages = args.languages
        merged = Submissions([])
        for language in languages:
            merged = merged.union(S.find_language(language))
        return merged
    parser_language = subparsers.add_parser("language")
    parser_language.add_argument('languages', metavar='LANGUAGES', nargs='+',
                   help='Languages to query')
    parser_language.set_defaults(func=run)

def add_languages_command(subparsers):
    def run(S, args):
        print "Language      \t\tSubmission Count"

        for (language, count) in S.language_count().items():
            if language:
                print "%s\t\t%s" % (language.ljust(20), count)

    parser_language = subparsers.add_parser("languages")
    parser_language.set_defaults(func=run)

def add_track_command(subparsers):
    def run(S, args):
        tracks = args.tracks
        merged = Submissions([])
        for track in tracks:
            merged = merged.union(S.find_track(track))
        return merged
    parser_track = subparsers.add_parser("track")
    parser_track.add_argument('tracks', metavar='TRACKS', nargs='+',
                   help='Tracks to query')
    parser_track.set_defaults(func=run)

def add_tracks_command(subparsers):
    def run(S, args):
        print "Track      \t\tSubmission Count"

        for (track, count) in S.track_count().items():
            if track:
                print "%s\t\t%s" % (track.ljust(20), count)

    parser_track = subparsers.add_parser("tracks")
    parser_track.set_defaults(func=run)

def add_company_command(subparsers):
    def run(S, args):
        companys = args.companys
        merged = Submissions([])
        for company in companys:
            merged = merged.union(S.find_company(company))
        return merged
    parser_company = subparsers.add_parser("company")
    parser_company.add_argument('companys', metavar='COMPANYS', nargs='+',
                   help='Companys to query')
    parser_company.set_defaults(func=run)

def add_companies_command(subparsers):
    def run(S, args):
        print "Company Count\t\tSubmission Count"

        for (company, count) in S.company_count().items():
            if company:
                print "%s\t\t%s" % (company.ljust(20), count)

    parser_company = subparsers.add_parser("companies")
    parser_company.set_defaults(func=run)

def add_speaker_command(subparsers):
    def run(S, args):
        speakers = args.speakers
        merged = Submissions([])
        for speaker in speakers:
            merged = merged.union(S.find_speaker(speaker))
        return merged
    parser_speaker = subparsers.add_parser("speaker")
    parser_speaker.add_argument('speakers', metavar='SPEAKERS', nargs='+',
                   help='Speakers to query')
    parser_speaker.set_defaults(func=run)

def add_speakers_command(subparsers):
    def run(S, args):
        print "Speaker Count\t\tSubmission Count"

        for (speaker, count) in S.speaker_count().items():
            if speaker and count > 1:
                print "%s\t\t%s" % (speaker.ljust(20), count)

    parser_speaker = subparsers.add_parser("speakers")
    parser_speaker.set_defaults(func=run)

def add_id_command(subparsers):
    def run(S, args):
        return S.filter(lambda s: s.id in args.ids)
    parser_speaker = subparsers.add_parser("id")
    parser_speaker.add_argument('ids', metavar='IDS', nargs='+',
                   help='List of node ids to include')
    parser_speaker.set_defaults(func=run)

if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    # Filters
    parser.add_argument('-m', "--min", type=float, default=os.environ.get('FOSS4G_MIN_VOTE', 0.0), help="Minimum vote to consider (inclusive)")
    parser.add_argument('-M', "--max", type=float, default=5.1, help="Maximum vote to consider (non-inclusive)")
    parser.add_argument('-v', "--votecount", type=int, default=0, help="Minimum vote count from PC to consider.")

    # Actions
    parser.add_argument('-x', "--accepted", action='store_true')
    parser.add_argument('-o', "--open", action='store_true')
    parser.add_argument('-s', "--save", default="")
    parser.add_argument('-f', "--force", action='store_true')
    parser.add_argument('-a', "--all", action='store_true', help="Print each individual submission results (default for under 10 results).")
    parser.add_argument('-r', "--report", action='store_true', help="Print summary report (default for 10 or more results).")
    parser.add_argument('-t', "--tutorials", action='store_true', help="Show tutorials instead of standard talks.")
    parser.add_argument('-p', "--poc", action='store_true', help="Filter for isPOC.")
    parser.add_argument('-w', "--woman", action='store_true', help="Filter for isWoman.")
    parser.add_argument("--custom", action='store_true', help="Custom filter.")

    subparsers = parser.add_subparsers()

    # Add subparsers
    add_all_command(subparsers)
    add_custom_command(subparsers)
    add_tag_command(subparsers)
    add_tags_command(subparsers)
    add_project_command(subparsers)
    add_projects_command(subparsers)
    add_language_command(subparsers)
    add_languages_command(subparsers)
    add_track_command(subparsers)
    add_tracks_command(subparsers)
    add_company_command(subparsers)
    add_companies_command(subparsers)
    add_speaker_command(subparsers)
    add_speakers_command(subparsers)
    add_id_command(subparsers)

    args = parser.parse_args()

    # Filter submissions
    S = ALL
    if args.tutorials:
        S = S.tutorials()
    else:
        S = S.standard()

    if args.custom:
        S = custom_filter(S)
    else:
        S = filter_min_vote_count(S, args.votecount)
        S = filter_min_vote(S, args.min)
        S = filter_max_vote(S, args.max)

    if args.poc:
        S = S.filter(lambda x: x.isPOC)

    if args.woman:
        S = S.filter(lambda x: x.isWoman)

    if args.accepted:
        S = S.filter(lambda s: s.accepted)

    # Execute query type
    S = args.func(S, args)

    print map(lambda x: x.id, S.subs)

    # If we returned results, potentially do things to them
    if S:
        # Perform any actions
        if args.all or (len(S.subs) < 10 and not args.report):
            print_subs(S)
        else:
            print_summary(S, args.min)

        if args.save:
            S.save_subs(args.save)

        if args.open:
            S.open_links(args.force)
<|endoftext|>


<commit_before>import bpy
from bpy.types import Panel
from . import (
	var,
	locale,
	previews,
	)

def icon_tria(prop):
	if prop:
		return 'TRIA_DOWN'
	else:
		return 'TRIA_RIGHT'

class UI:
	bl_category = 'JewelCraft'
	bl_space_type = 'VIEW_3D'
	bl_region_type = 'TOOLS'
	bl_context = 'objectmode'

	def __init__(self):
		prefs = bpy.context.user_preferences.addons[var.addon_id].preferences
		self.props = bpy.context.scene.jewelcraft
		self.l = locale.locale[prefs.lang]

class Gems(UI, Panel):
	bl_label = 'Gems'
	bl_idname = 'jewelcraft_import'

	def draw(self, context):
		layout = self.layout
		l = self.l
		icons = previews.preview_collections['icons']

		layout.template_icon_view(self.props, 'gem_cut', show_labels=True)

		col = layout.column(align=True)
		colrow = col.row(align=True)
		colrow.prop(self.props, 'gem_stone', text='')
		colrow.operator('jewelcraft.search_stone', text='', icon='VIEWZOOM')
		col.prop(self.props, 'gem_size', text=l['size'])
		col.operator('jewelcraft.make_gem', text=l['make_gem'])

		col = layout.column(align=True)
		colrow = col.row(align=True)
		colrow.label(l['gem'])
		colrow.operator('jewelcraft.replace_stone', text='', icon='COLOR')
		colrow.operator('jewelcraft.replace_cut', text='', icon_value=icons['TOOL-CUT'].icon_id)

		col = layout.column(align=True)
		colrow = col.row(align=True)
		colrow.label(l['prongs'])
		colrow.operator('jewelcraft.make_single_prong', text='', icon_value=icons['TOOL-SINGLE_PRONG'].icon_id)
		colrow.operator('jewelcraft.make_prongs', text='', icon='SURFACE_NCIRCLE')
		colrow = col.row(align=True)
		colrow.label(l['cutter'])
		colrow.operator('jewelcraft.make_cutter', text='', icon_value=icons['TOOL-CUTTER_SEAT'].icon_id).seat_only = True
		colrow.operator('jewelcraft.make_cutter', text='', icon_value=icons['TOOL-CUTTER'].icon_id)
		colrow = col.row(align=True)
		colrow.label(l['imitation'])
		colrow.operator('jewelcraft.make_imitation', text='', icon_value=icons['TOOL-IMITATION'].icon_id)

		col = layout.column(align=True)
		col.operator('jewelcraft.make_dupliface', text=l['make_dupliface'])
		col.operator('jewelcraft.select_doubles', text=l['select_doubles'])

class Weighting(UI, Panel):
	bl_label = 'Weighting'
	bl_idname = 'jewelcraft_weighting'
	bl_options = {'DEFAULT_CLOSED'}

	def draw(self, context):
		layout = self.layout
		l = self.l
		weight = var.weighting_report

		layout.prop(self.props, 'weighting_metals', text='')

		col = layout.column(align=True)
		if self.props.weighting_metals == 'CUSTOM':
			col.prop(self.props, 'weighting_custom', text=l['g/cm'])
		col.operator('jewelcraft.weight_display', text=l['wt_calc'])

		if weight:
			box = layout.box()
			box.label(weight)

class Stats(UI, Panel):
	bl_label = 'Statistics'
	bl_idname = 'jewelcraft_export'

	def draw(self, context):
		layout = self.layout
		scene = context.scene
		props = self.props
		l = self.l

		box = layout.box()
		boxrow = box.row(align=True)
		boxrow.prop(props, 'stats_options', icon=icon_tria(props.stats_options), icon_only=True)
		boxrow.label(l['stats_options'])
		if props.stats_options:
			col = box.column()
			colrow = col.row(align=True)
			colrow.prop_search(props, 'stats_size', scene, 'objects', text=l['size'])
			colrow.operator('jewelcraft.stats_pick', text='', icon='EYEDROPPER').prop = 'stats_size'
			colrow = col.row(align=True)
			colrow.prop_search(props, 'stats_shank', scene, 'objects', text=l['shank'])
			colrow.operator('jewelcraft.stats_pick', text='', icon='EYEDROPPER').prop = 'stats_shank'
			colrow = col.row(align=True)
			colrow.prop_search(props, 'stats_dim', scene, 'objects', text=l['dim'])
			colrow.operator('jewelcraft.stats_pick', text='', icon='EYEDROPPER').prop = 'stats_dim'
			colrow = col.row(align=True)
			colrow.prop_search(props, 'stats_weight', scene, 'objects', text=l['weight'])
			colrow.operator('jewelcraft.stats_pick', text='', icon='EYEDROPPER').prop = 'stats_weight'

			boxrow = box.row(align=True)
			boxrow.prop(props, 'stats_metals', icon=icon_tria(props.stats_metals), icon_only=True)
			boxrow.label(l['metals'])
			if props.stats_metals:
				col = box.column(align=True)
				col.prop(props, 'stats_24g',    text=l['24g'])
				col.prop(props, 'stats_22g',    text=l['22g'])
				col.prop(props, 'stats_18wg',   text=l['18wg'])
				col.prop(props, 'stats_18yg',   text=l['18yg'])
				col.prop(props, 'stats_14wg',   text=l['14wg'])
				col.prop(props, 'stats_14yg',   text=l['14yg'])
				col.prop(props, 'stats_ster',   text=l['ster'])
				col.prop(props, 'stats_pd',     text=l['pd'])
				col.prop(props, 'stats_pl',     text=l['pl'])
				col.prop(props, 'stats_custom', text=l['custom'])

				sub = col.column(align=True)
				sub.enabled = props.stats_custom
				subrow = sub.row()
				subrow.label(l['custom_name'])
				subrow.label(l['g/cm'] + ':')
				subrow = sub.row()
				subrow.prop(props, 'stats_custom_name', text='')
				subrow.prop(props, 'stats_custom_dens', text='')

			boxrow = box.row(align=True)
			boxrow.label(l['lang'] + ':')
			boxrow.prop(props, 'stats_lang', text='')

		col = layout.column(align=True)
		col.operator('jewelcraft.stats_export', text=l['stats_export'])
<commit_msg>Tweak stats Export Options UI<commit_after>import bpy
from bpy.types import Panel
from . import (
	var,
	locale,
	previews,
	)

def icon_tria(prop):
	if prop:
		return 'TRIA_DOWN'
	else:
		return 'TRIA_RIGHT'

class UI:
	bl_category = 'JewelCraft'
	bl_space_type = 'VIEW_3D'
	bl_region_type = 'TOOLS'
	bl_context = 'objectmode'

	def __init__(self):
		prefs = bpy.context.user_preferences.addons[var.addon_id].preferences
		self.props = bpy.context.scene.jewelcraft
		self.l = locale.locale[prefs.lang]

class Gems(UI, Panel):
	bl_label = 'Gems'
	bl_idname = 'jewelcraft_import'

	def draw(self, context):
		layout = self.layout
		l = self.l
		icons = previews.preview_collections['icons']

		layout.template_icon_view(self.props, 'gem_cut', show_labels=True)

		col = layout.column(align=True)
		colrow = col.row(align=True)
		colrow.prop(self.props, 'gem_stone', text='')
		colrow.operator('jewelcraft.search_stone', text='', icon='VIEWZOOM')
		col.prop(self.props, 'gem_size', text=l['size'])
		col.operator('jewelcraft.make_gem', text=l['make_gem'])

		col = layout.column(align=True)
		colrow = col.row(align=True)
		colrow.label(l['gem'])
		colrow.operator('jewelcraft.replace_stone', text='', icon='COLOR')
		colrow.operator('jewelcraft.replace_cut', text='', icon_value=icons['TOOL-CUT'].icon_id)

		col = layout.column(align=True)
		colrow = col.row(align=True)
		colrow.label(l['prongs'])
		colrow.operator('jewelcraft.make_single_prong', text='', icon_value=icons['TOOL-SINGLE_PRONG'].icon_id)
		colrow.operator('jewelcraft.make_prongs', text='', icon='SURFACE_NCIRCLE')
		colrow = col.row(align=True)
		colrow.label(l['cutter'])
		colrow.operator('jewelcraft.make_cutter', text='', icon_value=icons['TOOL-CUTTER_SEAT'].icon_id).seat_only = True
		colrow.operator('jewelcraft.make_cutter', text='', icon_value=icons['TOOL-CUTTER'].icon_id)
		colrow = col.row(align=True)
		colrow.label(l['imitation'])
		colrow.operator('jewelcraft.make_imitation', text='', icon_value=icons['TOOL-IMITATION'].icon_id)

		col = layout.column(align=True)
		col.operator('jewelcraft.make_dupliface', text=l['make_dupliface'])
		col.operator('jewelcraft.select_doubles', text=l['select_doubles'])

class Weighting(UI, Panel):
	bl_label = 'Weighting'
	bl_idname = 'jewelcraft_weighting'
	bl_options = {'DEFAULT_CLOSED'}

	def draw(self, context):
		layout = self.layout
		l = self.l
		weight = var.weighting_report

		layout.prop(self.props, 'weighting_metals', text='')

		col = layout.column(align=True)
		if self.props.weighting_metals == 'CUSTOM':
			col.prop(self.props, 'weighting_custom', text=l['g/cm'])
		col.operator('jewelcraft.weight_display', text=l['wt_calc'])

		if weight:
			box = layout.box()
			box.label(weight)

class Stats(UI, Panel):
	bl_label = 'Statistics'
	bl_idname = 'jewelcraft_export'

	def draw(self, context):
		layout = self.layout
		scene = context.scene
		props = self.props
		l = self.l

		box = layout.box()
		boxrow = box.row(align=True)
		boxrow.prop(props, 'stats_options', icon=icon_tria(props.stats_options), icon_only=True)
		boxrow.label(l['stats_options'])
		if props.stats_options:
			col = box.column()
			colrow = col.row(align=True)
			colrow.prop_search(props, 'stats_size', scene, 'objects', text=l['size'])
			colrow.operator('jewelcraft.stats_pick', text='', icon='EYEDROPPER').prop = 'stats_size'
			colrow = col.row(align=True)
			colrow.prop_search(props, 'stats_shank', scene, 'objects', text=l['shank'])
			colrow.operator('jewelcraft.stats_pick', text='', icon='EYEDROPPER').prop = 'stats_shank'
			colrow = col.row(align=True)
			colrow.prop_search(props, 'stats_dim', scene, 'objects', text=l['dim'])
			colrow.operator('jewelcraft.stats_pick', text='', icon='EYEDROPPER').prop = 'stats_dim'
			colrow = col.row(align=True)
			colrow.prop_search(props, 'stats_weight', scene, 'objects', text=l['weight'])
			colrow.operator('jewelcraft.stats_pick', text='', icon='EYEDROPPER').prop = 'stats_weight'

			boxrow = box.row(align=True)
			boxrow.label(l['lang'] + ':')
			boxrow.prop(props, 'stats_lang', text='')

			boxrow = box.row(align=True)
			boxrow.prop(props, 'stats_metals', icon=icon_tria(props.stats_metals), icon_only=True)
			boxrow.label(l['metals'])
			if props.stats_metals:
				col = box.column(align=True)
				col.prop(props, 'stats_24g',    text=l['24g'])
				col.prop(props, 'stats_22g',    text=l['22g'])
				col.prop(props, 'stats_18wg',   text=l['18wg'])
				col.prop(props, 'stats_18yg',   text=l['18yg'])
				col.prop(props, 'stats_14wg',   text=l['14wg'])
				col.prop(props, 'stats_14yg',   text=l['14yg'])
				col.prop(props, 'stats_ster',   text=l['ster'])
				col.prop(props, 'stats_pd',     text=l['pd'])
				col.prop(props, 'stats_pl',     text=l['pl'])
				col.prop(props, 'stats_custom', text=l['custom'])

				sub = col.column()
				sub.enabled = props.stats_custom
				subrow = sub.row(align=True)
				subrow.label(l['custom_name'])
				subrow.prop(props, 'stats_custom_name', text='')
				subrow = sub.row(align=True)
				subrow.label(l['g/cm'] + ':')
				subrow.prop(props, 'stats_custom_dens', text='')

		col = layout.column(align=True)
		col.operator('jewelcraft.stats_export', text=l['stats_export'])
<|endoftext|>


<commit_before>def format_author(author):
    return '%s, %s' % author

class Item:
    def __init__(self, item_dict={}):
        self.__dict__ = item_dict

    def __repr__(self):
        return repr(self.__dict__)

    def match(self, **kwargs):
        if not 'keywords' in kwargs: kwargs['keywords'] = []
        fields_to_search = {'title': 'title',
                            'pub': 'publicationTitle',
                            }
        result = []
        match_score = 0
        for field, to_search in fields_to_search.items():
            if not hasattr(self, to_search): continue
            search_terms = kwargs['keywords']
            if field in kwargs: field += kwargs[field]

            text_to_search = getattr(self, to_search).lower()
            search_terms = [term.lower() for term in search_terms]
            for search_term in search_terms:
                match_score += text_to_search.count(search_term)

        return match_score

    def author_string(self):
        if not hasattr(self, 'authors'): return ''
        return ', '.join([format_author(a) for a in getattr(self, 'authors')])

    def bibliography(self):
        bib = self.author_string()
        if hasattr(self, 'year'): bib += ' %s.' % getattr(self, 'year')
        if hasattr(self, 'title'): bib += ' %s.' % getattr(self, 'title')
        if hasattr(self, 'publicationTitle'): bib += ' %s.' % getattr(self, 'publicationTitle')

        return bib

    def citation(self):
        citation = ''
        if hasattr(self, 'authors'): citation = format_author(getattr(self, 'authors')[0])
        else: citation = getattr(self, 'title')
        if hasattr(self, 'year'): citation += ' %s.' % getattr(self, 'year')

        return citation

    def full_text(self):
        pass
<commit_msg>Search by author, better bibliography.<commit_after>def format_author(author):
    return '%s, %s' % author

class Item:
    def __init__(self, item_dict={}):
        self.__dict__ = item_dict

    def __repr__(self):
        return repr(self.__dict__)

    def match(self, **kwargs):
        if not 'keywords' in kwargs: kwargs['keywords'] = []
        fields_to_search = {'title': 'title',
                            'pub': 'publicationTitle',
                            'author': 'author_str'
                            }
        result = []
        match_score = 0
        for field, to_search in fields_to_search.items():
            if not hasattr(self, to_search): continue
            search_terms = kwargs['keywords']
            if field in kwargs: field += kwargs[field]

            text_to_search = getattr(self, to_search).lower()
            search_terms = [term.lower() for term in search_terms]
            for search_term in search_terms:
                match_score += text_to_search.count(search_term)

        return match_score

    def author_string(self):
        if not hasattr(self, 'authors'): return ''
        authors = getattr(self, 'authors')
        if len(authors) == 1: return format_author(authors[0])
        elif len(authors) == 2: return ' and '.join([format_author(a) for a in authors])
        else:
            return ', '.join([format_author(authors[n]) if n < len(authors)-1 else 'and %s' % format_author(authors[n]) for n in range(len(authors))])

    author_str = property(author_string)

    def bibliography(self):
        bib = self.author_string()
        if hasattr(self, 'year'): bib += ' %s.' % getattr(self, 'year')
        if hasattr(self, 'title'): bib += ' %s.' % getattr(self, 'title')
        if hasattr(self, 'publicationTitle'): bib += ' %s.' % getattr(self, 'publicationTitle')

        v = []
        if hasattr(self, 'volume'): v += ['Vol. %s' % getattr(self, 'volume')]
        if hasattr(self, 'issue'): v += ['Issue %s' % getattr(self, 'issue')]
        if hasattr(self, 'pages'): v += ['Pages %s' % getattr(self, 'pages')]
        if v: bib += ' ' + (', '.join(v)) + '.'

        if hasattr(self, 'doi'): bib += ' doi:%s' % getattr(self, 'doi')

        return bib

    def citation(self):
        citation = ''
        if hasattr(self, 'authors'): citation = format_author(getattr(self, 'authors')[0])
        else: citation = getattr(self, 'title')
        if hasattr(self, 'year'): citation += ' %s.' % getattr(self, 'year')

        return citation

    def full_text(self):
        pass
<|endoftext|>