We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Feature: pip-sync --dry-run should return a non-zero exit code if changes were to occur
#### What's the problem this feature will solve?
I'm looking to add a pre-commit hook to check the environment is up to date

```
-   repo: local
    hooks:
    -   id: pip-sync
        name: pip-sync check
        entry: pip-sync --dry-run
        language: system
        always_run: true
        pass_filenames: false
```

#### Describe the solution you'd like
```
$ pip-sync --dry-run
Would install:
  numpy==1.18.5
$ $?
2
```


#### Alternative Solutions
various | awk stuff

#### Additional context
NA


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `piptools/sync.py`
Content:
```
1 import collections
2 import os
3 import sys
4 import tempfile
5 from subprocess import check_call  # nosec
6 
7 from pip._internal.commands.freeze import DEV_PKGS
8 from pip._internal.utils.compat import stdlib_pkgs
9 
10 from . import click
11 from .exceptions import IncompatibleRequirements
12 from .utils import (
13     flat_map,
14     format_requirement,
15     get_hashes_from_ireq,
16     is_url_requirement,
17     key_from_ireq,
18     key_from_req,
19 )
20 
21 PACKAGES_TO_IGNORE = (
22     ["-markerlib", "pip", "pip-tools", "pip-review", "pkg-resources"]
23     + list(stdlib_pkgs)
24     + list(DEV_PKGS)
25 )
26 
27 
28 def dependency_tree(installed_keys, root_key):
29     """
30     Calculate the dependency tree for the package `root_key` and return
31     a collection of all its dependencies.  Uses a DFS traversal algorithm.
32 
33     `installed_keys` should be a {key: requirement} mapping, e.g.
34         {'django': from_line('django==1.8')}
35     `root_key` should be the key to return the dependency tree for.
36     """
37     dependencies = set()
38     queue = collections.deque()
39 
40     if root_key in installed_keys:
41         dep = installed_keys[root_key]
42         queue.append(dep)
43 
44     while queue:
45         v = queue.popleft()
46         key = key_from_req(v)
47         if key in dependencies:
48             continue
49 
50         dependencies.add(key)
51 
52         for dep_specifier in v.requires():
53             dep_name = key_from_req(dep_specifier)
54             if dep_name in installed_keys:
55                 dep = installed_keys[dep_name]
56 
57                 if dep_specifier.specifier.contains(dep.version):
58                     queue.append(dep)
59 
60     return dependencies
61 
62 
63 def get_dists_to_ignore(installed):
64     """
65     Returns a collection of package names to ignore when performing pip-sync,
66     based on the currently installed environment.  For example, when pip-tools
67     is installed in the local environment, it should be ignored, including all
68     of its dependencies (e.g. click).  When pip-tools is not installed
69     locally, click should also be installed/uninstalled depending on the given
70     requirements.
71     """
72     installed_keys = {key_from_req(r): r for r in installed}
73     return list(
74         flat_map(lambda req: dependency_tree(installed_keys, req), PACKAGES_TO_IGNORE)
75     )
76 
77 
78 def merge(requirements, ignore_conflicts):
79     by_key = {}
80 
81     for ireq in requirements:
82         # Limitation: URL requirements are merged by precise string match, so
83         # "file:///example.zip#egg=example", "file:///example.zip", and
84         # "example==1.0" will not merge with each other
85         if ireq.match_markers():
86             key = key_from_ireq(ireq)
87 
88             if not ignore_conflicts:
89                 existing_ireq = by_key.get(key)
90                 if existing_ireq:
91                     # NOTE: We check equality here since we can assume that the
92                     # requirements are all pinned
93                     if ireq.specifier != existing_ireq.specifier:
94                         raise IncompatibleRequirements(ireq, existing_ireq)
95 
96             # TODO: Always pick the largest specifier in case of a conflict
97             by_key[key] = ireq
98     return by_key.values()
99 
100 
101 def diff_key_from_ireq(ireq):
102     """
103     Calculate a key for comparing a compiled requirement with installed modules.
104     For URL requirements, only provide a useful key if the url includes
105     #egg=name==version, which will set ireq.req.name and ireq.specifier.
106     Otherwise return ireq.link so the key will not match and the package will
107     reinstall. Reinstall is necessary to ensure that packages will reinstall
108     if the URL is changed but the version is not.
109     """
110     if is_url_requirement(ireq):
111         if (
112             ireq.req
113             and (getattr(ireq.req, "key", None) or getattr(ireq.req, "name", None))
114             and ireq.specifier
115         ):
116             return key_from_ireq(ireq)
117         return str(ireq.link)
118     return key_from_ireq(ireq)
119 
120 
121 def diff(compiled_requirements, installed_dists):
122     """
123     Calculate which packages should be installed or uninstalled, given a set
124     of compiled requirements and a list of currently installed modules.
125     """
126     requirements_lut = {diff_key_from_ireq(r): r for r in compiled_requirements}
127 
128     satisfied = set()  # holds keys
129     to_install = set()  # holds InstallRequirement objects
130     to_uninstall = set()  # holds keys
131 
132     pkgs_to_ignore = get_dists_to_ignore(installed_dists)
133     for dist in installed_dists:
134         key = key_from_req(dist)
135         if key not in requirements_lut or not requirements_lut[key].match_markers():
136             to_uninstall.add(key)
137         elif requirements_lut[key].specifier.contains(dist.version):
138             satisfied.add(key)
139 
140     for key, requirement in requirements_lut.items():
141         if key not in satisfied and requirement.match_markers():
142             to_install.add(requirement)
143 
144     # Make sure to not uninstall any packages that should be ignored
145     to_uninstall -= set(pkgs_to_ignore)
146 
147     return (to_install, to_uninstall)
148 
149 
150 def sync(
151     to_install,
152     to_uninstall,
153     verbose=False,
154     dry_run=False,
155     install_flags=None,
156     ask=False,
157 ):
158     """
159     Install and uninstalls the given sets of modules.
160     """
161     if not to_uninstall and not to_install:
162         if verbose:
163             click.echo("Everything up-to-date")
164         return 0
165 
166     pip_flags = []
167     if not verbose:
168         pip_flags += ["-q"]
169 
170     if ask:
171         dry_run = True
172 
173     if dry_run:
174         if to_uninstall:
175             click.echo("Would uninstall:")
176             for pkg in sorted(to_uninstall):
177                 click.echo("  {}".format(pkg))
178 
179         if to_install:
180             click.echo("Would install:")
181             for ireq in sorted(to_install, key=key_from_ireq):
182                 click.echo("  {}".format(format_requirement(ireq)))
183 
184     if ask and click.confirm("Would you like to proceed with these changes?"):
185         dry_run = False
186 
187     if not dry_run:
188         if to_uninstall:
189             check_call(  # nosec
190                 [sys.executable, "-m", "pip", "uninstall", "-y"]
191                 + pip_flags
192                 + sorted(to_uninstall)
193             )
194 
195         if to_install:
196             if install_flags is None:
197                 install_flags = []
198             # prepare requirement lines
199             req_lines = []
200             for ireq in sorted(to_install, key=key_from_ireq):
201                 ireq_hashes = get_hashes_from_ireq(ireq)
202                 req_lines.append(format_requirement(ireq, hashes=ireq_hashes))
203 
204             # save requirement lines to a temporary file
205             tmp_req_file = tempfile.NamedTemporaryFile(mode="wt", delete=False)
206             tmp_req_file.write("\n".join(req_lines))
207             tmp_req_file.close()
208 
209             try:
210                 check_call(  # nosec
211                     [sys.executable, "-m", "pip", "install", "-r", tmp_req_file.name]
212                     + pip_flags
213                     + install_flags
214                 )
215             finally:
216                 os.unlink(tmp_req_file.name)
217 
218     return 0
219
```
--- 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/piptools/sync.py b/piptools/sync.py
--- a/piptools/sync.py
+++ b/piptools/sync.py
@@ -158,10 +158,12 @@
     """
     Install and uninstalls the given sets of modules.
     """
+    exit_code = 0
+
     if not to_uninstall and not to_install:
         if verbose:
             click.echo("Everything up-to-date")
-        return 0
+        return exit_code
 
     pip_flags = []
     if not verbose:
@@ -181,8 +183,11 @@
             for ireq in sorted(to_install, key=key_from_ireq):
                 click.echo("  {}".format(format_requirement(ireq)))
 
+        exit_code = 1
+
     if ask and click.confirm("Would you like to proceed with these changes?"):
         dry_run = False
+        exit_code = 0
 
     if not dry_run:
         if to_uninstall:
@@ -215,4 +220,4 @@
             finally:
                 os.unlink(tmp_req_file.name)
 
-    return 0
+    return exit_code

{"golden_diff": "diff --git a/piptools/sync.py b/piptools/sync.py\n--- a/piptools/sync.py\n+++ b/piptools/sync.py\n@@ -158,10 +158,12 @@\n     \"\"\"\n     Install and uninstalls the given sets of modules.\n     \"\"\"\n+    exit_code = 0\n+\n     if not to_uninstall and not to_install:\n         if verbose:\n             click.echo(\"Everything up-to-date\")\n-        return 0\n+        return exit_code\n \n     pip_flags = []\n     if not verbose:\n@@ -181,8 +183,11 @@\n             for ireq in sorted(to_install, key=key_from_ireq):\n                 click.echo(\"  {}\".format(format_requirement(ireq)))\n \n+        exit_code = 1\n+\n     if ask and click.confirm(\"Would you like to proceed with these changes?\"):\n         dry_run = False\n+        exit_code = 0\n \n     if not dry_run:\n         if to_uninstall:\n@@ -215,4 +220,4 @@\n             finally:\n                 os.unlink(tmp_req_file.name)\n \n-    return 0\n+    return exit_code\n", "issue": "Feature: pip-sync --dry-run should return a non-zero exit code if changes were to occur\n#### What's the problem this feature will solve?\r\nI'm looking to add a pre-commit hook to check the environment is up to date\r\n\r\n```\r\n-   repo: local\r\n    hooks:\r\n    -   id: pip-sync\r\n        name: pip-sync check\r\n        entry: pip-sync --dry-run\r\n        language: system\r\n        always_run: true\r\n        pass_filenames: false\r\n```\r\n\r\n#### Describe the solution you'd like\r\n```\r\n$ pip-sync --dry-run\r\nWould install:\r\n  numpy==1.18.5\r\n$ $?\r\n2\r\n```\r\n\r\n\r\n#### Alternative Solutions\r\nvarious | awk stuff\r\n\r\n#### Additional context\r\nNA\r\n\n", "before_files": [{"content": "import collections\nimport os\nimport sys\nimport tempfile\nfrom subprocess import check_call  # nosec\n\nfrom pip._internal.commands.freeze import DEV_PKGS\nfrom pip._internal.utils.compat import stdlib_pkgs\n\nfrom . import click\nfrom .exceptions import IncompatibleRequirements\nfrom .utils import (\n    flat_map,\n    format_requirement,\n    get_hashes_from_ireq,\n    is_url_requirement,\n    key_from_ireq,\n    key_from_req,\n)\n\nPACKAGES_TO_IGNORE = (\n    [\"-markerlib\", \"pip\", \"pip-tools\", \"pip-review\", \"pkg-resources\"]\n    + list(stdlib_pkgs)\n    + list(DEV_PKGS)\n)\n\n\ndef dependency_tree(installed_keys, root_key):\n    \"\"\"\n    Calculate the dependency tree for the package `root_key` and return\n    a collection of all its dependencies.  Uses a DFS traversal algorithm.\n\n    `installed_keys` should be a {key: requirement} mapping, e.g.\n        {'django': from_line('django==1.8')}\n    `root_key` should be the key to return the dependency tree for.\n    \"\"\"\n    dependencies = set()\n    queue = collections.deque()\n\n    if root_key in installed_keys:\n        dep = installed_keys[root_key]\n        queue.append(dep)\n\n    while queue:\n        v = queue.popleft()\n        key = key_from_req(v)\n        if key in dependencies:\n            continue\n\n        dependencies.add(key)\n\n        for dep_specifier in v.requires():\n            dep_name = key_from_req(dep_specifier)\n            if dep_name in installed_keys:\n                dep = installed_keys[dep_name]\n\n                if dep_specifier.specifier.contains(dep.version):\n                    queue.append(dep)\n\n    return dependencies\n\n\ndef get_dists_to_ignore(installed):\n    \"\"\"\n    Returns a collection of package names to ignore when performing pip-sync,\n    based on the currently installed environment.  For example, when pip-tools\n    is installed in the local environment, it should be ignored, including all\n    of its dependencies (e.g. click).  When pip-tools is not installed\n    locally, click should also be installed/uninstalled depending on the given\n    requirements.\n    \"\"\"\n    installed_keys = {key_from_req(r): r for r in installed}\n    return list(\n        flat_map(lambda req: dependency_tree(installed_keys, req), PACKAGES_TO_IGNORE)\n    )\n\n\ndef merge(requirements, ignore_conflicts):\n    by_key = {}\n\n    for ireq in requirements:\n        # Limitation: URL requirements are merged by precise string match, so\n        # \"file:///example.zip#egg=example\", \"file:///example.zip\", and\n        # \"example==1.0\" will not merge with each other\n        if ireq.match_markers():\n            key = key_from_ireq(ireq)\n\n            if not ignore_conflicts:\n                existing_ireq = by_key.get(key)\n                if existing_ireq:\n                    # NOTE: We check equality here since we can assume that the\n                    # requirements are all pinned\n                    if ireq.specifier != existing_ireq.specifier:\n                        raise IncompatibleRequirements(ireq, existing_ireq)\n\n            # TODO: Always pick the largest specifier in case of a conflict\n            by_key[key] = ireq\n    return by_key.values()\n\n\ndef diff_key_from_ireq(ireq):\n    \"\"\"\n    Calculate a key for comparing a compiled requirement with installed modules.\n    For URL requirements, only provide a useful key if the url includes\n    #egg=name==version, which will set ireq.req.name and ireq.specifier.\n    Otherwise return ireq.link so the key will not match and the package will\n    reinstall. Reinstall is necessary to ensure that packages will reinstall\n    if the URL is changed but the version is not.\n    \"\"\"\n    if is_url_requirement(ireq):\n        if (\n            ireq.req\n            and (getattr(ireq.req, \"key\", None) or getattr(ireq.req, \"name\", None))\n            and ireq.specifier\n        ):\n            return key_from_ireq(ireq)\n        return str(ireq.link)\n    return key_from_ireq(ireq)\n\n\ndef diff(compiled_requirements, installed_dists):\n    \"\"\"\n    Calculate which packages should be installed or uninstalled, given a set\n    of compiled requirements and a list of currently installed modules.\n    \"\"\"\n    requirements_lut = {diff_key_from_ireq(r): r for r in compiled_requirements}\n\n    satisfied = set()  # holds keys\n    to_install = set()  # holds InstallRequirement objects\n    to_uninstall = set()  # holds keys\n\n    pkgs_to_ignore = get_dists_to_ignore(installed_dists)\n    for dist in installed_dists:\n        key = key_from_req(dist)\n        if key not in requirements_lut or not requirements_lut[key].match_markers():\n            to_uninstall.add(key)\n        elif requirements_lut[key].specifier.contains(dist.version):\n            satisfied.add(key)\n\n    for key, requirement in requirements_lut.items():\n        if key not in satisfied and requirement.match_markers():\n            to_install.add(requirement)\n\n    # Make sure to not uninstall any packages that should be ignored\n    to_uninstall -= set(pkgs_to_ignore)\n\n    return (to_install, to_uninstall)\n\n\ndef sync(\n    to_install,\n    to_uninstall,\n    verbose=False,\n    dry_run=False,\n    install_flags=None,\n    ask=False,\n):\n    \"\"\"\n    Install and uninstalls the given sets of modules.\n    \"\"\"\n    if not to_uninstall and not to_install:\n        if verbose:\n            click.echo(\"Everything up-to-date\")\n        return 0\n\n    pip_flags = []\n    if not verbose:\n        pip_flags += [\"-q\"]\n\n    if ask:\n        dry_run = True\n\n    if dry_run:\n        if to_uninstall:\n            click.echo(\"Would uninstall:\")\n            for pkg in sorted(to_uninstall):\n                click.echo(\"  {}\".format(pkg))\n\n        if to_install:\n            click.echo(\"Would install:\")\n            for ireq in sorted(to_install, key=key_from_ireq):\n                click.echo(\"  {}\".format(format_requirement(ireq)))\n\n    if ask and click.confirm(\"Would you like to proceed with these changes?\"):\n        dry_run = False\n\n    if not dry_run:\n        if to_uninstall:\n            check_call(  # nosec\n                [sys.executable, \"-m\", \"pip\", \"uninstall\", \"-y\"]\n                + pip_flags\n                + sorted(to_uninstall)\n            )\n\n        if to_install:\n            if install_flags is None:\n                install_flags = []\n            # prepare requirement lines\n            req_lines = []\n            for ireq in sorted(to_install, key=key_from_ireq):\n                ireq_hashes = get_hashes_from_ireq(ireq)\n                req_lines.append(format_requirement(ireq, hashes=ireq_hashes))\n\n            # save requirement lines to a temporary file\n            tmp_req_file = tempfile.NamedTemporaryFile(mode=\"wt\", delete=False)\n            tmp_req_file.write(\"\\n\".join(req_lines))\n            tmp_req_file.close()\n\n            try:\n                check_call(  # nosec\n                    [sys.executable, \"-m\", \"pip\", \"install\", \"-r\", tmp_req_file.name]\n                    + pip_flags\n                    + install_flags\n                )\n            finally:\n                os.unlink(tmp_req_file.name)\n\n    return 0\n", "path": "piptools/sync.py"}], "after_files": [{"content": "import collections\nimport os\nimport sys\nimport tempfile\nfrom subprocess import check_call  # nosec\n\nfrom pip._internal.commands.freeze import DEV_PKGS\nfrom pip._internal.utils.compat import stdlib_pkgs\n\nfrom . import click\nfrom .exceptions import IncompatibleRequirements\nfrom .utils import (\n    flat_map,\n    format_requirement,\n    get_hashes_from_ireq,\n    is_url_requirement,\n    key_from_ireq,\n    key_from_req,\n)\n\nPACKAGES_TO_IGNORE = (\n    [\"-markerlib\", \"pip\", \"pip-tools\", \"pip-review\", \"pkg-resources\"]\n    + list(stdlib_pkgs)\n    + list(DEV_PKGS)\n)\n\n\ndef dependency_tree(installed_keys, root_key):\n    \"\"\"\n    Calculate the dependency tree for the package `root_key` and return\n    a collection of all its dependencies.  Uses a DFS traversal algorithm.\n\n    `installed_keys` should be a {key: requirement} mapping, e.g.\n        {'django': from_line('django==1.8')}\n    `root_key` should be the key to return the dependency tree for.\n    \"\"\"\n    dependencies = set()\n    queue = collections.deque()\n\n    if root_key in installed_keys:\n        dep = installed_keys[root_key]\n        queue.append(dep)\n\n    while queue:\n        v = queue.popleft()\n        key = key_from_req(v)\n        if key in dependencies:\n            continue\n\n        dependencies.add(key)\n\n        for dep_specifier in v.requires():\n            dep_name = key_from_req(dep_specifier)\n            if dep_name in installed_keys:\n                dep = installed_keys[dep_name]\n\n                if dep_specifier.specifier.contains(dep.version):\n                    queue.append(dep)\n\n    return dependencies\n\n\ndef get_dists_to_ignore(installed):\n    \"\"\"\n    Returns a collection of package names to ignore when performing pip-sync,\n    based on the currently installed environment.  For example, when pip-tools\n    is installed in the local environment, it should be ignored, including all\n    of its dependencies (e.g. click).  When pip-tools is not installed\n    locally, click should also be installed/uninstalled depending on the given\n    requirements.\n    \"\"\"\n    installed_keys = {key_from_req(r): r for r in installed}\n    return list(\n        flat_map(lambda req: dependency_tree(installed_keys, req), PACKAGES_TO_IGNORE)\n    )\n\n\ndef merge(requirements, ignore_conflicts):\n    by_key = {}\n\n    for ireq in requirements:\n        # Limitation: URL requirements are merged by precise string match, so\n        # \"file:///example.zip#egg=example\", \"file:///example.zip\", and\n        # \"example==1.0\" will not merge with each other\n        if ireq.match_markers():\n            key = key_from_ireq(ireq)\n\n            if not ignore_conflicts:\n                existing_ireq = by_key.get(key)\n                if existing_ireq:\n                    # NOTE: We check equality here since we can assume that the\n                    # requirements are all pinned\n                    if ireq.specifier != existing_ireq.specifier:\n                        raise IncompatibleRequirements(ireq, existing_ireq)\n\n            # TODO: Always pick the largest specifier in case of a conflict\n            by_key[key] = ireq\n    return by_key.values()\n\n\ndef diff_key_from_ireq(ireq):\n    \"\"\"\n    Calculate a key for comparing a compiled requirement with installed modules.\n    For URL requirements, only provide a useful key if the url includes\n    #egg=name==version, which will set ireq.req.name and ireq.specifier.\n    Otherwise return ireq.link so the key will not match and the package will\n    reinstall. Reinstall is necessary to ensure that packages will reinstall\n    if the URL is changed but the version is not.\n    \"\"\"\n    if is_url_requirement(ireq):\n        if (\n            ireq.req\n            and (getattr(ireq.req, \"key\", None) or getattr(ireq.req, \"name\", None))\n            and ireq.specifier\n        ):\n            return key_from_ireq(ireq)\n        return str(ireq.link)\n    return key_from_ireq(ireq)\n\n\ndef diff(compiled_requirements, installed_dists):\n    \"\"\"\n    Calculate which packages should be installed or uninstalled, given a set\n    of compiled requirements and a list of currently installed modules.\n    \"\"\"\n    requirements_lut = {diff_key_from_ireq(r): r for r in compiled_requirements}\n\n    satisfied = set()  # holds keys\n    to_install = set()  # holds InstallRequirement objects\n    to_uninstall = set()  # holds keys\n\n    pkgs_to_ignore = get_dists_to_ignore(installed_dists)\n    for dist in installed_dists:\n        key = key_from_req(dist)\n        if key not in requirements_lut or not requirements_lut[key].match_markers():\n            to_uninstall.add(key)\n        elif requirements_lut[key].specifier.contains(dist.version):\n            satisfied.add(key)\n\n    for key, requirement in requirements_lut.items():\n        if key not in satisfied and requirement.match_markers():\n            to_install.add(requirement)\n\n    # Make sure to not uninstall any packages that should be ignored\n    to_uninstall -= set(pkgs_to_ignore)\n\n    return (to_install, to_uninstall)\n\n\ndef sync(\n    to_install,\n    to_uninstall,\n    verbose=False,\n    dry_run=False,\n    install_flags=None,\n    ask=False,\n):\n    \"\"\"\n    Install and uninstalls the given sets of modules.\n    \"\"\"\n    exit_code = 0\n\n    if not to_uninstall and not to_install:\n        if verbose:\n            click.echo(\"Everything up-to-date\")\n        return exit_code\n\n    pip_flags = []\n    if not verbose:\n        pip_flags += [\"-q\"]\n\n    if ask:\n        dry_run = True\n\n    if dry_run:\n        if to_uninstall:\n            click.echo(\"Would uninstall:\")\n            for pkg in sorted(to_uninstall):\n                click.echo(\"  {}\".format(pkg))\n\n        if to_install:\n            click.echo(\"Would install:\")\n            for ireq in sorted(to_install, key=key_from_ireq):\n                click.echo(\"  {}\".format(format_requirement(ireq)))\n\n        exit_code = 1\n\n    if ask and click.confirm(\"Would you like to proceed with these changes?\"):\n        dry_run = False\n        exit_code = 0\n\n    if not dry_run:\n        if to_uninstall:\n            check_call(  # nosec\n                [sys.executable, \"-m\", \"pip\", \"uninstall\", \"-y\"]\n                + pip_flags\n                + sorted(to_uninstall)\n            )\n\n        if to_install:\n            if install_flags is None:\n                install_flags = []\n            # prepare requirement lines\n            req_lines = []\n            for ireq in sorted(to_install, key=key_from_ireq):\n                ireq_hashes = get_hashes_from_ireq(ireq)\n                req_lines.append(format_requirement(ireq, hashes=ireq_hashes))\n\n            # save requirement lines to a temporary file\n            tmp_req_file = tempfile.NamedTemporaryFile(mode=\"wt\", delete=False)\n            tmp_req_file.write(\"\\n\".join(req_lines))\n            tmp_req_file.close()\n\n            try:\n                check_call(  # nosec\n                    [sys.executable, \"-m\", \"pip\", \"install\", \"-r\", tmp_req_file.name]\n                    + pip_flags\n                    + install_flags\n                )\n            finally:\n                os.unlink(tmp_req_file.name)\n\n    return exit_code\n", "path": "piptools/sync.py"}]}