예제 #1
0
        private void CollectDependencies(string thisId, ref Dictionary <RestoredDependencyPair, SharedConfig> myDependencies, RestoredDependencyPair pair)
        {
            // pair contains simply a Dependency in most cases, but if it contains a version already, then we map that version to a SharedConfig
            // Null assertions
            if (pair is null || pair.Dependency is null)
            {
                throw new ArgumentNullException(nameof(pair), Resources.DependencyNull);
            }
            var d = pair.Dependency !;

            if (d.Id is null)
            {
                throw new ArgumentException(Resources.DependencyIdNull);
            }
            if (d.VersionRange is null)
            {
                throw new ArgumentException($"Dependency: {d.Id} {nameof(d.VersionRange)} is null!");
            }
            if (thisId.Equals(d.Id, StringComparison.OrdinalIgnoreCase))
            {
                throw new DependencyException($"Recursive dependency! Tried to get dependency: {d.Id}, but {thisId} matches {d.Id}!");
            }
            // We want to convert our uri into a config file
            var depConfig = dependencyResolver.GetSharedConfig(pair);

            if (depConfig is null)
            {
                throw new ConfigException($"Could not find config for: {d.Id}! Range: {d.VersionRange}");
            }
            // Then we want to check to ensure that the config file we have gotten is within our version
            if (depConfig.Config is null)
            {
                throw new ConfigException($"Confid is of an invalid format for: {d.Id} - No config!");
            }
            if (depConfig.Config.Info is null)
            {
                throw new ConfigException($"Config is of an invalid format for: {d.Id} - No info!");
            }
            if (string.IsNullOrEmpty(depConfig.Config.Info.Id))
            {
                throw new ConfigException($"Config is of an invalid format for: {d.Id} - No Id!");
            }
            // Check to make sure the config's version matches our dependency's version
            if (!depConfig.Config.Info.Id.Equals(d.Id, StringComparison.OrdinalIgnoreCase))
            {
                throw new ConfigException($"Dependency and config have different ids! {d.Id} != {depConfig.Config.Info.Id}!");
            }
            if (depConfig.Config.Info.Version is null)
            {
                throw new ConfigException($"Config is of an invalid format for: {d.Id} - No Version!");
            }
            // If it isn't, we fail to match our dependencies, exit out.
            if (!d.VersionRange.IsSatisfied(depConfig.Config.Info.Version))
            {
                throw new DependencyException($"Dependency unmet! Want: {d.VersionRange} got: {depConfig.Config.Info.Version} for: {d.Id}");
            }
            if (pair.Version != null && pair.Version != depConfig.Config.Info.Version)
            {
                throw new ConfigException($"Wanted specific version: {pair.Version} but got: {depConfig.Config.Info.Version} for: {d.Id}");
            }
            var toAdd = new RestoredDependencyPair {
                Dependency = d, Version = depConfig.Config.Info.Version
            };

            if (!myDependencies.ContainsKey(toAdd))
            {
                // We need to double check here, just to make sure we don't accidentally add when we literally have a potential match:
                if (myDependencies.Keys.FirstOrDefault(item => toAdd.Dependency.Id.Equals(item.Dependency !.Id, StringComparison.OrdinalIgnoreCase) && toAdd.Version == item.Version) is null)
                {
                    // If there is no exactly matching key:
                    // Add our mapping from dependency to config
                    myDependencies.Add(toAdd, depConfig);
                }
            }
            // Otherwise, we iterate over all of the config's RESTORED dependencies
            // That is, all of the dependencies that we used to actually build this
            foreach (var innerD in depConfig.RestoredDependencies)
            {
                if (innerD.Dependency is null || innerD.Version is null)
                {
                    throw new ConfigException($"A restored dependency in config for: {depConfig.Config.Info.Id} version: {depConfig.Config.Info.Version} has a null dependency or version property!");
                }
                // For each of the config's dependencies, collect all of the restored dependencies for it,
                // if we have no RestoredDependencies that match the ID, VersionRange, and Version already (since those would be the same).
                CollectDependencies(thisId, ref myDependencies, innerD);
                // We can actually take it easy here, we only need to COLLECT our dependencies, we don't need to COLLAPSE them.
            }
            // When we are done, myDependencies should contain a mapping of ALL of our dependencies (recursively) mapped to their SharedConfigs.
        }
 private string PrintRestoredDependency(RestoredDependencyPair pair) => $"{pair.Dependency.Id}: ({pair.Dependency.VersionRange}) --> {pair.Version}";
        private async Task CollectDependencies(string thisId, Dictionary <RestoredDependencyPair, SharedConfig> myDependencies, RestoredDependencyPair pair)
        {
            // pair contains simply a Dependency in most cases, but if it contains a version already, then we map that version to a SharedConfig
            // Null assertions
            if (pair is null || pair.Dependency is null)
            {
                throw new ArgumentNullException(nameof(pair), Resources.DependencyNull);
            }
            var d = pair.Dependency !;

            if (d.Id is null)
            {
                throw new ArgumentException(Resources.DependencyIdNull);
            }
            if (d.VersionRange is null)
            {
                throw new ArgumentException($"Dependency: {d.Id} {nameof(d.VersionRange)} is null!");
            }
            if (thisId.Equals(d.Id, StringComparison.OrdinalIgnoreCase))
            {
                throw new DependencyException($"Recursive dependency! Tried to get dependency: {d.Id}, but {thisId} matches {d.Id}!");
            }
            // We want to convert our uri into a config file
            var depConfig = await dependencyResolver.GetSharedConfig(pair).ConfigureAwait(false);

            if (depConfig is null)
            {
                throw new ConfigException($"Could not find config for: {d.Id}! Range: {d.VersionRange}");
            }
            // Then we want to check to ensure that the config file we have gotten is within our version
            if (depConfig.Config is null)
            {
                throw new ConfigException($"Confid is of an invalid format for: {d.Id} - No config!");
            }
            if (depConfig.Config.Info is null)
            {
                throw new ConfigException($"Config is of an invalid format for: {d.Id} - No info!");
            }
            if (string.IsNullOrEmpty(depConfig.Config.Info.Id))
            {
                throw new ConfigException($"Config is of an invalid format for: {d.Id} - No Id!");
            }
            // Check to make sure the config's version matches our dependency's version
            if (!depConfig.Config.Info.Id.Equals(d.Id, StringComparison.OrdinalIgnoreCase))
            {
                throw new ConfigException($"Dependency and config have different ids! {d.Id} != {depConfig.Config.Info.Id}!");
            }
            if (depConfig.Config.Info.Version is null)
            {
                throw new ConfigException($"Config is of an invalid format for: {d.Id} - No Version!");
            }
            // If it isn't, we fail to match our dependencies, exit out.
            if (!d.VersionRange.IsSatisfied(depConfig.Config.Info.Version))
            {
                throw new DependencyException($"Dependency unmet! Want: {d.VersionRange} got: {depConfig.Config.Info.Version} for: {d.Id}");
            }
            if (pair.Version != null && pair.Version != depConfig.Config.Info.Version)
            {
                throw new ConfigException($"Wanted specific version: {pair.Version} but got: {depConfig.Config.Info.Version} for: {d.Id}");
            }
            var toAdd = new RestoredDependencyPair {
                Dependency = d, Version = depConfig.Config.Info.Version
            };

            // Add to collapsed mapping, if the dep to add/config is not an override name that would be a duplicate
            var match = myDependencies.FirstOrDefault(sc => sc.Value.Config !.Info !.AdditionalData.TryGetValue("overrideSoName", out var val) &&
                                                      depConfig.Config !.Info !.AdditionalData.TryGetValue("overrideSoName", out var rhs) && val.GetString() == rhs.GetString()).Key;

            if (match is not null)
            {
                // If we have a matching overrideSoName, check our config vs. existing config.
                // If our config is higher, use that instead.
                if (depConfig.Config !.Info !.Version > myDependencies[match].Config !.Info !.Version)
                {
                    myDependencies.Remove(match);
                    match.Dependency = d;
                    match.Version    = depConfig.Config !.Info !.Version;
                    myDependencies.Add(match, depConfig);
                }
            }
            else if (!myDependencies.ContainsKey(toAdd))
            {
                // We need to double check here, just to make sure we don't accidentally add when we literally have a potential match:
                if (myDependencies.Keys.FirstOrDefault(item => toAdd.Dependency.Id.Equals(item.Dependency !.Id, StringComparison.OrdinalIgnoreCase) && toAdd.Version == item.Version) is null)
                {
                    // If there is no exactly matching key:
                    // Add our mapping from dependency to config
                    myDependencies.Add(toAdd, depConfig);
                }
            }
            // Otherwise, we iterate over all of the config's RESTORED dependencies
            // That is, all of the dependencies that we used to actually build this
            foreach (var innerD in new List <RestoredDependencyPair>(depConfig.RestoredDependencies))
            {
                if (innerD.Dependency is null || innerD.Version is null)
                {
                    throw new ConfigException($"A restored dependency in config for: {depConfig.Config.Info.Id} version: {depConfig.Config.Info.Version} has a null dependency or version property!");
                }

                // Skip private dependencies from resolving
                if (innerD.Dependency.AdditionalData.TryGetValue("private", out var isPrivate) &&
                    isPrivate.GetBoolean())
                {
                    // Console.WriteLine($"Skipping {innerD.Dependency.Id}");
                    // TODO: Does sc2ad approve of this?
                    depConfig.RestoredDependencies.Remove(innerD);
                    continue;
                }


                // For each of the config's dependencies, collect all of the restored dependencies for it,
                // if we have no RestoredDependencies that match the ID, VersionRange, and Version already (since those would be the same).
                await CollectDependencies(thisId, myDependencies, innerD).ConfigureAwait(false);

                // We can actually take it easy here, we only need to COLLECT our dependencies, we don't need to COLLAPSE them.
            }
            // When we are done, myDependencies should contain a mapping of ALL of our dependencies (recursively) mapped to their SharedConfigs.
        }