Sunday, October 6, 2024

Extract line count of file at each git revision

git rev-list --reverse HEAD -- words.csv | \
    xargs -I {} sh -c 'echo $(git show -s --date=short --format="%ad" {}) $(git show {}:./words.csv | wc -l)'

Wednesday, February 16, 2022

Traverse into zip files when walking the file system

func WalkDirZip(fsys fs.FS, root string, fn WalkDirFunc) error {
    return fs.WalkDir(fsys, root, func(path string, d fs.DirEntry, err error) error {
        if d.IsDir() || !strings.EqualFold(filepath.Ext(path), ".zip") {
            return fn(fsys, path, d, err)
        } else if f, err := fsys.Open(path); err != nil {
            return err
        } else if s, err := f.Stat(); err != nil {
            return err
        } else if zfs, err := zip.NewReader(f.(io.ReaderAt), s.Size()); err != nil {
            return err
        } else {
            return fs.WalkDir(zfs, ".", func(path string, d fs.DirEntry, err error) error {
                return fn(zfs, path, d, err)
            })
        }
    })
}

type WalkDirFunc func(fsys fs.FS, path string, d fs.DirEntry, err error) error

Friday, December 13, 2019

Recursively compact git repositories within a directory

find -name .git -exec echo {} \; -execdir git gc --aggressive ";"

Thursday, October 6, 2016

Generic extension method for traversing object graphs

  1. public static IEnumerable Traverse(this T root, Func> getChildren)
  2. {
  3. return Enumerable.Repeat(root, 1)
  4. .Concat((getChildren(root) ?? Enumerable.Empty())
  5. .SelectMany(child => Traverse(child, getChildren)));
  6. }

Tuesday, August 23, 2016

Extract attachments and inline files from a MIME message

  1. MimeMessage msg;
  2. using (var stream = File.OpenRead(fileName))
  3. {
  4. msg = MimeMessage.Load(stream);
  5. }
  6. foreach (var part in msg.BodyParts.OfType().Where(part => !string.IsNullOrEmpty(part.FileName)))
  7. {
  8. using (var stream = File.OpenWrite(Path.Combine(Path.GetDirectoryName(fileName), part.FileName)))
  9. {
  10. part.ContentObject.DecodeTo(stream);
  11. }
  12. }
MimeKit

Tuesday, April 8, 2014

Deserialize an anonymous type using SimpleJson

  1. var json = "{\"name\": \"Joe\"," +
  2. "\"age\": 25," +
  3. "\"address\": {\"city\": \"Paris\"}," +
  4. "\"emails\": [\"joe@home.com\", \"joe@work.com\"]," +
  5. "\"phones\": [{\"type\": \"Mobile\", \"number\": \"555 1234\"}]}";
  6. var prototype = new
  7. {
  8. name = default(string),
  9. age = default(int),
  10. address = new {city = default(string)},
  11. emails = new string[0],
  12. phones = new[] {new {type = default(string), number = default(string)}}
  13. };
  14. var result = SimpleJsonExt.DeserializeAnonymousObject(json, prototype);
  15.  
  16. using CacheEntry = KeyValuePair<ParameterInfo[], ReflectionUtils.ConstructorDelegate>;
  17. public static class SimpleJsonExt
  18. {
  19. public static T DeserializeAnonymousObject<T>(string json, T prototype)
  20. {
  21. return SimpleJson.SimpleJson.DeserializeObject<T>(json, new Strategy());
  22. }
  23. private class Strategy : PocoJsonSerializerStrategy
  24. {
  25. private readonly IDictionary<Type, CacheEntry> _ctorCache =
  26. new ReflectionUtils.ThreadSafeDictionary<Type, CacheEntry>(CreateConstructorDelegate);
  27. private static CacheEntry CreateConstructorDelegate(Type key)
  28. {
  29. var ctors = key.GetConstructors();
  30. if (ctors.Length == 1)
  31. {
  32. var ctor = ctors[0];
  33. var parms = ctor.GetParameters();
  34. if (parms.Length > 0)
  35. {
  36. return new CacheEntry(parms, ReflectionUtils.GetContructor(ctor));
  37. }
  38. }
  39. return default(CacheEntry);
  40. }
  41. public override object DeserializeObject(object value, Type type)
  42. {
  43. var dict = value as IDictionary<string, object>;
  44. if (dict != null)
  45. {
  46. var ctor = _ctorCache[type];
  47. if (ctor.Key != null)
  48. {
  49. return ctor.Value(ctor.Key
  50. .Select(param => DeserializeObject(
  51. dict.TryGetValue(param.Name, out value) ? value : null,
  52. param.ParameterType))
  53. .ToArray());
  54. }
  55. }
  56. return base.DeserializeObject(value, type);
  57. }
  58. }
  59. }
SimpleJson

Sunday, November 24, 2013

Recursively search and replace files from one folder into another

  1. $filter = '*.dll', '*.pdb'
  2. $copied = 0; $skipped = 0; $failed = 0
  3. $sourceFiles = $filter | % { Get-ChildItem $sourceDir -Filter $_ -Recurse } `
  4. | sort @{expression={$_.FullName.Length}} -Descending `
  5. | group Name -AsHashTable
  6. $targetFiles = $filter | % { Get-ChildItem $targetDir -Filter $_ -Recurse } `
  7. | ? { $sourceFiles.ContainsKey($_.Name) } `
  8. | sort FullName
  9. $targetFiles | % {
  10. $target = $_
  11. $sourceFiles[$target.Name] | % {
  12. $source = $_
  13. if ($target.FullName.EndsWith($source.FullName.Substring($sourceDir.Length),
  14. 'InvariantCultureIgnoreCase')) {
  15. if ($target.LastWriteTime.AddSeconds(2) -lt $source.LastWriteTime) {
  16. Write-Host $target.FullName
  17. try {
  18. Copy-Item $source.FullName $target.FullName -Force
  19. $copied++
  20. }
  21. catch {
  22. Write-Error $_.Message
  23. $failed++
  24. }
  25. }
  26. else {
  27. $skipped++
  28. }
  29. return
  30. }
  31. }
  32. }
  33. Write-Host "$copied copied, $skipped skipped, $failed failed in $($watch.Elapsed)"

Thursday, March 14, 2013

Programmatically configure a simple log4net trace appender

  1. var hierarchy = (Hierarchy) LogManager.GetRepository();
  2. var logger = (Logger) hierarchy.GetLogger(loggerName);
  3. logger.Level = Level.Debug;
  4. logger.AddAppender(new TraceAppender {Layout = new SimpleLayout()});
  5. hierarchy.Configured = true;
log4net

Monday, January 28, 2013

Convert an SQL like pattern into a regular expression pattern

  1. var pattern = Regex.Replace(
  2. likePattern,
  3. @"[%_]|\[[^]]*\]|[^%_[]+",
  4. match =>
  5. {
  6. if (match.Value == "%")
  7. {
  8. return ".*";
  9. }
  10. if (match.Value == "_")
  11. {
  12. return ".";
  13. }
  14. if (match.Value.StartsWith("[") && match.Value.EndsWith("]"))
  15. {
  16. return match.Value;
  17. }
  18. return Regex.Escape(match.Value);
  19. });

Saturday, January 12, 2013

Load test a web site using asynchronous requests and the TPL

  1. var queue = new Queue<Task>();
  2. while (true)
  3. {
  4. if (queue.Count >= 50)
  5. {
  6. var task = queue.Dequeue();
  7. task.Wait();
  8. task.Dispose();
  9. }
  10. var request = (HttpWebRequest) WebRequest.Create(url);
  11. var watch = Stopwatch.StartNew();
  12. queue.Enqueue(Task.Factory
  13. .FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null)
  14. .ContinueWith(task =>
  15. {
  16. using (var response = (HttpWebResponse) task.Result)
  17. {
  18. Console.WriteLine("{0}\t{1}\t{2}",
  19. response.StatusCode, response.ContentType, watch.Elapsed);
  20. }
  21. }));
  22. }
Task Parallel Library (TPL)

Thursday, June 28, 2012

Calculate the exponential moving average of a stream of numbers

  1. public static IEnumerable<double> ExponentialMovingAverage(this IEnumerable<double> source, double alpha)
  2. {
  3. double? last = null;
  4. return source.Select(
  5. value =>
  6. {
  7. var average = last != null ? alpha*value + (1 - alpha)*last.Value : value;
  8. last = average;
  9. return average;
  10. });
  11. }

Thursday, February 16, 2012

Create a fast compiled method invoker using LINQ

  1. var method = new Func<double, double, double>(Math.Pow).Method;
  2. var parameter = Expression.Parameter(typeof(object[]));
  3. var args = method.GetParameters()
  4. .Select((param, i) => Expression.Convert(
  5. Expression.ArrayIndex(parameter, Expression.Constant(i)), param.ParameterType));
  6. var expr = Expression.Lambda<Func<object[], object>>(
  7. Expression.Convert(Expression.Call(method, args), typeof(object)), parameter);
  8. var invoker = expr.Compile();
  9. var result = invoker(new object[] {Math.PI, 2.0});

Friday, February 10, 2012

Create a Google calendar event in an existing calendar

  1. var credentials = new GDataCredentials(userName, password);
  2. var service = new CalendarService(null) {Credentials = credentials};
  3. var query = new CalendarQuery("https://www.google.com/calendar/feeds/default/owncalendars/full");
  4. var feed = service.Query(query);
  5. var eventFeedLink = feed.Entries.Cast<CalendarEntry>()
  6. .Where(item => item.Title.Text == calendarName)
  7. .SelectMany(item => item.Links)
  8. .First(link => link.Rel == GDataParserNameTable.NSGCal + "#eventFeed");
  9. var entry = new EventEntry(title) {Times = {new When(start, end, allDay)}};
  10. service.Insert(new Uri(eventFeedLink.AbsoluteUri), entry);
Google Data API .NET client library

Thursday, February 2, 2012

Page through potentially large NHibernate criteria query results

  1. public static IEnumerable<T> Enumerate<T>(this ICriteria criteria, int pageSize = 1000)
  2. {
  3. var entityCount = CriteriaTransformer.TransformToRowCount(criteria).UniqueResult<int>();
  4. var pageCount = (int) Math.Ceiling(entityCount/(double) pageSize);
  5. criteria = CriteriaTransformer.Clone(criteria).SetMaxResults(pageSize);
  6. return Enumerable.Range(0, pageCount)
  7. .SelectMany(pageNum => criteria.SetFirstResult(pageNum*pageSize).List<T>());
  8. }
NHibernate

Friday, January 20, 2012

Create a YouTube playlist containing all the uploads of a given user

  1. var credentials = new GDataCredentials(userName, password);
  2. var service = new YouTubeService(applicationName, developerKey) {Credentials = credentials};
  3. var entry = new AtomEntry {Title = {Text = playlistName}};
  4. entry = service.Insert(new Uri(YouTubeQuery.CreatePlaylistsUri(null)), entry);
  5. var id = ((XmlExtension) entry.FindExtension("playlistId", YouTubeNameTable.NSYouTube)).Node.InnerText;
  6. var batchUri = new Uri(string.Format("https://gdata.youtube.com/feeds/api/playlists/{0}/batch", id));
  7. var query = new YouTubeQuery(YouTubeQuery.CreateUserUri(sourceUser)) {StartIndex = 1};
  8. AtomFeed feed;
  9. do
  10. {
  11. feed = service.Query(query);
  12. service.Batch(feed, batchUri);
  13. query.StartIndex += feed.Entries.Count;
  14. } while (query.StartIndex < feed.TotalResults);
Google Data API .NET client library

Sunday, January 8, 2012

List the users of a TFS project associated with a local workspace path

  1. var workspace = Workstation.Current.GetLocalWorkspaceInfo(path);
  2. var tfs = new TfsTeamProjectCollection(workspace.ServerUri);
  3. var gss = tfs.GetService<IGroupSecurityService>();
  4. var grp = gss.ReadIdentity(SearchFactor.EveryoneApplicationGroup, null, QueryMembership.Expanded);
  5. var names = gss.ReadIdentities(SearchFactor.Sid, grp.Members, QueryMembership.None)
  6. .Where(identity => identity.Type == IdentityType.WindowsUser)
  7. .Select(identity => string.Format(@"{0}\{1}", identity.Domain, identity.AccountName))
  8. .ToArray();

Friday, January 6, 2012

Quartz scheduler job that re-triggers itself on completion

  1. public class RetriggerJob : IInterruptableJob
  2. {
  3. private bool _interrupted;
  4. public void Execute(IJobExecutionContext context)
  5. {
  6. Thread.Sleep(1000);
  7. if (_interrupted)
  8. {
  9. return;
  10. }
  11. context.Scheduler.TriggerJob(context.JobDetail.Key);
  12. if (_interrupted)
  13. {
  14. context.Scheduler.Interrupt(context.JobDetail.Key);
  15. }
  16. }
  17. public void Interrupt()
  18. {
  19. _interrupted = true;
  20. }
  21. }
Quartz.NET

Friday, December 30, 2011

Read a published Google spreadsheet into a DataTable using GData

  1. var service = new SpreadsheetsService(null);
  2. var query = new ListQuery("0AjD5UGMt5CGDdEcwaS10S2IzVzJFNDYtaEo5anN2RHc", "1", "public", "values");
  3. var feed = service.Query(query);
  4. var table = new DataTable();
  5. foreach (ListEntry entry in feed.Entries)
  6. {
  7. var row = table.NewRow();
  8. foreach (ListEntry.Custom element in entry.Elements)
  9. {
  10. var column = table.Columns[element.LocalName] ??
  11. table.Columns.Add(element.LocalName);
  12. row[column] = element.Value;
  13. }
  14. table.Rows.Add(row);
  15. }
Google Data API .NET client library

Saturday, December 17, 2011

Determine if a WinForms control resource file is localized

  1. XPathDocument doc;
  2. using (var stream = File.OpenRead(fileName))
  3. {
  4. doc = new XPathDocument(stream);
  5. }
  6. var nav = doc.CreateNavigator();
  7. var itr = nav.Select("root/data[@name = '>>$this.Name']");
  8. var localized = itr.Count > 0;

Remove matching C# region directives using LINQ

  1. var flag = false;
  2. var modified = false;
  3. var lines = File.ReadLines(fileName)
  4. .Where(line =>
  5. {
  6. if ((!flag && line.Contains("#region " + regionName)) ||
  7. (flag && line.Contains("#endregion")))
  8. {
  9. flag = !flag;
  10. modified = true;
  11. return false;
  12. }
  13. return true;
  14. })
  15. .ToArray();
  16. if (modified)
  17. {
  18. File.WriteAllLines(fileName, lines);
  19. }

Thursday, December 8, 2011

Compile and execute a stateful T4 template using Mono.TextTemplating

  1. var input =
  2. "<#@ template language=\"C#\" debug=\"true\" #>" +
  3. "<#+ static int num; #>" +
  4. "<#= num++ #>";
  5. var generator = new TemplateGenerator();
  6. var compiled = generator.CompileTemplate(input);
  7. Debug.Assert(Equals(compiled.Process(), "0"));
  8. Debug.Assert(Equals(compiled.Process(), "1"));
  9. Debug.Assert(Equals(compiled.Process(), "2"));
Mono.TextTemplating