Skip to content

Commit

Permalink
Multiuser update dependencies support
Browse files Browse the repository at this point in the history
  • Loading branch information
Nice3point committed Aug 30, 2024
1 parent 993e1c6 commit d925486
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 71 deletions.
2 changes: 1 addition & 1 deletion source/DependenciesReport/DependenciesReport.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<Nullable>enable</Nullable>
<OutputType>Exe</OutputType>
<LangVersion>latest</LangVersion>
<TargetFramework>net8.0</TargetFramework>
<TargetFramework>net8.0-windows</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<SelfContained>false</SelfContained>
<PublishSingleFile>true</PublishSingleFile>
Expand Down
83 changes: 34 additions & 49 deletions source/DependenciesReport/DependenciesTools.cs
Original file line number Diff line number Diff line change
@@ -1,81 +1,66 @@
namespace DependenciesReport;
using System.Reflection;
using DependenciesReport.Models;

namespace DependenciesReport;

public static class DependenciesTools
{
public static Dictionary<string, Dictionary<string, string>> CreateDependenciesMap(string[] directories)
public static List<DirectoryDescriptor> CreateDependenciesMap(string[] directories)
{
var dependenciesMap = new Dictionary<string, Dictionary<string, string>>();
var dependenciesMap = new List<DirectoryDescriptor>();

foreach (var directory in directories)
{
var directoryDescriptor = new DirectoryDescriptor(Path.GetFileName(directory), directory);
var assemblies = Directory.GetFiles(directory, "*.dll");

foreach (var assembly in assemblies)
{
var assemblyName = Path.GetFileName(assembly);
var assemblyVersion = AssemblyUtils.GetAssemblyVersion(assembly);

if (!dependenciesMap.TryGetValue(assemblyName, out var value))
{
value = new Dictionary<string, string>();
dependenciesMap[assemblyName] = value;
}
var assemblyVersion = AssemblyName.GetAssemblyName(assembly).Version ?? new Version();

if (assemblyVersion != null)
{
value[Path.GetFileName(directory)] = assemblyVersion;
}
var assemblyDescriptor = new AssemblyDescriptor(assemblyName, assembly, assemblyVersion);
directoryDescriptor.Assemblies.Add(assemblyDescriptor);
}

dependenciesMap.Add(directoryDescriptor);
}

return dependenciesMap;
}

public static void UpgradeDependencies(Dictionary<string, Dictionary<string, Dictionary<string, string>>> dependenciesMaps)
public static void UpgradeDependencies(Dictionary<string, List<DirectoryDescriptor>> dependenciesMaps)
{
foreach (var (yearDirectory, dependenciesMap) in dependenciesMaps)
foreach (var (yearDirectory, directories) in dependenciesMaps)
{
foreach (var assemblyName in dependenciesMap.Keys)
var assemblyGroups = directories
.SelectMany(dir => dir.Assemblies, (dir, assembly) => new { Directory = dir, Assembly = assembly })
.GroupBy(x => x.Assembly.Name);

foreach (var assemblyGroup in assemblyGroups)
{
string? maxVersion = null;
string? maxVersionDirectory = null;
var maxAssembly = assemblyGroup.MaxBy(x => x.Assembly.Version);
if (maxAssembly is null) continue;

foreach (var directory in dependenciesMap[assemblyName].Keys)
{
var version = dependenciesMap[assemblyName][directory];
if (maxVersion == null || CompareVersions(version, maxVersion) > 0)
{
maxVersion = version;
maxVersionDirectory = directory;
}
}

if (maxVersionDirectory is not null && maxVersion is not null)
{
var maxVersionFilePath = Path.Combine(yearDirectory, maxVersionDirectory, assemblyName);
var maxVersion = maxAssembly.Assembly.Version;
var maxVersionFilePath = maxAssembly.Assembly.Path;

foreach (var directory in dependenciesMap[assemblyName].Keys)
foreach (var entry in assemblyGroup)
{
if (entry.Assembly.Version.CompareTo(maxVersion) < 0)
{
if (directory != maxVersionDirectory)
try
{
var targetFilePath = Path.Combine(yearDirectory, directory, assemblyName);
var targetVersion = dependenciesMap[assemblyName][directory];

if (CompareVersions(targetVersion, maxVersion) < 0)
{
File.Copy(maxVersionFilePath, targetFilePath, true);
Console.WriteLine($"Assembly {targetFilePath} was upgraded from version {targetVersion} to version {maxVersion}.");
}
File.Copy(maxVersionFilePath, entry.Assembly.Path, true);
Console.WriteLine($"Assembly {entry.Assembly.Path} was upgraded from version {entry.Assembly.Version.ToString(3)} to {maxVersion.ToString(3)}.");
}
catch (UnauthorizedAccessException)
{
Console.WriteLine($"No access to upgrade {entry.Assembly.Path}");
}
}
}
}
}
}

private static int CompareVersions(string version1, string version2)
{
var originVersion = new Version(version1);
var targetVersion = new Version(version2);
return originVersion.CompareTo(targetVersion);
}
}
3 changes: 3 additions & 0 deletions source/DependenciesReport/Models/AssemblyDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace DependenciesReport.Models;

public sealed record AssemblyDescriptor(string Name, string Path, Version Version);
6 changes: 6 additions & 0 deletions source/DependenciesReport/Models/DirectoryDescriptor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace DependenciesReport.Models;

public sealed record DirectoryDescriptor(string Name, string Path)
{
public List<AssemblyDescriptor> Assemblies { get; init; } = [];
}
46 changes: 36 additions & 10 deletions source/DependenciesReport/Program.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
using System.Diagnostics;
using System.Globalization;
using System.Security.Principal;
using DependenciesReport;
using DependenciesReport.Models;

var userFolder = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
var addinsPath = Path.Combine(userFolder, "Autodesk", "Revit", "Addins");
var yearsDirectories = Directory.GetDirectories(addinsPath);
var machineFolder = Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
var userAddinsPath = Path.Combine(userFolder, "Autodesk", "Revit", "Addins");
var machineAddinsPath = Path.Combine(machineFolder, "Autodesk", "Revit", "Addins");
var yearsGroups = Directory.GetDirectories(userAddinsPath)
.Union(Directory.GetDirectories(machineAddinsPath))
.GroupBy(Path.GetFileName)
.ToArray();

var reportName = $"DependenciesReport-{DateTime.Now.ToString("yyyy-MM-dd", DateTimeFormatInfo.InvariantInfo)}.txt";
var reportPath = Path.Combine(Path.GetTempPath(), reportName);
var summaryWriter = new SummaryWriter(reportPath);

var dependenciesMaps = new Dictionary<string, Dictionary<string, Dictionary<string, string>>>();
foreach (var yearDirectory in yearsDirectories)
var dependenciesMaps = new Dictionary<string, List<DirectoryDescriptor>>();
foreach (var yearsGroup in yearsGroups)
{
summaryWriter.Write($"Revit version: {Path.GetFileName(yearDirectory)}");
if (yearsGroup.Key is null) continue;

summaryWriter.Write($"Revit version: {Path.GetFileName(yearsGroup.Key)}");
summaryWriter.WriteLine();

var directories = Directory.GetDirectories(yearDirectory);
var directories = yearsGroup.SelectMany(Directory.GetDirectories).ToArray();
var dependenciesMap = DependenciesTools.CreateDependenciesMap(directories);
var dependenciesTable = TableFormater.CreateReportTable(directories, dependenciesMap);
dependenciesMaps.Add(yearDirectory, dependenciesMap);
var dependenciesTable = TableFormater.CreateReportTable(dependenciesMap);

if (dependenciesTable.Rows.Count == 0)
{
summaryWriter.Write("No conflicts detected.");
}
else
{
dependenciesMaps.Add(yearsGroup.Key, dependenciesMap);
summaryWriter.Write(dependenciesTable.ToMinimalString());
}

summaryWriter.Write(dependenciesTable.ToMinimalString());
summaryWriter.WriteLine();
}

Expand All @@ -47,9 +64,18 @@

if (string.Compare(response, "Y", StringComparison.OrdinalIgnoreCase) == 0)
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
var isAdmin = principal.IsInRole(WindowsBuiltInRole.Administrator);

if (!isAdmin)
{
Console.WriteLine("Permissions denied, only user dependencies will be updated. For a complete update, run application as administrator.");
}

DependenciesTools.UpgradeDependencies(dependenciesMaps);
Console.WriteLine("Success!");
}

Console.WriteLine();
Console.WriteLine("You can now close this terminal with Ctrl+C");
Console.ReadLine();
64 changes: 53 additions & 11 deletions source/DependenciesReport/TableFormater.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,69 @@
using System.Collections;
using ConsoleTables;
using ConsoleTables;
using DependenciesReport.Models;

namespace DependenciesReport;

public static class TableFormater
{
public static ConsoleTable CreateReportTable(string[] directories, Dictionary<string, Dictionary<string, string>> dependenciesMap)
public static ConsoleTable CreateReportTable(List<DirectoryDescriptor> dependenciesMap)
{
var conflictMap = dependenciesMap.Where(pair => pair.Value.Values.Distinct().Count() > 1);
var table = new ConsoleTable(directories.Select(Path.GetFileName).Prepend("Library").ToArray());
var conflictMap = GetConflictMap(dependenciesMap);

foreach (var conflictPair in conflictMap)
var assemblyNames = conflictMap
.SelectMany(dir => dir.Assemblies)
.Select(assembly => assembly.Name)
.Distinct()
.OrderBy(name => name)
.ToList();

var table = new ConsoleTable(new[] { "Dependency" }.Concat(conflictMap.Select(dir => dir.Name)).ToArray());

foreach (var assemblyName in assemblyNames)
{
var row = new ArrayList { conflictPair.Key };
foreach (var directory in directories)
var row = new List<object> { assemblyName };
foreach (var dir in conflictMap)
{
var directoryName = Path.GetFileName(directory);
row.Add(conflictPair.Value.GetValueOrDefault(directoryName, "-"));
var assembly = dir.Assemblies.FirstOrDefault(assembly => assembly.Name == assemblyName);
row.Add(assembly?.Version.ToString(3) ?? "-");
}

table.AddRow(row.ToArray());
}

return table;
}

private static List<DirectoryDescriptor> GetConflictMap(List<DirectoryDescriptor> directories)
{
var versionMap = directories
.SelectMany(directory => directory.Assemblies)
.GroupBy(assembly => assembly.Name)
.ToDictionary(
group => group.Key,
group => group.Select(assembly => assembly.Version).Distinct().ToList());

var uniqueAssemblies = new HashSet<AssemblyDescriptor>(
directories
.SelectMany(directory => directory.Assemblies)
.Where(assembly => versionMap[assembly.Name].Count > 1));

var conflictDirectories = new List<DirectoryDescriptor>();
foreach (var directory in directories)
{
var conflictAssemblies = new List<AssemblyDescriptor>();
foreach (var assembly in directory.Assemblies)
{
if (uniqueAssemblies.Contains(assembly)) conflictAssemblies.Add(assembly);
}

var conflictDirectory = new DirectoryDescriptor(directory.Name, directory.Path)
{
Assemblies = conflictAssemblies
};

if (conflictDirectory.Assemblies.Count > 0) conflictDirectories.Add(conflictDirectory);
}

return conflictDirectories;
}
}

0 comments on commit d925486

Please sign in to comment.