DocSpace-buildtools/common/ASC.Resource.Manager/Program.cs

460 lines
20 KiB
C#
Raw Normal View History

using System;
2019-08-15 09:14:10 +00:00
using System.Collections.Concurrent;
using System.Collections.Generic;
2021-02-28 12:40:50 +00:00
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
2019-08-15 09:14:10 +00:00
using System.Text.RegularExpressions;
using System.Threading.Tasks;
2021-02-09 17:53:49 +00:00
using System.Xml.Linq;
2020-01-23 11:03:38 +00:00
2020-08-24 18:41:06 +00:00
using ASC.Common;
using ASC.Common.Utils;
2020-01-23 11:03:38 +00:00
using CommandLine;
2020-01-23 11:03:38 +00:00
using Microsoft.Extensions.DependencyInjection;
namespace ASC.Resource.Manager
{
class Program
{
2021-02-09 17:53:49 +00:00
private const string CsProjScheme = "http://schemas.microsoft.com/developer/msbuild/2003";
private static readonly XName ItemGroupXname = XName.Get("ItemGroup", CsProjScheme);
private static readonly XName EmbededXname = XName.Get("EmbeddedResource", CsProjScheme);
private static readonly XName DependentUpon = XName.Get("DependentUpon", CsProjScheme);
private const string IncludeAttribute = "Include";
2021-02-28 12:40:50 +00:00
private const string ConditionAttribute = "Condition";
2021-03-07 16:30:36 +00:00
public static string[] Args;
public static void Main(string[] args)
{
2021-03-07 16:30:36 +00:00
Args = args;
2021-03-08 17:58:55 +00:00
var copy = new List<string>();
for(var i =0;i<args.Length;i++)
{
if(args[i] == "--pathToConf" || args[i] == "--ConnectionStrings:default:connectionString")
{
2021-04-13 19:49:43 +00:00
i++;
2021-03-08 17:58:55 +00:00
continue;
}
copy.Add(args[i]);
}
Parser.Default.ParseArguments<Options>(copy).WithParsed(Export);
}
2020-09-22 14:17:17 +00:00
public static void Export(Options options)
{
2021-03-07 16:30:36 +00:00
var services = new ServiceCollection();
2021-03-07 16:30:36 +00:00
var startup = new Startup(Args);
startup.ConfigureServices(services);
2020-12-28 13:22:08 +00:00
var serviceProvider = services.BuildServiceProvider();
2020-01-23 11:03:38 +00:00
using var scope = serviceProvider.CreateScope();
2020-08-24 18:41:06 +00:00
var scopeClass = scope.ServiceProvider.GetService<ProgramScope>();
var cultures = new List<string>();
var projects = new List<ResFile>();
var enabledSettings = new EnabledSettings();
2021-02-09 17:53:49 +00:00
Func<IServiceProvider, string, string, string, string, string, string, bool> export = null;
try
{
2019-08-13 15:17:14 +00:00
var (project, module, filePath, exportPath, culture, format, key) = options;
2019-08-13 11:17:18 +00:00
2021-03-08 17:58:55 +00:00
//project = "WebStudio";
//module = "Tips";
//filePath = "TipsResource.resx";
2021-03-07 16:30:36 +00:00
//culture = "ru";
//exportPath = @"C:\Git\portals\";
//key = "*,HtmlMaster*";
2021-03-06 08:08:57 +00:00
//key = "*";
2020-01-23 11:03:38 +00:00
2019-08-13 15:17:14 +00:00
if (format == "json")
2019-08-13 11:17:18 +00:00
{
export = JsonManager.Export;
}
else
{
export = ResxManager.Export;
}
if (string.IsNullOrEmpty(exportPath))
{
exportPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
}
2019-08-13 11:17:18 +00:00
if (!Path.IsPathRooted(exportPath))
{
exportPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), exportPath));
}
if (!Directory.Exists(exportPath))
{
Console.WriteLine("Error!!! Export path doesn't exist! Please enter a valid directory path.");
return;
}
2020-07-29 21:57:58 +00:00
enabledSettings = scopeClass.Configuration.GetSetting<EnabledSettings>("enabled");
2021-02-28 12:40:50 +00:00
cultures = scopeClass.ResourceData.GetCultures().Where(r => r.Available).Select(r => r.Title).ToList();//.Intersect(enabledSettings.Langs).ToList();
2020-07-29 21:57:58 +00:00
projects = scopeClass.ResourceData.GetAllFiles();
2019-08-13 15:17:14 +00:00
ExportWithProject(project, module, filePath, culture, exportPath, key);
Console.WriteLine("The data has been successfully exported!");
}
catch (Exception err)
{
Console.WriteLine(err);
}
2019-08-13 15:17:14 +00:00
void ExportWithProject(string projectName, string moduleName, string fileName, string culture, string exportPath, string key = null)
{
if (!string.IsNullOrEmpty(projectName))
{
2019-08-13 15:17:14 +00:00
ExportWithModule(projectName, moduleName, fileName, culture, exportPath, key);
}
else
{
2019-08-15 11:52:47 +00:00
var projectToExport = projects
.Where(r => string.IsNullOrEmpty(r.ModuleName) || r.ModuleName == moduleName)
.Where(r => string.IsNullOrEmpty(r.FileName) || r.FileName == fileName)
.Select(r => r.ProjectName)
.Intersect(enabledSettings.Projects);
foreach (var p in projectToExport)
{
2019-08-13 15:17:14 +00:00
ExportWithModule(p, moduleName, fileName, culture, exportPath, key);
}
}
}
2019-08-13 15:17:14 +00:00
void ExportWithModule(string projectName, string moduleName, string fileName, string culture, string exportPath, string key = null)
{
if (!string.IsNullOrEmpty(moduleName))
{
2019-08-13 15:17:14 +00:00
ExportWithFile(projectName, moduleName, fileName, culture, exportPath, key);
}
else
{
2019-08-15 11:52:47 +00:00
var moduleToExport = projects
.Where(r => r.ProjectName == projectName)
2021-02-09 14:58:35 +00:00
.Where(r => string.IsNullOrEmpty(fileName) || r.FileName == fileName)
.Select(r => r.ModuleName)
.Distinct();
2019-08-15 11:52:47 +00:00
foreach (var m in moduleToExport)
{
2019-08-13 15:17:14 +00:00
ExportWithFile(projectName, m, fileName, culture, exportPath, key);
}
}
}
void ExportWithFile(string projectName, string moduleName, string fileName, string culture, string exportPath, string key = null)
{
if (!string.IsNullOrEmpty(fileName))
{
ExportWithCulture(projectName, moduleName, fileName, culture, exportPath, key);
}
else
{
foreach (var f in projects.Where(r => r.ProjectName == projectName && r.ModuleName == moduleName).Select(r => r.FileName))
{
ExportWithCulture(projectName, moduleName, f, culture, exportPath, key);
}
}
}
2019-08-13 15:17:14 +00:00
void ExportWithCulture(string projectName, string moduleName, string fileName, string culture, string exportPath, string key)
{
2021-03-08 17:58:55 +00:00
var filePath = Directory.GetFiles(exportPath, $"{fileName}", SearchOption.AllDirectories).FirstOrDefault();
2021-03-07 16:30:36 +00:00
if (!string.IsNullOrEmpty(culture))
{
2021-03-07 16:30:36 +00:00
exportPath = Path.GetDirectoryName(filePath);
2020-01-23 11:03:38 +00:00
export(serviceProvider, projectName, moduleName, fileName, culture, exportPath, key);
2021-03-07 16:30:36 +00:00
Console.WriteLine(filePath);
}
else
{
2021-02-28 12:40:50 +00:00
var resultFiles = new ConcurrentBag<Tuple<string, string>>();
2021-03-07 16:30:36 +00:00
2021-02-09 17:53:49 +00:00
var asmbl = "";
2021-02-19 16:17:06 +00:00
var assmlPath = "";
2021-02-28 12:40:50 +00:00
var nsp = "";
2021-02-09 14:58:35 +00:00
2021-03-01 08:49:42 +00:00
var keys = key.Split(",");
if (keys.Contains("*"))
2021-02-09 14:58:35 +00:00
{
2021-02-19 16:17:06 +00:00
if (string.IsNullOrEmpty(filePath)) return;
assmlPath = Path.GetDirectoryName(filePath);
var name = Path.GetFileNameWithoutExtension(fileName);
2021-02-09 14:58:35 +00:00
var designerPath = Path.Combine(Path.GetDirectoryName(filePath), $"{name}.Designer.cs");
var data = File.ReadAllText(designerPath);
var regex = new Regex(@"namespace\s(\S*)\s", RegexOptions.IgnoreCase);
var matches = regex.Matches(data);
if (!matches.Any() || matches[0].Groups.Count < 2)
{
return;
}
2021-02-28 12:40:50 +00:00
//File.Delete(designerPath);
2021-02-09 14:58:35 +00:00
2021-02-28 12:40:50 +00:00
nsp = matches[0].Groups[1].Value;
2021-02-09 17:53:49 +00:00
2021-02-09 14:58:35 +00:00
do
{
asmbl = Directory.GetFiles(assmlPath, "*.csproj").FirstOrDefault();
2021-02-09 17:53:49 +00:00
if (string.IsNullOrEmpty(asmbl))
{
assmlPath = Path.GetFullPath(Path.Combine(assmlPath, ".."));
}
2021-02-09 14:58:35 +00:00
}
while (string.IsNullOrEmpty(asmbl));
regex = new Regex(@"\<AssemblyName\>(\S*)\<\/AssemblyName\>", RegexOptions.IgnoreCase);
matches = regex.Matches(File.ReadAllText(asmbl));
2021-04-13 18:19:48 +00:00
string assName = "";
2021-02-09 14:58:35 +00:00
if (!matches.Any() || matches[0].Groups.Count < 2)
{
2021-04-13 18:19:48 +00:00
assName = Path.GetFileNameWithoutExtension(asmbl);
}
else
{
assName = matches[0].Groups[1].Value;
2021-02-09 14:58:35 +00:00
}
2021-04-13 18:19:48 +00:00
key = CheckExist(fileName, $"{nsp}.{name},{assName}", exportPath);
2021-03-06 08:08:57 +00:00
var additional = string.Join(",", keys.Where(r => r.Length > 1 && r.Contains("*")).ToArray());
2021-03-01 08:49:42 +00:00
if (!string.IsNullOrEmpty(additional))
{
key += "," + additional;
}
2021-02-19 16:17:06 +00:00
exportPath = Path.GetDirectoryName(filePath);
2021-02-09 14:58:35 +00:00
}
2021-02-28 12:40:50 +00:00
else
{
exportPath = Path.GetDirectoryName(filePath);
}
2021-02-09 14:58:35 +00:00
if (string.IsNullOrEmpty(exportPath))
{
return;
}
ParallelEnumerable.ForAll(cultures.AsParallel(), c => {
2021-02-09 17:53:49 +00:00
var any = export(serviceProvider, projectName, moduleName, fileName, c, exportPath, key);
if (any)
{
2021-02-28 12:40:50 +00:00
resultFiles.Add(new Tuple<string, string>(c, $"{filePath.Replace(".resx", (c == "Neutral" ? $".resx" : $".{c}.resx"))}".Substring(assmlPath.Length + 1)));
2021-02-09 17:53:49 +00:00
}
2021-02-09 14:58:35 +00:00
});
2021-02-09 17:53:49 +00:00
2021-03-07 16:30:36 +00:00
Console.WriteLine(filePath);
if (string.IsNullOrEmpty(asmbl)) return;
2021-02-28 12:40:50 +00:00
AddResourceForCsproj(asmbl, filePath.Substring(assmlPath.Length + 1), resultFiles.OrderBy(r=> r.Item2));
2021-03-01 08:49:42 +00:00
var assmblName = Path.GetFileNameWithoutExtension(asmbl);
2021-03-06 08:08:57 +00:00
var f = Path.GetDirectoryName(filePath.Substring(assmlPath.Length + 1)).Replace('\\', '.');
nsp = assmblName;
if (!string.IsNullOrEmpty(f))
{
nsp += "." + Path.GetDirectoryName(filePath.Substring(assmlPath.Length + 1)).Replace('\\', '.');
}
2021-02-28 12:40:50 +00:00
var startInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
FileName = scopeClass.Configuration["resGen"],
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = $"{Path.GetFileName(filePath)} /str:cs,{nsp},{Path.GetFileNameWithoutExtension(filePath)},{Path.GetFileNameWithoutExtension(filePath)}.Designer.cs /publicClass",
WorkingDirectory = Path.GetDirectoryName(filePath)
};
using (var p = Process.Start(startInfo))
{
if (p.WaitForExit(10000))
{
Console.WriteLine($"{Path.GetFileNameWithoutExtension(filePath)}.Designer.cs");
}
p.Close();
}
var resourcesFile = filePath.Replace(".resx", ".resources");
if (File.Exists(resourcesFile))
{
File.Delete(resourcesFile);
}
}
}
}
2019-08-15 09:14:10 +00:00
2021-02-09 14:58:35 +00:00
public static string CheckExist(string fileName, string fullClassName, string path)
2019-08-15 09:14:10 +00:00
{
2021-02-09 14:58:35 +00:00
var resName = Path.GetFileNameWithoutExtension(fileName);
2019-08-15 09:14:10 +00:00
var bag = new ConcurrentBag<string>();
2021-02-28 12:40:50 +00:00
var csFiles = Directory.GetFiles(Path.GetFullPath(path), "*.cs", SearchOption.AllDirectories).Except(Directory.GetFiles(Path.GetFullPath(path), "*Resource.Designer.cs", SearchOption.AllDirectories));
2021-04-23 12:16:32 +00:00
csFiles = csFiles.Concat(Directory.GetFiles(Path.GetFullPath(path), "*.cshtml", SearchOption.AllDirectories)).ToArray();
2021-02-09 14:58:35 +00:00
csFiles = csFiles.Concat(Directory.GetFiles(Path.GetFullPath(path), "*.aspx", SearchOption.AllDirectories)).ToArray();
2021-02-28 12:40:50 +00:00
csFiles = csFiles.Concat(Directory.GetFiles(Path.GetFullPath(path), "*.Master", SearchOption.AllDirectories)).ToArray();
2021-02-09 14:58:35 +00:00
csFiles = csFiles.Concat(Directory.GetFiles(Path.GetFullPath(path), "*.ascx", SearchOption.AllDirectories)).ToArray();
csFiles = csFiles.Concat(Directory.GetFiles(Path.GetFullPath(path), "*.html", SearchOption.AllDirectories)).ToArray();
csFiles = csFiles.Concat(Directory.GetFiles(Path.GetFullPath(path), "*.js", SearchOption.AllDirectories).Where(r => !r.Contains("node_modules"))).ToArray();
2021-02-28 12:40:50 +00:00
csFiles = csFiles.Concat(Directory.GetFiles(Path.GetFullPath(path), "*.xsl", SearchOption.AllDirectories)).ToArray();
2019-08-15 09:14:10 +00:00
var xmlFiles = Directory.GetFiles(Path.GetFullPath(path), "*.xml", SearchOption.AllDirectories);
string localInit() => "";
Func<string, ParallelLoopState, long, string, string> func(string regexp) => (f, state, index, a) =>
{
var data = File.ReadAllText(f);
2021-02-09 14:58:35 +00:00
var regex = new Regex(regexp, RegexOptions.IgnoreCase);
2019-08-15 09:14:10 +00:00
var matches = regex.Matches(data);
if (matches.Count > 0)
{
2021-03-06 08:08:57 +00:00
var result = string.Join(",", matches.Select(r => r.Groups[1].Value));
if (!string.IsNullOrEmpty(a))
return a + "," + result;
return result;
2019-08-15 09:14:10 +00:00
}
return a;
};
void localFinally(string r)
{
if (!bag.Contains(r) && !string.IsNullOrEmpty(r))
{
bag.Add(r.Trim(','));
}
}
2019-08-23 11:27:18 +00:00
_ = Parallel.ForEach(csFiles, localInit, func(@$"\W+{resName}\.(\w*)"), localFinally);
_ = Parallel.ForEach(csFiles, localInit, func(@$"CustomNamingPeople\.Substitute\<{resName}\>\(""(\w*)""\)"), localFinally);
2021-03-07 16:30:36 +00:00
_ = Parallel.ForEach(csFiles, localInit, func(@$"{resName}\.ResourceManager\.GetString\(""(\w*)""[\),\,]"), localFinally);
2021-03-06 08:08:57 +00:00
_ = Parallel.ForEach(csFiles, localInit, func(@$"{resName}\.ResourceManager\.GetString\(""(\w*)""\s*\+"), (r) => {
if (!bag.Contains(r) && !string.IsNullOrEmpty(r))
{
bag.Add(r.Replace(",", "*,").Trim(',') + "*");
}
});
2019-08-15 09:14:10 +00:00
_ = Parallel.ForEach(xmlFiles, localInit, func(@$"\|(\w*)\|{fullClassName.Replace(".", "\\.")}"), localFinally);
2021-03-06 08:08:57 +00:00
if (fileName == "TipsResource.resx")
{
2021-03-08 17:58:55 +00:00
_ = Parallel.ForEach(xmlFiles, localInit, func(@$"<tip id=""(\w*)"""), (r) => {
if (!string.IsNullOrEmpty(r))
{
var ids = r.Split(',');
foreach (var id in ids)
{
bag.Add(id);
bag.Add($"{id}MessageBody");
bag.Add($"{id}MessageHeader");
}
}
});
2021-03-06 08:08:57 +00:00
}
if (fileName == "AuditReportResource.resx")
{
_ = Parallel.ForEach(csFiles.Where(r=> r.EndsWith("ActionMapper.cs")), localInit, func(@$"ResourceName\s*=\s*""(\w*)"""), localFinally);
_ = Parallel.ForEach(csFiles, localInit, func(@$"\[Event\(""(\w*)"""), localFinally);
}
if (fileName == "NamingPeopleResource.resx")
{
_ = Parallel.ForEach(xmlFiles.Where(r=> r.EndsWith("PeopleNames.xml")), localInit, func(@$"\>(\w*)\<"), localFinally);
}
2021-02-09 14:58:35 +00:00
return string.Join(',', bag.ToArray().Distinct());
2019-08-15 09:14:10 +00:00
}
2021-02-09 17:53:49 +00:00
2021-02-28 12:40:50 +00:00
private static void AddResourceForCsproj(string csproj, string fileName, IEnumerable<Tuple<string,string>> files)
2021-02-09 17:53:49 +00:00
{
if (!files.Any()) return;
var doc = XDocument.Parse(File.ReadAllText(csproj));
if (doc.Root == null) return;
foreach (var file in files)
{
var node = doc.Root.Elements().FirstOrDefault(r =>
r.Name == ItemGroupXname &&
r.Elements(EmbededXname).Any(x=>
{
var attr = x.Attribute(IncludeAttribute);
return attr != null && attr.Value == fileName;
})) ??
doc.Root.Elements().FirstOrDefault(r =>
r.Name == ItemGroupXname &&
r.Elements(EmbededXname).Any());
XElement reference;
bool referenceNotExist;
if (node == null)
{
node = new XElement(ItemGroupXname);
doc.Root.Add(node);
reference = new XElement(EmbededXname);
referenceNotExist = true;
}
else
{
var embeded = node.Elements(EmbededXname).ToList();
reference = embeded.FirstOrDefault(r =>
{
var attr = r.Attribute(IncludeAttribute);
2021-02-28 12:40:50 +00:00
return attr != null && attr.Value == file.Item2;
2021-02-09 17:53:49 +00:00
});
2021-02-28 12:40:50 +00:00
2021-02-09 17:53:49 +00:00
referenceNotExist = reference == null;
if (referenceNotExist)
{
reference = new XElement(EmbededXname);
2021-02-28 12:40:50 +00:00
if (file.Item2 != fileName)
2021-02-09 17:53:49 +00:00
{
reference.Add(new XElement(DependentUpon, Path.GetFileName(fileName)));
}
}
}
if (referenceNotExist)
{
2021-02-28 12:40:50 +00:00
reference.SetAttributeValue(IncludeAttribute, file.Item2);
reference.SetAttributeValue(ConditionAttribute, string.Format("$(Cultures.Contains('{0}'))", file.Item1));
2021-02-09 17:53:49 +00:00
node.Add(reference);
}
}
doc.Save(csproj);
}
}
2020-08-24 18:41:06 +00:00
2020-12-28 13:22:08 +00:00
[Scope]
2020-08-24 18:41:06 +00:00
public class ProgramScope
{
internal ResourceData ResourceData { get; }
2020-12-28 13:22:08 +00:00
internal ConfigurationExtension Configuration { get; }
2020-08-24 18:41:06 +00:00
2020-12-28 13:22:08 +00:00
public ProgramScope(ResourceData resourceData, ConfigurationExtension configuration)
2020-08-24 18:41:06 +00:00
{
ResourceData = resourceData;
Configuration = configuration;
}
}
}