We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Pyinstaller --distpath broken for Mac.Not making the .app file at -distpath.
<!--
Welcome to the PyInstaller issue tracker! Before creating an issue, please heed the following:

1. This tracker should only be used to report bugs and request features / enhancements to PyInstaller
    - For questions and general support, use the mailing list, see
	  <http://www.pyinstaller.org/support.html#mailing-list>
2. Use the search function before creating a new issue. Duplicates will be closed and directed to
   the original discussion.
3. When making a bug report, make sure you provide all required information. The easier it is for
   maintainers to reproduce, the faster it'll be fixed.
-->




While working with Pyinstaller 3.5 and 3.6 (have not worked on older versions),found out that .app is being made in the same place where .spec file is placed.Did some digging and think that the file
osx.py at line number 95 is the problem which is joining the spec file path with dest path .


## Context information (for bug reports)

* Output of `pyinstaller --version`: ```VERSION 3.5 and 3.6```
* Version of Python: 3.5
* Platform: OS X
* Did you also try this on another platform? Does it work there?
N/A




### A minimal example program which shows the error
To simulate the same issue :

- Decompress the files below
[smallexample.zip](https://github.com/pyinstaller/pyinstaller/files/4666539/smallexample.zip)
- pip install -r requirement.txt
- to make spec file :  pyinstaller --noconsole --windowed small.py
-Now run the spec file from outside the smallexmaple folder.
command to run :  `pyinstaller smallexample/small.spec --distpath small_dist/small_dist2/`
The .app file will be made inside the smallexample folder even though the --distpath is provided.

As mentioned above the spec path is being joined with the dest path ,which should not be the case.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `PyInstaller/building/osx.py`
Content:
```
1 #-----------------------------------------------------------------------------
2 # Copyright (c) 2005-2020, PyInstaller Development Team.
3 #
4 # Distributed under the terms of the GNU General Public License (version 2
5 # or later) with exception for distributing the bootloader.
6 #
7 # The full license is in the file COPYING.txt, distributed with this software.
8 #
9 # SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)
10 #-----------------------------------------------------------------------------
11 
12 import os
13 import plistlib
14 import shutil
15 from ..compat import is_darwin
16 from .api import EXE, COLLECT
17 from .datastruct import Target, TOC, logger
18 from .utils import _check_path_overlap, _rmtree, add_suffix_to_extensions, checkCache
19 
20 
21 
22 class BUNDLE(Target):
23     def __init__(self, *args, **kws):
24         from ..config import CONF
25 
26         # BUNDLE only has a sense under Mac OS X, it's a noop on other platforms
27         if not is_darwin:
28             return
29 
30         # get a path to a .icns icon for the app bundle.
31         self.icon = kws.get('icon')
32         if not self.icon:
33             # --icon not specified; use the default in the pyinstaller folder
34             self.icon = os.path.join(os.path.dirname(os.path.dirname(__file__)),
35                 'bootloader', 'images', 'icon-windowed.icns')
36         else:
37             # user gave an --icon=path. If it is relative, make it
38             # relative to the spec file location.
39             if not os.path.isabs(self.icon):
40                 self.icon = os.path.join(CONF['specpath'], self.icon)
41         # ensure icon path is absolute
42         self.icon = os.path.abspath(self.icon)
43 
44         Target.__init__(self)
45 
46         # .app bundle is created in DISTPATH.
47         self.name = kws.get('name', None)
48         base_name = os.path.basename(self.name)
49         self.name = os.path.join(CONF['distpath'], base_name)
50 
51         self.appname = os.path.splitext(base_name)[0]
52         self.version = kws.get("version", "0.0.0")
53         self.toc = TOC()
54         self.strip = False
55         self.upx = False
56         self.console = True
57 
58         # .app bundle identifier for Code Signing
59         self.bundle_identifier = kws.get('bundle_identifier')
60         if not self.bundle_identifier:
61             # Fallback to appname.
62             self.bundle_identifier = self.appname
63 
64         self.info_plist = kws.get('info_plist', None)
65 
66         for arg in args:
67             if isinstance(arg, EXE):
68                 self.toc.append((os.path.basename(arg.name), arg.name, arg.typ))
69                 self.toc.extend(arg.dependencies)
70                 self.strip = arg.strip
71                 self.upx = arg.upx
72                 self.upx_exclude = arg.upx_exclude
73                 self.console = arg.console
74             elif isinstance(arg, TOC):
75                 self.toc.extend(arg)
76                 # TOC doesn't have a strip or upx attribute, so there is no way for us to
77                 # tell which cache we should draw from.
78             elif isinstance(arg, COLLECT):
79                 self.toc.extend(arg.toc)
80                 self.strip = arg.strip_binaries
81                 self.upx = arg.upx_binaries
82                 self.upx_exclude = arg.upx_exclude
83                 self.console = arg.console
84             else:
85                 logger.info("unsupported entry %s", arg.__class__.__name__)
86         # Now, find values for app filepath (name), app name (appname), and name
87         # of the actual executable (exename) from the first EXECUTABLE item in
88         # toc, which might have come from a COLLECT too (not from an EXE).
89         for inm, name, typ in self.toc:
90             if typ == "EXECUTABLE":
91                 self.exename = name
92                 if self.name is None:
93                     self.appname = "Mac%s" % (os.path.splitext(inm)[0],)
94                     self.name = os.path.join(CONF['specpath'], self.appname + ".app")
95                 else:
96                     self.name = os.path.join(CONF['specpath'], self.name)
97                 break
98         self.__postinit__()
99 
100     _GUTS = (
101         # BUNDLE always builds, just want the toc to be written out
102         ('toc', None),
103     )
104 
105     def _check_guts(self, data, last_build):
106         # BUNDLE always needs to be executed, since it will clean the output
107         # directory anyway to make sure there is no existing cruft accumulating
108         return 1
109 
110     def assemble(self):
111         if _check_path_overlap(self.name) and os.path.isdir(self.name):
112             _rmtree(self.name)
113         logger.info("Building BUNDLE %s", self.tocbasename)
114 
115         # Create a minimal Mac bundle structure
116         os.makedirs(os.path.join(self.name, "Contents", "MacOS"))
117         os.makedirs(os.path.join(self.name, "Contents", "Resources"))
118         os.makedirs(os.path.join(self.name, "Contents", "Frameworks"))
119 
120         # Copy icns icon to Resources directory.
121         if os.path.exists(self.icon):
122             shutil.copy(self.icon, os.path.join(self.name, 'Contents', 'Resources'))
123         else:
124             logger.warning("icon not found %s", self.icon)
125 
126         # Key/values for a minimal Info.plist file
127         info_plist_dict = {"CFBundleDisplayName": self.appname,
128                            "CFBundleName": self.appname,
129 
130                            # Required by 'codesign' utility.
131                            # The value for CFBundleIdentifier is used as the default unique
132                            # name of your program for Code Signing purposes.
133                            # It even identifies the APP for access to restricted OS X areas
134                            # like Keychain.
135                            #
136                            # The identifier used for signing must be globally unique. The usal
137                            # form for this identifier is a hierarchical name in reverse DNS
138                            # notation, starting with the toplevel domain, followed by the
139                            # company name, followed by the department within the company, and
140                            # ending with the product name. Usually in the form:
141                            #   com.mycompany.department.appname
142                            # Cli option --osx-bundle-identifier sets this value.
143                            "CFBundleIdentifier": self.bundle_identifier,
144 
145                            # Fix for #156 - 'MacOS' must be in the name - not sure why
146                            "CFBundleExecutable": 'MacOS/%s' % os.path.basename(self.exename),
147                            "CFBundleIconFile": os.path.basename(self.icon),
148                            "CFBundleInfoDictionaryVersion": "6.0",
149                            "CFBundlePackageType": "APPL",
150                            "CFBundleShortVersionString": self.version,
151 
152                            }
153 
154         # Set some default values.
155         # But they still can be overwritten by the user.
156         if self.console:
157             # Setting EXE console=True implies LSBackgroundOnly=True.
158             info_plist_dict['LSBackgroundOnly'] = True
159         else:
160             # Let's use high resolution by default.
161             info_plist_dict['NSHighResolutionCapable'] = True
162 
163         # Merge info_plist settings from spec file
164         if isinstance(self.info_plist, dict) and self.info_plist:
165             info_plist_dict.update(self.info_plist)
166 
167         plist_filename = os.path.join(self.name, "Contents", "Info.plist")
168         with open(plist_filename, "wb") as plist_fh:
169             plistlib.dump(info_plist_dict, plist_fh)
170 
171         links = []
172         toc = add_suffix_to_extensions(self.toc)
173         for inm, fnm, typ in toc:
174             # Copy files from cache. This ensures that are used files with relative
175             # paths to dynamic library dependencies (@executable_path)
176             base_path = inm.split('/', 1)[0]
177             if typ in ('EXTENSION', 'BINARY'):
178                 fnm = checkCache(fnm, strip=self.strip, upx=self.upx,
179                                  upx_exclude=self.upx_exclude, dist_nm=inm)
180             # Add most data files to a list for symlinking later.
181             if typ == 'DATA' and base_path not in ('PySide2', 'PyQt5'):
182                 links.append((inm, fnm))
183             else:
184                 tofnm = os.path.join(self.name, "Contents", "MacOS", inm)
185                 todir = os.path.dirname(tofnm)
186                 if not os.path.exists(todir):
187                     os.makedirs(todir)
188                 if os.path.isdir(fnm):
189                     # beacuse shutil.copy2() is the default copy function
190                     # for shutil.copytree, this will also copy file metadata
191                     shutil.copytree(fnm, tofnm)
192                 else:
193                     shutil.copy(fnm, tofnm)
194 
195         logger.info('moving BUNDLE data files to Resource directory')
196 
197         # Mac OS X Code Signing does not work when .app bundle contains
198         # data files in dir ./Contents/MacOS.
199         #
200         # Put all data files in ./Resources and create symlinks in ./MacOS.
201         bin_dir = os.path.join(self.name, 'Contents', 'MacOS')
202         res_dir = os.path.join(self.name, 'Contents', 'Resources')
203         for inm, fnm in links:
204             tofnm = os.path.join(res_dir, inm)
205             todir = os.path.dirname(tofnm)
206             if not os.path.exists(todir):
207                 os.makedirs(todir)
208             if os.path.isdir(fnm):
209                 # beacuse shutil.copy2() is the default copy function
210                 # for shutil.copytree, this will also copy file metadata
211                 shutil.copytree(fnm, tofnm)
212             else:
213                 shutil.copy(fnm, tofnm)
214             base_path = os.path.split(inm)[0]
215             if base_path:
216                 if not os.path.exists(os.path.join(bin_dir, inm)):
217                     path = ''
218                     for part in iter(base_path.split(os.path.sep)):
219                         # Build path from previous path and the next part of the base path
220                         path = os.path.join(path, part)
221                         try:
222                             relative_source_path = os.path.relpath(os.path.join(res_dir, path),
223                                                                    os.path.split(os.path.join(bin_dir, path))[0])
224                             dest_path = os.path.join(bin_dir, path)
225                             os.symlink(relative_source_path, dest_path)
226                             break
227                         except FileExistsError:
228                             pass
229                     if not os.path.exists(os.path.join(bin_dir, inm)):
230                         relative_source_path = os.path.relpath(os.path.join(res_dir, inm),
231                                                                os.path.split(os.path.join(bin_dir, inm))[0])
232                         dest_path = os.path.join(bin_dir, inm)
233                         os.symlink(relative_source_path, dest_path)
234             else:  # If path is empty, e.g., a top level file, try to just symlink the file
235                 os.symlink(os.path.relpath(os.path.join(res_dir, inm),
236                                            os.path.split(os.path.join(bin_dir, inm))[0]),
237                            os.path.join(bin_dir, inm))
238
```
--- 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/PyInstaller/building/osx.py b/PyInstaller/building/osx.py
--- a/PyInstaller/building/osx.py
+++ b/PyInstaller/building/osx.py
@@ -89,11 +89,6 @@
         for inm, name, typ in self.toc:
             if typ == "EXECUTABLE":
                 self.exename = name
-                if self.name is None:
-                    self.appname = "Mac%s" % (os.path.splitext(inm)[0],)
-                    self.name = os.path.join(CONF['specpath'], self.appname + ".app")
-                else:
-                    self.name = os.path.join(CONF['specpath'], self.name)
                 break
         self.__postinit__()

{"golden_diff": "diff --git a/PyInstaller/building/osx.py b/PyInstaller/building/osx.py\n--- a/PyInstaller/building/osx.py\n+++ b/PyInstaller/building/osx.py\n@@ -89,11 +89,6 @@\n         for inm, name, typ in self.toc:\n             if typ == \"EXECUTABLE\":\n                 self.exename = name\n-                if self.name is None:\n-                    self.appname = \"Mac%s\" % (os.path.splitext(inm)[0],)\n-                    self.name = os.path.join(CONF['specpath'], self.appname + \".app\")\n-                else:\n-                    self.name = os.path.join(CONF['specpath'], self.name)\n                 break\n         self.__postinit__()\n", "issue": "Pyinstaller --distpath broken for Mac.Not making the .app file at -distpath.\n<!--\r\nWelcome to the PyInstaller issue tracker! Before creating an issue, please heed the following:\r\n\r\n1. This tracker should only be used to report bugs and request features / enhancements to PyInstaller\r\n    - For questions and general support, use the mailing list, see\r\n\t  <http://www.pyinstaller.org/support.html#mailing-list>\r\n2. Use the search function before creating a new issue. Duplicates will be closed and directed to\r\n   the original discussion.\r\n3. When making a bug report, make sure you provide all required information. The easier it is for\r\n   maintainers to reproduce, the faster it'll be fixed.\r\n-->\r\n\r\n\r\n\r\n\r\nWhile working with Pyinstaller 3.5 and 3.6 (have not worked on older versions),found out that .app is being made in the same place where .spec file is placed.Did some digging and think that the file\r\nosx.py at line number 95 is the problem which is joining the spec file path with dest path .\r\n\r\n\r\n## Context information (for bug reports)\r\n\r\n* Output of `pyinstaller --version`: ```VERSION 3.5 and 3.6```\r\n* Version of Python: 3.5\r\n* Platform: OS X\r\n* Did you also try this on another platform? Does it work there?\r\nN/A\r\n\r\n\r\n\r\n\r\n### A minimal example program which shows the error\r\nTo simulate the same issue :\r\n\r\n- Decompress the files below\r\n[smallexample.zip](https://github.com/pyinstaller/pyinstaller/files/4666539/smallexample.zip)\r\n- pip install -r requirement.txt\r\n- to make spec file :  pyinstaller --noconsole --windowed small.py\r\n-Now run the spec file from outside the smallexmaple folder.\r\ncommand to run :  `pyinstaller smallexample/small.spec --distpath small_dist/small_dist2/`\r\nThe .app file will be made inside the smallexample folder even though the --distpath is provided.\r\n\r\nAs mentioned above the spec path is being joined with the dest path ,which should not be the case.\n", "before_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2005-2020, PyInstaller Development Team.\n#\n# Distributed under the terms of the GNU General Public License (version 2\n# or later) with exception for distributing the bootloader.\n#\n# The full license is in the file COPYING.txt, distributed with this software.\n#\n# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)\n#-----------------------------------------------------------------------------\n\nimport os\nimport plistlib\nimport shutil\nfrom ..compat import is_darwin\nfrom .api import EXE, COLLECT\nfrom .datastruct import Target, TOC, logger\nfrom .utils import _check_path_overlap, _rmtree, add_suffix_to_extensions, checkCache\n\n\n\nclass BUNDLE(Target):\n    def __init__(self, *args, **kws):\n        from ..config import CONF\n\n        # BUNDLE only has a sense under Mac OS X, it's a noop on other platforms\n        if not is_darwin:\n            return\n\n        # get a path to a .icns icon for the app bundle.\n        self.icon = kws.get('icon')\n        if not self.icon:\n            # --icon not specified; use the default in the pyinstaller folder\n            self.icon = os.path.join(os.path.dirname(os.path.dirname(__file__)),\n                'bootloader', 'images', 'icon-windowed.icns')\n        else:\n            # user gave an --icon=path. If it is relative, make it\n            # relative to the spec file location.\n            if not os.path.isabs(self.icon):\n                self.icon = os.path.join(CONF['specpath'], self.icon)\n        # ensure icon path is absolute\n        self.icon = os.path.abspath(self.icon)\n\n        Target.__init__(self)\n\n        # .app bundle is created in DISTPATH.\n        self.name = kws.get('name', None)\n        base_name = os.path.basename(self.name)\n        self.name = os.path.join(CONF['distpath'], base_name)\n\n        self.appname = os.path.splitext(base_name)[0]\n        self.version = kws.get(\"version\", \"0.0.0\")\n        self.toc = TOC()\n        self.strip = False\n        self.upx = False\n        self.console = True\n\n        # .app bundle identifier for Code Signing\n        self.bundle_identifier = kws.get('bundle_identifier')\n        if not self.bundle_identifier:\n            # Fallback to appname.\n            self.bundle_identifier = self.appname\n\n        self.info_plist = kws.get('info_plist', None)\n\n        for arg in args:\n            if isinstance(arg, EXE):\n                self.toc.append((os.path.basename(arg.name), arg.name, arg.typ))\n                self.toc.extend(arg.dependencies)\n                self.strip = arg.strip\n                self.upx = arg.upx\n                self.upx_exclude = arg.upx_exclude\n                self.console = arg.console\n            elif isinstance(arg, TOC):\n                self.toc.extend(arg)\n                # TOC doesn't have a strip or upx attribute, so there is no way for us to\n                # tell which cache we should draw from.\n            elif isinstance(arg, COLLECT):\n                self.toc.extend(arg.toc)\n                self.strip = arg.strip_binaries\n                self.upx = arg.upx_binaries\n                self.upx_exclude = arg.upx_exclude\n                self.console = arg.console\n            else:\n                logger.info(\"unsupported entry %s\", arg.__class__.__name__)\n        # Now, find values for app filepath (name), app name (appname), and name\n        # of the actual executable (exename) from the first EXECUTABLE item in\n        # toc, which might have come from a COLLECT too (not from an EXE).\n        for inm, name, typ in self.toc:\n            if typ == \"EXECUTABLE\":\n                self.exename = name\n                if self.name is None:\n                    self.appname = \"Mac%s\" % (os.path.splitext(inm)[0],)\n                    self.name = os.path.join(CONF['specpath'], self.appname + \".app\")\n                else:\n                    self.name = os.path.join(CONF['specpath'], self.name)\n                break\n        self.__postinit__()\n\n    _GUTS = (\n        # BUNDLE always builds, just want the toc to be written out\n        ('toc', None),\n    )\n\n    def _check_guts(self, data, last_build):\n        # BUNDLE always needs to be executed, since it will clean the output\n        # directory anyway to make sure there is no existing cruft accumulating\n        return 1\n\n    def assemble(self):\n        if _check_path_overlap(self.name) and os.path.isdir(self.name):\n            _rmtree(self.name)\n        logger.info(\"Building BUNDLE %s\", self.tocbasename)\n\n        # Create a minimal Mac bundle structure\n        os.makedirs(os.path.join(self.name, \"Contents\", \"MacOS\"))\n        os.makedirs(os.path.join(self.name, \"Contents\", \"Resources\"))\n        os.makedirs(os.path.join(self.name, \"Contents\", \"Frameworks\"))\n\n        # Copy icns icon to Resources directory.\n        if os.path.exists(self.icon):\n            shutil.copy(self.icon, os.path.join(self.name, 'Contents', 'Resources'))\n        else:\n            logger.warning(\"icon not found %s\", self.icon)\n\n        # Key/values for a minimal Info.plist file\n        info_plist_dict = {\"CFBundleDisplayName\": self.appname,\n                           \"CFBundleName\": self.appname,\n\n                           # Required by 'codesign' utility.\n                           # The value for CFBundleIdentifier is used as the default unique\n                           # name of your program for Code Signing purposes.\n                           # It even identifies the APP for access to restricted OS X areas\n                           # like Keychain.\n                           #\n                           # The identifier used for signing must be globally unique. The usal\n                           # form for this identifier is a hierarchical name in reverse DNS\n                           # notation, starting with the toplevel domain, followed by the\n                           # company name, followed by the department within the company, and\n                           # ending with the product name. Usually in the form:\n                           #   com.mycompany.department.appname\n                           # Cli option --osx-bundle-identifier sets this value.\n                           \"CFBundleIdentifier\": self.bundle_identifier,\n\n                           # Fix for #156 - 'MacOS' must be in the name - not sure why\n                           \"CFBundleExecutable\": 'MacOS/%s' % os.path.basename(self.exename),\n                           \"CFBundleIconFile\": os.path.basename(self.icon),\n                           \"CFBundleInfoDictionaryVersion\": \"6.0\",\n                           \"CFBundlePackageType\": \"APPL\",\n                           \"CFBundleShortVersionString\": self.version,\n\n                           }\n\n        # Set some default values.\n        # But they still can be overwritten by the user.\n        if self.console:\n            # Setting EXE console=True implies LSBackgroundOnly=True.\n            info_plist_dict['LSBackgroundOnly'] = True\n        else:\n            # Let's use high resolution by default.\n            info_plist_dict['NSHighResolutionCapable'] = True\n\n        # Merge info_plist settings from spec file\n        if isinstance(self.info_plist, dict) and self.info_plist:\n            info_plist_dict.update(self.info_plist)\n\n        plist_filename = os.path.join(self.name, \"Contents\", \"Info.plist\")\n        with open(plist_filename, \"wb\") as plist_fh:\n            plistlib.dump(info_plist_dict, plist_fh)\n\n        links = []\n        toc = add_suffix_to_extensions(self.toc)\n        for inm, fnm, typ in toc:\n            # Copy files from cache. This ensures that are used files with relative\n            # paths to dynamic library dependencies (@executable_path)\n            base_path = inm.split('/', 1)[0]\n            if typ in ('EXTENSION', 'BINARY'):\n                fnm = checkCache(fnm, strip=self.strip, upx=self.upx,\n                                 upx_exclude=self.upx_exclude, dist_nm=inm)\n            # Add most data files to a list for symlinking later.\n            if typ == 'DATA' and base_path not in ('PySide2', 'PyQt5'):\n                links.append((inm, fnm))\n            else:\n                tofnm = os.path.join(self.name, \"Contents\", \"MacOS\", inm)\n                todir = os.path.dirname(tofnm)\n                if not os.path.exists(todir):\n                    os.makedirs(todir)\n                if os.path.isdir(fnm):\n                    # beacuse shutil.copy2() is the default copy function\n                    # for shutil.copytree, this will also copy file metadata\n                    shutil.copytree(fnm, tofnm)\n                else:\n                    shutil.copy(fnm, tofnm)\n\n        logger.info('moving BUNDLE data files to Resource directory')\n\n        # Mac OS X Code Signing does not work when .app bundle contains\n        # data files in dir ./Contents/MacOS.\n        #\n        # Put all data files in ./Resources and create symlinks in ./MacOS.\n        bin_dir = os.path.join(self.name, 'Contents', 'MacOS')\n        res_dir = os.path.join(self.name, 'Contents', 'Resources')\n        for inm, fnm in links:\n            tofnm = os.path.join(res_dir, inm)\n            todir = os.path.dirname(tofnm)\n            if not os.path.exists(todir):\n                os.makedirs(todir)\n            if os.path.isdir(fnm):\n                # beacuse shutil.copy2() is the default copy function\n                # for shutil.copytree, this will also copy file metadata\n                shutil.copytree(fnm, tofnm)\n            else:\n                shutil.copy(fnm, tofnm)\n            base_path = os.path.split(inm)[0]\n            if base_path:\n                if not os.path.exists(os.path.join(bin_dir, inm)):\n                    path = ''\n                    for part in iter(base_path.split(os.path.sep)):\n                        # Build path from previous path and the next part of the base path\n                        path = os.path.join(path, part)\n                        try:\n                            relative_source_path = os.path.relpath(os.path.join(res_dir, path),\n                                                                   os.path.split(os.path.join(bin_dir, path))[0])\n                            dest_path = os.path.join(bin_dir, path)\n                            os.symlink(relative_source_path, dest_path)\n                            break\n                        except FileExistsError:\n                            pass\n                    if not os.path.exists(os.path.join(bin_dir, inm)):\n                        relative_source_path = os.path.relpath(os.path.join(res_dir, inm),\n                                                               os.path.split(os.path.join(bin_dir, inm))[0])\n                        dest_path = os.path.join(bin_dir, inm)\n                        os.symlink(relative_source_path, dest_path)\n            else:  # If path is empty, e.g., a top level file, try to just symlink the file\n                os.symlink(os.path.relpath(os.path.join(res_dir, inm),\n                                           os.path.split(os.path.join(bin_dir, inm))[0]),\n                           os.path.join(bin_dir, inm))\n", "path": "PyInstaller/building/osx.py"}], "after_files": [{"content": "#-----------------------------------------------------------------------------\n# Copyright (c) 2005-2020, PyInstaller Development Team.\n#\n# Distributed under the terms of the GNU General Public License (version 2\n# or later) with exception for distributing the bootloader.\n#\n# The full license is in the file COPYING.txt, distributed with this software.\n#\n# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception)\n#-----------------------------------------------------------------------------\n\nimport os\nimport plistlib\nimport shutil\nfrom ..compat import is_darwin\nfrom .api import EXE, COLLECT\nfrom .datastruct import Target, TOC, logger\nfrom .utils import _check_path_overlap, _rmtree, add_suffix_to_extensions, checkCache\n\n\n\nclass BUNDLE(Target):\n    def __init__(self, *args, **kws):\n        from ..config import CONF\n\n        # BUNDLE only has a sense under Mac OS X, it's a noop on other platforms\n        if not is_darwin:\n            return\n\n        # get a path to a .icns icon for the app bundle.\n        self.icon = kws.get('icon')\n        if not self.icon:\n            # --icon not specified; use the default in the pyinstaller folder\n            self.icon = os.path.join(os.path.dirname(os.path.dirname(__file__)),\n                'bootloader', 'images', 'icon-windowed.icns')\n        else:\n            # user gave an --icon=path. If it is relative, make it\n            # relative to the spec file location.\n            if not os.path.isabs(self.icon):\n                self.icon = os.path.join(CONF['specpath'], self.icon)\n        # ensure icon path is absolute\n        self.icon = os.path.abspath(self.icon)\n\n        Target.__init__(self)\n\n        # .app bundle is created in DISTPATH.\n        self.name = kws.get('name', None)\n        base_name = os.path.basename(self.name)\n        self.name = os.path.join(CONF['distpath'], base_name)\n\n        self.appname = os.path.splitext(base_name)[0]\n        self.version = kws.get(\"version\", \"0.0.0\")\n        self.toc = TOC()\n        self.strip = False\n        self.upx = False\n        self.console = True\n\n        # .app bundle identifier for Code Signing\n        self.bundle_identifier = kws.get('bundle_identifier')\n        if not self.bundle_identifier:\n            # Fallback to appname.\n            self.bundle_identifier = self.appname\n\n        self.info_plist = kws.get('info_plist', None)\n\n        for arg in args:\n            if isinstance(arg, EXE):\n                self.toc.append((os.path.basename(arg.name), arg.name, arg.typ))\n                self.toc.extend(arg.dependencies)\n                self.strip = arg.strip\n                self.upx = arg.upx\n                self.upx_exclude = arg.upx_exclude\n                self.console = arg.console\n            elif isinstance(arg, TOC):\n                self.toc.extend(arg)\n                # TOC doesn't have a strip or upx attribute, so there is no way for us to\n                # tell which cache we should draw from.\n            elif isinstance(arg, COLLECT):\n                self.toc.extend(arg.toc)\n                self.strip = arg.strip_binaries\n                self.upx = arg.upx_binaries\n                self.upx_exclude = arg.upx_exclude\n                self.console = arg.console\n            else:\n                logger.info(\"unsupported entry %s\", arg.__class__.__name__)\n        # Now, find values for app filepath (name), app name (appname), and name\n        # of the actual executable (exename) from the first EXECUTABLE item in\n        # toc, which might have come from a COLLECT too (not from an EXE).\n        for inm, name, typ in self.toc:\n            if typ == \"EXECUTABLE\":\n                self.exename = name\n                break\n        self.__postinit__()\n\n    _GUTS = (\n        # BUNDLE always builds, just want the toc to be written out\n        ('toc', None),\n    )\n\n    def _check_guts(self, data, last_build):\n        # BUNDLE always needs to be executed, since it will clean the output\n        # directory anyway to make sure there is no existing cruft accumulating\n        return 1\n\n    def assemble(self):\n        if _check_path_overlap(self.name) and os.path.isdir(self.name):\n            _rmtree(self.name)\n        logger.info(\"Building BUNDLE %s\", self.tocbasename)\n\n        # Create a minimal Mac bundle structure\n        os.makedirs(os.path.join(self.name, \"Contents\", \"MacOS\"))\n        os.makedirs(os.path.join(self.name, \"Contents\", \"Resources\"))\n        os.makedirs(os.path.join(self.name, \"Contents\", \"Frameworks\"))\n\n        # Copy icns icon to Resources directory.\n        if os.path.exists(self.icon):\n            shutil.copy(self.icon, os.path.join(self.name, 'Contents', 'Resources'))\n        else:\n            logger.warning(\"icon not found %s\", self.icon)\n\n        # Key/values for a minimal Info.plist file\n        info_plist_dict = {\"CFBundleDisplayName\": self.appname,\n                           \"CFBundleName\": self.appname,\n\n                           # Required by 'codesign' utility.\n                           # The value for CFBundleIdentifier is used as the default unique\n                           # name of your program for Code Signing purposes.\n                           # It even identifies the APP for access to restricted OS X areas\n                           # like Keychain.\n                           #\n                           # The identifier used for signing must be globally unique. The usal\n                           # form for this identifier is a hierarchical name in reverse DNS\n                           # notation, starting with the toplevel domain, followed by the\n                           # company name, followed by the department within the company, and\n                           # ending with the product name. Usually in the form:\n                           #   com.mycompany.department.appname\n                           # Cli option --osx-bundle-identifier sets this value.\n                           \"CFBundleIdentifier\": self.bundle_identifier,\n\n                           # Fix for #156 - 'MacOS' must be in the name - not sure why\n                           \"CFBundleExecutable\": 'MacOS/%s' % os.path.basename(self.exename),\n                           \"CFBundleIconFile\": os.path.basename(self.icon),\n                           \"CFBundleInfoDictionaryVersion\": \"6.0\",\n                           \"CFBundlePackageType\": \"APPL\",\n                           \"CFBundleShortVersionString\": self.version,\n\n                           }\n\n        # Set some default values.\n        # But they still can be overwritten by the user.\n        if self.console:\n            # Setting EXE console=True implies LSBackgroundOnly=True.\n            info_plist_dict['LSBackgroundOnly'] = True\n        else:\n            # Let's use high resolution by default.\n            info_plist_dict['NSHighResolutionCapable'] = True\n\n        # Merge info_plist settings from spec file\n        if isinstance(self.info_plist, dict) and self.info_plist:\n            info_plist_dict.update(self.info_plist)\n\n        plist_filename = os.path.join(self.name, \"Contents\", \"Info.plist\")\n        with open(plist_filename, \"wb\") as plist_fh:\n            plistlib.dump(info_plist_dict, plist_fh)\n\n        links = []\n        toc = add_suffix_to_extensions(self.toc)\n        for inm, fnm, typ in toc:\n            # Copy files from cache. This ensures that are used files with relative\n            # paths to dynamic library dependencies (@executable_path)\n            base_path = inm.split('/', 1)[0]\n            if typ in ('EXTENSION', 'BINARY'):\n                fnm = checkCache(fnm, strip=self.strip, upx=self.upx,\n                                 upx_exclude=self.upx_exclude, dist_nm=inm)\n            # Add most data files to a list for symlinking later.\n            if typ == 'DATA' and base_path not in ('PySide2', 'PyQt5'):\n                links.append((inm, fnm))\n            else:\n                tofnm = os.path.join(self.name, \"Contents\", \"MacOS\", inm)\n                todir = os.path.dirname(tofnm)\n                if not os.path.exists(todir):\n                    os.makedirs(todir)\n                if os.path.isdir(fnm):\n                    # beacuse shutil.copy2() is the default copy function\n                    # for shutil.copytree, this will also copy file metadata\n                    shutil.copytree(fnm, tofnm)\n                else:\n                    shutil.copy(fnm, tofnm)\n\n        logger.info('moving BUNDLE data files to Resource directory')\n\n        # Mac OS X Code Signing does not work when .app bundle contains\n        # data files in dir ./Contents/MacOS.\n        #\n        # Put all data files in ./Resources and create symlinks in ./MacOS.\n        bin_dir = os.path.join(self.name, 'Contents', 'MacOS')\n        res_dir = os.path.join(self.name, 'Contents', 'Resources')\n        for inm, fnm in links:\n            tofnm = os.path.join(res_dir, inm)\n            todir = os.path.dirname(tofnm)\n            if not os.path.exists(todir):\n                os.makedirs(todir)\n            if os.path.isdir(fnm):\n                # beacuse shutil.copy2() is the default copy function\n                # for shutil.copytree, this will also copy file metadata\n                shutil.copytree(fnm, tofnm)\n            else:\n                shutil.copy(fnm, tofnm)\n            base_path = os.path.split(inm)[0]\n            if base_path:\n                if not os.path.exists(os.path.join(bin_dir, inm)):\n                    path = ''\n                    for part in iter(base_path.split(os.path.sep)):\n                        # Build path from previous path and the next part of the base path\n                        path = os.path.join(path, part)\n                        try:\n                            relative_source_path = os.path.relpath(os.path.join(res_dir, path),\n                                                                   os.path.split(os.path.join(bin_dir, path))[0])\n                            dest_path = os.path.join(bin_dir, path)\n                            os.symlink(relative_source_path, dest_path)\n                            break\n                        except FileExistsError:\n                            pass\n                    if not os.path.exists(os.path.join(bin_dir, inm)):\n                        relative_source_path = os.path.relpath(os.path.join(res_dir, inm),\n                                                               os.path.split(os.path.join(bin_dir, inm))[0])\n                        dest_path = os.path.join(bin_dir, inm)\n                        os.symlink(relative_source_path, dest_path)\n            else:  # If path is empty, e.g., a top level file, try to just symlink the file\n                os.symlink(os.path.relpath(os.path.join(res_dir, inm),\n                                           os.path.split(os.path.join(bin_dir, inm))[0]),\n                           os.path.join(bin_dir, inm))\n", "path": "PyInstaller/building/osx.py"}]}