We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Git w/ Non Standard Port Broken on Poetry 1.0.0b4
<!-- Checked checkbox should look like this: [x] -->
- [x] I am on the [latest](https://github.com/sdispater/poetry/releases/latest) Poetry version.
- [x] I have searched the [issues](https://github.com/sdispater/poetry/issues) of this repo and believe that this is not a duplicate.
- [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).

- **OS version and name**: macOS 10.14.6
- **Poetry version**: 1.0.0b4
- **Link of a [Gist](https://gist.github.com/) with the contents of your pyproject.toml file**: See Below

## Issue
I'm trying to use a git+ssh URL to a private repo using a non standard port, like this:
```toml
package = {git = "ssh://git@path.to.private.repo.com:1234/repo/project.git"}
```
This leads to an error like this:
```
[ValueError]
Invalid git url ""
```

I think the issue may be here:
https://github.com/sdispater/poetry/blob/master/poetry/vcs/git.py#L16

Specifically, I think this regex is broken:
```python
r"(:?P<port>[\d]+)?"
```
Instead, I think it should look like:
```python
r"(?P<port>:[\d]+)?"
```

If someone doesn't beat me to it I'll likely submit a PR later today or tomorrow.

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `poetry/puzzle/solver.py`
Content:
```
1 import time
2 
3 from typing import Any
4 from typing import Dict
5 from typing import List
6 
7 from poetry.mixology import resolve_version
8 from poetry.mixology.failure import SolveFailure
9 from poetry.packages import DependencyPackage
10 from poetry.packages import Package
11 from poetry.semver import parse_constraint
12 from poetry.version.markers import AnyMarker
13 
14 from .exceptions import CompatibilityError
15 from .exceptions import SolverProblemError
16 from .operations import Install
17 from .operations import Uninstall
18 from .operations import Update
19 from .operations.operation import Operation
20 from .provider import Provider
21 
22 
23 class Solver:
24     def __init__(self, package, pool, installed, locked, io):
25         self._package = package
26         self._pool = pool
27         self._installed = installed
28         self._locked = locked
29         self._io = io
30         self._provider = Provider(self._package, self._pool, self._io)
31         self._branches = []
32 
33     def solve(self, use_latest=None):  # type: (...) -> List[Operation]
34         with self._provider.progress():
35             start = time.time()
36             packages, depths = self._solve(use_latest=use_latest)
37             end = time.time()
38 
39             if len(self._branches) > 1:
40                 self._provider.debug(
41                     "Complete version solving took {:.3f} seconds for {} branches".format(
42                         end - start, len(self._branches[1:])
43                     )
44                 )
45                 self._provider.debug(
46                     "Resolved for branches: {}".format(
47                         ", ".join("({})".format(b) for b in self._branches[1:])
48                     )
49                 )
50 
51         operations = []
52         for package in packages:
53             installed = False
54             for pkg in self._installed.packages:
55                 if package.name == pkg.name:
56                     installed = True
57 
58                     if pkg.source_type == "git" and package.source_type == "git":
59                         from poetry.vcs.git import Git
60 
61                         # Trying to find the currently installed version
62                         pkg_source_url = Git.normalize_url(pkg.source_url)
63                         package_source_url = Git.normalize_url(package.source_url)
64                         for locked in self._locked.packages:
65                             locked_source_url = Git.normalize_url(locked.source_url)
66                             if (
67                                 locked.name == pkg.name
68                                 and locked.source_type == pkg.source_type
69                                 and locked_source_url == pkg_source_url
70                                 and locked.source_reference == pkg.source_reference
71                             ):
72                                 pkg = Package(pkg.name, locked.version)
73                                 pkg.source_type = "git"
74                                 pkg.source_url = locked.source_url
75                                 pkg.source_reference = locked.source_reference
76                                 break
77 
78                         if pkg_source_url != package_source_url or (
79                             pkg.source_reference != package.source_reference
80                             and not pkg.source_reference.startswith(
81                                 package.source_reference
82                             )
83                         ):
84                             operations.append(Update(pkg, package))
85                         else:
86                             operations.append(
87                                 Install(package).skip("Already installed")
88                             )
89                     elif package.version != pkg.version:
90                         # Checking version
91                         operations.append(Update(pkg, package))
92                     elif package.source_type != pkg.source_type:
93                         operations.append(Update(pkg, package))
94                     else:
95                         operations.append(Install(package).skip("Already installed"))
96 
97                     break
98 
99             if not installed:
100                 operations.append(Install(package))
101 
102         # Checking for removals
103         for pkg in self._locked.packages:
104             remove = True
105             for package in packages:
106                 if pkg.name == package.name:
107                     remove = False
108                     break
109 
110             if remove:
111                 skip = True
112                 for installed in self._installed.packages:
113                     if installed.name == pkg.name:
114                         skip = False
115                         break
116 
117                 op = Uninstall(pkg)
118                 if skip:
119                     op.skip("Not currently installed")
120 
121                 operations.append(op)
122 
123         return sorted(
124             operations,
125             key=lambda o: (
126                 o.job_type == "uninstall",
127                 # Packages to be uninstalled have no depth so we default to 0
128                 # since it actually doesn't matter since removals are always on top.
129                 -depths[packages.index(o.package)] if o.job_type != "uninstall" else 0,
130                 o.package.name,
131                 o.package.version,
132             ),
133         )
134 
135     def solve_in_compatibility_mode(self, constraints, use_latest=None):
136         locked = {}
137         for package in self._locked.packages:
138             locked[package.name] = DependencyPackage(package.to_dependency(), package)
139 
140         packages = []
141         depths = []
142         for constraint in constraints:
143             constraint = parse_constraint(constraint)
144             intersection = constraint.intersect(self._package.python_constraint)
145 
146             self._provider.debug(
147                 "<comment>Retrying dependency resolution "
148                 "for Python ({}).</comment>".format(intersection)
149             )
150             with self._package.with_python_versions(str(intersection)):
151                 _packages, _depths = self._solve(use_latest=use_latest)
152                 for index, package in enumerate(_packages):
153                     if package not in packages:
154                         packages.append(package)
155                         depths.append(_depths[index])
156                         continue
157                     else:
158                         idx = packages.index(package)
159                         pkg = packages[idx]
160                         depths[idx] = max(depths[idx], _depths[index])
161                         pkg.marker = pkg.marker.union(package.marker)
162 
163                         for dep in package.requires:
164                             if dep not in pkg.requires:
165                                 pkg.requires.append(dep)
166 
167         return packages, depths
168 
169     def _solve(self, use_latest=None):
170         self._branches.append(self._package.python_versions)
171 
172         locked = {}
173         for package in self._locked.packages:
174             locked[package.name] = DependencyPackage(package.to_dependency(), package)
175 
176         try:
177             result = resolve_version(
178                 self._package, self._provider, locked=locked, use_latest=use_latest
179             )
180 
181             packages = result.packages
182         except CompatibilityError as e:
183             return self.solve_in_compatibility_mode(
184                 e.constraints, use_latest=use_latest
185             )
186         except SolveFailure as e:
187             raise SolverProblemError(e)
188 
189         graph = self._build_graph(self._package, packages)
190 
191         depths = []
192         final_packages = []
193         for package in packages:
194             category, optional, marker, depth = self._get_tags_for_package(
195                 package, graph
196             )
197 
198             if marker is None:
199                 marker = AnyMarker()
200             if marker.is_empty():
201                 continue
202 
203             package.category = category
204             package.optional = optional
205             package.marker = marker
206 
207             depths.append(depth)
208             final_packages.append(package)
209 
210         return final_packages, depths
211 
212     def _build_graph(
213         self, package, packages, previous=None, previous_dep=None, dep=None
214     ):  # type: (...) -> Dict[str, Any]
215         if not previous:
216             category = "dev"
217             optional = True
218             marker = package.marker
219         else:
220             category = dep.category
221             optional = dep.is_optional() and not dep.is_activated()
222             intersection = (
223                 previous["marker"]
224                 .without_extras()
225                 .intersect(previous_dep.marker.without_extras())
226             )
227             intersection = intersection.intersect(package.marker.without_extras())
228 
229             marker = intersection
230 
231         childrens = []  # type: List[Dict[str, Any]]
232         graph = {
233             "name": package.name,
234             "category": category,
235             "optional": optional,
236             "marker": marker,
237             "children": childrens,
238         }
239 
240         if previous_dep and previous_dep is not dep and previous_dep.name == dep.name:
241             return graph
242 
243         for dependency in package.all_requires:
244             is_activated = True
245             if dependency.is_optional():
246                 if not package.is_root() and (
247                     not previous_dep or not previous_dep.extras
248                 ):
249                     continue
250 
251                 is_activated = False
252                 for group, extra_deps in package.extras.items():
253                     if dep:
254                         extras = previous_dep.extras
255                     elif package.is_root():
256                         extras = package.extras
257                     else:
258                         extras = []
259 
260                     if group in extras and dependency.name in (
261                         d.name for d in package.extras[group]
262                     ):
263                         is_activated = True
264                         break
265 
266             if previous and previous["name"] == dependency.name:
267                 # We have a circular dependency.
268                 # Since the dependencies are resolved we can
269                 # simply skip it because we already have it
270                 continue
271 
272             for pkg in packages:
273                 if pkg.name == dependency.name and dependency.constraint.allows(
274                     pkg.version
275                 ):
276                     # If there is already a child with this name
277                     # we merge the requirements
278                     existing = None
279                     for child in childrens:
280                         if (
281                             child["name"] == pkg.name
282                             and child["category"] == dependency.category
283                         ):
284                             existing = child
285                             continue
286 
287                     child_graph = self._build_graph(
288                         pkg, packages, graph, dependency, dep or dependency
289                     )
290 
291                     if not is_activated:
292                         child_graph["optional"] = True
293 
294                     if existing:
295                         existing["marker"] = existing["marker"].union(
296                             child_graph["marker"]
297                         )
298                         continue
299 
300                     childrens.append(child_graph)
301 
302         return graph
303 
304     def _get_tags_for_package(self, package, graph, depth=0):
305         categories = ["dev"]
306         optionals = [True]
307         markers = []
308         _depths = [0]
309 
310         children = graph["children"]
311         for child in children:
312             if child["name"] == package.name:
313                 category = child["category"]
314                 optional = child["optional"]
315                 marker = child["marker"]
316                 _depths.append(depth)
317             else:
318                 (category, optional, marker, _depth) = self._get_tags_for_package(
319                     package, child, depth=depth + 1
320                 )
321 
322                 _depths.append(_depth)
323 
324             categories.append(category)
325             optionals.append(optional)
326             if marker is not None:
327                 markers.append(marker)
328 
329         if "main" in categories:
330             category = "main"
331         else:
332             category = "dev"
333 
334         optional = all(optionals)
335 
336         depth = max(*(_depths + [0]))
337 
338         if not markers:
339             marker = None
340         else:
341             marker = markers[0]
342             for m in markers[1:]:
343                 marker = marker.union(m)
344 
345         return category, optional, marker, depth
346
```
--- 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/poetry/puzzle/solver.py b/poetry/puzzle/solver.py
--- a/poetry/puzzle/solver.py
+++ b/poetry/puzzle/solver.py
@@ -62,6 +62,9 @@
                         pkg_source_url = Git.normalize_url(pkg.source_url)
                         package_source_url = Git.normalize_url(package.source_url)
                         for locked in self._locked.packages:
+                            if locked.name != pkg.name or locked.source_type != "git":
+                                continue
+
                             locked_source_url = Git.normalize_url(locked.source_url)
                             if (
                                 locked.name == pkg.name

{"golden_diff": "diff --git a/poetry/puzzle/solver.py b/poetry/puzzle/solver.py\n--- a/poetry/puzzle/solver.py\n+++ b/poetry/puzzle/solver.py\n@@ -62,6 +62,9 @@\n                         pkg_source_url = Git.normalize_url(pkg.source_url)\n                         package_source_url = Git.normalize_url(package.source_url)\n                         for locked in self._locked.packages:\n+                            if locked.name != pkg.name or locked.source_type != \"git\":\n+                                continue\n+\n                             locked_source_url = Git.normalize_url(locked.source_url)\n                             if (\n                                 locked.name == pkg.name\n", "issue": "Git w/ Non Standard Port Broken on Poetry 1.0.0b4\n<!-- Checked checkbox should look like this: [x] -->\r\n- [x] I am on the [latest](https://github.com/sdispater/poetry/releases/latest) Poetry version.\r\n- [x] I have searched the [issues](https://github.com/sdispater/poetry/issues) of this repo and believe that this is not a duplicate.\r\n- [x] If an exception occurs when executing a command, I executed it again in debug mode (`-vvv` option).\r\n\r\n- **OS version and name**: macOS 10.14.6\r\n- **Poetry version**: 1.0.0b4\r\n- **Link of a [Gist](https://gist.github.com/) with the contents of your pyproject.toml file**: See Below\r\n\r\n## Issue\r\nI'm trying to use a git+ssh URL to a private repo using a non standard port, like this:\r\n```toml\r\npackage = {git = \"ssh://git@path.to.private.repo.com:1234/repo/project.git\"}\r\n```\r\nThis leads to an error like this:\r\n```\r\n[ValueError]\r\nInvalid git url \"\"\r\n```\r\n\r\nI think the issue may be here:\r\nhttps://github.com/sdispater/poetry/blob/master/poetry/vcs/git.py#L16\r\n\r\nSpecifically, I think this regex is broken:\r\n```python\r\nr\"(:?P<port>[\\d]+)?\"\r\n```\r\nInstead, I think it should look like:\r\n```python\r\nr\"(?P<port>:[\\d]+)?\"\r\n```\r\n\r\nIf someone doesn't beat me to it I'll likely submit a PR later today or tomorrow.\n", "before_files": [{"content": "import time\n\nfrom typing import Any\nfrom typing import Dict\nfrom typing import List\n\nfrom poetry.mixology import resolve_version\nfrom poetry.mixology.failure import SolveFailure\nfrom poetry.packages import DependencyPackage\nfrom poetry.packages import Package\nfrom poetry.semver import parse_constraint\nfrom poetry.version.markers import AnyMarker\n\nfrom .exceptions import CompatibilityError\nfrom .exceptions import SolverProblemError\nfrom .operations import Install\nfrom .operations import Uninstall\nfrom .operations import Update\nfrom .operations.operation import Operation\nfrom .provider import Provider\n\n\nclass Solver:\n    def __init__(self, package, pool, installed, locked, io):\n        self._package = package\n        self._pool = pool\n        self._installed = installed\n        self._locked = locked\n        self._io = io\n        self._provider = Provider(self._package, self._pool, self._io)\n        self._branches = []\n\n    def solve(self, use_latest=None):  # type: (...) -> List[Operation]\n        with self._provider.progress():\n            start = time.time()\n            packages, depths = self._solve(use_latest=use_latest)\n            end = time.time()\n\n            if len(self._branches) > 1:\n                self._provider.debug(\n                    \"Complete version solving took {:.3f} seconds for {} branches\".format(\n                        end - start, len(self._branches[1:])\n                    )\n                )\n                self._provider.debug(\n                    \"Resolved for branches: {}\".format(\n                        \", \".join(\"({})\".format(b) for b in self._branches[1:])\n                    )\n                )\n\n        operations = []\n        for package in packages:\n            installed = False\n            for pkg in self._installed.packages:\n                if package.name == pkg.name:\n                    installed = True\n\n                    if pkg.source_type == \"git\" and package.source_type == \"git\":\n                        from poetry.vcs.git import Git\n\n                        # Trying to find the currently installed version\n                        pkg_source_url = Git.normalize_url(pkg.source_url)\n                        package_source_url = Git.normalize_url(package.source_url)\n                        for locked in self._locked.packages:\n                            locked_source_url = Git.normalize_url(locked.source_url)\n                            if (\n                                locked.name == pkg.name\n                                and locked.source_type == pkg.source_type\n                                and locked_source_url == pkg_source_url\n                                and locked.source_reference == pkg.source_reference\n                            ):\n                                pkg = Package(pkg.name, locked.version)\n                                pkg.source_type = \"git\"\n                                pkg.source_url = locked.source_url\n                                pkg.source_reference = locked.source_reference\n                                break\n\n                        if pkg_source_url != package_source_url or (\n                            pkg.source_reference != package.source_reference\n                            and not pkg.source_reference.startswith(\n                                package.source_reference\n                            )\n                        ):\n                            operations.append(Update(pkg, package))\n                        else:\n                            operations.append(\n                                Install(package).skip(\"Already installed\")\n                            )\n                    elif package.version != pkg.version:\n                        # Checking version\n                        operations.append(Update(pkg, package))\n                    elif package.source_type != pkg.source_type:\n                        operations.append(Update(pkg, package))\n                    else:\n                        operations.append(Install(package).skip(\"Already installed\"))\n\n                    break\n\n            if not installed:\n                operations.append(Install(package))\n\n        # Checking for removals\n        for pkg in self._locked.packages:\n            remove = True\n            for package in packages:\n                if pkg.name == package.name:\n                    remove = False\n                    break\n\n            if remove:\n                skip = True\n                for installed in self._installed.packages:\n                    if installed.name == pkg.name:\n                        skip = False\n                        break\n\n                op = Uninstall(pkg)\n                if skip:\n                    op.skip(\"Not currently installed\")\n\n                operations.append(op)\n\n        return sorted(\n            operations,\n            key=lambda o: (\n                o.job_type == \"uninstall\",\n                # Packages to be uninstalled have no depth so we default to 0\n                # since it actually doesn't matter since removals are always on top.\n                -depths[packages.index(o.package)] if o.job_type != \"uninstall\" else 0,\n                o.package.name,\n                o.package.version,\n            ),\n        )\n\n    def solve_in_compatibility_mode(self, constraints, use_latest=None):\n        locked = {}\n        for package in self._locked.packages:\n            locked[package.name] = DependencyPackage(package.to_dependency(), package)\n\n        packages = []\n        depths = []\n        for constraint in constraints:\n            constraint = parse_constraint(constraint)\n            intersection = constraint.intersect(self._package.python_constraint)\n\n            self._provider.debug(\n                \"<comment>Retrying dependency resolution \"\n                \"for Python ({}).</comment>\".format(intersection)\n            )\n            with self._package.with_python_versions(str(intersection)):\n                _packages, _depths = self._solve(use_latest=use_latest)\n                for index, package in enumerate(_packages):\n                    if package not in packages:\n                        packages.append(package)\n                        depths.append(_depths[index])\n                        continue\n                    else:\n                        idx = packages.index(package)\n                        pkg = packages[idx]\n                        depths[idx] = max(depths[idx], _depths[index])\n                        pkg.marker = pkg.marker.union(package.marker)\n\n                        for dep in package.requires:\n                            if dep not in pkg.requires:\n                                pkg.requires.append(dep)\n\n        return packages, depths\n\n    def _solve(self, use_latest=None):\n        self._branches.append(self._package.python_versions)\n\n        locked = {}\n        for package in self._locked.packages:\n            locked[package.name] = DependencyPackage(package.to_dependency(), package)\n\n        try:\n            result = resolve_version(\n                self._package, self._provider, locked=locked, use_latest=use_latest\n            )\n\n            packages = result.packages\n        except CompatibilityError as e:\n            return self.solve_in_compatibility_mode(\n                e.constraints, use_latest=use_latest\n            )\n        except SolveFailure as e:\n            raise SolverProblemError(e)\n\n        graph = self._build_graph(self._package, packages)\n\n        depths = []\n        final_packages = []\n        for package in packages:\n            category, optional, marker, depth = self._get_tags_for_package(\n                package, graph\n            )\n\n            if marker is None:\n                marker = AnyMarker()\n            if marker.is_empty():\n                continue\n\n            package.category = category\n            package.optional = optional\n            package.marker = marker\n\n            depths.append(depth)\n            final_packages.append(package)\n\n        return final_packages, depths\n\n    def _build_graph(\n        self, package, packages, previous=None, previous_dep=None, dep=None\n    ):  # type: (...) -> Dict[str, Any]\n        if not previous:\n            category = \"dev\"\n            optional = True\n            marker = package.marker\n        else:\n            category = dep.category\n            optional = dep.is_optional() and not dep.is_activated()\n            intersection = (\n                previous[\"marker\"]\n                .without_extras()\n                .intersect(previous_dep.marker.without_extras())\n            )\n            intersection = intersection.intersect(package.marker.without_extras())\n\n            marker = intersection\n\n        childrens = []  # type: List[Dict[str, Any]]\n        graph = {\n            \"name\": package.name,\n            \"category\": category,\n            \"optional\": optional,\n            \"marker\": marker,\n            \"children\": childrens,\n        }\n\n        if previous_dep and previous_dep is not dep and previous_dep.name == dep.name:\n            return graph\n\n        for dependency in package.all_requires:\n            is_activated = True\n            if dependency.is_optional():\n                if not package.is_root() and (\n                    not previous_dep or not previous_dep.extras\n                ):\n                    continue\n\n                is_activated = False\n                for group, extra_deps in package.extras.items():\n                    if dep:\n                        extras = previous_dep.extras\n                    elif package.is_root():\n                        extras = package.extras\n                    else:\n                        extras = []\n\n                    if group in extras and dependency.name in (\n                        d.name for d in package.extras[group]\n                    ):\n                        is_activated = True\n                        break\n\n            if previous and previous[\"name\"] == dependency.name:\n                # We have a circular dependency.\n                # Since the dependencies are resolved we can\n                # simply skip it because we already have it\n                continue\n\n            for pkg in packages:\n                if pkg.name == dependency.name and dependency.constraint.allows(\n                    pkg.version\n                ):\n                    # If there is already a child with this name\n                    # we merge the requirements\n                    existing = None\n                    for child in childrens:\n                        if (\n                            child[\"name\"] == pkg.name\n                            and child[\"category\"] == dependency.category\n                        ):\n                            existing = child\n                            continue\n\n                    child_graph = self._build_graph(\n                        pkg, packages, graph, dependency, dep or dependency\n                    )\n\n                    if not is_activated:\n                        child_graph[\"optional\"] = True\n\n                    if existing:\n                        existing[\"marker\"] = existing[\"marker\"].union(\n                            child_graph[\"marker\"]\n                        )\n                        continue\n\n                    childrens.append(child_graph)\n\n        return graph\n\n    def _get_tags_for_package(self, package, graph, depth=0):\n        categories = [\"dev\"]\n        optionals = [True]\n        markers = []\n        _depths = [0]\n\n        children = graph[\"children\"]\n        for child in children:\n            if child[\"name\"] == package.name:\n                category = child[\"category\"]\n                optional = child[\"optional\"]\n                marker = child[\"marker\"]\n                _depths.append(depth)\n            else:\n                (category, optional, marker, _depth) = self._get_tags_for_package(\n                    package, child, depth=depth + 1\n                )\n\n                _depths.append(_depth)\n\n            categories.append(category)\n            optionals.append(optional)\n            if marker is not None:\n                markers.append(marker)\n\n        if \"main\" in categories:\n            category = \"main\"\n        else:\n            category = \"dev\"\n\n        optional = all(optionals)\n\n        depth = max(*(_depths + [0]))\n\n        if not markers:\n            marker = None\n        else:\n            marker = markers[0]\n            for m in markers[1:]:\n                marker = marker.union(m)\n\n        return category, optional, marker, depth\n", "path": "poetry/puzzle/solver.py"}], "after_files": [{"content": "import time\n\nfrom typing import Any\nfrom typing import Dict\nfrom typing import List\n\nfrom poetry.mixology import resolve_version\nfrom poetry.mixology.failure import SolveFailure\nfrom poetry.packages import DependencyPackage\nfrom poetry.packages import Package\nfrom poetry.semver import parse_constraint\nfrom poetry.version.markers import AnyMarker\n\nfrom .exceptions import CompatibilityError\nfrom .exceptions import SolverProblemError\nfrom .operations import Install\nfrom .operations import Uninstall\nfrom .operations import Update\nfrom .operations.operation import Operation\nfrom .provider import Provider\n\n\nclass Solver:\n    def __init__(self, package, pool, installed, locked, io):\n        self._package = package\n        self._pool = pool\n        self._installed = installed\n        self._locked = locked\n        self._io = io\n        self._provider = Provider(self._package, self._pool, self._io)\n        self._branches = []\n\n    def solve(self, use_latest=None):  # type: (...) -> List[Operation]\n        with self._provider.progress():\n            start = time.time()\n            packages, depths = self._solve(use_latest=use_latest)\n            end = time.time()\n\n            if len(self._branches) > 1:\n                self._provider.debug(\n                    \"Complete version solving took {:.3f} seconds for {} branches\".format(\n                        end - start, len(self._branches[1:])\n                    )\n                )\n                self._provider.debug(\n                    \"Resolved for branches: {}\".format(\n                        \", \".join(\"({})\".format(b) for b in self._branches[1:])\n                    )\n                )\n\n        operations = []\n        for package in packages:\n            installed = False\n            for pkg in self._installed.packages:\n                if package.name == pkg.name:\n                    installed = True\n\n                    if pkg.source_type == \"git\" and package.source_type == \"git\":\n                        from poetry.vcs.git import Git\n\n                        # Trying to find the currently installed version\n                        pkg_source_url = Git.normalize_url(pkg.source_url)\n                        package_source_url = Git.normalize_url(package.source_url)\n                        for locked in self._locked.packages:\n                            if locked.name != pkg.name or locked.source_type != \"git\":\n                                continue\n\n                            locked_source_url = Git.normalize_url(locked.source_url)\n                            if (\n                                locked.name == pkg.name\n                                and locked.source_type == pkg.source_type\n                                and locked_source_url == pkg_source_url\n                                and locked.source_reference == pkg.source_reference\n                            ):\n                                pkg = Package(pkg.name, locked.version)\n                                pkg.source_type = \"git\"\n                                pkg.source_url = locked.source_url\n                                pkg.source_reference = locked.source_reference\n                                break\n\n                        if pkg_source_url != package_source_url or (\n                            pkg.source_reference != package.source_reference\n                            and not pkg.source_reference.startswith(\n                                package.source_reference\n                            )\n                        ):\n                            operations.append(Update(pkg, package))\n                        else:\n                            operations.append(\n                                Install(package).skip(\"Already installed\")\n                            )\n                    elif package.version != pkg.version:\n                        # Checking version\n                        operations.append(Update(pkg, package))\n                    elif package.source_type != pkg.source_type:\n                        operations.append(Update(pkg, package))\n                    else:\n                        operations.append(Install(package).skip(\"Already installed\"))\n\n                    break\n\n            if not installed:\n                operations.append(Install(package))\n\n        # Checking for removals\n        for pkg in self._locked.packages:\n            remove = True\n            for package in packages:\n                if pkg.name == package.name:\n                    remove = False\n                    break\n\n            if remove:\n                skip = True\n                for installed in self._installed.packages:\n                    if installed.name == pkg.name:\n                        skip = False\n                        break\n\n                op = Uninstall(pkg)\n                if skip:\n                    op.skip(\"Not currently installed\")\n\n                operations.append(op)\n\n        return sorted(\n            operations,\n            key=lambda o: (\n                o.job_type == \"uninstall\",\n                # Packages to be uninstalled have no depth so we default to 0\n                # since it actually doesn't matter since removals are always on top.\n                -depths[packages.index(o.package)] if o.job_type != \"uninstall\" else 0,\n                o.package.name,\n                o.package.version,\n            ),\n        )\n\n    def solve_in_compatibility_mode(self, constraints, use_latest=None):\n        locked = {}\n        for package in self._locked.packages:\n            locked[package.name] = DependencyPackage(package.to_dependency(), package)\n\n        packages = []\n        depths = []\n        for constraint in constraints:\n            constraint = parse_constraint(constraint)\n            intersection = constraint.intersect(self._package.python_constraint)\n\n            self._provider.debug(\n                \"<comment>Retrying dependency resolution \"\n                \"for Python ({}).</comment>\".format(intersection)\n            )\n            with self._package.with_python_versions(str(intersection)):\n                _packages, _depths = self._solve(use_latest=use_latest)\n                for index, package in enumerate(_packages):\n                    if package not in packages:\n                        packages.append(package)\n                        depths.append(_depths[index])\n                        continue\n                    else:\n                        idx = packages.index(package)\n                        pkg = packages[idx]\n                        depths[idx] = max(depths[idx], _depths[index])\n                        pkg.marker = pkg.marker.union(package.marker)\n\n                        for dep in package.requires:\n                            if dep not in pkg.requires:\n                                pkg.requires.append(dep)\n\n        return packages, depths\n\n    def _solve(self, use_latest=None):\n        self._branches.append(self._package.python_versions)\n\n        locked = {}\n        for package in self._locked.packages:\n            locked[package.name] = DependencyPackage(package.to_dependency(), package)\n\n        try:\n            result = resolve_version(\n                self._package, self._provider, locked=locked, use_latest=use_latest\n            )\n\n            packages = result.packages\n        except CompatibilityError as e:\n            return self.solve_in_compatibility_mode(\n                e.constraints, use_latest=use_latest\n            )\n        except SolveFailure as e:\n            raise SolverProblemError(e)\n\n        graph = self._build_graph(self._package, packages)\n\n        depths = []\n        final_packages = []\n        for package in packages:\n            category, optional, marker, depth = self._get_tags_for_package(\n                package, graph\n            )\n\n            if marker is None:\n                marker = AnyMarker()\n            if marker.is_empty():\n                continue\n\n            package.category = category\n            package.optional = optional\n            package.marker = marker\n\n            depths.append(depth)\n            final_packages.append(package)\n\n        return final_packages, depths\n\n    def _build_graph(\n        self, package, packages, previous=None, previous_dep=None, dep=None\n    ):  # type: (...) -> Dict[str, Any]\n        if not previous:\n            category = \"dev\"\n            optional = True\n            marker = package.marker\n        else:\n            category = dep.category\n            optional = dep.is_optional() and not dep.is_activated()\n            intersection = (\n                previous[\"marker\"]\n                .without_extras()\n                .intersect(previous_dep.marker.without_extras())\n            )\n            intersection = intersection.intersect(package.marker.without_extras())\n\n            marker = intersection\n\n        childrens = []  # type: List[Dict[str, Any]]\n        graph = {\n            \"name\": package.name,\n            \"category\": category,\n            \"optional\": optional,\n            \"marker\": marker,\n            \"children\": childrens,\n        }\n\n        if previous_dep and previous_dep is not dep and previous_dep.name == dep.name:\n            return graph\n\n        for dependency in package.all_requires:\n            is_activated = True\n            if dependency.is_optional():\n                if not package.is_root() and (\n                    not previous_dep or not previous_dep.extras\n                ):\n                    continue\n\n                is_activated = False\n                for group, extra_deps in package.extras.items():\n                    if dep:\n                        extras = previous_dep.extras\n                    elif package.is_root():\n                        extras = package.extras\n                    else:\n                        extras = []\n\n                    if group in extras and dependency.name in (\n                        d.name for d in package.extras[group]\n                    ):\n                        is_activated = True\n                        break\n\n            if previous and previous[\"name\"] == dependency.name:\n                # We have a circular dependency.\n                # Since the dependencies are resolved we can\n                # simply skip it because we already have it\n                continue\n\n            for pkg in packages:\n                if pkg.name == dependency.name and dependency.constraint.allows(\n                    pkg.version\n                ):\n                    # If there is already a child with this name\n                    # we merge the requirements\n                    existing = None\n                    for child in childrens:\n                        if (\n                            child[\"name\"] == pkg.name\n                            and child[\"category\"] == dependency.category\n                        ):\n                            existing = child\n                            continue\n\n                    child_graph = self._build_graph(\n                        pkg, packages, graph, dependency, dep or dependency\n                    )\n\n                    if not is_activated:\n                        child_graph[\"optional\"] = True\n\n                    if existing:\n                        existing[\"marker\"] = existing[\"marker\"].union(\n                            child_graph[\"marker\"]\n                        )\n                        continue\n\n                    childrens.append(child_graph)\n\n        return graph\n\n    def _get_tags_for_package(self, package, graph, depth=0):\n        categories = [\"dev\"]\n        optionals = [True]\n        markers = []\n        _depths = [0]\n\n        children = graph[\"children\"]\n        for child in children:\n            if child[\"name\"] == package.name:\n                category = child[\"category\"]\n                optional = child[\"optional\"]\n                marker = child[\"marker\"]\n                _depths.append(depth)\n            else:\n                (category, optional, marker, _depth) = self._get_tags_for_package(\n                    package, child, depth=depth + 1\n                )\n\n                _depths.append(_depth)\n\n            categories.append(category)\n            optionals.append(optional)\n            if marker is not None:\n                markers.append(marker)\n\n        if \"main\" in categories:\n            category = \"main\"\n        else:\n            category = \"dev\"\n\n        optional = all(optionals)\n\n        depth = max(*(_depths + [0]))\n\n        if not markers:\n            marker = None\n        else:\n            marker = markers[0]\n            for m in markers[1:]:\n                marker = marker.union(m)\n\n        return category, optional, marker, depth\n", "path": "poetry/puzzle/solver.py"}]}