We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
imports/copy question
Suppose I have
```
x86
  vc15
    bin
      opencv_core310.dll 
      ...
```
directory structure in my package. Is it possible to import `opencv_core310.dll` and friends to project's `bin` folder forgetting all the directory structure? I tried
```python
def imports(self):
   self.copy("*.dll", "", "bin")
```
but it creates `x86/vc15/bin/opencv_core310.dll` while I would like to get `bin/opencv_core310.dll`
Probably  import/copy should have `keep_path` parameter like package/copy does?



--- 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/importer.py`
Content:
```
1 import calendar
2 import fnmatch
3 import os
4 import time
5 
6 from conans import tools
7 from conans.client.file_copier import FileCopier, report_copied_files
8 from conans.client.output import ScopedOutput
9 from conans.errors import ConanException
10 from conans.model.conan_file import get_env_context_manager
11 from conans.model.manifest import FileTreeManifest
12 from conans.util.files import save, md5sum, load
13 
14 IMPORTS_MANIFESTS = "conan_imports_manifest.txt"
15 
16 
17 def undo_imports(current_path, output):
18     manifest_path = os.path.join(current_path, IMPORTS_MANIFESTS)
19     try:
20         manifest_content = load(manifest_path)
21     except:
22         raise ConanException("Cannot load file %s" % manifest_path)
23 
24     try:
25         manifest = FileTreeManifest.loads(manifest_content)
26     except:
27         raise ConanException("Wrong manifest file format %s" % manifest_path)
28 
29     not_removed = 0
30     files = manifest.files()
31     for filepath in files:
32         if not os.path.exists(filepath):
33             output.warn("File doesn't exist: %s" % filepath)
34             continue
35         try:
36             os.remove(filepath)
37         except:
38             output.error("Cannot remove file (open or busy): %s" % filepath)
39             not_removed += 1
40 
41     if not_removed:
42         raise ConanException("Cannot remove %s or more imported files" % not_removed)
43 
44     output.success("Removed %s imported files" % (len(files)))
45     try:
46         os.remove(manifest_path)
47         output.success("Removed imports manifest file: %s" % manifest_path)
48     except:
49         raise ConanException("Cannot remove manifest file (open or busy): %s" % manifest_path)
50 
51 
52 def _report_save_manifest(copied_files, output, dest_folder, manifest_name):
53     report_copied_files(copied_files, output)
54     if copied_files:
55         date = calendar.timegm(time.gmtime())
56         file_dict = {}
57         for f in copied_files:
58             abs_path = os.path.join(dest_folder, f)
59             file_dict[f] = md5sum(abs_path)
60         manifest = FileTreeManifest(date, file_dict)
61         save(os.path.join(dest_folder, manifest_name), str(manifest))
62 
63 
64 def run_imports(conanfile, dest_folder, output):
65     if not hasattr(conanfile, "imports"):
66         return []
67     file_importer = _FileImporter(conanfile, dest_folder)
68     conanfile.copy = file_importer
69     conanfile.imports_folder = dest_folder
70     with get_env_context_manager(conanfile):
71         with tools.chdir(dest_folder):
72             conanfile.imports()
73     copied_files = file_importer.copied_files
74     import_output = ScopedOutput("%s imports()" % output.scope, output)
75     _report_save_manifest(copied_files, import_output, dest_folder, IMPORTS_MANIFESTS)
76     return copied_files
77 
78 
79 def run_deploy(conanfile, install_folder, output):
80     deploy_output = ScopedOutput("%s deploy()" % output.scope, output)
81     file_importer = _FileImporter(conanfile, install_folder)
82     package_copied = set()
83 
84     # This is necessary to capture FileCopier full destination paths
85     # Maybe could be improved in FileCopier
86     def file_copier(*args, **kwargs):
87         file_copy = FileCopier(conanfile.package_folder, install_folder)
88         copied = file_copy(*args, **kwargs)
89         package_copied.update(copied)
90 
91     conanfile.copy_deps = file_importer
92     conanfile.copy = file_copier
93     conanfile.install_folder = install_folder
94     with get_env_context_manager(conanfile):
95         with tools.chdir(install_folder):
96             conanfile.deploy()
97 
98     copied_files = file_importer.copied_files
99     copied_files.update(package_copied)
100     _report_save_manifest(copied_files, deploy_output, install_folder, "deploy_manifest.txt")
101 
102 
103 class _FileImporter(object):
104     """ manages the copy of files, resources, libs from the local store to the user
105     space. E.g.: shared libs, dlls, they will be in the package folder of your
106     configuration in the store. But you dont want to add every package to the
107     system PATH. Those shared libs can be copied to the user folder, close to
108     the exes where they can be found without modifying the path.
109     Useful also for copying other resources as images or data files.
110     It can be also used for Golang projects, in which the packages are always
111     source based and need to be copied to the user folder to be built
112     """
113     def __init__(self, conanfile, dst_folder):
114         self._conanfile = conanfile
115         self._dst_folder = dst_folder
116         self.copied_files = set()
117 
118     def __call__(self, pattern, dst="", src="", root_package=None, folder=False,
119                  ignore_case=False, excludes=None):
120         """
121         param pattern: an fnmatch file pattern of the files that should be copied. Eg. *.dll
122         param dst: the destination local folder, wrt to current conanfile dir, to which
123                    the files will be copied. Eg: "bin"
124         param src: the source folder in which those files will be searched. This folder
125                    will be stripped from the dst name. Eg.: lib/Debug/x86
126         param root_package: fnmatch pattern of the package name ("OpenCV", "Boost") from
127                             which files will be copied. Default: all packages in deps
128         """
129         if os.path.isabs(dst):
130             real_dst_folder = dst
131         else:
132             real_dst_folder = os.path.normpath(os.path.join(self._dst_folder, dst))
133 
134         matching_paths = self._get_folders(root_package)
135         for name, matching_path in matching_paths.items():
136             final_dst_path = os.path.join(real_dst_folder, name) if folder else real_dst_folder
137             file_copier = FileCopier(matching_path, final_dst_path)
138             files = file_copier(pattern, src=src, links=True, ignore_case=ignore_case,
139                                 excludes=excludes)
140             self.copied_files.update(files)
141 
142     def _get_folders(self, pattern):
143         """ given the current deps graph, compute a dict {name: store-path} of
144         each dependency
145         """
146         if not pattern:
147             return {pkg: cpp_info.rootpath for pkg, cpp_info in self._conanfile.deps_cpp_info.dependencies}
148         return {pkg: cpp_info.rootpath for pkg, cpp_info in self._conanfile.deps_cpp_info.dependencies
149                 if fnmatch.fnmatch(pkg, pattern)}
150
```

Path: `conans/client/loader_parse.py`
Content:
```
1 import imp
2 import inspect
3 import os
4 import sys
5 import uuid
6 
7 from conans.errors import ConanException, NotFoundException
8 from conans.model.conan_file import ConanFile
9 from conans.util.config_parser import ConfigParser
10 from conans.tools import chdir
11 from conans.client.generators import registered_generators
12 from conans.model import Generator
13 
14 
15 def load_conanfile_class(conanfile_path):
16     loaded, filename = _parse_file(conanfile_path)
17     try:
18         return _parse_module(loaded, filename)
19     except Exception as e:  # re-raise with file name
20         raise ConanException("%s: %s" % (conanfile_path, str(e)))
21 
22 
23 def _parse_module(conanfile_module, filename):
24     """ Parses a python in-memory module, to extract the classes, mainly the main
25     class defining the Recipe, but also process possible existing generators
26     @param conanfile_module: the module to be processed
27     @param consumer: if this is a root node in the hierarchy, the consumer project
28     @return: the main ConanFile class from the module
29     """
30     result = None
31     for name, attr in conanfile_module.__dict__.items():
32         if name[0] == "_":
33             continue
34         if (inspect.isclass(attr) and issubclass(attr, ConanFile) and attr != ConanFile and
35                 attr.__dict__["__module__"] == filename):
36             if result is None:
37                 result = attr
38             else:
39                 raise ConanException("More than 1 conanfile in the file")
40         if (inspect.isclass(attr) and issubclass(attr, Generator) and attr != Generator and
41                 attr.__dict__["__module__"] == filename):
42             registered_generators.add(attr.__name__, attr)
43 
44     if result is None:
45         raise ConanException("No subclass of ConanFile")
46 
47     return result
48 
49 
50 def _parse_file(conan_file_path):
51     """ From a given path, obtain the in memory python import module
52     """
53 
54     if not os.path.exists(conan_file_path):
55         raise NotFoundException("%s not found!" % conan_file_path)
56 
57     filename = os.path.splitext(os.path.basename(conan_file_path))[0]
58 
59     try:
60         current_dir = os.path.dirname(conan_file_path)
61         sys.path.append(current_dir)
62         old_modules = list(sys.modules.keys())
63         with chdir(current_dir):
64             sys.dont_write_bytecode = True
65             loaded = imp.load_source(filename, conan_file_path)
66             sys.dont_write_bytecode = False
67         # Put all imported files under a new package name
68         module_id = uuid.uuid1()
69         added_modules = set(sys.modules).difference(old_modules)
70         for added in added_modules:
71             module = sys.modules[added]
72             if module:
73                 try:
74                     folder = os.path.dirname(module.__file__)
75                 except AttributeError:  # some module doesn't have __file__
76                     pass
77                 else:
78                     if folder.startswith(current_dir):
79                         module = sys.modules.pop(added)
80                         sys.modules["%s.%s" % (module_id, added)] = module
81     except Exception:
82         import traceback
83         trace = traceback.format_exc().split('\n')
84         raise ConanException("Unable to load conanfile in %s\n%s" % (conan_file_path,
85                                                                      '\n'.join(trace[3:])))
86     finally:
87         sys.path.pop()
88 
89     return loaded, filename
90 
91 
92 class ConanFileTextLoader(object):
93     """Parse a conanfile.txt file"""
94 
95     def __init__(self, input_text):
96         # Prefer composition over inheritance, the __getattr__ was breaking things
97         self._config_parser = ConfigParser(input_text,  ["requires", "generators", "options",
98                                                          "imports"], parse_lines=True)
99 
100     @property
101     def requirements(self):
102         """returns a list of requires
103         EX:  "OpenCV/2.4.10@phil/stable"
104         """
105         return [r.strip() for r in self._config_parser.requires.splitlines()]
106 
107     @property
108     def options(self):
109         return self._config_parser.options
110 
111     @property
112     def _import_parameters(self):
113         def _parse_args(param_string):
114             root_package, ignore_case, folder, excludes = None, False, False, None
115             params = param_string.split(",")
116             params = [p.split("=") for p in params if p]
117             for (var, value) in params:
118                 var = var.strip()
119                 value = value.strip()
120                 if var == "root_package":
121                     root_package = value
122                 elif var == "ignore_case":
123                     ignore_case = (value.lower() == "true")
124                 elif var == "folder":
125                     folder = (value.lower() == "true")
126                 elif var == "excludes":
127                     excludes = value.split()
128                 else:
129                     raise Exception("Invalid imports. Unknown argument %s" % var)
130             return root_package, ignore_case, folder, excludes
131 
132         def _parse_import(line):
133             pair = line.split("->")
134             source = pair[0].strip().split(',', 1)
135             dest = pair[1].strip()
136             src, pattern = source[0].strip(), source[1].strip()
137             return pattern, dest, src
138 
139         ret = []
140         local_install_text = self._config_parser.imports
141         for line in local_install_text.splitlines():
142             # discard blanks, comments, and discard trailing comments
143             line = line.strip()
144             if not line or line.startswith("#"):
145                 continue
146             line = line.split("#", 1)[0]
147 
148             invalid_line_msg = "Invalid imports line: %s\nEX: OpenCV/lib, * -> ./lib" % line
149             if line.startswith("/") or line.startswith(".."):
150                 raise ConanException("%s\n%s" % (invalid_line_msg,
151                                                  "Import's paths can't begin with '/' or '..'"))
152             try:
153                 tokens = line.split("@", 1)
154                 if len(tokens) > 1:
155                     line = tokens[0]
156                     params = tokens[1]
157                 else:
158                     params = ""
159                 root_package, ignore_case, folder, excludes = _parse_args(params)
160                 pattern, dest, src = _parse_import(line)
161                 ret.append((pattern, dest, src, root_package, folder, ignore_case, excludes))
162             except Exception as e:
163                 raise ConanException("%s\n%s" % (invalid_line_msg, str(e)))
164         return ret
165 
166     @property
167     def generators(self):
168         return self._config_parser.generators.splitlines()
169 
170     def imports_method(self, conan_file):
171         parameters = self._import_parameters
172 
173         def imports():
174             for import_params in parameters:
175                 conan_file.copy(*import_params)
176         return imports
177
```
--- 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/importer.py b/conans/client/importer.py
--- a/conans/client/importer.py
+++ b/conans/client/importer.py
@@ -116,7 +116,7 @@
         self.copied_files = set()
 
     def __call__(self, pattern, dst="", src="", root_package=None, folder=False,
-                 ignore_case=False, excludes=None):
+                 ignore_case=False, excludes=None, keep_path=True):
         """
         param pattern: an fnmatch file pattern of the files that should be copied. Eg. *.dll
         param dst: the destination local folder, wrt to current conanfile dir, to which
@@ -136,7 +136,7 @@
             final_dst_path = os.path.join(real_dst_folder, name) if folder else real_dst_folder
             file_copier = FileCopier(matching_path, final_dst_path)
             files = file_copier(pattern, src=src, links=True, ignore_case=ignore_case,
-                                excludes=excludes)
+                                excludes=excludes, keep_path=keep_path)
             self.copied_files.update(files)
 
     def _get_folders(self, pattern):
diff --git a/conans/client/loader_parse.py b/conans/client/loader_parse.py
--- a/conans/client/loader_parse.py
+++ b/conans/client/loader_parse.py
@@ -111,7 +111,7 @@
     @property
     def _import_parameters(self):
         def _parse_args(param_string):
-            root_package, ignore_case, folder, excludes = None, False, False, None
+            root_package, ignore_case, folder, excludes, keep_path = None, False, False, None, True
             params = param_string.split(",")
             params = [p.split("=") for p in params if p]
             for (var, value) in params:
@@ -125,9 +125,11 @@
                     folder = (value.lower() == "true")
                 elif var == "excludes":
                     excludes = value.split()
+                elif var == "keep_path":
+                    keep_path = (value.lower() == "true")
                 else:
                     raise Exception("Invalid imports. Unknown argument %s" % var)
-            return root_package, ignore_case, folder, excludes
+            return root_package, ignore_case, folder, excludes, keep_path
 
         def _parse_import(line):
             pair = line.split("->")
@@ -156,9 +158,9 @@
                     params = tokens[1]
                 else:
                     params = ""
-                root_package, ignore_case, folder, excludes = _parse_args(params)
+                root_package, ignore_case, folder, excludes, keep_path = _parse_args(params)
                 pattern, dest, src = _parse_import(line)
-                ret.append((pattern, dest, src, root_package, folder, ignore_case, excludes))
+                ret.append((pattern, dest, src, root_package, folder, ignore_case, excludes, keep_path))
             except Exception as e:
                 raise ConanException("%s\n%s" % (invalid_line_msg, str(e)))
         return ret

{"golden_diff": "diff --git a/conans/client/importer.py b/conans/client/importer.py\n--- a/conans/client/importer.py\n+++ b/conans/client/importer.py\n@@ -116,7 +116,7 @@\n         self.copied_files = set()\n \n     def __call__(self, pattern, dst=\"\", src=\"\", root_package=None, folder=False,\n-                 ignore_case=False, excludes=None):\n+                 ignore_case=False, excludes=None, keep_path=True):\n         \"\"\"\n         param pattern: an fnmatch file pattern of the files that should be copied. Eg. *.dll\n         param dst: the destination local folder, wrt to current conanfile dir, to which\n@@ -136,7 +136,7 @@\n             final_dst_path = os.path.join(real_dst_folder, name) if folder else real_dst_folder\n             file_copier = FileCopier(matching_path, final_dst_path)\n             files = file_copier(pattern, src=src, links=True, ignore_case=ignore_case,\n-                                excludes=excludes)\n+                                excludes=excludes, keep_path=keep_path)\n             self.copied_files.update(files)\n \n     def _get_folders(self, pattern):\ndiff --git a/conans/client/loader_parse.py b/conans/client/loader_parse.py\n--- a/conans/client/loader_parse.py\n+++ b/conans/client/loader_parse.py\n@@ -111,7 +111,7 @@\n     @property\n     def _import_parameters(self):\n         def _parse_args(param_string):\n-            root_package, ignore_case, folder, excludes = None, False, False, None\n+            root_package, ignore_case, folder, excludes, keep_path = None, False, False, None, True\n             params = param_string.split(\",\")\n             params = [p.split(\"=\") for p in params if p]\n             for (var, value) in params:\n@@ -125,9 +125,11 @@\n                     folder = (value.lower() == \"true\")\n                 elif var == \"excludes\":\n                     excludes = value.split()\n+                elif var == \"keep_path\":\n+                    keep_path = (value.lower() == \"true\")\n                 else:\n                     raise Exception(\"Invalid imports. Unknown argument %s\" % var)\n-            return root_package, ignore_case, folder, excludes\n+            return root_package, ignore_case, folder, excludes, keep_path\n \n         def _parse_import(line):\n             pair = line.split(\"->\")\n@@ -156,9 +158,9 @@\n                     params = tokens[1]\n                 else:\n                     params = \"\"\n-                root_package, ignore_case, folder, excludes = _parse_args(params)\n+                root_package, ignore_case, folder, excludes, keep_path = _parse_args(params)\n                 pattern, dest, src = _parse_import(line)\n-                ret.append((pattern, dest, src, root_package, folder, ignore_case, excludes))\n+                ret.append((pattern, dest, src, root_package, folder, ignore_case, excludes, keep_path))\n             except Exception as e:\n                 raise ConanException(\"%s\\n%s\" % (invalid_line_msg, str(e)))\n         return ret\n", "issue": "imports/copy question\nSuppose I have\r\n```\r\nx86\r\n  vc15\r\n    bin\r\n      opencv_core310.dll \r\n      ...\r\n```\r\ndirectory structure in my package. Is it possible to import `opencv_core310.dll` and friends to project's `bin` folder forgetting all the directory structure? I tried\r\n```python\r\ndef imports(self):\r\n   self.copy(\"*.dll\", \"\", \"bin\")\r\n```\r\nbut it creates `x86/vc15/bin/opencv_core310.dll` while I would like to get `bin/opencv_core310.dll`\r\nProbably  import/copy should have `keep_path` parameter like package/copy does?\r\n\r\n\n", "before_files": [{"content": "import calendar\nimport fnmatch\nimport os\nimport time\n\nfrom conans import tools\nfrom conans.client.file_copier import FileCopier, report_copied_files\nfrom conans.client.output import ScopedOutput\nfrom conans.errors import ConanException\nfrom conans.model.conan_file import get_env_context_manager\nfrom conans.model.manifest import FileTreeManifest\nfrom conans.util.files import save, md5sum, load\n\nIMPORTS_MANIFESTS = \"conan_imports_manifest.txt\"\n\n\ndef undo_imports(current_path, output):\n    manifest_path = os.path.join(current_path, IMPORTS_MANIFESTS)\n    try:\n        manifest_content = load(manifest_path)\n    except:\n        raise ConanException(\"Cannot load file %s\" % manifest_path)\n\n    try:\n        manifest = FileTreeManifest.loads(manifest_content)\n    except:\n        raise ConanException(\"Wrong manifest file format %s\" % manifest_path)\n\n    not_removed = 0\n    files = manifest.files()\n    for filepath in files:\n        if not os.path.exists(filepath):\n            output.warn(\"File doesn't exist: %s\" % filepath)\n            continue\n        try:\n            os.remove(filepath)\n        except:\n            output.error(\"Cannot remove file (open or busy): %s\" % filepath)\n            not_removed += 1\n\n    if not_removed:\n        raise ConanException(\"Cannot remove %s or more imported files\" % not_removed)\n\n    output.success(\"Removed %s imported files\" % (len(files)))\n    try:\n        os.remove(manifest_path)\n        output.success(\"Removed imports manifest file: %s\" % manifest_path)\n    except:\n        raise ConanException(\"Cannot remove manifest file (open or busy): %s\" % manifest_path)\n\n\ndef _report_save_manifest(copied_files, output, dest_folder, manifest_name):\n    report_copied_files(copied_files, output)\n    if copied_files:\n        date = calendar.timegm(time.gmtime())\n        file_dict = {}\n        for f in copied_files:\n            abs_path = os.path.join(dest_folder, f)\n            file_dict[f] = md5sum(abs_path)\n        manifest = FileTreeManifest(date, file_dict)\n        save(os.path.join(dest_folder, manifest_name), str(manifest))\n\n\ndef run_imports(conanfile, dest_folder, output):\n    if not hasattr(conanfile, \"imports\"):\n        return []\n    file_importer = _FileImporter(conanfile, dest_folder)\n    conanfile.copy = file_importer\n    conanfile.imports_folder = dest_folder\n    with get_env_context_manager(conanfile):\n        with tools.chdir(dest_folder):\n            conanfile.imports()\n    copied_files = file_importer.copied_files\n    import_output = ScopedOutput(\"%s imports()\" % output.scope, output)\n    _report_save_manifest(copied_files, import_output, dest_folder, IMPORTS_MANIFESTS)\n    return copied_files\n\n\ndef run_deploy(conanfile, install_folder, output):\n    deploy_output = ScopedOutput(\"%s deploy()\" % output.scope, output)\n    file_importer = _FileImporter(conanfile, install_folder)\n    package_copied = set()\n\n    # This is necessary to capture FileCopier full destination paths\n    # Maybe could be improved in FileCopier\n    def file_copier(*args, **kwargs):\n        file_copy = FileCopier(conanfile.package_folder, install_folder)\n        copied = file_copy(*args, **kwargs)\n        package_copied.update(copied)\n\n    conanfile.copy_deps = file_importer\n    conanfile.copy = file_copier\n    conanfile.install_folder = install_folder\n    with get_env_context_manager(conanfile):\n        with tools.chdir(install_folder):\n            conanfile.deploy()\n\n    copied_files = file_importer.copied_files\n    copied_files.update(package_copied)\n    _report_save_manifest(copied_files, deploy_output, install_folder, \"deploy_manifest.txt\")\n\n\nclass _FileImporter(object):\n    \"\"\" manages the copy of files, resources, libs from the local store to the user\n    space. E.g.: shared libs, dlls, they will be in the package folder of your\n    configuration in the store. But you dont want to add every package to the\n    system PATH. Those shared libs can be copied to the user folder, close to\n    the exes where they can be found without modifying the path.\n    Useful also for copying other resources as images or data files.\n    It can be also used for Golang projects, in which the packages are always\n    source based and need to be copied to the user folder to be built\n    \"\"\"\n    def __init__(self, conanfile, dst_folder):\n        self._conanfile = conanfile\n        self._dst_folder = dst_folder\n        self.copied_files = set()\n\n    def __call__(self, pattern, dst=\"\", src=\"\", root_package=None, folder=False,\n                 ignore_case=False, excludes=None):\n        \"\"\"\n        param pattern: an fnmatch file pattern of the files that should be copied. Eg. *.dll\n        param dst: the destination local folder, wrt to current conanfile dir, to which\n                   the files will be copied. Eg: \"bin\"\n        param src: the source folder in which those files will be searched. This folder\n                   will be stripped from the dst name. Eg.: lib/Debug/x86\n        param root_package: fnmatch pattern of the package name (\"OpenCV\", \"Boost\") from\n                            which files will be copied. Default: all packages in deps\n        \"\"\"\n        if os.path.isabs(dst):\n            real_dst_folder = dst\n        else:\n            real_dst_folder = os.path.normpath(os.path.join(self._dst_folder, dst))\n\n        matching_paths = self._get_folders(root_package)\n        for name, matching_path in matching_paths.items():\n            final_dst_path = os.path.join(real_dst_folder, name) if folder else real_dst_folder\n            file_copier = FileCopier(matching_path, final_dst_path)\n            files = file_copier(pattern, src=src, links=True, ignore_case=ignore_case,\n                                excludes=excludes)\n            self.copied_files.update(files)\n\n    def _get_folders(self, pattern):\n        \"\"\" given the current deps graph, compute a dict {name: store-path} of\n        each dependency\n        \"\"\"\n        if not pattern:\n            return {pkg: cpp_info.rootpath for pkg, cpp_info in self._conanfile.deps_cpp_info.dependencies}\n        return {pkg: cpp_info.rootpath for pkg, cpp_info in self._conanfile.deps_cpp_info.dependencies\n                if fnmatch.fnmatch(pkg, pattern)}\n", "path": "conans/client/importer.py"}, {"content": "import imp\nimport inspect\nimport os\nimport sys\nimport uuid\n\nfrom conans.errors import ConanException, NotFoundException\nfrom conans.model.conan_file import ConanFile\nfrom conans.util.config_parser import ConfigParser\nfrom conans.tools import chdir\nfrom conans.client.generators import registered_generators\nfrom conans.model import Generator\n\n\ndef load_conanfile_class(conanfile_path):\n    loaded, filename = _parse_file(conanfile_path)\n    try:\n        return _parse_module(loaded, filename)\n    except Exception as e:  # re-raise with file name\n        raise ConanException(\"%s: %s\" % (conanfile_path, str(e)))\n\n\ndef _parse_module(conanfile_module, filename):\n    \"\"\" Parses a python in-memory module, to extract the classes, mainly the main\n    class defining the Recipe, but also process possible existing generators\n    @param conanfile_module: the module to be processed\n    @param consumer: if this is a root node in the hierarchy, the consumer project\n    @return: the main ConanFile class from the module\n    \"\"\"\n    result = None\n    for name, attr in conanfile_module.__dict__.items():\n        if name[0] == \"_\":\n            continue\n        if (inspect.isclass(attr) and issubclass(attr, ConanFile) and attr != ConanFile and\n                attr.__dict__[\"__module__\"] == filename):\n            if result is None:\n                result = attr\n            else:\n                raise ConanException(\"More than 1 conanfile in the file\")\n        if (inspect.isclass(attr) and issubclass(attr, Generator) and attr != Generator and\n                attr.__dict__[\"__module__\"] == filename):\n            registered_generators.add(attr.__name__, attr)\n\n    if result is None:\n        raise ConanException(\"No subclass of ConanFile\")\n\n    return result\n\n\ndef _parse_file(conan_file_path):\n    \"\"\" From a given path, obtain the in memory python import module\n    \"\"\"\n\n    if not os.path.exists(conan_file_path):\n        raise NotFoundException(\"%s not found!\" % conan_file_path)\n\n    filename = os.path.splitext(os.path.basename(conan_file_path))[0]\n\n    try:\n        current_dir = os.path.dirname(conan_file_path)\n        sys.path.append(current_dir)\n        old_modules = list(sys.modules.keys())\n        with chdir(current_dir):\n            sys.dont_write_bytecode = True\n            loaded = imp.load_source(filename, conan_file_path)\n            sys.dont_write_bytecode = False\n        # Put all imported files under a new package name\n        module_id = uuid.uuid1()\n        added_modules = set(sys.modules).difference(old_modules)\n        for added in added_modules:\n            module = sys.modules[added]\n            if module:\n                try:\n                    folder = os.path.dirname(module.__file__)\n                except AttributeError:  # some module doesn't have __file__\n                    pass\n                else:\n                    if folder.startswith(current_dir):\n                        module = sys.modules.pop(added)\n                        sys.modules[\"%s.%s\" % (module_id, added)] = module\n    except Exception:\n        import traceback\n        trace = traceback.format_exc().split('\\n')\n        raise ConanException(\"Unable to load conanfile in %s\\n%s\" % (conan_file_path,\n                                                                     '\\n'.join(trace[3:])))\n    finally:\n        sys.path.pop()\n\n    return loaded, filename\n\n\nclass ConanFileTextLoader(object):\n    \"\"\"Parse a conanfile.txt file\"\"\"\n\n    def __init__(self, input_text):\n        # Prefer composition over inheritance, the __getattr__ was breaking things\n        self._config_parser = ConfigParser(input_text,  [\"requires\", \"generators\", \"options\",\n                                                         \"imports\"], parse_lines=True)\n\n    @property\n    def requirements(self):\n        \"\"\"returns a list of requires\n        EX:  \"OpenCV/2.4.10@phil/stable\"\n        \"\"\"\n        return [r.strip() for r in self._config_parser.requires.splitlines()]\n\n    @property\n    def options(self):\n        return self._config_parser.options\n\n    @property\n    def _import_parameters(self):\n        def _parse_args(param_string):\n            root_package, ignore_case, folder, excludes = None, False, False, None\n            params = param_string.split(\",\")\n            params = [p.split(\"=\") for p in params if p]\n            for (var, value) in params:\n                var = var.strip()\n                value = value.strip()\n                if var == \"root_package\":\n                    root_package = value\n                elif var == \"ignore_case\":\n                    ignore_case = (value.lower() == \"true\")\n                elif var == \"folder\":\n                    folder = (value.lower() == \"true\")\n                elif var == \"excludes\":\n                    excludes = value.split()\n                else:\n                    raise Exception(\"Invalid imports. Unknown argument %s\" % var)\n            return root_package, ignore_case, folder, excludes\n\n        def _parse_import(line):\n            pair = line.split(\"->\")\n            source = pair[0].strip().split(',', 1)\n            dest = pair[1].strip()\n            src, pattern = source[0].strip(), source[1].strip()\n            return pattern, dest, src\n\n        ret = []\n        local_install_text = self._config_parser.imports\n        for line in local_install_text.splitlines():\n            # discard blanks, comments, and discard trailing comments\n            line = line.strip()\n            if not line or line.startswith(\"#\"):\n                continue\n            line = line.split(\"#\", 1)[0]\n\n            invalid_line_msg = \"Invalid imports line: %s\\nEX: OpenCV/lib, * -> ./lib\" % line\n            if line.startswith(\"/\") or line.startswith(\"..\"):\n                raise ConanException(\"%s\\n%s\" % (invalid_line_msg,\n                                                 \"Import's paths can't begin with '/' or '..'\"))\n            try:\n                tokens = line.split(\"@\", 1)\n                if len(tokens) > 1:\n                    line = tokens[0]\n                    params = tokens[1]\n                else:\n                    params = \"\"\n                root_package, ignore_case, folder, excludes = _parse_args(params)\n                pattern, dest, src = _parse_import(line)\n                ret.append((pattern, dest, src, root_package, folder, ignore_case, excludes))\n            except Exception as e:\n                raise ConanException(\"%s\\n%s\" % (invalid_line_msg, str(e)))\n        return ret\n\n    @property\n    def generators(self):\n        return self._config_parser.generators.splitlines()\n\n    def imports_method(self, conan_file):\n        parameters = self._import_parameters\n\n        def imports():\n            for import_params in parameters:\n                conan_file.copy(*import_params)\n        return imports\n", "path": "conans/client/loader_parse.py"}], "after_files": [{"content": "import calendar\nimport fnmatch\nimport os\nimport time\n\nfrom conans import tools\nfrom conans.client.file_copier import FileCopier, report_copied_files\nfrom conans.client.output import ScopedOutput\nfrom conans.errors import ConanException\nfrom conans.model.conan_file import get_env_context_manager\nfrom conans.model.manifest import FileTreeManifest\nfrom conans.util.files import save, md5sum, load\n\nIMPORTS_MANIFESTS = \"conan_imports_manifest.txt\"\n\n\ndef undo_imports(current_path, output):\n    manifest_path = os.path.join(current_path, IMPORTS_MANIFESTS)\n    try:\n        manifest_content = load(manifest_path)\n    except:\n        raise ConanException(\"Cannot load file %s\" % manifest_path)\n\n    try:\n        manifest = FileTreeManifest.loads(manifest_content)\n    except:\n        raise ConanException(\"Wrong manifest file format %s\" % manifest_path)\n\n    not_removed = 0\n    files = manifest.files()\n    for filepath in files:\n        if not os.path.exists(filepath):\n            output.warn(\"File doesn't exist: %s\" % filepath)\n            continue\n        try:\n            os.remove(filepath)\n        except:\n            output.error(\"Cannot remove file (open or busy): %s\" % filepath)\n            not_removed += 1\n\n    if not_removed:\n        raise ConanException(\"Cannot remove %s or more imported files\" % not_removed)\n\n    output.success(\"Removed %s imported files\" % (len(files)))\n    try:\n        os.remove(manifest_path)\n        output.success(\"Removed imports manifest file: %s\" % manifest_path)\n    except:\n        raise ConanException(\"Cannot remove manifest file (open or busy): %s\" % manifest_path)\n\n\ndef _report_save_manifest(copied_files, output, dest_folder, manifest_name):\n    report_copied_files(copied_files, output)\n    if copied_files:\n        date = calendar.timegm(time.gmtime())\n        file_dict = {}\n        for f in copied_files:\n            abs_path = os.path.join(dest_folder, f)\n            file_dict[f] = md5sum(abs_path)\n        manifest = FileTreeManifest(date, file_dict)\n        save(os.path.join(dest_folder, manifest_name), str(manifest))\n\n\ndef run_imports(conanfile, dest_folder, output):\n    if not hasattr(conanfile, \"imports\"):\n        return []\n    file_importer = _FileImporter(conanfile, dest_folder)\n    conanfile.copy = file_importer\n    conanfile.imports_folder = dest_folder\n    with get_env_context_manager(conanfile):\n        with tools.chdir(dest_folder):\n            conanfile.imports()\n    copied_files = file_importer.copied_files\n    import_output = ScopedOutput(\"%s imports()\" % output.scope, output)\n    _report_save_manifest(copied_files, import_output, dest_folder, IMPORTS_MANIFESTS)\n    return copied_files\n\n\ndef run_deploy(conanfile, install_folder, output):\n    deploy_output = ScopedOutput(\"%s deploy()\" % output.scope, output)\n    file_importer = _FileImporter(conanfile, install_folder)\n    package_copied = set()\n\n    # This is necessary to capture FileCopier full destination paths\n    # Maybe could be improved in FileCopier\n    def file_copier(*args, **kwargs):\n        file_copy = FileCopier(conanfile.package_folder, install_folder)\n        copied = file_copy(*args, **kwargs)\n        package_copied.update(copied)\n\n    conanfile.copy_deps = file_importer\n    conanfile.copy = file_copier\n    conanfile.install_folder = install_folder\n    with get_env_context_manager(conanfile):\n        with tools.chdir(install_folder):\n            conanfile.deploy()\n\n    copied_files = file_importer.copied_files\n    copied_files.update(package_copied)\n    _report_save_manifest(copied_files, deploy_output, install_folder, \"deploy_manifest.txt\")\n\n\nclass _FileImporter(object):\n    \"\"\" manages the copy of files, resources, libs from the local store to the user\n    space. E.g.: shared libs, dlls, they will be in the package folder of your\n    configuration in the store. But you dont want to add every package to the\n    system PATH. Those shared libs can be copied to the user folder, close to\n    the exes where they can be found without modifying the path.\n    Useful also for copying other resources as images or data files.\n    It can be also used for Golang projects, in which the packages are always\n    source based and need to be copied to the user folder to be built\n    \"\"\"\n    def __init__(self, conanfile, dst_folder):\n        self._conanfile = conanfile\n        self._dst_folder = dst_folder\n        self.copied_files = set()\n\n    def __call__(self, pattern, dst=\"\", src=\"\", root_package=None, folder=False,\n                 ignore_case=False, excludes=None, keep_path=True):\n        \"\"\"\n        param pattern: an fnmatch file pattern of the files that should be copied. Eg. *.dll\n        param dst: the destination local folder, wrt to current conanfile dir, to which\n                   the files will be copied. Eg: \"bin\"\n        param src: the source folder in which those files will be searched. This folder\n                   will be stripped from the dst name. Eg.: lib/Debug/x86\n        param root_package: fnmatch pattern of the package name (\"OpenCV\", \"Boost\") from\n                            which files will be copied. Default: all packages in deps\n        \"\"\"\n        if os.path.isabs(dst):\n            real_dst_folder = dst\n        else:\n            real_dst_folder = os.path.normpath(os.path.join(self._dst_folder, dst))\n\n        matching_paths = self._get_folders(root_package)\n        for name, matching_path in matching_paths.items():\n            final_dst_path = os.path.join(real_dst_folder, name) if folder else real_dst_folder\n            file_copier = FileCopier(matching_path, final_dst_path)\n            files = file_copier(pattern, src=src, links=True, ignore_case=ignore_case,\n                                excludes=excludes, keep_path=keep_path)\n            self.copied_files.update(files)\n\n    def _get_folders(self, pattern):\n        \"\"\" given the current deps graph, compute a dict {name: store-path} of\n        each dependency\n        \"\"\"\n        if not pattern:\n            return {pkg: cpp_info.rootpath for pkg, cpp_info in self._conanfile.deps_cpp_info.dependencies}\n        return {pkg: cpp_info.rootpath for pkg, cpp_info in self._conanfile.deps_cpp_info.dependencies\n                if fnmatch.fnmatch(pkg, pattern)}\n", "path": "conans/client/importer.py"}, {"content": "import imp\nimport inspect\nimport os\nimport sys\nimport uuid\n\nfrom conans.errors import ConanException, NotFoundException\nfrom conans.model.conan_file import ConanFile\nfrom conans.util.config_parser import ConfigParser\nfrom conans.tools import chdir\nfrom conans.client.generators import registered_generators\nfrom conans.model import Generator\n\n\ndef load_conanfile_class(conanfile_path):\n    loaded, filename = _parse_file(conanfile_path)\n    try:\n        return _parse_module(loaded, filename)\n    except Exception as e:  # re-raise with file name\n        raise ConanException(\"%s: %s\" % (conanfile_path, str(e)))\n\n\ndef _parse_module(conanfile_module, filename):\n    \"\"\" Parses a python in-memory module, to extract the classes, mainly the main\n    class defining the Recipe, but also process possible existing generators\n    @param conanfile_module: the module to be processed\n    @param consumer: if this is a root node in the hierarchy, the consumer project\n    @return: the main ConanFile class from the module\n    \"\"\"\n    result = None\n    for name, attr in conanfile_module.__dict__.items():\n        if name[0] == \"_\":\n            continue\n        if (inspect.isclass(attr) and issubclass(attr, ConanFile) and attr != ConanFile and\n                attr.__dict__[\"__module__\"] == filename):\n            if result is None:\n                result = attr\n            else:\n                raise ConanException(\"More than 1 conanfile in the file\")\n        if (inspect.isclass(attr) and issubclass(attr, Generator) and attr != Generator and\n                attr.__dict__[\"__module__\"] == filename):\n            registered_generators.add(attr.__name__, attr)\n\n    if result is None:\n        raise ConanException(\"No subclass of ConanFile\")\n\n    return result\n\n\ndef _parse_file(conan_file_path):\n    \"\"\" From a given path, obtain the in memory python import module\n    \"\"\"\n\n    if not os.path.exists(conan_file_path):\n        raise NotFoundException(\"%s not found!\" % conan_file_path)\n\n    filename = os.path.splitext(os.path.basename(conan_file_path))[0]\n\n    try:\n        current_dir = os.path.dirname(conan_file_path)\n        sys.path.append(current_dir)\n        old_modules = list(sys.modules.keys())\n        with chdir(current_dir):\n            sys.dont_write_bytecode = True\n            loaded = imp.load_source(filename, conan_file_path)\n            sys.dont_write_bytecode = False\n        # Put all imported files under a new package name\n        module_id = uuid.uuid1()\n        added_modules = set(sys.modules).difference(old_modules)\n        for added in added_modules:\n            module = sys.modules[added]\n            if module:\n                try:\n                    folder = os.path.dirname(module.__file__)\n                except AttributeError:  # some module doesn't have __file__\n                    pass\n                else:\n                    if folder.startswith(current_dir):\n                        module = sys.modules.pop(added)\n                        sys.modules[\"%s.%s\" % (module_id, added)] = module\n    except Exception:\n        import traceback\n        trace = traceback.format_exc().split('\\n')\n        raise ConanException(\"Unable to load conanfile in %s\\n%s\" % (conan_file_path,\n                                                                     '\\n'.join(trace[3:])))\n    finally:\n        sys.path.pop()\n\n    return loaded, filename\n\n\nclass ConanFileTextLoader(object):\n    \"\"\"Parse a conanfile.txt file\"\"\"\n\n    def __init__(self, input_text):\n        # Prefer composition over inheritance, the __getattr__ was breaking things\n        self._config_parser = ConfigParser(input_text,  [\"requires\", \"generators\", \"options\",\n                                                         \"imports\"], parse_lines=True)\n\n    @property\n    def requirements(self):\n        \"\"\"returns a list of requires\n        EX:  \"OpenCV/2.4.10@phil/stable\"\n        \"\"\"\n        return [r.strip() for r in self._config_parser.requires.splitlines()]\n\n    @property\n    def options(self):\n        return self._config_parser.options\n\n    @property\n    def _import_parameters(self):\n        def _parse_args(param_string):\n            root_package, ignore_case, folder, excludes, keep_path = None, False, False, None, True\n            params = param_string.split(\",\")\n            params = [p.split(\"=\") for p in params if p]\n            for (var, value) in params:\n                var = var.strip()\n                value = value.strip()\n                if var == \"root_package\":\n                    root_package = value\n                elif var == \"ignore_case\":\n                    ignore_case = (value.lower() == \"true\")\n                elif var == \"folder\":\n                    folder = (value.lower() == \"true\")\n                elif var == \"excludes\":\n                    excludes = value.split()\n                elif var == \"keep_path\":\n                    keep_path = (value.lower() == \"true\")\n                else:\n                    raise Exception(\"Invalid imports. Unknown argument %s\" % var)\n            return root_package, ignore_case, folder, excludes, keep_path\n\n        def _parse_import(line):\n            pair = line.split(\"->\")\n            source = pair[0].strip().split(',', 1)\n            dest = pair[1].strip()\n            src, pattern = source[0].strip(), source[1].strip()\n            return pattern, dest, src\n\n        ret = []\n        local_install_text = self._config_parser.imports\n        for line in local_install_text.splitlines():\n            # discard blanks, comments, and discard trailing comments\n            line = line.strip()\n            if not line or line.startswith(\"#\"):\n                continue\n            line = line.split(\"#\", 1)[0]\n\n            invalid_line_msg = \"Invalid imports line: %s\\nEX: OpenCV/lib, * -> ./lib\" % line\n            if line.startswith(\"/\") or line.startswith(\"..\"):\n                raise ConanException(\"%s\\n%s\" % (invalid_line_msg,\n                                                 \"Import's paths can't begin with '/' or '..'\"))\n            try:\n                tokens = line.split(\"@\", 1)\n                if len(tokens) > 1:\n                    line = tokens[0]\n                    params = tokens[1]\n                else:\n                    params = \"\"\n                root_package, ignore_case, folder, excludes, keep_path = _parse_args(params)\n                pattern, dest, src = _parse_import(line)\n                ret.append((pattern, dest, src, root_package, folder, ignore_case, excludes, keep_path))\n            except Exception as e:\n                raise ConanException(\"%s\\n%s\" % (invalid_line_msg, str(e)))\n        return ret\n\n    @property\n    def generators(self):\n        return self._config_parser.generators.splitlines()\n\n    def imports_method(self, conan_file):\n        parameters = self._import_parameters\n\n        def imports():\n            for import_params in parameters:\n                conan_file.copy(*import_params)\n        return imports\n", "path": "conans/client/loader_parse.py"}]}