Clearing special permissions from folders in a branch - version-control

We're a fairly large project with a single trunk branch. Most of it uses the default permissions, but a few folders have custom permissions - say, only "Builders" group is allowed to check-in.
We want to allow people to create their own private branches out of trunk, where they can freely check-in and merge later (hopefully often). However, creating a branch, the special permissions are copied along with the folders, meaning that people can't freely check-in into their branch.
Is there a way to clear special permissions from a branch, or a folder?
Is there a way to do so automatically, so anyone creating a branch under /private/** will not encounter this problem?

I found out about tf permission (Example: tf permission /inherit:yes itemSpec). However, the /recursive switch doesn't work with it. I guess I could write something that runs it recursively...
Edit: I finally got around to writing a tool for it:
static int Main(string[] args)
{
if (args.Length == 0 || args.Any(a => !a.StartsWith("$/")))
{
Console.WriteLine("Removes all explicit permissions and enables inheritance for a subtree.\n"
+ "Example: " + Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location) + " $/project/path1 $/project/path2");
return 3;
}
WorkspaceInfo wi = Workstation.Current.GetLocalWorkspaceInfo(Environment.CurrentDirectory);
if (wi == null)
{
Console.WriteLine("Can't determine workspace for current directory: " + Environment.CurrentDirectory);
return 2;
}
var Tfs = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(wi.ServerUri);
VersionControlServer VersionControlServer = Tfs.GetService<VersionControlServer>();
Console.WriteLine("Server: {0} Getting permissions...", wi.ServerUri);
ItemSecurity[] perms = VersionControlServer.GetPermissions(args, RecursionType.Full);
Console.WriteLine("Will remove explicit permissions from the following items:");
var changes = new List<SecurityChange>();
foreach (ItemSecurity perm in perms)
{
Console.WriteLine(" " + perm.ServerItem);
changes.Add(new InheritanceChange(perm.ServerItem, inherit: true));
foreach (AccessEntry e in perm.Entries)
{
changes.Add(new PermissionChange(perm.ServerItem, e.IdentityName, null, null, PermissionChange.AllItemPermissions));
}
}
Console.WriteLine("Enter to confirm:");
Console.ReadLine();
var successfulchanges = VersionControlServer.SetPermissions(changes.ToArray());
if (successfulchanges.Length == changes.Count)
{
Console.WriteLine("Explicit permissions removed from all items");
return 0;
}
else
{
Console.WriteLine("Explicit permissions removed only from:");
foreach (var c in successfulchanges)
{
Console.WriteLine(" " + c.Item);
}
return 1;
}
}

Related

amend all comments of all commits of a repository

I'm moving our on premise tfs repositories to visualstudio online. In the process I'd prefer to convert everything to git.
I found this (*) post online and everything works. But now I would like to use libgit2sharp to amend all the comments so to point to the correct work items.
I've cobbled together a bit of code that should do the trick:
Dictionary<string,string> links; //contains all links between new and old workitems, keys: old workitems, values: new workitems
using (var repo = new Repository(#"D:\gittfs\testproject"))
{
foreach (var commit in repo.Commits)
{
var commitMessage = commit.Message;
var regex = new Regex(#"#[0-9]*");
foreach (Match match in regex.Matches(commitMessage))
{
string newId;
if (links.TryGetValue(match.ToString(), out newId))
{
commitMessage = commitMessage.Replace(match.ToString(), newId);
}
}
var c = repo.Commit(commitMessage, new CommitOptions { AmendPreviousCommit = true });
}
}
This code runs without a problem and if I compare c.Message with commit.Message, I can see several of these being replaced. The problem is that after the program has ran, none of the amended commits are in the repository. So I think I'm still doing something wrong?
(*)https://www.microsoft.com/en-gb/developers/articles/week02mar2014/migrating-a-tfs-tfvc-based-team-project-to-a-git-team-project-retaining-as-much-source-and-work-item-history-as-possible/
I think you might rather be after some git filter-branch like feature.
LibGit2Sharp exposes this through the HistoryRewriter type.
You can peek at the FilterBranchFixture test suite for inspiration.
following code did the trick for me. thnx nulltoken!
var rewriteHistoryOptions = new RewriteHistoryOptions()
{
CommitHeaderRewriter = commit =>
{
var commitMessage = commit.Message;
bool stuffreplaced = false;
var r = new Regex(#"#[0-9]*\ ");
foreach (Match match in r.Matches(commit.Message))
{
string value;
if (links.TryGetValue(match.ToString().TrimEnd(), out value))
{
commitMessage = commitMessage.Replace(match.ToString().Trim(), value);
Console.WriteLine(commit.Id + ": " + match.ToString() + " replaced by " + value);
stuffreplaced = true;
counter++;
}
}
if (stuffreplaced)
{
return CommitRewriteInfo.From(commit, message: commitMessage);
}
else
{
return CommitRewriteInfo.From(commit);
}
}
};
repo.Refs.RewriteHistory(rewriteHistoryOptions, repo.Commits);

finding "active" branch in EGIT repository

I have to modify a faulty program/feature, which is an extension to org.eclipse.jgit
the program overrides the close method of the PushResultDialog and passes the Repository to an method.
Here i want to find the branch which was actually pushed/checked out. I am only interested if its the master, if not i don't wanna do anything.
else i need the list of the pushed files.
First the program looked like this :
head = repo.resolve(Constants.HEAD);
RevCommit commit = rw.parseCommit(head);
PersonIdent committerIdent = commit.getCommitterIdent();
sCommitter = committerIdent.getName();
String sBranch = "?";
for (Map.Entry<String, Ref> e : repo.getAllRefs().entrySet()) {
if (e.getKey().startsWith(Constants.R_HEADS)) {
Ref ref = e.getValue();
if (rw.isMergedInto(commit, rw.parseCommit(ref.getObjectId()))) {
sTemp = ref.getName();
int i = sTemp.lastIndexOf('/');
if (i == -1)
continue;
sBranch = sTemp.substring(i + 1);
System.out.println("Ref " + sBranch
+ " < contains > " + commit);
if (sBranch.equalsIgnoreCase("master")) {
break;
} else {
return;
}
}
}
}
RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
DiffFormatter df = new DiffFormatter(
DisabledOutputStream.INSTANCE);
df.setRepository(repo);
df.setDiffComparator(RawTextComparator.DEFAULT);
df.setDetectRenames(true);
List<DiffEntry> diffs = df.scan(parent.getTree(),
commit.getTree());
for (DiffEntry diff : diffs) {
sTemp = diff.getNewPath();
pushedObjects.add(sTemp);
}
now .. this works as long as the workflow in eclipse is just "checkout master" "pull" "merge branch" "push"
any other order seems to mess with the order of the branches in the set, and it stumbles over this "else" :
if (sBranch.equalsIgnoreCase("master")) {
break;
} else {
return;
}
the question is : is there an eaasy method to pick the right branch?
Ok, i think i can simply look at the HEAD in the set:
e.getKey().startsWith(Constants.HEAD)
and then parse the branchname, that should always be the branch which is checked out, if (in my case),if it is the master, i am happy.

Programmatically move files after virus scan

Is it possible to move files programmatically based on virus scan status?
What I want to do is have a set of folders:
Incoming
Scanned
Scanned/Clean
Scanned/Infected
Not Scanned
Files would be dropped into the Incoming folder. At that point, I would like to kick off the antivirus and scan the files in the Incoming folder. Once complete, the files would then need to be moved to the appropriate folder, either Clean or Infected. If, for whatever reason, the file could not be scanned or had trouble scanning, it would be moved to the Not Scanned folder.
I was hoping there would be a way to script this out. Has anyone ever done anything like this before?
public void Scan()
{
string[] uploadPath = Directory.GetFiles(ConfigurationManager.AppSettings["UploadPath"]);
foreach(string filePath in uploadPath)
{
string fileName = Path.GetFileName(filePath);
string cleanPath = Path.Combine(ConfigurationManager.AppSettings["CleanPath"], fileName);
try
{
Process AV = new Process();
AV.StartInfo.UseShellExecute = false;
AV.StartInfo.RedirectStandardOutput = true;
AV.StartInfo.FileName = ConfigurationManager.AppSettings["VSApp"];
AV.StartInfo.Arguments = " -Scan -ScanType 3 -file " + ConfigurationManager.AppSettings["UploadPath"] + " -DisableRemediation";
AV.Start();
string output = AV.StandardOutput.ReadToEnd();
AV.WaitForExit();
if (AV.ExitCode == 0)
{
File.Move(filePath, cleanPath);
}
else if (AV.ExitCode == 2)
{
using (TextWriter tw = new StreamWriter(ConfigurationManager.AppSettings["FailedPath"] + fileName + ".txt"))
{
tw.WriteLine("2");
tw.Close();
}
using (TextWriter tw1 = new StreamWriter(ConfigurationManager.AppSettings["FailedFiles"] + fileName + ".txt"))
{
tw1.WriteLine(AV.StandardOutput);
tw1.Close();
}
File.Delete(filePath);
}
AV.Close();
}
catch (Exception ex)
{
if (ex.ToString().Contains("Could not find file"))
{
string failedFile = ConfigurationManager.AppSettings["FailedPath"] + fileName + ".txt";
string failedFileDesc = ConfigurationManager.AppSettings["FailedPath"] + fileName + "_ErrorDesc" + ".txt";
using (TextWriter tw = new StreamWriter(failedFile))
{
tw.WriteLine("2");
tw.Close();
}
using (TextWriter tw1 = new StreamWriter(failedFileDesc))
{
tw1.WriteLine(ex.ToString());
tw1.Close();
}
}
else
{
Thread.Sleep(2000);
if (runCounter == 0)
{
Scan();
}
runCounter++;
string errorFile = ConfigurationManager.AppSettings["ProcessErrorPath"] + fileName + ".txt";
using (TextWriter tw = new StreamWriter(errorFile))
{
tw.WriteLine(ex.ToString());
tw.Close();
}
}
}
}
}
I created this as a Windows Service. My OnStart method creates my FileSystemWatcher to watch the Upload Path. For On Created, I have a method that runs my Scan method and creates my counter and sets it to 0. My On Error event just logs. I had an issue where the FileSystemWatcher was trying to open the file before it had been uploaded, hence why I added the sleep.
Finally, I am using Microsoft Forefront's command line scanner. File path: C:\Program Files\Microsoft Security Client\mpcmdrun.exe.
Let me know if any questions.

Mercurial - log the command executed

We've been using mercurial for a while now and everything is working fine.
The only problem we encounter is when someone runs a "bad command".
An example would be, merging an unstable branch in the stable trunk or pulling a similarly named branch over something completely unrelated overwriting a bunch of stuff...
You've got hg log but you always get people that won't believe the output saying "I didn't do that"...now in the interest of public shaming :) and giving rightful priviledges to the "You broke the built hat", I'm wondering, is there a way to have Mercurial log every command its given to a text file that would give us something like:
hg pull -b something
hg merge TotallyWrongBranch
hg ci -m "I didn't do it!" -u bsimpson
Ok, I had a few minutes on my hand so I wrote an exe and named it hg.exe and renamed Mercurial's original exe to real_hg...
An ugly hack don't mind the code quality please IT WORKS!
public static StreamWriter sw;
static void Main(string[] args)
{
sw = new StreamWriter("hgCommandLog.txt", true);
StringBuilder sbArguments = new StringBuilder();
if (args.Length > 0)
{
for (int i = 0; i < args.Length; i++)
{
sbArguments.Append(args[i]);
sbArguments.Append(" ");
}
}
//Console.WriteLine("arg:" + sbArguments.ToString());
//Console.WriteLine("Session ID = " + System.Diagnostics.Process.GetCurrentProcess().SessionId.ToString());
//Console.WriteLine("hello ->"+Environment.GetEnvironmentVariable("CLIENTNAME"));
string sessionID = System.Diagnostics.Process.GetCurrentProcess().SessionId.ToString();
string clientName = Environment.GetEnvironmentVariable("CLIENTNAME");
//log the command to sw
sw.WriteLine(DateTime.Now.ToString() + "\t" + clientName + "("+sessionID+")\t" + "hg " + sbArguments.ToString());
sw.Flush();
// Start the child process.
Process p = new Process();
// Redirect the output stream of the child process.
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "real_hg";
p.StartInfo.Arguments = sbArguments.ToString();
p.StartInfo.CreateNoWindow = true;
p.ErrorDataReceived += outputReceived;
p.OutputDataReceived += outputReceived;
p.EnableRaisingEvents = true;
p.Start();
// Do not wait for the child process to exit before
// reading to the end of its redirected stream.
p.BeginOutputReadLine();
//p.BeginErrorReadLine();
p.WaitForExit();
sw.Close();
}
static void outputReceived(object sender, DataReceivedEventArgs e)
{
sw.WriteLine("\t"+e.Data);
Console.WriteLine(e.Data);
}

How to get a previous revision of a specific revision of a file in CVS

Is there any CVS command that can give me previous revision of a file, given the filename and its revision?
The way CVS controls the version of a file is that the revision is increased only when there is a commit in that file. The changes in the tree or tagging etc will not affect the revision of a single file.
Although there is no definite way of getting the previous revision of a file, given the name and it's revision... But there is a hit and trial method around it. Blindly go to the previous revision. For eg, the prev revision of Rev 1.5 would be Rev 1.4
Another way to sort this out is, to write a shell script. Use cvs log to get the change log of a particular filename and grep the desired revision number.
There is no direct way to do this from CVS commands. But since I am using the output (of CVS log) IN java, following code snippet worked for me
if (currentRevision == null || currentRevision.trim().length() == 0) {
return null;
}
String[] revComponents = currentRevision.trim().split("\\.");
if (revComponents == null || revComponents.length == 0) {
log.warn("Failed to parse revision number: " + currentRevision
+ " for identification of previous revision");
return null;
}
if (revComponents.length % 2 == 1) {
log.warn("Odd number of components in revision: " + currentRevision);
log.warn("Possibly a tag revision.");
return null;
}
int lastComp;
try {
lastComp = Integer.parseInt(revComponents[revComponents.length - 1]);
} catch (NumberFormatException nmfe) {
log.warn("Failed to parse the last component of revision from " + currentRevision);
log.warn("Identified presence of alphanumric values in the last component. Cannot predict previous revision for this");
return null;
}
if (revComponents.length == 2 && lastComp == 1) {
log.debug("Revision: " + currentRevision + " is the first revision for the current file. Cannot go further back");
return null;
}
StringBuilder result = new StringBuilder();
if (lastComp == 1) {
for (int i = 0; i < revComponents.length - 2; i++) {
if (result.length() > 0)
result.append('.');
result.append(revComponents[i]);
}
} else if (lastComp > 1) {
for (int i = 0; i < revComponents.length - 1; i++) {
result.append(revComponents[i]);
result.append('.');
}
result.append((lastComp - 1));
} else {
log.warn("Found invalid value for last revision number component in " + currentRevision);
return null;
}
return result.toString();
}
Above code also handles branch revisions, for example, if the current revision (in picture) is the first one on branch that it will return the revision from which branch for that file was created.
Hope this helps.