<commit_before>from docutils import nodes
from sphinx.ext.viewcode import collect_pages
from sphinx.pycode import ModuleAnalyzer
import imp
from sphinx import addnodes
import re
from sphinx.util.compat import Directive
import os
from docutils.statemachine import StringList
from sphinx.environment import NoUri

def view_source(name, rawtext, text, lineno, inliner,
                      options={}, content=[]):

    env = inliner.document.settings.env

    node = _view_source_node(env, text, None)
    return [node], []

def _view_source_node(env, text, state):
    # pretend we're using viewcode fully,
    # install the context it looks for
    if not hasattr(env, '_viewcode_modules'):
        env._viewcode_modules = {}

    modname = text
    text = modname.split(".")[-1] + ".py"

    # imitate sphinx .<modname> syntax
    if modname.startswith("."):
        # see if the modname needs to be corrected in terms
        # of current module context
        base_module = env.temp_data.get('autodoc:module')
        if base_module is None:
            base_module = env.temp_data.get('py:module')

        if base_module:
            modname = base_module + modname

    urito = env.app.builder.get_relative_uri

    # we're showing code examples which may have dependencies
    # which we really don't want to have required so load the
    # module by file, not import (though we are importing)
    # the top level module here...
    pathname = None
    for token in modname.split("."):
        file_, pathname, desc = imp.find_module(token, [pathname] if pathname else None)
        if file_:
            file_.close()

    # unlike viewcode which silently traps exceptions,
    # I want this to totally barf if the file can't be loaded.
    # a failed build better than a complete build missing
    # key content
    analyzer = ModuleAnalyzer.for_file(pathname, modname)
    # copied from viewcode
    analyzer.find_tags()
    if not isinstance(analyzer.code, unicode):
        code = analyzer.code.decode(analyzer.encoding)
    else:
        code = analyzer.code

    if state is not None:
        docstring = _find_mod_docstring(analyzer)
        if docstring:
            # get rid of "foo.py" at the top
            docstring = re.sub(r"^[a-zA-Z_0-9]+\.py", "", docstring)

            # strip
            docstring = docstring.strip()

            # yank only first paragraph
            docstring = docstring.split("\n\n")[0].strip()
    else:
        docstring = None

    entry = code, analyzer.tags, {}
    env._viewcode_modules[modname] = entry
    pagename = '_modules/' + modname.replace('.', '/')

    try:
        refuri = urito(env.docname, pagename)
    except NoUri:
        # if we're in the latex builder etc., this seems
        # to be what we get
        refuri = None

    if docstring:
        # embed the ref with the doc text so that it isn't
        # a separate paragraph
        if refuri:
            docstring = "`%s <%s>`_ - %s" % (text, refuri, docstring)
        else:
            docstring = "``%s`` - %s" % (text, docstring)
        para = nodes.paragraph('', '')
        state.nested_parse(StringList([docstring]), 0, para)
        return_node = para
    else:
        if refuri:
            refnode = nodes.reference('', '',
                    nodes.Text(text, text),
                    refuri=urito(env.docname, pagename)
                )
        else:
            refnode = nodes.Text(text, text)

        if state:
            return_node = nodes.paragraph('', '', refnode)
        else:
            return_node = refnode

    return return_node

from sphinx.pycode.pgen2 import token

def _find_mod_docstring(analyzer):
    """attempt to locate the module-level docstring.

    Note that sphinx autodoc just uses ``__doc__``.  But we don't want
    to import the module, so we need to parse for it.

    """
    analyzer.tokenize()
    for type_, parsed_line, start_pos, end_pos, raw_line in analyzer.tokens:
        if type_ == token.COMMENT:
            continue
        elif type_ == token.STRING:
            return eval(parsed_line)
        else:
            return None

def _parse_content(content):
    d = {}
    d['text'] = []
    idx = 0
    for line in content:
        idx += 1
        m = re.match(r' *\:(.+?)\:(?: +(.+))?', line)
        if m:
            attrname, value = m.group(1, 2)
            d[attrname] = value or ''
        else:
            break
    d["text"] = content[idx:]
    return d

def _comma_list(text):
    return re.split(r"\s*,\s*", text.strip())

class AutoSourceDirective(Directive):
    has_content = True

    def run(self):
        content = _parse_content(self.content)

        env = self.state.document.settings.env
        self.docname = env.docname

        sourcefile = self.state.document.current_source.split(":")[0]
        dir_ = os.path.dirname(sourcefile)
        files = [
            f for f in os.listdir(dir_) if f.endswith(".py")
            and f != "__init__.py"
        ]

        if "files" in content:
            # ordered listing of files to include
            files = [fname for fname in _comma_list(content["files"])
                        if fname in set(files)]

        node = nodes.paragraph('', '',
                        nodes.Text("Listing of files:", "Listing of files:")
                )

        bullets = nodes.bullet_list()
        for fname in files:
            modname, ext = os.path.splitext(fname)
            # relative lookup
            modname = "." + modname

            link = _view_source_node(env, modname, self.state)

            list_node = nodes.list_item('',
                link
            )
            bullets += list_node

        node += bullets

        return [node]

def setup(app):
    app.add_role('viewsource', view_source)

    app.add_directive('autosource', AutoSourceDirective)

    # from sphinx.ext.viewcode
    app.connect('html-collect-pages', collect_pages)
<commit_msg>- some py3k compatibility<commit_after>from docutils import nodes
from sphinx.ext.viewcode import collect_pages
from sphinx.pycode import ModuleAnalyzer
import imp
from sphinx import addnodes
import re
from sphinx.util.compat import Directive
import os
from docutils.statemachine import StringList
from sphinx.environment import NoUri

import sys

py2k = sys.version_info < (3, 0)
if py2k:
    text_type = unicode
else:
    text_type = str

def view_source(name, rawtext, text, lineno, inliner,
                      options={}, content=[]):

    env = inliner.document.settings.env

    node = _view_source_node(env, text, None)
    return [node], []

def _view_source_node(env, text, state):
    # pretend we're using viewcode fully,
    # install the context it looks for
    if not hasattr(env, '_viewcode_modules'):
        env._viewcode_modules = {}

    modname = text
    text = modname.split(".")[-1] + ".py"

    # imitate sphinx .<modname> syntax
    if modname.startswith("."):
        # see if the modname needs to be corrected in terms
        # of current module context
        base_module = env.temp_data.get('autodoc:module')
        if base_module is None:
            base_module = env.temp_data.get('py:module')

        if base_module:
            modname = base_module + modname

    urito = env.app.builder.get_relative_uri

    # we're showing code examples which may have dependencies
    # which we really don't want to have required so load the
    # module by file, not import (though we are importing)
    # the top level module here...
    pathname = None
    for token in modname.split("."):
        file_, pathname, desc = imp.find_module(token, [pathname] if pathname else None)
        if file_:
            file_.close()

    # unlike viewcode which silently traps exceptions,
    # I want this to totally barf if the file can't be loaded.
    # a failed build better than a complete build missing
    # key content
    analyzer = ModuleAnalyzer.for_file(pathname, modname)
    # copied from viewcode
    analyzer.find_tags()
    if not isinstance(analyzer.code, text_type):
        code = analyzer.code.decode(analyzer.encoding)
    else:
        code = analyzer.code

    if state is not None:
        docstring = _find_mod_docstring(analyzer)
        if docstring:
            # get rid of "foo.py" at the top
            docstring = re.sub(r"^[a-zA-Z_0-9]+\.py", "", docstring)

            # strip
            docstring = docstring.strip()

            # yank only first paragraph
            docstring = docstring.split("\n\n")[0].strip()
    else:
        docstring = None

    entry = code, analyzer.tags, {}
    env._viewcode_modules[modname] = entry
    pagename = '_modules/' + modname.replace('.', '/')

    try:
        refuri = urito(env.docname, pagename)
    except NoUri:
        # if we're in the latex builder etc., this seems
        # to be what we get
        refuri = None

    if docstring:
        # embed the ref with the doc text so that it isn't
        # a separate paragraph
        if refuri:
            docstring = "`%s <%s>`_ - %s" % (text, refuri, docstring)
        else:
            docstring = "``%s`` - %s" % (text, docstring)
        para = nodes.paragraph('', '')
        state.nested_parse(StringList([docstring]), 0, para)
        return_node = para
    else:
        if refuri:
            refnode = nodes.reference('', '',
                    nodes.Text(text, text),
                    refuri=urito(env.docname, pagename)
                )
        else:
            refnode = nodes.Text(text, text)

        if state:
            return_node = nodes.paragraph('', '', refnode)
        else:
            return_node = refnode

    return return_node

from sphinx.pycode.pgen2 import token

def _find_mod_docstring(analyzer):
    """attempt to locate the module-level docstring.

    Note that sphinx autodoc just uses ``__doc__``.  But we don't want
    to import the module, so we need to parse for it.

    """
    analyzer.tokenize()
    for type_, parsed_line, start_pos, end_pos, raw_line in analyzer.tokens:
        if type_ == token.COMMENT:
            continue
        elif type_ == token.STRING:
            return eval(parsed_line)
        else:
            return None

def _parse_content(content):
    d = {}
    d['text'] = []
    idx = 0
    for line in content:
        idx += 1
        m = re.match(r' *\:(.+?)\:(?: +(.+))?', line)
        if m:
            attrname, value = m.group(1, 2)
            d[attrname] = value or ''
        else:
            break
    d["text"] = content[idx:]
    return d

def _comma_list(text):
    return re.split(r"\s*,\s*", text.strip())

class AutoSourceDirective(Directive):
    has_content = True

    def run(self):
        content = _parse_content(self.content)

        env = self.state.document.settings.env
        self.docname = env.docname

        sourcefile = self.state.document.current_source.split(":")[0]
        dir_ = os.path.dirname(sourcefile)
        files = [
            f for f in os.listdir(dir_) if f.endswith(".py")
            and f != "__init__.py"
        ]

        if "files" in content:
            # ordered listing of files to include
            files = [fname for fname in _comma_list(content["files"])
                        if fname in set(files)]

        node = nodes.paragraph('', '',
                        nodes.Text("Listing of files:", "Listing of files:")
                )

        bullets = nodes.bullet_list()
        for fname in files:
            modname, ext = os.path.splitext(fname)
            # relative lookup
            modname = "." + modname

            link = _view_source_node(env, modname, self.state)

            list_node = nodes.list_item('',
                link
            )
            bullets += list_node

        node += bullets

        return [node]

def setup(app):
    app.add_role('viewsource', view_source)

    app.add_directive('autosource', AutoSourceDirective)

    # from sphinx.ext.viewcode
    app.connect('html-collect-pages', collect_pages)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-

"""

ZUGBRUECKE
Calling routines in Windows DLLs from Python scripts running on unixlike systems
https://github.com/pleiszenburg/zugbruecke

	test_gdc.py: Tests by value argument passing and return value (int)

	Required to run on platform / side: [UNIX, WINE]

	Copyright (C) 2017 Sebastian M. Ernst <ernst@pleiszenburg.de>

<LICENSE_BLOCK>
The contents of this file are subject to the GNU Lesser General Public License
Version 2.1 ("LGPL" or "License"). You may not use this file except in
compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
https://github.com/pleiszenburg/zugbruecke/blob/master/LICENSE

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
specific language governing rights and limitations under the License.
</LICENSE_BLOCK>

"""

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# IMPORT
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

import pytest

from zugbruecke import ctypes

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# CLASSES AND ROUTINES
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

class sample_class:

	def __init__(self):

		self.__dll__ = ctypes.windll.LoadLibrary('tests/demo_dll.dll')

		# int gcd(int, int)
		self.gcd = self.__dll__.cookbook_gcd
		self.gcd.argtypes = (ctypes.c_int, ctypes.c_int)
		self.gcd.restype = ctypes.c_int

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# TEST(s)
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

def test_gdc():

	sample = sample_class()

	assert 7 == sample.gcd(35, 42)
<commit_msg>test travis cwd ...<commit_after># -*- coding: utf-8 -*-

"""

ZUGBRUECKE
Calling routines in Windows DLLs from Python scripts running on unixlike systems
https://github.com/pleiszenburg/zugbruecke

	test_gdc.py: Tests by value argument passing and return value (int)

	Required to run on platform / side: [UNIX, WINE]

	Copyright (C) 2017 Sebastian M. Ernst <ernst@pleiszenburg.de>

<LICENSE_BLOCK>
The contents of this file are subject to the GNU Lesser General Public License
Version 2.1 ("LGPL" or "License"). You may not use this file except in
compliance with the License. You may obtain a copy of the License at
https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt
https://github.com/pleiszenburg/zugbruecke/blob/master/LICENSE

Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the
specific language governing rights and limitations under the License.
</LICENSE_BLOCK>

"""

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# IMPORT
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

import pytest

from zugbruecke import ctypes
ctypes.windll.start_session(parameter = {'log_level': 10})

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# CLASSES AND ROUTINES
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

class sample_class:

	def __init__(self):

		self.__dll__ = ctypes.windll.LoadLibrary('tests/demo_dll.dll')

		# int gcd(int, int)
		self.gcd = self.__dll__.cookbook_gcd
		self.gcd.argtypes = (ctypes.c_int, ctypes.c_int)
		self.gcd.restype = ctypes.c_int

# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# TEST(s)
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

def test_gdc():

	sample = sample_class()

	assert 7 == sample.gcd(35, 42)
<|endoftext|>


<commit_before>import unittest
import gc

from common import gtk

class CallOnDel:
    def __init__(self, callback):
        self.callback = callback
    def __del__(self):
        self.callback()

class GdkTest(unittest.TestCase):
    def testBitmapCreateFromData(self):
        gtk.gdk.bitmap_create_from_data(None, '\x00', 1, 1)

    def testPixmapCreateFromData(self):
        black = gtk.gdk.color_parse('black')
        gtk.gdk.pixmap_create_from_data(None, '\x00', 1, 1, 1,
                                        black, black)

    def _testWindow(self):
        common = {'finalized': False}
        def on_finalize():
            common['finalized'] = True
        w = gtk.gdk.Window(None, 200, 200, gtk.gdk.WINDOW_TEMP, 0, 0)
        w.set_data('foo', CallOnDel(on_finalize))
        w.destroy()
        while gtk.events_pending():
            gtk.main_iteration(block=False)
        del w

        # Note that this depends on the mainloop processing an X event so
        # if might fail if the timing is off
        while gc.collect():
            pass
        assert common['finalized']

    def testDrawIndexedImage(self):
        w = gtk.Window()
        w.realize()
        w.window.draw_indexed_image(gtk.gdk.GC(w.window),
                                    0, 0,
                                    1, 2,
                                    gtk.gdk.RGB_DITHER_NONE,
                                    '\x00\x01',
                                    1,
                                    [0xdeadbe, 0xbebabe])
<commit_msg>Add a display refcounting test<commit_after>import unittest
import gc

from common import gtk

class CallOnDel:
    def __init__(self, callback):
        self.callback = callback
    def __del__(self):
        self.callback()

class GdkTest(unittest.TestCase):
    def testBitmapCreateFromData(self):
        gtk.gdk.bitmap_create_from_data(None, '\x00', 1, 1)

    def testPixmapCreateFromData(self):
        black = gtk.gdk.color_parse('black')
        gtk.gdk.pixmap_create_from_data(None, '\x00', 1, 1, 1,
                                        black, black)

    def _testWindow(self):
        common = {'finalized': False}
        def on_finalize():
            common['finalized'] = True
        w = gtk.gdk.Window(None, 200, 200, gtk.gdk.WINDOW_TEMP, 0, 0)
        w.set_data('foo', CallOnDel(on_finalize))
        w.destroy()
        while gtk.events_pending():
            gtk.main_iteration(block=False)
        del w

        # Note that this depends on the mainloop processing an X event so
        # if might fail if the timing is off
        while gc.collect():
            pass
        assert common['finalized']

    def testDrawIndexedImage(self):
        w = gtk.Window()
        w.realize()
        w.window.draw_indexed_image(gtk.gdk.GC(w.window),
                                    0, 0,
                                    1, 2,
                                    gtk.gdk.RGB_DITHER_NONE,
                                    '\x00\x01',
                                    1,
                                    [0xdeadbe, 0xbebabe])

    def testDisplay(self):
        gc.collect()
        display = gtk.gdk.Display(None)
        del display
        self.assertEquals(gc.collect(), 1)
        display = gtk.gdk.Display(None)
        display.close()
        del display
        #self.assertEquals(gc.collect(), 1)
<|endoftext|>


<commit_before>from __future__ import absolute_import
import lintreview.git as git
import os
from .test_github import config
from nose.tools import eq_, raises, assert_in
from unittest import skipIf

settings = {
    'WORKSPACE': './tests'
}
clone_path = settings['WORKSPACE'] + '/test_clone'
cant_write_to_test = not(os.access(os.path.abspath('./tests'), os.W_OK))

def teardown():
    if git.exists(clone_path):
        git.destroy(clone_path)

def test_get_repo_path():
    user = 'markstory'
    repo = 'asset_compress'
    num = '4'
    res = git.get_repo_path(user, repo, num, settings)
    expected = os.sep.join(
        (settings['WORKSPACE'], user, repo, num))
    expected = os.path.realpath(expected)
    eq_(res, expected)

def test_get_repo_path__int():
    user = 'markstory'
    repo = 'asset_compress'
    num = 4
    res = git.get_repo_path(user, repo, num, settings)
    expected = os.sep.join(
        (settings['WORKSPACE'], user, repo, str(num)))
    expected = os.path.realpath(expected)
    eq_(res, expected)

def test_get_repo_path__absoulte_dir():
    user = 'markstory'
    repo = 'asset_compress'
    num = 4
    settings['WORKSPACE'] = os.path.realpath(settings['WORKSPACE'])
    res = git.get_repo_path(user, repo, num, settings)
    expected = os.sep.join(
        (settings['WORKSPACE'], user, repo, str(num)))
    expected = os.path.realpath(expected)
    eq_(res, expected)

def test_exists__no_path():
    assert not git.exists(settings['WORKSPACE'] + '/herp/derp')

def test_exists__no_git():
    assert not git.exists(settings['WORKSPACE'])

@raises(IOError)
def test_repo_clone_no_repo():
    git.clone(
        'git://github.com/markstory/it will never work.git',
        clone_path)

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
def test_repo_operations():
    res = git.clone(
        'git://github.com/markstory/lint-review.git',
        clone_path)
    assert res, 'Cloned successfully.'
    assert git.exists(clone_path), 'Cloned dir should be there.'
    git.destroy(clone_path)
    assert not(git.exists(clone_path)), 'Cloned dir should be gone.'

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
def test_clone_or_update():
    git.clone_or_update(
        config,
        'git://github.com/markstory/lint-review.git',
        clone_path,
        'e4f880c77e6b2c81c81cad5d45dd4e1c39b919a0')
    assert git.exists(clone_path)

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
def test_diff():
    git.clone_or_update(
        config,
        'git://github.com/markstory/lint-review.git',
        clone_path,
        'master')
    with open(clone_path + '/README.mdown', 'w') as f:
        f.write('New readme')
    result = git.diff(clone_path)

    assert_in('a/README.mdown', result)
    assert_in('b/README.mdown', result)
    assert_in('+New readme', result)
    assert_in('-# Lint Review', result)

def test_apply_cached():
    git.clone_or_update(
        config,
        'git://github.com/markstory/lint-review.git',
        clone_path,
        'master')
    with open(clone_path + '/README.mdown', 'w') as f:
        f.write('New readme')
    # Get the initial diff.
    diff = git.diff(clone_path)
    git.apply_cached(clone_path, diff)

    # Changes have been staged, diff result should be empty.
    diff = git.diff(clone_path)
    eq_(diff, '')

def test_apply_cached__empty():
    git.clone_or_update(
        config,
        'git://github.com/markstory/lint-review.git',
        clone_path,
        'master')
    git.apply_cached(clone_path, '')

    # No changes, no diff.
    diff = git.diff(clone_path)
    eq_(diff, '')

@raises(IOError)
def test_apply_cached__bad_patch():
    git.clone_or_update(
        config,
        'git://github.com/markstory/lint-review.git',
        clone_path,
        'master')
    git.apply_cached(clone_path, 'not a diff')

def test_commit_and_status():
    git.clone_or_update(
        config,
        'git://github.com/markstory/lint-review.git',
        clone_path,
        'master')
    with open(clone_path + '/README.mdown', 'w') as f:
        f.write('New readme')
    diff = git.diff(clone_path)

    status = git.status(clone_path)
    assert 'README.mdown' in status

    git.apply_cached(clone_path, diff)
    git.commit(clone_path, 'robot <bot@example.com>', 'Fixed readme')
    status = git.status(clone_path)
    eq_('', status, 'No changes unstaged, or uncommitted')

def test_push():
    assert False, 'not done'

def test_push__fails():
    assert False, 'not done'

def test_add_remote():
    assert False, 'not done'
<commit_msg>Add tests for bad path setups.<commit_after>from __future__ import absolute_import
import lintreview.git as git
import os
from .test_github import config
from nose.tools import eq_, raises, assert_in, with_setup
from unittest import skipIf

settings = {
    'WORKSPACE': './tests'
}
clone_path = settings['WORKSPACE'] + '/test_clone'
cant_write_to_test = not(os.access(os.path.abspath('./tests'), os.W_OK))

def setup_repo():
    git.clone_or_update(
        config,
        'git://github.com/markstory/lint-review.git',
        clone_path,
        'master')

def teardown_repo():
    if git.exists(clone_path):
        git.destroy(clone_path)

def noop():
    pass

def test_get_repo_path():
    user = 'markstory'
    repo = 'asset_compress'
    num = '4'
    res = git.get_repo_path(user, repo, num, settings)
    expected = os.sep.join(
        (settings['WORKSPACE'], user, repo, num))
    expected = os.path.realpath(expected)
    eq_(res, expected)

def test_get_repo_path__int():
    user = 'markstory'
    repo = 'asset_compress'
    num = 4
    res = git.get_repo_path(user, repo, num, settings)
    expected = os.sep.join(
        (settings['WORKSPACE'], user, repo, str(num)))
    expected = os.path.realpath(expected)
    eq_(res, expected)

def test_get_repo_path__absoulte_dir():
    user = 'markstory'
    repo = 'asset_compress'
    num = 4
    settings['WORKSPACE'] = os.path.realpath(settings['WORKSPACE'])
    res = git.get_repo_path(user, repo, num, settings)
    expected = os.sep.join(
        (settings['WORKSPACE'], user, repo, str(num)))
    expected = os.path.realpath(expected)
    eq_(res, expected)

def test_exists__no_path():
    assert not git.exists(settings['WORKSPACE'] + '/herp/derp')

def test_exists__no_git():
    assert not git.exists(settings['WORKSPACE'])

@raises(IOError)
@with_setup(noop, teardown_repo)
def test_repo_clone_no_repo():
    git.clone(
        'git://github.com/markstory/it will never work.git',
        clone_path)

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
def test_repo_operations():
    res = git.clone(
        'git://github.com/markstory/lint-review.git',
        clone_path)
    assert res, 'Cloned successfully.'
    assert git.exists(clone_path), 'Cloned dir should be there.'
    git.destroy(clone_path)
    assert not(git.exists(clone_path)), 'Cloned dir should be gone.'

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
@with_setup(noop, teardown_repo)
def test_clone_or_update():
    git.clone_or_update(
        config,
        'git://github.com/markstory/lint-review.git',
        clone_path,
        'e4f880c77e6b2c81c81cad5d45dd4e1c39b919a0')
    assert git.exists(clone_path)

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
@with_setup(setup_repo, teardown_repo)
def test_diff():
    with open(clone_path + '/README.mdown', 'w') as f:
        f.write('New readme')
    result = git.diff(clone_path)

    assert_in('a/README.mdown', result)
    assert_in('b/README.mdown', result)
    assert_in('+New readme', result)
    assert_in('-# Lint Review', result)

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
@raises(IOError)
def test_diff__non_git_path():
    git.diff(settings['WORKSPACE'] + '/../../')

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
@with_setup(setup_repo, teardown_repo)
def test_apply_cached():
    with open(clone_path + '/README.mdown', 'w') as f:
        f.write('New readme')
    # Get the initial diff.
    diff = git.diff(clone_path)
    git.apply_cached(clone_path, diff)

    # Changes have been staged, diff result should be empty.
    diff = git.diff(clone_path)
    eq_(diff, '')

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
@with_setup(setup_repo, teardown_repo)
def test_apply_cached__empty():
    git.apply_cached(clone_path, '')

    # No changes, no diff.
    diff = git.diff(clone_path)
    eq_(diff, '')

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
@raises(IOError)
@with_setup(setup_repo, teardown_repo)
def test_apply_cached__bad_patch():
    git.apply_cached(clone_path, 'not a diff')

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
@raises(IOError)
def test_apply_cached__non_git_path():
    git.apply_cached(settings['WORKSPACE'] + '/../../', 'not a patch')

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
@with_setup(setup_repo, teardown_repo)
def test_commit_and_status():
    with open(clone_path + '/README.mdown', 'w') as f:
        f.write('New readme')
    diff = git.diff(clone_path)

    status = git.status(clone_path)
    assert 'README.mdown' in status

    git.apply_cached(clone_path, diff)
    git.commit(clone_path, 'robot <bot@example.com>', 'Fixed readme')
    status = git.status(clone_path)
    eq_('', status, 'No changes unstaged, or uncommitted')

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
def test_push():
    assert False, 'not done'

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
def test_push__fails():
    assert False, 'not done'

@skipIf(cant_write_to_test, 'Cannot write to ./tests skipping')
def test_add_remote():
    assert False, 'not done'
<|endoftext|>


<commit_before>import errno
import json
import os
import socket
import threading
import time

from borg.helpers import Error

ADD, REMOVE = 'add', 'remove'
SHARED, EXCLUSIVE = 'shared', 'exclusive'

def get_id():
    """Get identification tuple for 'us'"""
    hostname = socket.gethostname()
    pid = os.getpid()
    tid = threading.current_thread().ident & 0xffffffff
    return hostname, pid, tid

class TimeoutTimer:
    """
    A timer for timeout checks (can also deal with no timeout, give timeout=None [default]).
    It can also compute and optionally execute a reasonable sleep time (e.g. to avoid
    polling too often or to support thread/process rescheduling).
    """
    def __init__(self, timeout=None, sleep=None):
        """
        Initialize a timer.

        :param timeout: time out interval [s] or None (no timeout)
        :param sleep: sleep interval [s] (>= 0: do sleep call, <0: don't call sleep)
                      or None (autocompute: use 10% of timeout, or 1s for no timeout)
        """
        if timeout is not None and timeout < 0:
            raise ValueError("timeout must be >= 0")
        self.timeout_interval = timeout
        if sleep is None:
            if timeout is None:
                sleep = 1.0
            else:
                sleep = timeout / 10.0
        self.sleep_interval = sleep
        self.start_time = None
        self.end_time = None

    def __repr__(self):
        return "<%s: start=%r end=%r timeout=%r sleep=%r>" % (
            self.__class__.__name__, self.start_time, self.end_time,
            self.timeout_interval, self.sleep_interval)

    def start(self):
        self.start_time = time.time()
        if self.timeout_interval is not None:
            self.end_time = self.start_time + self.timeout_interval
        return self

    def sleep(self):
        if self.sleep_interval >= 0:
            time.sleep(self.sleep_interval)

    def timed_out(self):
        return self.end_time is not None and time.time() >= self.end_time

    def timed_out_or_sleep(self):
        if self.timed_out():
            return True
        else:
            self.sleep()
            return False

class ExclusiveLock:
    """An exclusive Lock based on mkdir fs operation being atomic"""
    class LockError(Error):
        """Failed to acquire the lock {}."""

    class LockTimeout(LockError):
        """Failed to create/acquire the lock {} (timeout)."""

    class LockFailed(LockError):
        """Failed to create/acquire the lock {} ({})."""

    class UnlockError(Error):
        """Failed to release the lock {}."""

    class NotLocked(UnlockError):
        """Failed to release the lock {} (was not locked)."""

    class NotMyLock(UnlockError):
        """Failed to release the lock {} (was/is locked, but not by me)."""

    def __init__(self, path, timeout=None, sleep=None, id=None):
        self.timeout = timeout
        self.sleep = sleep
        self.path = os.path.abspath(path)
        self.id = id or get_id()
        self.unique_name  = os.path.join(self.path, "%s.%d-%x" % self.id)

    def __enter__(self):
        return self.acquire()

    def __exit__(self, *exc):
        self.release()

    def __repr__(self):
        return "<%s: %r>" % (self.__class__.__name__, self.unique_name)

    def acquire(self, timeout=None, sleep=None):
        if timeout is None:
            timeout = self.timeout
        if sleep is None:
            sleep = self.sleep
        timer = TimeoutTimer(timeout, sleep).start()
        while True:
            try:
                os.mkdir(self.path)
            except OSError as err:
                if err.errno == errno.EEXIST:  # already locked
                    if self.by_me():
                        return self
                    if timer.timed_out_or_sleep():
                        raise self.LockTimeout(self.path)
                else:
                    raise self.LockFailed(self.path, str(err))
            else:
                with open(self.unique_name, "wb"):
                    pass
                return self

    def release(self):
        if not self.is_locked():
            raise self.NotLocked(self.path)
        if not self.by_me():
            raise self.NotMyLock(self.path)
        os.unlink(self.unique_name)
        os.rmdir(self.path)

    def is_locked(self):
        return os.path.exists(self.path)

    def by_me(self):
        return os.path.exists(self.unique_name)

    def break_lock(self):
        if self.is_locked():
            for name in os.listdir(self.path):
                os.unlink(os.path.join(self.path, name))
            os.rmdir(self.path)

class LockRoster:
    """
    A Lock Roster to track shared/exclusive lockers.

    Note: you usually should call the methods with an exclusive lock held,
    to avoid conflicting access by multiple threads/processes/machines.
    """
    def __init__(self, path, id=None):
        self.path = path
        self.id = id or get_id()

    def load(self):
        try:
            with open(self.path) as f:
                data = json.load(f)
        except IOError as err:
            if err.errno != errno.ENOENT:
                raise
            data = {}
        return data

    def save(self, data):
        with open(self.path, "w") as f:
            json.dump(data, f)

    def remove(self):
        try:
            os.unlink(self.path)
        except OSError as e:
            if e.errno != errno.ENOENT:
                raise

    def get(self, key):
        roster = self.load()
        return set(tuple(e) for e in roster.get(key, []))

    def modify(self, key, op):
        roster = self.load()
        try:
            elements = set(tuple(e) for e in roster[key])
        except KeyError:
            elements = set()
        if op == ADD:
            elements.add(self.id)
        elif op == REMOVE:
            elements.remove(self.id)
        else:
            raise ValueError('Unknown LockRoster op %r' % op)
        roster[key] = list(list(e) for e in elements)
        self.save(roster)

class UpgradableLock:
    """
    A Lock for a resource that can be accessed in a shared or exclusive way.
    Typically, write access to a resource needs an exclusive lock (1 writer,
    noone is allowed reading) and read access to a resource needs a shared
    lock (multiple readers are allowed).
    """
    class SharedLockFailed(Error):
        """Failed to acquire shared lock [{}]"""

    class ExclusiveLockFailed(Error):
        """Failed to acquire write lock [{}]"""

    def __init__(self, path, exclusive=False, sleep=None, id=None):
        self.path = path
        self.is_exclusive = exclusive
        self.sleep = sleep
        self.id = id or get_id()
        # globally keeping track of shared and exclusive lockers:
        self._roster = LockRoster(path + '.roster', id=id)
        # an exclusive lock, used for:
        # - holding while doing roster queries / updates
        # - holding while the UpgradableLock itself is exclusive
        self._lock = ExclusiveLock(path + '.exclusive', id=id)

    def __enter__(self):
        return self.acquire()

    def __exit__(self, *exc):
        self.release()

    def __repr__(self):
        return "<%s: %r>" % (self.__class__.__name__, self.id)

    def acquire(self, exclusive=None, remove=None, sleep=None):
        if exclusive is None:
            exclusive = self.is_exclusive
        sleep = sleep or self.sleep or 0.2
        try:
            if exclusive:
                self._wait_for_readers_finishing(remove, sleep)
                self._roster.modify(EXCLUSIVE, ADD)
            else:
                with self._lock:
                    if remove is not None:
                        self._roster.modify(remove, REMOVE)
                    self._roster.modify(SHARED, ADD)
            self.is_exclusive = exclusive
            return self
        except ExclusiveLock.LockError as err:
            msg = str(err)
            if exclusive:
                raise self.ExclusiveLockFailed(msg)
            else:
                raise self.SharedLockFailed(msg)

    def _wait_for_readers_finishing(self, remove, sleep):
        while True:
            self._lock.acquire()
            if remove is not None:
                self._roster.modify(remove, REMOVE)
                remove = None
            if len(self._roster.get(SHARED)) == 0:
                return  # we are the only one and we keep the lock!
            self._lock.release()
            time.sleep(sleep)

    def release(self):
        if self.is_exclusive:
            self._roster.modify(EXCLUSIVE, REMOVE)
            self._lock.release()
        else:
            with self._lock:
                self._roster.modify(SHARED, REMOVE)

    def upgrade(self):
        if not self.is_exclusive:
            self.acquire(exclusive=True, remove=SHARED)

    def downgrade(self):
        if self.is_exclusive:
            self.acquire(exclusive=False, remove=EXCLUSIVE)

    def break_lock(self):
        self._roster.remove()
        self._lock.break_lock()
<commit_msg>do not crash on empty lock.roster, fixes #232<commit_after>import errno
import json
import os
import socket
import threading
import time

from borg.helpers import Error

ADD, REMOVE = 'add', 'remove'
SHARED, EXCLUSIVE = 'shared', 'exclusive'

def get_id():
    """Get identification tuple for 'us'"""
    hostname = socket.gethostname()
    pid = os.getpid()
    tid = threading.current_thread().ident & 0xffffffff
    return hostname, pid, tid

class TimeoutTimer:
    """
    A timer for timeout checks (can also deal with no timeout, give timeout=None [default]).
    It can also compute and optionally execute a reasonable sleep time (e.g. to avoid
    polling too often or to support thread/process rescheduling).
    """
    def __init__(self, timeout=None, sleep=None):
        """
        Initialize a timer.

        :param timeout: time out interval [s] or None (no timeout)
        :param sleep: sleep interval [s] (>= 0: do sleep call, <0: don't call sleep)
                      or None (autocompute: use 10% of timeout, or 1s for no timeout)
        """
        if timeout is not None and timeout < 0:
            raise ValueError("timeout must be >= 0")
        self.timeout_interval = timeout
        if sleep is None:
            if timeout is None:
                sleep = 1.0
            else:
                sleep = timeout / 10.0
        self.sleep_interval = sleep
        self.start_time = None
        self.end_time = None

    def __repr__(self):
        return "<%s: start=%r end=%r timeout=%r sleep=%r>" % (
            self.__class__.__name__, self.start_time, self.end_time,
            self.timeout_interval, self.sleep_interval)

    def start(self):
        self.start_time = time.time()
        if self.timeout_interval is not None:
            self.end_time = self.start_time + self.timeout_interval
        return self

    def sleep(self):
        if self.sleep_interval >= 0:
            time.sleep(self.sleep_interval)

    def timed_out(self):
        return self.end_time is not None and time.time() >= self.end_time

    def timed_out_or_sleep(self):
        if self.timed_out():
            return True
        else:
            self.sleep()
            return False

class ExclusiveLock:
    """An exclusive Lock based on mkdir fs operation being atomic"""
    class LockError(Error):
        """Failed to acquire the lock {}."""

    class LockTimeout(LockError):
        """Failed to create/acquire the lock {} (timeout)."""

    class LockFailed(LockError):
        """Failed to create/acquire the lock {} ({})."""

    class UnlockError(Error):
        """Failed to release the lock {}."""

    class NotLocked(UnlockError):
        """Failed to release the lock {} (was not locked)."""

    class NotMyLock(UnlockError):
        """Failed to release the lock {} (was/is locked, but not by me)."""

    def __init__(self, path, timeout=None, sleep=None, id=None):
        self.timeout = timeout
        self.sleep = sleep
        self.path = os.path.abspath(path)
        self.id = id or get_id()
        self.unique_name  = os.path.join(self.path, "%s.%d-%x" % self.id)

    def __enter__(self):
        return self.acquire()

    def __exit__(self, *exc):
        self.release()

    def __repr__(self):
        return "<%s: %r>" % (self.__class__.__name__, self.unique_name)

    def acquire(self, timeout=None, sleep=None):
        if timeout is None:
            timeout = self.timeout
        if sleep is None:
            sleep = self.sleep
        timer = TimeoutTimer(timeout, sleep).start()
        while True:
            try:
                os.mkdir(self.path)
            except OSError as err:
                if err.errno == errno.EEXIST:  # already locked
                    if self.by_me():
                        return self
                    if timer.timed_out_or_sleep():
                        raise self.LockTimeout(self.path)
                else:
                    raise self.LockFailed(self.path, str(err))
            else:
                with open(self.unique_name, "wb"):
                    pass
                return self

    def release(self):
        if not self.is_locked():
            raise self.NotLocked(self.path)
        if not self.by_me():
            raise self.NotMyLock(self.path)
        os.unlink(self.unique_name)
        os.rmdir(self.path)

    def is_locked(self):
        return os.path.exists(self.path)

    def by_me(self):
        return os.path.exists(self.unique_name)

    def break_lock(self):
        if self.is_locked():
            for name in os.listdir(self.path):
                os.unlink(os.path.join(self.path, name))
            os.rmdir(self.path)

class LockRoster:
    """
    A Lock Roster to track shared/exclusive lockers.

    Note: you usually should call the methods with an exclusive lock held,
    to avoid conflicting access by multiple threads/processes/machines.
    """
    def __init__(self, path, id=None):
        self.path = path
        self.id = id or get_id()

    def load(self):
        try:
            with open(self.path) as f:
                data = json.load(f)
        except IOError as err:
            if err.errno != errno.ENOENT:
                raise
            data = {}
        except ValueError:
            # corrupt/empty roster file?
            data = {}
        return data

    def save(self, data):
        with open(self.path, "w") as f:
            json.dump(data, f)

    def remove(self):
        try:
            os.unlink(self.path)
        except OSError as e:
            if e.errno != errno.ENOENT:
                raise

    def get(self, key):
        roster = self.load()
        return set(tuple(e) for e in roster.get(key, []))

    def modify(self, key, op):
        roster = self.load()
        try:
            elements = set(tuple(e) for e in roster[key])
        except KeyError:
            elements = set()
        if op == ADD:
            elements.add(self.id)
        elif op == REMOVE:
            elements.remove(self.id)
        else:
            raise ValueError('Unknown LockRoster op %r' % op)
        roster[key] = list(list(e) for e in elements)
        self.save(roster)

class UpgradableLock:
    """
    A Lock for a resource that can be accessed in a shared or exclusive way.
    Typically, write access to a resource needs an exclusive lock (1 writer,
    noone is allowed reading) and read access to a resource needs a shared
    lock (multiple readers are allowed).
    """
    class SharedLockFailed(Error):
        """Failed to acquire shared lock [{}]"""

    class ExclusiveLockFailed(Error):
        """Failed to acquire write lock [{}]"""

    def __init__(self, path, exclusive=False, sleep=None, id=None):
        self.path = path
        self.is_exclusive = exclusive
        self.sleep = sleep
        self.id = id or get_id()
        # globally keeping track of shared and exclusive lockers:
        self._roster = LockRoster(path + '.roster', id=id)
        # an exclusive lock, used for:
        # - holding while doing roster queries / updates
        # - holding while the UpgradableLock itself is exclusive
        self._lock = ExclusiveLock(path + '.exclusive', id=id)

    def __enter__(self):
        return self.acquire()

    def __exit__(self, *exc):
        self.release()

    def __repr__(self):
        return "<%s: %r>" % (self.__class__.__name__, self.id)

    def acquire(self, exclusive=None, remove=None, sleep=None):
        if exclusive is None:
            exclusive = self.is_exclusive
        sleep = sleep or self.sleep or 0.2
        try:
            if exclusive:
                self._wait_for_readers_finishing(remove, sleep)
                self._roster.modify(EXCLUSIVE, ADD)
            else:
                with self._lock:
                    if remove is not None:
                        self._roster.modify(remove, REMOVE)
                    self._roster.modify(SHARED, ADD)
            self.is_exclusive = exclusive
            return self
        except ExclusiveLock.LockError as err:
            msg = str(err)
            if exclusive:
                raise self.ExclusiveLockFailed(msg)
            else:
                raise self.SharedLockFailed(msg)

    def _wait_for_readers_finishing(self, remove, sleep):
        while True:
            self._lock.acquire()
            if remove is not None:
                self._roster.modify(remove, REMOVE)
                remove = None
            if len(self._roster.get(SHARED)) == 0:
                return  # we are the only one and we keep the lock!
            self._lock.release()
            time.sleep(sleep)

    def release(self):
        if self.is_exclusive:
            self._roster.modify(EXCLUSIVE, REMOVE)
            self._lock.release()
        else:
            with self._lock:
                self._roster.modify(SHARED, REMOVE)

    def upgrade(self):
        if not self.is_exclusive:
            self.acquire(exclusive=True, remove=SHARED)

    def downgrade(self):
        if self.is_exclusive:
            self.acquire(exclusive=False, remove=EXCLUSIVE)

    def break_lock(self):
        self._roster.remove()
        self._lock.break_lock()
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
import time
from threading import Lock
from .loader import *
from .args import *
from .userdata import *
from .exceptions import *
from .module import *
from .context import *
from .settings import *
from .running import runningservers

threads = True
run = True

from lib import utils, parser
[reload(x) for x in [utils, parser]]

def make_server(module, kind, name, shared, options):
    global currentplugin
    if kind not in servers:
        loadnamedmodule(module)
    if kind not in servers:
        raise IndexError("%s is not a valid server type!" % kind)
    return servers[kind](name, shared, options)

def load_server(*args):
    server = make_server(*args)
    runningservers.append(server)

class Server(LoaderBase):

    """The Server Plugin."""

    """Override with plugins that are required to run the server."""
    requiredplugins = []

    """Default Options."""
    options = {
        'charlimit': 0,
    }

    """Optionally loaded plugins."""
    autoload = []

    dautoload = [
        "misc",
        "internet",
        "games",
    ]

    Settings = Settings

    def __init__(self, name, shared, options):
        self.name = name
        self.shared = shared
        self.hooks = {}
        self.globalaliases = {}
        self.runlock = Lock()
        self.timers = {}
        self.otimers = []
        self.options.update(options)
        self.settings = self.Settings(self)
        self.build_settings()
        self.modules = {}
        self.plugins = {}
        self.protected = []
        self.righttypes = {}
        self.registry = {}
        self.pluginpaths = []
        for k in ["core",
                  self.index] + self.requiredplugins:
                self.loadplugin(k)
                self.protected.append(k)
                for x in newmodules:
                    self.protected.append(k.split('/')[0] + '/%s' % x)
        self.build_lists()
        for k in self.dautoload + self.autoload + self.settings.get(
                "server.autoload"):
                self.loadplugin(k, auto=True)
        self.build_lists()
        self.addhook("server_ready", "sinit", self.ready)
        self.dohook("server_ready")

    def addrights(self, d):
        """Add <d> to the rights hierarchy."""
        self.righttypes.update(d)

    def opt(self, n):
        """Get config.py value <n>."""
        if n not in self.options and n in Server.options:
            return Server.options[n]
        return self.options[n]

    def log(self, category, text):
        """Log <text> under <category>."""
        print(("%s %s: %s" % (self.name, category, text.strip())))
        self.dohook("log", "bot", category, text.strip())

    def build_settings(self):
        """Ready to build settings."""
        pass

    def build_lists(self):
        """Recreate the command and settings lists."""
        self.commands = {}
        self.numcommands = {}
        for m in list(self.modules.values()):
            for k, v in list(m.commands.items()):
                self.commands[(m.plugin, m.index, k)] = (m, v)
                if k not in self.numcommands:
                    self.numcommands[k] = []
                self.numcommands[k].append(m.index)
        self.commands = sorted(list(self.commands.items()),
                               key=lambda x: -len(x[0][2].split()))
        self.settings.user = []
        self.settings.defaults = {}
        self.settings.tree = {}
        self.dohook("core_prepare_settings")
        for m in list(self.modules.values()):
            for k, v in m.serversettings:
                self.settings.add(k, v)

    def addhook(self, name, uname, function):
        """Add a hook to <name> with the unique id <uname>
        and the function <function>."""
        if name not in self.hooks:
            self.hooks[name] = {}
        self.hooks[name][uname] = function

    def dohook(self, name, *args):
        """Call all functions registered to <name> with <*args>."""
        if name in self.hooks:
            for f in list(self.hooks[name].values()):
                f(*args)

    def addtimer(self, f, n, t):
        """Add a timer with unique name <n>, function <f> and timeout <t>."""
        self.timers[n] = {
            'name': n,
            'function': f,
            'time': t,
            'last': 0,
        }

    def callonce(self, f, t):
        """Call f after <t> ms."""
        self.otimers.append({
            'start': time.time(),
            'function': f,
            'time': t,
        })

    def dotimers(self):
        for timer in list(self.timers.values()):
            if time.time() - timer['last'] > timer['time'] / 1000:
                try:
                    timer['function']()
                except:
                    import traceback
                    traceback.print_exc()
                timer['last'] = time.time()
        tod = []
        i = 0
        for timer in self.otimers:
            if time.time() - timer['start'] > timer['time'] / 1000:
                try:
                    timer['function']()
                except:
                    import traceback
                    traceback.print_exc()
                tod.append(i)
            i += 1
        tod.reverse()
        for i in tod:
            del self.otimers[i]

    def rset(self, n, v):
        """Register a function or structure to be used by other modules."""
        self.registry[n] = v

    def rget(self, n):
        """Get a value from the registry."""
        return self.registry[n]

    def rhas(self, n):
        """Is a key in the registry?"""
        return n in self.registry

    def corerun(self):
        if self.build:
            self.build = False
            self.build_lists()
        try:
            self.run()
        except:
            import traceback
            traceback.print_exc()
            global run
            run = False

    def splitparse(self, text, context=None):
        sections = []
        sectiond = {}
        sectione = {}
        idx = 0
        try:
            cchar = text[idx]
        except IndexError:
            return sections, sectiond
        section = ""
        escaped = False
        quoted = None
        running = False
        runningsection = ""
        rlevel = 0
        while cchar is not None:
            if not escaped and cchar == parser.escape:
                escaped = True
                if not section:
                    sectiond[len(sections)] = "cooked"
            elif escaped:
                if cchar in ["%s%s" % (parser.escape, parser.quotes)]:
                    section += cchar
                    escaped = False
                else:
                    section += cchar
                    escaped = False
            elif not quoted and cchar == parser.run[0]:
                if not running:
                    runningsection = section
                    section = ""
                    running = True
                else:
                    section += cchar
                rlevel += 1
            elif not quoted and cchar == parser.run[1]:
                rlevel -= 1
                if running and rlevel == 0:
                    c = section
                    section = self.runcommand(context, section)[0]
                    if section is None:
                        raise ParserBadCommand("Failed running: {%s}" % c)
                    section = runningsection + section
                    running = False
                else:
                    section += cchar
            elif not quoted and cchar in parser.quotes and not running:
                quoted = cchar
                if not section:
                    sectiond[len(sections)] = "cooked"
            elif quoted and not running:
                if cchar == quoted:
                    quoted = None
                    if not section:
                        sectione[len(sections)] = True
                else:
                    section += cchar
            else:
                if cchar == ' ' and not running:
                    if section or len(sections) in sectione:
                        sections.append(section)
                    section = ""
                else:
                    section += cchar
            idx += 1
            cchar = text[idx] if idx in range(len(text)) else None
        if section or len(sections) in sectione:
            sections.append(section)
        section = ""
        return sections, sectiond

    def makeargdict(self, argtext, context, v):
        sections, sectiond = self.splitparse(argtext, context)
        parsedargs = {}
        args = [a for a in v[1]['args'] if not a['kv']]
        kvargs = [a for a in v[1]['args'] if a['kv']]
        argi = 0
        sectioni = 0
        while sectioni in range(len(sections)):
            st = sections[sectioni]
            sd = sectiond[sectioni] if sectioni in sectiond else ""
            done = False
            if sd != "cooked":
                for prefix in ['--', '-']:
                    if st.startswith(prefix):
                        param = st[len(prefix):]
                        name = param.split('=')[0]
                        if name in [a['name'] for a in kvargs]:
                            try:
                                parsedargs[name] = param.split('=')[1]
                            except IndexError:
                                parsedargs[name] = ""
                            done = True
                        break
            if not done:
                if argi in range(len(args)):
                    arg = args[argi]
                    if arg['optional']:
                        if arg['recognizer'](st):
                            parsedargs[arg['name']] = st
                        else:
                            argi += 1
                            if argi in range(len(args)):
                                arg = args[argi]
                    if arg['full']:
                        parsedargs[arg['name']] = ' '.join(
                            sections[sectioni:]
                        )
                        argi = len(args)
                    else:
                        parsedargs[arg['name']] = st
                    argi += 1
            sectioni += 1
        return parsedargs

    def parsecommand(self, context, text, v, argtext):
        parsedargs = self.makeargdict(argtext, context, v)
        args = Args(parsedargs)
        return v[1]['function'](context, args)

    def getrights(self, *args):
        """Set by modules to get rights."""
        pass

    def modulesetup(self, m):
        """Modify and return <m>, to add attributes to the module class."""
        return m

    def idstring(self, context):
        """Return the rights idstring from <context>.
        Implemented by modules."""
        pass

    def shutdown(self):
        """Called on bot restart."""
        pass

    def commandlist(self):
        """List of commands and names."""
        commands = []
        for k, v in self.commands:
            for splitc in [
                    [v[0].plugin] + [v[0].index] + v[1]['name'].split(),
                    [v[0].index] + v[1]['name'].split(),
                    v[1]['name'].split()]:
                        commands.append((splitc, v))
        return commands

    def runcommand(self, context, text):
        """Run <text> as <context>."""
        commands = self.commandlist()
        split = text.split()
        commands.sort(key=lambda x: -len(x[0]))
        for splitc, v in commands:
            if splitc == split[:len(splitc)]:
                if len(splitc) == 1:
                    if len(self.numcommands[splitc[0]]) > 1:
                        return None, (
                            "Use <module> %s, %s" % (splitc[0], splitc[0]) +
                            " is provided by multiple modules: %s" % (
                                ', '.join(self.numcommands[splitc[0]])
                            ))
                argtext = ' '.join(split[len(splitc):])
                try:
                    context.exceptcancommand(v[0], v[1])
                    return self.parsecommand(context,
                                             text, v, argtext), None
                except ParserBadCommand as e:
                    return None, e
                except NoPerms as e:
                    if not str(e):
                        return None, None
                    return None, e
                except NoArg as e:
                    return None, "%s, Usage: %s %s" % (e,
                                                       ' '.join(splitc),
                                                       self.gethelp(v[1])[0])
                except Exception as e:
                    import traceback
                    traceback.print_exc()
                    return None, "Internal Error: %s" % type(e).__name__
        responses = []
        self.dohook('command', context, text, responses, False)
        for r in responses:
            if r[0] is not None:
                return r[0], None
            elif r[1] is not None:
                return None, r[1]
            else:
                continue

        return None, self.settings.get('messages.notfound')
<commit_msg>dootimers<commit_after># -*- coding: utf-8 -*-
import time
from threading import Lock
from .loader import *
from .args import *
from .userdata import *
from .exceptions import *
from .module import *
from .context import *
from .settings import *
from .running import runningservers

threads = True
run = True

from lib import utils, parser
[reload(x) for x in [utils, parser]]

def make_server(module, kind, name, shared, options):
    global currentplugin
    if kind not in servers:
        loadnamedmodule(module)
    if kind not in servers:
        raise IndexError("%s is not a valid server type!" % kind)
    return servers[kind](name, shared, options)

def load_server(*args):
    server = make_server(*args)
    runningservers.append(server)

class Server(LoaderBase):

    """The Server Plugin."""

    """Override with plugins that are required to run the server."""
    requiredplugins = []

    """Default Options."""
    options = {
        'charlimit': 0,
    }

    """Optionally loaded plugins."""
    autoload = []

    dautoload = [
        "misc",
        "internet",
        "games",
    ]

    Settings = Settings

    def __init__(self, name, shared, options):
        self.name = name
        self.shared = shared
        self.hooks = {}
        self.globalaliases = {}
        self.runlock = Lock()
        self.timers = {}
        self.otimers = []
        self.options.update(options)
        self.settings = self.Settings(self)
        self.build_settings()
        self.modules = {}
        self.plugins = {}
        self.protected = []
        self.righttypes = {}
        self.registry = {}
        self.pluginpaths = []
        for k in ["core",
                  self.index] + self.requiredplugins:
                self.loadplugin(k)
                self.protected.append(k)
                for x in newmodules:
                    self.protected.append(k.split('/')[0] + '/%s' % x)
        self.build_lists()
        for k in self.dautoload + self.autoload + self.settings.get(
                "server.autoload"):
                self.loadplugin(k, auto=True)
        self.build_lists()
        self.addhook("server_ready", "sinit", self.ready)
        self.dohook("server_ready")

    def addrights(self, d):
        """Add <d> to the rights hierarchy."""
        self.righttypes.update(d)

    def opt(self, n):
        """Get config.py value <n>."""
        if n not in self.options and n in Server.options:
            return Server.options[n]
        return self.options[n]

    def log(self, category, text):
        """Log <text> under <category>."""
        print(("%s %s: %s" % (self.name, category, text.strip())))
        self.dohook("log", "bot", category, text.strip())

    def build_settings(self):
        """Ready to build settings."""
        pass

    def build_lists(self):
        """Recreate the command and settings lists."""
        self.commands = {}
        self.numcommands = {}
        for m in list(self.modules.values()):
            for k, v in list(m.commands.items()):
                self.commands[(m.plugin, m.index, k)] = (m, v)
                if k not in self.numcommands:
                    self.numcommands[k] = []
                self.numcommands[k].append(m.index)
        self.commands = sorted(list(self.commands.items()),
                               key=lambda x: -len(x[0][2].split()))
        self.settings.user = []
        self.settings.defaults = {}
        self.settings.tree = {}
        self.dohook("core_prepare_settings")
        for m in list(self.modules.values()):
            for k, v in m.serversettings:
                self.settings.add(k, v)

    def addhook(self, name, uname, function):
        """Add a hook to <name> with the unique id <uname>
        and the function <function>."""
        if name not in self.hooks:
            self.hooks[name] = {}
        self.hooks[name][uname] = function

    def dohook(self, name, *args):
        """Call all functions registered to <name> with <*args>."""
        if name in self.hooks:
            for f in list(self.hooks[name].values()):
                f(*args)

    def addtimer(self, f, n, t):
        """Add a timer with unique name <n>, function <f> and timeout <t>."""
        self.timers[n] = {
            'name': n,
            'function': f,
            'time': t,
            'last': 0,
        }

    def callonce(self, f, t):
        """Call f after <t> ms."""
        self.otimers.append({
            'start': time.time(),
            'function': f,
            'time': t,
        })

    def dotimers(self):
        for timer in list(self.timers.values()):
            if time.time() - timer['last'] > timer['time'] / 1000:
                try:
                    timer['function']()
                except:
                    import traceback
                    traceback.print_exc()
                timer['last'] = time.time()
        self.dootimers()

    def dootimers(self):
        tod = []
        i = 0
        for timer in self.otimers:
            if time.time() - timer['start'] > timer['time'] / 1000:
                try:
                    timer['function']()
                except:
                    import traceback
                    traceback.print_exc()
                tod.append(i)
            i += 1
        tod.reverse()
        for i in tod:
            del self.otimers[i]

    def rset(self, n, v):
        """Register a function or structure to be used by other modules."""
        self.registry[n] = v

    def rget(self, n):
        """Get a value from the registry."""
        return self.registry[n]

    def rhas(self, n):
        """Is a key in the registry?"""
        return n in self.registry

    def corerun(self):
        if self.build:
            self.build = False
            self.build_lists()
        try:
            self.run()
        except:
            import traceback
            traceback.print_exc()
            global run
            run = False

    def splitparse(self, text, context=None):
        sections = []
        sectiond = {}
        sectione = {}
        idx = 0
        try:
            cchar = text[idx]
        except IndexError:
            return sections, sectiond
        section = ""
        escaped = False
        quoted = None
        running = False
        runningsection = ""
        rlevel = 0
        while cchar is not None:
            if not escaped and cchar == parser.escape:
                escaped = True
                if not section:
                    sectiond[len(sections)] = "cooked"
            elif escaped:
                if cchar in ["%s%s" % (parser.escape, parser.quotes)]:
                    section += cchar
                    escaped = False
                else:
                    section += cchar
                    escaped = False
            elif not quoted and cchar == parser.run[0]:
                if not running:
                    runningsection = section
                    section = ""
                    running = True
                else:
                    section += cchar
                rlevel += 1
            elif not quoted and cchar == parser.run[1]:
                rlevel -= 1
                if running and rlevel == 0:
                    c = section
                    section = self.runcommand(context, section)[0]
                    if section is None:
                        raise ParserBadCommand("Failed running: {%s}" % c)
                    section = runningsection + section
                    running = False
                else:
                    section += cchar
            elif not quoted and cchar in parser.quotes and not running:
                quoted = cchar
                if not section:
                    sectiond[len(sections)] = "cooked"
            elif quoted and not running:
                if cchar == quoted:
                    quoted = None
                    if not section:
                        sectione[len(sections)] = True
                else:
                    section += cchar
            else:
                if cchar == ' ' and not running:
                    if section or len(sections) in sectione:
                        sections.append(section)
                    section = ""
                else:
                    section += cchar
            idx += 1
            cchar = text[idx] if idx in range(len(text)) else None
        if section or len(sections) in sectione:
            sections.append(section)
        section = ""
        return sections, sectiond

    def makeargdict(self, argtext, context, v):
        sections, sectiond = self.splitparse(argtext, context)
        parsedargs = {}
        args = [a for a in v[1]['args'] if not a['kv']]
        kvargs = [a for a in v[1]['args'] if a['kv']]
        argi = 0
        sectioni = 0
        while sectioni in range(len(sections)):
            st = sections[sectioni]
            sd = sectiond[sectioni] if sectioni in sectiond else ""
            done = False
            if sd != "cooked":
                for prefix in ['--', '-']:
                    if st.startswith(prefix):
                        param = st[len(prefix):]
                        name = param.split('=')[0]
                        if name in [a['name'] for a in kvargs]:
                            try:
                                parsedargs[name] = param.split('=')[1]
                            except IndexError:
                                parsedargs[name] = ""
                            done = True
                        break
            if not done:
                if argi in range(len(args)):
                    arg = args[argi]
                    if arg['optional']:
                        if arg['recognizer'](st):
                            parsedargs[arg['name']] = st
                        else:
                            argi += 1
                            if argi in range(len(args)):
                                arg = args[argi]
                    if arg['full']:
                        parsedargs[arg['name']] = ' '.join(
                            sections[sectioni:]
                        )
                        argi = len(args)
                    else:
                        parsedargs[arg['name']] = st
                    argi += 1
            sectioni += 1
        return parsedargs

    def parsecommand(self, context, text, v, argtext):
        parsedargs = self.makeargdict(argtext, context, v)
        args = Args(parsedargs)
        return v[1]['function'](context, args)

    def getrights(self, *args):
        """Set by modules to get rights."""
        pass

    def modulesetup(self, m):
        """Modify and return <m>, to add attributes to the module class."""
        return m

    def idstring(self, context):
        """Return the rights idstring from <context>.
        Implemented by modules."""
        pass

    def shutdown(self):
        """Called on bot restart."""
        pass

    def commandlist(self):
        """List of commands and names."""
        commands = []
        for k, v in self.commands:
            for splitc in [
                    [v[0].plugin] + [v[0].index] + v[1]['name'].split(),
                    [v[0].index] + v[1]['name'].split(),
                    v[1]['name'].split()]:
                        commands.append((splitc, v))
        return commands

    def runcommand(self, context, text):
        """Run <text> as <context>."""
        commands = self.commandlist()
        split = text.split()
        commands.sort(key=lambda x: -len(x[0]))
        for splitc, v in commands:
            if splitc == split[:len(splitc)]:
                if len(splitc) == 1:
                    if len(self.numcommands[splitc[0]]) > 1:
                        return None, (
                            "Use <module> %s, %s" % (splitc[0], splitc[0]) +
                            " is provided by multiple modules: %s" % (
                                ', '.join(self.numcommands[splitc[0]])
                            ))
                argtext = ' '.join(split[len(splitc):])
                try:
                    context.exceptcancommand(v[0], v[1])
                    return self.parsecommand(context,
                                             text, v, argtext), None
                except ParserBadCommand as e:
                    return None, e
                except NoPerms as e:
                    if not str(e):
                        return None, None
                    return None, e
                except NoArg as e:
                    return None, "%s, Usage: %s %s" % (e,
                                                       ' '.join(splitc),
                                                       self.gethelp(v[1])[0])
                except Exception as e:
                    import traceback
                    traceback.print_exc()
                    return None, "Internal Error: %s" % type(e).__name__
        responses = []
        self.dohook('command', context, text, responses, False)
        for r in responses:
            if r[0] is not None:
                return r[0], None
            elif r[1] is not None:
                return None, r[1]
            else:
                continue

        return None, self.settings.get('messages.notfound')
<|endoftext|>


<commit_before>#! /usr/bin/python
import subprocess
import os
import sys

def _execute(*args, **kwargs):
    result = subprocess.call(*args, **kwargs)
    if result != 0:
        sys.exit(result)

if __name__ == '__main__':
    python_version = sys.version_info

    deps = [
        "execnet>=1.0.9",
        "pytest",
        "pyzmq",
        "sqlalchemy",
    ]

    if (3, 2) <= python_version < (3, 3):
        deps.append("markupsafe==0.15")
        deps.append("Jinja2==2.6")
    else:
        deps.append("Jinja2")
    print("Setting up dependencies...")
    _execute([os.path.join(os.path.dirname(sys.executable), "pip"),  "install"] + deps, shell=False)
<commit_msg>Fix test_setup.py for Windows<commit_after>#! /usr/bin/python
import os
import pip
import sys

if __name__ == '__main__':
    python_version = sys.version_info

    deps = [
        "execnet>=1.0.9",
        "pytest",
        "pyzmq",
        "sqlalchemy",
    ]

    if (3, 2) <= python_version < (3, 3):
        deps.append("markupsafe==0.15")
        deps.append("Jinja2==2.6")
    else:
        deps.append("Jinja2")
    print("Setting up dependencies...")
    result = pip.main(["install"] + deps)
    sys.exit(result)
<|endoftext|>


<commit_before># -*- coding: utf-8 -*-
"""Tests for libvcs git repos."""
from __future__ import absolute_import, print_function, unicode_literals

import datetime
import os

import pytest

from libvcs import exc
from libvcs._compat import string_types
from libvcs.git import GitRemote, GitRepo
from libvcs.shortcuts import create_repo_from_pip_url
from libvcs.util import run, which

if not which('git'):
    pytestmark = pytest.mark.skip(reason="git is not available")

def test_repo_git_obtain_initial_commit_repo(tmpdir):
    """initial commit repos return 'initial'.

    note: this behaviors differently from git(1)'s use of the word "bare".
    running `git rev-parse --is-bare-repository` would return false.
    """
    repo_name = 'my_git_project'

    run(['git', 'init', repo_name], cwd=str(tmpdir))

    bare_repo_dir = tmpdir.join(repo_name)

    git_repo = create_repo_from_pip_url(
        **{
            'pip_url': 'git+file://' + str(bare_repo_dir),
            'repo_dir': str(tmpdir.join('obtaining a bare repo')),
        }
    )

    git_repo.obtain()
    assert git_repo.get_revision() == 'initial'

def test_repo_git_obtain_full(tmpdir, git_remote):
    git_repo = create_repo_from_pip_url(
        **{
            'pip_url': 'git+file://' + git_remote,
            'repo_dir': str(tmpdir.join('myrepo')),
        }
    )

    git_repo.obtain()

    test_repo_revision = run(['git', 'rev-parse', 'HEAD'], cwd=git_remote)

    assert git_repo.get_revision() == test_repo_revision
    assert os.path.exists(str(tmpdir.join('myrepo')))

def test_repo_update_handle_cases(tmpdir, git_remote, mocker):
    git_repo = create_repo_from_pip_url(
        **{
            'pip_url': 'git+file://' + git_remote,
            'repo_dir': str(tmpdir.join('myrepo')),
        }
    )

    git_repo.obtain()  # clone initial repo
    mocka = mocker.spy(git_repo, 'run')
    git_repo.update_repo()

    mocka.assert_any_call(['symbolic-ref', '--short', 'HEAD'])

    mocka.reset_mock()

    # will only look up symbolic-ref if no rev specified for object
    git_repo.rev = 'HEAD'
    git_repo.update_repo()
    assert mocker.call(['symbolic-ref', '--short', 'HEAD']) not in mocka.mock_calls

def test_progress_callback(tmpdir, git_remote, mocker):
    def progress_callback_spy(output, timestamp):
        assert isinstance(output, string_types)
        assert isinstance(timestamp, datetime.datetime)

    progress_callback = mocker.Mock(
        name='progress_callback_stub', side_effect=progress_callback_spy
    )

    run(['git', 'rev-parse', 'HEAD'], cwd=git_remote)

    # create a new repo with the repo as a remote
    git_repo = create_repo_from_pip_url(
        **{
            'pip_url': 'git+file://' + git_remote,
            'repo_dir': str(tmpdir.join('myrepo')),
            'progress_callback': progress_callback,
        }
    )
    git_repo.obtain()

    assert progress_callback.called

def test_remotes(parentdir, git_remote):
    repo_name = 'myrepo'
    remote_name = 'myremote'
    remote_url = 'https://localhost/my/git/repo.git'

    git_repo = create_repo_from_pip_url(
        pip_url='git+file://{git_remote}'.format(git_remote=git_remote),
        repo_dir=os.path.join(str(parentdir), repo_name),
    )
    git_repo.obtain()
    git_repo.remote_set(name=remote_name, url=remote_url)

    assert (remote_name, remote_url, remote_url) == git_repo.remote_get(remote_name)

def test_git_get_url_and_rev_from_pip_url():
    pip_url = 'git+ssh://git@bitbucket.example.com:7999/PROJ/repo.git'
    url, rev = GitRepo.get_url_and_revision_from_pip_url(pip_url)
    assert 'ssh://git@bitbucket.example.com:7999/PROJ/repo.git' == url
    assert rev is None

    pip_url = '%s@%s' % (
        'git+ssh://git@bitbucket.example.com:7999/PROJ/repo.git',
        'eucalyptus',
    )
    url, rev = GitRepo.get_url_and_revision_from_pip_url(pip_url)
    assert 'ssh://git@bitbucket.example.com:7999/PROJ/repo.git' == url
    assert rev == 'eucalyptus'

    # the git manual refers to this as "scp-like syntax"
    # https://git-scm.com/docs/git-clone
    pip_url = '%s@%s' % ('git+user@hostname:user/repo.git', 'eucalyptus')
    url, rev = GitRepo.get_url_and_revision_from_pip_url(pip_url)
    assert 'user@hostname:user/repo.git' == url
    assert rev == 'eucalyptus'

def test_remotes_preserves_git_ssh(parentdir, git_remote):
    # Regression test for #14
    repo_name = 'myexamplegit'
    repo_dir = os.path.join(str(parentdir), repo_name)
    remote_name = 'myremote'
    remote_url = 'git+ssh://git@github.com/tony/AlgoXY.git'

    git_repo = create_repo_from_pip_url(pip_url=remote_url, repo_dir=repo_dir)
    git_repo.obtain()
    git_repo.remote_set(name=remote_name, url=remote_url)

    assert (
        GitRemote(remote_name, remote_url, remote_url)._asdict()
        in git_repo.remotes_get.values()
    )

def test_private_ssh_format(pip_url_kwargs):
    pip_url_kwargs.update(
        **{'pip_url': 'git+ssh://github.com:' + '/tmp/omg/private_ssh_repo'}
    )

    with pytest.raises(exc.LibVCSException) as excinfo:
        create_repo_from_pip_url(**pip_url_kwargs)
    excinfo.match(r'is malformatted')

def test_ls_remotes(git_repo):
    remotes = git_repo.remotes_get

    assert 'origin' in remotes

def test_get_remotes(git_repo):
    assert 'origin' in git_repo.remotes_get

@pytest.mark.parametrize('repo_name,new_repo_url', [['myrepo', 'file:///apples'],])
def test_set_remote(git_repo, repo_name, new_repo_url):
    mynewremote = git_repo.remote_set(name=repo_name, url='file:///')

    assert 'file:///' in mynewremote, 'remote_set returns remote'

    assert 'file:///' in git_repo.remote_get(
        name=repo_name
    ), 'remote_get returns remote'

    assert 'myrepo' in git_repo.remotes_get, '.remotes_get() returns new remote'

    with pytest.raises(
        exc.CommandError,
        match='.*remote {repo_name} already exists.*'.format(repo_name=repo_name),
    ):
        mynewremote = git_repo.remote_set(name='myrepo', url=new_repo_url)

    mynewremote = git_repo.remote_set(name='myrepo', url=new_repo_url, overwrite=True)

    assert new_repo_url in git_repo.remote_get(
        name='myrepo'
    ), 'Running remove_set should overwrite previous remote'
<commit_msg>test: Update to use non-deprecated methods<commit_after># -*- coding: utf-8 -*-
"""Tests for libvcs git repos."""
from __future__ import absolute_import, print_function, unicode_literals

import datetime
import os

import pytest

from libvcs import exc
from libvcs._compat import string_types
from libvcs.git import GitRemote, GitRepo
from libvcs.shortcuts import create_repo_from_pip_url
from libvcs.util import run, which

if not which('git'):
    pytestmark = pytest.mark.skip(reason="git is not available")

def test_repo_git_obtain_initial_commit_repo(tmpdir):
    """initial commit repos return 'initial'.

    note: this behaviors differently from git(1)'s use of the word "bare".
    running `git rev-parse --is-bare-repository` would return false.
    """
    repo_name = 'my_git_project'

    run(['git', 'init', repo_name], cwd=str(tmpdir))

    bare_repo_dir = tmpdir.join(repo_name)

    git_repo = create_repo_from_pip_url(
        **{
            'pip_url': 'git+file://' + str(bare_repo_dir),
            'repo_dir': str(tmpdir.join('obtaining a bare repo')),
        }
    )

    git_repo.obtain()
    assert git_repo.get_revision() == 'initial'

def test_repo_git_obtain_full(tmpdir, git_remote):
    git_repo = create_repo_from_pip_url(
        **{
            'pip_url': 'git+file://' + git_remote,
            'repo_dir': str(tmpdir.join('myrepo')),
        }
    )

    git_repo.obtain()

    test_repo_revision = run(['git', 'rev-parse', 'HEAD'], cwd=git_remote)

    assert git_repo.get_revision() == test_repo_revision
    assert os.path.exists(str(tmpdir.join('myrepo')))

def test_repo_update_handle_cases(tmpdir, git_remote, mocker):
    git_repo = create_repo_from_pip_url(
        **{
            'pip_url': 'git+file://' + git_remote,
            'repo_dir': str(tmpdir.join('myrepo')),
        }
    )

    git_repo.obtain()  # clone initial repo
    mocka = mocker.spy(git_repo, 'run')
    git_repo.update_repo()

    mocka.assert_any_call(['symbolic-ref', '--short', 'HEAD'])

    mocka.reset_mock()

    # will only look up symbolic-ref if no rev specified for object
    git_repo.rev = 'HEAD'
    git_repo.update_repo()
    assert mocker.call(['symbolic-ref', '--short', 'HEAD']) not in mocka.mock_calls

def test_progress_callback(tmpdir, git_remote, mocker):
    def progress_callback_spy(output, timestamp):
        assert isinstance(output, string_types)
        assert isinstance(timestamp, datetime.datetime)

    progress_callback = mocker.Mock(
        name='progress_callback_stub', side_effect=progress_callback_spy
    )

    run(['git', 'rev-parse', 'HEAD'], cwd=git_remote)

    # create a new repo with the repo as a remote
    git_repo = create_repo_from_pip_url(
        **{
            'pip_url': 'git+file://' + git_remote,
            'repo_dir': str(tmpdir.join('myrepo')),
            'progress_callback': progress_callback,
        }
    )
    git_repo.obtain()

    assert progress_callback.called

def test_remotes(parentdir, git_remote):
    repo_name = 'myrepo'
    remote_name = 'myremote'
    remote_url = 'https://localhost/my/git/repo.git'

    git_repo = create_repo_from_pip_url(
        pip_url='git+file://{git_remote}'.format(git_remote=git_remote),
        repo_dir=os.path.join(str(parentdir), repo_name),
    )
    git_repo.obtain()
    git_repo.set_remote(name=remote_name, url=remote_url)

    assert (remote_name, remote_url, remote_url) == git_repo.remote(remote_name)

def test_git_get_url_and_rev_from_pip_url():
    pip_url = 'git+ssh://git@bitbucket.example.com:7999/PROJ/repo.git'
    url, rev = GitRepo.get_url_and_revision_from_pip_url(pip_url)
    assert 'ssh://git@bitbucket.example.com:7999/PROJ/repo.git' == url
    assert rev is None

    pip_url = '%s@%s' % (
        'git+ssh://git@bitbucket.example.com:7999/PROJ/repo.git',
        'eucalyptus',
    )
    url, rev = GitRepo.get_url_and_revision_from_pip_url(pip_url)
    assert 'ssh://git@bitbucket.example.com:7999/PROJ/repo.git' == url
    assert rev == 'eucalyptus'

    # the git manual refers to this as "scp-like syntax"
    # https://git-scm.com/docs/git-clone
    pip_url = '%s@%s' % ('git+user@hostname:user/repo.git', 'eucalyptus')
    url, rev = GitRepo.get_url_and_revision_from_pip_url(pip_url)
    assert 'user@hostname:user/repo.git' == url
    assert rev == 'eucalyptus'

def test_remotes_preserves_git_ssh(parentdir, git_remote):
    # Regression test for #14
    repo_name = 'myexamplegit'
    repo_dir = os.path.join(str(parentdir), repo_name)
    remote_name = 'myremote'
    remote_url = 'git+ssh://git@github.com/tony/AlgoXY.git'

    git_repo = create_repo_from_pip_url(pip_url=remote_url, repo_dir=repo_dir)
    git_repo.obtain()
    git_repo.set_remote(name=remote_name, url=remote_url)

    assert (
        GitRemote(remote_name, remote_url, remote_url)._asdict()
        in git_repo.remotes.values()
    )

def test_private_ssh_format(pip_url_kwargs):
    pip_url_kwargs.update(
        **{'pip_url': 'git+ssh://github.com:' + '/tmp/omg/private_ssh_repo'}
    )

    with pytest.raises(exc.LibVCSException) as excinfo:
        create_repo_from_pip_url(**pip_url_kwargs)
    excinfo.match(r'is malformatted')

def test_ls_remotes(git_repo):
    remotes = git_repo.remotes

    assert 'origin' in remotes

def test_get_remotes(git_repo):
    assert 'origin' in git_repo.remotes

@pytest.mark.parametrize('repo_name,new_repo_url', [['myrepo', 'file:///apples'],])
def test_set_remote(git_repo, repo_name, new_repo_url):
    mynewremote = git_repo.set_remote(name=repo_name, url='file:///')

    assert 'file:///' in mynewremote, 'set_remote returns remote'

    assert 'file:///' in git_repo.remote(name=repo_name), 'remote returns remote'

    assert 'myrepo' in git_repo.remotes, '.remotes() returns new remote'

    with pytest.raises(
        exc.CommandError,
        match='.*remote {repo_name} already exists.*'.format(repo_name=repo_name),
    ):
        mynewremote = git_repo.set_remote(name='myrepo', url=new_repo_url)

    mynewremote = git_repo.set_remote(name='myrepo', url=new_repo_url, overwrite=True)

    assert new_repo_url in git_repo.remote(
        name='myrepo'
    ), 'Running remove_set should overwrite previous remote'
<|endoftext|>