Skip to content

Commit

Permalink
Added basic support for building SCons projects.
Browse files Browse the repository at this point in the history
git-svn-id: http://svn.textmate.org/trunk/Bundles/SCons.tmbundle@2814 dfb7d73b-c2ec-0310-8fea-fb051d288c6d
  • Loading branch information
Mitch Chapman committed Mar 3, 2006
0 parents commit 0c71e51
Show file tree
Hide file tree
Showing 5 changed files with 264 additions and 0 deletions.
27 changes: 27 additions & 0 deletions Commands/Build.plist
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>beforeRunningCommand</key>
<string>saveModifiedFiles</string>
<key>command</key>
<string># TM_IGNORE_WARNINGS is a sequence of glob patterns of files in which to ignore
# warnings. Right now it doesn't support escaped ':" -- the separator character.
# export TM_IGNORE_WARNINGS="mitchcode_*.h:*/MitchCode/*"
python -u "${TM_BUNDLE_SUPPORT}/bin/scons_html_wrapper.py"</string>
<key>fallbackInput</key>
<string>word</string>
<key>input</key>
<string>selection</string>
<key>keyEquivalent</key>
<string>@b</string>
<key>name</key>
<string>Build</string>
<key>output</key>
<string>showAsHTML</string>
<key>scope</key>
<string>source.c, source.objc, source.c++, source.objc++, source.python</string>
<key>uuid</key>
<string>C0F342BE-9F5F-4D62-A3C8-D9C95B46F4CD</string>
</dict>
</plist>
25 changes: 25 additions & 0 deletions LICENSE.BSD
@@ -0,0 +1,25 @@
This bundle is released under the following BSD license.

Copyright (C) 2006 by Mitch Chapman
mitch.chapman@mac.com

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.

THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
125 changes: 125 additions & 0 deletions Support/bin/scons_gcc_filter.py
@@ -0,0 +1,125 @@
#!/usr/bin/env python
"""Filter for scons output, adds TextMate hyperlinks for gcc error msgs."""

import re
import sys
import os
import fnmatch
import cgi

class SConsGCCFilter(object):
stlIgnore = ["iosfwd", "streambuf", "streambuf_iterator.h", "basic_ios.h",
"basic_string.h", "istream", "istream.tcc",
"ostream", "ostream.tcc",
"fstream.tcc",
]

def __init__(self, currdir=None):
self._content = ""
self._index = 0
if currdir is None:
currdir = os.getcwd()
self._currdir = currdir

self._ignorePatterns = []
self._initIgnorePatterns()
self._errExpr = re.compile(
r"^(?P<preamble>"
r"(?P<pathname>[/A-Za-z0-9_.+]*):"
r"(?P<line_num>\d+):\s*"
r"(?P<errwarn>(error|warning)):"
r")"
r"(?P<error_msg>.*(\n .*)*)",
re.MULTILINE)

def _initIgnorePatterns(self):
"""Initialize with settings from TM_IGNORE_WARNINGS, if any."""
value = os.environ.get("TM_IGNORE_WARNINGS")
if value is not None:
# Better hope nobody uses a filename containing ':'.
patterns = value.split(":")
for p in patterns:
self._addIgnorePath(p)

def _addIgnorePath(self, pattern):
"""Ignore (or rather, don't highlight) warnings from files
whose names match the glob pattern."""
print "<i>Will not highlight warnings in %r</i><br/>" % cgi.escape(pattern)
self._ignorePatterns.append(pattern)

def _isIgnoredPath(self, pathname):
for pattern in self._ignorePatterns:
if fnmatch.fnmatch(pathname, pattern):
return True
return False

def _isIgnoredSTLWarning(self, filename):
# GCC 3.3 -Weffc++
# produces some warnings because of code generated from
# STL. Uncomment the return statement to pass-through these warnings
#return False
result = ((filename in self.stlIgnore) or
fnmatch.fnmatch(filename, "stl_*.h"))
return result

def feed(self, newContent):
self._content += newContent

def _worthHighlighting(self, pathname, isError):
filename = os.path.basename(pathname)
result = (isError or not
(self._isIgnoredPath(pathname) or
self._isIgnoredSTLWarning(filename)))
return result

def filter(self, consumeAll=False):
resultList = []

currdir = self._currdir
content = self._content
search = self._errExpr.search
while True:
match = search(content)
if match is None:
if consumeAll:
resultList.append(content)
self._content = ""
else:
# Error msgs start near beginning of a line, so flush
# all unmatched, complete lines.
iLine = content.rfind("\n")
if (iLine >= 0):
resultList.append(content[:iLine+1])
content = content[iLine+2:]
# Save the rest for later consumption.
self._content = content
break
else:
resultList.append(content[:match.start()])
pathname = match.group("pathname")
isError = (match.group("errwarn") == "error")
if self._worthHighlighting(pathname, isError):
msg = match.group("error_msg")
lineNum = match.group("line_num")
errorURL = ("txmt://open?url=file://%s/%s&line=%s" %
(currdir, pathname, lineNum))
resultList.append('<a href="%s">' % errorURL)
resultList.append(match.group("preamble"))
resultList.append('</a>')
resultList.append(msg)
resultList.append("<br/>")
else:
resultList.append(match.group(0))

content = content[match.end()+1:]

result = "".join(resultList).replace("\n", "<br/>\n")
return result

def main():
f = SConsGCCFilter()
f.feed(sys.stdin.read())
print f.filter(consumeAll=True)

if __name__ == "__main__":
main()
73 changes: 73 additions & 0 deletions Support/bin/scons_html_wrapper.py
@@ -0,0 +1,73 @@
#!/usr/bin/env python
"""Runs scons and wraps its output as HTML."""

import sys
import os
import select
from scons_gcc_filter import SConsGCCFilter
import cgi

def findSConstructDir():
"""Search upward from the current dir for the top-level SConstruct dir."""
result = None
d = os.getcwd()
while (d != "/") and not result:
candidate = os.path.join(d, "SConstruct")
if os.path.exists(candidate) and os.path.isfile(candidate):
result = d
d = os.path.dirname(d)
return result or os.getcwd()

def write(s):
"""Write a string to stdout, flushing immediately."""
if s:
sys.stdout.write(s)
sys.stdout.flush()

def filterOutput(cmd):
"""Run a shell cmd, reformatting output as HTML."""
theFilter = SConsGCCFilter(findSConstructDir())

childIn, childOut, childErr = os.popen3(cmd, 0)
infd = childIn.fileno()
outfd = childOut.fileno()
errfd = childErr.fileno()
inSet = [outfd, errfd]
errSet = [infd, outfd, errfd]

while True:
ins, outs, errs = select.select(inSet, [], errSet)
if errs:
print "<b>Error descriptors: <i>%s</i><b>" % repr(errs)
for item in errs:
errSet.remove(item)
if not errSet:
break
for fd in ins:
content = os.read(fd, 65536)
if not content:
inSet.remove(fd)
else:
theFilter.feed(content)
if ins:
write(theFilter.filter())
if not inSet:
childIn.close()
childOut.close()
childErr.close()
write(theFilter.filter(consumeAll=True))
break


def runSCons():
"""Run SCons in a not-very-flexible way."""
cmd = "scons -u 2>&1"
print "<i># Working dir: %s</i><br/>" % cgi.escape(os.getcwd())
print "<b>%s</b><br/>" % cgi.escape(cmd)
filterOutput(cmd)

def main():
runSCons()

if __name__ == "__main__":
main()
14 changes: 14 additions & 0 deletions info.plist
@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>name</key>
<string>SCons</string>
<key>ordering</key>
<array>
<string>C0F342BE-9F5F-4D62-A3C8-D9C95B46F4CD</string>
</array>
<key>uuid</key>
<string>31ACFE4A-592A-41C5-9D23-0C315EC5F7A8</string>
</dict>
</plist>

0 comments on commit 0c71e51

Please sign in to comment.