Repository: conan-io/conan
Pull request #3581 (2018-09-20 07:26:23)

- fix PowerPC architecture detection
Signed-off-by: SSE4 <tomskside@gmail.com>

related to the https://github.com/bincrafters/community/issues/443
properly detects ppc64le architecture and few others
based on python's `platform.machine()`, which actually uses `uname` under the hood
tested on PowerPC VM
see also

1. https://stackoverflow.com/questions/45125516/possible-values-for-uname-m
2. https://en.wikipedia.org/wiki/Uname
3. https://github.com/gcc-mirror/gcc/blob/master/config.guess

- [x] Refer to the issue that supports this Pull Request.
- [x] If the issue has missing info, explain the purpose/use case/pain/need that covers this Pull Request.
- [x] I've read the [Contributing guide](https://raw.githubusercontent.com/conan-io/conan/develop/.github/CONTRIBUTING.md).
- [x] I've followed the PEP8 style guides for Python code.
- [ ] I've opened another PR in the Conan docs repo to the ``develop`` branch, documenting this one. Also adding a description of the changes in the ``changelog.rst`` file. https://github.com/conan-io/docs



Patch:
diff --git a/conans/client/generators/__init__.py b/conans/client/generators/__init__.py
index 958d2a163..afb25020d 100644
--- a/conans/client/generators/__init__.py
+++ b/conans/client/generators/__init__.py
@@ -26,6 +26,7 @@ from .boostbuild import BoostBuildGenerator
 from .json_generator import JsonGenerator
 import traceback
 from conans.util.env_reader import get_env
+from .b2 import B2Generator
 
 
 class _GeneratorManager(object):
@@ -70,6 +71,7 @@ registered_generators.add("virtualrunenv", VirtualRunEnvGenerator)
 registered_generators.add("boost-build", BoostBuildGenerator)
 registered_generators.add("pkg_config", PkgConfigGenerator)
 registered_generators.add("json", JsonGenerator)
+registered_generators.add("b2", B2Generator)
 
 
 def write_generators(conanfile, path, output):
diff --git a/conans/client/generators/b2.py b/conans/client/generators/b2.py
new file mode 100644
index 000000000..d02129de9
--- /dev/null
+++ b/conans/client/generators/b2.py
@@ -0,0 +1,418 @@
+
+"""
+B2 Conan Generator
+This is a generator for conanbuildinfo.jam files declaring all conan dependencies
+as B2 project and library targets. This generates multiple tagged build info
+source files, each containing a single variant as specified by the user's
+conan install profile in addition to the central generic one that includes
+all possible variants.
+"""
+
+from conans.model import Generator
+from hashlib import md5
+
+
+class B2Generator(Generator):
+
+    @property
+    def filename(self):
+        pass  # in this case, filename defined in return value of content method
+
+    @property
+    def content(self):
+        '''
+        Generates two content files: conanbuildinfo.jam and conanbuildinfo-ID.jam which
+        the former defines sub-projects for each package and loads the other files and
+        the latter define variables and targets for the packages.
+        '''
+        result = {
+            'conanbuildinfo.jam': None,
+            self.conanbuildinfo_variation_jam: None
+        }
+
+        # Generate the common conanbuildinfo.jam which does four things:
+        # 1. Defines some common utility functions to make the rest of the code short.
+        # 2. Includes the conanbuildinfo-*.jam sub-files for constant declarations.
+        # 3. Defines all the package sub-projects.
+        # 4. Includes the conanbuildinfo-*.jam sub-files again, this time for declaring targets.
+        cbi = [self.conanbuildinfo_header_text]
+        # The prefix that does 1 & 2.
+        cbi += [self.conanbuildinfo_prefix_text]
+        # The sub-project definitions, i.e. 3.
+        for dep_name, dep_cpp_info in self.deps_build_info.dependencies:
+            cbi += ["", "# %s" % (dep_name.lower())]
+            cbi += self.b2_project_for_dep(dep_name, dep_cpp_info)
+        # The postfix which does 4.
+        cbi += [self.conanbuildinfo_postfix_text]
+        # The combined text.
+        result['conanbuildinfo.jam'] = "\n".join(cbi)
+
+        # Generate the current build variation conanbuildinfo-/variation/.jam which does two things:
+        # 1. Defines project constants for the corresponding conan buildinfo variables.
+        # 2. Declares targets, with b2 requirements to select the variation, for each
+        #   library in a package and one "libs" target for the collection of all the libraries
+        #   in the package.
+        cbiv = [self.conanbuildinfo_header_text]
+        # The first, 1, set of variables are collective in that they have the info for all
+        # of the packages combined, 1a.
+        cbiv += ["# global" ]
+        cbiv += self.b2_constants_for_dep('conan', self.deps_build_info)
+        # Now the constants for individual packages, 1b.
+        for dep_name, dep_cpp_info in self.deps_build_info.dependencies:
+            cbiv += ["# %s" % (dep_name.lower())]
+            cbiv += self.b2_constants_for_dep(
+                dep_name, dep_cpp_info, self.deps_user_info[dep_name])
+        # Second, 2, part are the targets for the packages.
+        for dep_name, dep_cpp_info in self.deps_build_info.dependencies:
+            cbiv += ["# %s" % (dep_name.lower())]
+            cbiv += self.b2_targets_for_dep(dep_name, dep_cpp_info)
+        result[self.conanbuildinfo_variation_jam] = "\n".join(cbiv)
+
+        return result
+
+    def b2_project_for_dep(self, name, info):
+        '''
+        Generates a sub-project definition to match the package. Which is used later
+        to define targets for the package libs.
+        '''
+        if not info:
+            return []
+        name = name.lower()
+        # Create a b2 project for the package dependency.
+        return [self.conanbuildinfo_project_template.format(name=name)]
+    
+    def b2_constants_for_dep(self, name, info, user=None):
+        '''
+        Generates a list of constant variable definitions for the information in the
+        CppInfo conan data given for the package. If user variables map is also given
+        those are also generated following the package variables.
+        '''
+        if not info:
+            return []
+        name = name.lower()
+
+        # Define the info specific variables. Note that the 'usage-requirements' one
+        # needs to be last as it references the others.
+        result = \
+            self.b2_constant(name, 'rootpath', [info.rootpath], True) + \
+            self.b2_constant(name, 'includedirs', info.include_paths, True) + \
+            self.b2_constant(name, 'libdirs', info.lib_paths, True) + \
+            self.b2_constant(name, 'defines', info.defines) + \
+            self.b2_constant(name, 'cppflags', info.cppflags) + \
+            self.b2_constant(name, 'cflags', info.cflags) + \
+            self.b2_constant(name, 'sharedlinkflags', info.sharedlinkflags) + \
+            self.b2_constant(name, 'exelinkflags', info.exelinkflags) + \
+            self.b2_constant(name, 'requirements', self.b2_features(self.b2_variation)) + \
+            self.b2_constant(name, 'usage-requirements', [
+                '<include>$(includedirs({name},{variation}))'.format(name=name, variation=self.b2_variation_id),
+                '<define>$(defines({name},{variation}))'.format(name=name, variation=self.b2_variation_id),
+                '<cflags>$(cflags({name},{variation}))'.format(name=name, variation=self.b2_variation_id),
+                '<cxxflags>$(cppflags({name},{variation}))'.format(name=name, variation=self.b2_variation_id),
+                '<link>shared:<linkflags>$(sharedlinkflags({name},{variation}))'.format(name=name, variation=self.b2_variation_id)
+                ])
+
+        if user:
+            for uk, uv in user.vars.items():
+                result += self.b2_constant(uk.lower() + ',' + name, 'user', [uv])
+
+        return result
+
+    def b2_targets_for_dep(self, name, info):
+        '''
+        Generates individual targets for the libraries in a package and a single "libs"
+        collective alias target that refers to them.
+        '''
+        if not info:
+            return []
+        name = name.lower()
+        result = []
+        if info.libs:
+            for lib in info.libs:
+                result += [self.conanbuildinfo_variation_lib_template.format(
+                    name=name, lib=lib, variation=self.b2_variation_id)]
+            result += [self.conanbuildinfo_variation_alias_template.format(
+                name=name, libs=" ".join(info.libs), variation=self.b2_variation_id)]
+        else:
+            result += [self.conanbuildinfo_variation_alias_template.format(
+                name=name, libs="", variation=self.b2_variation_id)]
+
+        return result
+
+    def b2_constant(self, name, var, val, is_paths=False):
+        '''
+        Generates a constant definition for the given variable and value(s). If is_path
+        is True the value(s) are reformated to be acceptable to b2.
+        '''
+        if not val:
+            return []
+        if is_paths:
+            val = list(self.b2_path(p) for p in val)
+        value = []
+        for v in val:
+            if v.startswith('<'):
+                value += ['    {val}'.format(val=v)]
+            else:
+                value += ['    "{val}"'.format(val=v)]
+        return [self.conanbuildinfo_variation_constant_template.format(
+            name=name, var=var, variation=self.b2_variation_id, value="\n".join(value)
+        )]
+
+    def b2_path(self, p):
+        '''
+        Adjust a ragular path to the form b2 can use in source code.
+        '''
+        return p.replace('\\', '/')
+
+    def b2_features(self, m):
+        '''
+        Generated a b2 requirements list, i.e. <name>value list, from the given
+        map of key-values.
+        '''
+        result = []
+        for k, v in sorted(m.items()):
+            if v:
+                result += ['<%s>%s' % (k, v)]
+        return result
+
+    @property
+    def conanbuildinfo_variation_jam(self):
+        return 'conanbuildinfo-%s.jam'%(self.b2_variation_key)
+
+    _b2_variation_key = None
+
+    @property
+    def b2_variation_key(self):
+        '''
+        A hashed key of the variation to use a UID for the variation.
+        '''
+        if not self._b2_variation_key:
+            self._b2_variation_key = md5(self.b2_variation_id.encode('utf-8')).hexdigest()
+        return self._b2_variation_key
+
+    _b2_variation_id = None
+
+    @property
+    def b2_variation_id(self):
+        '''
+        A compact single comma separated list of the variation where only the values
+        of the b2 variation are included in sorted by feature name order.
+        '''
+        if not self._b2_variation_id:
+            vid = []
+            for k in sorted(self.b2_variation.keys()):
+                if self.b2_variation[k]:
+                    vid += [self.b2_variation[k]]
+            self._b2_variation_id = ",".join(vid)
+        return self._b2_variation_id
+
+    @property
+    def b2_variation(self):
+        '''
+        Returns a map of b2 features & values as translated from conan settings that
+        can affect the link compatibility of libraries.
+        '''
+        if not getattr(self, "_b2_variation_key", None):
+            self._b2_variation = {}
+            self._b2_variation['toolset'] = {
+                'sun-cc': 'sun',
+                'gcc': 'gcc',
+                'Visual Studio': 'msvc',
+                'clang': 'clang',
+                'apple-clang': 'clang'
+            }.get(self.conanfile.settings.get_safe('compiler'))+'-'+self.b2_toolset_version
+            self._b2_variation['architecture'] = {
+                'x86': 'x86', 'x86_64': 'x86',
+                'ppc64le': 'power', 'ppc64': 'power',
+                'armv6': 'arm', 'armv7': 'arm', 'armv7hf': 'arm', 'armv8': 'arm',
+                'armv7s': 'arm', 'armv7k': 'arm',
+                'sparc': 'sparc', 'sparcv9': 'sparc',
+                'mips': 'mips1', 'mips64': 'mips64',
+            }.get(self.conanfile.settings.get_safe('arch'))
+            self._b2_variation['instruction-set'] = {
+                'armv6': 'armv6', 'armv7': 'armv7', 'armv7hf': None, 'armv7k': None,
+                'armv7s': 'armv7s', 'armv8': None, 'avr': None,
+                'mips': None, 'mips64': None,
+                'ppc64le': None, 'ppc64': 'powerpc64',
+                'sparc': None, 'sparcv9': 'v9',
+                'x86': None, 'x86_64': None,
+            }.get(self.conanfile.settings.get_safe('arch'))
+            self._b2_variation['address-model'] = {
+                'x86': '32', 'x86_64': '64',
+                'ppc64le': '64', 'ppc64': '64',
+                'armv6': '32', 'armv7': '32', 'armv7hf': '32', 'armv8': '64',
+                'armv7s': '32', 'armv7k': '32',
+                'sparc': '32', 'sparcv9': '64',
+                'mips': '32', 'mips64': '64',
+            }.get(self.conanfile.settings.get_safe('arch'))
+            self._b2_variation['target-os'] = {
+                'Windows': 'windows', 'WindowsStore': 'windows',
+                'Linux': 'linux',
+                'Macos': 'darwin',
+                'Android': 'android',
+                'iOS': 'darwin', 'watchOS': 'darwin', 'tvOS': 'darwin',
+                'FreeBSD': 'freebsd',
+                'SunOS': 'solaris',
+                'Arduino': 'linux',
+            }.get(self.conanfile.settings.get_safe('os'))
+            self._b2_variation['variant'] = {
+                'Debug': 'debug',
+                'Release': 'release',
+                'RelWithDebInfo': 'relwithdebinfo',
+                'MinSizeRel': 'minsizerel',
+            }.get(self.conanfile.settings.get_safe('build_type'))
+            self._b2_variation['cxxstd'] = {
+                '98': '98', 'gnu98': '98',
+                '11': '11', 'gnu11': '11',
+                '14': '14', 'gnu14': '14',
+                '17': '17', 'gnu17': '17',
+                '2a': '2a', 'gnu2a': '2a',
+                '2b': '2b', 'gnu2b': '2b',
+                '2c': '2c', 'gnu2c': '2c',
+            }.get(self.conanfile.settings.get_safe('cppstd'))
+            self._b2_variation['cxxstd:dialect'] = {
+                '98': None, 'gnu98': 'gnu',
+                '11': None, 'gnu11': 'gnu',
+                '14': None, 'gnu14': 'gnu',
+                '17': None, 'gnu17': 'gnu',
+                '2a': None, 'gnu2a': 'gnu',
+                '2b': None, 'gnu2b': 'gnu',
+                '2c': None, 'gnu2c': 'gnu',
+            }.get(self.conanfile.settings.get_safe('cppstd'))
+        return self._b2_variation
+    
+    @property
+    def b2_toolset_version(self):
+        if self.conanfile.settings.compiler == 'Visual Studio':
+            if self.conanfile.settings.compiler.version == '15':
+                return '14.1'
+            else:
+                return str(self.conanfile.settings.compiler.version)+'.0'
+        return str(self.conanfile.settings.compiler.version)
+
+    conanbuildinfo_header_text = '''\
+#|
+    B2 definitions for Conan packages. This is a generated file.
+    Edit the corresponding conanfile.txt instead.
+|#
+'''
+
+    conanbuildinfo_prefix_text = '''\
+import path ;
+import project ;
+import modules ;
+import feature ;
+
+local base-project = [ project.current ] ;
+local base-project-mod = [ $(base-project).project-module ] ;
+local base-project-location = [ project.attribute $(base-project-mod) location ] ;
+
+rule project-define ( id )
+{
+    id = $(id:L) ;
+    local saved-project = [ modules.peek project : .base-project ] ;
+    local id-location = [ path.join $(base-project-location) $(id) ] ;
+    local id-mod = [ project.load $(id-location) : synthesize ] ;
+    project.initialize $(id-mod) : $(id-location) ;
+    project.inherit-attributes $(id-mod) : $(base-project-mod) ;
+    local attributes = [ project.attributes $(id-mod) ] ;
+    $(attributes).set parent-module : $(base-project-mod) : exact ;
+    modules.poke $(base-project-mod) : $(id)-mod : $(id-mod) ;
+    modules.poke [ CALLER_MODULE ] : $(id)-mod : $(id-mod) ;
+    modules.poke project : .base-project : $(saved-project) ;
+    IMPORT $(__name__)
+        : constant-if call-in-project
+        : $(id-mod)
+        : constant-if call-in-project ;
+    return $(id-mod) ;
+}
+
+rule constant-if ( name : value * )
+{
+    if $(__define_constants__) && $(value)
+    {
+        call-in-project : constant $(name) : $(value) ;
+        modules.poke $(__name__) : $(name) : [ modules.peek $(base-project-mod) : $(name) ] ;
+    }
+}
+
+rule call-in-project ( project-mod ? : rule-name args * : * )
+{
+    project-mod ?= $(base-project-mod) ;
+    project.push-current [ project.target $(project-mod) ] ;
+    local result = [ modules.call-in $(project-mod) :
+        $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : $(10) :
+        $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17) : $(18) :
+        $(19) ] ;
+    project.pop-current ;
+    return $(result) ;
+}
+
+rule include-conanbuildinfo ( cbi )
+{
+    include $(cbi) ;
+}
+
+IMPORT $(__name__)
+    : project-define constant-if call-in-project include-conanbuildinfo
+    : $(base-project-mod)
+    : project-define constant-if call-in-project include-conanbuildinfo ;
+
+if ! ( relwithdebinfo in [ feature.values variant ] )
+{
+    variant relwithdebinfo : : <optimization>speed <debug-symbols>on <inlining>full <runtime-debugging>off ;
+}
+if ! ( minsizerel in [ feature.values variant ] )
+{
+    variant minsizerel : : <optimization>space <debug-symbols>off <inlining>full <runtime-debugging>off ;
+}
+
+local __conanbuildinfo__ = [ GLOB $(__file__:D) : conanbuildinfo-*.jam : downcase ] ;
+{
+    local __define_constants__ = yes ;
+    for local __cbi__ in $(__conanbuildinfo__)
+    {
+        call-in-project : include-conanbuildinfo $(__cbi__) ;
+    }
+}
+'''
+
+    conanbuildinfo_project_template = '''\
+# {name}
+project-define {name} ;
+'''
+
+    conanbuildinfo_postfix_text = '''\
+{
+    local __define_targets__ = yes ;
+    for local __cbi__ in $(__conanbuildinfo__)
+    {
+        call-in-project : include-conanbuildinfo $(__cbi__) ;
+    }
+}
+'''
+
+    conanbuildinfo_variation_constant_template = '''\
+constant-if {var}({name},{variation}) :
+{value}
+    ;
+'''
+
+    conanbuildinfo_variation_lib_template = '''\
+if $(__define_targets__) {{
+    call-in-project $({name}-mod) : lib {lib}
+        :
+        : <name>{lib} <search>$(libdirs({name},{variation})) $(requirements({name},{variation}))
+        :
+        : $(usage-requirements({name},{variation})) ;
+    call-in-project $({name}-mod) : explicit {lib} ; }}
+'''
+
+    conanbuildinfo_variation_alias_template = '''\
+if $(__define_targets__) {{
+    call-in-project $({name}-mod) : alias libs
+        : {libs}
+        : $(requirements({name},{variation}))
+        :
+        : $(usage-requirements({name},{variation})) ;
+    call-in-project $({name}-mod) : explicit libs ; }}
+'''
diff --git a/conans/client/tools/oss.py b/conans/client/tools/oss.py
index 9e492a9ed..f66a3226b 100644
--- a/conans/client/tools/oss.py
+++ b/conans/client/tools/oss.py
@@ -35,7 +35,21 @@ def cpu_count():
 def detected_architecture():
     # FIXME: Very weak check but not very common to run conan in other architectures
     machine = platform.machine()
-    if "64" in machine:
+    if "ppc64le" in machine:
+        return "ppc64le"
+    elif "ppc64" in machine:
+        return "ppc64"
+    elif "mips64" in machine:
+        return "mips64"
+    elif "mips" in machine:
+        return "mips"
+    elif "sparc64" in machine:
+        return "sparcv9"
+    elif "sparc" in machine:
+        return "sparc"
+    elif "aarch64" in machine:
+        return "armv8"
+    elif "64" in machine:
         return "x86_64"
     elif "86" in machine:
         return "x86"
@@ -43,6 +57,8 @@ def detected_architecture():
         return "armv8"
     elif "armv7" in machine:
         return "armv7"
+    elif "arm" in machine:
+        return "armv6"
 
     return None
 
diff --git a/conans/client/tools/system_pm.py b/conans/client/tools/system_pm.py
index cf77a82be..2bf99c931 100644
--- a/conans/client/tools/system_pm.py
+++ b/conans/client/tools/system_pm.py
@@ -149,7 +149,7 @@ class AptTool(object):
         _run(self._runner, "%sapt-get install -y %s%s" % (self._sudo_str, recommends_str, package_name))
 
     def installed(self, package_name):
-        exit_code = self._runner("dpkg -s %s" % package_name, None)
+        exit_code = self._runner("dpkg-query -W -f='${Status}' %s | grep -q \"ok installed\"" % package_name, None)
         return exit_code == 0
 
 
diff --git a/conans/model/ref.py b/conans/model/ref.py
index dd99986bd..8fd25f750 100644
--- a/conans/model/ref.py
+++ b/conans/model/ref.py
@@ -1,44 +1,56 @@
 from collections import namedtuple
 import re
+from six import string_types
 from conans.errors import ConanException, InvalidNameException
 from conans.model.version import Version
 
 
 class ConanName(object):
-    _max_chars = 50
+    _max_chars = 51
     _min_chars = 2
     _validation_pattern = re.compile("^[a-zA-Z0-9_][a-zA-Z0-9_\+\.-]{%s,%s}$"
-                                     % (_min_chars - 1, _max_chars))
+                                     % (_min_chars - 1, _max_chars - 1))
 
     @staticmethod
-    def invalid_name_message(name):
-        if len(name) > ConanName._max_chars:
-            message = ("'%s' is too long. Valid names must contain at most %s characters."
-                       % (name, ConanName._max_chars))
-        elif len(name) < ConanName._min_chars:
-            message = ("'%s' is too short. Valid names must contain at least %s characters."
-                       % (name, ConanName._min_chars))
+    def invalid_name_message(value, reference_token=None):
+        if len(value) > ConanName._max_chars:
+            reason = "is too long. Valid names must contain at most %s characters."\
+                     % ConanName._max_chars
+        elif len(value) < ConanName._min_chars:
+            reason = "is too short. Valid names must contain at least %s characters."\
+                     % ConanName._min_chars
         else:
-            message = ("'%s' is an invalid name. Valid names MUST begin with a "
-                       "letter or number, have between %s-%s chars, including "
-                       "letters, numbers, underscore, dot and dash"
-                       % (name, ConanName._min_chars, ConanName._max_chars))
+            reason = ("is an invalid name. Valid names MUST begin with a "
+                      "letter, number or underscore, have between %s-%s chars, including "
+                      "letters, numbers, underscore, dot and dash"
+                      % (ConanName._min_chars, ConanName._max_chars))
+        message = "Value provided{ref_token}, '{value}' (type {type}), {reason}".format(
+            ref_token=" for {}".format(reference_token) if reference_token else "",
+            value=value, type=type(value).__name__, reason=reason
+        )
         raise InvalidNameException(message)
 
     @staticmethod
-    def validate_user(username):
-        if ConanName._validation_pattern.match(username) is None:
-            ConanName.invalid_name_message(username)
+    def validate_string(value, reference_token=None):
+        """Check for string"""
+        if not isinstance(value, string_types):
+            message = "Value provided{ref_token}, '{value}' (type {type}), {reason}".format(
+                ref_token=" for {}".format(reference_token) if reference_token else "",
+                value=value, type=type(value).__name__,
+                reason="is not a string"
+            )
+            raise InvalidNameException(message)
 
     @staticmethod
-    def validate_name(name, version=False):
+    def validate_name(name, version=False, reference_token=None):
         """Check for name compliance with pattern rules"""
+        ConanName.validate_string(name, reference_token=reference_token)
         if name == "*":
             return
         if ConanName._validation_pattern.match(name) is None:
             if version and name.startswith("[") and name.endswith("]"):
                 return
-            ConanName.invalid_name_message(name)
+            ConanName.invalid_name_message(name, reference_token=reference_token)
 
 
 class ConanFileReference(namedtuple("ConanFileReference", "name version user channel")):
@@ -52,16 +64,19 @@ class ConanFileReference(namedtuple("ConanFileReference", "name version user cha
     def __new__(cls, name, version, user, channel, revision=None):
         """Simple name creation.
         @param name:        string containing the desired name
-        @param validate:    checks for valid complex name. default True
+        @param version:     string containing the desired version
+        @param user:        string containing the user name
+        @param channel:     string containing the user channel
+        @param revision:    string containing the revision (optional)
         """
-        ConanName.validate_name(name)
-        ConanName.validate_name(version, True)
-        ConanName.validate_name(user)
-        ConanName.validate_name(channel)
+        ConanName.validate_name(name, reference_token="package name")
+        ConanName.validate_name(version, True, reference_token="package version")
+        ConanName.validate_name(user, reference_token="user name")
+        ConanName.validate_name(channel, reference_token="channel")
         version = Version(version)
         obj = super(cls, ConanFileReference).__new__(cls, name, version, user, channel)
         if revision:
-            ConanName.validate_name(revision)
+            ConanName.validate_name(revision, reference_token="revision")
         obj.revision = revision
         return obj
 
@@ -123,7 +138,7 @@ class PackageReference(namedtuple("PackageReference", "conan package_id")):
         revision = None
         if "#" in package_id:
             package_id, revision = package_id.rsplit("#", 1)
-            ConanName.validate_name(revision)
+            ConanName.validate_name(revision, reference_token="revision")
         obj = super(cls, PackageReference).__new__(cls, conan, package_id)
         obj.revision = revision
         return obj
diff --git a/conans/util/config_parser.py b/conans/util/config_parser.py
index 64404a0f4..6c2d62e94 100644
--- a/conans/util/config_parser.py
+++ b/conans/util/config_parser.py
@@ -4,7 +4,7 @@ from conans.errors import ConanException
 
 def get_bool_from_text_value(value):
     """ to be deprecated
-    It has issues, as accepting into the registry whatever=value, as False, withoug
+    It has issues, as accepting into the registry whatever=value, as False, without
     complaining
     """
     return (value == "1" or value.lower() == "yes" or value.lower() == "y" or


Test patch:
diff --git a/conans/test/command/new_test.py b/conans/test/command/new_test.py
index 5f9410bde..4237bbde4 100644
--- a/conans/test/command/new_test.py
+++ b/conans/test/command/new_test.py
@@ -28,12 +28,12 @@ class NewTest(unittest.TestCase):
         client = TestClient()
         error = client.run('new A/1.3@myuser/testing', ignore_error=True)
         self.assertTrue(error)
-        self.assertIn("ERROR: 'A' is too short. Valid names must contain at least 2 characters.",
-                      client.user_io.out)
+        self.assertIn("ERROR: Value provided for package name, 'A' (type str), is too short. Valid "
+                      "names must contain at least 2 characters.", client.user_io.out)
         error = client.run('new A2/1.3@myuser/u', ignore_error=True)
         self.assertTrue(error)
-        self.assertIn("ERROR: 'u' is too short. Valid names must contain at least 2 characters.",
-                      client.user_io.out)
+        self.assertIn("ERROR: Value provided for channel, 'u' (type str), is too short. Valid "
+                      "names must contain at least 2 characters.", client.user_io.out)
 
     def new_dash_test(self):
         """ packages with dash
diff --git a/conans/test/generators/b2_test.py b/conans/test/generators/b2_test.py
new file mode 100644
index 000000000..1b1b94fe8
--- /dev/null
+++ b/conans/test/generators/b2_test.py
@@ -0,0 +1,330 @@
+import unittest
+
+from conans.client.generators.b2 import B2Generator
+from conans.model.settings import Settings
+from conans.model.conan_file import ConanFile
+from conans.model.build_info import CppInfo
+from conans.model.ref import ConanFileReference
+from conans.model.env_info import EnvValues
+from conans.client.conf import default_settings_yml
+
+
+class B2GeneratorTest(unittest.TestCase):
+
+    def b2_test(self):
+        settings = Settings.loads(default_settings_yml)
+        settings.os = "Linux"
+        settings.compiler = "gcc"
+        settings.compiler.version = "6.3"
+        settings.arch = "x86"
+        settings.build_type = "Release"
+        settings.cppstd = "gnu17"
+
+        conanfile = ConanFile(None, None)
+        conanfile.initialize(Settings({}), EnvValues())
+        conanfile.settings = settings
+
+        ref = ConanFileReference.loads("MyPkg/0.1@lasote/stables")
+        cpp_info = CppInfo("dummy_root_folder1")
+        cpp_info.defines = ["MYDEFINE1"]
+        cpp_info.cflags.append("-Flag1=23")
+        cpp_info.version = "1.3"
+        cpp_info.description = "My cool description"
+        cpp_info.libs = ["MyLib1"]
+
+        conanfile.deps_cpp_info.update(cpp_info, ref.name)
+        ref = ConanFileReference.loads("MyPkg2/0.1@lasote/stables")
+        cpp_info = CppInfo("dummy_root_folder2")
+        cpp_info.libs = ["MyLib2"]
+        cpp_info.defines = ["MYDEFINE2"]
+        cpp_info.version = "2.3"
+        cpp_info.exelinkflags = ["-exelinkflag"]
+        cpp_info.sharedlinkflags = ["-sharedlinkflag"]
+        cpp_info.cppflags = ["-cppflag"]
+        cpp_info.public_deps = ["MyPkg"]
+        cpp_info.lib_paths.extend(["Path\\with\\slashes", "regular/path/to/dir"])
+        cpp_info.include_paths.extend(["other\\Path\\with\\slashes", "other/regular/path/to/dir"])
+        conanfile.deps_cpp_info.update(cpp_info, ref.name)
+        generator = B2Generator(conanfile)
+
+        content = {
+'conanbuildinfo.jam':
+'''#|
+    B2 definitions for Conan packages. This is a generated file.
+    Edit the corresponding conanfile.txt instead.
+|#
+
+import path ;
+import project ;
+import modules ;
+import feature ;
+
+local base-project = [ project.current ] ;
+local base-project-mod = [ $(base-project).project-module ] ;
+local base-project-location = [ project.attribute $(base-project-mod) location ] ;
+
+rule project-define ( id )
+{
+    id = $(id:L) ;
+    local saved-project = [ modules.peek project : .base-project ] ;
+    local id-location = [ path.join $(base-project-location) $(id) ] ;
+    local id-mod = [ project.load $(id-location) : synthesize ] ;
+    project.initialize $(id-mod) : $(id-location) ;
+    project.inherit-attributes $(id-mod) : $(base-project-mod) ;
+    local attributes = [ project.attributes $(id-mod) ] ;
+    $(attributes).set parent-module : $(base-project-mod) : exact ;
+    modules.poke $(base-project-mod) : $(id)-mod : $(id-mod) ;
+    modules.poke [ CALLER_MODULE ] : $(id)-mod : $(id-mod) ;
+    modules.poke project : .base-project : $(saved-project) ;
+    IMPORT $(__name__)
+        : constant-if call-in-project
+        : $(id-mod)
+        : constant-if call-in-project ;
+    return $(id-mod) ;
+}
+
+rule constant-if ( name : value * )
+{
+    if $(__define_constants__) && $(value)
+    {
+        call-in-project : constant $(name) : $(value) ;
+        modules.poke $(__name__) : $(name) : [ modules.peek $(base-project-mod) : $(name) ] ;
+    }
+}
+
+rule call-in-project ( project-mod ? : rule-name args * : * )
+{
+    project-mod ?= $(base-project-mod) ;
+    project.push-current [ project.target $(project-mod) ] ;
+    local result = [ modules.call-in $(project-mod) :
+        $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) : $(10) :
+        $(11) : $(12) : $(13) : $(14) : $(15) : $(16) : $(17) : $(18) :
+        $(19) ] ;
+    project.pop-current ;
+    return $(result) ;
+}
+
+rule include-conanbuildinfo ( cbi )
+{
+    include $(cbi) ;
+}
+
+IMPORT $(__name__)
+    : project-define constant-if call-in-project include-conanbuildinfo
+    : $(base-project-mod)
+    : project-define constant-if call-in-project include-conanbuildinfo ;
+
+if ! ( relwithdebinfo in [ feature.values variant ] )
+{
+    variant relwithdebinfo : : <optimization>speed <debug-symbols>on <inlining>full <runtime-debugging>off ;
+}
+if ! ( minsizerel in [ feature.values variant ] )
+{
+    variant minsizerel : : <optimization>space <debug-symbols>off <inlining>full <runtime-debugging>off ;
+}
+
+local __conanbuildinfo__ = [ GLOB $(__file__:D) : conanbuildinfo-*.jam : downcase ] ;
+{
+    local __define_constants__ = yes ;
+    for local __cbi__ in $(__conanbuildinfo__)
+    {
+        call-in-project : include-conanbuildinfo $(__cbi__) ;
+    }
+}
+
+
+# mypkg
+# mypkg
+project-define mypkg ;
+
+
+# mypkg2
+# mypkg2
+project-define mypkg2 ;
+
+{
+    local __define_targets__ = yes ;
+    for local __cbi__ in $(__conanbuildinfo__)
+    {
+        call-in-project : include-conanbuildinfo $(__cbi__) ;
+    }
+}
+''',
+'conanbuildinfo-316f2f0b155dc874a672d40d98d93f95.jam':
+'''#|
+    B2 definitions for Conan packages. This is a generated file.
+    Edit the corresponding conanfile.txt instead.
+|#
+
+# global
+constant-if rootpath(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    ""
+    ;
+
+constant-if includedirs(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "other/Path/with/slashes"
+    "other/regular/path/to/dir"
+    ;
+
+constant-if libdirs(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "Path/with/slashes"
+    "regular/path/to/dir"
+    ;
+
+constant-if defines(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "MYDEFINE2"
+    "MYDEFINE1"
+    ;
+
+constant-if cppflags(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "-cppflag"
+    ;
+
+constant-if cflags(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "-Flag1=23"
+    ;
+
+constant-if sharedlinkflags(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "-sharedlinkflag"
+    ;
+
+constant-if exelinkflags(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "-exelinkflag"
+    ;
+
+constant-if requirements(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    <address-model>32
+    <architecture>x86
+    <cxxstd>17
+    <cxxstd:dialect>gnu
+    <target-os>linux
+    <toolset>gcc-6.3
+    <variant>release
+    ;
+
+constant-if usage-requirements(conan,32,x86,17,gnu,linux,gcc-6.3,release) :
+    <include>$(includedirs(conan,32,x86,17,gnu,linux,gcc-6.3,release))
+    <define>$(defines(conan,32,x86,17,gnu,linux,gcc-6.3,release))
+    <cflags>$(cflags(conan,32,x86,17,gnu,linux,gcc-6.3,release))
+    <cxxflags>$(cppflags(conan,32,x86,17,gnu,linux,gcc-6.3,release))
+    <link>shared:<linkflags>$(sharedlinkflags(conan,32,x86,17,gnu,linux,gcc-6.3,release))
+    ;
+
+# mypkg
+constant-if rootpath(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "dummy_root_folder1"
+    ;
+
+constant-if defines(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "MYDEFINE1"
+    ;
+
+constant-if cflags(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "-Flag1=23"
+    ;
+
+constant-if requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) :
+    <address-model>32
+    <architecture>x86
+    <cxxstd>17
+    <cxxstd:dialect>gnu
+    <target-os>linux
+    <toolset>gcc-6.3
+    <variant>release
+    ;
+
+constant-if usage-requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release) :
+    <include>$(includedirs(mypkg,32,x86,17,gnu,linux,gcc-6.3,release))
+    <define>$(defines(mypkg,32,x86,17,gnu,linux,gcc-6.3,release))
+    <cflags>$(cflags(mypkg,32,x86,17,gnu,linux,gcc-6.3,release))
+    <cxxflags>$(cppflags(mypkg,32,x86,17,gnu,linux,gcc-6.3,release))
+    <link>shared:<linkflags>$(sharedlinkflags(mypkg,32,x86,17,gnu,linux,gcc-6.3,release))
+    ;
+
+# mypkg2
+constant-if rootpath(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "dummy_root_folder2"
+    ;
+
+constant-if includedirs(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "other/Path/with/slashes"
+    "other/regular/path/to/dir"
+    ;
+
+constant-if libdirs(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "Path/with/slashes"
+    "regular/path/to/dir"
+    ;
+
+constant-if defines(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "MYDEFINE2"
+    ;
+
+constant-if cppflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "-cppflag"
+    ;
+
+constant-if sharedlinkflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "-sharedlinkflag"
+    ;
+
+constant-if exelinkflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    "-exelinkflag"
+    ;
+
+constant-if requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    <address-model>32
+    <architecture>x86
+    <cxxstd>17
+    <cxxstd:dialect>gnu
+    <target-os>linux
+    <toolset>gcc-6.3
+    <variant>release
+    ;
+
+constant-if usage-requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release) :
+    <include>$(includedirs(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release))
+    <define>$(defines(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release))
+    <cflags>$(cflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release))
+    <cxxflags>$(cppflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release))
+    <link>shared:<linkflags>$(sharedlinkflags(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release))
+    ;
+
+# mypkg
+if $(__define_targets__) {
+    call-in-project $(mypkg-mod) : lib MyLib1
+        :
+        : <name>MyLib1 <search>$(libdirs(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) $(requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release))
+        :
+        : $(usage-requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) ;
+    call-in-project $(mypkg-mod) : explicit MyLib1 ; }
+
+if $(__define_targets__) {
+    call-in-project $(mypkg-mod) : alias libs
+        : MyLib1
+        : $(requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release))
+        :
+        : $(usage-requirements(mypkg,32,x86,17,gnu,linux,gcc-6.3,release)) ;
+    call-in-project $(mypkg-mod) : explicit libs ; }
+
+# mypkg2
+if $(__define_targets__) {
+    call-in-project $(mypkg2-mod) : lib MyLib2
+        :
+        : <name>MyLib2 <search>$(libdirs(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) $(requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release))
+        :
+        : $(usage-requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) ;
+    call-in-project $(mypkg2-mod) : explicit MyLib2 ; }
+
+if $(__define_targets__) {
+    call-in-project $(mypkg2-mod) : alias libs
+        : MyLib2
+        : $(requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release))
+        :
+        : $(usage-requirements(mypkg2,32,x86,17,gnu,linux,gcc-6.3,release)) ;
+    call-in-project $(mypkg2-mod) : explicit libs ; }
+''',
+        }
+
+        for ck, cv in generator.content.items():
+            self.assertEquals(cv, content[ck])
diff --git a/conans/test/model/ref_test.py b/conans/test/model/ref_test.py
index c74bdd3b2..0940e8edc 100644
--- a/conans/test/model/ref_test.py
+++ b/conans/test/model/ref_test.py
@@ -1,5 +1,5 @@
 import unittest
-from conans.model.ref import ConanFileReference
+from conans.model.ref import ConanFileReference, ConanName, InvalidNameException
 from conans.errors import ConanException
 
 
@@ -42,3 +42,38 @@ class RefTest(unittest.TestCase):
                           "opencv/2.4.10@laso%s/testing" % "A" * 40)
         self.assertRaises(ConanException, ConanFileReference.loads,
                           "opencv/2.4.10@laso/testing%s" % "A" * 40)
+
+
+class ConanNameTestCase(unittest.TestCase):
+
+    def _check_invalid_format(self, value, *args):
+        with self.assertRaisesRegexp(InvalidNameException, "Valid names"):
+            ConanName.validate_name(value, *args)
+
+    def _check_invalid_type(self, value):
+        with self.assertRaisesRegexp(InvalidNameException, "is not a string"):
+            ConanName.validate_name(value)
+
+    def validate_name_test(self):
+        self.assertIsNone(ConanName.validate_name("string.dot.under-score.123"))
+        self.assertIsNone(ConanName.validate_name("_underscore+123"))
+        self.assertIsNone(ConanName.validate_name("*"))
+        self.assertIsNone(ConanName.validate_name("a" * ConanName._min_chars))
+        self.assertIsNone(ConanName.validate_name("a" * ConanName._max_chars))
+        self.assertIsNone(ConanName.validate_name("a" * 50))  # Regression test
+
+    def validate_name_test_invalid_format(self):
+        self._check_invalid_format("-no.dash.start")
+        self._check_invalid_format("a" * (ConanName._min_chars - 1))
+        self._check_invalid_format("a" * (ConanName._max_chars + 1))
+
+    def validate_name_test_invalid_type(self):
+        self._check_invalid_type(123.34)
+        self._check_invalid_type(("item1", "item2",))
+
+    def validate_name_version_test(self):
+        self.assertIsNone(ConanName.validate_name("[vvvv]", version=True))
+
+    def validate_name_version_test_invalid(self):
+        self._check_invalid_format("[no.close.bracket", True)
+        self._check_invalid_format("no.open.bracket]", True)
diff --git a/conans/test/util/detected_architecture_test.py b/conans/test/util/detected_architecture_test.py
new file mode 100644
index 000000000..b8eb6c5f5
--- /dev/null
+++ b/conans/test/util/detected_architecture_test.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
+
+
+import unittest
+from mock import mock
+from conans.tools import detected_architecture
+
+
+class DetectedArchitectureTest(unittest.TestCase):
+
+    def test_various(self):
+
+        # x86
+        with mock.patch("platform.machine", mock.MagicMock(return_value='i386')):
+            self.assertEqual('x86', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='i686')):
+            self.assertEqual('x86', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='x86_64')):
+            self.assertEqual('x86_64', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='amd64')):
+            self.assertEqual('x86_64', detected_architecture())
+
+        # ARM
+        with mock.patch("platform.machine", mock.MagicMock(return_value='aarch64_be')):
+            self.assertEqual('armv8', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='armv8b')):
+            self.assertEqual('armv8', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='armv7l')):
+            self.assertEqual('armv7', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='armv6l')):
+            self.assertEqual('armv6', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='arm')):
+            self.assertEqual('armv6', detected_architecture())
+
+        # PowerPC
+        with mock.patch("platform.machine", mock.MagicMock(return_value='ppc64le')):
+            self.assertEqual('ppc64le', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='ppc64')):
+            self.assertEqual('ppc64', detected_architecture())
+
+        # MIPS
+        with mock.patch("platform.machine", mock.MagicMock(return_value='mips')):
+            self.assertEqual('mips', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='mips64')):
+            self.assertEqual('mips64', detected_architecture())
+
+        # SPARC
+        with mock.patch("platform.machine", mock.MagicMock(return_value='sparc')):
+            self.assertEqual('sparc', detected_architecture())
+
+        with mock.patch("platform.machine", mock.MagicMock(return_value='sparc64')):
+            self.assertEqual('sparcv9', detected_architecture())
diff --git a/conans/test/util/tools_test.py b/conans/test/util/tools_test.py
index 7b8f9e55d..dde6a8efe 100644
--- a/conans/test/util/tools_test.py
+++ b/conans/test/util/tools_test.py
@@ -163,7 +163,7 @@ class SystemPackageToolTest(unittest.TestCase):
 
             runner.return_ok = True
             spt.install("a_package", force=False)
-            self.assertEquals(runner.command_called, "dpkg -s a_package")
+            self.assertEquals(runner.command_called, 'dpkg-query -W -f=\'${Status}\' a_package | grep -q "ok installed"')
 
             os_info.is_macos = True
             os_info.is_linux = False
@@ -278,7 +278,7 @@ class SystemPackageToolTest(unittest.TestCase):
 
         packages = ["a_package", "another_package", "yet_another_package"]
         with tools.environment_append({"CONAN_SYSREQUIRES_SUDO": "True"}):
-            runner = RunnerMultipleMock(["dpkg -s another_package"])
+            runner = RunnerMultipleMock(['dpkg-query -W -f=\'${Status}\' another_package | grep -q "ok installed"'])
             spt = SystemPackageTool(runner=runner, tool=AptTool())
             spt.install(packages)
             self.assertEquals(2, runner.calls)
@@ -555,7 +555,7 @@ class HelloConan(ConanFile):
 
     def test_global_tools_overrided(self):
         client = TestClient()
-
+ 
         conanfile = """
 from conans import ConanFile, tools