thefuck-leeguoo 3.41__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (218) hide show
  1. thefuck/__init__.py +0 -0
  2. thefuck/ai.py +765 -0
  3. thefuck/argument_parser.py +96 -0
  4. thefuck/conf.py +141 -0
  5. thefuck/const.py +111 -0
  6. thefuck/corrector.py +92 -0
  7. thefuck/entrypoints/__init__.py +0 -0
  8. thefuck/entrypoints/alias.py +28 -0
  9. thefuck/entrypoints/fix_command.py +105 -0
  10. thefuck/entrypoints/main.py +50 -0
  11. thefuck/entrypoints/not_configured.py +201 -0
  12. thefuck/entrypoints/setup.py +227 -0
  13. thefuck/entrypoints/shell_logger.py +79 -0
  14. thefuck/exceptions.py +10 -0
  15. thefuck/logs.py +255 -0
  16. thefuck/output_readers/__init__.py +20 -0
  17. thefuck/output_readers/read_log.py +108 -0
  18. thefuck/output_readers/rerun.py +72 -0
  19. thefuck/output_readers/shell_logger.py +60 -0
  20. thefuck/rules/__init__.py +0 -0
  21. thefuck/rules/adb_unknown_command.py +54 -0
  22. thefuck/rules/ag_literal.py +10 -0
  23. thefuck/rules/apt_get.py +50 -0
  24. thefuck/rules/apt_get_search.py +14 -0
  25. thefuck/rules/apt_invalid_operation.py +63 -0
  26. thefuck/rules/apt_list_upgradable.py +16 -0
  27. thefuck/rules/apt_upgrade.py +16 -0
  28. thefuck/rules/aws_cli.py +17 -0
  29. thefuck/rules/az_cli.py +17 -0
  30. thefuck/rules/brew_cask_dependency.py +33 -0
  31. thefuck/rules/brew_install.py +24 -0
  32. thefuck/rules/brew_link.py +15 -0
  33. thefuck/rules/brew_reinstall.py +19 -0
  34. thefuck/rules/brew_uninstall.py +14 -0
  35. thefuck/rules/brew_unknown_command.py +82 -0
  36. thefuck/rules/brew_update_formula.py +12 -0
  37. thefuck/rules/cargo.py +6 -0
  38. thefuck/rules/cargo_no_command.py +15 -0
  39. thefuck/rules/cat_dir.py +14 -0
  40. thefuck/rules/cd_correction.py +61 -0
  41. thefuck/rules/cd_cs.py +21 -0
  42. thefuck/rules/cd_mkdir.py +21 -0
  43. thefuck/rules/cd_parent.py +16 -0
  44. thefuck/rules/chmod_x.py +15 -0
  45. thefuck/rules/choco_install.py +25 -0
  46. thefuck/rules/composer_not_command.py +22 -0
  47. thefuck/rules/conda_mistype.py +17 -0
  48. thefuck/rules/cp_create_destination.py +15 -0
  49. thefuck/rules/cp_omitting_directory.py +15 -0
  50. thefuck/rules/cpp11.py +12 -0
  51. thefuck/rules/dirty_untar.py +53 -0
  52. thefuck/rules/dirty_unzip.py +60 -0
  53. thefuck/rules/django_south_ghost.py +8 -0
  54. thefuck/rules/django_south_merge.py +8 -0
  55. thefuck/rules/dnf_no_such_command.py +37 -0
  56. thefuck/rules/docker_image_being_used_by_container.py +20 -0
  57. thefuck/rules/docker_login.py +13 -0
  58. thefuck/rules/docker_not_command.py +49 -0
  59. thefuck/rules/dry.py +15 -0
  60. thefuck/rules/fab_command_not_found.py +38 -0
  61. thefuck/rules/fix_alt_space.py +15 -0
  62. thefuck/rules/fix_file.py +80 -0
  63. thefuck/rules/gem_unknown_command.py +36 -0
  64. thefuck/rules/git_add.py +27 -0
  65. thefuck/rules/git_add_force.py +13 -0
  66. thefuck/rules/git_bisect_usage.py +16 -0
  67. thefuck/rules/git_branch_0flag.py +24 -0
  68. thefuck/rules/git_branch_delete.py +13 -0
  69. thefuck/rules/git_branch_delete_checked_out.py +19 -0
  70. thefuck/rules/git_branch_exists.py +25 -0
  71. thefuck/rules/git_branch_list.py +14 -0
  72. thefuck/rules/git_checkout.py +49 -0
  73. thefuck/rules/git_clone_git_clone.py +12 -0
  74. thefuck/rules/git_clone_missing.py +42 -0
  75. thefuck/rules/git_commit_add.py +17 -0
  76. thefuck/rules/git_commit_amend.py +11 -0
  77. thefuck/rules/git_commit_reset.py +11 -0
  78. thefuck/rules/git_diff_no_index.py +16 -0
  79. thefuck/rules/git_diff_staged.py +13 -0
  80. thefuck/rules/git_fix_stash.py +37 -0
  81. thefuck/rules/git_flag_after_filename.py +31 -0
  82. thefuck/rules/git_help_aliased.py +12 -0
  83. thefuck/rules/git_hook_bypass.py +27 -0
  84. thefuck/rules/git_lfs_mistype.py +18 -0
  85. thefuck/rules/git_main_master.py +16 -0
  86. thefuck/rules/git_merge.py +18 -0
  87. thefuck/rules/git_merge_unrelated.py +12 -0
  88. thefuck/rules/git_not_command.py +18 -0
  89. thefuck/rules/git_pull.py +16 -0
  90. thefuck/rules/git_pull_clone.py +13 -0
  91. thefuck/rules/git_pull_uncommitted_changes.py +14 -0
  92. thefuck/rules/git_push.py +44 -0
  93. thefuck/rules/git_push_different_branch_names.py +12 -0
  94. thefuck/rules/git_push_force.py +18 -0
  95. thefuck/rules/git_push_pull.py +20 -0
  96. thefuck/rules/git_push_without_commits.py +12 -0
  97. thefuck/rules/git_rebase_merge_dir.py +17 -0
  98. thefuck/rules/git_rebase_no_changes.py +13 -0
  99. thefuck/rules/git_remote_delete.py +13 -0
  100. thefuck/rules/git_remote_seturl_add.py +12 -0
  101. thefuck/rules/git_rm_local_modifications.py +19 -0
  102. thefuck/rules/git_rm_recursive.py +16 -0
  103. thefuck/rules/git_rm_staged.py +19 -0
  104. thefuck/rules/git_stash.py +15 -0
  105. thefuck/rules/git_stash_pop.py +18 -0
  106. thefuck/rules/git_tag_force.py +13 -0
  107. thefuck/rules/git_two_dashes.py +14 -0
  108. thefuck/rules/go_run.py +16 -0
  109. thefuck/rules/go_unknown_command.py +28 -0
  110. thefuck/rules/gradle_no_task.py +34 -0
  111. thefuck/rules/gradle_wrapper.py +13 -0
  112. thefuck/rules/grep_arguments_order.py +23 -0
  113. thefuck/rules/grep_recursive.py +10 -0
  114. thefuck/rules/grunt_task_not_found.py +37 -0
  115. thefuck/rules/gulp_not_task.py +22 -0
  116. thefuck/rules/has_exists_script.py +13 -0
  117. thefuck/rules/heroku_multiple_apps.py +12 -0
  118. thefuck/rules/heroku_not_command.py +11 -0
  119. thefuck/rules/history.py +15 -0
  120. thefuck/rules/hostscli.py +27 -0
  121. thefuck/rules/ifconfig_device_not_found.py +23 -0
  122. thefuck/rules/java.py +17 -0
  123. thefuck/rules/javac.py +18 -0
  124. thefuck/rules/lein_not_task.py +19 -0
  125. thefuck/rules/ln_no_hard_link.py +23 -0
  126. thefuck/rules/ln_s_order.py +26 -0
  127. thefuck/rules/long_form_help.py +27 -0
  128. thefuck/rules/ls_all.py +10 -0
  129. thefuck/rules/ls_lah.py +12 -0
  130. thefuck/rules/man.py +33 -0
  131. thefuck/rules/man_no_space.py +10 -0
  132. thefuck/rules/mercurial.py +27 -0
  133. thefuck/rules/missing_space_before_subcommand.py +21 -0
  134. thefuck/rules/mkdir_p.py +13 -0
  135. thefuck/rules/mvn_no_command.py +11 -0
  136. thefuck/rules/mvn_unknown_lifecycle_phase.py +30 -0
  137. thefuck/rules/nixos_cmd_not_found.py +15 -0
  138. thefuck/rules/no_command.py +41 -0
  139. thefuck/rules/no_such_file.py +30 -0
  140. thefuck/rules/npm_missing_script.py +17 -0
  141. thefuck/rules/npm_run_script.py +17 -0
  142. thefuck/rules/npm_wrong_command.py +42 -0
  143. thefuck/rules/omnienv_no_such_command.py +35 -0
  144. thefuck/rules/open.py +40 -0
  145. thefuck/rules/pacman.py +17 -0
  146. thefuck/rules/pacman_invalid_option.py +20 -0
  147. thefuck/rules/pacman_not_found.py +26 -0
  148. thefuck/rules/path_from_history.py +53 -0
  149. thefuck/rules/php_s.py +11 -0
  150. thefuck/rules/pip_install.py +15 -0
  151. thefuck/rules/pip_unknown_command.py +19 -0
  152. thefuck/rules/port_already_in_use.py +40 -0
  153. thefuck/rules/prove_recursively.py +27 -0
  154. thefuck/rules/python_command.py +17 -0
  155. thefuck/rules/python_execute.py +15 -0
  156. thefuck/rules/python_module_error.py +13 -0
  157. thefuck/rules/quotation_marks.py +12 -0
  158. thefuck/rules/rails_migrations_pending.py +14 -0
  159. thefuck/rules/react_native_command_unrecognized.py +34 -0
  160. thefuck/rules/remove_shell_prompt_literal.py +23 -0
  161. thefuck/rules/remove_trailing_cedilla.py +11 -0
  162. thefuck/rules/rm_dir.py +16 -0
  163. thefuck/rules/rm_root.py +16 -0
  164. thefuck/rules/scm_correction.py +32 -0
  165. thefuck/rules/sed_unterminated_s.py +18 -0
  166. thefuck/rules/sl_ls.py +14 -0
  167. thefuck/rules/ssh_known_hosts.py +37 -0
  168. thefuck/rules/sudo.py +47 -0
  169. thefuck/rules/sudo_command_from_user_path.py +21 -0
  170. thefuck/rules/switch_lang.py +117 -0
  171. thefuck/rules/systemctl.py +22 -0
  172. thefuck/rules/terraform_init.py +13 -0
  173. thefuck/rules/terraform_no_command.py +16 -0
  174. thefuck/rules/test.py.py +10 -0
  175. thefuck/rules/tmux.py +18 -0
  176. thefuck/rules/touch.py +14 -0
  177. thefuck/rules/tsuru_login.py +12 -0
  178. thefuck/rules/tsuru_not_command.py +15 -0
  179. thefuck/rules/unknown_command.py +13 -0
  180. thefuck/rules/unsudo.py +15 -0
  181. thefuck/rules/vagrant_up.py +21 -0
  182. thefuck/rules/whois.py +34 -0
  183. thefuck/rules/workon_doesnt_exists.py +32 -0
  184. thefuck/rules/wrong_hyphen_before_subcommand.py +20 -0
  185. thefuck/rules/yarn_alias.py +14 -0
  186. thefuck/rules/yarn_command_not_found.py +43 -0
  187. thefuck/rules/yarn_command_replaced.py +13 -0
  188. thefuck/rules/yarn_help.py +17 -0
  189. thefuck/rules/yum_invalid_operation.py +39 -0
  190. thefuck/shells/__init__.py +52 -0
  191. thefuck/shells/bash.py +94 -0
  192. thefuck/shells/fish.py +131 -0
  193. thefuck/shells/generic.py +154 -0
  194. thefuck/shells/powershell.py +43 -0
  195. thefuck/shells/tcsh.py +44 -0
  196. thefuck/shells/zsh.py +98 -0
  197. thefuck/specific/__init__.py +0 -0
  198. thefuck/specific/apt.py +3 -0
  199. thefuck/specific/archlinux.py +48 -0
  200. thefuck/specific/brew.py +15 -0
  201. thefuck/specific/dnf.py +3 -0
  202. thefuck/specific/git.py +32 -0
  203. thefuck/specific/nix.py +3 -0
  204. thefuck/specific/npm.py +21 -0
  205. thefuck/specific/sudo.py +18 -0
  206. thefuck/specific/yum.py +3 -0
  207. thefuck/system/__init__.py +7 -0
  208. thefuck/system/unix.py +57 -0
  209. thefuck/system/win32.py +43 -0
  210. thefuck/types.py +261 -0
  211. thefuck/ui.py +116 -0
  212. thefuck/utils.py +385 -0
  213. thefuck_leeguoo-3.41.dist-info/METADATA +681 -0
  214. thefuck_leeguoo-3.41.dist-info/RECORD +218 -0
  215. thefuck_leeguoo-3.41.dist-info/WHEEL +6 -0
  216. thefuck_leeguoo-3.41.dist-info/entry_points.txt +3 -0
  217. thefuck_leeguoo-3.41.dist-info/licenses/LICENSE.md +22 -0
  218. thefuck_leeguoo-3.41.dist-info/top_level.txt +1 -0
thefuck/logs.py ADDED
@@ -0,0 +1,255 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ from contextlib import contextmanager
4
+ from datetime import datetime
5
+ import os
6
+ import re
7
+ import sys
8
+ import unicodedata
9
+ from traceback import format_exception
10
+ import colorama
11
+ try:
12
+ from shutil import get_terminal_size
13
+ except ImportError: # pragma: no cover - Python < 3.3
14
+ from backports.shutil_get_terminal_size import get_terminal_size
15
+ from .conf import settings
16
+ from . import const
17
+
18
+
19
+ def color(color_):
20
+ """Utility for ability to disabling colored output."""
21
+ if settings.no_colors:
22
+ return ''
23
+ else:
24
+ return color_
25
+
26
+
27
+ _ANSI_RE = re.compile(r'\x1b\[[0-?]*[ -/]*[@-~]')
28
+ _last_confirm_lines = 0
29
+
30
+
31
+ def _strip_ansi(text):
32
+ return _ANSI_RE.sub('', text)
33
+
34
+
35
+ def _terminal_columns():
36
+ try:
37
+ return os.get_terminal_size(sys.stderr.fileno()).columns or 80
38
+ except Exception:
39
+ cols = get_terminal_size((80, 20)).columns or 80
40
+ return cols
41
+
42
+
43
+ def _text_width(text):
44
+ width = 0
45
+ for ch in text:
46
+ if unicodedata.combining(ch):
47
+ continue
48
+ if unicodedata.east_asian_width(ch) in ('W', 'F'):
49
+ width += 2
50
+ else:
51
+ width += 1
52
+ return width
53
+
54
+
55
+ def _calc_prompt_lines(text):
56
+ cols = _terminal_columns()
57
+ if cols <= 0:
58
+ cols = 80
59
+ visible = _strip_ansi(text.replace(const.USER_COMMAND_MARK, ''))
60
+ if not visible:
61
+ return 1
62
+ total = 0
63
+ for line in visible.splitlines() or ['']:
64
+ width = _text_width(line)
65
+ total += max(1, (width - 1) // cols + 1)
66
+ return total
67
+
68
+
69
+ def _clear_previous_confirm():
70
+ if _last_confirm_lines <= 0:
71
+ return ''
72
+ seq = '\r'
73
+ for idx in range(_last_confirm_lines):
74
+ seq += '\033[2K'
75
+ if idx < _last_confirm_lines - 1:
76
+ seq += '\033[1A'
77
+ return seq + '\r'
78
+
79
+
80
+ def reset_confirm_text():
81
+ global _last_confirm_lines
82
+ _last_confirm_lines = 0
83
+
84
+
85
+ def warn(title):
86
+ sys.stderr.write(u'{warn}[WARN] {title}{reset}\n'.format(
87
+ warn=color(colorama.Back.RED + colorama.Fore.WHITE
88
+ + colorama.Style.BRIGHT),
89
+ reset=color(colorama.Style.RESET_ALL),
90
+ title=title))
91
+
92
+
93
+ def exception(title, exc_info):
94
+ sys.stderr.write(
95
+ u'{warn}[WARN] {title}:{reset}\n{trace}'
96
+ u'{warn}----------------------------{reset}\n\n'.format(
97
+ warn=color(colorama.Back.RED + colorama.Fore.WHITE
98
+ + colorama.Style.BRIGHT),
99
+ reset=color(colorama.Style.RESET_ALL),
100
+ title=title,
101
+ trace=''.join(format_exception(*exc_info))))
102
+
103
+
104
+ def rule_failed(rule, exc_info):
105
+ exception(u'Rule {}'.format(rule.name), exc_info)
106
+
107
+
108
+ def failed(msg):
109
+ sys.stderr.write(u'{red}{msg}{reset}\n'.format(
110
+ msg=msg,
111
+ red=color(colorama.Fore.RED),
112
+ reset=color(colorama.Style.RESET_ALL)))
113
+
114
+
115
+ def show_corrected_command(corrected_command):
116
+ desc = getattr(corrected_command, 'desc', '') or ''
117
+ desc = u' '.join(desc.split())
118
+ desc_output = ''
119
+ if desc:
120
+ desc_output = u' — {desc_color}{desc}{reset}'.format(
121
+ desc_color=color(colorama.Fore.YELLOW),
122
+ desc=desc,
123
+ reset=color(colorama.Style.RESET_ALL))
124
+ sys.stderr.write(
125
+ u'{prefix}{cmd_color}{script}{reset}{desc_output}{side_effect}\n'.format(
126
+ prefix=const.USER_COMMAND_MARK,
127
+ script=corrected_command.script,
128
+ desc_output=desc_output,
129
+ side_effect=u' (+side effect)' if corrected_command.side_effect else u'',
130
+ cmd_color=color(colorama.Style.BRIGHT + colorama.Fore.CYAN),
131
+ reset=color(colorama.Style.RESET_ALL)))
132
+
133
+
134
+ def confirm_text(corrected_command):
135
+ global _last_confirm_lines
136
+ desc = getattr(corrected_command, 'desc', '') or ''
137
+ desc = u' '.join(desc.split())
138
+ desc_output = ''
139
+ if desc:
140
+ desc_output = u' — {desc_color}{desc}{reset}'.format(
141
+ desc_color=color(colorama.Fore.YELLOW),
142
+ desc=desc,
143
+ reset=color(colorama.Style.RESET_ALL))
144
+ prompt = (u'{prefix}{cmd_color}{script}{reset}{desc_output}{side_effect} '
145
+ u'[{green}enter{reset}/{blue}↑{reset}/{blue}↓{reset}'
146
+ u'/{blue}tab{reset}/{red}ctrl+c{reset}]').format(
147
+ prefix=const.USER_COMMAND_MARK,
148
+ script=corrected_command.script,
149
+ desc_output=desc_output,
150
+ side_effect=' (+side effect)' if corrected_command.side_effect else '',
151
+ cmd_color=color(colorama.Style.BRIGHT + colorama.Fore.CYAN),
152
+ green=color(colorama.Fore.GREEN),
153
+ red=color(colorama.Fore.RED),
154
+ reset=color(colorama.Style.RESET_ALL),
155
+ blue=color(colorama.Fore.BLUE))
156
+ sys.stderr.write(_clear_previous_confirm())
157
+ sys.stderr.write(prompt)
158
+ sys.stderr.flush()
159
+ _last_confirm_lines = _calc_prompt_lines(prompt)
160
+
161
+
162
+ def ai_choose_header():
163
+ sys.stderr.write(u'\n{label}Choose{reset}\n'.format(
164
+ label=color(colorama.Style.BRIGHT + colorama.Fore.GREEN),
165
+ reset=color(colorama.Style.RESET_ALL)))
166
+
167
+
168
+ def confirm_choice(corrected_command):
169
+ global _last_confirm_lines
170
+ index = getattr(corrected_command, '_tf_index', None)
171
+ if not index:
172
+ return confirm_text(corrected_command)
173
+ prompt = (u'{prefix}{bold}{index}{reset} '
174
+ u'[{green}enter{reset}/{blue}↑{reset}/{blue}↓{reset}'
175
+ u'/{blue}tab{reset}/{red}ctrl+c{reset}]').format(
176
+ prefix=const.USER_COMMAND_MARK,
177
+ index=index,
178
+ bold=color(colorama.Style.BRIGHT),
179
+ green=color(colorama.Fore.GREEN),
180
+ red=color(colorama.Fore.RED),
181
+ reset=color(colorama.Style.RESET_ALL),
182
+ blue=color(colorama.Fore.BLUE))
183
+ sys.stderr.write(_clear_previous_confirm())
184
+ sys.stderr.write(prompt)
185
+ sys.stderr.flush()
186
+ _last_confirm_lines = _calc_prompt_lines(prompt)
187
+
188
+
189
+ def debug(msg):
190
+ if settings.debug:
191
+ sys.stderr.write(u'{blue}{bold}DEBUG:{reset} {msg}\n'.format(
192
+ msg=msg,
193
+ reset=color(colorama.Style.RESET_ALL),
194
+ blue=color(colorama.Fore.BLUE),
195
+ bold=color(colorama.Style.BRIGHT)))
196
+
197
+
198
+ @contextmanager
199
+ def debug_time(msg):
200
+ started = datetime.now()
201
+ try:
202
+ yield
203
+ finally:
204
+ debug(u'{} took: {}'.format(msg, datetime.now() - started))
205
+
206
+
207
+ def how_to_configure_alias(configuration_details):
208
+ print(u"Seems like {bold}fuck{reset} alias isn't configured!".format(
209
+ bold=color(colorama.Style.BRIGHT),
210
+ reset=color(colorama.Style.RESET_ALL)))
211
+
212
+ if configuration_details:
213
+ print(
214
+ u"Please put {bold}{content}{reset} in your "
215
+ u"{bold}{path}{reset} and apply "
216
+ u"changes with {bold}{reload}{reset} or restart your shell.".format(
217
+ bold=color(colorama.Style.BRIGHT),
218
+ reset=color(colorama.Style.RESET_ALL),
219
+ **configuration_details._asdict()))
220
+
221
+ if configuration_details.can_configure_automatically:
222
+ print(
223
+ u"Or run {bold}fuck{reset} a second time to configure"
224
+ u" it automatically.".format(
225
+ bold=color(colorama.Style.BRIGHT),
226
+ reset=color(colorama.Style.RESET_ALL)))
227
+
228
+ print(u'More details - https://github.com/nvbn/thefuck#manual-installation')
229
+
230
+
231
+ def already_configured(configuration_details):
232
+ print(
233
+ u"Seems like {bold}fuck{reset} alias already configured!\n"
234
+ u"For applying changes run {bold}{reload}{reset}"
235
+ u" or restart your shell.".format(
236
+ bold=color(colorama.Style.BRIGHT),
237
+ reset=color(colorama.Style.RESET_ALL),
238
+ reload=configuration_details.reload))
239
+
240
+
241
+ def configured_successfully(configuration_details):
242
+ print(
243
+ u"{bold}fuck{reset} alias configured successfully!\n"
244
+ u"For applying changes run {bold}{reload}{reset}"
245
+ u" or restart your shell.".format(
246
+ bold=color(colorama.Style.BRIGHT),
247
+ reset=color(colorama.Style.RESET_ALL),
248
+ reload=configuration_details.reload))
249
+
250
+
251
+ def version(thefuck_version, python_version, shell_info):
252
+ sys.stderr.write(
253
+ u'The Fuck {} using Python {} and {}\n'.format(thefuck_version,
254
+ python_version,
255
+ shell_info))
@@ -0,0 +1,20 @@
1
+ from ..conf import settings
2
+ from . import read_log, rerun, shell_logger
3
+
4
+
5
+ def get_output(script, expanded):
6
+ """Get output of the script.
7
+
8
+ :param script: Console script.
9
+ :type script: str
10
+ :param expanded: Console script with expanded aliases.
11
+ :type expanded: str
12
+ :rtype: str
13
+
14
+ """
15
+ if shell_logger.is_available():
16
+ return shell_logger.get_output(script)
17
+ if settings.instant_mode:
18
+ return read_log.get_output(script)
19
+ else:
20
+ return rerun.get_output(script, expanded)
@@ -0,0 +1,108 @@
1
+ import os
2
+ import shlex
3
+ import mmap
4
+ import re
5
+ try:
6
+ from shutil import get_terminal_size
7
+ except ImportError:
8
+ from backports.shutil_get_terminal_size import get_terminal_size
9
+ import six
10
+ import pyte
11
+ from ..exceptions import ScriptNotInLog
12
+ from .. import const, logs
13
+
14
+
15
+ def _group_by_calls(log):
16
+ ps1 = os.environ['PS1']
17
+ ps1_newlines = ps1.count('\\n') + ps1.count('\n')
18
+ ps1_counter = 0
19
+
20
+ script_line = None
21
+ lines = []
22
+ for line in log:
23
+ if const.USER_COMMAND_MARK in line or ps1_counter > 0:
24
+ if script_line and ps1_counter == 0:
25
+ yield script_line, lines
26
+
27
+ if ps1_newlines > 0:
28
+ if ps1_counter <= 0:
29
+ ps1_counter = ps1_newlines
30
+ else:
31
+ ps1_counter -= 1
32
+
33
+ script_line = line
34
+ lines = [line]
35
+ elif script_line is not None:
36
+ lines.append(line)
37
+
38
+ if script_line:
39
+ yield script_line, lines
40
+
41
+
42
+ def _get_script_group_lines(grouped, script):
43
+ if six.PY2:
44
+ script = script.encode('utf-8')
45
+
46
+ parts = shlex.split(script)
47
+
48
+ for script_line, lines in reversed(grouped):
49
+ if all(part in script_line for part in parts):
50
+ return lines
51
+
52
+ raise ScriptNotInLog
53
+
54
+
55
+ def _get_output_lines(script, log_file):
56
+ data = log_file.read().decode()
57
+ data = re.sub(r'\x00+$', '', data)
58
+ lines = data.split('\n')
59
+ grouped = list(_group_by_calls(lines))
60
+ script_lines = _get_script_group_lines(grouped, script)
61
+ screen = pyte.Screen(get_terminal_size().columns, len(script_lines))
62
+ stream = pyte.Stream(screen)
63
+ stream.feed('\n'.join(script_lines))
64
+ return screen.display
65
+
66
+
67
+ def _skip_old_lines(log_file):
68
+ size = os.path.getsize(os.environ['THEFUCK_OUTPUT_LOG'])
69
+ if size > const.LOG_SIZE_IN_BYTES:
70
+ log_file.seek(size - const.LOG_SIZE_IN_BYTES)
71
+
72
+
73
+ def get_output(script):
74
+ """Reads script output from log.
75
+
76
+ :type script: str
77
+ :rtype: str | None
78
+
79
+ """
80
+ if six.PY2:
81
+ logs.warn('Experimental instant mode is Python 3+ only')
82
+ return None
83
+
84
+ if 'THEFUCK_OUTPUT_LOG' not in os.environ:
85
+ logs.warn("Output log isn't specified")
86
+ return None
87
+
88
+ if const.USER_COMMAND_MARK not in os.environ.get('PS1', ''):
89
+ logs.warn(
90
+ "PS1 doesn't contain user command mark, please ensure "
91
+ "that PS1 is not changed after The Fuck alias initialization")
92
+ return None
93
+
94
+ try:
95
+ with logs.debug_time(u'Read output from log'):
96
+ fd = os.open(os.environ['THEFUCK_OUTPUT_LOG'], os.O_RDONLY)
97
+ buffer = mmap.mmap(fd, const.LOG_SIZE_IN_BYTES, mmap.MAP_SHARED, mmap.PROT_READ)
98
+ _skip_old_lines(buffer)
99
+ lines = _get_output_lines(script, buffer)
100
+ output = '\n'.join(lines).strip()
101
+ logs.debug(u'Received output: {}'.format(output))
102
+ return output
103
+ except OSError:
104
+ logs.warn("Can't read output log")
105
+ return None
106
+ except ScriptNotInLog:
107
+ logs.warn("Script not found in output log")
108
+ return None
@@ -0,0 +1,72 @@
1
+ import os
2
+ import shlex
3
+ import six
4
+ from subprocess import Popen, PIPE, STDOUT
5
+ from psutil import AccessDenied, Process, TimeoutExpired
6
+ from .. import logs
7
+ from ..conf import settings
8
+
9
+
10
+ def _kill_process(proc):
11
+ """Tries to kill the process otherwise just logs a debug message, the
12
+ process will be killed when thefuck terminates.
13
+
14
+ :type proc: Process
15
+
16
+ """
17
+ try:
18
+ proc.kill()
19
+ except AccessDenied:
20
+ logs.debug(u'Rerun: process PID {} ({}) could not be terminated'.format(
21
+ proc.pid, proc.exe()))
22
+
23
+
24
+ def _wait_output(popen, is_slow):
25
+ """Returns `True` if we can get output of the command in the
26
+ `settings.wait_command` time.
27
+
28
+ Command will be killed if it wasn't finished in the time.
29
+
30
+ :type popen: Popen
31
+ :rtype: bool
32
+
33
+ """
34
+ proc = Process(popen.pid)
35
+ try:
36
+ proc.wait(settings.wait_slow_command if is_slow
37
+ else settings.wait_command)
38
+ return True
39
+ except TimeoutExpired:
40
+ for child in proc.children(recursive=True):
41
+ _kill_process(child)
42
+ _kill_process(proc)
43
+ return False
44
+
45
+
46
+ def get_output(script, expanded):
47
+ """Runs the script and obtains stdin/stderr.
48
+
49
+ :type script: str
50
+ :type expanded: str
51
+ :rtype: str | None
52
+
53
+ """
54
+ env = dict(os.environ)
55
+ env.update(settings.env)
56
+
57
+ if six.PY2:
58
+ expanded = expanded.encode('utf-8')
59
+
60
+ split_expand = shlex.split(expanded)
61
+ is_slow = split_expand[0] in settings.slow_commands if split_expand else False
62
+ with logs.debug_time(u'Call: {}; with env: {}; is slow: {}'.format(
63
+ script, env, is_slow)):
64
+ result = Popen(expanded, shell=True, stdin=PIPE,
65
+ stdout=PIPE, stderr=STDOUT, env=env)
66
+ if _wait_output(result, is_slow):
67
+ output = result.stdout.read().decode('utf-8', errors='replace')
68
+ logs.debug(u'Received output: {}'.format(output))
69
+ return output
70
+ else:
71
+ logs.debug(u'Execution timed out!')
72
+ return None
@@ -0,0 +1,60 @@
1
+ import json
2
+ import os
3
+ import socket
4
+ try:
5
+ from shutil import get_terminal_size
6
+ except ImportError:
7
+ from backports.shutil_get_terminal_size import get_terminal_size
8
+ import pyte
9
+ from .. import const, logs
10
+
11
+
12
+ def _get_socket_path():
13
+ return os.environ.get(const.SHELL_LOGGER_SOCKET_ENV)
14
+
15
+
16
+ def is_available():
17
+ """Returns `True` if shell logger socket available.
18
+
19
+ :rtype: book
20
+
21
+ """
22
+ path = _get_socket_path()
23
+ if not path:
24
+ return False
25
+
26
+ return os.path.exists(path)
27
+
28
+
29
+ def _get_last_n(n):
30
+ with socket.socket(socket.AF_UNIX) as client:
31
+ client.connect(_get_socket_path())
32
+ request = json.dumps({
33
+ "type": "list",
34
+ "count": n,
35
+ }) + '\n'
36
+ client.sendall(request.encode('utf-8'))
37
+ response = client.makefile().readline()
38
+ return json.loads(response)['commands']
39
+
40
+
41
+ def _get_output_lines(output):
42
+ lines = output.split('\n')
43
+ screen = pyte.Screen(get_terminal_size().columns, len(lines))
44
+ stream = pyte.Stream(screen)
45
+ stream.feed('\n'.join(lines))
46
+ return screen.display
47
+
48
+
49
+ def get_output(script):
50
+ """Gets command output from shell logger."""
51
+ with logs.debug_time(u'Read output from external shell logger'):
52
+ commands = _get_last_n(const.SHELL_LOGGER_LIMIT)
53
+ for command in commands:
54
+ if command['command'] == script:
55
+ lines = _get_output_lines(command['output'])
56
+ output = '\n'.join(lines).strip()
57
+ return output
58
+ else:
59
+ logs.warn("Output isn't available in shell logger")
60
+ return None
File without changes
@@ -0,0 +1,54 @@
1
+ from thefuck.utils import is_app, get_closest, replace_argument
2
+
3
+
4
+ _ADB_COMMANDS = (
5
+ 'backup',
6
+ 'bugreport',
7
+ 'connect',
8
+ 'devices',
9
+ 'disable-verity',
10
+ 'disconnect',
11
+ 'enable-verity',
12
+ 'emu',
13
+ 'forward',
14
+ 'get-devpath',
15
+ 'get-serialno',
16
+ 'get-state',
17
+ 'install',
18
+ 'install-multiple',
19
+ 'jdwp',
20
+ 'keygen',
21
+ 'kill-server',
22
+ 'logcat',
23
+ 'pull',
24
+ 'push',
25
+ 'reboot',
26
+ 'reconnect',
27
+ 'restore',
28
+ 'reverse',
29
+ 'root',
30
+ 'run-as',
31
+ 'shell',
32
+ 'sideload',
33
+ 'start-server',
34
+ 'sync',
35
+ 'tcpip',
36
+ 'uninstall',
37
+ 'unroot',
38
+ 'usb',
39
+ 'wait-for',
40
+ )
41
+
42
+
43
+ def match(command):
44
+ return (is_app(command, 'adb')
45
+ and command.output.startswith('Android Debug Bridge version'))
46
+
47
+
48
+ def get_new_command(command):
49
+ for idx, arg in enumerate(command.script_parts[1:]):
50
+ # allowed params to ADB are a/d/e/s/H/P/L where s, H, P and L take additional args
51
+ # for example 'adb -s 111 logcat' or 'adb -e logcat'
52
+ if not arg[0] == '-' and not command.script_parts[idx] in ('-s', '-H', '-P', '-L'):
53
+ adb_cmd = get_closest(arg, _ADB_COMMANDS)
54
+ return replace_argument(command.script, arg, adb_cmd)
@@ -0,0 +1,10 @@
1
+ from thefuck.utils import for_app
2
+
3
+
4
+ @for_app('ag')
5
+ def match(command):
6
+ return command.output.endswith('run ag with -Q\n')
7
+
8
+
9
+ def get_new_command(command):
10
+ return command.script.replace('ag', 'ag -Q', 1)
@@ -0,0 +1,50 @@
1
+ from types import ModuleType
2
+ from thefuck.specific.apt import apt_available
3
+ from thefuck.utils import memoize, which
4
+ from thefuck.shells import shell
5
+
6
+ try:
7
+ from CommandNotFound import CommandNotFound
8
+
9
+ enabled_by_default = apt_available
10
+
11
+ if isinstance(CommandNotFound, ModuleType):
12
+ # For ubuntu 18.04+
13
+ _get_packages = CommandNotFound.CommandNotFound().get_packages
14
+ else:
15
+ # For older versions
16
+ _get_packages = CommandNotFound().getPackages
17
+ except ImportError:
18
+ enabled_by_default = False
19
+
20
+
21
+ def _get_executable(command):
22
+ if command.script_parts[0] == 'sudo':
23
+ return command.script_parts[1]
24
+ else:
25
+ return command.script_parts[0]
26
+
27
+
28
+ @memoize
29
+ def get_package(executable):
30
+ try:
31
+ packages = _get_packages(executable)
32
+ return packages[0][0]
33
+ except IndexError:
34
+ # IndexError is thrown when no matching package is found
35
+ return None
36
+
37
+
38
+ def match(command):
39
+ if 'not found' in command.output or 'not installed' in command.output:
40
+ executable = _get_executable(command)
41
+ return not which(executable) and get_package(executable)
42
+ else:
43
+ return False
44
+
45
+
46
+ def get_new_command(command):
47
+ executable = _get_executable(command)
48
+ name = get_package(executable)
49
+ formatme = shell.and_('sudo apt-get install {}', '{}')
50
+ return formatme.format(name, command.script)
@@ -0,0 +1,14 @@
1
+ import re
2
+ from thefuck.specific.apt import apt_available
3
+ from thefuck.utils import for_app
4
+
5
+ enabled_by_default = apt_available
6
+
7
+
8
+ @for_app('apt-get')
9
+ def match(command):
10
+ return command.script.startswith('apt-get search')
11
+
12
+
13
+ def get_new_command(command):
14
+ return re.sub(r'^apt-get', 'apt-cache', command.script)