Repository: pybuilder/pybuilder
Issue: Error writing to log while building in windows continued

When running pybuilder in windows I get the following error.

---

 [1;31mBUILD FAILED - [Errno 22] invalid mode ('w') or filename: u'C:\\Users\\josh\\IdeaProjects\\SparkPlug\\target\\reports\\dependency_unittest-xml-reporting<2.0_install.log'
 [0;0m------------------------------------------------------------

The first time I got this error it was because the backslashes had been hardcoded, but that was recently fixed.  In this case I believe it is because the '<' character is reserved in the Windows file system.  I'm including the stack trace that comes from pyb -X

[pybuilder_debug.txt](https://github.com/pybuilder/pybuilder/files/362076/pybuilder_debug.txt)


Changed files:
src/main/python/pybuilder/utils.py, src/main/python/pybuilder/plugins/python/stdeb_plugin.py, src/main/python/pybuilder/plugins/python/sphinx_plugin.py, src/main/python/pybuilder/plugins/python/install_dependencies_plugin.py, src/main/python/pybuilder/plugins/core_plugin.py

diff --git a/src/main/python/pybuilder/plugins/core_plugin.py b/src/main/python/pybuilder/plugins/core_plugin.py
index 7999ac0..4947a6f 100644
--- a/src/main/python/pybuilder/plugins/core_plugin.py
+++ b/src/main/python/pybuilder/plugins/core_plugin.py
@@ -22,6 +22,7 @@ from os.path import join
 
 from pybuilder.core import init, task, description, depends, optional
 from pybuilder.pip_utils import get_package_version, version_satisfies_spec, pip_install, as_pip_install_target
+from pybuilder.utils import safe_log_file_name
 
 
 @init
@@ -62,10 +63,11 @@ def prepare(project, logger):
     for plugin_dependency in project.plugin_dependencies:
         logger.debug("Processing plugin dependency %s" % plugin_dependency)
         if plugin_dependency.name.lower() not in plugin_dependency_versions or not \\
-            version_satisfies_spec(plugin_dependency.version,
-                                   plugin_dependency_versions[plugin_dependency.name.lower()]):
+                version_satisfies_spec(plugin_dependency.version,
+                                       plugin_dependency_versions[plugin_dependency.name.lower()]):
             logger.info("Installing plugin dependency %s" % plugin_dependency)
-            log_file = project.expand_path("$dir_reports", "dependency_%s_install.log" % plugin_dependency)
+            log_file = project.expand_path("$dir_reports",
+                                           safe_log_file_name("dependency_%s_install.log" % plugin_dependency))
             pip_install(as_pip_install_target(plugin_dependency),
                         index_url=project.get_property("install_dependencies_index_url"),
                         extra_index_url=project.get_property("install_dependencies_extra_index_url"),
diff --git a/src/main/python/pybuilder/plugins/python/install_dependencies_plugin.py b/src/main/python/pybuilder/plugins/python/install_dependencies_plugin.py
index e01fcf1..b540dc9 100644
--- a/src/main/python/pybuilder/plugins/python/install_dependencies_plugin.py
+++ b/src/main/python/pybuilder/plugins/python/install_dependencies_plugin.py
@@ -21,7 +21,6 @@ from __future__ import print_function
 import collections
 import imp
 import os
-import re
 import sys
 
 from pybuilder.core import (before,
@@ -39,7 +38,7 @@ from pybuilder.pip_utils import (PIP_EXEC_STANZA,
                                  should_update_package,
                                  version_satisfies_spec)
 from pybuilder.terminal import print_file_content
-from pybuilder.utils import execute_command, mkdir, as_list
+from pybuilder.utils import execute_command, mkdir, as_list, safe_log_file_name
 
 __author__ = "Alexander Metzner, Arcadiy Ivanov"
 
@@ -118,8 +117,7 @@ def install_dependency(logger, project, dependencies):
 
     for standalone_dependency in standalone_dependencies:
         url = getattr(standalone_dependency, "url", None)
-        log_file = project.expand_path("$dir_install_logs", dependency.name)
-        log_file = re.sub(r'<|>|=', '_', log_file)
+        log_file = project.expand_path("$dir_install_logs", safe_log_file_name(dependency.name))
         _do_install_dependency(logger, project, standalone_dependency,
                                True,
                                url,
diff --git a/src/main/python/pybuilder/plugins/python/sphinx_plugin.py b/src/main/python/pybuilder/plugins/python/sphinx_plugin.py
index 16fba21..108d2db 100644
--- a/src/main/python/pybuilder/plugins/python/sphinx_plugin.py
+++ b/src/main/python/pybuilder/plugins/python/sphinx_plugin.py
@@ -19,31 +19,30 @@
 """Sphinx-plugin for PyBuildern to run a sphinx quickstart and generate the documentation once set up.
 """
 
+from os.path import join
+
+from pybuilder import scaffolding as SCAFFOLDING
+from pybuilder.core import NAME_ATTRIBUTE
 from pybuilder.core import after
 from pybuilder.core import depends
 from pybuilder.core import init
 from pybuilder.core import task
 from pybuilder.core import use_plugin
 from pybuilder.errors import BuildFailedException
-from pybuilder.utils import assert_can_execute
-from pybuilder.utils import execute_command
-from pybuilder import scaffolding as SCAFFOLDING
-from pybuilder.core import NAME_ATTRIBUTE
+from pybuilder.utils import (execute_command,
+                             assert_can_execute)
 
 __author__ = 'Thomas Prebble', 'Marcel Wolf'
 
-
 use_plugin("core")
 
-
-DEFAULT_SPHINX_OUTPUT_DIR = SCAFFOLDING.DEFAULT_DOCS_DIRECTORY + "/_build/"
+DEFAULT_SPHINX_OUTPUT_DIR = join(SCAFFOLDING.DEFAULT_DOCS_DIRECTORY, "_build", "")
 
 SPHINX_DOC_BUILDER = "html"
 
 
 @init
 def initialize_sphinx_plugin(project):
-
     default_project_version = project.version
     default_project_name = project.name
     default_doc_author = ", ".join([author.name for author in project.authors])
@@ -87,8 +86,7 @@ def assert_sphinx_quickstart_is_available(logger):
 
 def run_sphinx_build(build_command, task_name, logger, project):
     logger.info("Running %s" % task_name)
-    log_file = project.expand_path(
-        "$dir_target/reports/{0}".format(task_name))
+    log_file = project.expand_path("$dir_target", "reports", task_name)
 
     if project.get_property("verbose"):
         logger.info(build_command)
diff --git a/src/main/python/pybuilder/plugins/python/stdeb_plugin.py b/src/main/python/pybuilder/plugins/python/stdeb_plugin.py
index a0778a8..bd260c3 100644
--- a/src/main/python/pybuilder/plugins/python/stdeb_plugin.py
+++ b/src/main/python/pybuilder/plugins/python/stdeb_plugin.py
@@ -17,15 +17,16 @@
 #   limitations under the License.
 #
 
-from pybuilder.utils import assert_can_execute
-from pybuilder.utils import execute_command
-from pybuilder.errors import BuildFailedException
 from pybuilder.core import NAME_ATTRIBUTE
 from pybuilder.core import (after,
                             task,
                             init,
                             use_plugin,
                             depends)
+from pybuilder.errors import BuildFailedException
+from pybuilder.utils import (assert_can_execute,
+                             execute_command
+                             )
 
 __author__ = 'Marcel Wolf'
 
@@ -36,14 +37,12 @@ use_plugin("core")
 
 @init
 def initialize_make_deb_plugin(project):
-
     project.plugin_depends_on("stdeb")
 
     package_name = project.name + "-" + project.version + ".tar.gz"
 
-    PATH_TO_SOURCE_TARBALL = project.expand_path(
-        "$dir_dist/dist/" + package_name)
-    PATH_FINAL_BUILD = project.expand_path("$dir_dist/dist/")
+    PATH_TO_SOURCE_TARBALL = project.expand_path("$dir_dist", "dist", package_name)
+    PATH_FINAL_BUILD = project.expand_path("$dir_dist", "dist")
 
     project.set_property_if_unset(
         "deb_package_maintainer", DEB_PACKAGE_MAINTAINER)
@@ -97,8 +96,7 @@ def get_py2dsc_deb_command(project):
 
 def run_py2dsc_deb_build(build_command, task_name, logger, project):
     logger.info("Running %s" % task_name)
-    log_file = project.expand_path(
-        "$dir_target/reports/{0}".format(task_name))
+    log_file = project.expand_path("$dir_target", "reports", task_name)
     if project.get_property("verbose"):
         logger.info(build_command)
         exit_code = execute_command(build_command, log_file, shell=True)
diff --git a/src/main/python/pybuilder/utils.py b/src/main/python/pybuilder/utils.py
index 4f5ae84..8450dad 100644
--- a/src/main/python/pybuilder/utils.py
+++ b/src/main/python/pybuilder/utils.py
@@ -348,6 +348,7 @@ if sys.version_info[0] == 2 and sys.version_info[1] == 6:  # if Python is 2.6
 
     class OrderedDict(dict):
         'Dictionary that remembers insertion order'
+
         # An inherited dict maps keys to values.
         # The inherited dict provides __getitem__, __len__, __contains__, and get.
         # The remaining methods are order-aware.
@@ -605,3 +606,7 @@ def is_notstr_iterable(obj):
 
 def get_dist_version_string(project, format=" (%s)"):
     return format % project.dist_version if project.version != project.dist_version else ""
+
+
+def safe_log_file_name(file_name):
+    return re.sub(r'\\<|\\>|=|\\:|\\*|\\?|\\|\\"', '_', file_name)