Repository: conan-io/conan

Issue:
Enhancement: propogate source file info in package_info
There are at least three known use cases for propagating information about sources of a package to downstream dependencies.  This includes: 

1. Debugging - Its highly probable that step-through debugging into upstream sources in Conan cache will be possible once generators have access to those source paths. 
1. Code Generation - Many projects and frameworks generate sources intended to be compiled directly into downstream projects. 
1. source_requires - Within Boost, my organization, and likely in other OSS frameworks, there are libraries which crossed some boundaries in terms of "dependency management best-practices", and directly include or depend on one or more source files of other libraries.  

This request is divided into two parts:  `package_info()` and `source_requires()`

Part 1:  `package_info()`
The first part of this request is to first add the following two members and a helper functions for use within the `conanfile.py` `package_info()` method:
```
self.cpp_info.srcdirs = "src"
self.cpp_info.srcs.append(tools.collect_srcs(self, folder))
self.cpp_info.srcs.append(tools.collect_srcs(self, folder))
```

It seems easy to model after the behavior for propagating library information, and could have similar default logic for collecting common/known file extensions, and searching any directories appended to `srcdirs`.  This part seems very straightforward to implement. 

Part 2: `source_requires()`
The second part of this request can come later, and is more difficult to think about and less clear to implement.  It is to enable downstream packages to depend purely on the sources of upstreams, as is needed for several libraries in Boost.  We have an manually implemented example here: 

https://github.com/bincrafters/conan-boost_fiber/blob/testing/1.67.0/conanfile.py#L15
https://github.com/bincrafters/conan-boost_base/blob/testing/1.67.0/conanfile.py#L124

There are several nuances and design questions to be decided before implementing a general case, but hopefully these examples make the intention clear, and can guide future discussion. 

Ping @memsharded per his request. 

- [X] I've read the [CONTRIBUTING guide](https://raw.githubusercontent.com/conan-io/conan/develop/.github/CONTRIBUTING.md).
- [X ] I've specified the Conan version, operating system version and any tool that can be relevant.
- [X] I've explained the steps to reproduce the error or the motivation/use case of the question/suggestion.



Discussion:

Patch:
diff --git a/conans/client/build/cmake.py b/conans/client/build/cmake.py
index a92fb1eff..80fddbd07 100644
--- a/conans/client/build/cmake.py
+++ b/conans/client/build/cmake.py
@@ -138,10 +138,8 @@ class CMake(object):
 
     def _run(self, command):
         compiler = self._settings.get_safe("compiler")
-        the_os = self._settings.get_safe("os")
-        is_clangcl = the_os == 'Windows' and compiler == 'clang'
-        is_msvc = compiler == 'Visual Studio'
-        if (is_msvc or is_clangcl) and self.generator in ['Ninja', 'NMake Makefiles', 'NMake Makefiles JOM']:
+        if compiler == 'Visual Studio' and self.generator in ['Ninja', 'NMake Makefiles',
+                                                              'NMake Makefiles JOM']:
             with tools.vcvars(self._settings, force=True, filter_known_paths=False):
                 self._conanfile.run(command)
         else:
diff --git a/conans/client/build/cppstd_flags.py b/conans/client/build/cppstd_flags.py
index 44e5bde77..49e5d5fc6 100644
--- a/conans/client/build/cppstd_flags.py
+++ b/conans/client/build/cppstd_flags.py
@@ -1,6 +1,15 @@
 from conans.model.version import Version
 
 
+def available_cppstd_versions(compiler, compiler_version):
+    ret = []
+    stds = ["98", "gnu98", "11", "gnu11", "14",  "gnu14", "17", "gnu17", "20", "gnu20"]
+    for stdver in stds:
+        if cppstd_flag(compiler, compiler_version, stdver):
+            ret.append(stdver)
+    return ret
+
+
 def cppstd_flag(compiler, compiler_version, cppstd):
     if not compiler or not compiler_version or not cppstd:
         return ""
diff --git a/conans/client/build/visual_environment.py b/conans/client/build/visual_environment.py
index 0f82a2eae..c3f530d22 100644
--- a/conans/client/build/visual_environment.py
+++ b/conans/client/build/visual_environment.py
@@ -10,12 +10,10 @@ class VisualStudioBuildEnvironment(object):
     """
     - LIB: library paths with semicolon separator
     - CL: /I (include paths)
-    - _LINK_: linker options and libraries
 
     https://msdn.microsoft.com/en-us/library/19z1t1wy.aspx
     https://msdn.microsoft.com/en-us/library/fwkeyyhe.aspx
     https://msdn.microsoft.com/en-us/library/9s7c9wdw.aspx
-    https://msdn.microsoft.com/en-us/library/6y6t9esh.aspx
 
     """
     def __init__(self, conanfile):
@@ -34,7 +32,6 @@ class VisualStudioBuildEnvironment(object):
         self.flags = self._configure_flags()
         self.cxx_flags = copy.copy(self._deps_cpp_info.cppflags)
         self.link_flags = self._configure_link_flags()
-        self.libs = conanfile.deps_cpp_info.libs
         self.std = self._std_cpp()
         self.parallel = False
 
@@ -63,6 +60,7 @@ class VisualStudioBuildEnvironment(object):
         ret.extend(format_defines(self.defines))
         ret.extend(self.flags)
         ret.extend(self.cxx_flags)
+        ret.extend(self.link_flags)
 
         if self.parallel:  # Build source in parallel
             ret.append(parallel_compiler_cl_flag())
@@ -72,34 +70,20 @@ class VisualStudioBuildEnvironment(object):
 
         return ret
 
-    def _get_link_list(self):
-        def format_lib(lib):
-            return lib if lib.endswith('.lib') else '%s.lib' % lib
-
-        ret = [flag for flag in self.link_flags]  # copy
-        ret.extend([format_lib(lib) for lib in self.libs])
-
-        return ret
-
     @property
     def vars(self):
         """Used in conanfile with environment_append"""
         flags = self._get_cl_list()
-        link_flags = self._get_link_list()
-
         cl_args = " ".join(flags) + _environ_value_prefix("CL")
-        link_args = " ".join(link_flags)
         lib_paths = ";".join(['%s' % lib for lib in self.lib_paths]) + _environ_value_prefix("LIB", ";")
         return {"CL": cl_args,
-                "LIB": lib_paths,
-                "_LINK_": link_args}
+                "LIB": lib_paths}
 
     @property
     def vars_dict(self):
         """Used in virtualbuildenvironment"""
         # Here we do not quote the include paths, it's going to be used by virtual environment
         cl = self._get_cl_list(quotes=False)
-        link = self._get_link_list()
 
         lib = [lib for lib in self.lib_paths]  # copy
 
@@ -109,12 +93,8 @@ class VisualStudioBuildEnvironment(object):
         if os.environ.get("LIB", None):
             lib.append(os.environ.get("LIB"))
 
-        if os.environ.get("_LINK_", None):
-            link.append(os.environ.get("_LINK_"))
-
         ret = {"CL": cl,
-               "LIB": lib,
-               "_LINK_": link}
+               "LIB": lib}
         return ret
 
     def _std_cpp(self):
diff --git a/conans/client/cmd/export.py b/conans/client/cmd/export.py
index af02b4181..b9514376a 100644
--- a/conans/client/cmd/export.py
+++ b/conans/client/cmd/export.py
@@ -1,5 +1,6 @@
 import ast
 import os
+import stat
 import shutil
 import six
 from conans.client.cmd.export_linter import conan_linter
@@ -140,6 +141,9 @@ def _replace_scm_data_in_conanfile(conanfile_path, scm_data):
     new_text = "scm = " + ",\n          ".join(str(scm_data).split(",")) + "\n"
     content = content.replace(to_replace[0], new_text)
     content = content if not headers else ''.join(headers) + content
+    
+    if not os.access(conanfile_path, os.W_OK):
+        os.chmod(conanfile_path, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  # 0777
     save(conanfile_path, content)
 
 
diff --git a/conans/client/generators/cmake.py b/conans/client/generators/cmake.py
index e1fe49e6d..145ea4b51 100644
--- a/conans/client/generators/cmake.py
+++ b/conans/client/generators/cmake.py
@@ -1,15 +1,16 @@
-from conans.model import Generator
-from conans.paths import BUILD_INFO_CMAKE
 from conans.client.generators.cmake_common import cmake_dependency_vars,\
     cmake_macros, generate_targets_section, cmake_dependencies, cmake_package_info,\
     cmake_global_vars, cmake_user_info_vars, cmake_settings_info
+from conans.model import Generator
+from conans.paths import BUILD_INFO_CMAKE
 
 
 class DepsCppCmake(object):
     def __init__(self, cpp_info):
         def join_paths(paths):
             # Paths are doubled quoted, and escaped (but spaces)
-            return "\n\t\t\t".join('"%s"' % p.replace('\\', '/').replace('$', '\\$').replace('"', '\\"')
+            return "\n\t\t\t".join('"%s"'
+                                   % p.replace('\\', '/').replace('$', '\\$').replace('"', '\\"')
                                    for p in paths)
 
         def join_flags(separator, values):
@@ -28,6 +29,7 @@ class DepsCppCmake(object):
         self.res_paths = join_paths(cpp_info.res_paths)
         self.bin_paths = join_paths(cpp_info.bin_paths)
         self.build_paths = join_paths(cpp_info.build_paths)
+        self.src_paths = join_paths(cpp_info.src_paths)
 
         self.libs = join_flags(" ", cpp_info.libs)
         self.defines = join_defines(cpp_info.defines, "-D")
diff --git a/conans/client/generators/cmake_common.py b/conans/client/generators/cmake_common.py
index b2a14ddb5..9423c6baf 100644
--- a/conans/client/generators/cmake_common.py
+++ b/conans/client/generators/cmake_common.py
@@ -3,6 +3,7 @@ set(CONAN_INCLUDE_DIRS_{dep}{build_type} {deps.include_paths})
 set(CONAN_LIB_DIRS_{dep}{build_type} {deps.lib_paths})
 set(CONAN_BIN_DIRS_{dep}{build_type} {deps.bin_paths})
 set(CONAN_RES_DIRS_{dep}{build_type} {deps.res_paths})
+set(CONAN_SRC_DIRS_{dep}{build_type} {deps.src_paths})
 set(CONAN_BUILD_DIRS_{dep}{build_type} {deps.build_paths})
 set(CONAN_LIBS_{dep}{build_type} {deps.libs})
 set(CONAN_DEFINES_{dep}{build_type} {deps.defines})
@@ -41,7 +42,8 @@ def cmake_user_info_vars(deps_user_info):
     lines = []
     for dep, the_vars in deps_user_info.items():
         for name, value in the_vars.vars.items():
-            lines.append('set(CONAN_USER_%s_%s %s)' % (dep.upper(), name, _cmake_string_representation(value)))
+            lines.append('set(CONAN_USER_%s_%s %s)'
+                         % (dep.upper(), name, _cmake_string_representation(value)))
     return "\n".join(lines)
 
 
@@ -64,7 +66,8 @@ def cmake_settings_info(settings):
     for item in settings.items():
         key, value = item
         name = "CONAN_SETTINGS_%s" % key.upper().replace(".", "_")
-        settings_info += "set({key} {value})\n".format(key=name, value=_cmake_string_representation(value))
+        settings_info += "set({key} {value})\n".format(key=name,
+                                                       value=_cmake_string_representation(value))
     return settings_info
 
 
diff --git a/conans/client/installer.py b/conans/client/installer.py
index 983652e08..17343bc8d 100644
--- a/conans/client/installer.py
+++ b/conans/client/installer.py
@@ -27,7 +27,7 @@ from conans.model.user_info import UserInfo
 from conans.paths import CONANINFO, BUILD_INFO, RUN_LOG_NAME
 from conans.util.env_reader import get_env
 from conans.util.files import (save, rmdir, mkdir, make_read_only,
-                               set_dirty, clean_dirty, load, is_dirty)
+                               set_dirty, clean_dirty, load)
 from conans.util.log import logger
 from conans.util.tracer import log_package_built, \
     log_package_got_from_local_cache
@@ -373,16 +373,14 @@ class ConanInstaller(object):
     def _build_package(self, node, package_ref, output, keep_build):
         conan_ref, conan_file = node.conan_ref, node.conanfile
 
+        skip_build = conan_file.develop and keep_build
+        if skip_build:
+            output.info("Won't be built as specified by --keep-build")
+
         t1 = time.time()
         builder = _ConanPackageBuilder(conan_file, package_ref, self._client_cache, output,
                                        self._plugin_manager)
-        if is_dirty(builder.build_folder):
-            output.warn("Build folder is dirty, removing it: %s" % builder.build_folder)
-            rmdir(builder.build_folder)
 
-        skip_build = conan_file.develop and keep_build
-        if skip_build:
-            output.info("Won't be built as specified by --keep-build")
         if skip_build:
             if not os.path.exists(builder.build_folder):
                 msg = "--keep-build specified, but build folder not found"
@@ -392,7 +390,6 @@ class ConanInstaller(object):
                 raise ConanException(msg)
         else:
             with self._client_cache.conanfile_write_lock(conan_ref):
-                set_dirty(builder.build_folder)
                 complete_recipe_sources(self._remote_manager, self._client_cache,
                                         self._registry, conan_file, conan_ref)
                 builder.prepare_build()
@@ -401,7 +398,6 @@ class ConanInstaller(object):
             try:
                 if not skip_build:
                     builder.build()
-                    clean_dirty(builder.build_folder)
                 builder.package()
             except ConanException as exc:
                 self._recorder.package_install_error(package_ref, INSTALL_ERROR_BUILDING,
diff --git a/conans/client/loader.py b/conans/client/loader.py
index b493e934b..be11c5519 100644
--- a/conans/client/loader.py
+++ b/conans/client/loader.py
@@ -32,6 +32,7 @@ class ProcessedProfile(object):
         self._package_settings = profile.package_settings_values
         self._env_values = profile.env_values
         # Make sure the paths are normalized first, so env_values can be just a copy
+        self._env_values.normalize_paths()
         self._dev_reference = create_reference
 
 
@@ -102,8 +103,7 @@ class ConanFileLoader(object):
             # Prepare the settings for the loaded conanfile
             # Mixing the global settings with the specified for that name if exist
             tmp_settings = processed_profile._settings.copy()
-            if (processed_profile._package_settings and
-                    conanfile.name in processed_profile._package_settings):
+            if processed_profile._package_settings and conanfile.name in processed_profile._package_settings:
                 # Update the values, keeping old ones (confusing assign)
                 values_tuple = processed_profile._package_settings[conanfile.name]
                 tmp_settings.values = Values.from_list(values_tuple)
@@ -229,27 +229,11 @@ def _parse_file(conan_file_path):
         module_id = str(uuid.uuid1())
         current_dir = os.path.dirname(conan_file_path)
         sys.path.append(current_dir)
-        old_modules = list(sys.modules.keys())
         with chdir(current_dir):
             sys.dont_write_bytecode = True
             loaded = imp.load_source(module_id, conan_file_path)
             loaded.python_requires = _invalid_python_requires
             sys.dont_write_bytecode = False
-
-        # These lines are necessary, otherwise local conanfile imports with same name
-        # collide, but no error, and overwrite other packages imports!!
-        added_modules = set(sys.modules).difference(old_modules)
-        for added in added_modules:
-            module = sys.modules[added]
-            if module:
-                try:
-                    folder = os.path.dirname(module.__file__)
-                except AttributeError:  # some module doesn't have __file__
-                    pass
-                else:
-                    if folder.startswith(current_dir):
-                        module = sys.modules.pop(added)
-                        sys.modules["%s.%s" % (module_id, added)] = module
     except Exception:
         import traceback
         trace = traceback.format_exc().split('\n')
diff --git a/conans/client/settings_preprocessor.py b/conans/client/settings_preprocessor.py
index 73b0dcc3c..88909b6b8 100644
--- a/conans/client/settings_preprocessor.py
+++ b/conans/client/settings_preprocessor.py
@@ -1,4 +1,4 @@
-from conans.client.build.cppstd_flags import cppstd_flag
+from conans.client.build.cppstd_flags import available_cppstd_versions
 from conans.errors import ConanException
 from conans.util.log import logger
 
@@ -12,10 +12,10 @@ def check_cppstd(settings):
     compiler = settings.get_safe("compiler")
     compiler_version = settings.get_safe("compiler.version")
     cppstd = settings.get_safe("cppstd")
-    if not cppstd or compiler not in ("gcc", "clang", "apple-clang", "Visual Studio"):
+
+    if not cppstd or not compiler or not compiler_version:
         return
-    cpp_values = settings.cppstd.values_range
-    available = [v for v in cpp_values if cppstd_flag(compiler, compiler_version, v)]
+    available = available_cppstd_versions(compiler, compiler_version)
     if str(cppstd) not in available:
         raise ConanException("The specified 'cppstd=%s' is not available "
                              "for '%s %s'. Possible values are %s'" % (cppstd,
diff --git a/conans/client/source.py b/conans/client/source.py
index 303c91c94..c7ce00250 100644
--- a/conans/client/source.py
+++ b/conans/client/source.py
@@ -1,5 +1,6 @@
 import os
 import shutil
+import stat
 
 import six
 
@@ -66,6 +67,8 @@ def merge_directories(src, dst, excluded=None, symlinks=True):
                 linkto = os.readlink(src_file)
                 os.symlink(linkto, dst_file)
             else:
+                if os.path.isfile(dst_file) and not os.access(dst_file, os.W_OK):
+                    os.chmod(dst_file, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  # 0777
                 shutil.copy2(src_file, dst_file)
 
 
diff --git a/conans/client/tools/scm.py b/conans/client/tools/scm.py
index 5124b105c..1b8580280 100644
--- a/conans/client/tools/scm.py
+++ b/conans/client/tools/scm.py
@@ -251,7 +251,7 @@ class SVN(SCMBase):
         excluded_list = []
         output = self.run("status --no-ignore")
         for it in output.splitlines():
-            if it.startswith('I'):  # Only ignored files
+            if it[0] == 'I':  # Only ignored files
                 filepath = it[8:].strip()
                 excluded_list.append(os.path.normpath(filepath))
         return excluded_list
diff --git a/conans/model/build_info.py b/conans/model/build_info.py
index a769d0e9d..459f433fb 100644
--- a/conans/model/build_info.py
+++ b/conans/model/build_info.py
@@ -16,6 +16,7 @@ class _CppInfo(object):
     """
     def __init__(self):
         self.includedirs = []  # Ordered list of include paths
+        self.srcdirs = []  # Ordered list of source paths
         self.libdirs = []  # Directories to find libraries
         self.resdirs = []  # Directories to find resources, data, etc
         self.bindirs = []  # Directories to find executables and shared libs
@@ -34,6 +35,7 @@ class _CppInfo(object):
         self._bin_paths = None
         self._build_paths = None
         self._res_paths = None
+        self._src_paths = None
         self.version = None  # Version of the conan package
         self.description = None  # Description of the conan package
 
@@ -54,6 +56,12 @@ class _CppInfo(object):
             self._lib_paths = self._filter_paths(self.libdirs)
         return self._lib_paths
 
+    @property
+    def src_paths(self):
+        if self._src_paths is None:
+            self._src_paths = self._filter_paths(self.srcdirs)
+        return self._src_paths
+
     @property
     def bin_paths(self):
         if self._bin_paths is None:
@@ -117,6 +125,7 @@ class _BaseDepsCppInfo(_CppInfo):
             return [s for s in seq1 if s not in seq2] + seq2
 
         self.includedirs = merge_lists(self.includedirs, dep_cpp_info.include_paths)
+        self.srcdirs = merge_lists(self.srcdirs, dep_cpp_info.src_paths)
         self.libdirs = merge_lists(self.libdirs, dep_cpp_info.lib_paths)
         self.bindirs = merge_lists(self.bindirs, dep_cpp_info.bin_paths)
         self.resdirs = merge_lists(self.resdirs, dep_cpp_info.res_paths)
@@ -142,6 +151,10 @@ class _BaseDepsCppInfo(_CppInfo):
     def lib_paths(self):
         return self.libdirs
 
+    @property
+    def src_paths(self):
+        return self.srcdirs
+
     @property
     def bin_paths(self):
         return self.bindirs
diff --git a/conans/model/env_info.py b/conans/model/env_info.py
index e7b0bc193..a99f54fbe 100644
--- a/conans/model/env_info.py
+++ b/conans/model/env_info.py
@@ -73,9 +73,9 @@ class EnvValues(object):
                 if isinstance(value, list):
                     value = "[%s]" % ",".join(value)
                 if package:
-                    result.append("%s:%s=%s" % (package, name, value))
+                    result.append("%s:%s=%s" % (package, name, value.replace("\\", "/")))
                 else:
-                    result.append("%s=%s" % (name, value))
+                    result.append("%s=%s" % (name, value.replace("\\", "/")))
 
         result = []
         # First the global vars
@@ -102,7 +102,10 @@ class EnvValues(object):
     def add(self, name, value, package=None):
         # New data, not previous value
         if name not in self._data[package]:
-            self._data[package][name] = value
+            if isinstance(value, list):
+                self._data[package][name] = value
+            else:
+                self._data[package][name] = value.replace("\\", "/")
         # There is data already
         else:
             # Only append at the end if we had a list
@@ -125,6 +128,12 @@ class EnvValues(object):
             package_name, key = None, key
         self._data[package_name][key] = value
 
+    def normalize_paths(self):
+        for package_name, env_vars in self._data.items():
+            for name, value in env_vars.items():
+                if not isinstance(value, list):
+                    self._data[package_name][name] = value.replace("\\", "/")
+
     def update(self, env_obj):
         """accepts other EnvValues object or DepsEnvInfo
            it prioritize the values that are already at self._data
diff --git a/conans/requirements.txt b/conans/requirements.txt
index 3d654c0b4..5b4a32db0 100644
--- a/conans/requirements.txt
+++ b/conans/requirements.txt
@@ -12,4 +12,4 @@ future==0.16.0
 pygments>=2.0, <3.0
 astroid>=1.6.5
 deprecation>=2.0, <2.1
-tqdm>=4.28.1, <5
+tqdm-conan==4.27.0


Test patch:
diff --git a/conans/test/build_helpers/cmake_test.py b/conans/test/build_helpers/cmake_test.py
index db051d2a3..7b1b755d4 100644
--- a/conans/test/build_helpers/cmake_test.py
+++ b/conans/test/build_helpers/cmake_test.py
@@ -1089,19 +1089,13 @@ build_type: [ Release]
         pattern = "%s" if sys.platform == "win32" else r"'%s'"
         return ' '.join(pattern % i for i in args.split())
 
-    @parameterized.expand([('Ninja', 'Visual Studio', 15),
-                           ('NMake Makefiles', 'Visual Studio', 15),
-                           ('NMake Makefiles JOM', 'Visual Studio', 15),
-                           ('Ninja', 'clang', 6.0),
-                           ('NMake Makefiles', 'clang', 6.0),
-                           ('NMake Makefiles JOM', 'clang', 6.0)
-                           ])
-    def test_vcvars_applied(self, generator, compiler, version):
+    @parameterized.expand([('Ninja',), ('NMake Makefiles',), ('NMake Makefiles JOM',)])
+    def test_vcvars_applied(self, generator):
         conanfile = ConanFileMock()
         settings = Settings.loads(default_settings_yml)
         settings.os = "Windows"
-        settings.compiler = compiler
-        settings.compiler.version = version
+        settings.compiler = 'Visual Studio'
+        settings.compiler.version = 15
         conanfile.settings = settings
 
         cmake = CMake(conanfile, generator=generator)
@@ -1110,13 +1104,13 @@ build_type: [ Release]
             vcvars_mock.__enter__ = mock.MagicMock(return_value=(mock.MagicMock(), None))
             vcvars_mock.__exit__ = mock.MagicMock(return_value=None)
             cmake.configure()
-            self.assertTrue(vcvars_mock.called, "vcvars weren't called")
+            self.assertTrue(vcvars_mock.called)
 
         with mock.patch("conans.tools.vcvars") as vcvars_mock:
             vcvars_mock.__enter__ = mock.MagicMock(return_value=(mock.MagicMock(), None))
             vcvars_mock.__exit__ = mock.MagicMock(return_value=None)
             cmake.build()
-            self.assertTrue(vcvars_mock.called, "vcvars weren't called")
+            self.assertTrue(vcvars_mock.called)
 
 
 class ConanFileMock(ConanFile):
diff --git a/conans/test/build_helpers/visual_environment_test.py b/conans/test/build_helpers/visual_environment_test.py
index b65df7727..89033f31d 100644
--- a/conans/test/build_helpers/visual_environment_test.py
+++ b/conans/test/build_helpers/visual_environment_test.py
@@ -23,7 +23,6 @@ class VisualStudioBuildEnvironmentTest(unittest.TestCase):
         conanfile.deps_cpp_info.cppflags.append("-mycppflag2")
         conanfile.deps_cpp_info.exelinkflags.append("-myexelinkflag")
         conanfile.deps_cpp_info.sharedlinkflags.append("-mysharedlinkflag")
-        conanfile.deps_cpp_info.libs.extend(['gdi32', 'user32.lib'])
 
         tool = VisualStudioBuildEnvironment(conanfile)
         self.assertEquals(tool.vars_dict, {
@@ -35,9 +34,10 @@ class VisualStudioBuildEnvironmentTest(unittest.TestCase):
                    '-Ob0',
                    '-Od',
                    '-mycppflag',
-                   '-mycppflag2'],
+                   '-mycppflag2',
+                   '-myexelinkflag',
+                   '-mysharedlinkflag'],
             "LIB": ["/one/lib/path", "/two/lib/path"],
-            "_LINK_": ['-myexelinkflag', '-mysharedlinkflag', 'gdi32.lib', 'user32.lib']
         })
         tool.parallel = True
         self.assertEquals(tool.vars_dict, {
@@ -50,9 +50,10 @@ class VisualStudioBuildEnvironmentTest(unittest.TestCase):
                    '-Od',
                    '-mycppflag',
                    '-mycppflag2',
+                   '-myexelinkflag',
+                   '-mysharedlinkflag',
                    '/MP%s' % tools.cpu_count()],
             "LIB": ["/one/lib/path", "/two/lib/path"],
-            "_LINK_": ['-myexelinkflag', '-mysharedlinkflag', 'gdi32.lib', 'user32.lib']
         })
         tool.parallel = False
 
@@ -71,9 +72,10 @@ class VisualStudioBuildEnvironmentTest(unittest.TestCase):
                    '-Ob0',
                    '-Od',
                    '-mycppflag',
-                   '-mycppflag2'],
+                   '-mycppflag2',
+                   '-myexelinkflag',
+                   '-mysharedlinkflag'],
             "LIB": ["/one/lib/path", "/two/lib/path", "/three/lib/path"],
-            "_LINK_": ['-myexelinkflag', '-mysharedlinkflag', 'gdi32.lib', 'user32.lib']
         })
 
         # Now try appending to environment
@@ -90,18 +92,18 @@ class VisualStudioBuildEnvironmentTest(unittest.TestCase):
                        '-Od',
                        '-mycppflag',
                        '-mycppflag2',
+                       '-myexelinkflag',
+                       '-mysharedlinkflag',
                        "-I/four/include/path -I/five/include/path"],
                 "LIB": ["/one/lib/path", "/two/lib/path", "/three/lib/path", "/four/lib/path;/five/lib/path"],
-                "_LINK_": ['-myexelinkflag', '-mysharedlinkflag', 'gdi32.lib', 'user32.lib']
             })
 
             self.assertEquals(tool.vars, {
                 "CL": '-I"/one/include/path" -I"/two/include/path" -I"/three/include/path" -MDd '
                       '-mycflag -mycflag2 -Zi -Ob0 -Od '
-                      '-mycppflag -mycppflag2 '
+                      '-mycppflag -mycppflag2 -myexelinkflag -mysharedlinkflag '
                       '-I/four/include/path -I/five/include/path',
                 "LIB": "/one/lib/path;/two/lib/path;/three/lib/path;/four/lib/path;/five/lib/path",
-                "_LINK_": "-myexelinkflag -mysharedlinkflag gdi32.lib user32.lib"
             })
 
     def build_type_toolset_test(self):
diff --git a/conans/test/client/cmd/export_test.py b/conans/test/client/cmd/export_test.py
index 210ada8c6..d2bb3757e 100644
--- a/conans/test/client/cmd/export_test.py
+++ b/conans/test/client/cmd/export_test.py
@@ -4,9 +4,6 @@ import shutil
 import unittest
 from collections import namedtuple
 
-from conans.client.tools import chdir
-from conans.model.ref import ConanFileReference
-from conans.test.utils.tools import TestServer, TestClient
 from conans.util.files import save, load
 from conans.client.cmd.export import _replace_scm_data_in_conanfile
 from conans.client.loader import _parse_file
@@ -82,48 +79,3 @@ class ConanLib(ConanFile):
         after_scm = ''
         after_recipe = ''
         self._do_actual_test(scm_data=scm_data, after_scm=after_scm, after_recipe=after_recipe)
-
-
-class SCMUpload(unittest.TestCase):
-
-    def scm_sources_test(self):
-        """ Test conan_sources.tgz is deleted in server when removing 'exports_sources' and using
-        'scm'"""
-        conanfile = """from conans import ConanFile
-class TestConan(ConanFile):
-    name = "test"
-    version = "1.0"
-"""
-        exports_sources = """
-    exports_sources = "include/*"
-"""
-        servers = {"upload_repo": TestServer([("*/*@*/*", "*")], [("*/*@*/*", "*")],
-                                             users={"lasote": "mypass"})}
-        client = TestClient(servers=servers, users={"upload_repo": [("lasote", "mypass")]})
-        client.save({"conanfile.py": conanfile + exports_sources, "include/file": "content"})
-        client.run("create . danimtb/testing")
-        client.run("upload test/1.0@danimtb/testing -r upload_repo")
-        self.assertIn("Uploading conan_sources.tgz", client.out)
-        conan_ref = ConanFileReference("test", "1.0", "danimtb", "testing")
-        export_sources_path = os.path.join(servers["upload_repo"].paths.export(conan_ref),
-                                           "conan_sources.tgz")
-        self.assertTrue(os.path.exists(export_sources_path))
-
-        scm = """
-    scm = {"type": "git",
-           "url": "auto",
-           "revision": "auto"}
-"""
-        client.save({"conanfile.py": conanfile + scm})
-        with chdir(client.current_folder):
-            client.runner("git init")
-            client.runner('git config user.email "you@example.com"')
-            client.runner('git config user.name "Your Name"')
-            client.runner("git remote add origin https://github.com/fake/fake.git")
-            client.runner("git add .")
-            client.runner("git commit -m \"initial commit\"")
-        client.run("create . danimtb/testing")
-        self.assertIn("Repo origin deduced by 'auto': https://github.com/fake/fake.git", client.out)
-        client.run("upload test/1.0@danimtb/testing -r upload_repo")
-        self.assertNotIn("Uploading conan_sources.tgz", client.out)
-        self.assertFalse(os.path.exists(export_sources_path))
diff --git a/conans/test/functional/conanfile_helpers_test.py b/conans/test/functional/conanfile_helpers_test.py
index c1953a193..2080feba0 100644
--- a/conans/test/functional/conanfile_helpers_test.py
+++ b/conans/test/functional/conanfile_helpers_test.py
@@ -1,28 +1,30 @@
 import unittest
-
 from conans.test.utils.tools import TestClient
-from parameterized.parameterized import parameterized
+import random
+import string
 
 
 class ConanfileHelpersTest(unittest.TestCase):
 
-    @parameterized.expand([(True,), (False,)])
-    def test_helpers_same_name(self, scope_imports):
-        helpers = '''
+    def test_replace_in_file(self):
+        for libname in [''.join(random.choice(string.ascii_lowercase) for _ in range(5))
+                        for _ in range(5)]:
+            helpers = '''
 def build_helper(output):
     output.info("Building %d!")
     '''
-        other_helper = '''
+            other_helper = '''
 def source_helper(output):
     output.info("Source %d!")
     '''
-
-        if scope_imports:
-            file_content = '''from conans import ConanFile
-from myhelper import build_helper
-from myhelpers.other import source_helper
+            file_content = '''
+from conans import ConanFile
+from {libname} import build_helper
+from {libname}s.other import source_helper
 
 class ConanFileToolsTest(ConanFile):
+    name = "test"
+    version = "1.9"
     exports = "*"
 
     def source(self):
@@ -30,40 +32,49 @@ class ConanFileToolsTest(ConanFile):
 
     def build(self):
         build_helper(self.output)
-'''
-        else:
-            file_content = '''from conans import ConanFile
-import myhelper
-from myhelpers import other
+    '''
+            file_content2 = '''
+from a{libname} import build_helper
+from a{libname}s.other import source_helper
+from conans import ConanFile
+
 
 class ConanFileToolsTest(ConanFile):
+    name = "test2"
+    version = "2.3"
     exports = "*"
 
     def source(self):
-        other.source_helper(self.output)
+        source_helper(self.output)
 
     def build(self):
-        myhelper.build_helper(self.output)
-'''
+        build_helper(self.output)
+    '''
+            files = {"%s.py" % libname: helpers % 1,
+                     "%ss/__init__.py" % libname: "",
+                     "%ss/other.py" % libname: other_helper % 1,
+                     "conanfile.py": file_content.format(libname=libname)}
 
-        def files(number):
-            return {"myhelper.py": helpers % number,
-                    "myhelpers/__init__.py": "",
-                    "myhelpers/other.py": other_helper % number,
-                    "conanfile.py": file_content}
+            client = TestClient()
+            client.save(files)
+            client.run("export . lasote/testing")
 
-        client = TestClient()
-        client.save(files(1))
-        client.run("export . test/1.9@user/testing")
-        client.save(files(2), clean_first=True)
-        client.run("export . test2/2.3@user/testing")
+            client2 = TestClient(client.base_folder)
+            files = {"a%s.py" % libname: helpers % 2,
+                     "a%ss/__init__.py" % libname: "",
+                     "a%ss/other.py" % libname: other_helper % 2,
+                     "conanfile.py": file_content2.format(libname=libname)}
+            client2.save(files)
+            client2.run("export . lasote/testing")
 
-        files = {"conanfile.txt": """[requires]
-                                    test/1.9@user/testing\n
-                                    test2/2.3@user/testing"""}
-        client.save(files, clean_first=True)
-        client.run("install . --build")
-        self.assertIn("test/1.9@user/testing: Building 1!", client.out)
-        self.assertIn("test/1.9@user/testing: Source 1!", client.out)
-        self.assertIn("test2/2.3@user/testing: Building 2!", client.out)
-        self.assertIn("test2/2.3@user/testing: Source 2!", client.out)
+            client3 = TestClient(client.base_folder)
+            files = {"conanfile.txt": """[requires]
+                                        test/1.9@lasote/testing\n
+                                        test2/2.3@lasote/testing"""}
+            client3.save(files)
+            client3.run("install . --build")
+            # print client3.user_io.out
+            self.assertIn("Building 1!", client3.user_io.out)
+            self.assertIn("Source 1!", client3.user_io.out)
+            self.assertIn("Building 2!", client3.user_io.out)
+            self.assertIn("Source 2!", client3.user_io.out)
diff --git a/conans/test/functional/scm_test.py b/conans/test/functional/scm_test.py
index cd3cd5ad3..eed96dd83 100644
--- a/conans/test/functional/scm_test.py
+++ b/conans/test/functional/scm_test.py
@@ -1,5 +1,6 @@
 import json
 import os
+import stat
 import unittest
 from collections import namedtuple
 
@@ -561,6 +562,39 @@ class ConanLib(ConanFile):
                       str(self.client.out).lower())
         self.assertIn("My file is copied", self.client.out)
 
+    def test_with_locked_svn(self):
+        conanfile = base_svn.format(directory="None", url="auto", revision="auto")
+        project_url, rev = self.create_project(files={"conanfile.py": conanfile,
+                                                      "myfile.txt": "My file is copied"},
+                                               lock_repo=True)
+        project_url = project_url.replace(" ", "%20")
+        self.client.runner('svn co "{url}" "{path}"'.format(url=project_url, path=self.client.current_folder))
+
+        curdir = self.client.current_folder.replace("\\", "/")
+        # Create the package, will copy the sources from the local folder
+        self.client.run("create . user/channel")
+        sources_dir = self.client.client_cache.scm_folder(self.reference)
+        self.assertEquals(load(sources_dir), curdir)
+        self.assertIn("Repo origin deduced by 'auto': {}".format(project_url).lower(),
+                      str(self.client.out).lower())
+        self.assertIn("Revision deduced by 'auto'", self.client.out)
+        self.assertIn("Getting sources from folder: %s" % curdir, self.client.out)
+        self.assertIn("My file is copied", self.client.out)
+
+        # Export again but now with absolute reference, so no pointer file is created nor kept
+        svn = SVN(curdir)
+        if not os.access(os.path.join(curdir, "conanfile.py"), os.W_OK):
+            os.chmod(os.path.join(curdir, "conanfile.py"), stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)  # 0777
+        self.client.save({"conanfile.py": base_svn.format(url=svn.get_remote_url(), revision=svn.get_revision())})
+        self.client.run("create . user/channel", ignore_error=False)
+        sources_dir = self.client.client_cache.scm_folder(self.reference)
+        self.assertFalse(os.path.exists(sources_dir))
+        self.assertNotIn("Repo origin deduced by 'auto'", self.client.out)
+        self.assertNotIn("Revision deduced by 'auto'", self.client.out)
+        self.assertIn("Getting sources from url: '{}'".format(project_url).lower(),
+                      str(self.client.out).lower())
+        self.assertIn("My file is copied", self.client.out)
+        
     def test_auto_subfolder(self):
         conanfile = base_svn.replace('"revision": "{revision}"',
                                      '"revision": "{revision}",\n        '
diff --git a/conans/test/generators/cmake_test.py b/conans/test/generators/cmake_test.py
index 74dd65fab..a63a0f8af 100644
--- a/conans/test/generators/cmake_test.py
+++ b/conans/test/generators/cmake_test.py
@@ -1,18 +1,18 @@
+import os
 import re
 import unittest
-from collections import namedtuple
 
-from conans.client.generators.cmake_multi import CMakeMultiGenerator
-from conans.model.settings import Settings
-from conans.model.conan_file import ConanFile
+from collections import namedtuple
+from conans.client.conf import default_settings_yml
 from conans.client.generators.cmake import CMakeGenerator
+from conans.client.generators.cmake_multi import CMakeMultiGenerator
 from conans.model.build_info import CppInfo
+from conans.model.conan_file import ConanFile
+from conans.model.env_info import EnvValues
 from conans.model.ref import ConanFileReference
-from conans.client.conf import default_settings_yml
+from conans.model.settings import Settings
 from conans.test.utils.test_files import temp_folder
 from conans.util.files import save
-import os
-from conans.model.env_info import EnvValues
 
 
 class CMakeGeneratorTest(unittest.TestCase):
@@ -70,9 +70,8 @@ class CMakeGeneratorTest(unittest.TestCase):
     def paths_cmake_test(self):
         settings_mock = namedtuple("Settings", "build_type, os, os_build, constraint, items")
         conanfile = ConanFile(None, None)
-        conanfile.initialize(settings_mock(None, None, None,
-                                                        lambda x, raise_undefined_field: x,
-                                                        lambda: {}), EnvValues())
+        conanfile.initialize(settings_mock(None, None, None, lambda x, raise_undefined_field: x,
+                                           lambda: {}), EnvValues())
         ref = ConanFileReference.loads("MyPkg/0.1@lasote/stables")
         tmp_folder = temp_folder()
         save(os.path.join(tmp_folder, "lib", "mylib.lib"), "")
diff --git a/conans/test/generators/generators_test.py b/conans/test/generators/generators_test.py
index becaa6891..443fc8b3f 100644
--- a/conans/test/generators/generators_test.py
+++ b/conans/test/generators/generators_test.py
@@ -1,8 +1,11 @@
 import os
 import platform
 import unittest
+
 from conans.test.utils.tools import TestClient
 from conans.util.files import load
+from conans.model.ref import ConanFileReference
+import re
 
 
 class GeneratorsTest(unittest.TestCase):
@@ -38,18 +41,39 @@ ycm
         client.save(files)
         client.run("install . --build")
 
-        virtualenvFiles = ["activate.sh", "deactivate.sh"]
+        venv_files = ["activate.sh", "deactivate.sh"]
         if platform.system() == "Windows":
-            virtualenvFiles.extend(["activate.bat", "deactivate.bat", "activate.ps1",
-                                    "deactivate.ps1"])
+            venv_files.extend(["activate.bat", "deactivate.bat", "activate.ps1",
+                               "deactivate.ps1"])
 
         self.assertEqual(sorted(['conanfile.txt', 'conaninfo.txt', 'conanbuildinfo.cmake',
                                  'conanbuildinfo.gcc', 'conanbuildinfo.qbs', 'conanbuildinfo.pri',
                                  'SConscript_conan', 'conanbuildinfo.txt', 'conanbuildinfo.props',
                                  'conanbuildinfo.vsprops', 'conanbuildinfo.xcconfig',
-                                 'conan_ycm_flags.json', 'conan_ycm_extra_conf.py'] + virtualenvFiles),
+                                 'conan_ycm_flags.json', 'conan_ycm_extra_conf.py'] + venv_files),
                          sorted(os.listdir(client.current_folder)))
 
+    def test_srcdirs(self):
+        client = TestClient()
+        conanfile = """from conans import ConanFile
+from conans.tools import save
+import os
+class TestConan(ConanFile):
+    def package(self):
+        save(os.path.join(self.package_folder, "src/file.h"), "//header")
+    def package_info(self):
+        self.cpp_info.srcdirs = ["src"]
+"""
+
+        client.save({"conanfile.py": conanfile})
+        client.run("create . mysrc/0.1@user/testing")
+        client.run("install mysrc/0.1@user/testing -g cmake")
+
+        cmake = load(os.path.join(client.current_folder, "conanbuildinfo.cmake"))
+        src_dirs = re.search('set\(CONAN_SRC_DIRS_MYSRC "(.*)"\)', cmake).group(1)
+        self.assertIn("mysrc/0.1/user/testing/package/5ab84d6acfe1f23c4fae0ab88f26e3a396351ac9/src",
+                      src_dirs)
+
     def test_qmake(self):
         client = TestClient()
         dep = """
diff --git a/conans/test/generators/virtualenv_test.py b/conans/test/generators/virtualenv_test.py
index 482c54ee7..202135759 100644
--- a/conans/test/generators/virtualenv_test.py
+++ b/conans/test/generators/virtualenv_test.py
@@ -28,7 +28,6 @@ class BaseConan(ConanFile):
         self.env_info.SPECIAL_VAR = "baseValue"
         self.env_info.BASE_LIST = ["baseValue1", "baseValue2"]
         self.env_info.CPPFLAGS = ["-baseFlag1", "-baseFlag2"]
-        self.env_info.BCKW_SLASH = r"base\\value"
 """
 
         dep2 = """
@@ -46,7 +45,6 @@ class DummyConan(ConanFile):
         self.env_info.SPECIAL_VAR = "dummyValue"
         self.env_info.BASE_LIST = ["dummyValue1", "dummyValue2"]
         self.env_info.CPPFLAGS = ["-flag1", "-flag2"]
-        self.env_info.BCKW_SLASH = r"dummy\\value"
 """
         base = '''
 [requires]
@@ -70,7 +68,6 @@ virtualenv
             self.assertIn('SET LD_LIBRARY_PATH=dummydir\\lib;basedir\\lib;%LD_LIBRARY_PATH%', activate)
             self.assertIn('SET PATH=dummydir\\bin;basedir\\bin;samebin;%PATH%', activate)
             self.assertIn('SET SPECIAL_VAR=dummyValue', activate)
-            self.assertIn('SET BCKW_SLASH=dummy\\value', activate)
 
             activate = load(os.path.join(client.current_folder, "activate.ps1"))
             self.assertIn('$env:BASE_LIST = "dummyValue1;dummyValue2;baseValue1;baseValue2;$env:BASE_LIST"', activate)
@@ -79,7 +76,6 @@ virtualenv
             self.assertIn('$env:LD_LIBRARY_PATH = "dummydir\\lib;basedir\\lib;$env:LD_LIBRARY_PATH"', activate)
             self.assertIn('$env:PATH = "dummydir\\bin;basedir\\bin;samebin;$env:PATH"', activate)
             self.assertIn('$env:SPECIAL_VAR = "dummyValue"', activate)
-            self.assertIn('$env:BCKW_SLASH = "dummy\\value"', activate)
 
             deactivate = load(os.path.join(client.current_folder, "deactivate.bat"))
             self.assertIn('SET PROMPT=%s' % env.setdefault('PROMPT', ''), deactivate)
@@ -89,7 +85,6 @@ virtualenv
             self.assertIn('SET LD_LIBRARY_PATH=%s' % env.setdefault('LD_LIBRARY_PATH', ''), deactivate)
             self.assertIn('SET PATH=%s' % env.setdefault('PATH', ''), deactivate)
             self.assertIn('SET SPECIAL_VAR=%s' % env.setdefault('SPECIAL_VAR', ''), deactivate)
-            self.assertIn('SET BCKW_SLASH=%s' % env.setdefault('BCKW_SLASH', ''), deactivate)
 
             deactivate = load(os.path.join(client.current_folder, "deactivate.ps1"))
             self.assertIn('$env:BASE_LIST = "%s"' % env.setdefault('BASE_LIST', ''), deactivate)
@@ -98,7 +93,6 @@ virtualenv
             self.assertIn('$env:LD_LIBRARY_PATH = "%s"' % env.setdefault('LD_LIBRARY_PATH', ''), deactivate)
             self.assertIn('$env:PATH = "%s"' % env.setdefault('PATH', ''), deactivate)
             self.assertIn('$env:SPECIAL_VAR = "%s"' % env.setdefault('SPECIAL_VAR', ''), deactivate)
-            self.assertIn('$env:BCKW_SLASH = "%s"' % env.setdefault('BCKW_SLASH', ''), deactivate)
 
         activate = load(os.path.join(client.current_folder, "activate.sh"))
         self.assertIn('OLD_PS1="$PS1"', activate)
@@ -113,8 +107,6 @@ virtualenv
         self.assertIn('export CPPFLAGS', activate)
         self.assertIn('SPECIAL_VAR="dummyValue"', activate)
         self.assertIn('export SPECIAL_VAR', activate)
-        self.assertIn('BCKW_SLASH="dummy\\value"', activate)
-        self.assertIn('export BCKW_SLASH', activate)
         if os_info.is_windows:
             self.assertIn('LD_LIBRARY_PATH="dummydir\\lib":"basedir\\lib":$LD_LIBRARY_PATH', activate)
             self.assertIn('PATH="dummydir\\bin":"basedir\\bin":"samebin":$PATH', activate)
@@ -134,7 +126,6 @@ virtualenv
             self.assertIn('PATH="%s"' % env.setdefault('PATH', ''), deactivate)
             self.assertIn('export PATH', deactivate)
             self.assertIn('unset SPECIAL_VAR', deactivate)
-            self.assertIn('unset BCKW_SLASH', deactivate)
         else:
             self.assertIn('OLD_PS1="%s"' % env.setdefault('OLD_PS1', ''), deactivate)
             self.assertIn('PS1=$OLD_PS1', deactivate)
@@ -153,8 +144,6 @@ virtualenv
             self.assertIn('export PATH', deactivate)
             self.assertIn('SPECIAL_VAR="%s"' % env.setdefault('SPECIAL_VAR', ''), deactivate)
             self.assertIn('export SPECIAL_VAR', deactivate)
-            self.assertIn('BCKW_SLASH="%s"' % env.setdefault('BCKW_SLASH', ''), deactivate)
-            self.assertIn('export BCKW_SLASH', deactivate)
 
     def environment_test(self):
         env = {"PROMPT": "old_PROMPT",
@@ -164,7 +153,6 @@ virtualenv
                "BASE_VAR": "old_BASE_VAR",
                "CPPFLAGS": "old_CPPFLAGS",
                "LD_LIBRARY_PATH": "old_LD_LIBRARY_PATH",
-               "SPECIAL_VAR": "old_SPECIAL_VAR",
-               "BCKW_SLASH": "old_BCKW_SLASH"}
+               "SPECIAL_VAR": "old_SPECIAL_VAR"}
         with tools.environment_append(env):
             self.basic_test(posix_empty_vars=False)
diff --git a/conans/test/integration/build_id_test.py b/conans/test/integration/build_id_test.py
index 519da1827..995674053 100644
--- a/conans/test/integration/build_id_test.py
+++ b/conans/test/integration/build_id_test.py
@@ -265,33 +265,3 @@ class BuildIdTest(unittest.TestCase):
             _check()
             self.assertIn("ID: ab2e9f86b4109980930cdc685f4a320b359e7bb4", client.out)
             self.assertNotIn("ID: f3989dcba0ab50dc5ed9b40ede202bdd7b421f09", client.out)
-
-    def failed_build_test(self):
-        conanfile = """from conans import ConanFile
-class MyTest(ConanFile):
-    settings = "os"
-    def build(self):
-        raise Exception("Failed build!!")
-"""
-        client = TestClient()
-        # NORMAL case, every create fails
-        client.save({"conanfile.py": conanfile})
-        error = client.run("create . pkg/0.1@user/channel", ignore_error=True)
-        self.assertTrue(error)
-        self.assertIn("ERROR: pkg/0.1@user/channel: Error in build() method, line 5",
-                      client.out)
-        error = client.run("create . pkg/0.1@user/channel", ignore_error=True)
-        self.assertTrue(error)
-        self.assertIn("ERROR: pkg/0.1@user/channel: Error in build() method, line 5",
-                      client.out)
-        # now test with build_id
-        client.save({"conanfile.py": conanfile +
-                     "    def build_id(self): self.info_build.settings.os = 'any'"})
-        error = client.run("create . pkg/0.1@user/channel", ignore_error=True)
-        self.assertTrue(error)
-        self.assertIn("ERROR: pkg/0.1@user/channel: Error in build() method, line 5",
-                      client.out)
-        error = client.run("create . pkg/0.1@user/channel", ignore_error=True)
-        self.assertTrue(error)
-        self.assertIn("ERROR: pkg/0.1@user/channel: Error in build() method, line 5",
-                      client.out)
diff --git a/conans/test/integration/cmake_flags_test.py b/conans/test/integration/cmake_flags_test.py
index 4de9bfef9..be114ce6b 100644
--- a/conans/test/integration/cmake_flags_test.py
+++ b/conans/test/integration/cmake_flags_test.py
@@ -1,11 +1,12 @@
+import os
 import platform
 import unittest
-import os
+
 from nose.plugins.attrib import attr
 from parameterized.parameterized import parameterized
 
-from conans.model.version import Version
 from conans.client.build.cmake import CMake
+from conans.model.version import Version
 from conans.test.utils.tools import TestClient
 
 
diff --git a/conans/test/integration/cppstd_test.py b/conans/test/integration/cppstd_test.py
index b7bce8626..b82e8d95d 100644
--- a/conans/test/integration/cppstd_test.py
+++ b/conans/test/integration/cppstd_test.py
@@ -23,7 +23,7 @@ class TestConan(ConanFile):
                            '-s compiler.version="4.6" -s cppstd=17', ignore_error=True)
         self.assertTrue(error)
         self.assertIn("The specified 'cppstd=17' is not available for 'gcc 4.6'", client.out)
-        self.assertIn("Possible values are ['11', '98', 'gnu11', 'gnu98']", client.out)
+        self.assertIn("Possible values are ['98', 'gnu98', '11', 'gnu11']", client.out)
 
         client.run('create . user/testing -s compiler="gcc" -s compiler.libcxx="libstdc++11" '
                    '-s compiler.version="6.3" -s cppstd=17')
diff --git a/conans/test/model/other_settings_test.py b/conans/test/model/other_settings_test.py
index ce4a5d4dc..0dbba5d7d 100644
--- a/conans/test/model/other_settings_test.py
+++ b/conans/test/model/other_settings_test.py
@@ -1,16 +1,19 @@
 import os
 import unittest
 
+from conans.util.files import save, load
+from conans.test.utils.tools import TestClient
+from conans.paths import CONANFILE, CONANINFO
 from conans.model.info import ConanInfo
-from conans.model.ref import PackageReference
 from conans.model.settings import undefined_value, bad_value_msg
-from conans.paths import CONANFILE, CONANINFO
-from conans.test.utils.tools import TestClient
-from conans.util.files import save, load
+from conans.model.ref import PackageReference
 
 
 class SettingsTest(unittest.TestCase):
 
+    def setUp(self):
+        self.client = TestClient()
+
     def wrong_settings_test(self):
         settings = """os:
     None:
@@ -28,35 +31,6 @@ class Pkg(ConanFile):
         self.assertTrue(error)
         self.assertIn("ERROR: settings.yml: None setting can't have subsettings", client.out)
 
-    def custom_compiler_preprocessor_test(self):
-        # https://github.com/conan-io/conan/issues/3842
-        settings = """compiler:
-    mycomp:
-        version: ["2.3", "2.4"]
-cppstd: [None, 98, gnu98, 11, gnu11, 14, gnu14, 17, gnu17, 20, gnu20]
-"""
-        client = TestClient()
-        save(client.paths.settings_path, settings)
-        save(client.paths.default_profile_path, """[settings]
-compiler=mycomp
-compiler.version=2.3
-cppstd=11
-""")
-        conanfile = """from conans import ConanFile
-class Pkg(ConanFile):
-    settings = "compiler", "cppstd"
-"""
-        client.save({"conanfile.py": conanfile})
-        client.run("create . Pkg/0.1@lasote/testing")
-        self.assertIn("""Configuration:
-[settings]
-compiler=mycomp
-compiler.version=2.3
-cppstd=11""", client.out)
-        self.assertIn("Pkg/0.1@lasote/testing: Package "
-                      "'c2f0c2641722089d9b11cd646c47d239af044b5a' created",
-                      client.out)
-
     def custom_settings_test(self):
         settings = """os:
     None:
@@ -77,8 +51,7 @@ class Pkg(ConanFile):
         self.assertIn("544c1d8c53e9d269737e68e00ec66716171d2704", client.out)
         client.run("search Pkg/0.1@lasote/testing")
         self.assertNotIn("os: None", client.out)
-        package_reference = PackageReference.loads("Pkg/0.1@lasote/testing:"
-                                                   "544c1d8c53e9d269737e68e00ec66716171d2704")
+        package_reference = PackageReference.loads("Pkg/0.1@lasote/testing:544c1d8c53e9d269737e68e00ec66716171d2704")
         info_path = os.path.join(client.paths.package(package_reference), CONANINFO)
         info = load(info_path)
         self.assertNotIn("os", info)
@@ -91,8 +64,9 @@ class Pkg(ConanFile):
         self.assertIn("os", info)
 
     def test_update_settings(self):
-        # This test is to validate that after adding a new settings, that allows a None
-        # value, this None value does not modify exisisting packages SHAs
+        """ This test is to validate that after adding a new settings, that allows a None
+    value, this None value does not modify exisisting packages SHAs
+    """
         file_content = '''
 from conans import ConanFile
 
@@ -153,8 +127,7 @@ compiler:
         client.run("export . lasote/testing")
 
         client.run("install test/1.9@lasote/testing --build -s arch=x86_64 -s compiler=gcc "
-                   "-s compiler.version=4.9 -s os=Windows -s build_type=None -s "
-                   "compiler.libcxx=libstdc++")
+                   "-s compiler.version=4.9 -s os=Windows -s build_type=None -s compiler.libcxx=libstdc++")
         self.assertIn("build_type", load(client.paths.settings_path))
         self.assertIn("390146894f59dda18c902ee25e649ef590140732", client.user_io.out)
 
@@ -208,19 +181,19 @@ class SayConan(ConanFile):
     version = "0.1"
     settings = "os"
 """
-        client = TestClient()
-        client.save({CONANFILE: content})
-        client.run("install . -s os=Windows --build missing")
+        self.client.save({CONANFILE: content})
+        self.client.run("install . -s os=Windows --build missing")
         # Now read the conaninfo and verify that settings applied is only os and value is windows
-        conan_info = ConanInfo.loads(load(os.path.join(client.current_folder, CONANINFO)))
+        conan_info = ConanInfo.loads(load(os.path.join(self.client.current_folder, CONANINFO)))
         self.assertEquals(conan_info.settings.os, "Windows")
 
-        client.run("install . -s os=Linux --build missing")
+        self.client.run("install . -s os=Linux --build missing")
         # Now read the conaninfo and verify that settings applied is only os and value is windows
-        conan_info = ConanInfo.loads(load(os.path.join(client.current_folder, CONANINFO)))
+        conan_info = ConanInfo.loads(load(os.path.join(self.client.current_folder, CONANINFO)))
         self.assertEquals(conan_info.settings.os, "Linux")
 
     def settings_as_a_list_conanfile_test(self):
+        """Declare settings as a list"""
         # Now with conanfile as a list
         content = """
 from conans import ConanFile
@@ -230,16 +203,16 @@ class SayConan(ConanFile):
     version = "0.1"
     settings = "os", "arch"
 """
-        client = TestClient()
-        client.save({CONANFILE: content})
-        client.run("install . -s os=Windows --build missing")
-        conan_info = ConanInfo.loads(load(os.path.join(client.current_folder, CONANINFO)))
+        self.client.save({CONANFILE: content})
+        self.client.run("install . -s os=Windows --build missing")
+        conan_info = ConanInfo.loads(load(os.path.join(self.client.current_folder, CONANINFO)))
         self.assertEquals(conan_info.settings.os,  "Windows")
         self.assertEquals(conan_info.settings.fields, ["arch", "os"])
 
     def settings_as_a_dict_conanfile_test(self):
+        """Declare settings as a dict"""
         # Now with conanfile as a dict
-        # XXX: this test only works on machines w default arch "x86", "x86_64", "sparc" or "sparcv9"
+        # XXX: this test only works on machines that default arch to "x86" or "x86_64" or "sparc" or "sparcv9"
         content = """
 from conans import ConanFile
 
@@ -248,20 +221,18 @@ class SayConan(ConanFile):
     version = "0.1"
     settings = {"os": ["Windows"], "arch": ["x86", "x86_64", "sparc", "sparcv9"]}
 """
-        client = TestClient()
-        client.save({CONANFILE: content})
-        client.run("install . -s os=Windows --build missing")
-        conan_info = ConanInfo.loads(load(os.path.join(client.current_folder, CONANINFO)))
+        self.client.save({CONANFILE: content})
+        self.client.run("install . -s os=Windows --build missing")
+        conan_info = ConanInfo.loads(load(os.path.join(self.client.current_folder, CONANINFO)))
         self.assertEquals(conan_info.settings.os,  "Windows")
         self.assertEquals(conan_info.settings.fields, ["arch", "os"])
 
     def invalid_settings_test(self):
         '''Test wrong values and wrong constraints'''
-        client = TestClient()
-        client.client_cache.default_profile
-        default_conf = load(client.paths.default_profile_path)
+        self.client.client_cache.default_profile
+        default_conf = load(self.client.paths.default_profile_path)
         new_conf = default_conf.replace("\nos=", "\n# os=")
-        save(client.paths.default_profile_path, new_conf)
+        save(self.client.paths.default_profile_path, new_conf)
         # MISSING VALUE FOR A SETTING
         content = """
 from conans import ConanFile
@@ -272,9 +243,9 @@ class SayConan(ConanFile):
     settings = "os", "build_type"
 """
 
-        client.save({CONANFILE: content})
-        client.run("install . --build missing", ignore_error=True)
-        self.assertIn(str(undefined_value("settings.os")), str(client.user_io.out))
+        self.client.save({CONANFILE: content})
+        self.client.run("install . --build missing", ignore_error=True)
+        self.assertIn(str(undefined_value("settings.os")), str(self.client.user_io.out))
 
     def invalid_settings_test2(self):
         # MISSING A DEFAULT VALUE BECAUSE ITS RESTRICTED TO OTHER, SO ITS REQUIRED
@@ -284,15 +255,13 @@ from conans import ConanFile
 class SayConan(ConanFile):
     name = "Say"
     version = "0.1"
-    settings = {"os": ["Windows", "Linux", "Macos", "FreeBSD", "SunOS"],
-                "compiler": ["Visual Studio"]}
+    settings = {"os": ["Windows", "Linux", "Macos", "FreeBSD", "SunOS"], "compiler": ["Visual Studio"]}
 """
-        client = TestClient()
-        client.save({CONANFILE: content})
-        client.run("install . -s compiler=gcc -s compiler.version=4.8 --build missing",
-                   ignore_error=True)
+
+        self.client.save({CONANFILE: content})
+        self.client.run("install . -s compiler=gcc -s compiler.version=4.8 --build missing", ignore_error=True)
         self.assertIn(bad_value_msg("settings.compiler", "gcc", ["Visual Studio"]),
-                      str(client.user_io.out))
+                      str(self.client.user_io.out))
 
     def invalid_settings_test3(self):
         # dict without options
@@ -304,12 +273,11 @@ class SayConan(ConanFile):
     version = "0.1"
     settings = {"os": None, "compiler": ["Visual Studio"]}
 """
-        client = TestClient()
-        client.save({CONANFILE: content})
-        client.run("install . -s compiler=gcc -s compiler.version=4.8 --build missing",
-                   ignore_error=True)
+
+        self.client.save({CONANFILE: content})
+        self.client.run("install . -s compiler=gcc -s compiler.version=4.8 --build missing", ignore_error=True)
         self.assertIn(bad_value_msg("settings.compiler", "gcc", ["Visual Studio"]),
-                      str(client.user_io.out))
+                      str(self.client.user_io.out))
 
         # Test wrong settings in conanfile
         content = """
@@ -321,10 +289,10 @@ class SayConan(ConanFile):
     settings = invalid
 """
 
-        client.save({CONANFILE: content})
-        client.run("install . --build missing", ignore_error=True)
+        self.client.save({CONANFILE: content})
+        self.client.run("install . --build missing", ignore_error=True)
         self.assertIn("invalid' is not defined",
-                      str(client.user_io.out))
+                      str(self.client.user_io.out))
 
         # Test wrong values in conanfile
     def invalid_settings_test4(self):
@@ -336,22 +304,22 @@ class SayConan(ConanFile):
     version = "0.1"
     settings = "os"
 """
-        client = TestClient()
-        client.save({CONANFILE: content})
-        client.run("install . -s os=ChromeOS --build missing", ignore_error=True)
+
+        self.client.save({CONANFILE: content})
+        self.client.run("install . -s os=ChromeOS --build missing", ignore_error=True)
         self.assertIn(bad_value_msg("settings.os", "ChromeOS",
-                                    ['Android', 'Arduino', 'FreeBSD', 'Linux', 'Macos', 'SunOS',
-                                     'Windows', 'WindowsStore', 'iOS', 'tvOS', 'watchOS']),
-                      str(client.user_io.out))
+                                    ['Android', 'Arduino', 'FreeBSD', 'Linux', 'Macos', 'SunOS', 'Windows',
+                                     'WindowsStore', 'iOS', 'tvOS', 'watchOS']),
+                      str(self.client.user_io.out))
 
         # Now add new settings to config and try again
-        config = load(client.paths.settings_path)
+        config = load(self.client.paths.settings_path)
         config = config.replace("Windows:%s" % os.linesep,
                                 "Windows:%s    ChromeOS:%s" % (os.linesep, os.linesep))
 
-        save(client.paths.settings_path, config)
-        client.run("install . -s os=ChromeOS --build missing")
-        self.assertIn('Generated conaninfo.txt', str(client.user_io.out))
+        save(self.client.paths.settings_path, config)
+        self.client.run("install . -s os=ChromeOS --build missing")
+        self.assertIn('Generated conaninfo.txt', str(self.client.user_io.out))
 
         # Settings is None
         content = """
@@ -362,10 +330,10 @@ class SayConan(ConanFile):
     version = "0.1"
     settings = None
 """
-        client.save({CONANFILE: content})
-        client.run("install . --build missing")
-        self.assertIn('Generated conaninfo.txt', str(client.user_io.out))
-        conan_info = ConanInfo.loads(load(os.path.join(client.current_folder, CONANINFO)))
+        self.client.save({CONANFILE: content})
+        self.client.run("install . --build missing")
+        self.assertIn('Generated conaninfo.txt', str(self.client.user_io.out))
+        conan_info = ConanInfo.loads(load(os.path.join(self.client.current_folder, CONANINFO)))
         self.assertEquals(conan_info.settings.dumps(), "")
 
         # Settings is {}
@@ -377,8 +345,8 @@ class SayConan(ConanFile):
     version = "0.1"
     settings = {}
 """
-        client.save({CONANFILE: content})
-        client.run("install . --build missing")
-        self.assertIn('Generated conaninfo.txt', str(client.user_io.out))
-        conan_info = ConanInfo.loads(load(os.path.join(client.current_folder, CONANINFO)))
+        self.client.save({CONANFILE: content})
+        self.client.run("install . --build missing")
+        self.assertIn('Generated conaninfo.txt', str(self.client.user_io.out))
+        conan_info = ConanInfo.loads(load(os.path.join(self.client.current_folder, CONANINFO)))
         self.assertEquals(conan_info.settings.dumps(), "")
diff --git a/conans/test/utils/tools.py b/conans/test/utils/tools.py
index 0360250c9..f7c8ea341 100644
--- a/conans/test/utils/tools.py
+++ b/conans/test/utils/tools.py
@@ -336,7 +336,8 @@ class SVNLocalRepoTestCase(unittest.TestCase):
             os.makedirs(tmp)
         return tmp
 
-    def create_project(self, files, rel_project_path=None, commit_msg='default commit message', delete_checkout=True):
+    def create_project(self, files, rel_project_path=None, commit_msg='default commit message',
+                       delete_checkout=True, lock_repo=False):
         tmp_dir = self.gimme_tmp()
         try:
             rel_project_path = rel_project_path or str(uuid.uuid4())
@@ -347,6 +348,8 @@ class SVNLocalRepoTestCase(unittest.TestCase):
             save_files(tmp_project_dir, files)
             with chdir(tmp_project_dir):
                 subprocess.check_output("svn add .", shell=True)
+                if lock_repo:
+                    subprocess.check_output('svn propset svn:needs-lock * . -R', shell=True)
                 subprocess.check_output('svn commit -m "{}"'.format(commit_msg), shell=True)
                 if SVN.get_version() >= SVN.API_CHANGE_VERSION:
                     rev = subprocess.check_output("svn info --show-item revision", shell=True).decode().strip()