How to get latest revision number from SharpSVN? - c#

How to get latest revision number using SharpSVN?

The least expensive way to retrieve the head revision from a repository
is the Info command.
using(SvnClient client = new SvnClient())
{
SvnInfoEventArgs info;
Uri repos = new Uri("http://my.server/svn/repos");
client.GetInfo(repos, out info);
Console.WriteLine(string.Format("The last revision of {0} is {1}", repos, info.Revision));
}

I am checking the latest version of the working copy using SvnWorkingCopyClient:
var workingCopyClient = new SvnWorkingCopyClient();
SvnWorkingCopyVersion version;
workingCopyClient.GetVersion(workingFolder, out version);
The latest version of the local working repository is then available through
long localRev = version.End;
For a remote repository, use
var client = new SvnClient();
SvnInfoEventArgs info;
client.GetInfo(targetUri, out info);
long remoteRev = info.Revision;
instead.
This is similar to using the svnversion tool from the command line. Hope this helps.

Ok, I figured it by myself:
SvnInfoEventArgs statuses;
client.GetInfo("svn://repo.address", out statuses);
int LastRevision = statuses.LastChangeRevision;

i googled also a lot but the only one thing which was working for me to get really the last revision was:
public static long GetRevision(String target)
{
SvnClient client = new SvnClient();
//SvnInfoEventArgs info;
//client.GetInfo(SvnTarget.FromString(target), out info); //Specify the repository root as Uri
//return info.Revision
//return info.LastChangeRevision
Collection<SvnLogEventArgs> info = new Collection<SvnLogEventArgs>();
client.GetLog(target, out info);
return info[0].Revision;
}
the other solutions are commented out. Try by yourself and see the difference . . .

Well, a quick google search gave me that, and it works (just point at the /trunk/ URI):
http://sharpsvn.open.collab.net/ds/viewMessage.do?dsForumId=728&dsMessageId=89318

This is a very old question, and it has been answered well in the top two answers. Still, in the hopes it might be of some help to someone I'm posting the following C# method to illustrate how to not only get the revision numbers from both the repository and the working copy, but also how to test for typical situations that might be considered as problems, for example in an automated build process.
/// <summary>
/// Method to get the Subversion revision number for the top folder of the build collection,
/// assuming these files were checked-out from Merlinia's Subversion repository. This also
/// checks that the working copy is up-to-date. (This does require that a connection to the
/// Subversion repository is possible, and that it is running.)
///
/// One minor problem is that SharpSvn is available in 32-bit or 64-bit DLLs, so the program
/// needs to target one or the other platform, not "Any CPU".
///
/// On error an exception is thrown; caller must be prepared to catch it.
/// </summary>
/// <returns>Subversion repository revision number</returns>
private int GetSvnRevisionNumber()
{
try
{
// Get the latest revision number from the Subversion repository
SvnInfoEventArgs svnInfoEventArgs;
using (SvnClient svnClient = new SvnClient())
{
svnClient.GetInfo(new Uri("svn://99.99.99.99/Merlinia/Trunk"), out svnInfoEventArgs);
}
// Get the current revision numbers from the working copy that is the "build collection"
SvnWorkingCopyVersion svnWorkingCopyVersion;
using (SvnWorkingCopyClient svnWorkingCopyClient = new SvnWorkingCopyClient())
{
svnWorkingCopyClient.GetVersion(_collectionFolder, out svnWorkingCopyVersion);
}
// Check the build collection has not been modified since last commit or update
if (svnWorkingCopyVersion.Modified)
{
throw new MerliniaException(0x3af34e1u,
"Build collection has been modified since last repository commit or update.");
}
// Check the build collection is up-to-date relative to the repository
if (svnInfoEventArgs.Revision != svnWorkingCopyVersion.Start)
{
throw new MerliniaException(0x3af502eu,
"Build collection not up-to-date, its revisions = {0}-{1}, repository = {2}.",
svnWorkingCopyVersion.Start, svnWorkingCopyVersion.End, svnInfoEventArgs.Revision);
}
return (int)svnInfoEventArgs.Revision;
}
catch (Exception e)
{
_fLog.Error(0x3af242au, e);
throw;
}
}
(This code does include a couple of things specific for the program it was copied from, but that shouldn't make the SharpSvn parts difficult to understand.)

Related

Querying TFS 2015 Source Code Repository DateTime Properties with .Net Framework v4.8 and Visual Studio 2019

I am trying to filter for source control files that were either created or modified within a specific time period on particular Team Foundation Server 2015 branches. I am thus far able to access file properties (e.g. url) with the Microsoft.VisualStudio.Services.WebAPI and Microsoft.TeamFoundation.SourceControl.WebApi libraries with a C# .Net Framework 4.8 Console Application using the GitHttpClient class.
The GetItemsAsync() method of this class returns a list of "GitItems" that contain a "path" property that can be passed as an argument into the System.IO class FileInfo to instantiate an object with the properties I need: CreationTime and LastWriteTime. However, the GitItem objects do not include the full file (blob) path that FileInfo (as well as the class File) needs to generate these properties accurately. The path property only includes the file name (e.g. '/.gitignore'). Therefore, in the code below, the variable lastWriteTime and the CreationTime property both return '12/31/1600 7:00:00 PM,' since the path isn't recognized.
static void Main(string[] args)
{
VssCredentials creds = new VssClientCredentials();
creds.Storage = new VssClientCredentialStorage();
VssConnection connection = new VssConnection(new Uri(teamCollection), creds);
// Get a GitHttpClient to talk to the Git endpoints
GitHttpClient gitClient = connection.GetClient<GitHttpClient>();
// Get data about a specific repository
var repositories = gitClient.GetRepositoriesAsync(teamProject).Result;
GitVersionDescriptor descriptor = new GitVersionDescriptor()
{
VersionType = GitVersionType.Branch,
Version = "develop",
VersionOptions = GitVersionOptions.None
};
foreach (var repository in repositories)
{
var branches = gitClient.GetBranchesAsync(repository.Id).Result;
var items = gitClient.GetItemsAsync(repository.Id, recursionLevel: VersionControlRecursionType.Full, versionDescriptor: descriptor, includeContentMetadata: true).Result;
foreach (var item in items)
{
var fullPath = Path.GetFullPath(item.Path);
FileInfo file = new FileInfo(fullPath);
DateTime lastWriteTime = file.LastWriteTime;
}
Console.WriteLine(repository.Name);
}
}
}
}
According to your code, you are using GitHttpClient.GetItemsAsync method.
public Task<GitItemsCollection> GetItemsAsync(
Guid repositoryId,
string path,
GitVersionDescriptor version,
VersionControlRecursionType recursionLevel,
bool includeContentMetadata,
bool includeLatestChange,
Object userState
)
This will return a server side git path. File info class with LastWriteTime properties
Gets or sets the time when the current file or directory was last written to. This should be a local system path.
That's why the path isn't recognized. Which may return a date kind of '12/31/1600 7:00:00 PM,'
Your question is similar to this VSTS API - repository creation date
Don't think it is possible to get the exact date of the moment the
operation create repo was completed. However, logically the birthday
of the repository is usually considered its first commit date.
If that's what you're looking for, you can achieve your goal with a
usual Git command:
git log -1 --reverse --format="format:%ci"
Besides, you could also get a git commit with detail info through Rest API. Also take a look at this blog, which maybe helpful.

Tfs Check-in using PendAdd: The array must contain at least one element

So I'm having a problem with automating my code to check-in files to TFS, and it's been driving me up the wall! Here is my code:
string location = AppDomain.CurrentDomain.BaseDirectory;
TfsTeamProjectCollection baseUserTpcConnection = new TfsTeamProjectCollection(uriToTeamProjectCollection);
IIdentityManagementService ims = baseUserTpcConnection.GetService<IIdentityManagementService>();
TeamFoundationIdentity identity = ims.ReadIdentity(IdentitySearchFactor.AccountName, #"PROD1\JR", MembershipQuery.None, ReadIdentityOptions.None);
TfsTeamProjectCollection impersonatedTpcConnection = new TfsTeamProjectCollection(uriToTeamProjectCollection, identity.Descriptor);
VersionControlServer sourceControl = impersonatedTpcConnection.GetService<VersionControlServer>();
Workspace workspace = sourceControl.CreateWorkspace("MyTempWorkspace", sourceControl.AuthorizedUser);
String topDir = null;
try
{
Directory.CreateDirectory(location + "TFS");
String localDir = location + "TFS";
workspace.Map("$/Automation/", localDir);
workspace.Get();
destinationFile = Path.Combine(localDir, Name + ".xml");
string SeconddestinationFile = Path.Combine(localDir, Name + ".ial");
bool check = sourceControl.ServerItemExists(destinationFile, ItemType.Any);
PendingChange[] pendingChanges;
File.Move(sourceFile, destinationFile);
File.Copy(destinationFile, sourceFile, true);
File.Move(SecondsourceFile, SeconddestinationFile);
File.Copy(SeconddestinationFile, SecondsourceFile, true);
if (check == false)
{
workspace.PendAdd(localDir,true);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
else
{
workspace.PendEdit(destinationFile);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
and the problem is that whenever it's NEW files (PendEdit works correctly when the files already exist in TFS) that my code is attempting to check in, and it runs through this code:
if (check == false)
{
workspace.PendAdd(localDir,true);
pendingChanges = workspace.GetPendingChanges();
workspace.CheckIn(pendingChanges, Comments);
}
The files, instead of being in the included changes in pending changes, are instead in the excluded changes like so:
and when the line that actually does the check-in runs, I'll get a "The array must contain at least one element" error, and the only way to fix it is to manually add those detected changes, and promote them to included changes, and I simply can't for the life of me figure out how to do that programatically though C#. If anyone has any guidance on what direction I should take for this, I would really appreciate it! Thank you!
Edit: I've also discovered another way to solve this by reconciling the folder, which also promotes the detected changes, but again the problem is I can't seem to figure out how to program that to do it automatically.
I know that running the visual studio developer command prompt, redirecting to the folder that this mapping is in, and the running "tf reconcile /promote" is one way, but I can only automate that as far as the /promote part, because that brings up a toolbox that a user would have to input into, which defeats the purpose of the automation. I'm at a loss.
Next Edit in response to TToni:
Next Edit in response to TToni:
I'm not entirely sure if I did this CreateWorkspaceParameters correctly (see picture 1), but this time it gave the same error, but the files were not even in the excluded portions. They just didn't show up anywhere in the pending changes (see picture 2).
Check this blog:
The workspace has a method GetPendingChangesWithCandidates, which actually gets all the “Excluded” changes. Code snippet is as below:
private void PendChangesAndCheckIn(string pathToWorkspace)
{
//Get Version Control Server object
VersionControlServer vs = collection.GetService(typeof
(VersionControlServer)) as VersionControlServer;
Workspace ws = vs.TryGetWorkspace(pathToWorkspace);
//Do Delete and Copy Actions to local path
//Create a item spec from the server Path
PendingChange[] candidateChanges = null;
string serverPath = ws.GetServerItemForLocalItem(pathToWorkspace);
List<ItemSpec> its = new List<ItemSpec>();
its.Add(new ItemSpec(serverPath, RecursionType.Full));
//get all candidate changes and promote them to included changes
ws.GetPendingChangesWithCandidates(its.ToArray(), true,
out candidateChanges);
foreach (var change in candidateChanges)
{
if (change.IsAdd)
{
ws.PendAdd(change.LocalItem);
}
else if (change.IsDelete)
{
ws.PendDelete(change.LocalItem);
}
}
//Check In all pending changes
ws.CheckIn(ws.GetPendingChanges(), "This is a comment");
}

SharpShell server .dll NOT signed

I need to develop a Shell Context Menu extension that references some other custom assemblies... I don't want to assign a Strong Name Key to those custom assemblies!
The guide I followed to do this uses the SharpShell project and illustrates how to sign (but does not expalins why) the assembly... and this is my problem: if I sign my final .dll then I have many errors during my project's building phase, because some assemblies my project references are not strongly named ("Referenced assembly does not have a strong name").
In general, googling about the C# Shell Extension implementation, all best tutorials I found sign the final assembly... is it mandatory?
Without signing the assembly ServerManager.exe returns this error: "The file 'XYZ.dll' is not a SharpShell Server".
Finally I've solved my troubles... the SharpShell.dll file obtained through NuGet was a different version of the ServerManager.exe ones.
Uninstalling the SharpShell NuGet package and directly referencing the SharpShell.dll you find inside the ServerManager folder was my solution!
Moreover, I was looking between the article comments... please read this question.
You don't need to use old DLL.
Please use this code directly, without using ServerManager.exe.
private static ServerEntry serverEntry = null;
public static ServerEntry SelectedServerEntry
{
get
{
if (serverEntry == null)
serverEntry = ServerManagerApi.LoadServer("xxx.dll");
return serverEntry;
}
}
public static ServerEntry LoadServer(string path)
{
try
{
// Create a server entry for the server.
var serverEntry = new ServerEntry();
// Set the data.
serverEntry.ServerName = Path.GetFileNameWithoutExtension(path);
serverEntry.ServerPath = path;
// Create an assembly catalog for the assembly and a container from it.
var catalog = new AssemblyCatalog(Path.GetFullPath(path));
var container = new CompositionContainer(catalog);
// Get the exported server.
var server = container.GetExport<ISharpShellServer>().Value;
serverEntry.ServerType = server.ServerType;
serverEntry.ClassId = server.GetType().GUID;
serverEntry.Server = server;
return serverEntry;
}
catch (Exception)
{
// It's almost certainly not a COM server.
MessageBox.Show("The file '" + Path.GetFileName(path) + "' is not a SharpShell Server.", "Warning");
return null;
}
}
Install code:
ServerRegistrationManager.InstallServer(SelectedServerEntry.Server, RegistrationType.OS64Bit, true);
Register code:
ServerRegistrationManager.RegisterServer(SelectedServerEntry.Server, RegistrationType.OS64Bit);

Retrieve Filename of a font

I would like to get the filename of a font. This can't be that hard... I am aware, there is a very similar question already, but the answer to that question just can't be it.
What I want to do is to send a Font file over TCP/IP to an other client, if he requests it. I select the desired font over a FontDialog, I can get the FontName from the framework. I can't find the font file in a way that I can say will work most of the time.
Where does .NET know which fonts are installed on the system? It can't be that the framework relies on a solution which does not work all the time, like the solution on CodeProject and suggested in Stackoverflow. There must be a secure way to retrieve the font file. The FontDialog can list them all in a box and the fonts installed must have a path to their file.
Anyone interested in helping me?
using System;
using System.Drawing;
using System.Text.RegularExpressions;
using Microsoft.Win32
public static string GetSystemFontFileName(Font font)
{
RegistryKey fonts = null;
try{
fonts = Registry.LocalMachine.OpenSubKey(#"Software\Microsoft\Windows NT\CurrentVersion\Fonts", false);
if(fonts == null)
{
fonts = Registry.LocalMachine.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Fonts", false);
if(fonts == null)
{
throw new Exception("Can't find font registry database.");
}
}
string suffix = "";
if(font.Bold)
suffix += "(?: Bold)?";
if(font.Italic)
suffix += "(?: Italic)?";
var regex = new Regex(#"^(?:.+ & )?"+Regex.Escape(font.Name)+#"(?: & .+)?(?<suffix>"+suffix+#") \(TrueType\)$");
string[] names = fonts.GetValueNames();
string name = names.Select(n => regex.Match(n)).Where(m => m.Success).OrderByDescending(m => m.Groups["suffix"].Length).Select(m => m.Value).FirstOrDefault();
if(name != null)
{
return fonts.GetValue(name).ToString();
}else{
return null;
}
}finally{
if(fonts != null)
{
fonts.Dispose();
}
}
}
For one, your problem describes issues with Windows OS. Hence your solution needs to be a Windows specific solution. In your comment you mentioned that the solution may not work on other OS.
It surely WILL NOT work.
Each OS will needs to be handled separately. Also, you can't assume that installation of fonts will happen in the same way on client's OS.
As for the problem with getting font file names. There is nothing wrong with the solutions provided on CP. In many instances the only way to get something in windows is to make API calls. .Net simply has no support for a number of things we may need to do. So relying on API is doesn't make it automatically wrong or undesirable.
EDIT:
In .NET 4.0 Fonts is a special folder that can be accessed like so
var fontsFolderPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
Dictionary<string, List<string>> _fontNameToFiles;
/// <summary>
/// This is a brute force way of finding the files that represent a particular
/// font family.
/// The first call may be quite slow.
/// Only finds font files that are installed in the standard directory.
/// Will not discover font files installed after the first call.
/// </summary>
/// <returns>enumeration of file paths (possibly none) that contain data
/// for the specified font name</returns>
private IEnumerable<string> GetFilesForFont(string fontName)
{
if (_fontNameToFiles == null)
{
_fontNameToFiles = new Dictionary<string, List<string>>();
foreach (var fontFile in Directory.GetFiles(Environment.GetFolderPath(Environment.SpecialFolder.Fonts)))
{
var fc = new PrivateFontCollection();
try
{
fc.AddFontFile(fontFile);
}
catch (FileNotFoundException)
{
continue; // not sure how this can happen but I've seen it.
}
var name = fc.Families[0].Name;
// If you care about bold, italic, etc, you can filter here.
List<string> files;
if (!_fontNameToFiles.TryGetValue(name, out files))
{
files = new List<string>();
_fontNameToFiles[name] = files;
}
files.Add(fontFile);
}
}
List<string> result;
if (!_fontNameToFiles.TryGetValue(fontName, out result))
return new string[0];
return result;
}

How to retrieve and set mapping of project on TFS

How can I get mapping of current project on TFS 2010? I need to take single file, find out its mapping and with that information I want to find this file on another computer, which has mapped same workspace. Any idea how can I achieve this?
Your question is a little bit unclear.
Whats your main goal?
If you install Team Foundation Sidekicks you can have a view called "Workspace Sidekick".
There you can filter by computername, Owner (User) and access date (first/last).
With TFS Sidekicks its a little bit easier to find mapped workspaces.
So I've found solution by myself.
First I get server name for every file
try
{
WorkspaceInfo wsi = Workstation.Current.GetLocalWorkspaceInfo(localFileName);
TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wsi.ServerUri);
Workspace wr = wsi.GetWorkspace(tfs);
string ret = wr.TryGetServerItemForLocalItem(localFileName);
return ret;
}
catch
{
return null;
}
and than, on another computer, I can load local names
try
{
Uri serverUri = new Uri(uri);
TfsTeamProjectCollection tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(serverUri);
VersionControlServer vcs = (VersionControlServer)tfs.GetService(typeof(VersionControlServer));
Workstation.Current.EnsureUpdateWorkspaceInfoCache(vcs, Environment.UserName);
Workspace wr = vcs.GetWorkspace(Environment.MachineName, Environment.UserName);
string ret=wr.TryGetLocalItemForServerItem(serverFileName);
return ret;
}
catch
{
return null;
}
It has some limitations, but works perfect for me.

Categories