Пример #1
0
        // <inheritdoc />
        public async Task <SiteExtensionInfo> GetLocalExtension(string id, bool checkLatest = true)
        {
            ITracer           tracer  = _traceFactory.GetTracer();
            UIPackageMetadata package = null;

            using (tracer.Step("Now querying from local repo for package '{0}'.", id))
            {
                package = await _localRepository.GetLatestPackageById(id);
            }

            if (package == null)
            {
                tracer.Trace("No package found from local repo with id: {0}.", id);
                return(null);
            }

            SiteExtensionInfo info;

            using (tracer.Step("Converting NuGet object to SiteExtensionInfo"))
            {
                info = await ConvertLocalPackageToSiteExtensionInfo(package, checkLatest, tracer : tracer);
            }

            SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);

            armSettings.FillSiteExtensionInfo(info);
            return(info);
        }
Пример #2
0
        // <inheritdoc />
        public async Task <SiteExtensionInfo> GetLocalExtension(string id, bool checkLatest = true)
        {
            ITracer           tracer = _traceFactory.GetTracer();
            SiteExtensionInfo info   = GetPreInstalledExtension(id);

            if (info != null && info.ExtensionUrl != null)
            {
                tracer.Trace("Pre-installed site extension found: {0}", id);
            }
            else
            {
                UIPackageMetadata package = null;
                using (tracer.Step("{0} is not a pre-installed package. Now querying from local repo.", id))
                {
                    package = await _localRepository.GetLatestPackageById(id);
                }

                if (package == null)
                {
                    tracer.Trace("No package found from local repo with id: {0}.", id);
                    return(null);
                }

                using (tracer.Step("Converting NuGet object to SiteExtensionInfo"))
                {
                    info = await ConvertLocalPackageToSiteExtensionInfo(package, checkLatest, tracer : tracer);
                }
            }

            SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);

            armSettings.FillSiteExtensionInfo(info);
            return(info);
        }
Пример #3
0
        private async Task TryCheckLocalPackageLatestVersionFromRemote(SiteExtensionInfo info, bool checkLatest, ITracer tracer = null)
        {
            if (checkLatest)
            {
                try
                {
                    // FindPackage gets back the latest version.
                    SourceRepository  remoteRepo    = GetRemoteRepository(info.FeedUrl);
                    UIPackageMetadata latestPackage = await remoteRepo.GetLatestPackageById(info.Id);

                    if (latestPackage != null)
                    {
                        NuGetVersion currentVersion = NuGetVersion.Parse(info.Version);
                        info.LocalIsLatestVersion = NuGetVersion.Parse(info.Version).Equals(latestPackage.Identity.Version);
                        info.DownloadCount        = latestPackage.DownloadCount;
                        info.PublishedDateTime    = latestPackage.Published;
                    }
                }
                catch (Exception ex)
                {
                    if (tracer != null)
                    {
                        tracer.TraceError(ex);
                    }
                }
            }
        }
Пример #4
0
        /// <summary>
        /// <para> Return true if any of below cases is satisfied:</para>
        /// <para>      1) Package with same version and from same feed already exist in local repo</para>
        /// <para>      2) If given feedUrl is null</para>
        /// <para>              Try to use feed from local package, if feed from local package also null, fallback to default feed</para>
        /// <para>              Check if version from query is same as local package</para>
        /// <para>      3) If given version and feedUrl are null</para>
        /// <para>              Try to use feed from local package, if feed from local package also null, fallback to default feed</para>
        /// <para>              Check if version from query is same as local package</para>
        /// </summary>
        private async Task <bool> IsSiteExtensionInstalled(string id, string version, string feedUrl)
        {
            JsonSettings siteExtensionSettings = GetSettingManager(id);
            string       localPackageVersion   = siteExtensionSettings.GetValue(_versionSetting);
            string       localPackageFeedUrl   = siteExtensionSettings.GetValue(_feedUrlSetting);
            bool         isInstalled           = false;

            // Try to use given feed
            // If given feed is null, try with feed that from local package
            // And GetRemoteRepository will fallback to use default feed if pass in feed param is null
            SourceRepository remoteRepo = GetRemoteRepository(feedUrl ?? localPackageFeedUrl);

            // case 1 and 2
            if (!string.IsNullOrWhiteSpace(version) &&
                version.Equals(localPackageVersion, StringComparison.OrdinalIgnoreCase) &&
                remoteRepo.PackageSource.Source.Equals(localPackageFeedUrl, StringComparison.OrdinalIgnoreCase))
            {
                isInstalled = true;
            }
            else if (string.IsNullOrWhiteSpace(version) && string.IsNullOrWhiteSpace(feedUrl))
            {
                // case 3
                UIPackageMetadata remotePackage = await remoteRepo.GetLatestPackageById(id);

                if (remotePackage != null)
                {
                    isInstalled = remotePackage.Identity.Version.ToNormalizedString().Equals(localPackageVersion, StringComparison.OrdinalIgnoreCase);
                }
            }

            return(isInstalled);
        }
Пример #5
0
        public async Task <SiteExtensionInfo> GetRemoteExtension(string id, string version, string feedUrl)
        {
            ITracer tracer = _traceFactory.GetTracer();

            SourceRepository  remoteRepo = GetRemoteRepository(feedUrl);
            UIPackageMetadata package    = null;

            if (string.IsNullOrWhiteSpace(version))
            {
                using (tracer.Step("Version is null, search latest package by id: {0}", id))
                {
                    package = await remoteRepo.GetLatestPackageById(id);
                }
            }
            else
            {
                using (tracer.Step("Search package by id: {0} and version: {1}", id, version))
                {
                    package = await remoteRepo.GetPackageByIdentity(id, version);
                }
            }

            if (package == null)
            {
                tracer.Trace("No package found with id: {0} and version: {1}", id, version);
                return(null);
            }

            return(await ConvertRemotePackageToSiteExtensionInfo(package, feedUrl));
        }
Пример #6
0
        public async Task <SiteExtensionInfo> GetLocalExtension(string id, bool checkLatest = true)
        {
            ITracer           tracer = _traceFactory.GetTracer();
            SiteExtensionInfo info   = GetPreInstalledExtension(id);

            if (info != null && info.ExtensionUrl != null)
            {
                tracer.Trace("Pre-installed site extension found: {0}", id);
                return(info);
            }

            UIPackageMetadata package = await _localRepository.GetLatestPackageById(id);

            if (package == null)
            {
                tracer.Trace("No package found from local repo with id: {0}.", id);
                return(null);
            }

            return(await ConvertLocalPackageToSiteExtensionInfo(package, checkLatest));
        }
Пример #7
0
        public static async Task UpdateLocalPackage(this SourceRepository srcRepo, SourceRepository localRepo, PackageIdentity identity, string destinationFolder, string pathToLocalCopyOfNupkg, ITracer tracer)
        {
            tracer.Trace("Performing incremental package update for {0}", identity.Id);
            using (Stream newPackageStream = await srcRepo.GetPackageStream(identity))
            {
                // update file
                var localPackage = await localRepo.GetLatestPackageById(identity.Id);

                if (localPackage == null)
                {
                    throw new FileNotFoundException(string.Format(CultureInfo.InvariantCulture, "Package {0} not found from local repo.", identity.Id));
                }
                using (Stream oldPackageStream = await localRepo.GetPackageStream(localPackage.Identity))
                    using (ZipFile oldPackageZip = ZipFile.Read(oldPackageStream))
                        using (ZipFile newPackageZip = ZipFile.Read(newPackageStream))
                        {
                            // we only care about stuff under "content" folder
                            IEnumerable <ZipEntry>        oldContentEntries = oldPackageZip.Entries.Where(e => e.FileName.StartsWith(@"content/", StringComparison.InvariantCultureIgnoreCase));
                            IEnumerable <ZipEntry>        newContentEntries = newPackageZip.Entries.Where(e => e.FileName.StartsWith(@"content/", StringComparison.InvariantCultureIgnoreCase));
                            List <ZipEntry>               filesNeedToUpdate = new List <ZipEntry>();
                            Dictionary <string, ZipEntry> indexedOldFiles   = new Dictionary <string, ZipEntry>();
                            foreach (var item in oldContentEntries)
                            {
                                indexedOldFiles.Add(item.FileName.ToLowerInvariant(), item);
                            }

                            foreach (var newEntry in newContentEntries)
                            {
                                var fileName = newEntry.FileName.ToLowerInvariant();
                                if (indexedOldFiles.ContainsKey(fileName))
                                {
                                    // file name existed, only update if file has been touched
                                    ZipEntry oldEntry = indexedOldFiles[fileName];
                                    if (oldEntry.LastModified != newEntry.LastModified)
                                    {
                                        filesNeedToUpdate.Add(newEntry);
                                    }

                                    // remove from old index files buffer, the rest will be files that need to be deleted
                                    indexedOldFiles.Remove(fileName);
                                }
                                else
                                {
                                    // new files
                                    filesNeedToUpdate.Add(newEntry);
                                }
                            }

                            int substringStartIndex = @"content/".Length;

                            foreach (var entry in filesNeedToUpdate)
                            {
                                string fullPath = Path.Combine(destinationFolder, entry.FileName.Substring(substringStartIndex));

                                if (entry.IsDirectory)
                                {
                                    using (tracer.Step("Ensure directory: {0}", fullPath))
                                    {
                                        FileSystemHelpers.EnsureDirectory(fullPath.Replace('/', '\\'));
                                    }

                                    continue;
                                }

                                using (tracer.Step("Adding/Updating file: {0}", fullPath))
                                {
                                    FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(fullPath));
                                    using (Stream writeStream = FileSystemHelpers.OpenWrite(fullPath))
                                    {
                                        // let the thread go with itself, so that once file finsihed writing, doesn`t need to request thread context from main thread
                                        await entry.OpenReader().CopyToAsync(writeStream).ConfigureAwait(false);
                                    }
                                }
                            }

                            foreach (var entry in indexedOldFiles.Values)
                            {
                                string fullPath = Path.Combine(destinationFolder, entry.FileName.Substring(substringStartIndex));

                                if (entry.IsDirectory)
                                {
                                    // in case the two zip file was created from different tool. some tool will include folder as seperate entry, some don`t.
                                    // to be sure that foder is meant to be deleted, double check there is no files under it
                                    var entryNameInLower = entry.FileName.ToLower();
                                    if (!string.Equals(destinationFolder, fullPath, StringComparison.OrdinalIgnoreCase) &&
                                        newContentEntries.FirstOrDefault(e => e.FileName.ToLowerInvariant().StartsWith(entryNameInLower)) == null)
                                    {
                                        using (tracer.Step("Deleting directory: {0}", fullPath))
                                        {
                                            FileSystemHelpers.DeleteDirectorySafe(fullPath);
                                        }
                                    }
                                    continue;
                                }

                                using (tracer.Step("Deleting file: {0}", fullPath))
                                {
                                    FileSystemHelpers.DeleteFileSafe(fullPath);
                                }
                            }
                        }

                // update nupkg
                newPackageStream.Position = 0;
                using (tracer.Step("Updating nupkg file."))
                {
                    WriteStreamToFile(newPackageStream, pathToLocalCopyOfNupkg);
                    if (!identity.Version.Equals(localPackage.Identity.Version))
                    {
                        using (tracer.Step("New package has difference version {0} from old package {1}. Remove old nupkg file.", identity.Version, localPackage.Identity.Version))
                        {
                            // if version is difference, nupkg file name will be difference. will need to clean up the old one.
                            var oldNupkg = pathToLocalCopyOfNupkg.Replace(
                                string.Format(CultureInfo.InvariantCulture, "{0}.{1}.nupkg", identity.Id, identity.Version.ToNormalizedString()),
                                string.Format(CultureInfo.InvariantCulture, "{0}.{1}.nupkg", localPackage.Identity.Id, localPackage.Identity.Version.ToNormalizedString()));

                            FileSystemHelpers.DeleteFileSafe(oldNupkg);
                        }
                    }
                }
            }
        }
Пример #8
0
        private async Task <SiteExtensionInfo> TryInstallExtension(string id, string version, string feedUrl, SiteExtensionInfo.SiteExtensionType type, ITracer tracer)
        {
            SiteExtensionInfo info   = null;
            HttpStatusCode    status = HttpStatusCode.OK; // final status when success
            bool alreadyInstalled    = false;

            try
            {
                // Check if site extension already installed (id, version, feedUrl), if already install return right away
                if (await this.IsSiteExtensionInstalled(id, version, feedUrl))
                {
                    // package already installed, return package from local repo.
                    tracer.Trace("Package {0} with version {1} from {2} already installed.", id, version, feedUrl);
                    info = await GetLocalExtension(id);

                    alreadyInstalled = true;
                }
                else
                {
                    JsonSettings siteExtensionSettings = GetSettingManager(id);
                    feedUrl = (string.IsNullOrEmpty(feedUrl) ? siteExtensionSettings.GetValue(_feedUrlSetting) : feedUrl);
                    SourceRepository  remoteRepo   = GetRemoteRepository(feedUrl);
                    UIPackageMetadata localPackage = null;
                    UIPackageMetadata repoPackage  = null;

                    if (this.IsInstalledToWebRoot(id))
                    {
                        // override WebRoot type from setting
                        // WebRoot is a special type that install package to wwwroot, when perform update we need to update new content to wwwroot even if type is not specified
                        type = SiteExtensionInfo.SiteExtensionType.WebRoot;
                    }

                    if (string.IsNullOrWhiteSpace(version))
                    {
                        using (tracer.Step("Version is null, search latest package by id: {0}, will not search for unlisted package.", id))
                        {
                            repoPackage = await remoteRepo.GetLatestPackageById(id);
                        }
                    }
                    else
                    {
                        using (tracer.Step("Search package by id: {0} and version: {1}, will also search for unlisted package.", id, version))
                        {
                            repoPackage = await remoteRepo.GetPackageByIdentity(id, version);
                        }
                    }

                    if (repoPackage != null)
                    {
                        using (tracer.Step("Install package: {0}.", id))
                        {
                            string installationDirectory = GetInstallationDirectory(id);
                            localPackage = await InstallExtension(repoPackage, installationDirectory, feedUrl, type, tracer);

                            siteExtensionSettings.SetValues(new KeyValuePair <string, JToken>[] {
                                new KeyValuePair <string, JToken>(_versionSetting, localPackage.Identity.Version.ToNormalizedString()),
                                new KeyValuePair <string, JToken>(_feedUrlSetting, feedUrl),
                                new KeyValuePair <string, JToken>(_installUtcTimestampSetting, DateTime.UtcNow.ToString("u")),
                                new KeyValuePair <string, JToken>(_packageType, Enum.GetName(typeof(SiteExtensionInfo.SiteExtensionType), type))
                            });
                        }
                    }

                    info = await ConvertLocalPackageToSiteExtensionInfo(localPackage, checkLatest : true, tracer : tracer);
                }
            }
            catch (FileNotFoundException ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.NotFound;
            }
            catch (WebException ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }
            catch (InvalidEndpointException ex)
            {
                _analytics.UnexpectedException(ex, trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }
            catch (Exception ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }

            if (info == null)
            {
                // treat this as an error case since no result return from repo
                _analytics.UnexpectedException(
                    new FileNotFoundException(id),
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                info = new SiteExtensionInfo();
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = string.Format(Constants.SiteExtensionProvisioningStateNotFoundMessageFormat, id);
                status = HttpStatusCode.NotFound;
            }
            else if (!string.Equals(Constants.SiteExtensionProvisioningStateFailed, info.ProvisioningState, StringComparison.OrdinalIgnoreCase))
            {
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateSucceeded;
                info.Comment           = null;
            }

            using (tracer.Step("Update arm settings for {0} installation. Status: {1}", id, status))
            {
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                armSettings.ReadSiteExtensionInfo(info);
                armSettings.Status    = status;
                armSettings.Operation = alreadyInstalled ? null : Constants.SiteExtensionOperationInstall;
            }

            return(info);
        }
Пример #9
0
        // <inheritdoc />
        public async Task <SiteExtensionInfo> InstallExtension(string id, string version, string feedUrl)
        {
            ITracer tracer = _traceFactory.GetTracer();

            if (_preInstalledExtensionDictionary.ContainsKey(id))
            {
                tracer.Trace("Pre-installed site extension found: {0}, not going to perform new installation.", id);
                return(EnablePreInstalledExtension(_preInstalledExtensionDictionary[id]));
            }
            else
            {
                // Check if site extension already installed (id, version, feedUrl), if already install return right away
                if (await this.IsSiteExtensionInstalled(id, version, feedUrl))
                {
                    // package already installed, return package from local repo.
                    tracer.Trace("Site extension {0} with version {1} from {2} already installed.", id, version, feedUrl);
                    return(await GetLocalExtension(id));
                }

                JsonSettings siteExtensionSettings = GetSettingManager(id);

                if (String.IsNullOrEmpty(feedUrl))
                {
                    feedUrl = siteExtensionSettings.GetValue(_feedUrlSetting);
                }

                SourceRepository  remoteRepo   = GetRemoteRepository(feedUrl);
                UIPackageMetadata localPackage = null;
                UIPackageMetadata repoPackage  = null;

                if (string.IsNullOrWhiteSpace(version))
                {
                    using (tracer.Step("Version is null, search latest package by id: {0}", id))
                    {
                        repoPackage = await remoteRepo.GetLatestPackageById(id);
                    }
                }
                else
                {
                    using (tracer.Step("Search package by id: {0} and version: {1}", id, version))
                    {
                        repoPackage = await remoteRepo.GetPackageByIdentity(id, version);
                    }
                }

                if (repoPackage != null)
                {
                    using (tracer.Step("Install package: {0}.", id))
                    {
                        string installationDirectory = GetInstallationDirectory(id);
                        localPackage = await InstallExtension(repoPackage, installationDirectory, feedUrl);

                        siteExtensionSettings.SetValues(new KeyValuePair <string, JToken>[] {
                            new KeyValuePair <string, JToken>(_versionSetting, localPackage.Identity.Version.ToNormalizedString()),
                            new KeyValuePair <string, JToken>(_feedUrlSetting, feedUrl),
                            new KeyValuePair <string, JToken>(_installUtcTimestampSetting, DateTime.UtcNow.ToString("u"))
                        });
                    }
                }

                return(await ConvertLocalPackageToSiteExtensionInfo(localPackage, checkLatest : true));
            }
        }