web-dev-qa-db-ja.com

コマンドラインからのトレイでの通知の進行状況

OpenSuse 42.1 + KDE 5

スクリプトでkdialogを使用して、プロセスの開始/終了を通知します

#!/bin/sh
while inotifywait -r -e modify -e create -e delete ~/www/gruz.org.uab/www/; do
    kdialog --passivepopup 'Started' --title 'UNISON update';
    unison   -ui text -auto -batch gruz.org.uab
    kdialog --passivepopup 'Finished' --title 'UNISON update';
done

ただし、ポップアップは一部の表示領域をカバーしているため、ファイルをコピーするときのように、システムトレイの進行状況インジケーターに置き換えたいと思います。

http://static.xscreenshot.com/small/2016/08/04/13/screen_c0544580363c95b1458ba32ad0dcb741

qdbus org.kde.JobViewServer.requestViewのようなものについて読みましたが、知識が不足しているため、実装できませんでした。

コマンドラインの例(または他の同等のもの)をに提供していただけますか

  • プロセスを実行する
  • トレイの開始インジケーター
  • 終了時の停止インジケーター

ありがとう、親愛なるすべて

3
Gruz

シェルスクリプトからqdbus org.kde.JobViewServer.requestViewを使用する場合の問題は、要求しているD-Busクライアントが終了したときに通知を削除するように設計されているため、dbus-sendqdbusなどのツールが機能しないことです。 requestViewを呼び出した直後に終了します。

qdbusviewerを使用してリクエストを作成すると、このような呼び出しを試してみることができ、それは機能しますが、シェルスクリプトから呼び出すことができる既製のものが見つかるかどうかは疑わしいです。接続を開いたままにします。

# Assuming qdbusviewer got /JobViewServer/JobView_15 from the call...

qdbus org.kde.kuiserver /JobViewServer/JobView_15 org.kde.JobViewV2.setInfoMessage 'Frobnicating the foobles...'
qdbus org.kde.kuiserver /JobViewServer/JobView_15 org.kde.JobViewV2.setDescriptionField 1 Cromulence fair
qdbus org.kde.kuiserver /JobViewServer/JobView_15 org.kde.JobViewV2.setPercent 25
qdbus org.kde.kuiserver /JobViewServer/JobView_15 org.kde.JobViewV2.setSpeed 200
qdbus org.kde.kuiserver /JobViewServer/JobView_15 org.kde.JobViewV2.setTotalAmount 100000 bytes
qdbus org.kde.kuiserver /JobViewServer/JobView_15 org.kde.JobViewV2.setProcessedAmount 200 bytes

qdbus org.kde.kuiserver /JobViewServer/JobView_15 org.kde.JobViewV2.terminate 'Received Ctrl+C'

ただし、シェルスクリプトの代わりに少しPythonを使用したい場合は、doesが機能し、Pythonを保証できる例を提供できます。同じタスクのシェルスクリプトの非常に優れた代替手段として。

これは、イベントループを設定せずに、可能な限り多くの関連機能を示すために書かれています。

#!/usr/bin/env python

# This line opts into some Python 3.x features if you run Python 2.x
# and must go at the top of the file because it changes how the file is parsed.
# (Specifically, the Python 3.x print() syntax and sane division)
from __future__ import print_function, division

# These lines are analogous to `source` in a Shell script
# The `import` statement searches `sys.path` for the requested packages
import fnmatch, os, subprocess, time

# I'm not sure what package you'll need on OpenSUSE, but this comes from
# python-dbus on Debian, *buntu, and Mint.
import dbus

# -- Get a handle for the D-Bus API to create a new Job --

session_bus = dbus.SessionBus()

# A simple little helper function to paper over some complexity
# See Also: https://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html
def get_dbus_interface(name, path, interface):
    obj = session_bus.get_object(name, path)
    return dbus.Interface(obj, dbus_interface=interface)

create_handle = get_dbus_interface(
    'org.kde.kuiserver', '/JobViewServer', 'org.kde.JobViewServer')

# -- Create a Job and get a handle to manipulate it --

# requestView takes (appName, appIconName, capabilities)
# https://lists.freedesktop.org/archives/xdg/2008-April/009410.html
# ...but according to the source code, capabilities never got hooked up, so
# the pause and stop buttons will always be there, whether or not you're
# listening for them. (And stop will always kill the popup.)
request_path = create_handle.requestView('MyTestApp', 'download', 0)
request_handle = get_dbus_interface(
    'org.kde.kuiserver', request_path, 'org.kde.JobViewV2')

# -- Set up a fake task for demonstration purposes --
files = os.listdir('/etc')  # NOTE: Check out os.walk() for recursive
file_count = len(files)
wait_per_file = 5.0 / file_count  # Add 2 seconds to the total runtime

# -- Configure the bits of the popup that won't change in our example --
request_handle.setInfoMessage('Echoing files in /etc')
request_handle.setTotalAmount(file_count, 'files')
request_handle.setSpeed(200 * 1024**4)  # 200 TiB/s

# -- Do our fake work --

# NOTE: In Python, indentation outside of () and [] is significant
try:
    for position, filename in enumerate(files):
        # Visible in the collapsed view
        request_handle.setPercent((position / file_count) * 100)
        request_handle.setDescriptionField(0, 'Source', filename)
        request_handle.setDescriptionField(1, 'Destination', filename)

        # These are for the expanded view
        request_handle.setProcessedAmount(position, 'files')

        # Here's some fake work so you can see how to call subprocesses
        subprocess.call(['echo', filename])
        time.sleep(wait_per_file)

    # Set the final state of the popup that will be left behind
    request_handle.setDescriptionField(0, "", "Completed successfully.")
    request_handle.clearDescriptionField(1)
    request_handle.terminate("All done")
except KeyboardInterrupt:
    print("Ctrl+C Pressed")
    request_handle.setDescriptionField(0, "Cancelled", "Ctrl+C Pressed")
    request_handle.clearDescriptionField(1)
    request_handle.terminate("Cancelled from outside")
finally:
    # This gets called no matter what
    print("Doing fake cleanup")

print("%s of the files were *.conf" % len(fnmatch.filter(files, '*.conf')))
2
ssokolow

進行状況インジケーターを使用してbashコマンドを実行するために、pythonスクリプトを変更しました。進行状況は表示されませんが、何かがまだ実行されているかどうかは確認できます。

#!/usr/bin/env python
# This line opts into some Python 3.x features if you run Python 2.x
# and must go at the top of the file because it changes how the file is parsed.
# (Specifically, the Python 3.x print() syntax and sane division)
from __future__ import print_function, division

# These lines are analogous to `source` in a Shell script
# The `import` statement searches `sys.path` for the requested packages
import subprocess, time

# I'm not sure what package you'll need on OpenSUSE, but this comes from
# python-dbus on Debian, *buntu, and Mint.
import dbus

# Get command line parameters
import sys

# Run bash script in background
import threading

# -- Get a handle for the D-Bus API to create a new Job --

session_bus = dbus.SessionBus()


# A simple little helper function to paper over some complexity
# See Also: https://dbus.freedesktop.org/doc/dbus-python/doc/tutorial.html
def get_dbus_interface(name, path, interface):
    obj = session_bus.get_object(name, path)
    return dbus.Interface(obj, dbus_interface=interface)


def run_bash_command(command):
    try:
        subprocess.call(command, Shell=False)
    except Exception as e:
        print("Exception: ")
        print(e)


def main():
    create_handle = get_dbus_interface(
        'org.kde.kuiserver', '/JobViewServer', 'org.kde.JobViewServer')

    # -- Create a Job and get a handle to manipulate it --

    # requestView takes (appName, appIconName, capabilities)
    # https://lists.freedesktop.org/archives/xdg/2008-April/009410.html
    # ...but according to the source code, capabilities never got hooked up, so
    # the pause and stop buttons will always be there, whether or not you're
    # listening for them. (And stop will always kill the popup.)
    request_path = create_handle.requestView('bash', 'download', 0)
    request_handle = get_dbus_interface(
        'org.kde.kuiserver', request_path, 'org.kde.JobViewV2')

    # -- Configure the bits of the popup that won't change in our example --
    request_handle.setInfoMessage(sys.argv[1])

    # NOTE: In Python, indentation outside of () and [] is significant
    try:
        worker = threading.Thread(target=run_bash_command, args=[sys.argv[1:]])
        worker.start()
        #        for position, filename in enumerate(files):
        #            # Visible in the collapsed view
        request_handle.setPercent(0)
        request_handle.setDescriptionField(0, 'Command:', str(sys.argv[1]))
        request_handle.setDescriptionField(1, 'Arguments:', str(sys.argv[2:]))
        while worker.isAlive():
            time.sleep(1)

        # Set the final state of the popup that will be left behind
        request_handle.setDescriptionField(0, "", "Finished.")
#        request_handle.clearDescriptionField(1)
        request_handle.terminate("All done")
    except KeyboardInterrupt:
        request_handle.setDescriptionField(0, "Cancelled", "Ctrl+C Pressed")
        request_handle.clearDescriptionField(1)
        request_handle.terminate("Cancelled from outside")
    finally:
        # This gets called no matter what
        pass


main()
0
Poleprogger