Refactor: move all pass related non gui stuff to module
This commit refactors this program to use a separate module for pass related stuff. This will enable a better separation between backend and frontend. There is still some work to do, e.g. adding getters and setters instead of using member attributes directly, but it is a start.
This commit is contained in:
parent
d6b0842991
commit
49473c85bf
3 changed files with 159 additions and 139 deletions
|
@ -1,18 +1,20 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/python3
|
||||||
"""
|
"""
|
||||||
A mobile first interface for the standard unix password manager written in python
|
A mobile first interface for the standard unix password manager written in python
|
||||||
"""
|
"""
|
||||||
import os
|
import os
|
||||||
import subprocess
|
|
||||||
|
|
||||||
import wx
|
import wx
|
||||||
import wx.lib.scrolledpanel as scrolled
|
import wx.lib.scrolledpanel as scrolled
|
||||||
|
|
||||||
|
from pass_handler import Pass, copy_to_clipboard, get_password_from_path, pass_pull, pass_push
|
||||||
|
|
||||||
|
|
||||||
class PassUi(wx.Frame):
|
class PassUi(wx.Frame):
|
||||||
"""
|
"""
|
||||||
The wx.Frame for passui
|
The wx.Frame for passui
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, *args, **kw):
|
def __init__(self, *args, **kw):
|
||||||
"""__init__.
|
"""__init__.
|
||||||
|
|
||||||
|
@ -20,33 +22,27 @@ class PassUi(wx.Frame):
|
||||||
:param kw:
|
:param kw:
|
||||||
"""
|
"""
|
||||||
super().__init__(*args, **kw)
|
super().__init__(*args, **kw)
|
||||||
# Find the top directory and set that to current directory
|
self.pass_handler = Pass()
|
||||||
self.topdir = os.environ.get('PASSWORD_STORE_DIR')
|
|
||||||
if not self.topdir:
|
|
||||||
self.topdir = os.environ.get('HOME') + '/.password-store'
|
|
||||||
self.curdir = self.topdir
|
|
||||||
# create a panel in the frame
|
# create a panel in the frame
|
||||||
self.pnl = scrolled.ScrolledPanel(self, -1, style=wx.VSCROLL)
|
self.pnl = scrolled.ScrolledPanel(self, -1, style=wx.VSCROLL)
|
||||||
self.pnl.SetupScrolling()
|
self.pnl.SetupScrolling()
|
||||||
# and create a sizer to manage the layout of child widgets
|
# and create a sizer to manage the layout of child widgets
|
||||||
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
self.sizer = wx.BoxSizer(wx.VERTICAL)
|
||||||
self.pnl.SetSizer(self.sizer)
|
self.pnl.SetSizer(self.sizer)
|
||||||
self.cur_paths = self.get_pass_paths()
|
|
||||||
self.cur_passwords = self.get_pass_passwords()
|
|
||||||
self.add_buttons()
|
self.add_buttons()
|
||||||
|
|
||||||
def add_buttons(self):
|
def add_buttons(self):
|
||||||
"""add_buttons."""
|
"""add_buttons."""
|
||||||
self.sizer.Clear(delete_windows=True)
|
self.sizer.Clear(delete_windows=True)
|
||||||
self.add_tools()
|
self.add_tools()
|
||||||
if self.curdir != self.topdir:
|
if self.pass_handler.cur_dir != self.pass_handler.top_dir:
|
||||||
btn = self.make_back_button()
|
btn = self.make_back_button()
|
||||||
self.sizer.Add(btn, 0, wx.EXPAND) # pylint: disable=no-member
|
self.sizer.Add(btn, 0, wx.EXPAND) # pylint: disable=no-member
|
||||||
self.Bind(wx.EVT_BUTTON,
|
self.Bind(wx.EVT_BUTTON,
|
||||||
lambda event: self.path_button_clicked(), btn)
|
lambda event: self.path_button_clicked(), btn)
|
||||||
index = 0
|
index = 0
|
||||||
for cpath in self.cur_paths:
|
for cpath in self.pass_handler.cur_paths:
|
||||||
if cpath != self.curdir:
|
if cpath != self.pass_handler.cur_dir:
|
||||||
label = '🗀 ' + os.path.basename(os.path.normpath(cpath))
|
label = '🗀 ' + os.path.basename(os.path.normpath(cpath))
|
||||||
btn = wx.Button(self.pnl, label=label)
|
btn = wx.Button(self.pnl, label=label)
|
||||||
self.sizer.Add(btn, 0, wx.EXPAND) # pylint: disable=no-member
|
self.sizer.Add(btn, 0, wx.EXPAND) # pylint: disable=no-member
|
||||||
|
@ -56,7 +52,7 @@ class PassUi(wx.Frame):
|
||||||
btn)
|
btn)
|
||||||
index = index + 1
|
index = index + 1
|
||||||
index = 0
|
index = 0
|
||||||
for password in self.cur_passwords:
|
for password in self.pass_handler.cur_passwords:
|
||||||
label = '🗝 ' + os.path.splitext(
|
label = '🗝 ' + os.path.splitext(
|
||||||
os.path.basename(os.path.normpath(password)))[0]
|
os.path.basename(os.path.normpath(password)))[0]
|
||||||
btn = wx.Button(self.pnl, label=label)
|
btn = wx.Button(self.pnl, label=label)
|
||||||
|
@ -106,7 +102,7 @@ class PassUi(wx.Frame):
|
||||||
|
|
||||||
:param index:
|
:param index:
|
||||||
"""
|
"""
|
||||||
path = self.get_pass_path_from_index(index, "password")
|
path = self.pass_handler.get_pass_path_from_index(index, "password")
|
||||||
dlg = wx.MessageDialog(self.pnl,
|
dlg = wx.MessageDialog(self.pnl,
|
||||||
"Delete " + path + "?",
|
"Delete " + path + "?",
|
||||||
"Are you sure?",
|
"Are you sure?",
|
||||||
|
@ -115,69 +111,23 @@ class PassUi(wx.Frame):
|
||||||
reply = dlg.ShowModal()
|
reply = dlg.ShowModal()
|
||||||
if reply == wx.ID_CANCEL:
|
if reply == wx.ID_CANCEL:
|
||||||
return
|
return
|
||||||
command1 = ['/usr/bin/pass', 'rm', '-f', path]
|
self.pass_handler.delete_password(path)
|
||||||
run_command(command1)
|
|
||||||
self.move_up()
|
|
||||||
self.cur_paths = self.get_pass_paths()
|
|
||||||
self.cur_passwords = self.get_pass_passwords()
|
|
||||||
self.back_button_clicked()
|
self.back_button_clicked()
|
||||||
|
|
||||||
def get_pass_path_from_index(self, index, pathtype="path"):
|
|
||||||
"""get_pass_path_from_index.
|
|
||||||
|
|
||||||
:param index:
|
|
||||||
:param pathtype:
|
|
||||||
"""
|
|
||||||
if pathtype == "password":
|
|
||||||
result = self.cur_passwords[index]
|
|
||||||
else:
|
|
||||||
result = self.cur_paths[index]
|
|
||||||
return result.replace(self.topdir, '').replace('.gpg', '')
|
|
||||||
|
|
||||||
def get_pass_passwords(self):
|
|
||||||
"""get_pass_passwords."""
|
|
||||||
passwords = []
|
|
||||||
for mfile in os.listdir(self.curdir):
|
|
||||||
if mfile.endswith(".gpg"): # and os.path.isfile(mfile):
|
|
||||||
passwords.append(os.path.join(self.curdir, mfile))
|
|
||||||
passwords = sorted(passwords)
|
|
||||||
return passwords
|
|
||||||
|
|
||||||
def get_pass_paths(self):
|
|
||||||
"""get_pass_paths."""
|
|
||||||
dirs = []
|
|
||||||
if self.curdir != self.topdir:
|
|
||||||
dirs.append(self.curdir)
|
|
||||||
for cdir in os.listdir(self.curdir):
|
|
||||||
if os.path.isdir(os.path.join(self.curdir,
|
|
||||||
cdir)) and cdir != ".git":
|
|
||||||
dirs.append(os.path.join(self.curdir, cdir))
|
|
||||||
dirs = sorted(dirs)
|
|
||||||
return dirs
|
|
||||||
|
|
||||||
def make_back_button(self, index=None):
|
def make_back_button(self, index=None):
|
||||||
"""make_back_button.
|
"""make_back_button.
|
||||||
|
|
||||||
:param index:
|
:param index:
|
||||||
"""
|
"""
|
||||||
if index is not None:
|
if index is not None:
|
||||||
label = self.get_pass_path_from_index(index, "password")
|
label = self.pass_handler.get_pass_path_from_index(index, "password")
|
||||||
else:
|
else:
|
||||||
label = self.curdir.replace(self.topdir, '')
|
label = self.pass_handler.cur_dir.replace(self.pass_handler.top_dir, '')
|
||||||
btn = wx.Button(self.pnl, label=label + '⤴')
|
btn = wx.Button(self.pnl, label=label + '⤴')
|
||||||
font = btn.GetFont().MakeItalic().MakeBold()
|
font = btn.GetFont().MakeItalic().MakeBold()
|
||||||
btn.SetFont(font)
|
btn.SetFont(font)
|
||||||
return btn
|
return btn
|
||||||
|
|
||||||
def move_up(self):
|
|
||||||
"""move_up."""
|
|
||||||
if self.curdir == self.topdir:
|
|
||||||
return True
|
|
||||||
if not os.path.isdir(self.curdir):
|
|
||||||
self.curdir = os.path.abspath(os.path.join(self.curdir, os.pardir))
|
|
||||||
self.move_up()
|
|
||||||
return True
|
|
||||||
|
|
||||||
def password_button_clicked(self, index):
|
def password_button_clicked(self, index):
|
||||||
"""password_button_clicked.
|
"""password_button_clicked.
|
||||||
|
|
||||||
|
@ -191,10 +141,10 @@ class PassUi(wx.Frame):
|
||||||
:param path:
|
:param path:
|
||||||
"""
|
"""
|
||||||
if path is None:
|
if path is None:
|
||||||
path = os.path.abspath(os.path.join(self.curdir, os.pardir))
|
path = os.path.abspath(os.path.join(self.pass_handler.cur_dir, os.pardir))
|
||||||
self.curdir = path
|
self.pass_handler.cur_dir = path
|
||||||
self.cur_paths = self.get_pass_paths()
|
self.pass_handler.cur_paths = self.pass_handler.get_pass_paths()
|
||||||
self.cur_passwords = self.get_pass_passwords()
|
self.pass_handler.cur_passwords = self.pass_handler.get_pass_passwords()
|
||||||
self.add_buttons()
|
self.add_buttons()
|
||||||
|
|
||||||
def save_to_pass(self, path, text, name=None):
|
def save_to_pass(self, path, text, name=None):
|
||||||
|
@ -204,10 +154,10 @@ class PassUi(wx.Frame):
|
||||||
:param text:
|
:param text:
|
||||||
:param name:
|
:param name:
|
||||||
"""
|
"""
|
||||||
fullpath = os.path.dirname(self.topdir + '/' + path.lstrip('/'))
|
fullpath = os.path.dirname(self.pass_handler.top_dir + '/' + path.lstrip('/'))
|
||||||
if name is not None:
|
if name is not None:
|
||||||
path = name.GetLineText(0)
|
path = name.GetLineText(0)
|
||||||
fullpath = os.path.dirname(self.topdir + '/' + path.lstrip('/'))
|
fullpath = os.path.dirname(self.pass_handler.top_dir + '/' + path.lstrip('/'))
|
||||||
filename = fullpath + '.gpg'
|
filename = fullpath + '.gpg'
|
||||||
if os.path.exists(fullpath) or os.path.exists(filename):
|
if os.path.exists(fullpath) or os.path.exists(filename):
|
||||||
dlg = wx.MessageDialog(
|
dlg = wx.MessageDialog(
|
||||||
|
@ -222,8 +172,7 @@ class PassUi(wx.Frame):
|
||||||
dlg = wx.MessageDialog(self.pnl,
|
dlg = wx.MessageDialog(self.pnl,
|
||||||
"Save to " + path + "?",
|
"Save to " + path + "?",
|
||||||
"Are you sure?",
|
"Are you sure?",
|
||||||
style=wx.CANCEL | wx.CANCEL_DEFAULT
|
style=wx.CANCEL | wx.CANCEL_DEFAULT | wx.OK)
|
||||||
| wx.OK)
|
|
||||||
dlg.SetOKCancelLabels("&Yes", "&Don't save")
|
dlg.SetOKCancelLabels("&Yes", "&Don't save")
|
||||||
reply = dlg.ShowModal()
|
reply = dlg.ShowModal()
|
||||||
if reply == wx.ID_CANCEL:
|
if reply == wx.ID_CANCEL:
|
||||||
|
@ -233,11 +182,7 @@ class PassUi(wx.Frame):
|
||||||
password += text.GetLineText(lineno)
|
password += text.GetLineText(lineno)
|
||||||
password += '\n'
|
password += '\n'
|
||||||
|
|
||||||
command1 = ['/bin/echo', password.rstrip("\n")]
|
self.pass_handler.save_to_pass(password,path,fullpath)
|
||||||
command2 = ['/usr/bin/pass', 'insert', '-m', path]
|
|
||||||
run_command(command1, command2)
|
|
||||||
self.cur_paths = sorted([fullpath] + self.cur_paths)
|
|
||||||
self.cur_passwords = self.get_pass_passwords()
|
|
||||||
self.back_button_clicked()
|
self.back_button_clicked()
|
||||||
|
|
||||||
def show_new_dialog(self):
|
def show_new_dialog(self):
|
||||||
|
@ -245,11 +190,11 @@ class PassUi(wx.Frame):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
self.sizer.Clear(delete_windows=True)
|
self.sizer.Clear(delete_windows=True)
|
||||||
passpath = self.curdir.replace(self.topdir, '')
|
passpath = self.pass_handler.cur_dir.replace(self.pass_handler.top_dir, '')
|
||||||
btn = self.make_back_button()
|
btn = self.make_back_button()
|
||||||
self.sizer.Add(btn, 0, wx.EXPAND) # pylint: disable=no-member
|
self.sizer.Add(btn, 0, wx.EXPAND) # pylint: disable=no-member
|
||||||
self.Bind(wx.EVT_BUTTON,
|
self.Bind(wx.EVT_BUTTON,
|
||||||
lambda event, path=self.curdir: self.path_button_clicked(
|
lambda event, path=self.pass_handler.cur_dir: self.path_button_clicked(
|
||||||
path),
|
path),
|
||||||
btn)
|
btn)
|
||||||
|
|
||||||
|
@ -282,8 +227,8 @@ class PassUi(wx.Frame):
|
||||||
self.sizer.Clear(delete_windows=True)
|
self.sizer.Clear(delete_windows=True)
|
||||||
self.add_tools(index)
|
self.add_tools(index)
|
||||||
|
|
||||||
passpath = self.get_pass_path_from_index(index, "password")
|
passpath = self.pass_handler.get_pass_path_from_index(index, "password")
|
||||||
cpath = self.topdir + os.path.dirname(passpath)
|
cpath = self.pass_handler.top_dir + os.path.dirname(passpath)
|
||||||
password = get_password_from_path(passpath)
|
password = get_password_from_path(passpath)
|
||||||
|
|
||||||
btn = self.make_back_button(index)
|
btn = self.make_back_button(index)
|
||||||
|
@ -320,8 +265,8 @@ class PassUi(wx.Frame):
|
||||||
"""
|
"""
|
||||||
self.sizer.Clear(delete_windows=True)
|
self.sizer.Clear(delete_windows=True)
|
||||||
self.add_tools(index)
|
self.add_tools(index)
|
||||||
passpath = self.get_pass_path_from_index(index, "password")
|
passpath = self.pass_handler.get_pass_path_from_index(index, "password")
|
||||||
cpath = self.topdir + os.path.dirname(passpath)
|
cpath = self.pass_handler.top_dir + os.path.dirname(passpath)
|
||||||
password = get_password_from_path(passpath)
|
password = get_password_from_path(passpath)
|
||||||
btn = self.make_back_button(index)
|
btn = self.make_back_button(index)
|
||||||
self.sizer.Add(btn, 0, wx.EXPAND) # pylint: disable=no-member
|
self.sizer.Add(btn, 0, wx.EXPAND) # pylint: disable=no-member
|
||||||
|
@ -373,63 +318,6 @@ class PassUi(wx.Frame):
|
||||||
self.sizer.Layout()
|
self.sizer.Layout()
|
||||||
|
|
||||||
|
|
||||||
def copy_to_clipboard(text):
|
|
||||||
"""copy_to_clipboard.
|
|
||||||
|
|
||||||
:param text:
|
|
||||||
"""
|
|
||||||
password = text.split('\n')[0]
|
|
||||||
command1 = ['/bin/echo', password]
|
|
||||||
command2 = ['/usr/bin/wl-copy']
|
|
||||||
result = run_command(command1, command2)
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
def get_password_from_path(passpath):
|
|
||||||
"""get_password_from_path.
|
|
||||||
|
|
||||||
:param passpath:
|
|
||||||
"""
|
|
||||||
result = run_command(['/usr/bin/pass', 'show', passpath])
|
|
||||||
password = result[0].decode()
|
|
||||||
return password
|
|
||||||
|
|
||||||
|
|
||||||
def pass_pull():
|
|
||||||
"""pass_pull.
|
|
||||||
|
|
||||||
"""
|
|
||||||
run_command(['/usr/bin/pass', 'git', 'pull'])
|
|
||||||
|
|
||||||
|
|
||||||
def pass_push():
|
|
||||||
"""pass_push.
|
|
||||||
|
|
||||||
"""
|
|
||||||
run_command(['/usr/bin/pass', 'git', 'push'])
|
|
||||||
|
|
||||||
|
|
||||||
def run_command(command1, command2=None):
|
|
||||||
"""Run a command on system and capture result
|
|
||||||
|
|
||||||
:param command1:
|
|
||||||
:param command2:
|
|
||||||
"""
|
|
||||||
process1 = subprocess.Popen(command1,
|
|
||||||
shell=False,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
# If there is a second command it is taken to be a pipline
|
|
||||||
if command2:
|
|
||||||
subprocess.Popen(command2,
|
|
||||||
shell=False,
|
|
||||||
stdin=process1.stdout,
|
|
||||||
stdout=subprocess.PIPE,
|
|
||||||
stderr=subprocess.PIPE)
|
|
||||||
process1.stdout.close()
|
|
||||||
return process1.communicate()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
# When this module is run (not imported) then create the app, the
|
# When this module is run (not imported) then create the app, the
|
||||||
# frame, show it, and start the event loop.
|
# frame, show it, and start the event loop.
|
132
src/pass_handler/__init__.py
Normal file
132
src/pass_handler/__init__.py
Normal file
|
@ -0,0 +1,132 @@
|
||||||
|
#!/usr/bin/python3
|
||||||
|
import os
|
||||||
|
import subprocess
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
|
class Pass:
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.top_dir: str = os.environ.get('PASSWORD_STORE_DIR')
|
||||||
|
if not self.top_dir:
|
||||||
|
self.top_dir = os.environ.get('HOME') + '/.password-store'
|
||||||
|
self.cur_dir: str = self.top_dir
|
||||||
|
self.cur_paths: list[str] = self.get_pass_paths()
|
||||||
|
self.cur_passwords: list[str] = self.get_pass_passwords()
|
||||||
|
|
||||||
|
def delete_password(self, path: str):
|
||||||
|
"""delete_password.
|
||||||
|
|
||||||
|
:param path: str
|
||||||
|
"""
|
||||||
|
command1: list[str] = ['/usr/bin/pass', 'rm', '-f', path]
|
||||||
|
run_command(command1)
|
||||||
|
self.move_up()
|
||||||
|
self.cur_paths = self.get_pass_paths()
|
||||||
|
self.cur_passwords = self.get_pass_passwords()
|
||||||
|
|
||||||
|
def get_pass_path_from_index(self, index: int, path_type: str = "path") -> str:
|
||||||
|
"""get_pass_path_from_index.
|
||||||
|
|
||||||
|
:param index: int
|
||||||
|
:param path_type: str, default: "path"
|
||||||
|
"""
|
||||||
|
if path_type == "password":
|
||||||
|
result: str = self.cur_passwords[index]
|
||||||
|
else:
|
||||||
|
result: str = self.cur_paths[index]
|
||||||
|
return result.replace(self.top_dir, '').replace('.gpg', '')
|
||||||
|
|
||||||
|
def get_pass_passwords(self) -> list[str]:
|
||||||
|
"""get_pass_passwords."""
|
||||||
|
passwords: list[str] = list()
|
||||||
|
for m_file in os.listdir(self.cur_dir):
|
||||||
|
if m_file.endswith(".gpg"):
|
||||||
|
passwords.append(os.path.join(self.cur_dir, m_file))
|
||||||
|
passwords = sorted(passwords)
|
||||||
|
return passwords
|
||||||
|
|
||||||
|
def get_pass_paths(self) -> list[str]:
|
||||||
|
"""get_pass_paths."""
|
||||||
|
dirs: list[str] = list()
|
||||||
|
if self.cur_dir != self.top_dir:
|
||||||
|
dirs.append(self.cur_dir)
|
||||||
|
for c_dir in os.listdir(self.cur_dir):
|
||||||
|
if os.path.isdir(os.path.join(self.cur_dir,
|
||||||
|
c_dir)) and c_dir != ".git":
|
||||||
|
dirs.append(os.path.join(self.cur_dir, c_dir))
|
||||||
|
dirs = sorted(dirs)
|
||||||
|
return dirs
|
||||||
|
|
||||||
|
def move_up(self) -> bool:
|
||||||
|
"""move_up."""
|
||||||
|
if self.cur_dir == self.top_dir:
|
||||||
|
return True
|
||||||
|
if not os.path.isdir(self.cur_dir):
|
||||||
|
self.cur_dir = os.path.abspath(os.path.join(self.cur_dir, os.pardir))
|
||||||
|
self.move_up()
|
||||||
|
return True
|
||||||
|
|
||||||
|
def save_to_pass(self, password, path, full_path):
|
||||||
|
command1: list[str] = ['/bin/echo', password.rstrip("\n")]
|
||||||
|
command2: list[str] = ['/usr/bin/pass', 'insert', '-m', path]
|
||||||
|
run_command(command1, command2)
|
||||||
|
self.cur_paths = sorted([full_path] + self.cur_paths)
|
||||||
|
self.cur_passwords = self.get_pass_passwords()
|
||||||
|
|
||||||
|
|
||||||
|
def copy_to_clipboard(text) -> tuple[Union[str, bytes], Union[str, bytes]]:
|
||||||
|
"""copy_to_clipboard.
|
||||||
|
|
||||||
|
:param text:
|
||||||
|
"""
|
||||||
|
password: str = text.split('\n')[0]
|
||||||
|
command1: list[str] = ['/bin/echo', password]
|
||||||
|
command2: list[str] = ['/usr/bin/wl-copy']
|
||||||
|
result: tuple[Union[str, bytes], Union[str, bytes]] = run_command(command1, command2)
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def get_password_from_path(pass_path) -> str:
|
||||||
|
"""get_password_from_path.
|
||||||
|
|
||||||
|
:param pass_path:
|
||||||
|
"""
|
||||||
|
result: tuple[Union[str, bytes], Union[str, bytes]] = run_command(['/usr/bin/pass', 'show', pass_path])
|
||||||
|
password: str = result[0].decode()
|
||||||
|
return password
|
||||||
|
|
||||||
|
|
||||||
|
def pass_pull():
|
||||||
|
"""pass_pull.
|
||||||
|
|
||||||
|
"""
|
||||||
|
run_command(['/usr/bin/pass', 'git', 'pull'])
|
||||||
|
|
||||||
|
|
||||||
|
def pass_push():
|
||||||
|
"""pass_push.
|
||||||
|
|
||||||
|
"""
|
||||||
|
run_command(['/usr/bin/pass', 'git', 'push'])
|
||||||
|
|
||||||
|
|
||||||
|
def run_command(command1, command2=None) -> tuple[Union[str, bytes], Union[str, bytes]]:
|
||||||
|
"""Run a command on system and capture result
|
||||||
|
|
||||||
|
:param command1:
|
||||||
|
:param command2:
|
||||||
|
"""
|
||||||
|
process1: subprocess.Popen = subprocess.Popen(command1,
|
||||||
|
shell=False,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
# If there is a second command it is taken to be a pipeline
|
||||||
|
if command2:
|
||||||
|
subprocess.Popen(command2,
|
||||||
|
shell=False,
|
||||||
|
stdin=process1.stdout,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE)
|
||||||
|
process1.stdout.close()
|
||||||
|
return process1.communicate()
|
BIN
src/pass_handler/__pycache__/__init__.cpython-39.pyc
Normal file
BIN
src/pass_handler/__pycache__/__init__.cpython-39.pyc
Normal file
Binary file not shown.
Loading…
Add table
Reference in a new issue