ExcelマクロからSVNリポジトリ上の情報を取得する方法

2020年10月20日

こんにちわ、ごさくです。

自己紹介で技術ブログなどを書いていきたいと言いながら、既に3週間近く経過してしまっていました。(反省・・・。)


今回のネタは、自分が今いる現場でExcelマクロからSVNリポジトリ上の情報を取得してその内容をシートに出力する必要性に迫られたのですが、意外に手こずることになりましたので、同じ悩みを抱えた方の少しでも手助けになればと思い、ごさくが実施した方法を情報共有させていただければと思います。

まずごさくが実験した環境(前提条件)は以下のようになります。

【実行環境】
クライアント環境
・OS:Windows10
・SVNクライアントソフト:TotoiseSVN、Apache-Subversion command line tools

サーバ環境
・OS:Windows Server2012 R2
・バージョン管理ソフト:Apache-Subversion-1.14.0

【前提条件】
以下のサイトから「Apache-Subversion command line tools」ダウンロードして、ローカル環境の任意の場所に配置して下さい。
上記ツールは以下のサイトからダウンロードできます。
https://www.visualsvn.com/downloads/

【事前準備】
Excelマクロでコマンドプロンプトを実行するには、事前にメニュー「ツール」→「参照設定」で「Windows Script Host Object Model」にチェックを入れておく必要性があります。

【Exceマクロの仕様】
以下の仕様のマクロサンプルになります。
・Excelマクロからコマンドプロンプトを起動し、SVNコマンド経由でSVNリポジトリ上の一覧内容を取得して、特定のセルに書き込む。

以下、2パターン作成してみました。

パターン①:コマンドプロンプトを表示したままSVNリポジトリ上の内容をセルに書き込む。

Sub checkSVN1()
  Dim svn_output_sheet As Worksheet ' svnリスト出力結果格納シート
  Dim wsh As New IWshRuntimeLibrary.WshShell ' WshShellクラスインスタンス
  Dim do_cmd As WshExec ' コマンドプロンプトを起動し、入力するコマンドを格納
  Dim each_cmd(2) As String  ’ コマンドプロンプト上で入力するコマンド
  Dim all_cmd As String  ’ コマンドプロンプト上で入力するコマンドを連結させたもの
  Dim svn_command_tools_path As String ’ SVNコマンドツール パス
  Dim svnUrl As String   ’ SVNリポジトリ上URL
  Dim cmdcnt As Integer  ’ コマンドループカウンタ
  Dim colcnt As Integer   ’ SVN出力結果ループカウンタ
  Dim filedatas() As String  ’ コマンド実行結果格納リスト
  Dim filedata As String   ’ コマンド実行結果1行

  ’ ワークシートの設定
  Set svn_output_sheet = ThisWorkbook.Worksheets(“svnコマンド結果出力")

  ’ SVNコマンドツールパス
  svn_command_tools_path = “D:\Apache-Subversion-1.14.0\bin"

  ’——————————————————————————-
  ’ コマンドの作成
  ’——————————————————————————-
  ’ ※IPアドレス部分は実際のIPアドレスを指定して下さい。
  svnUrl = “svn://IPアドレス/testpackage/tags/release/test1"

  ’ コマンドプロンプトの操作コマンド
  each_cmd(0) = “D:"
  each_cmd(1) = “cd " & svn_command_tools_path
  ’ SVNユーザ名:test1、SVNパスワード:test1とします。
  each_cmd(2) = “svn ls –username test1 –password test1 –no-auth-cache –non-interactive -R " & svnUrl

  ’ 各コマンドを"&"で連結する
  For cmdcnt = 0 To UBound(each_cmd)
    If (cmdcnt > 0) Then
      all_cmd = all_cmd & " & “
    End If
    all_cmd = all_cmd & each_cmd(cmdcnt)
  Next

  ’——————————————————————————–
  ’ コマンドプロンプト上でコマンドの実行
  ’——————————————————————————–
  Set do_cmd = wsh.Exec(“cmd.exe /c " & all_cmd)
  ’ コマンドの実行が終わるのを待つ
  Do While do_cmd.Status = 0
    DoEvents
  Loop

  ’ 結果を改行区切りにし格納
  filedatas = Split(do_cmd.StdOut.ReadAll, vbCrLf)

  ’ 「svnコマンド結果出力」シートに結果を書き込む
  colcnt = 1
  For Each filedata In filedatas
    svn_output_sheet.Cells(colcnt, 1).Value = filedata
    colcnt = colcnt + 1
  Next

  ’ 初期化
  Set wsh = Nothing
  all_cmd = “"

End Sub

【パターン①で実施した場合のメリット】
パターン①のメリットとしては、「WshShell」クラスのexec関数を使用しているため、コマンドの実行結果を取得することが出来ます。Run関数では実行結果を取得することが出来ないため、今回のような「svn ls」や「dir」コマンドなど、出力結果を使用したい場合はexec関数を使用することになります。

【パターン①で実施した場合のデメリット】
では反対にパターン①のデメリットとしてはどのようなものがあるかというと、exec関数で実施した場合は必ずコマンドプロンプト画面がWindows上に表示されてしまうという点になります。サンプル例ではSVN-URLを固定のパスにしていますが、複数のSVN-URLパスからリスト情報を取得したいという場合は、SVNコマンドが実行されるたびにコマンドプロンプトが表示されてしまいます。ちょっと鬱陶しいと感じますよね?
またexec関数で呼び出す場合、コマンド上の処理が終わるまで、ここでマクロ自体が停止してしまうという問題があります。

上記パターン①のデメリットを解決する案として、以下のパターン②があります。

パターン②:コマンドプロンプトを表示せずにSVNリポジトリ上の内容をセルに書き込む。

Sub checkSVN2()
  ’ (checkSVN1関数と同じ変数定義は記載を省略)
  Dim svnOutputPath As String ’ SVN結果一時ファイルパス
  Dim fileNumber As Integer
  Dim textLine As String

  ’ ワークシートの設定
  Set svn_output_sheet = ThisWorkbook.Worksheets(“svnコマンド結果出力")

  ’ SVNコマンドツールパス
  svn_command_tools_path = “D:\Apache-Subversion-1.14.0\bin"

  ’——————————————————————————-
  ’ コマンドの作成
  ’——————————————————————————-
  ’ (コマンドの生成方法は、checkSVN1関数と同じため、省略)

  ’——————————————————————————–
  ’ コマンドプロンプト上でコマンドの実行
  ’——————————————————————————–
  wsh.Run “cmd.exe /c " & all_cmd & " > " & svnOutputPath, vbHide, True

  ’ 空いているファイル番号を取得
  fileNumber = FreeFile

  ’ 入力ファイルをInputモードで開く
  Open svnOutputPath For Input As #fileNumber

  ’ 「svnコマンド結果出力」シートに結果を書き込む
  colcnt = 1
  Do While Not EOF(fileNumber)
    ’ ファイルから1行読み込む
    Line Input #fileNumber, textLine
    ’ 「svnコマンド結果出力」シートに1行書き込む
    svn_output_sheet.Cells(colcnt, 1).Value = textLine
    colcnt = colcnt + 1
  Next

  ’ 入力ファイルを閉じる
  Close #fileNumber

  ’ 初期化
  Set wsh = Nothing
  all_cmd = “"
  ’ コマンドの結果を記載したテキストファイルの消去
  Kill svnOutputPath

End Sub

【パターン①とパターン②の違い】
パターン①とパターン②との最大の違いは、パターン①はexec関数で結果が返却されるまで待っており、出力結果もexec関数の戻り値から取得しているのに対して、パターン②はRun関数で実行、戻り値ではなく「>」(リダイレクト)してファイルにsvnコマンドの実行結果を出力し、Run実行後でもマクロはコマンド実行で待機せずに処理を継続している点が大きく異なります。パターン②では、Run関数実行時の第2引数で「vbHide」を指定していますが、これを指定することにより、コマンドプロンプトを非表示とすることが出来ます。

またその直後の第3パラメータで、「True」を指定していますが、ここで「True」設定をしておくことで、起動したコマンドの終了を待つ(同期)ことが出来ます。「False」を指定するか、未設定の場合は、コマンド実行の終了を待たない(非同期となる)ということなります。今回の場合は、コマンドの実行結果をすぐに使用したいので、「True」指定にしています。

最後に「Kill」関数で一時ファイルを削除することは忘れずに・・・。

上記のことから、実運用としてはパターン②でのやり方をお勧めします。(Excelのバージョンがあがり、exec関数の仕様が変わるのが、ベストですが、Excelマクロからコマンドプロンプトを起動し、コマンドを実行するというニーズは少ないと思いますので、望みは薄いかと思います。

初ブログにしては、かなり長くなってしまいましたが、最後までお付き合いいただき、ありがとうございました。同じ悩みを抱えている方の少しでも助けになれば、幸いです。