Skip to content

Commit d531d41

Browse files
authored
Merge pull request #35 from mkcn/clipboard-feature
Clipboard feature
2 parents c8ea3b9 + 89156b3 commit d531d41

File tree

7 files changed

+109
-75
lines changed

7 files changed

+109
-75
lines changed

.github/workflows/pythonUnitTest.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ jobs:
66
build:
77
strategy:
88
matrix:
9-
os: [ubuntu-16.04, ubuntu-18.04, macos-10.15] # ubuntu-16.04, macos-10.15
10-
python-version: [3.6, 3.7, 3.8] # 3.7, 3.8
9+
os: [ubuntu-16.04, ubuntu-latest, macos-latest]
10+
python-version: [3.6, 3.8]
1111

1212
runs-on: ${{ matrix.os }}
1313

@@ -27,7 +27,8 @@ jobs:
2727
2828
if [[ "$OSTYPE" == "linux-gnu" ]]; then
2929
echo "OS: Linux"
30-
sudo apt-get install nmap # nmap is needed for the man parser in UnitTest
30+
sudo apt-get --yes install net-tools nmap # needed for the man parser in UnitTest
31+
# sudo apt-get --yes install xclip # needed for pyperclip, only on Linux (more info: https://pyperclip.readthedocs.io/en/latest/index.html#not-implemented-error)
3132
elif [[ "$OSTYPE" == "darwin"* ]]; then
3233
echo "OS: Mac OSX"
3334
brew install nmap
@@ -40,6 +41,8 @@ jobs:
4041
if: always()
4142
run: |
4243
$GITHUB_WORKSPACE/installer.sh
44+
# this flag file is needed to run the TestMain unitTests (test_main.py)
45+
touch $HOME/.local/share/fastHistory/THIS_IS_A_TEST_FASTHISTORY_INSTALLATION
4346
4447
- name: Test with UnitTest
4548
run: |

fastHistory/__init__.py

Lines changed: 21 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -36,26 +36,16 @@ def handle_search_request(logger_console, input_cmd_str, path_data_folder, theme
3636
picker = Picker(data_manager, theme=theme, last_column_size=last_column_size, search_text=input_cmd_str)
3737
selected_option = picker.start()
3838

39-
# inject into the terminal the selected command
40-
try:
41-
if selected_option[0]:
42-
ConsoleUtils.fill_terminal_input(selected_option[1])
39+
if selected_option[0]:
40+
res = ConsoleUtils.paste_into_terminal(selected_option[1])
41+
if not res[0]:
42+
logger_console.log_on_console_error(res[1])
43+
else:
44+
res = ConsoleUtils.copy_to_clipboard(selected_option[1])
45+
if res[0]:
46+
logger_console.log_on_console_info(res[1])
4347
else:
44-
if ConsoleUtils.set_value_clipboard(selected_option[1]):
45-
logger_console.log_on_console_info("copied to clipboard: '%s'" % selected_option[1])
46-
else:
47-
logger_console.log_on_console_error("pyperclip package not found")
48-
logger_console.log_on_console_error("To enable auto-copy execute the following command:")
49-
logger_console.log_on_console("")
50-
logger_console.log_on_console("pip3 install pyperclip")
51-
logger_console.log_on_console("")
52-
except:
53-
logging.debug("your terminal does not support automatic input injection")
54-
logger_console.log_on_console_error("your terminal does not support automatic input injection")
55-
logger_console.log_on_console_error("please manually copy and paste the selected command")
56-
logger_console.log_on_console("")
57-
logger_console.log_on_console(selected_option)
58-
logger_console.log_on_console("")
48+
logger_console.log_on_console_error(res[1])
5949

6050

6151
def handle_add_request(logger_console, input_cmd_str, path_data_folder, error_feedback=False):
@@ -192,38 +182,29 @@ def handle_update(logger_console):
192182
update_command = update_with_installer
193183
except ImportError as e:
194184
update_command = update_with_installer
195-
logger_console.log_on_console_info("to update fastHistory use the following injected command")
196-
try:
197-
ConsoleUtils.fill_terminal_input(update_command)
198-
except:
199-
logger_console.log_on_console_error("your terminal does not support automatic input injection")
200-
logger_console.log_on_console_error("please copy and execute the following command")
201-
logger_console.log_on_console(update_command)
185+
logger_console.log_on_console_info("to update fastHistory use the following command")
186+
res = ConsoleUtils.paste_into_terminal(update_command)
187+
if not res[0]:
188+
logger_console.log_on_console_error(res[1])
202189

203190

204191
def handle_config_file(logger_console, path_data_folder):
205192
config_file = path_data_folder + NAME_CONFIGURATION_FILE
206-
logger_console.log_on_console_info("to change the config file use the following injected command")
207-
try:
208-
ConsoleUtils.fill_terminal_input("nano " + config_file)
209-
except:
210-
logger_console.log_on_console_error("your terminal does not support automatic input injection")
211-
logger_console.log_on_console_error("please edit the configuration file manually")
212-
logger_console.log_on_console(config_file)
193+
logger_console.log_on_console_info("to change the config file use the following command")
194+
res = ConsoleUtils.paste_into_terminal("nano " + config_file)
195+
if not res[0]:
196+
logger_console.log_on_console_error(res[1])
213197

214198

215199
def handle_log_file(logger_console, path_data_folder):
216200
log_file = path_data_folder + NAME_LOG_FILE
217201
if not os.path.exists(log_file):
218202
logger_console.log_on_console_warn("log file not found, try to change the log level in the config file")
219203
else:
220-
logger_console.log_on_console_info("to read the log file use the following injected command")
221-
try:
222-
ConsoleUtils.fill_terminal_input("nano " + log_file)
223-
except:
224-
logger_console.log_on_console_error("your terminal does not support automatic input injection")
225-
logger_console.log_on_console_error("please read the log file manually")
226-
logger_console.log_on_console(log_file)
204+
logger_console.log_on_console_info("to read the log file use the following command")
205+
res = ConsoleUtils.paste_into_terminal("nano " + log_file)
206+
if not res[0]:
207+
logger_console.log_on_console_error(res[1])
227208

228209

229210
def handle_helper(logger_console):
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.2.1
1+
2.2.2

fastHistory/console/consoleUtils.py

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,42 @@ class ConsoleUtils:
1515
"""
1616

1717
@staticmethod
18-
def fill_terminal_input(data):
18+
def paste_into_terminal(data):
1919
"""
2020
Fill terminal input with data
2121
# https://unix.stackexchange.com/a/217390
2222
"""
23-
# check if python version >= 3
24-
if sys.version_info >= (3,):
25-
# reverse the automatic encoding and pack into a list of bytes
26-
data = (struct.pack('B', c) for c in os.fsencode(data))
2723

28-
# put each char of data in the standard input of the current terminal
29-
for c in data:
30-
fcntl.ioctl(sys.stdin, termios.TIOCSTI, c)
31-
# clear output printed by the previous command
32-
# and leave only the terminal with the submitted input
33-
sys.stdout.write('\r')
24+
try:
25+
# check if python version >= 3
26+
if sys.version_info >= (3,):
27+
# reverse the automatic encoding and pack into a list of bytes
28+
data_bytes = (struct.pack('B', c) for c in os.fsencode(data))
29+
30+
# put each char of data in the standard input of the current terminal
31+
for c in data_bytes:
32+
fcntl.ioctl(sys.stdin, termios.TIOCSTI, c)
33+
# clear output printed by the previous command
34+
# and leave only the terminal with the submitted input
35+
sys.stdout.write('\r')
36+
return [True, None]
37+
except Exception:
38+
res = ConsoleUtils.copy_to_clipboard(data)
39+
if res[0]:
40+
return [False, "your terminal does not support auto-paste, the command is copied to clipboard instead:\n%s" % data]
41+
else:
42+
return [False, "your terminal does not support auto-paste\ncopy-to-clipboard failed too with the following message:\n\t%s\nplease manually copy and use the following command:\n\t%s" % (res[1], data)]
3443

3544
@staticmethod
36-
def set_value_clipboard(data):
45+
def copy_to_clipboard(data):
3746
try:
3847
import pyperclip
3948
pyperclip.copy(data)
40-
return True
49+
return [True, "copied to clipboard: %s" % data]
50+
except ImportError:
51+
return [False, "pyperclip module not found (to install it run 'pip3 install pyperclip')"]
4152
except Exception as e:
42-
return False
53+
return [False, "pyperclip error: %s" % str(e)]
4354

4455
@staticmethod
4556
def handler_close_signal(signum, frame):

fastHistory/unitTests/test_main.py

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,35 @@
55
import fastHistory
66
import sys
77

8+
from fastHistory import ConsoleUtils
89
from fastHistory.console import colors
910
from fastHistory.unitTests.loggerTest import LoggerBashTest, LoggerTest
1011

1112

1213
class TestMain(unittest.TestCase):
1314
"""
1415
note: some of these tests need a successful installation and setup of fastHistory
16+
included bashlex, pyperclip modules
1517
"""
1618

19+
NAME_FILE_THIS_IS_A_TEST_FASTHISTORY_INSTALLATION = "THIS_IS_A_TEST_FASTHISTORY_INSTALLATION"
20+
1721
@classmethod
1822
def setUpClass(cls):
1923
cls.logger_test = LoggerTest()
2024
cls.output_file = cls.logger_test.get_test_folder() + "output.db"
25+
cls.path_data_folder = ConsoleUtils.compose_home_relative_path(fastHistory.PATH_DATA_FOLDER)
2126

2227
def setUp(self):
2328
self.logger_test.log_test_function_name(self.id())
29+
self.assertTrue(os.path.isfile(self.path_data_folder + fastHistory.NAME_CONFIGURATION_FILE),
30+
"To run these tests you first need to install fastHistory on this machine:\n./installer.sh")
31+
self.assertTrue(os.path.isfile(self.path_data_folder + TestMain.NAME_FILE_THIS_IS_A_TEST_FASTHISTORY_INSTALLATION),
32+
"A fastHistory installation has been found,\n\
33+
these tests should NOT be run with your daily used fastHistory but only in a test environment\n\
34+
if you understand this, please manually create a file with the following command:\ntouch %s\n\
35+
otherwise just ignore these test cases"
36+
% (self.path_data_folder + TestMain.NAME_FILE_THIS_IS_A_TEST_FASTHISTORY_INSTALLATION))
2437

2538
if os.path.isfile(self.output_file):
2639
os.remove(self.output_file)
@@ -104,7 +117,6 @@ def test_call_add_error(self):
104117
self.assertEqual(len(console_logs), 0)
105118

106119
def test_call_export_with_parameter_and_import(self):
107-
108120
logger_test = LoggerBashTest()
109121
sys.argv = ["", "--export", self.output_file, "--from-installer"]
110122
fastHistory.f(logger_console=logger_test)
@@ -138,7 +150,7 @@ def test_call_import_with_error(self):
138150
console_logs = logger_test.get_console_logs()
139151
self.assertRegex(console_logs[1][LoggerBashTest.INDEX_VALUE], "^input file does not exist:")
140152

141-
def test_call_setup(self):
153+
def __test_call_setup(self):
142154
logger_test = LoggerBashTest()
143155
sys.argv = ["", "--setup", "--from-installer"]
144156
fastHistory.f(logger_console=logger_test)
@@ -149,7 +161,7 @@ def test_call_setup(self):
149161
# last message value
150162
self.assertRegex(console_logs[-1][LoggerBashTest.INDEX_VALUE], "^setup completed")
151163

152-
def test_call_setup_with_config_reader_error(self):
164+
def __test_call_setup_with_config_reader_error(self):
153165
logger_test = LoggerBashTest()
154166
sys.argv = ["", "--setup", ]
155167
fastHistory.f(logger_console=logger_test)
@@ -166,13 +178,16 @@ def test_call_update(self):
166178
fastHistory.f(logger_console=logger_test)
167179
console_logs = logger_test.get_console_logs()
168180
# last message value
169-
if len(console_logs) == 4:
181+
if len(console_logs) == 2:
182+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_TYPE], LoggerBashTest.INFO)
183+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to update fastHistory use the following command")
170184
self.assertEqual(console_logs[1][LoggerBashTest.INDEX_TYPE], LoggerBashTest.ERROR)
171-
self.assertEqual(console_logs[1][LoggerBashTest.INDEX_VALUE], "your terminal does not support automatic input injection")
185+
self.assertRegex(console_logs[1][LoggerBashTest.INDEX_VALUE], "^your terminal does not support auto-paste")
172186
elif len(console_logs) == 1:
173187
# note: this test may be successful if executed directly from the terminal
174188
# e.g. python3 -m unittest discover -s fastHistory/
175-
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to update fastHistory use the following injected command")
189+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_TYPE], LoggerBashTest.INFO)
190+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to update fastHistory use the following command")
176191
else:
177192
self.assertTrue(False)
178193

@@ -182,15 +197,17 @@ def test_call_log_with_error(self):
182197
fastHistory.f(logger_console=logger_test)
183198
console_logs = logger_test.get_console_logs()
184199
# last message value
185-
if len(console_logs) == 4:
200+
if len(console_logs) == 2:
201+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_TYPE], LoggerBashTest.INFO)
202+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to read the log file use the following command")
186203
self.assertEqual(console_logs[1][LoggerBashTest.INDEX_TYPE], LoggerBashTest.ERROR)
187-
self.assertEqual(console_logs[1][LoggerBashTest.INDEX_VALUE], "your terminal does not support automatic input injection")
204+
self.assertRegex(console_logs[1][LoggerBashTest.INDEX_VALUE], "^your terminal does not support auto-paste")
188205
elif len(console_logs) == 1:
189206
# note: this test may be successful if executed directly from the terminal
190207
# e.g. python3 -m unittest discover -s fastHistory/
191208
if console_logs[0][LoggerBashTest.INDEX_VALUE] == "log file not found, try to change the log level in the config file":
192209
self.assertTrue(True)
193-
elif console_logs[0][LoggerBashTest.INDEX_VALUE] == "to read the log file use the following injected command":
210+
elif console_logs[0][LoggerBashTest.INDEX_VALUE] == "to read the log file use the following command":
194211
self.assertTrue(True)
195212
else:
196213
self.assertTrue(False)
@@ -203,13 +220,16 @@ def test_call_config_with_error(self):
203220
fastHistory.f(logger_console=logger_test)
204221
console_logs = logger_test.get_console_logs()
205222
# last message value
206-
if len(console_logs) == 4:
223+
if len(console_logs) == 2:
224+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_TYPE], LoggerBashTest.INFO)
225+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to change the config file use the following command")
207226
self.assertEqual(console_logs[1][LoggerBashTest.INDEX_TYPE], LoggerBashTest.ERROR)
208-
self.assertEqual(console_logs[1][LoggerBashTest.INDEX_VALUE], "your terminal does not support automatic input injection")
227+
self.assertRegex(console_logs[1][LoggerBashTest.INDEX_VALUE], "^your terminal does not support auto-paste")
209228
elif len(console_logs) == 1:
210229
# note: this test may be successful if executed directly from the terminal
211230
# e.g. python3 -m unittest discover -s fastHistory/
212-
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to change the config file use the following injected command")
231+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_TYPE], LoggerBashTest.INFO)
232+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to change the config file use the following command")
213233
else:
214234
self.assertTrue(False)
215235

@@ -219,12 +239,15 @@ def test_call_config_with_error_with_config_reader_error(self):
219239
fastHistory.f(logger_console=logger_test)
220240
console_logs = logger_test.get_console_logs()
221241
# last message value
222-
if len(console_logs) == 4:
242+
if len(console_logs) == 2:
243+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_TYPE], LoggerBashTest.INFO)
244+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to change the config file use the following command")
223245
self.assertEqual(console_logs[1][LoggerBashTest.INDEX_TYPE], LoggerBashTest.ERROR)
224-
self.assertEqual(console_logs[1][LoggerBashTest.INDEX_VALUE], "your terminal does not support automatic input injection")
246+
self.assertRegex(console_logs[1][LoggerBashTest.INDEX_VALUE], "^your terminal does not support auto-paste")
225247
elif len(console_logs) == 1:
226248
# note: this test may be successful if executed directly from the terminal
227249
# e.g. python3 -m unittest discover -s fastHistory/
228-
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to change the config file use the following injected command")
250+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_TYPE], LoggerBashTest.INFO)
251+
self.assertEqual(console_logs[0][LoggerBashTest.INDEX_VALUE], "to change the config file use the following command")
229252
else:
230253
self.assertTrue(False)

pip/build.sh

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,16 @@ installation_python_env="build-env/bin/activate"
44
version_file="../fastHistory/config/default_version.txt"
55

66

7+
# note: manually create $HOME/.pypirc based on the pyirc_template
8+
# https://pypi.org/manage/account/token/
9+
# https://test.pypi.org/manage/account/token/
710
pypi_upload=false
811
pypi_domain="pypi.org"
9-
pypi_repo="pypi" #defined in the $HOME/.pypirc file
12+
pypi_repo="pypi"
1013

1114
pypi_test_upload=false
1215
pypi_test_domain="test.pypi.org"
13-
pypi_test_repo="testpypi" #defined in the $HOME/.pypirc file
16+
pypi_test_repo="testpypi"
1417

1518

1619
if [ -f setup.py ]; then

pip/pypirc_template

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[distutils]
2+
index-servers=
3+
pypi
4+
testpypi
5+
6+
[pypi]
7+
username: __token__
8+
password: pypi-...
9+
10+
[testpypi]
11+
repository: https://test.pypi.org/legacy/
12+
username: __token__
13+
password: pypi-...

0 commit comments

Comments
 (0)