Example #1
0
 private async Task InitializeDetails(TemplateViewModel selection) {
     if (!string.IsNullOrEmpty(selection.RemoteUrl)) {
         try {
             var repo = await _githubClient.GetRepositoryDetails(selection.RepositoryOwner, selection.RepositoryName);
             selection.Description = repo.Description;
             selection.AvatarUrl = repo.Owner.AvatarUrl;
             selection.OwnerUrl = repo.Owner.HtmlUrl;
         } catch (WebException) {
         }
     } else {
         selection.Description = string.Empty;
         selection.AvatarUrl = string.Empty;
         selection.OwnerUrl = string.Empty;
     }
 }
 private static void PrintTemplate(TemplateViewModel template) {
     Console.WriteLine($"DisplayName: '{template.DisplayName}', RemoteUrl: '{template.RemoteUrl}', ClonedPath: '{template.ClonedPath}', Desc: '{template.Description}'");
 }
Example #3
0
        private async Task RefreshContextAsync(TemplateViewModel selection) {
            if (!await EnsureCookiecutterIsInstalled()) {
                return;
            }

            try {
                LoadingStatus = OperationStatus.InProgress;

                _outputWindow.ShowAndActivate();
                _outputWindow.WriteLine(Strings.LoadingTemplateStarted.FormatUI(selection.DisplayName));

                var result = await _cutterClient.LoadContextAsync(selection.ClonedPath, UserConfigFilePath);

                ContextItems.Clear();
                foreach (var item in result) {
                    ContextItems.Add(new ContextItemViewModel(item.Name, item.Selector, item.Label, item.Description, item.Url, item.DefaultValue, item.Values));
                }

                LoadingStatus = OperationStatus.Succeeded;

                _outputWindow.WriteLine(Strings.LoadingTemplateSuccess.FormatUI(selection.DisplayName));

                ReportTemplateEvent(CookiecutterTelemetry.TelemetryArea.Template, CookiecutterTelemetry.TemplateEvents.Load, selection);

                // Go to the context page
                ContextLoaded?.Invoke(this, EventArgs.Empty);
            } catch (Exception ex) when (!ex.IsCriticalException()) {
                LoadingStatus = OperationStatus.Failed;

                _outputWindow.WriteErrorLine(ex.Message);
                _outputWindow.WriteLine(Strings.LoadingTemplateFailed.FormatUI(selection.DisplayName));

                ReportTemplateEvent(CookiecutterTelemetry.TelemetryArea.Template, CookiecutterTelemetry.TemplateEvents.Load, selection, ex);
            }
        }
Example #4
0
        private async Task RefreshSelectedDescriptionAsync(TemplateViewModel selection) {
            if (selection == null) {
                SelectedDescription = string.Empty;
                SelectedImage = null;
                return;
            }

            if (!selection.HasDetails) {
                await InitializeDetails(selection);
            }

            SelectedDescription = selection.Description ?? string.Empty;
            try {
                // Create an ImageSource because binding to that feels significantly faster than binding to the image url
                SelectedImage = !string.IsNullOrEmpty(selection.AvatarUrl) ? new BitmapImage(new Uri(selection.AvatarUrl)) : null;
            } catch (Exception ex) when (!ex.IsCriticalException()) {
                SelectedImage = null;
            }
        }
Example #5
0
 public async Task SelectTemplate(TemplateViewModel template) {
     SelectedTemplate = template;
     await RefreshSelectedDescriptionAsync(template);
 }
Example #6
0
        private async Task AddFromSource(
            ITemplateSource source,
            string searchTerm,
            CategorizedViewModel parent,
            CancellationToken ct,
            string continuationToken = null,
            VisualStudio.Imaging.Interop.ImageMoniker? updateableImage = null
        ) {
            var loading = new LoadingViewModel();
            parent.Templates.Add(loading);

            try {
                var result = await source.GetTemplatesAsync(searchTerm, continuationToken, ct);
                foreach (var t in result.Templates) {
                    ct.ThrowIfCancellationRequested();

                    var vm = new TemplateViewModel();
                    vm.DisplayName = t.Name;
                    vm.Description = t.Description;
                    vm.AvatarUrl = t.AvatarUrl;
                    vm.OwnerUrl = t.OwnerUrl;
                    vm.RemoteUrl = t.RemoteUrl;
                    vm.ClonedPath = t.LocalFolderPath;
                    vm.IsUpdateAvailable = t.UpdateAvailable == true;
                    parent.Templates.Add(vm);
                }

                ct.ThrowIfCancellationRequested();

                if (result.ContinuationToken != null) {
                    parent.Templates.Add(new ContinuationViewModel(result.ContinuationToken));
                }
            } catch (TemplateEnumerationException ex) {
                var template = new ErrorViewModel() {
                    ErrorDescription = ex.Message,
                    ErrorDetails = ex.InnerException?.Message,
                };
                parent.Templates.Add(template);
            } finally {
                parent.Templates.Remove(loading);
            }
        }
Example #7
0
        public bool IsCloneNeeded(TemplateViewModel template) {
            // TODO: every search clears the ClonedPath for the online templates, so this will trigger cloning more often than we desire

            // If it's from online (recommended or github) and hasn't been cloned then we need to clone it
            return !string.IsNullOrEmpty(template.RemoteUrl) && string.IsNullOrEmpty(template.ClonedPath);
        }
Example #8
0
 public bool IsCloneCollision(TemplateViewModel template, out TemplateViewModel collidingTemplate) {
     // If an installed template has the same repository name, we'll have a collision,
     // unless the installed template is a perfect match, ie. same repo owner.
     var result = Installed.Templates.OfType<TemplateViewModel>().Where(t => t.RepositoryName == template.RepositoryName && t.RepositoryFullName != template.RepositoryFullName).ToArray();
     if (result.Length > 0) {
         collidingTemplate = result.First();
         return true;
     } else {
         collidingTemplate = null;
         return false;
     }
 }
Example #9
0
        private async Task RefreshTemplatesAsync(string searchTerm, CancellationToken ct) {
            Custom.Templates.Clear();
            Recommended.Templates.Clear();
            GitHub.Templates.Clear();
            Installed.Templates.Clear();

            SearchResults.Clear();

            if (!string.IsNullOrEmpty(searchTerm)) {
                var searchTermTemplate = new TemplateViewModel();
                searchTermTemplate.IsSearchTerm = true;

                if (searchTerm.StartsWith("http")) {
                    searchTermTemplate.DisplayName = searchTerm;
                    searchTermTemplate.RemoteUrl = searchTerm;
                    Custom.Templates.Add(searchTermTemplate);
                    SearchResults.Add(Custom);
                    return;
                } else if (Directory.Exists(searchTerm)) {
                    searchTermTemplate.DisplayName = searchTerm;
                    searchTermTemplate.ClonedPath = searchTerm;
                    Custom.Templates.Add(searchTermTemplate);
                    SearchResults.Add(Custom);
                    return;
                }
            }

            SearchResults.Add(Installed);
            SearchResults.Add(Recommended);
            SearchResults.Add(GitHub);

            var recommendedTask = AddFromSource(_recommendedSource, searchTerm, Recommended, ct);
            var installedTask = AddFromSource(_installedSource, searchTerm, Installed, ct);
            var githubTask = AddFromSource(_githubSource, searchTerm, GitHub, ct);

            await Task.WhenAll(recommendedTask, installedTask, githubTask);
        }
Example #10
0
        public async Task DeleteTemplateAsync(TemplateViewModel template) {
            try {
                string remote = template.RemoteUrl;

                _outputWindow.ShowAndActivate();
                _outputWindow.WriteLine(String.Empty);
                _outputWindow.WriteLine(Strings.DeletingTemplateStarted.FormatUI(template.ClonedPath));

                await _installedSource.DeleteTemplateAsync(template.ClonedPath);

                _outputWindow.WriteLine(Strings.DeletingTemplateSuccess.FormatUI(template.ClonedPath));

                ReportTemplateEvent(CookiecutterTelemetry.TelemetryArea.Template, CookiecutterTelemetry.TemplateEvents.Delete, template);

                if (!string.IsNullOrEmpty(remote)) {
                    var t = Installed.Templates.SingleOrDefault(current => (current as TemplateViewModel)?.RemoteUrl == remote) as TemplateViewModel;
                    if (t != null) {
                        Installed.Templates.Remove(t);
                    }

                    t = Recommended.Templates.SingleOrDefault(current => (current as TemplateViewModel)?.RemoteUrl == remote) as TemplateViewModel;
                    if (t != null) {
                        t.ClonedPath = string.Empty;
                    }

                    t = GitHub.Templates.SingleOrDefault(current => (current as TemplateViewModel)?.RemoteUrl == remote) as TemplateViewModel;
                    if (t != null) {
                        t.ClonedPath = string.Empty;
                    }
                } else {
                    if (Installed.Templates.Contains(template)) {
                        Installed.Templates.Remove(template);
                    }
                }
            } catch (Exception ex) when (!ex.IsCriticalException()) {
                _outputWindow.WriteErrorLine(ex.Message);
                _outputWindow.WriteLine(Strings.DeletingTemplateFailed.FormatUI(template.ClonedPath));
                ReportTemplateEvent(CookiecutterTelemetry.TelemetryArea.Template, CookiecutterTelemetry.TemplateEvents.Delete, template, ex);
            }
        }
Example #11
0
        private void ReportTemplateEvent(string area, string eventName, TemplateViewModel selection, Exception error = null) {
            try {
                if (!_telemetry.TelemetryService.IsEnabled) {
                    return;
                }

                var repoUrl = selection.RemoteUrl?.ToLowerInvariant() ?? string.Empty;
                var repoFullName = selection.RepositoryFullName?.ToLowerInvariant() ?? string.Empty;
                var repoOwner = selection.RepositoryOwner?.ToLowerInvariant() ?? string.Empty;
                var repoName = selection.RepositoryName?.ToLowerInvariant() ?? string.Empty;
                var projKind = TargetProjectLocation?.ProjectKind ?? string.Empty;

                var obj = new {
                    Success = error == null,
                    RepoUrl = new TelemetryPiiProperty(repoUrl),
                    RepoFullName = new TelemetryPiiProperty(repoFullName),
                    RepoOwner = new TelemetryPiiProperty(repoOwner),
                    RepoName = new TelemetryPiiProperty(repoName),
                    ProjectKind = projKind,
                };
                ReportEvent(area, eventName, obj);
            } catch (Exception ex) {
                Debug.Fail($"Error reporting event.\n{ex.Message}");
            }
        }
Example #12
0
        private void ReportTemplateEvent(string area, string eventName, TemplateViewModel selection, Exception error = null) {
            try {
                if (!_telemetry.TelemetryService.IsEnabled) {
                    return;
                }

                var repoUrl = selection.RemoteUrl?.ToLowerInvariant();
                var repoFullName = selection.RepositoryFullName?.ToLowerInvariant();
                var repoOwner = selection.RepositoryOwner?.ToLowerInvariant();
                var repoName = selection.RepositoryName?.ToLowerInvariant();

                var obj = new {
                    Success = error == null,
                    RepoUrl = repoUrl?.GetSha512(),
                    RepoFullName = repoFullName?.GetSha512(),
                    RepoOwner = repoOwner?.GetSha512(),
                    RepoName = repoName?.GetSha512(),
                };
                ReportEvent(area, eventName, obj);
            } catch (Exception ex) {
                Debug.Fail($"Error reporting event.\n{ex.Message}");
            }
        }
Example #13
0
        private async Task RefreshSelectedDescriptionAsync(TemplateViewModel selection) {
            if (selection == null) {
                SelectedDescription = string.Empty;
                return;
            }

            if (string.IsNullOrEmpty(selection.Description)) {
                await InitializeDescription(selection);
            }

            SelectedDescription = selection.Description ?? string.Empty;
        }
Example #14
0
 public async Task SelectTemplate(TemplateViewModel template) {
     SelectedTemplate = template;
     await RefreshSelectedDescriptionAsync(template);
 }
Example #15
0
        public bool IsCloneNeeded(TemplateViewModel template) {
            // TODO: every search clears the ClonedPath for the online templates, so this will trigger cloning more often than we desire

            // If it's from online (recommended or github) and hasn't been cloned then we need to clone it
            return !string.IsNullOrEmpty(template.RemoteUrl) && string.IsNullOrEmpty(template.ClonedPath);
        }