TeamFoundationServerからチェックイン日付でファイルを取得する

TeamFoundationServer(TFS)はローカルにダウンロードしたファイルの日付はすべて現在時刻となってしまいます。例えば、1年前に修正しチェックインしたファイルでもダウンロードするたびにファイルの日付が異なってしまう、Visual Source Safe(VSS) では、オプションでダウンロードしたファイルの日付をチェックイン日付にすることが出来ましたが、 TFSではそうしたオプションは無いようです。
(ファイルの更新日付はTFSが保持していないため、チェックイン日付となります。)

TFS SDK を使うとTFSのソース管理のメタ情報を取得する事ができるので、ファイルダウンロード後にファイルの日付を変更する方法をしらべてみました。手順としては以下のステップが必要です。

  1. TFSサーバへのログイン
  2. ソース管理(バージョンコントロール)サービスへの接続
  3. ダウンロード用の一時ワークスペースを作成
  4. 出力先フォルダのクリア
  5. ファイルのダウンロード
  6. ダウンロードしたファイルをチェックイン日付に変更
  7. ダウンロード用の一時ワークスペースを削除
  • TFSサーバへのログイン

まず、TFSサーバに接続します。接続に必要なものはURL,ユーザ名,パスワードの3つ。


// 認証
NetworkCredential nc = new NetworkCredential(this.UserName, this.Password);
TfsConfigurationServer configurationServer = new TfsConfigurationServer(new Uri(this.Uri), nc);
configurationServer.Authenticate();

if (configurationServer.HasAuthenticated)
{
// 認証後の処理
}

  • ソース管理(バージョンコントロール)サービスへの接続

TFSのチームプロジェクト情報を取得してバージョンコントロールサービスに接続。


// VSC接続
ITeamProjectCollectionService tpcService = configurationServer.GetService();
CatalogNode configurationServerNode = configurationServer.CatalogNode;

ReadOnlyCollection tpcNodes = configurationServerNode.QueryChildren(new Guid[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None);

foreach (CatalogNode tpcNode in tpcNodes)
{
Guid tpcId = new Guid(tpcNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection tpc = configurationServer.GetTeamProjectCollection(tpcId);
_vcs = tpc.GetService();
}

ソースをダウンロードするには、TFSのリポジトリ ($/Source/〜) と ローカルパス ( C:\Source )をマッピングしたワークスペースを作成する必要があります。一時ダウンロード用のものなので、"TemporaryDownloadWorkSpace"などの重複しない名前で作成します


try
{
// ワークスペース削除
_vcs.DeleteWorkspace(tempWorkSpaceName, _vcs.AuthorizedUser);
}
catch (Exception)
{
}

// ワークスペース作成
Workspace ws = _vcs.TryGetWorkspace(localPath);
if (ws == null)
{
ws = _vcs.CreateWorkspace(tempWorkSpaceName, _vcs.AuthorizedUser);
WorkingFolder folder = new WorkingFolder(repository, localPath);
ws.CreateMapping(folder);
}

  • 出力先フォルダのクリア

ダウンロード先のフォルダはあらかじめクリアしておきます


// 出力先フォルダ再作成
if (System.IO.Directory.Exists(localPath))
{
System.IO.Directory.Delete(localPath, true);
}

System.IO.Directory.CreateDirectory(localPath);

  • ファイルのダウンロード

ワークスペースからバージョンを指定してファイルをダウンロードします。過去の日時や、変更セットNoなどのバージョンを指定することもできます。今回は最新版を取得するので、VersionSpec.Latestを指定します。


ws.Get(VersionSpec.Latest, GetOptions.GetAll);

  • ダウンロードしたファイルをチェックイン日付に変更

バージョンコントロールサービスからリポジトリのアイテム情報を抜き出して対応するローカルファイルの日付を変更します。


// ファイルの日付変更
ItemSet vcsItemSet = _vcs.GetItems(repository, VersionSpec.Latest, RecursionType.Full);
foreach (Item vcsItem in vcsItemSet.Items)
{

String filePath = vcsItem.ServerItem.Replace(repository , localPath).Replace("/", "\\");

try
{

if (vcsItem.ItemType == ItemType.Folder)
{
if (System.IO.Directory.Exists(filePath))
{

DirectoryInfo dInfo = new System.IO.DirectoryInfo(filePath);

// ディレクトリの日付をチェックイン日付に変更
System.IO.Directory.SetCreationTime(filePath, vcsItem.CheckinDate);
System.IO.Directory.SetLastAccessTime(filePath, vcsItem.CheckinDate);
System.IO.Directory.SetLastWriteTime(filePath, vcsItem.CheckinDate);

}
}
else
{
if (System.IO.File.Exists(filePath))
{

FileInfo fInfo = new System.IO.FileInfo(filePath);
File.SetAttributes(filePath, FileAttributes.Normal);

// ファイルの日付をチェックイン日付に変更
System.IO.File.SetCreationTime(filePath, vcsItem.CheckinDate);
System.IO.File.SetLastAccessTime(filePath, vcsItem.CheckinDate);
System.IO.File.SetLastWriteTime(filePath, vcsItem.CheckinDate);

}

}

}
catch (Exception ex)
{
System.Diagnostics.Debug.Print(String.Format("{0} {1} {2}", ex.Message, vcsItem.ServerItem , filePath ));
}

}

最後に不要になった一時ワークスペースを削除します。


// ワークスペース削除
_vcs.DeleteWorkspace(tempWorkSpaceName, _vcs.AuthorizedUser);

TfsManager.cs
上記の処理をクラスにまとめてみました。


using System;
using System.IO;
using System.Net;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.VersionControl.Client;
using Microsoft.TeamFoundation.Framework.Client;
using Microsoft.TeamFoundation.Framework.Common;

namespace TfsBuilder
{
public class TfsManager
{

private const string TEMP_WORK_SPACE_NAME = "TemporaryDownloadWorkSpace";

private VersionControlServer _vcs = null;

///


/// コンストラク
///

public TfsManager()
{
}

public string Uri { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Repository { get; set; }

///


/// 接続
///

///
///
///
public bool Connect(string uri, string userName, string password)
{
bool result = false;
this.Uri = uri;
this.UserName = userName;
this.Password = password;

try
{
// 認証
NetworkCredential nc = new NetworkCredential(this.UserName, this.Password);
TfsConfigurationServer configurationServer = new TfsConfigurationServer(new Uri(this.Uri), nc);
configurationServer.Authenticate();

if (configurationServer.HasAuthenticated)
{
// VSC接続
ITeamProjectCollectionService tpcService = configurationServer.GetService();
CatalogNode configurationServerNode = configurationServer.CatalogNode;

ReadOnlyCollection tpcNodes = configurationServerNode.QueryChildren(new Guid[] { CatalogResourceTypes.ProjectCollection }, false, CatalogQueryOptions.None);

foreach (CatalogNode tpcNode in tpcNodes)
{
Guid tpcId = new Guid(tpcNode.Resource.Properties["InstanceId"]);
TfsTeamProjectCollection tpc = configurationServer.GetTeamProjectCollection(tpcId);
_vcs = tpc.GetService();
}
}
result = configurationServer.HasAuthenticated;
}
catch (Exception)
{
}

return result;
}


///


/// プロジェクトを取得します。
///

/// リポジトリ
/// ダウンロード先
public void Get(string repository, string localPath)
{

Get(repository, localPath, TEMP_WORK_SPACE_NAME, VersionSpec.Latest);

}

///


/// プロジェクトを取得します。
///

/// リポジトリ
/// ダウンロード先
/// 一時ワークスペース
public void Get(string repository, string localPath, string tempWorkSpaceName)
{

Get(repository, localPath, tempWorkSpaceName, VersionSpec.Latest);

}

///


/// プロジェクトを取得します。
///

/// リポジトリ
/// ダウンロード先
/// 取得するバージョン
public void Get(string repository, string localPath, VersionSpec version)
{

Get(repository, localPath, TEMP_WORK_SPACE_NAME, version);

}

///


/// プロジェクトを取得します。
///

/// リポジトリ
/// ダウンロード先
/// 一時ワークスペース
/// 取得するバージョン
public void Get(string repository, string localPath, string tempWorkSpaceName, VersionSpec version)
{
try
{
// ワークスペース削除
_vcs.DeleteWorkspace(tempWorkSpaceName, _vcs.AuthorizedUser);
}
catch (Exception)
{
}

// ワークスペース作成
Workspace ws = _vcs.TryGetWorkspace(localPath);
if (ws == null)
{
ws = _vcs.CreateWorkspace(tempWorkSpaceName, _vcs.AuthorizedUser);
WorkingFolder folder = new WorkingFolder(repository, localPath);
ws.CreateMapping(folder);
}

// 出力先フォルダ再作成
if (System.IO.Directory.Exists(localPath))
{
System.IO.Directory.Delete(localPath, true);
}

System.IO.Directory.CreateDirectory(localPath);

// ファイル取得
ws.Get(version, GetOptions.GetAll);

// ファイルの日付変更
ItemSet vcsItemSet = _vcs.GetItems(repository, version, RecursionType.Full);
foreach (Item vcsItem in vcsItemSet.Items)
{

String filePath = vcsItem.ServerItem.Replace(repository , localPath).Replace("/", "\\");

try
{

if (vcsItem.ItemType == ItemType.Folder)
{
if (System.IO.Directory.Exists(filePath))
{

DirectoryInfo dInfo = new System.IO.DirectoryInfo(filePath);

// ディレクトリの日付をチェックイン日付に変更
System.IO.Directory.SetCreationTime(filePath, vcsItem.CheckinDate);
System.IO.Directory.SetLastAccessTime(filePath, vcsItem.CheckinDate);
System.IO.Directory.SetLastWriteTime(filePath, vcsItem.CheckinDate);

}
}
else
{
if (System.IO.File.Exists(filePath))
{

FileInfo fInfo = new System.IO.FileInfo(filePath);
File.SetAttributes(filePath, FileAttributes.Normal);

// ファイルの日付をチェックイン日付に変更
System.IO.File.SetCreationTime(filePath, vcsItem.CheckinDate);
System.IO.File.SetLastAccessTime(filePath, vcsItem.CheckinDate);
System.IO.File.SetLastWriteTime(filePath, vcsItem.CheckinDate);

}

}

}
catch (Exception ex)
{
System.Diagnostics.Debug.Print(String.Format("{0} {1} {2}", ex.Message, vcsItem.ServerItem , filePath ));
}

}

// ワークスペース削除
_vcs.DeleteWorkspace(tempWorkSpaceName, _vcs.AuthorizedUser);

}

}
}