Exemple #1
0
        internal int WhoWins(CanonicalName negative, CanonicalName positive)
        {
            if (positive == negative)
            {
                return(0);
            }

            foreach (var p in Priorities)
            {
                int pos = 0;
                int neg = 0;
                foreach (var key in GetCanonicalNames(p).Where(each => this[p, each, null].IsTrue()))
                {
                    pos = Math.Max(positive.MatchQuality(key), pos);
                    neg = Math.Max(negative.MatchQuality(key), neg);
                }
                if (pos == neg)
                {
                    continue;
                }
                return(pos - neg);
            }

            // didn't find a rule that can distinguish.
            // if the packages differ by version only, use that to decide
            if (positive.DiffersOnlyByVersion(negative))
            {
                return(((long)(ulong)positive.Version - (long)(ulong)negative.Version) > 0 ? 1 : -1);
            }

            // nothing to decide with!
            return(0);
        }
Exemple #2
0
        public Task InstallPackage(CanonicalName canonicalName, bool? autoUpgrade, bool? force, bool? download, bool? pretend, CanonicalName replacingPackage)
        {
            var response = Event<GetResponseInterface>.RaiseFirst();

            if (CancellationRequested) {
                response.OperationCanceled("install-package");
                return FinishedSynchronously;
            }

            double[] overallProgress = {0.0};
            double[] eachTaskIsWorth = {0.0};
            int[] lastProgress = {0};
            Package currentPackageInstalling = null;
            var numberOfPackagesToInstall = 0;
            var numberOfPackagesToDownload = 0;

            CurrentTask.Events += new IndividualProgress(percentage => {
                overallProgress[0] += ((percentage - lastProgress[0])*eachTaskIsWorth[0])/100;
                lastProgress[0] = percentage;
                // ReSharper disable PossibleNullReferenceException ... this is what I really want. :[
                // ReSharper disable AccessToModifiedClosure
                response.InstallingPackageProgress(currentPackageInstalling.CanonicalName, percentage, (int)(overallProgress[0]*100));
                // ReSharper restore AccessToModifiedClosure
                // ReSharper restore PossibleNullReferenceException
            });

            var unwantedPackages = new List<Package>();
            if( null != replacingPackage ) {
                if( replacingPackage.DiffersOnlyByVersion(canonicalName)) {
                    unwantedPackages.AddRange(SearchForPackages(replacingPackage));
                }
            }

            using (var manualResetEvent = new ManualResetEvent(true)) {
                try {
                    lock (_manualResetEvents) {
                        _manualResetEvents.Add(manualResetEvent);
                    }

                    var packagesTriedToDownloadThisTask = new List<Package>();
                    if (canonicalName.IsPartial) {
                        response.Error("Invalid Canonical Name", "InstallPackage", "Canonical name '{0}' is not a complete canonical name".format(canonicalName));
                    }
                    var package = SearchForPackages(canonicalName).FirstOrDefault();

                    if (package == null) {
                        response.UnknownPackage(canonicalName);
                        return FinishedSynchronously;
                    }

                    if (package.IsBlocked) {
                        response.PackageBlocked(canonicalName);
                        return FinishedSynchronously;
                    }

                    var installedPackages = package.InstalledPackages.ToArray();

                    // is the user authorized to install this?
                    if (null != replacingPackage) {
                        if (replacingPackage.DiffersOnlyByVersion(canonicalName)) {
                            if (!Event<CheckForPermission>.RaiseFirst(PermissionPolicy.UpdatePackage)) {
                                return FinishedSynchronously;
                            }
                        }
                    } else {
                        if( package.LatestInstalledThatUpdatesToThis != null ) {
                            if (!Event<CheckForPermission>.RaiseFirst(PermissionPolicy.UpdatePackage)) {
                                return FinishedSynchronously;
                            }
                        } else {
                            if (!Event<CheckForPermission>.RaiseFirst(PermissionPolicy.InstallPackage)) {
                                return FinishedSynchronously;
                            }
                        }
                    }

                    // if this is an explicit update or upgrade,
                    //      - check to see if there is a compatible package already installed that is marked do-not-update
                    //        fail if so.
                    if (null != replacingPackage && unwantedPackages.Any( each => each.IsBlocked )) {
                        response.PackageBlocked(canonicalName);
                        return FinishedSynchronously;
                    }

                    // mark the package as the client requested.
                    package.PackageSessionData.DoNotSupercede = (false == autoUpgrade);
                    package.PackageSessionData.UpgradeAsNeeded = (true == autoUpgrade);
                    package.PackageSessionData.IsWanted = true;

                    // the resolve-acquire-install-loop
                    do {
                        // if the world changes, this will get set somewhere between here and the
                        // other end of the do-loop.
                        manualResetEvent.Reset();

                        if (CancellationRequested) {
                            response.OperationCanceled("install-package");
                            return FinishedSynchronously;
                        }

                        IEnumerable<Package> installGraph;
                        try {
                            UpdateDependencyFlags();
                            installGraph = GenerateInstallGraph(package).ToArray();
                        } catch (OperationCompletedBeforeResultException) {
                            // we encountered an unresolvable condition in the install graph.
                            // messages should have already been sent.
                            response.FailedPackageInstall(canonicalName, package.LocalLocations.FirstOrDefault(),
                                "One or more dependencies are unable to be resolved.");
                            return FinishedSynchronously;
                        }

                        // seems like a good time to check if we're supposed to bail...
                        if (CancellationRequested) {
                            response.OperationCanceled("install-package");
                            return FinishedSynchronously;
                        }

                        if (download == false && pretend == true) {
                            // we can just return a bunch of foundpackage messages, since we're not going to be
                            // actually installing anything, nor trying to download anything.
                            foreach (var p in installGraph) {
                                response.PackageInformation(p);
                            }
                            return FinishedSynchronously;
                        }

                        // we've got an install graph.
                        // let's see if we've got all the files
                        var missingFiles = (from p in installGraph where !p.HasLocalLocation select p).ToArray();

                        if (download == true) {
                            // we want to try downloading all the files that we're missing, regardless if we've tried before.
                            // unless we've already tried in this task once.
                            foreach (var p in missingFiles.Where(packagesTriedToDownloadThisTask.Contains)) {
                                packagesTriedToDownloadThisTask.Add(p);
                                p.PackageSessionData.CouldNotDownload = false;
                            }
                        }

                        if (numberOfPackagesToInstall != installGraph.Count() || numberOfPackagesToDownload != missingFiles.Count()) {
                            // recalculate the rest of the install progress based on the new install graph.
                            numberOfPackagesToInstall = installGraph.Count();
                            numberOfPackagesToDownload = missingFiles.Count();

                            eachTaskIsWorth[0] = (1.0 - overallProgress[0])/(numberOfPackagesToInstall + numberOfPackagesToDownload);
                        }

                        if (missingFiles.Any()) {
                            // we've got some packages to install that don't have files.
                            foreach (var p in missingFiles.Where(p => !p.PackageSessionData.HasRequestedDownload)) {
                                SessionData.Current.RequireRemoteFile(p.CanonicalName,
                                    p.RemotePackageLocations, PackageManagerSettings.CoAppPackageCache, false,(rrfState) => {
                                        Updated(); //shake loose anything that might be waiting for this.
                                        return rrfState.LocalLocation;
                                    });

                                p.PackageSessionData.HasRequestedDownload = true;
                            }
                        } else {
                            // check to see if this package requires trust.
                            bool ok = true;
                            foreach (var pkg in installGraph.Where(pkg => pkg.RequiresTrustedPublisher && !TrustedPublishers.ContainsIgnoreCase(pkg.PublicKeyToken))) {
                                response.FailedPackageInstall(pkg.CanonicalName, pkg.LocalLocations.FirstOrDefault(), "Package requires a trusted publisher key of '{0}'.".format(pkg.PublicKeyToken));
                                ok = false;
                            }
                            if( ok == false) {
                                return FinishedSynchronously;
                            }

                            if (pretend == true) {
                                // we can just return a bunch of found-package messages, since we're not going to be
                                // actually installing anything, and everything we needed is downloaded.
                                foreach (var p in installGraph) {
                                    response.PackageInformation(p);
                                }
                                return FinishedSynchronously;
                            }

                            var failed = false;
                            // no missing files? Check
                            // complete install graph? Check

                            foreach (var p in installGraph) {
                                currentPackageInstalling = p;
                                // seems like a good time to check if we're supposed to bail...
                                if (CancellationRequested) {
                                    response.OperationCanceled("install-package");
                                    return FinishedSynchronously;
                                }
                                var validLocation = currentPackageInstalling.PackageSessionData.LocalValidatedLocation;

                                try {
                                    if (!currentPackageInstalling.IsInstalled) {
                                        if (string.IsNullOrEmpty(validLocation)) {
                                            // can't find a valid location
                                            response.FailedPackageInstall(currentPackageInstalling.CanonicalName, currentPackageInstalling.LocalLocations.FirstOrDefault(), "Can not find local valid package");
                                            currentPackageInstalling.PackageSessionData.PackageFailedInstall = true;
                                        } else {
                                            lastProgress[0] = 0;
                                            // GS01: We should put a softer lock here to keep the client aware that packages
                                            // are being installed on other threads...
                                            lock (typeof (MSIBase)) {
                                                if (Engine.DoesTheServiceNeedARestart) {
                                                    // something has changed where we need restart the service before we can continue.
                                                    // and the one place we don't wanna be when we issue a shutdown in in Install :) ...
                                                    Engine.RestartService();
                                                    response.OperationCanceled("install-package");
                                                    return FinishedSynchronously;
                                                }

                                                // install progress is now handled by the delegate at the beginning of this function.
                                                currentPackageInstalling.Install();
                                            }
                                            overallProgress[0] += ((100 - lastProgress[0])*eachTaskIsWorth[0])/100;
                                            response.InstallingPackageProgress(currentPackageInstalling.CanonicalName, 100, (int)(overallProgress[0]*100));
                                            response.InstalledPackage(currentPackageInstalling.CanonicalName);
                                            Signals.InstalledPackage(currentPackageInstalling.CanonicalName);
                                        }
                                    }
                                } catch (Exception e) /* (PackageInstallFailedException pife)  */ {
                                    Logger.Error("FAILED INSTALL");
                                    Logger.Error(e);

                                    response.FailedPackageInstall(currentPackageInstalling.CanonicalName, validLocation, "Package failed to install.");
                                    currentPackageInstalling.PackageSessionData.PackageFailedInstall = true;

                                    if (!currentPackageInstalling.PackageSessionData.AllowedToSupercede) {
                                        throw new OperationCompletedBeforeResultException(); // user specified packge as critical.
                                    }
                                    failed = true;
                                    break;
                                }
                            }
                            if (!failed) {
                                if( unwantedPackages.Any()) {
                                    foreach (Package eachPkg in unwantedPackages) {
                                        eachPkg.IsWanted = false;
                                    }
                                } else {
                                    var olderpkgs = package.InstalledPackages.Where(each => each.IsWanted && package.IsNewerThan(each)).ToArray();
                                    if( olderpkgs.Length > 0 ) {
                                        //anthing older?

                                        if( olderpkgs.Length > 1) {
                                            // hmm. more than one.
                                            // is there just a single thing we're updating?
                                            olderpkgs = olderpkgs.Where(package.IsAnUpdateFor).ToArray();
                                        }

                                        // if we can get down to one, let's unwant that.
                                        if (olderpkgs.Length == 1) {
                                            ((Package)olderpkgs[0]).IsWanted = false;
                                        }
                                    }

                                }

                                // W00T ... We did it!
                                // check for restart required...
                                if (Engine.DoesTheServiceNeedARestart) {
                                    // something has changed where we need restart the service before we can continue.
                                    // and the one place we don't wanna be when we issue a shutdown in in Install :) ...
                                    response.Restarting();
                                    Engine.RestartService();
                                    return FinishedSynchronously;
                                }
                                return FinishedSynchronously;
                            }

                            // otherwise, let's run it thru again. maybe it'll come together.
                        }

                        //----------------------------------------------------------------------------
                        // wait until either the manualResetEvent is set, but check every second or so
                        // to see if the client has cancelled the operation.
                        while (!manualResetEvent.WaitOne(500)) {
                            if (CancellationRequested) {
                                response.OperationCanceled("install-package");
                                return FinishedSynchronously;
                            }

                            // we can also use this opportunity to update progress on any outstanding download tasks.
                            overallProgress[0] += missingFiles.Sum(missingFile => ((missingFile.PackageSessionData.DownloadProgressDelta*eachTaskIsWorth[0])/100));
                        }
                    } while (true);
                } catch (OperationCompletedBeforeResultException) {
                    // can't continue with options given.
                    return FinishedSynchronously;
                } finally {
                    // remove manualResetEvent from the mre list
                    lock (_manualResetEvents) {
                        _manualResetEvents.Remove(manualResetEvent);
                    }
                }
            }
        }
Exemple #3
0
 internal static FourPartVersion GetCurrentPackageVersion(CanonicalName canonicalName)
 {
     var activePkg = PackageManagerImpl.Instance.InstalledPackages.Where(each => canonicalName.DiffersOnlyByVersion(each.CanonicalName))
         .OrderBy(each => each, new Toolkit.Extensions.Comparer<Package>((packageA, packageB) => GeneralPackageSettings.Instance.WhoWins(packageA, packageB)))
         .FirstOrDefault();
     return activePkg == null ? 0 : activePkg.Version;
 }
Exemple #4
0
        internal static FourPartVersion GetCurrentPackageVersion(CanonicalName canonicalName)
        {
            var installedVersionsOfPackage = PackageManagerImpl.Instance.InstalledPackages.Where(each => canonicalName.DiffersOnlyByVersion(each.CanonicalName)).OrderByDescending(each => each.CanonicalName.Version);
            var latestPackage = installedVersionsOfPackage.FirstOrDefault();

            // clean as we go...
            if (latestPackage == null) {
                PackageManagerSettings.PerPackageSettings[canonicalName.GeneralName, "CurrentVersion"].Value = null;
                return 0;
            }

            // is there a version set?
            FourPartVersion ver = (ulong)PackageManagerSettings.PerPackageSettings[canonicalName.GeneralName, "CurrentVersion"].LongValue;

            // if not (or it's not set to an installed package), let's set it to the latest version of the package.
            if (ver == 0 || installedVersionsOfPackage.FirstOrDefault(p => p.CanonicalName.Version == ver) == null) {
                latestPackage.SetPackageCurrent();
                return latestPackage.CanonicalName.Version;
            }
            return ver;
        }
        internal int WhoWins(CanonicalName negative, CanonicalName positive)
        {
            if( positive == negative ) {
                return 0;
            }

            foreach( var p in Priorities) {
                int pos = 0;
                int neg = 0;
                foreach (var key in GetCanonicalNames(p).Where(each=> this[p, each, null].IsTrue())) {
                    pos = Math.Max(positive.MatchQuality(key), pos);
                    neg = Math.Max(negative.MatchQuality(key), neg);
                }
                if( pos == neg) {
                    continue;
                }
                return pos - neg;
            }

            // didn't find a rule that can distinguish.
            // if the packages differ by version only, use that to decide
            if( positive.DiffersOnlyByVersion(negative) ) {
                return (((long)(ulong)positive.Version - (long)(ulong)negative.Version) > 0 ? 1 : -1);
            }

            // nothing to decide with!
            return 0;
        }
Exemple #6
0
        internal static FourPartVersion GetCurrentPackageVersion(CanonicalName canonicalName)
        {
            var activePkg = PackageManagerImpl.Instance.InstalledPackages.Where(each => canonicalName.DiffersOnlyByVersion(each.CanonicalName))
                            .OrderBy(each => each, new Toolkit.Extensions.Comparer <Package>((packageA, packageB) => GeneralPackageSettings.Instance.WhoWins(packageA, packageB)))
                            .FirstOrDefault();

            return(activePkg == null ? 0 : activePkg.Version);
        }