Skip to content

Commit

Permalink
Bump version to 0.8.1; replace existing build window on first build, …
Browse files Browse the repository at this point in the history
…better respects settings changes; more responsive output display
  • Loading branch information
Walt Woods committed Jan 9, 2013
1 parent 4c93de7 commit 1b24601
Show file tree
Hide file tree
Showing 10 changed files with 110 additions and 171 deletions.
15 changes: 13 additions & 2 deletions ContextBuild.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@
import sublime_plugin

import datetime
import re
import threading
import time

from runnerMocha import RunnerMocha
from runnerNosetests import RunnerNosetests

runners = [ RunnerNosetests, RunnerMocha ]

options = sublime.load_settings('ContextBuild.sublime-settings')

class Build(object):
Expand Down Expand Up @@ -69,6 +69,17 @@ def run(self):

newView = True
if options.get('hide_last_build_on_new'):
if self.lastView is None:
# Plugin may have been reloaded, see if our window has any
# other context builds that we should replace.
for view in self.window.views():
if (re.match("^Build.*\.context-build$", view.name())
is not None):
# This is an old build view from a previous invocation,
# use it instead of creating a new one.
self.lastView = view
break

if (self.lastView
and self.window.get_view_index(self.lastView)[0] != -1):
self.view = self.lastView
Expand All @@ -83,8 +94,8 @@ def run(self):
# Be sure to make the view for our output in the main thread, so
# that we don't have issues with memory access in sublime.
self.view = self.window.new_file()
self.viewId = self.view.id()
self.lastView = self.view
self.viewId = self.view.id()

now = datetime.datetime.now()
timeStr = now.strftime("%I:%M:%S%p-%d-%m-%Y")
Expand Down
14 changes: 9 additions & 5 deletions ContextBuild.sublime-settings
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
{
//Project-specific build configuration
//=========================================================================
//Project-specific build configuration (may be overridden by settings in
//.sublime-project files
//=========================================================================
//The PATH to used for launching subprocesses
"context_build_path": "/usr/local/bin:/usr/bin:/usr/sbin",
//The PYTHONPATH to use for launching python_runner
"context_build_python_path": "",
//Default runner for this project.
//Default runner for this project
"context_build_runner": "nosetests",
//Specific runners (run before the default) for

//Plugin configuration
//=========================================================================
//Plugin configuration (global)
//=========================================================================
//Hide last build when a new build is issued in the same window?
"hide_last_build_on_new": true,
"save_before_build": true,

//Settings for Built-in runners
//nosetests
"nosetests_args": "-v",
"nosetests_args": "",
//mocha
"mocha_compilers": []
}
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,15 @@ ContextBuild -> Settings - User). For instance:
{
"mocha_compilers": [ "sjs:/home/walt/dev/seriousjs/src/seriousjs" ]
}

## Changelog

### 0.8.1

* When you close and re-open sublime text, any existing build views will be
replaced with new builds, rather than creating a new view.

* Output from child process (e.g. nosetests) displays as it happens rather
than based on lines.

* Repeated builds are sensitive to config changes
137 changes: 0 additions & 137 deletions Side Bar.sublime-workspace

This file was deleted.

2 changes: 1 addition & 1 deletion packages.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"platforms": {
"*": [
{
"version": "0.8.0",
"version": "0.8.1",
"url": "https://github.com/sellerengine/sublime_context_build"
}
]
Expand Down
36 changes: 24 additions & 12 deletions runnerBase.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,16 +113,17 @@ def _coalesceOption(self, name, default = ''):
return self.view.settings().get(name, self.options.get(name, default))


def _dumpStdout(self, p, lineCallback):
def _dumpStdout(self, p, outputCallback):
"""Dumps the stdout from subprocess p; called in a new thread."""
while p.poll() is None:
while True:
l = p.stdout.readline()
if not l:
break
lineCallback(l)
try:
# May raise IOError if in non-blocking mode
l = p.stdout.read()
outputCallback(l)
except IOError:
pass
time.sleep(0.1)
lineCallback(p.stdout.read())
outputCallback(p.stdout.read())


def _escapePaths(self, paths):
Expand All @@ -148,14 +149,19 @@ def _runProcess(self, cmd, echoStdout = True, **kwargs):
the execution.
echoStdout -- If false, returns the standard output as a file-like
object.
object. If a callable, then the method passed will be
called with each buffered output read (not necessarily a line).
"""
cmd = str(self.cmd)
# Can't use unicode!
cmd = str(cmd)
defaultKwargs = {
'universal_newlines': True
}
if echoStdout:
defaultKwargs['stdout'] = subprocess.PIPE
# Don't buffer the output, but echo it as it comes in regardless
# of newlines, etc
defaultKwargs['bufsize'] = 1
else:
defaultKwargs['stdout'] = tempfile.TemporaryFile()
defaultKwargs['stderr'] = subprocess.STDOUT
Expand All @@ -168,13 +174,19 @@ def _runProcess(self, cmd, echoStdout = True, **kwargs):

p = subprocess.Popen(shlex.split(cmd), **defaultKwargs)
if echoStdout:
try:
import fcntl
fcntl.fcntl(p.stdout.fileno(), fcntl.F_SETFL, os.O_NONBLOCK)
except ImportError:
# Windows?
pass
if callable(echoStdout):
lineCallback = echoStdout
outputCallback = echoStdout
else:
lineCallback = lambda l: self.writeOutput(l, end = '')
outputCallback = lambda l: self.writeOutput(l, end = '')

stdThread = threading.Thread(target = self._dumpStdout,
args = (p, lineCallback))
args = (p, outputCallback))
stdThread.start()
while p.poll() is None:
if self._shouldStop():
Expand Down
35 changes: 26 additions & 9 deletions runnerMocha.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,27 @@ class RunnerMocha(RunnerBase):


def doRunner(self, writeOutput, shouldStop):
writeOutput("Running tests: " + self.cmd)
realCmd = self.cmd
mochaOptions = ""

# mocha_compilers is a system-wide setting, not a project setting,
# se we get it from options rather than settings.
compilers = self.options.get('mocha_compilers')
if compilers:
mochaOptions += ' --compilers '
mochaOptions += ','.join(compilers)

realCmd = realCmd.replace("{mocha_options}", mochaOptions)

writeOutput("Running tests: " + realCmd)
self._nextTestLines = None # Set to None before the header line
self._lastTest = -1
self._tests = {}
self._countOk = 0
self._countFailed = 0
self._allOutput = ""
# Use first failure as paths storage
self._runProcess(self.cmd, echoStdout = self._processLine)
self._runProcess(realCmd, echoStdout = self._processOutput)

self.writeOutput('')
self.writeOutput("=" * 80)
Expand All @@ -39,13 +52,7 @@ def doRunner(self, writeOutput, shouldStop):


def runnerSetup(self, paths = [], tests = {}):
cmd = "mocha --reporter tap"
# mocha_compilers is a system-wide setting, not a project setting,
# se we get it from options rather than settings.
compilers = self.options.get('mocha_compilers')
if compilers:
cmd += ' --compilers '
cmd += ','.join(compilers)
cmd = "mocha --reporter tap{mocha_options} "

if paths:
cmd += self._escapePaths(paths)
Expand Down Expand Up @@ -125,3 +132,13 @@ def _processLine(self, line):
self._tests[self._lastTest]['errorLines'].append(line.rstrip())
else:
self._nextTestLines.append(line.rstrip())


def _processOutput(self, output):
self._allOutput += output
while True:
parts = self._allOutput.split('\n', 1)
if len(parts) == 1:
break
self._processLine(parts[0] + '\n')
self._allOutput = parts[1]
14 changes: 9 additions & 5 deletions runnerNosetests.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,14 @@ class RunnerNosetests(RunnerBase):


def doRunner(self, writeOutput, shouldStop):
writeOutput("Running tests: " + self.cmd)
self._runProcess(self.cmd, echoStdout = True,
realCmd = self.cmd
nosetestsArgs = self.options.get('nosetests_args', '')
if nosetestsArgs:
# Must have preceding space
nosetestsArgs = ' ' + nosetestsArgs
realCmd = realCmd.replace("{nosetests_args}", nosetestsArgs)
writeOutput("Running tests: " + realCmd)
self._runProcess(realCmd, echoStdout = True,
env = { 'PYTHONPATH':
self.settings['context_build_python_path']})

Expand All @@ -37,9 +43,7 @@ def runnerSetup(self, paths = [], tests = {}):
self._noseIdsFile = os.path.join(tempfile.gettempdir(),
"context-build-nose-ids")
cmd += self._noseIdsFile
args = self.options.get('nosetests_args', '')
if args:
cmd += " " + args
cmd += "{nosetests_args}"

if paths:
cmd += self._escapePaths(paths)
Expand Down
Loading

0 comments on commit 1b24601

Please sign in to comment.