private async Task ValidateChecksumAsync(Checksum checksumFromRequest, Solution incrementalSolutionBuilt) { #if DEBUG var currentSolutionChecksum = await incrementalSolutionBuilt.State.GetChecksumAsync(CancellationToken.None).ConfigureAwait(false); if (checksumFromRequest == currentSolutionChecksum) { return; } var solutionFromScratch = await CreateSolutionFromScratchAsync(checksumFromRequest).ConfigureAwait(false); await TestUtils.AssertChecksumsAsync(_assetService, checksumFromRequest, solutionFromScratch, incrementalSolutionBuilt).ConfigureAwait(false); async Task <Solution> CreateSolutionFromScratchAsync(Checksum checksum) { var solutionInfo = await SolutionInfoCreator.CreateSolutionInfoAsync(_assetService, checksum, _cancellationToken).ConfigureAwait(false); var workspace = new TemporaryWorkspace(solutionInfo); return(workspace.CurrentSolution); } #else // have this to avoid error on async await Task.CompletedTask.ConfigureAwait(false); #endif }
private async Task <Solution> GetSolutionAsync(IRemotableDataService service, PinnedRemotableDataScope syncScope) { var(solutionInfo, _) = await SolutionInfoCreator.CreateSolutionInfoAndOptionsAsync(new AssetProvider(service), syncScope.SolutionChecksum, CancellationToken.None).ConfigureAwait(false); var workspace = new AdhocWorkspace(); return(workspace.AddSolution(solutionInfo)); }
private async Task <Solution> UpdateProjectsAsync(Solution solution, HashSet <Checksum> oldChecksums, HashSet <Checksum> newChecksums) { var oldMap = await GetProjectMapAsync(solution, oldChecksums).ConfigureAwait(false); var newMap = await GetProjectMapAsync(_assetService, newChecksums).ConfigureAwait(false); // bulk sync assets await SynchronizeAssetsAsync(solution, oldMap, newMap).ConfigureAwait(false); // added project foreach (var kv in newMap) { if (!oldMap.ContainsKey(kv.Key)) { var projectInfo = await SolutionInfoCreator.CreateProjectInfoAsync(_assetService, kv.Value.Checksum, _cancellationToken).ConfigureAwait(false); if (projectInfo == null) { // this project is not supported in OOP continue; } // we have new project added solution = solution.AddProject(projectInfo); } } // changed project foreach (var kv in newMap) { if (!oldMap.TryGetValue(kv.Key, out var oldProjectChecksums)) { continue; } var newProjectChecksums = kv.Value; Contract.ThrowIfTrue(oldProjectChecksums.Checksum == newProjectChecksums.Checksum); solution = await UpdateProjectAsync(solution.GetProject(kv.Key), oldProjectChecksums, newProjectChecksums).ConfigureAwait(false); } // removed project foreach (var kv in oldMap) { if (!newMap.ContainsKey(kv.Key)) { // we have a project removed solution = solution.RemoveProject(kv.Key); } } return(solution); }
private async Task <Solution> LoadAsync(CancellationToken cancellationToken) { var adhocWorkspace = new AdhocWorkspace(); var serializer = adhocWorkspace.Services.GetService <ISerializerService>(); var solutionChecksum = default(Checksum); var map = new Dictionary <Checksum, object>(); using (var stream = new FileStream(_fileName, FileMode.Open)) using (var compressed = new DeflateStream(stream, CompressionMode.Decompress)) using (var reader = ObjectReader.TryGetReader(compressed, cancellationToken)) { // save root checksum and number of entries solutionChecksum = Checksum.ReadFrom(reader); // number of items in the package var count = reader.ReadInt32(); for (var i = 0; i < count; i++) { var itemChecksum = Checksum.ReadFrom(reader); var kind = (WellKnownSynchronizationKind)reader.ReadInt32(); // in service hub, cancellation means simply closed stream var @object = serializer.Deserialize <object>(kind, reader, cancellationToken); Debug.Assert(itemChecksum == serializer.CreateChecksum(@object, cancellationToken)); map.Add(itemChecksum, @object); } } var assetSource = new SimpleAssetSource(AssetStorage.Default, map); var assetService = new AssetService(scopeId: 0, AssetStorage.Default, serializer); var solutionCreator = new SolutionCreator(assetService, _solution, cancellationToken); // check whether solution is update to the given base solution if (await solutionCreator.IsIncrementalUpdateAsync(solutionChecksum).ConfigureAwait(false)) { // create updated solution off the baseSolution return(await solutionCreator.CreateSolutionAsync(solutionChecksum).ConfigureAwait(false)); } // get new solution info var solutionInfo = await SolutionInfoCreator.CreateSolutionInfoAsync(assetService, solutionChecksum, cancellationToken).ConfigureAwait(false); // otherwise, just return new solution return(adhocWorkspace.AddSolution(solutionInfo)); }
/// <summary> /// SolutionService is designed to be stateless. if someone asks a solution (through solution checksum), /// it will create one and return the solution. the engine takes care of synching required data and creating a solution /// correspoing to the given checksum. /// /// but doing that from scratch all the time wil be expansive in terms of synching data, compilation being cached, file being parsed /// and etc. so even if the service itself is stateless, internally it has several caches to improve perf of various parts. /// /// first, it holds onto last solution got built. this will take care of common cases where multiple services running off same solution. /// second, it uses assets cache to hold onto data just synched (within 3 min) so that if it requires to build new solution, /// it can save some time to re-sync data which might just used by other solution. /// third, it holds onto solution from primary branch from Host. and it will try to see whether it can build new solution off the /// primary solution it is holding onto. this will make many solution level cache to be re-used. /// /// the primary solution can be updated in 2 ways. /// first, host will keep track of primary solution changes in host, and call OOP to synch to latest time to time. /// second, engine keeps track of whether a certain request is for primary solution or not, and if it is, /// it let that request to update primary solution cache to latest. /// /// these 2 are complimentary to each other. #1 makes OOP's primary solution to be ready for next call (push), #2 makes OOP's primary /// solution be not stale as much as possible. (pull) /// </summary> private async Task <Solution> CreateSolution_NoLockAsync(Checksum solutionChecksum, bool fromPrimaryBranch, Solution baseSolution, CancellationToken cancellationToken) { var updater = new SolutionCreator(_assetService, baseSolution, cancellationToken); // check whether solution is update to the given base solution if (await updater.IsIncrementalUpdateAsync(solutionChecksum).ConfigureAwait(false)) { // create updated solution off the baseSolution var solution = await updater.CreateSolutionAsync(solutionChecksum).ConfigureAwait(false); if (fromPrimaryBranch) { // if the solutionChecksum is for primary branch, update primary workspace cache with the solution PrimaryWorkspace.UpdateSolution(solution); return(PrimaryWorkspace.CurrentSolution); } // otherwise, just return the solution return(solution); } // we need new solution. bulk sync all asset for the solution first. await _assetService.SynchronizeSolutionAssetsAsync(solutionChecksum, cancellationToken).ConfigureAwait(false); // get new solution info var solutionInfo = await SolutionInfoCreator.CreateSolutionInfoAsync(_assetService, solutionChecksum, cancellationToken).ConfigureAwait(false); if (fromPrimaryBranch) { // if the solutionChecksum is for primary branch, update primary workspace cache with new solution PrimaryWorkspace.ClearSolution(); PrimaryWorkspace.AddSolution(solutionInfo); return(PrimaryWorkspace.CurrentSolution); } // otherwise, just return new solution var workspace = new TemporaryWorkspace(await SolutionInfoCreator.CreateSolutionInfoAsync(_assetService, solutionChecksum, cancellationToken).ConfigureAwait(false)); return(workspace.CurrentSolution); }
public Task <(SolutionInfo, SerializableOptionSet)> GetSolutionInfoAndOptionsAsync(Checksum solutionChecksum, CancellationToken cancellationToken) { return(SolutionInfoCreator.CreateSolutionInfoAndOptionsAsync(_assetService, solutionChecksum, cancellationToken)); }
private async Task <Project> UpdateDocumentsAsync( Project project, IEnumerable <TextDocumentState> existingTextDocumentStates, ChecksumCollection oldChecksums, ChecksumCollection newChecksums, Func <Solution, ImmutableArray <DocumentInfo>, Solution> addDocuments, Func <Solution, DocumentId, Solution> removeDocument) { using (var olds = SharedPools.Default <HashSet <Checksum> >().GetPooledObject()) using (var news = SharedPools.Default <HashSet <Checksum> >().GetPooledObject()) { olds.Object.UnionWith(oldChecksums); news.Object.UnionWith(newChecksums); // remove documents that exist in both side olds.Object.ExceptWith(newChecksums); news.Object.ExceptWith(oldChecksums); var oldMap = await GetDocumentMapAsync(project, existingTextDocumentStates, olds.Object).ConfigureAwait(false); var newMap = await GetDocumentMapAsync(_assetService, news.Object).ConfigureAwait(false); // added document ImmutableArray <DocumentInfo> .Builder documentsToAdd = null; foreach (var kv in newMap) { if (!oldMap.ContainsKey(kv.Key)) { documentsToAdd = documentsToAdd ?? ImmutableArray.CreateBuilder <DocumentInfo>(); // we have new document added var documentInfo = await SolutionInfoCreator.CreateDocumentInfoAsync(_assetService, kv.Value.Checksum, _cancellationToken).ConfigureAwait(false); documentsToAdd.Add(documentInfo); } } if (documentsToAdd != null) { project = addDocuments(project.Solution, documentsToAdd.ToImmutable()).GetProject(project.Id); } // changed document foreach (var kv in newMap) { if (!oldMap.TryGetValue(kv.Key, out var oldDocumentChecksums)) { continue; } var newDocumentChecksums = kv.Value; Contract.ThrowIfTrue(oldDocumentChecksums.Checksum == newDocumentChecksums.Checksum); var document = project.GetDocument(kv.Key) ?? project.GetAdditionalDocument(kv.Key) ?? project.GetAnalyzerConfigDocument(kv.Key); project = await UpdateDocumentAsync(document, oldDocumentChecksums, newDocumentChecksums).ConfigureAwait(false); } // removed document foreach (var kv in oldMap) { if (!newMap.ContainsKey(kv.Key)) { // we have a document removed project = removeDocument(project.Solution, kv.Key).GetProject(project.Id); } } return(project); } }
public Task <SolutionInfo> GetSolutionInfoAsync(Checksum solutionChecksum, CancellationToken cancellationToken) { return(SolutionInfoCreator.CreateSolutionInfoAsync(_assetService, solutionChecksum, cancellationToken)); }
/// <summary> /// This function is the callback used to execute the command when the menu item is clicked. /// See the constructor to see how the menu item is associated with this function using /// OleMenuCommandService service and MenuCommand class. /// </summary> /// <param name="sender">Event sender.</param> /// <param name="e">Event args.</param> private void Execute(object sender, EventArgs e) { ThreadHelper.ThrowIfNotOnUIThread(); try { VisualStudioWorkspace workspace = ((IComponentModel)Package.GetGlobalService(typeof(SComponentModel))).GetService <VisualStudioWorkspace>(); ProjectItem selectedItem = this.GetSelectedSolutionExplorerItem(); if (selectedItem != null && selectedItem.Name != null && !selectedItem.Name.EndsWith(".cs")) { "52ABP代码生成器(官网:52abp.com),仅支持C#文件!".ErrorMsg(); } else { Document currentSelectedDocument; if (((selectedItem != null) ? selectedItem.Document : null) != null) { currentSelectedDocument = workspace.CurrentSolution.GetDocumentByFilePath(selectedItem.Document.FullName); } else { if (selectedItem == null) { "致命异常-无法获得当前选择的解决方案:请重新打开这个解决方案,然后重试本工具。(官网:52abp.com)".ErrorMsg(); return; } string file = selectedItem.Name; string projectName = selectedItem.ContainingProject.Name; List <Project> allProjects = workspace.CurrentSolution.Projects.ToList <Project>(); List <Project> tmpProjects = (from o in allProjects where o.Name.StartsWith(projectName + "(net") select o).ToList <Project>(); List <Document> docs; if (allProjects.Exists((Project p) => p.Name.Contains(".Shared"))) { docs = (from d in (from p in allProjects where p.Name.Contains(projectName) && !p.Name.Contains(".Shared") select p).FirstOrDefault <Project>().Documents where d.Name == file select d).ToList <Document>(); } else if (tmpProjects.Count > 1) { docs = (from d in tmpProjects.FirstOrDefault <Project>().Documents where d.Name == file select d).ToList <Document>(); } else { docs = (from d in (from p in allProjects where p.Name == projectName select p).SelectMany((Project p) => p.Documents) where d.Name == file select d).ToList <Document>(); } if (docs.Count == 0) { "致命异常-无法获得当前选择的解决方案。请尝试重新打开解决方案,然后再使用本工具(官网:52abp.com)".ErrorMsg(); return; } if (docs.Count > 1) { "当前解决方案中,有多个同名的类文件,请处理之后再使用本工具,比如删除一个^_^(官网:52abp.com)。".ErrorMsg(); return; } currentSelectedDocument = docs.FirstOrDefault <Document>(); } SolutionInfoModel solutionInfo = SolutionInfoCreator.Create(currentSelectedDocument); string path = Path.Combine(solutionInfo.SolutionPath, "solutionInfo.json"); string solutionInfoJson = JsonConvert.SerializeObject(solutionInfo); path.CreateFile(solutionInfoJson); ProcessStartInfo processStartInfo = new ProcessStartInfo(); string exePath = Path.Combine(Path.GetDirectoryName(typeof(CommonConsts).Assembly.Location), "YoyoAbpCodePowerProject.WPF.exe"); processStartInfo.FileName = exePath; processStartInfo.Arguments = " \"" + solutionInfo.SolutionPath + "\""; Process.Start(processStartInfo); } } catch (Exception ex) { try { "发生了一个异常。请复制 c/p 堆栈信息,然后打开项目网站(https://github.com/52ABP/52ABP.CodeGenerator),补充问题和增加简短描述。".ErrorMsg(); StringBuilder sb = new StringBuilder(); sb.Append("<html><head></head><body><a hrf='https://github.com/52ABP/52ABP.CodeGenerator/issues/new'>baidu</a><br>"); sb.Append(ex.ToString()); sb.Append("</body></html>"); string tmpFile = Path.GetTempFileName(); File.WriteAllText(tmpFile, sb.ToString()); VsShellUtilities.OpenBrowser("file:///" + tmpFile); } catch (Exception) { "发生了一个异常。 无法将堆栈跟踪写入临时目录.".ErrorMsg(); } } }