We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
PROFILE_DIR with forward slashes
hi there,
I want to use the ```PROFILE_DIR``` variable in my profiles to access a path relative to the value of that variable. Now I do cross-compiling with a compiler that cannot parse backslashes.

An example yaml like this:
```yaml
[env]
ABC=$PROFILE_DIR/path/abc
```
will result in a malformed path as the compiler tries to interpret the slashes as excape characters:
compiler parsed: ... C:UsersNAME.conanprofiles/path/abc ...

Would it be possible to provide an POSIX style path (like PROFILE_DIR_POSIX)?

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `conans/client/profile_loader.py`
Content:
```
1 import os
2 from collections import OrderedDict, defaultdict
3 
4 from conans.errors import ConanException
5 from conans.model.env_info import EnvValues, unquote
6 from conans.model.options import OptionsValues
7 from conans.model.profile import Profile
8 from conans.model.ref import ConanFileReference
9 from conans.util.config_parser import ConfigParser
10 from conans.util.files import load, mkdir
11 from conans.util.log import logger
12 
13 
14 class ProfileParser(object):
15 
16     def __init__(self, text):
17         self.vars = OrderedDict()  # Order matters, if user declares F=1 and then FOO=12,
18         # and in profile MYVAR=$FOO, it will
19         self.includes = []
20         self.profile_text = ""
21 
22         for counter, line in enumerate(text.splitlines()):
23             if not line.strip() or line.strip().startswith("#"):
24                 continue
25             elif line.strip().startswith("["):
26                 self.profile_text = "\n".join(text.splitlines()[counter:])
27                 break
28             elif line.strip().startswith("include("):
29                 include = line.split("include(", 1)[1]
30                 if not include.endswith(")"):
31                     raise ConanException("Invalid include statement")
32                 include = include[:-1]
33                 self.includes.append(include)
34             else:
35                 name, value = line.split("=", 1)
36                 name = name.strip()
37                 if " " in name:
38                     raise ConanException("The names of the variables cannot contain spaces")
39                 value = unquote(value)
40                 self.vars[name] = value
41 
42     def apply_vars(self, repl_vars):
43         self.vars = self._apply_in_vars(repl_vars)
44         self.includes = self._apply_in_includes(repl_vars)
45         self.profile_text = self._apply_in_profile_text(repl_vars)
46 
47     def _apply_in_vars(self, repl_vars):
48         tmp_vars = OrderedDict()
49         for key, value in self.vars.items():
50             for repl_key, repl_value in repl_vars.items():
51                 key = key.replace("$%s" % repl_key, repl_value)
52                 value = value.replace("$%s" % repl_key, repl_value)
53             tmp_vars[key] = value
54         return tmp_vars
55 
56     def _apply_in_includes(self, repl_vars):
57         tmp_includes = []
58         for include in self.includes:
59             for repl_key, repl_value in repl_vars.items():
60                 include = include.replace("$%s" % repl_key, repl_value)
61             tmp_includes.append(include)
62         return tmp_includes
63 
64     def _apply_in_profile_text(self, repl_vars):
65         tmp_text = self.profile_text
66         for repl_key, repl_value in repl_vars.items():
67             tmp_text = tmp_text.replace("$%s" % repl_key, repl_value)
68         return tmp_text
69 
70 
71 def get_profile_path(profile_name, default_folder, cwd, exists=True):
72     def valid_path(profile_path):
73         if exists and not os.path.isfile(profile_path):
74             raise ConanException("Profile not found: %s" % profile_path)
75         return profile_path
76 
77     if os.path.isabs(profile_name):
78         return valid_path(profile_name)
79 
80     if profile_name[:2] in ("./", ".\\"):  # local
81         profile_path = os.path.abspath(os.path.join(cwd, profile_name))
82         return valid_path(profile_path)
83 
84     if not os.path.exists(default_folder):
85         mkdir(default_folder)
86     profile_path = os.path.join(default_folder, profile_name)
87     if exists:
88         if not os.path.isfile(profile_path):
89             profile_path = os.path.abspath(os.path.join(cwd, profile_name))
90         if not os.path.isfile(profile_path):
91             raise ConanException("Profile not found: %s" % profile_name)
92     return profile_path
93 
94 
95 def read_profile(profile_name, cwd, default_folder):
96     """ Will look for "profile_name" in disk if profile_name is absolute path,
97     in current folder if path is relative or in the default folder otherwise.
98     return: a Profile object
99     """
100     if not profile_name:
101         return None, None
102 
103     profile_path = get_profile_path(profile_name, default_folder, cwd)
104     logger.debug("PROFILE LOAD: %s" % profile_path)
105     text = load(profile_path)
106 
107     try:
108         return _load_profile(text, profile_path, default_folder)
109     except ConanException as exc:
110         raise ConanException("Error reading '%s' profile: %s" % (profile_name, exc))
111 
112 
113 def _load_profile(text, profile_path, default_folder):
114     """ Parse and return a Profile object from a text config like representation.
115         cwd is needed to be able to load the includes
116     """
117 
118     try:
119         inherited_profile = Profile()
120         cwd = os.path.dirname(os.path.abspath(profile_path)) if profile_path else None
121         profile_parser = ProfileParser(text)
122         inherited_vars = profile_parser.vars
123         # Iterate the includes and call recursive to get the profile and variables
124         # from parent profiles
125         for include in profile_parser.includes:
126             # Recursion !!
127             profile, declared_vars = read_profile(include, cwd, default_folder)
128             inherited_profile.update(profile)
129             inherited_vars.update(declared_vars)
130 
131         # Apply the automatic PROFILE_DIR variable
132         if cwd:
133             inherited_vars["PROFILE_DIR"] = os.path.abspath(cwd)
134             # Allows PYTHONPATH=$PROFILE_DIR/pythontools
135 
136         # Replace the variables from parents in the current profile
137         profile_parser.apply_vars(inherited_vars)
138 
139         # Current profile before update with parents (but parent variables already applied)
140         doc = ConfigParser(profile_parser.profile_text,
141                            allowed_fields=["build_requires", "settings", "env",
142                                            "scopes", "options"])
143 
144         # Merge the inherited profile with the readed from current profile
145         _apply_inner_profile(doc, inherited_profile)
146 
147         # Return the intherited vars to apply them in the parent profile if exists
148         inherited_vars.update(profile_parser.vars)
149         return inherited_profile, inherited_vars
150 
151     except ConanException:
152         raise
153     except Exception as exc:
154         raise ConanException("Error parsing the profile text file: %s" % str(exc))
155 
156 
157 def _load_single_build_require(profile, line):
158 
159     tokens = line.split(":", 1)
160     if len(tokens) == 1:
161         pattern, req_list = "*", line
162     else:
163         pattern, req_list = tokens
164     refs = [ConanFileReference.loads(reference.strip()) for reference in req_list.split(",")]
165     profile.build_requires.setdefault(pattern, []).extend(refs)
166 
167 
168 def _apply_inner_profile(doc, base_profile):
169     """
170 
171     :param doc: ConfigParser object from the current profile (excluding includes and vars,
172     and with values already replaced)
173     :param base_profile: Profile inherited, it's used as a base profile to modify it.
174     :return: None
175     """
176 
177     def get_package_name_value(item):
178         """Parse items like package:name=value or name=value"""
179         package_name = None
180         if ":" in item:
181             tmp = item.split(":", 1)
182             package_name, item = tmp
183 
184         name, value = item.split("=", 1)
185         name = name.strip()
186         value = unquote(value)
187         return package_name, name, value
188 
189     for setting in doc.settings.splitlines():
190         setting = setting.strip()
191         if setting and not setting.startswith("#"):
192             if "=" not in setting:
193                 raise ConanException("Invalid setting line '%s'" % setting)
194             package_name, name, value = get_package_name_value(setting)
195             if package_name:
196                 base_profile.package_settings[package_name][name] = value
197             else:
198                 base_profile.settings[name] = value
199 
200     if doc.build_requires:
201         # FIXME CHECKS OF DUPLICATED?
202         for req in doc.build_requires.splitlines():
203             _load_single_build_require(base_profile, req)
204 
205     if doc.options:
206         base_profile.options.update(OptionsValues.loads(doc.options))
207 
208     # The env vars from the current profile (read in doc)
209     # are updated with the included profiles (base_profile)
210     # the current env values has priority
211     current_env_values = EnvValues.loads(doc.env)
212     current_env_values.update(base_profile.env_values)
213     base_profile.env_values = current_env_values
214 
215 
216 def profile_from_args(profiles, settings, options, env, cwd, cache):
217     """ Return a Profile object, as the result of merging a potentially existing Profile
218     file and the args command-line arguments
219     """
220     default_profile = cache.default_profile  # Ensures a default profile creating
221 
222     if profiles is None:
223         result = default_profile
224     else:
225         result = Profile()
226         for p in profiles:
227             tmp, _ = read_profile(p, cwd, cache.profiles_path)
228             result.update(tmp)
229 
230     args_profile = _profile_parse_args(settings, options, env)
231 
232     if result:
233         result.update(args_profile)
234     else:
235         result = args_profile
236     return result
237 
238 
239 def _profile_parse_args(settings, options, envs):
240     """ return a Profile object result of parsing raw data
241     """
242     def _get_tuples_list_from_extender_arg(items):
243         if not items:
244             return []
245         # Validate the pairs
246         for item in items:
247             chunks = item.split("=", 1)
248             if len(chunks) != 2:
249                 raise ConanException("Invalid input '%s', use 'name=value'" % item)
250         return [(item[0], item[1]) for item in [item.split("=", 1) for item in items]]
251 
252     def _get_simple_and_package_tuples(items):
253         """Parse items like "thing:item=value or item2=value2 and returns a tuple list for
254         the simple items (name, value) and a dict for the package items
255         {package: [(item, value)...)], ...}
256         """
257         simple_items = []
258         package_items = defaultdict(list)
259         tuples = _get_tuples_list_from_extender_arg(items)
260         for name, value in tuples:
261             if ":" in name:  # Scoped items
262                 tmp = name.split(":", 1)
263                 ref_name = tmp[0]
264                 name = tmp[1]
265                 package_items[ref_name].append((name, value))
266             else:
267                 simple_items.append((name, value))
268         return simple_items, package_items
269 
270     def _get_env_values(env, package_env):
271         env_values = EnvValues()
272         for name, value in env:
273             env_values.add(name, EnvValues.load_value(value))
274         for package, data in package_env.items():
275             for name, value in data:
276                 env_values.add(name, EnvValues.load_value(value), package)
277         return env_values
278 
279     result = Profile()
280     options = _get_tuples_list_from_extender_arg(options)
281     result.options = OptionsValues(options)
282     env, package_env = _get_simple_and_package_tuples(envs)
283     env_values = _get_env_values(env, package_env)
284     result.env_values = env_values
285     settings, package_settings = _get_simple_and_package_tuples(settings)
286     result.settings = OrderedDict(settings)
287     for pkg, values in package_settings.items():
288         result.package_settings[pkg] = OrderedDict(values)
289     return result
290
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/conans/client/profile_loader.py b/conans/client/profile_loader.py
--- a/conans/client/profile_loader.py
+++ b/conans/client/profile_loader.py
@@ -130,7 +130,7 @@
 
         # Apply the automatic PROFILE_DIR variable
         if cwd:
-            inherited_vars["PROFILE_DIR"] = os.path.abspath(cwd)
+            inherited_vars["PROFILE_DIR"] = os.path.abspath(cwd).replace('\\', '/')
             # Allows PYTHONPATH=$PROFILE_DIR/pythontools
 
         # Replace the variables from parents in the current profile
@@ -144,7 +144,7 @@
         # Merge the inherited profile with the readed from current profile
         _apply_inner_profile(doc, inherited_profile)
 
-        # Return the intherited vars to apply them in the parent profile if exists
+        # Return the inherited vars to apply them in the parent profile if exists
         inherited_vars.update(profile_parser.vars)
         return inherited_profile, inherited_vars

{"golden_diff": "diff --git a/conans/client/profile_loader.py b/conans/client/profile_loader.py\n--- a/conans/client/profile_loader.py\n+++ b/conans/client/profile_loader.py\n@@ -130,7 +130,7 @@\n \n         # Apply the automatic PROFILE_DIR variable\n         if cwd:\n-            inherited_vars[\"PROFILE_DIR\"] = os.path.abspath(cwd)\n+            inherited_vars[\"PROFILE_DIR\"] = os.path.abspath(cwd).replace('\\\\', '/')\n             # Allows PYTHONPATH=$PROFILE_DIR/pythontools\n \n         # Replace the variables from parents in the current profile\n@@ -144,7 +144,7 @@\n         # Merge the inherited profile with the readed from current profile\n         _apply_inner_profile(doc, inherited_profile)\n \n-        # Return the intherited vars to apply them in the parent profile if exists\n+        # Return the inherited vars to apply them in the parent profile if exists\n         inherited_vars.update(profile_parser.vars)\n         return inherited_profile, inherited_vars\n", "issue": "PROFILE_DIR with forward slashes\nhi there,\r\nI want to use the ```PROFILE_DIR``` variable in my profiles to access a path relative to the value of that variable. Now I do cross-compiling with a compiler that cannot parse backslashes.\r\n\r\nAn example yaml like this:\r\n```yaml\r\n[env]\r\nABC=$PROFILE_DIR/path/abc\r\n```\r\nwill result in a malformed path as the compiler tries to interpret the slashes as excape characters:\r\ncompiler parsed: ... C:UsersNAME.conanprofiles/path/abc ...\r\n\r\nWould it be possible to provide an POSIX style path (like PROFILE_DIR_POSIX)?\n", "before_files": [{"content": "import os\nfrom collections import OrderedDict, defaultdict\n\nfrom conans.errors import ConanException\nfrom conans.model.env_info import EnvValues, unquote\nfrom conans.model.options import OptionsValues\nfrom conans.model.profile import Profile\nfrom conans.model.ref import ConanFileReference\nfrom conans.util.config_parser import ConfigParser\nfrom conans.util.files import load, mkdir\nfrom conans.util.log import logger\n\n\nclass ProfileParser(object):\n\n    def __init__(self, text):\n        self.vars = OrderedDict()  # Order matters, if user declares F=1 and then FOO=12,\n        # and in profile MYVAR=$FOO, it will\n        self.includes = []\n        self.profile_text = \"\"\n\n        for counter, line in enumerate(text.splitlines()):\n            if not line.strip() or line.strip().startswith(\"#\"):\n                continue\n            elif line.strip().startswith(\"[\"):\n                self.profile_text = \"\\n\".join(text.splitlines()[counter:])\n                break\n            elif line.strip().startswith(\"include(\"):\n                include = line.split(\"include(\", 1)[1]\n                if not include.endswith(\")\"):\n                    raise ConanException(\"Invalid include statement\")\n                include = include[:-1]\n                self.includes.append(include)\n            else:\n                name, value = line.split(\"=\", 1)\n                name = name.strip()\n                if \" \" in name:\n                    raise ConanException(\"The names of the variables cannot contain spaces\")\n                value = unquote(value)\n                self.vars[name] = value\n\n    def apply_vars(self, repl_vars):\n        self.vars = self._apply_in_vars(repl_vars)\n        self.includes = self._apply_in_includes(repl_vars)\n        self.profile_text = self._apply_in_profile_text(repl_vars)\n\n    def _apply_in_vars(self, repl_vars):\n        tmp_vars = OrderedDict()\n        for key, value in self.vars.items():\n            for repl_key, repl_value in repl_vars.items():\n                key = key.replace(\"$%s\" % repl_key, repl_value)\n                value = value.replace(\"$%s\" % repl_key, repl_value)\n            tmp_vars[key] = value\n        return tmp_vars\n\n    def _apply_in_includes(self, repl_vars):\n        tmp_includes = []\n        for include in self.includes:\n            for repl_key, repl_value in repl_vars.items():\n                include = include.replace(\"$%s\" % repl_key, repl_value)\n            tmp_includes.append(include)\n        return tmp_includes\n\n    def _apply_in_profile_text(self, repl_vars):\n        tmp_text = self.profile_text\n        for repl_key, repl_value in repl_vars.items():\n            tmp_text = tmp_text.replace(\"$%s\" % repl_key, repl_value)\n        return tmp_text\n\n\ndef get_profile_path(profile_name, default_folder, cwd, exists=True):\n    def valid_path(profile_path):\n        if exists and not os.path.isfile(profile_path):\n            raise ConanException(\"Profile not found: %s\" % profile_path)\n        return profile_path\n\n    if os.path.isabs(profile_name):\n        return valid_path(profile_name)\n\n    if profile_name[:2] in (\"./\", \".\\\\\"):  # local\n        profile_path = os.path.abspath(os.path.join(cwd, profile_name))\n        return valid_path(profile_path)\n\n    if not os.path.exists(default_folder):\n        mkdir(default_folder)\n    profile_path = os.path.join(default_folder, profile_name)\n    if exists:\n        if not os.path.isfile(profile_path):\n            profile_path = os.path.abspath(os.path.join(cwd, profile_name))\n        if not os.path.isfile(profile_path):\n            raise ConanException(\"Profile not found: %s\" % profile_name)\n    return profile_path\n\n\ndef read_profile(profile_name, cwd, default_folder):\n    \"\"\" Will look for \"profile_name\" in disk if profile_name is absolute path,\n    in current folder if path is relative or in the default folder otherwise.\n    return: a Profile object\n    \"\"\"\n    if not profile_name:\n        return None, None\n\n    profile_path = get_profile_path(profile_name, default_folder, cwd)\n    logger.debug(\"PROFILE LOAD: %s\" % profile_path)\n    text = load(profile_path)\n\n    try:\n        return _load_profile(text, profile_path, default_folder)\n    except ConanException as exc:\n        raise ConanException(\"Error reading '%s' profile: %s\" % (profile_name, exc))\n\n\ndef _load_profile(text, profile_path, default_folder):\n    \"\"\" Parse and return a Profile object from a text config like representation.\n        cwd is needed to be able to load the includes\n    \"\"\"\n\n    try:\n        inherited_profile = Profile()\n        cwd = os.path.dirname(os.path.abspath(profile_path)) if profile_path else None\n        profile_parser = ProfileParser(text)\n        inherited_vars = profile_parser.vars\n        # Iterate the includes and call recursive to get the profile and variables\n        # from parent profiles\n        for include in profile_parser.includes:\n            # Recursion !!\n            profile, declared_vars = read_profile(include, cwd, default_folder)\n            inherited_profile.update(profile)\n            inherited_vars.update(declared_vars)\n\n        # Apply the automatic PROFILE_DIR variable\n        if cwd:\n            inherited_vars[\"PROFILE_DIR\"] = os.path.abspath(cwd)\n            # Allows PYTHONPATH=$PROFILE_DIR/pythontools\n\n        # Replace the variables from parents in the current profile\n        profile_parser.apply_vars(inherited_vars)\n\n        # Current profile before update with parents (but parent variables already applied)\n        doc = ConfigParser(profile_parser.profile_text,\n                           allowed_fields=[\"build_requires\", \"settings\", \"env\",\n                                           \"scopes\", \"options\"])\n\n        # Merge the inherited profile with the readed from current profile\n        _apply_inner_profile(doc, inherited_profile)\n\n        # Return the intherited vars to apply them in the parent profile if exists\n        inherited_vars.update(profile_parser.vars)\n        return inherited_profile, inherited_vars\n\n    except ConanException:\n        raise\n    except Exception as exc:\n        raise ConanException(\"Error parsing the profile text file: %s\" % str(exc))\n\n\ndef _load_single_build_require(profile, line):\n\n    tokens = line.split(\":\", 1)\n    if len(tokens) == 1:\n        pattern, req_list = \"*\", line\n    else:\n        pattern, req_list = tokens\n    refs = [ConanFileReference.loads(reference.strip()) for reference in req_list.split(\",\")]\n    profile.build_requires.setdefault(pattern, []).extend(refs)\n\n\ndef _apply_inner_profile(doc, base_profile):\n    \"\"\"\n\n    :param doc: ConfigParser object from the current profile (excluding includes and vars,\n    and with values already replaced)\n    :param base_profile: Profile inherited, it's used as a base profile to modify it.\n    :return: None\n    \"\"\"\n\n    def get_package_name_value(item):\n        \"\"\"Parse items like package:name=value or name=value\"\"\"\n        package_name = None\n        if \":\" in item:\n            tmp = item.split(\":\", 1)\n            package_name, item = tmp\n\n        name, value = item.split(\"=\", 1)\n        name = name.strip()\n        value = unquote(value)\n        return package_name, name, value\n\n    for setting in doc.settings.splitlines():\n        setting = setting.strip()\n        if setting and not setting.startswith(\"#\"):\n            if \"=\" not in setting:\n                raise ConanException(\"Invalid setting line '%s'\" % setting)\n            package_name, name, value = get_package_name_value(setting)\n            if package_name:\n                base_profile.package_settings[package_name][name] = value\n            else:\n                base_profile.settings[name] = value\n\n    if doc.build_requires:\n        # FIXME CHECKS OF DUPLICATED?\n        for req in doc.build_requires.splitlines():\n            _load_single_build_require(base_profile, req)\n\n    if doc.options:\n        base_profile.options.update(OptionsValues.loads(doc.options))\n\n    # The env vars from the current profile (read in doc)\n    # are updated with the included profiles (base_profile)\n    # the current env values has priority\n    current_env_values = EnvValues.loads(doc.env)\n    current_env_values.update(base_profile.env_values)\n    base_profile.env_values = current_env_values\n\n\ndef profile_from_args(profiles, settings, options, env, cwd, cache):\n    \"\"\" Return a Profile object, as the result of merging a potentially existing Profile\n    file and the args command-line arguments\n    \"\"\"\n    default_profile = cache.default_profile  # Ensures a default profile creating\n\n    if profiles is None:\n        result = default_profile\n    else:\n        result = Profile()\n        for p in profiles:\n            tmp, _ = read_profile(p, cwd, cache.profiles_path)\n            result.update(tmp)\n\n    args_profile = _profile_parse_args(settings, options, env)\n\n    if result:\n        result.update(args_profile)\n    else:\n        result = args_profile\n    return result\n\n\ndef _profile_parse_args(settings, options, envs):\n    \"\"\" return a Profile object result of parsing raw data\n    \"\"\"\n    def _get_tuples_list_from_extender_arg(items):\n        if not items:\n            return []\n        # Validate the pairs\n        for item in items:\n            chunks = item.split(\"=\", 1)\n            if len(chunks) != 2:\n                raise ConanException(\"Invalid input '%s', use 'name=value'\" % item)\n        return [(item[0], item[1]) for item in [item.split(\"=\", 1) for item in items]]\n\n    def _get_simple_and_package_tuples(items):\n        \"\"\"Parse items like \"thing:item=value or item2=value2 and returns a tuple list for\n        the simple items (name, value) and a dict for the package items\n        {package: [(item, value)...)], ...}\n        \"\"\"\n        simple_items = []\n        package_items = defaultdict(list)\n        tuples = _get_tuples_list_from_extender_arg(items)\n        for name, value in tuples:\n            if \":\" in name:  # Scoped items\n                tmp = name.split(\":\", 1)\n                ref_name = tmp[0]\n                name = tmp[1]\n                package_items[ref_name].append((name, value))\n            else:\n                simple_items.append((name, value))\n        return simple_items, package_items\n\n    def _get_env_values(env, package_env):\n        env_values = EnvValues()\n        for name, value in env:\n            env_values.add(name, EnvValues.load_value(value))\n        for package, data in package_env.items():\n            for name, value in data:\n                env_values.add(name, EnvValues.load_value(value), package)\n        return env_values\n\n    result = Profile()\n    options = _get_tuples_list_from_extender_arg(options)\n    result.options = OptionsValues(options)\n    env, package_env = _get_simple_and_package_tuples(envs)\n    env_values = _get_env_values(env, package_env)\n    result.env_values = env_values\n    settings, package_settings = _get_simple_and_package_tuples(settings)\n    result.settings = OrderedDict(settings)\n    for pkg, values in package_settings.items():\n        result.package_settings[pkg] = OrderedDict(values)\n    return result\n", "path": "conans/client/profile_loader.py"}], "after_files": [{"content": "import os\nfrom collections import OrderedDict, defaultdict\n\nfrom conans.errors import ConanException\nfrom conans.model.env_info import EnvValues, unquote\nfrom conans.model.options import OptionsValues\nfrom conans.model.profile import Profile\nfrom conans.model.ref import ConanFileReference\nfrom conans.util.config_parser import ConfigParser\nfrom conans.util.files import load, mkdir\nfrom conans.util.log import logger\n\n\nclass ProfileParser(object):\n\n    def __init__(self, text):\n        self.vars = OrderedDict()  # Order matters, if user declares F=1 and then FOO=12,\n        # and in profile MYVAR=$FOO, it will\n        self.includes = []\n        self.profile_text = \"\"\n\n        for counter, line in enumerate(text.splitlines()):\n            if not line.strip() or line.strip().startswith(\"#\"):\n                continue\n            elif line.strip().startswith(\"[\"):\n                self.profile_text = \"\\n\".join(text.splitlines()[counter:])\n                break\n            elif line.strip().startswith(\"include(\"):\n                include = line.split(\"include(\", 1)[1]\n                if not include.endswith(\")\"):\n                    raise ConanException(\"Invalid include statement\")\n                include = include[:-1]\n                self.includes.append(include)\n            else:\n                name, value = line.split(\"=\", 1)\n                name = name.strip()\n                if \" \" in name:\n                    raise ConanException(\"The names of the variables cannot contain spaces\")\n                value = unquote(value)\n                self.vars[name] = value\n\n    def apply_vars(self, repl_vars):\n        self.vars = self._apply_in_vars(repl_vars)\n        self.includes = self._apply_in_includes(repl_vars)\n        self.profile_text = self._apply_in_profile_text(repl_vars)\n\n    def _apply_in_vars(self, repl_vars):\n        tmp_vars = OrderedDict()\n        for key, value in self.vars.items():\n            for repl_key, repl_value in repl_vars.items():\n                key = key.replace(\"$%s\" % repl_key, repl_value)\n                value = value.replace(\"$%s\" % repl_key, repl_value)\n            tmp_vars[key] = value\n        return tmp_vars\n\n    def _apply_in_includes(self, repl_vars):\n        tmp_includes = []\n        for include in self.includes:\n            for repl_key, repl_value in repl_vars.items():\n                include = include.replace(\"$%s\" % repl_key, repl_value)\n            tmp_includes.append(include)\n        return tmp_includes\n\n    def _apply_in_profile_text(self, repl_vars):\n        tmp_text = self.profile_text\n        for repl_key, repl_value in repl_vars.items():\n            tmp_text = tmp_text.replace(\"$%s\" % repl_key, repl_value)\n        return tmp_text\n\n\ndef get_profile_path(profile_name, default_folder, cwd, exists=True):\n    def valid_path(profile_path):\n        if exists and not os.path.isfile(profile_path):\n            raise ConanException(\"Profile not found: %s\" % profile_path)\n        return profile_path\n\n    if os.path.isabs(profile_name):\n        return valid_path(profile_name)\n\n    if profile_name[:2] in (\"./\", \".\\\\\"):  # local\n        profile_path = os.path.abspath(os.path.join(cwd, profile_name))\n        return valid_path(profile_path)\n\n    if not os.path.exists(default_folder):\n        mkdir(default_folder)\n    profile_path = os.path.join(default_folder, profile_name)\n    if exists:\n        if not os.path.isfile(profile_path):\n            profile_path = os.path.abspath(os.path.join(cwd, profile_name))\n        if not os.path.isfile(profile_path):\n            raise ConanException(\"Profile not found: %s\" % profile_name)\n    return profile_path\n\n\ndef read_profile(profile_name, cwd, default_folder):\n    \"\"\" Will look for \"profile_name\" in disk if profile_name is absolute path,\n    in current folder if path is relative or in the default folder otherwise.\n    return: a Profile object\n    \"\"\"\n    if not profile_name:\n        return None, None\n\n    profile_path = get_profile_path(profile_name, default_folder, cwd)\n    logger.debug(\"PROFILE LOAD: %s\" % profile_path)\n    text = load(profile_path)\n\n    try:\n        return _load_profile(text, profile_path, default_folder)\n    except ConanException as exc:\n        raise ConanException(\"Error reading '%s' profile: %s\" % (profile_name, exc))\n\n\ndef _load_profile(text, profile_path, default_folder):\n    \"\"\" Parse and return a Profile object from a text config like representation.\n        cwd is needed to be able to load the includes\n    \"\"\"\n\n    try:\n        inherited_profile = Profile()\n        cwd = os.path.dirname(os.path.abspath(profile_path)) if profile_path else None\n        profile_parser = ProfileParser(text)\n        inherited_vars = profile_parser.vars\n        # Iterate the includes and call recursive to get the profile and variables\n        # from parent profiles\n        for include in profile_parser.includes:\n            # Recursion !!\n            profile, declared_vars = read_profile(include, cwd, default_folder)\n            inherited_profile.update(profile)\n            inherited_vars.update(declared_vars)\n\n        # Apply the automatic PROFILE_DIR variable\n        if cwd:\n            inherited_vars[\"PROFILE_DIR\"] = os.path.abspath(cwd).replace('\\\\', '/')\n            # Allows PYTHONPATH=$PROFILE_DIR/pythontools\n\n        # Replace the variables from parents in the current profile\n        profile_parser.apply_vars(inherited_vars)\n\n        # Current profile before update with parents (but parent variables already applied)\n        doc = ConfigParser(profile_parser.profile_text,\n                           allowed_fields=[\"build_requires\", \"settings\", \"env\",\n                                           \"scopes\", \"options\"])\n\n        # Merge the inherited profile with the readed from current profile\n        _apply_inner_profile(doc, inherited_profile)\n\n        # Return the inherited vars to apply them in the parent profile if exists\n        inherited_vars.update(profile_parser.vars)\n        return inherited_profile, inherited_vars\n\n    except ConanException:\n        raise\n    except Exception as exc:\n        raise ConanException(\"Error parsing the profile text file: %s\" % str(exc))\n\n\ndef _load_single_build_require(profile, line):\n\n    tokens = line.split(\":\", 1)\n    if len(tokens) == 1:\n        pattern, req_list = \"*\", line\n    else:\n        pattern, req_list = tokens\n    refs = [ConanFileReference.loads(reference.strip()) for reference in req_list.split(\",\")]\n    profile.build_requires.setdefault(pattern, []).extend(refs)\n\n\ndef _apply_inner_profile(doc, base_profile):\n    \"\"\"\n\n    :param doc: ConfigParser object from the current profile (excluding includes and vars,\n    and with values already replaced)\n    :param base_profile: Profile inherited, it's used as a base profile to modify it.\n    :return: None\n    \"\"\"\n\n    def get_package_name_value(item):\n        \"\"\"Parse items like package:name=value or name=value\"\"\"\n        package_name = None\n        if \":\" in item:\n            tmp = item.split(\":\", 1)\n            package_name, item = tmp\n\n        name, value = item.split(\"=\", 1)\n        name = name.strip()\n        value = unquote(value)\n        return package_name, name, value\n\n    for setting in doc.settings.splitlines():\n        setting = setting.strip()\n        if setting and not setting.startswith(\"#\"):\n            if \"=\" not in setting:\n                raise ConanException(\"Invalid setting line '%s'\" % setting)\n            package_name, name, value = get_package_name_value(setting)\n            if package_name:\n                base_profile.package_settings[package_name][name] = value\n            else:\n                base_profile.settings[name] = value\n\n    if doc.build_requires:\n        # FIXME CHECKS OF DUPLICATED?\n        for req in doc.build_requires.splitlines():\n            _load_single_build_require(base_profile, req)\n\n    if doc.options:\n        base_profile.options.update(OptionsValues.loads(doc.options))\n\n    # The env vars from the current profile (read in doc)\n    # are updated with the included profiles (base_profile)\n    # the current env values has priority\n    current_env_values = EnvValues.loads(doc.env)\n    current_env_values.update(base_profile.env_values)\n    base_profile.env_values = current_env_values\n\n\ndef profile_from_args(profiles, settings, options, env, cwd, cache):\n    \"\"\" Return a Profile object, as the result of merging a potentially existing Profile\n    file and the args command-line arguments\n    \"\"\"\n    default_profile = cache.default_profile  # Ensures a default profile creating\n\n    if profiles is None:\n        result = default_profile\n    else:\n        result = Profile()\n        for p in profiles:\n            tmp, _ = read_profile(p, cwd, cache.profiles_path)\n            result.update(tmp)\n\n    args_profile = _profile_parse_args(settings, options, env)\n\n    if result:\n        result.update(args_profile)\n    else:\n        result = args_profile\n    return result\n\n\ndef _profile_parse_args(settings, options, envs):\n    \"\"\" return a Profile object result of parsing raw data\n    \"\"\"\n    def _get_tuples_list_from_extender_arg(items):\n        if not items:\n            return []\n        # Validate the pairs\n        for item in items:\n            chunks = item.split(\"=\", 1)\n            if len(chunks) != 2:\n                raise ConanException(\"Invalid input '%s', use 'name=value'\" % item)\n        return [(item[0], item[1]) for item in [item.split(\"=\", 1) for item in items]]\n\n    def _get_simple_and_package_tuples(items):\n        \"\"\"Parse items like \"thing:item=value or item2=value2 and returns a tuple list for\n        the simple items (name, value) and a dict for the package items\n        {package: [(item, value)...)], ...}\n        \"\"\"\n        simple_items = []\n        package_items = defaultdict(list)\n        tuples = _get_tuples_list_from_extender_arg(items)\n        for name, value in tuples:\n            if \":\" in name:  # Scoped items\n                tmp = name.split(\":\", 1)\n                ref_name = tmp[0]\n                name = tmp[1]\n                package_items[ref_name].append((name, value))\n            else:\n                simple_items.append((name, value))\n        return simple_items, package_items\n\n    def _get_env_values(env, package_env):\n        env_values = EnvValues()\n        for name, value in env:\n            env_values.add(name, EnvValues.load_value(value))\n        for package, data in package_env.items():\n            for name, value in data:\n                env_values.add(name, EnvValues.load_value(value), package)\n        return env_values\n\n    result = Profile()\n    options = _get_tuples_list_from_extender_arg(options)\n    result.options = OptionsValues(options)\n    env, package_env = _get_simple_and_package_tuples(envs)\n    env_values = _get_env_values(env, package_env)\n    result.env_values = env_values\n    settings, package_settings = _get_simple_and_package_tuples(settings)\n    result.settings = OrderedDict(settings)\n    for pkg, values in package_settings.items():\n        result.package_settings[pkg] = OrderedDict(values)\n    return result\n", "path": "conans/client/profile_loader.py"}]}