Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: List logged dnf transaction cmds as txt or json #2149

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
113 changes: 87 additions & 26 deletions dnf/cli/commands/history.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,20 @@ def set_argparser(parser):
HistoryCommand._CMDS[0],
", ".join(HistoryCommand._CMDS[1:])))
parser.add_argument('--reverse', action='store_true',
help="display history list output reversed")
help="display history list output in reverse "
"(in ascending order with the first transaction first)")

parser.add_argument("-o", "--output", default=None,
help=_("For the store command, file path to store the transaction to"))
help=_("For the store command, file path to store history transactions in "
"(default: transaction[s].[json|txt])"))
parser.add_argument("-a", "--all", dest='store_all', action='store_true', default=False,
help=_("For the store command, whether to store all transactions"))
parser.add_argument("--commands", dest='store_shell_commands', action='store_true', default=False,
help=_("For the store command, whether to store just shell command(s) in a transaction(s).txt"))
parser.add_argument("--comments", dest='store_shell_command_comments', action='store_true', default=False,
help=_("For the store command, whether to include comments before "
"history transaction shell command(s)"))

parser.add_argument("--ignore-installed", action="store_true",
help=_("For the replay command, don't check for installed packages matching "
"those in transaction"))
Expand Down Expand Up @@ -117,9 +128,10 @@ def configure(self):

dnf.cli.commands._checkGPGKey(self.base, self.cli)
elif self.opts.transactions_action == 'store':
self._require_one_transaction_id = True
if not self.opts.transactions:
raise dnf.cli.CliError(_('No transaction ID or package name given.'))
self._require_one_transaction_id = True # TODO
if not self.opts.store_all:
if not self.opts.transactions:
raise dnf.cli.CliError(_('No transaction ID or package name or -a/--all given.'))
elif self.opts.transactions_action in ['redo', 'undo', 'rollback']:
demands.available_repos = True
demands.resolving = True
Expand Down Expand Up @@ -179,6 +191,10 @@ def _history_get_transactions(self, extcmds):
raise dnf.cli.CliError(_('Transaction ID "{0}" not found.').format(extcmds[0]))
return old

def _history_get_all_transactions(self, extcmds=None):
old = self.base.history.old(extcmds)
return old

def _history_get_transaction(self, extcmds):
old = self._history_get_transactions(extcmds)
if len(old) > 1:
Expand Down Expand Up @@ -358,27 +374,72 @@ def run(self):
elif vcmd == 'userinstalled':
self._hcmd_userinstalled()
elif vcmd == 'store':
tid = self._history_get_transaction(tids)
data = serialize_transaction(tid)
try:
filename = self.opts.output if self.opts.output is not None else "transaction.json"

# it is absolutely possible for both assumeyes and assumeno to be True, go figure
if (self.base.conf.assumeno or not self.base.conf.assumeyes) and os.path.isfile(filename):
msg = _("{} exists, overwrite?").format(filename)
if self.base.conf.assumeno or not self.base.output.userconfirm(
msg='\n{} [y/N]: '.format(msg), defaultyes_msg='\n{} [Y/n]: '.format(msg)):
print(_("Not overwriting {}, exiting.").format(filename))
return

with open(filename, "w") as f:
json.dump(data, f, indent=4, sort_keys=True)
f.write("\n")

print(_("Transaction saved to {}.").format(filename))

except OSError as e:
raise dnf.cli.CliError(_('Error storing transaction: {}').format(str(e)))
if self.opts.store_all:
self._hcmd_store_all(tids)
else:
self._hcmd_store(tids)

def _hcmd_store(self, extcmd):
tid = self._history_get_transaction(extcmd)
data = serialize_transaction(tid)
try:
filename = self.opts.output if self.opts.output is not None else "transaction.json"
self._write_json(filename, data)
except OSError as e:
raise dnf.cli.CliError(_('Error storing transaction: {}').format(str(e)))

def _hcmd_store_all(self, extcmd):
#breakpoint()
transactions = self._history_get_all_transactions(extcmd)
data = {}
for txn in transactions:
data[txn.tid] = serialize_transaction(txn)
if not self.opts.store_shell_commands and not self.opts.store_shell_command_comments:
try:
filename = self.opts.output if self.opts.output is not None else "transactions.json"
self._write_json(filename, data)
except OSError as e:
raise dnf.cli.CliError(_('Error storing transactions: {}').format(str(e)))
else:
filename = self.opts.output if self.opts.output is not None else "transactions.txt"
try:
with open(filename, 'w') as f:
for transaction in reversed(transactions):
tid = transaction.tid
#breakpoint()
if self.opts.store_shell_command_comments:
transaction_dict = {'tid': transaction.tid} #serialize_transaction(transaction)
#transaction_dict['cmdline'] = str(transaction.cmdline)
transaction_dict['uid'] = dnf.cli.output.Output._pwd_ui_username(
dnf.cli.output.Output, transaction.loginuid, limit=24) # TODO: why 24?
#f.write(f'## dnf history info {transaction.tid} \n') # TODO: which fields only
f.write(f"## {transaction_dict} \n")
if transaction.cmdline is None:
cmdlines = []
elif isinstance(transaction.cmdline, (tuple, list)):
cmdlines = transaction.cmdline
else:
cmdlines = [transaction.cmdline]
for cmdline in cmdlines:
f.write("dnf {}\n".format(cmdline))
except OSError as e:
raise dnf.cli.CliError(_('Error storing transactions: {}').format(str(e)))
print(_("Wrote transactions to: ")+filename)


def _write_json(self, filename, data):
# it is absolutely possible for both assumeyes and assumeno to be True, go figure
if (self.base.conf.assumeno or not self.base.conf.assumeyes) and os.path.isfile(filename):
msg = _("{} exists, overwrite?").format(filename)
if self.base.conf.assumeno or not self.base.output.userconfirm(
msg='\n{} [y/N]: '.format(msg), defaultyes_msg='\n{} [Y/n]: '.format(msg)):
print(_("Not overwriting {}, exiting.").format(filename))
return

with open(filename, "w") as f:
json.dump(data, f, indent=4, sort_keys=True)
f.write("\n")
print(_("Transaction saved to {}.").format(filename))

def run_resolved(self):
if self.opts.transactions_action not in ("replay", "redo", "rollback", "undo"):
Expand Down
54 changes: 54 additions & 0 deletions scripts/install_env_in_a_virtualenv.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#!/bin/sh

# contribscript.sh -- run dnf from a local clone in a virtualenv

setup_const_py_in() {
#prefix=$_WRD cd "$prefix"
cp dnf/const.py.in dnf/const.py && \
sed -i "s/^VERSION[[:blank:]]*=.*/VERSION='0.0.1-todo'/; s/^PLUGINPATH[[:blank:]]*=.*/PLUGINPATH='$pluginpath'/" dnf/const.py
}

setup_virtualenv_dnf() {
dnfsrcdir="$VIRTUAL_ENV/src/dnf/dnf"

pythonver="python3.12"
systemsitepackages='/usr/lib64/python3.12/site-packages'
VIRTUAL_ENV_sitepackages="${VIRTUAL_ENV}/lib/python3.12/site-packages"
(set -x; cd "${VIRTUAL_ENV_sitepackages}";
ln -s "${systemsitepackages}/rpm";
ln -s "${systemsitepackages}/hawkey";
ln -s "${systemsitepackages}/libcomps";
ln -s "${dnfsrcdir}";
#ln -s /usr/lib64/libdnf.so.2;
)

}

test_virtualenv_dnf() {
set -ex
_WRD=$VIRTUAL_ENV/src/dnf
#PYTHONPATH=${_WRD} LD_LIBRARY_PATH=/usr/lib64 python $_WRD/dnf/cli/main.py
#PYTHONPATH=${_WRD} LD_LIBRARY_PATH=/usr/lib64 python $_WRD/dnf/cli/main.py
#PYTHONPATH=${_WRD} LD_LIBRARY_PATH=/usr/lib64 python $_WRD/dnf/cli/main.py history -h
#PYTHONPATH=${_WRD} python $_WRD/dnf/cli/main.py history -h
python "${_WRD}/dnf/cli/main.py" history -h

python "${_WRD}/dnf/cli/main.py" history store --all
cat ./transactions.json

python "${_WRD}/dnf/cli/main.py" history store --all --comments
cat ./transactions.txt

python "${_WRD}/dnf/cli/main.py" history store --all --commands
cat ./transactions.txt

}

main() {
if [ ! `id -g` -eq 0 ]; then
(set -x; setup_virtualenv_dnf)
fi
test_virtualenv_dnf
}

main
Loading