Index: buildbot/process/base.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/process/base.py,v
retrieving revision 1.84
diff -u -r1.84 base.py
--- buildbot/process/base.py	22 May 2008 22:13:22 -0000	1.84
+++ buildbot/process/base.py	26 May 2008 16:26:17 -0000
@@ -193,6 +193,9 @@
     def setLocks(self, locks):
         self.locks = locks
 
+    def setSlaveEnvironment(self, env):
+        self.slaveEnvironment = env
+
     def getSourceStamp(self):
         return self.source
 
Index: buildbot/process/builder.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/process/builder.py,v
retrieving revision 1.54
diff -u -r1.54 builder.py
--- buildbot/process/builder.py	22 May 2008 22:13:06 -0000	1.54
+++ buildbot/process/builder.py	26 May 2008 16:26:17 -0000
@@ -278,6 +278,8 @@
         self.builddir = setup['builddir']
         self.buildFactory = setup['factory']
         self.locks = setup.get("locks", [])
+        self.env = setup.get('env', {})
+        assert isinstance(self.env, dict)
         if setup.has_key('periodicBuildTime'):
             raise ValueError("periodicBuildTime can no longer be defined as"
                              " part of the Builder: use scheduler.Periodic"
@@ -587,6 +589,8 @@
         build = self.buildFactory.newBuild(requests)
         build.setBuilder(self)
         build.setLocks(self.locks)
+        if len(self.env) > 0:
+            build.setSlaveEnvironment(self.env)
 
         # start it
         self.startBuild(build, sb)
Index: buildbot/steps/shell.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/steps/shell.py,v
retrieving revision 1.23
diff -u -r1.23 shell.py
--- buildbot/steps/shell.py	22 May 2008 22:13:26 -0000	1.23
+++ buildbot/steps/shell.py	26 May 2008 16:26:17 -0000
@@ -133,17 +133,21 @@
         return ["'%s" % words[0], "%s" % words[1], "...'"]
 
     def setupEnvironment(self, cmd):
-        # XXX is this used? documented? replaced by properties?
-        # merge in anything from Build.slaveEnvironment . Earlier steps
-        # (perhaps ones which compile libraries or sub-projects that need to
-        # be referenced by later steps) can add keys to
-        # self.build.slaveEnvironment to affect later steps.
+        # merge in anything from Build.slaveEnvironment
+        # This can be set from a Builder-level environment, or from earlier
+        # BuildSteps. The latter method is deprecated and superceded by
+        # BuildProperties.
+        # Environment variables passed in by a BuildStep override
+        # those passed in at the Builder level.
         properties = self.build.getProperties()
         slaveEnv = self.build.slaveEnvironment
         if slaveEnv:
             if cmd.args['env'] is None:
                 cmd.args['env'] = {}
-            cmd.args['env'].update(properties.render(slaveEnv))
+            fullSlaveEnv = slaveEnv.copy()
+            fullSlaveEnv = properties.render(fullSlaveEnv)
+            fullSlaveEnv.update(cmd.args['env'])
+            cmd.args['env'] = fullSlaveEnv
             # note that each RemoteShellCommand gets its own copy of the
             # dictionary, so we shouldn't be affecting anyone but ourselves.
 
Index: buildbot/test/test_run.py
===================================================================
RCS file: /cvsroot/buildbot/buildbot/buildbot/test/test_run.py,v
retrieving revision 1.56
diff -u -r1.56 test_run.py
--- buildbot/test/test_run.py	22 May 2008 22:13:17 -0000	1.56
+++ buildbot/test/test_run.py	26 May 2008 16:26:17 -0000
@@ -843,3 +843,80 @@
 # of the bug where I forgot to make Waterfall inherit from StatusReceiver
 # such that buildSetSubmitted failed.
 
+config_test_builder = config_base + """
+from buildbot.scheduler import Scheduler
+c['schedulers'] = [Scheduler('quick', 'dummy', 0.1, ['dummy']),
+                   Scheduler('quick2', 'dummy2', 0.1, ['dummy2']),
+                   Scheduler('quick3', 'dummy3', 0.1, ['dummy3'])]
+
+from buildbot.steps.shell import ShellCommand
+f3 = factory.BuildFactory([
+    s(ShellCommand, command="sleep 3", env={'blah':'blah'})
+    ])
+
+c['builders'] = [{'name': 'dummy', 'slavename': 'bot1', 'env': {'foo':'bar'},
+                  'builddir': 'dummy', 'factory': f3}]
+
+c['builders'].append({'name': 'dummy2', 'slavename': 'bot1',
+                       'env': {'blah':'bar'}, 'builddir': 'dummy2',
+                       'factory': f3})
+
+f4 = factory.BuildFactory([
+    s(ShellCommand, command="sleep 3")
+    ])
+
+c['builders'].append({'name': 'dummy3', 'slavename': 'bot1',
+                       'env': {'blah':'bar'}, 'builddir': 'dummy3',
+                       'factory': f4})
+"""
+
+class TestBuilder(RunMixin, unittest.TestCase):
+    def setUp(self):
+        RunMixin.setUp(self)
+        self.master.loadConfig(config_test_builder)
+        self.master.readConfig = True
+        self.master.startService()
+        self.connectSlave(builders=["dummy", "dummy2", "dummy3"])
+
+    def doBuilderEnvTest(self, branch, cb):
+        c = changes.Change("bob", ["Makefile", "foo/bar.c"], "changed",
+                           branch=branch)
+        self.master.change_svc.addChange(c)
+
+        d = defer.Deferred()
+        reactor.callLater(0.5, d.callback, None)
+        d.addCallback(cb)
+
+        return d
+
+    def testBuilderEnv(self):
+        return self.doBuilderEnvTest("dummy", self._testBuilderEnv1)
+
+    def _testBuilderEnv1(self, res):
+        b = self.master.botmaster.builders['dummy']
+        build = b.building[0]
+        s = build.currentStep
+        self.failUnless('foo' in s.cmd.args['env'])
+        self.failUnlessEqual('bar', s.cmd.args['env']['foo'])
+        self.failUnless('blah' in s.cmd.args['env'])
+        self.failUnlessEqual('blah', s.cmd.args['env']['blah'])
+
+    def testBuilderEnvOverride(self):
+        return self.doBuilderEnvTest("dummy2", self._testBuilderEnvOverride1)
+
+    def _testBuilderEnvOverride1(self, res):
+        b = self.master.botmaster.builders['dummy2']
+        build = b.building[0]
+        s = build.currentStep
+        self.failUnless('blah' in s.cmd.args['env'])
+        self.failUnlessEqual('blah', s.cmd.args['env']['blah'])
+
+    def testBuilderNoStepEnv(self):
+        return self.doBuilderEnvTest("dummy3", self._testBuilderNoStepEnv1)
+
+    def _testBuilderNoStepEnv1(self, res):
+        b = self.master.botmaster.builders['dummy3']
+        build = b.building[0]
+        s = build.currentStep
+        self.failUnless('blah' in s.cmd.args['env'])
+        self.failUnlessEqual('bar', s.cmd.args['env']['blah'])

