ベンダー提供の python ツールがあります (これはバイト コンパイルされており、ソースはありません)。このため、ベンダー提供の python 2.4 を使用することにも縛られています。ユーティリティへの道は次のとおりです。
source login.sh
oupload [options]
login.sh はいくつかの環境変数を設定し、次に 2 つのエイリアスを設定します。
odownload () {
${PYTHON_CMD} ${OCLIPATH}/ocli/commands/word_download_command.pyc "$@"
}
oupload () {
${PYTHON_CMD} ${OCLIPATH}/ocli/commands/word_upload_command.pyc "$@"
}
今、私がそれを彼らのやり方で実行すると、うまくいきます。ユーザー名とパスワードの入力を求めるプロンプトが表示されます。
ツールの周りにラッパーを作成して、実行後に追加の手順を実行し、ユーティリティに適切なデフォルトを提供しようとしています。私が直面している問題は、私の人生では、サブプロセスを使用してこれを成功させる方法を理解できないことです。元のコマンドが端末から直接実行されていないことに気付いたようで、ベイルします。
「/usr/local/bin/oupload」を作成し、元の login.sh からコピーしました。唯一の違いは、最後にエイリアスを実行する代わりに、実際にコマンドを実行することです。
次に、私の python スクリプトで、新しいシェル スクリプトを実行しようとします。
if os.path.exists(options.zipfile):
try:
cmd = string.join(cmdargs,' ')
p1 = Popen(cmd, shell=True, stdin=PIPE)
しかし、私は得る:
Enter Opsware Username: Traceback (most recent call last):
File "./command.py", line 31, in main
File "./controller.py", line 51, in handle
File "./controllers/word_upload_controller.py", line 81, in _handle
File "./controller.py", line 66, in _determineNew
File "./lib/util.py", line 83, in determineNew
File "./lib/util.py", line 112, in getAuth
Empty Username not legal
Unknown Error Encountered
SUMMARY:
Name: Empty Username not legal
Description: None
そのため、追加の改行が送信されているように見えました (すべてのオプションを削除しようとしましたが、役に立ちませんでした)。
stdin=PIPE を設定しないと、次のようになります。
Enter Opsware Username: Traceback (most recent call last):
File "./command.py", line 31, in main
File "./controller.py", line 51, in handle
File "./controllers/word_upload_controller.py", line 81, in _handle
File "./controller.py", line 66, in _determineNew
File "./lib/util.py", line 83, in determineNew
File "./lib/util.py", line 109, in getAuth
IOError: [Errno 5] Input/output error
Unknown Error Encountered
shell=False および shell=True とともに p1.communicate、p1.stdin.write() を使用する他のバリエーションを試しましたが、ユーザー名とパスワードを適切に送信する方法を見つけようとしてもうまくいきませんでした. 最後の結果として、提供されたユーティリティのバイトコードを調べてみましたが、役に立ちませんでした。ユーティリティのメインルーチンを適切な引数で呼び出すと、スレッドエラーでコアダンプが発生しました。
最終的な考え - ユーティリティは、入力を「待機」しているように見えたくありません。シェルから実行すると、'Username' プロンプトで一時停止します。python の popen を実行すると、パスワードが指定されていないと仮定して、ただ燃えて終了します。stdinバッファをプリロードする方法を調べようとしました - プロセスが利用可能であればそこから読み取るかもしれないと考えましたが、それが可能かどうかはわかりませんでした。
私は pexpect の使用を避けようとしています。これは主に、ベンダーが提供するプリコンパイル済みライブラリのためにベンダーが提供する python 2.4 を使用する必要があり、スクリプトの配布を可能な限り最小限のフットプリントに維持しようとしているためです。しなければなりません、しなければなりませんが、私はむしろそれを使用したくありません (正直なところ、この状況で機能するかどうかもわかりません)。
他に何を試すことができるかについての考えは、最も高く評価されます。
アップデート
そこで、バイトコードをさらに掘り下げて、コンパイルされたコマンドに欠けているものを見つけ出すことで、これを解決しました。
ただし、これには 2 つの問題がありました。
- ベンダー コードは、呼び出されたときに、完了時に終了していました
- ベンダー コードは stdout に書き込んでおり、これを保存して操作する必要がありました (アップロードされた pkg の ID が含まれています)。ベンダー コードがまだユーザー名/パスワードを要求していたため、stdout をリダイレクトすることはできませんでした。
1 は、コードを try/except 句でラップすることで簡単に解決できました。
2 は、次のようなことを行うことで解決されました: https://stackoverflow.com/a/616672/677373
ログ ファイルの代わりに、cStringIO を使用しました。偽の「フラッシュ」メソッドも実装する必要がありました。これは、ベンダー コードがそれを呼び出していて、stdout 用に提供した新しい obj がそれを提供していないと不平を言っているように見えるためです。コードは次のようになります。
class Logger(object):
def __init__(self):
self.terminal = sys.stdout
self.log = StringIO()
def write(self, message):
self.terminal.write(message)
self.log.write(message)
def flush(self):
self.terminal.flush()
self.log.flush()
if os.path.exists(options.zipfile):
try:
os.environ['OCLI_CODESET'] = 'ISO-8859-1'
backup = sys.stdout
sys.stdout = output = Logger()
# UploadCommand was the command found in the bytecode
upload = UploadCommand()
try:
upload.main(cmdargs)
except Exception, rc:
pass
sys.stdout = backup
# now do some fancy stuff with output from output.log
私が単に except: 節で 'pass' を実行する唯一の理由は、except 節が常に呼び出されることです。「rc」は実際にはコマンドからの戻りコードなので、ゼロ以外の場合の処理を追加する予定です。