Beispiel #1
0
        private async Task ValidateRunnerHash(string archiveFile, string packageHashValue)
        {
            var stopWatch = Stopwatch.StartNew();

            // Validate Hash Matches if it is provided
            using (FileStream stream = File.OpenRead(archiveFile))
            {
                if (!string.IsNullOrEmpty(packageHashValue))
                {
                    using (SHA256 sha256 = SHA256.Create())
                    {
                        byte[] srcHashBytes = await sha256.ComputeHashAsync(stream);

                        var hash = PrimitiveExtensions.ConvertToHexString(srcHashBytes);
                        if (hash != packageHashValue)
                        {
                            // Hash did not match, we can't recover from this, just throw
                            throw new Exception($"Computed runner hash {hash} did not match expected Runner Hash {packageHashValue} for {_targetPackage.Filename}");
                        }

                        stopWatch.Stop();
                        Trace.Info($"Validated Runner Hash matches {_targetPackage.Filename} : {packageHashValue}");
                        _updateTrace.Add($"ValidateHashTime: {stopWatch.ElapsedMilliseconds}ms");
                    }
                }
            }
        }
        public static IQueryable <TEntity> Sort <TEntity>(this IQueryable <TEntity> result, string fields)
        {
            if (string.IsNullOrEmpty(fields))
            {
                return(result);
            }

            var useThenBy = false;

            foreach (var sortTerm in fields.Fields())
            {
                var property = PrimitiveExtensions.GetProperty <TEntity>(sortTerm.FieldName());

                if (property != null)
                {
                    var command = useThenBy ? "ThenBy" : "OrderBy";
                    command += sortTerm.IsDescending() ? "Descending" : string.Empty;

                    result = result.OrderBy(property, command);
                }

                useThenBy = true;
            }

            return(result);
        }
Beispiel #3
0
        public bool IsMatch(ResolutionContext context)
        {
            var isMatch = PrimitiveExtensions.IsEnumerableType(context.SourceType) &&
                          PrimitiveExtensions.IsCollectionType(context.DestinationType);

            return(isMatch);
        }
Beispiel #4
0
        public static IQueryable <TEntity> Paginate <TEntity, TModel>(this
                                                                      IQueryable <TEntity> result,
                                                                      TModel options)
            where TModel : IQueryPaging
        {
            var attr = Attribute.GetCustomAttributes(PrimitiveExtensions.GetProperty <TModel>("Limit")).FirstOrDefault();

            // Check for the AnimalType attribute.
            if (attr?.GetType() == typeof(QueryOperatorAttribute))
            {
                var data = (QueryOperatorAttribute)attr;
                if (data.Max > 0)
                {
                    options.Limit = data.Max;
                }
            }

            if (options.Offset.HasValue)
            {
                result = result.Skip(options.Offset.Value);
            }

            if (options.Limit.HasValue)
            {
                result = result.Take(options.Limit.Value);
            }

            return(result);
        }
Beispiel #5
0
 public override bool IsMatch(ResolutionContext context)
 {
     // destination type must be IEnumerable interface or a class implementing at least IList
     return(PrimitiveExtensions.IsEnumerableType(context.SourceType) &&
            (PrimitiveExtensions.IsListType(context.DestinationType) ||
             DestinationIListTypedAsIEnumerable(context)));
 }
Beispiel #6
0
        public static IQueryable <TEntity> Paginate <TEntity, TModel>(this
                                                                      IQueryable <TEntity> result,
                                                                      TModel options)
            where TModel : class, IQueryPaging
        {
            var attr = Attribute.GetCustomAttribute(PrimitiveExtensions.GetProperty(options.GetType(), "Limit"), typeof(QueryOperatorAttribute));

            if (attr?.GetType() == typeof(QueryOperatorAttribute))
            {
                var data = (QueryOperatorAttribute)attr;
                if (data.Max > 0)
                {
                    options.Limit = data.Max;
                }
            }

            if (options.Offset.HasValue)
            {
                result = result.Skip(options.Offset.Value);
            }

            if (options.Limit.HasValue)
            {
                result = result.Take(options.Limit.Value);
            }

            return(result);
        }
Beispiel #7
0
        public TypeMap ResolveTypeMap(TypePair typePair)
        {
            var typeMap = _typeMapPlanCache.GetOrAdd(typePair,
                                                     _ =>
                                                     GetRelatedTypePairs(_)
                                                     .Select(tp => PrimitiveExtensions.GetOrDefault(_typeMapPlanCache, tp) ?? FindTypeMapFor(tp))
                                                     .FirstOrDefault(tm => tm != null));

            return(typeMap);
        }
        /// <summary>
        /// Adds a node to this database.
        /// </summary>
        /// <param name="node"></param>
        public override void AddNode(Node node)
        {
            // save the node in the current redis key.
            string nodeKey = node.GetRedisKey();

            _nodeTypeClient.SetEntry(nodeKey, PrimitiveExtensions.ConvertTo(node));

            // save the node in the correct osmhash location.
            var idBytes = BitConverter.GetBytes(node.Id.Value);

            _redisClient.SAdd(node.GetOsmHash(), idBytes);
        }
Beispiel #9
0
        public bool IsMatch(ResolutionContext context)
        {
            if (
                !(PrimitiveExtensions.IsEnumerableType(context.SourceType) &&
                  TypeExtensions.IsGenericType(context.DestinationType)))
            {
                return(false);
            }

            var genericType = context.DestinationType.GetGenericTypeDefinition();

            return(genericType == typeof(ReadOnlyCollection <>));
        }
        private static MethodInfo GetImplicitConversionOperator(ResolutionContext context)
        {
            var destinationType = context.DestinationType;

            if (PrimitiveExtensions.IsNullableType(destinationType))
            {
                destinationType = PrimitiveExtensions.GetTypeOfNullable(destinationType);
            }
            var sourceTypeMethod = TypeExtensions.GetDeclaredMethods(context.SourceType)
                                   .FirstOrDefault(
                mi => mi.IsPublic && mi.IsStatic && mi.Name == "op_Implicit" && mi.ReturnType == destinationType);

            return(sourceTypeMethod ?? destinationType.GetMethod("op_Implicit", new[] { context.SourceType }));
        }
Beispiel #11
0
        public static Type GetEnumerationType(Type enumType)
        {
            if (PrimitiveExtensions.IsNullableType(enumType))
            {
                enumType = enumType.GetGenericArguments()[0];
            }

            if (!TypeExtensions.IsEnum(enumType))
            {
                return(null);
            }

            return(enumType);
        }
        /// <summary>
        /// Adds a relation to this database.
        /// </summary>
        /// <param name="relation"></param>
        public override void AddRelation(Relation relation)
        {
            // save the relation in the current redis key.
            string relationKey = relation.GetRedisKey();

            _relationTypeClient.SetEntry(relationKey, PrimitiveExtensions.ConvertTo(relation));

            // save the relation-member relation.
            if (relation.Members != null)
            {
                foreach (var member in relation.Members)
                {
                    _redisClient.AddItemToSet(PrimitiveExtensions.BuildMemberRelationListRedisKey(member),
                                              relation.Id.Value.ToString());
                }
            }
        }
Beispiel #13
0
        private static MemberInfo[] BuildPublicAccessors(IEnumerable <MemberInfo> allMembers)
        {
            // Multiple types may define the same property (e.g. the class and multiple interfaces) - filter this to one of those properties
            var filteredMembers = allMembers
                                  .OfType <PropertyInfo>()
                                  .GroupBy(x => x.Name) // group properties of the same name together
                                  .Select(x =>
                                          x.Any(y => y.CanWrite && y.CanRead)
                        ? // favor the first property that can both read & write - otherwise pick the first one
                                          x.First(y => y.CanWrite && y.CanRead)
                        : x.First())
                                  .Where(pi => pi.CanWrite || PrimitiveExtensions.IsListOrDictionaryType(pi.PropertyType))
                                  .OfType <MemberInfo>()                          // cast back to MemberInfo so we can add back FieldInfo objects
                                  .Concat(allMembers.Where(x => x is FieldInfo)); // add FieldInfo objects back

            return(filteredMembers.ToArray());
        }
Beispiel #14
0
        bool IMappingEngineRunner.ShouldMapSourceValueAsNull(ResolutionContext context)
        {
            if (TypeExtensions.IsValueType(context.DestinationType) &&
                !PrimitiveExtensions.IsNullableType(context.DestinationType))
            {
                return(false);
            }

            var typeMap = context.GetContextTypeMap();

            if (typeMap != null)
            {
                return(ConfigurationProvider.GetProfileConfiguration(typeMap.Profile).AllowNullDestinationValues);
            }

            return(ConfigurationProvider.AllowNullDestinationValues);
        }
        /// <summary>
        /// Adds a way to this database.
        /// </summary>
        /// <param name="way"></param>
        public override void AddWay(Way way)
        {
            // save the way in the current redis key.
            string wayKey = way.GetRedisKey();

            _wayTypeClient.SetEntry(wayKey, PrimitiveExtensions.ConvertTo(way));

            // save the way-node relation.
            if (way.Nodes != null)
            {
                foreach (long nodeId in way.Nodes)
                {
                    _redisClient.AddItemToSet(PrimitiveExtensions.BuildNodeWayListRedisKey(nodeId),
                                              way.Id.Value.ToString());
                }
            }
        }
Beispiel #16
0
        /// <summary>
        /// Returns true if the given object exists.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="type"></param>
        /// <returns></returns>
        private bool Exist(long id, OsmGeoType type)
        {
            switch (type)
            {
            case OsmGeoType.Node:
                string nodeKey = PrimitiveExtensions.BuildNodeRedisKey(id);
                return(_clientNode.ContainsKey(nodeKey));

            case OsmGeoType.Way:
                string wayKey = PrimitiveExtensions.BuildWayRedisKey(id);
                return(_clientWay.ContainsKey(wayKey));

            case OsmGeoType.Relation:
                string relationKey = PrimitiveExtensions.BuildRelationRedisKey(id);
                return(_clientRelation.ContainsKey(relationKey));
            }
            throw new ArgumentOutOfRangeException("type");
        }
Beispiel #17
0
        public object Map(ResolutionContext context, IMappingEngineRunner mapper)
        {
            if (context.IsSourceValueNull && mapper.ShouldMapSourceCollectionAsNull(context))
            {
                return(null);
            }
            var genericSourceDictType = PrimitiveExtensions.GetDictionaryType(context.SourceType);
            var sourceKeyType         = genericSourceDictType.GetGenericArguments()[0];
            var sourceValueType       = genericSourceDictType.GetGenericArguments()[1];
            var sourceKvpType         = KvpType.MakeGenericType(sourceKeyType, sourceValueType);
            var genericDestDictType   = PrimitiveExtensions.GetDictionaryType(context.DestinationType);
            var destKeyType           = genericDestDictType.GetGenericArguments()[0];
            var destValueType         = genericDestDictType.GetGenericArguments()[1];

            var kvpEnumerator  = GetKeyValuePairEnumerator(context, sourceKvpType);
            var destDictionary = ObjectCreator.CreateDictionary(context.DestinationType, destKeyType, destValueType);
            var count          = 0;

            while (kvpEnumerator.MoveNext())
            {
                var keyValuePair = kvpEnumerator.Current;
                var sourceKey    = sourceKvpType.GetProperty("Key").GetValue(keyValuePair, new object[0]);
                var sourceValue  = sourceKvpType.GetProperty("Value").GetValue(keyValuePair, new object[0]);

                var keyTypeMap = mapper.ConfigurationProvider.ResolveTypeMap(sourceKey, null, sourceKeyType,
                                                                             destKeyType);
                var valueTypeMap = mapper.ConfigurationProvider.ResolveTypeMap(sourceValue, null, sourceValueType,
                                                                               destValueType);

                var keyContext = context.CreateElementContext(keyTypeMap, sourceKey, sourceKeyType,
                                                              destKeyType, count);
                var valueContext = context.CreateElementContext(valueTypeMap, sourceValue, sourceValueType,
                                                                destValueType, count);

                var destKey   = mapper.Map(keyContext);
                var destValue = mapper.Map(valueContext);

                genericDestDictType.GetMethod("Add").Invoke(destDictionary, new[] { destKey, destValue });

                count++;
            }

            return(destDictionary);
        }
Beispiel #18
0
        public object Map(ResolutionContext context, IMappingEngineRunner mapper)
        {
            var sourceEnumerableValue = (IEnumerable)context.SourceValue ?? new object[0];
            var enumerableValue       = sourceEnumerableValue.Cast <object>();

            var sourceElementType   = TypeHelper.GetElementType(context.SourceType, sourceEnumerableValue);
            var genericDestDictType = PrimitiveExtensions.GetDictionaryType(context.DestinationType);
            var destKeyType         = genericDestDictType.GetGenericArguments()[0];
            var destValueType       = genericDestDictType.GetGenericArguments()[1];
            var destKvpType         = KvpType.MakeGenericType(destKeyType, destValueType);

            var destDictionary = ObjectCreator.CreateDictionary(context.DestinationType, destKeyType, destValueType);
            var count          = 0;

            foreach (var item in enumerableValue)
            {
                var typeMap = mapper.ConfigurationProvider.ResolveTypeMap(item, null, sourceElementType, destKvpType);

                var targetSourceType      = typeMap != null ? typeMap.SourceType : sourceElementType;
                var targetDestinationType = typeMap != null ? typeMap.DestinationType : destKvpType;

                var newContext = context.CreateElementContext(typeMap, item, targetSourceType, targetDestinationType,
                                                              count);

                var mappedValue = mapper.Map(newContext);
                var keyProperty = mappedValue.GetType().GetProperty("Key");
                var destKey     = keyProperty.GetValue(mappedValue, null);

                var valueProperty = mappedValue.GetType().GetProperty("Value");
                var destValue     = valueProperty.GetValue(mappedValue, null);

                genericDestDictType.GetMethod("Add").Invoke(destDictionary, new[] { destKey, destValue });

                count++;
            }

            return(destDictionary);
        }
Beispiel #19
0
        /// <summary>
        /// Stores an osmGeo object to disk.
        /// </summary>
        /// <param name="osmGeo"></param>
        private void Store(OsmGeo osmGeo)
        {
            switch (osmGeo.Type)
            {
            case OsmGeoType.Node:
                Node   node    = osmGeo as Node;
                string nodeKey = node.GetRedisKey();
                _clientNode.SetEntry(nodeKey, PrimitiveExtensions.ConvertTo(node));
                break;

            case OsmGeoType.Way:
                Way    way    = osmGeo as Way;
                string wayKey = way.GetRedisKey();
                _clientWay.SetEntry(wayKey, PrimitiveExtensions.ConvertTo(way));
                break;

            case OsmGeoType.Relation:
                Relation relation    = osmGeo as Relation;
                string   relationKey = relation.GetRedisKey();
                _clientRelation.SetEntry(relationKey, PrimitiveExtensions.ConvertTo(relation));
                break;
            }
        }
Beispiel #20
0
        /// <summary>
        /// Deletes an osmGeo object from disk.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="type"></param>
        private void Delete(long id, OsmGeoType type)
        {
            switch (type)
            {
            case OsmGeoType.Node:
                string nodeKey = PrimitiveExtensions.BuildNodeRedisKey(id);
                _client.Del(nodeKey);
                //_clientNode.DeleteById(nodeKey);
                break;

            case OsmGeoType.Way:
                string wayKey = PrimitiveExtensions.BuildWayRedisKey(id);
                //_clientWay.DeleteById(wayKey);
                _client.Del(wayKey);
                break;

            case OsmGeoType.Relation:
                string relationKey = PrimitiveExtensions.BuildRelationRedisKey(id);
                //_clientRelation.DeleteById(relationKey);
                _client.Del(relationKey);
                break;
            }
        }
Beispiel #21
0
        /// <summary>
        /// Reads an osmGeo object from disk.
        /// </summary>
        /// <param name="id"></param>
        /// <param name="type"></param>
        private OsmGeo Read(long id, OsmGeoType type)
        {
            switch (type)
            {
            case OsmGeoType.Node:
                string    nodeKey   = PrimitiveExtensions.BuildNodeRedisKey(id);
                RedisNode redisNode = _clientNode.GetValue(nodeKey);
                Node      node      = null;
                if (redisNode != null)
                {
                    node = PrimitiveExtensions.ConvertFrom(redisNode);
                }
                return(node);

            case OsmGeoType.Way:
                string   wayKey   = PrimitiveExtensions.BuildWayRedisKey(id);
                RedisWay redisWay = _clientWay.GetValue(wayKey);
                Way      way      = null;
                if (redisWay != null)
                {
                    way = PrimitiveExtensions.ConvertFrom(redisWay);
                }
                return(way);

            case OsmGeoType.Relation:
                string        relationKey   = PrimitiveExtensions.BuildRelationRedisKey(id);
                RedisRelation redisRelation = _clientRelation.GetValue(relationKey);
                Relation      relation      = null;
                if (redisRelation != null)
                {
                    relation = PrimitiveExtensions.ConvertFrom(redisRelation);
                }
                return(relation);
            }
            throw new ArgumentOutOfRangeException("type");
        }
Beispiel #22
0
        public object Map(ResolutionContext context, IMappingEngineRunner mapper)
        {
            var toEnum              = false;
            var enumSourceType      = TypeHelper.GetEnumerationType(context.SourceType);
            var enumDestinationType = TypeHelper.GetEnumerationType(context.DestinationType);

            if (EnumToStringMapping(context, ref toEnum))
            {
                if (context.SourceValue == null)
                {
                    return(mapper.CreateObject(context));
                }

                if (toEnum)
                {
                    var stringValue = context.SourceValue.ToString();
                    if (string.IsNullOrEmpty(stringValue))
                    {
                        return(mapper.CreateObject(context));
                    }

                    return(Enum.Parse(enumDestinationType, stringValue, true));
                }
                return(Enum.GetName(enumSourceType, context.SourceValue));
            }
            if (EnumToEnumMapping(context))
            {
                if (context.SourceValue == null)
                {
                    if (mapper.ShouldMapSourceValueAsNull(context) &&
                        PrimitiveExtensions.IsNullableType(context.DestinationType))
                    {
                        return(null);
                    }

                    return(mapper.CreateObject(context));
                }

                if (!Enum.IsDefined(enumSourceType, context.SourceValue))
                {
                    return(Enum.ToObject(enumDestinationType, context.SourceValue));
                }

                if (FeatureDetector.IsEnumGetNamesSupported)
                {
                    var enumValueMapper = EnumNameValueMapperFactory.Create();

                    if (enumValueMapper.IsMatch(enumDestinationType, context.SourceValue.ToString()))
                    {
                        return(enumValueMapper.Convert(enumSourceType, enumDestinationType, context));
                    }
                }

                return(Enum.Parse(enumDestinationType, Enum.GetName(enumSourceType, context.SourceValue), true));
            }
            if (EnumToUnderlyingTypeMapping(context, ref toEnum))
            {
                if (toEnum && context.SourceValue != null)
                {
                    return(Enum.Parse(enumDestinationType, context.SourceValue.ToString(), true));
                }

                if (EnumToNullableTypeMapping(context))
                {
                    return(ConvertEnumToNullableType(context));
                }

                return(Convert.ChangeType(context.SourceValue, context.DestinationType, null));
            }
            return(null);
        }
Beispiel #23
0
 public override bool IsMatch(ResolutionContext context)
 {
     return((context.DestinationType.IsArray) && (PrimitiveExtensions.IsEnumerableType(context.SourceType)));
 }
Beispiel #24
0
 private static bool DestinationIListTypedAsIEnumerable(ResolutionContext context)
 {
     return(TypeExtensions.IsInterface(context.DestinationType) &&
            PrimitiveExtensions.IsEnumerableType(context.DestinationType) &&
            (context.DestinationValue == null || context.DestinationValue is IList));
 }
Beispiel #25
0
        private void DryRunTypeMap(ICollection <TypeMap> typeMapsChecked, ResolutionContext context)
        {
            if (context.TypeMap != null)
            {
                typeMapsChecked.Add(context.TypeMap);
            }

            var mapperToUse = GetMappers().FirstOrDefault(mapper => mapper.IsMatch(context));

            if (mapperToUse == null && PrimitiveExtensions.IsNullableType(context.SourceType))
            {
                var nullableContext = context.CreateValueContext(null, Nullable.GetUnderlyingType(context.SourceType));

                mapperToUse = GetMappers().FirstOrDefault(mapper => mapper.IsMatch(nullableContext));
            }

            if (mapperToUse == null)
            {
                throw new AutoMapperConfigurationException(context);
            }

            if (mapperToUse is TypeMapMapper)
            {
                foreach (var propertyMap in context.TypeMap.GetPropertyMaps())
                {
                    if (!propertyMap.IsIgnored())
                    {
                        var lastResolver =
                            propertyMap.GetSourceValueResolvers().OfType <IMemberResolver>().LastOrDefault();

                        if (lastResolver != null)
                        {
                            var sourceType      = lastResolver.MemberType;
                            var destinationType = propertyMap.DestinationProperty.MemberType;
                            var memberTypeMap   = ((IConfigurationProvider)this).ResolveTypeMap(sourceType,
                                                                                                destinationType);

                            if (typeMapsChecked.Any(typeMap => Equals(typeMap, memberTypeMap)))
                            {
                                continue;
                            }

                            var memberContext = context.CreateMemberContext(memberTypeMap, null, null, sourceType,
                                                                            propertyMap);

                            DryRunTypeMap(typeMapsChecked, memberContext);
                        }
                    }
                }
            }
            else if (mapperToUse is ArrayMapper || mapperToUse is EnumerableMapper || mapperToUse is CollectionMapper)
            {
                var sourceElementType = TypeHelper.GetElementType(context.SourceType);
                var destElementType   = TypeHelper.GetElementType(context.DestinationType);
                var itemTypeMap       = ((IConfigurationProvider)this).ResolveTypeMap(sourceElementType, destElementType);

                if (typeMapsChecked.Any(typeMap => Equals(typeMap, itemTypeMap)))
                {
                    return;
                }

                var memberContext = context.CreateElementContext(itemTypeMap, null, sourceElementType, destElementType,
                                                                 0);

                DryRunTypeMap(typeMapsChecked, memberContext);
            }
        }
Beispiel #26
0
 private static bool BothAreNonNullable(Expression node, Expression newLeft)
 {
     return(!PrimitiveExtensions.IsNullableType(node.Type) &&
            !PrimitiveExtensions.IsNullableType(newLeft.Type));
 }
 public bool IsMatch(PropertyMap propertyMap, TypeMap propertyTypeMap, ExpressionResolutionResult result)
 {
     return(PrimitiveExtensions.IsNullableType(propertyMap.DestinationPropertyType) &&
            !PrimitiveExtensions.IsNullableType(result.Type));
 }
Beispiel #28
0
 public bool IsMatch(ResolutionContext context)
 {
     return(PrimitiveExtensions.IsDictionaryType(context.SourceType) &&
            PrimitiveExtensions.IsDictionaryType(context.DestinationType));
 }
Beispiel #29
0
        /// <summary>
        /// _work
        ///     \_update
        ///            \bin
        ///            \externals
        ///            \run.sh
        ///            \run.cmd
        ///            \package.zip //temp download .zip/.tar.gz
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        private async Task DownloadLatestRunner(CancellationToken token)
        {
            string latestRunnerDirectory = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Work), Constants.Path.UpdateDirectory);

            IOUtil.DeleteDirectory(latestRunnerDirectory, token);
            Directory.CreateDirectory(latestRunnerDirectory);

            int    runnerSuffix      = 1;
            string archiveFile       = null;
            bool   downloadSucceeded = false;

            try
            {
                // Download the runner, using multiple attempts in order to be resilient against any networking/CDN issues
                for (int attempt = 1; attempt <= Constants.RunnerDownloadRetryMaxAttempts; attempt++)
                {
                    // Generate an available package name, and do our best effort to clean up stale local zip files
                    while (true)
                    {
                        if (_targetPackage.Platform.StartsWith("win"))
                        {
                            archiveFile = Path.Combine(latestRunnerDirectory, $"runner{runnerSuffix}.zip");
                        }
                        else
                        {
                            archiveFile = Path.Combine(latestRunnerDirectory, $"runner{runnerSuffix}.tar.gz");
                        }

                        try
                        {
                            // delete .zip file
                            if (!string.IsNullOrEmpty(archiveFile) && File.Exists(archiveFile))
                            {
                                Trace.Verbose("Deleting latest runner package zip '{0}'", archiveFile);
                                IOUtil.DeleteFile(archiveFile);
                            }

                            break;
                        }
                        catch (Exception ex)
                        {
                            // couldn't delete the file for whatever reason, so generate another name
                            Trace.Warning("Failed to delete runner package zip '{0}'. Exception: {1}", archiveFile, ex);
                            runnerSuffix++;
                        }
                    }

                    // Allow a 15-minute package download timeout, which is good enough to update the runner from a 1 Mbit/s ADSL connection.
                    if (!int.TryParse(Environment.GetEnvironmentVariable("GITHUB_ACTIONS_RUNNER_DOWNLOAD_TIMEOUT") ?? string.Empty, out int timeoutSeconds))
                    {
                        timeoutSeconds = 15 * 60;
                    }

                    Trace.Info($"Attempt {attempt}: save latest runner into {archiveFile}.");

                    using (var downloadTimeout = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds)))
                        using (var downloadCts = CancellationTokenSource.CreateLinkedTokenSource(downloadTimeout.Token, token))
                        {
                            try
                            {
                                Trace.Info($"Download runner: begin download");

                                //open zip stream in async mode
                                using (HttpClient httpClient = new HttpClient(HostContext.CreateHttpClientHandler()))
                                {
                                    if (!string.IsNullOrEmpty(_targetPackage.Token))
                                    {
                                        Trace.Info($"Adding authorization token ({_targetPackage.Token.Length} chars)");
                                        httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", _targetPackage.Token);
                                    }

                                    Trace.Info($"Downloading {_targetPackage.DownloadUrl}");

                                    using (FileStream fs = new FileStream(archiveFile, FileMode.Create, FileAccess.Write, FileShare.None, bufferSize: 4096, useAsync: true))
                                        using (Stream result = await httpClient.GetStreamAsync(_targetPackage.DownloadUrl))
                                        {
                                            //81920 is the default used by System.IO.Stream.CopyTo and is under the large object heap threshold (85k).
                                            await result.CopyToAsync(fs, 81920, downloadCts.Token);

                                            await fs.FlushAsync(downloadCts.Token);
                                        }
                                }

                                Trace.Info($"Download runner: finished download");
                                downloadSucceeded = true;
                                break;
                            }
                            catch (OperationCanceledException) when(token.IsCancellationRequested)
                            {
                                Trace.Info($"Runner download has been canceled.");
                                throw;
                            }
                            catch (Exception ex)
                            {
                                if (downloadCts.Token.IsCancellationRequested)
                                {
                                    Trace.Warning($"Runner download has timed out after {timeoutSeconds} seconds");
                                }

                                Trace.Warning($"Failed to get package '{archiveFile}' from '{_targetPackage.DownloadUrl}'. Exception {ex}");
                            }
                        }
                }

                if (!downloadSucceeded)
                {
                    throw new TaskCanceledException($"Runner package '{archiveFile}' failed after {Constants.RunnerDownloadRetryMaxAttempts} download attempts");
                }

                // If we got this far, we know that we've successfully downloaded the runner package
                // Validate Hash Matches if it is provided
                using (FileStream stream = File.OpenRead(archiveFile))
                {
                    if (!String.IsNullOrEmpty(_targetPackage.HashValue))
                    {
                        using (SHA256 sha256 = SHA256.Create())
                        {
                            byte[] srcHashBytes = await sha256.ComputeHashAsync(stream);

                            var hash = PrimitiveExtensions.ConvertToHexString(srcHashBytes);
                            if (hash != _targetPackage.HashValue)
                            {
                                // Hash did not match, we can't recover from this, just throw
                                throw new Exception($"Computed runner hash {hash} did not match expected Runner Hash {_targetPackage.HashValue} for {_targetPackage.Filename}");
                            }
                            Trace.Info($"Validated Runner Hash matches {_targetPackage.Filename} : {_targetPackage.HashValue}");
                        }
                    }
                }
                if (archiveFile.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
                {
                    ZipFile.ExtractToDirectory(archiveFile, latestRunnerDirectory);
                }
                else if (archiveFile.EndsWith(".tar.gz", StringComparison.OrdinalIgnoreCase))
                {
                    string tar = WhichUtil.Which("tar", trace: Trace);

                    if (string.IsNullOrEmpty(tar))
                    {
                        throw new NotSupportedException($"tar -xzf");
                    }

                    // tar -xzf
                    using (var processInvoker = HostContext.CreateService <IProcessInvoker>())
                    {
                        processInvoker.OutputDataReceived += new EventHandler <ProcessDataReceivedEventArgs>((sender, args) =>
                        {
                            if (!string.IsNullOrEmpty(args.Data))
                            {
                                Trace.Info(args.Data);
                            }
                        });

                        processInvoker.ErrorDataReceived += new EventHandler <ProcessDataReceivedEventArgs>((sender, args) =>
                        {
                            if (!string.IsNullOrEmpty(args.Data))
                            {
                                Trace.Error(args.Data);
                            }
                        });

                        int exitCode = await processInvoker.ExecuteAsync(latestRunnerDirectory, tar, $"-xzf \"{archiveFile}\"", null, token);

                        if (exitCode != 0)
                        {
                            throw new NotSupportedException($"Can't use 'tar -xzf' extract archive file: {archiveFile}. return code: {exitCode}.");
                        }
                    }
                }
                else
                {
                    throw new NotSupportedException($"{archiveFile}");
                }

                Trace.Info($"Finished getting latest runner package at: {latestRunnerDirectory}.");
            }
            finally
            {
                try
                {
                    // delete .zip file
                    if (!string.IsNullOrEmpty(archiveFile) && File.Exists(archiveFile))
                    {
                        Trace.Verbose("Deleting latest runner package zip: {0}", archiveFile);
                        IOUtil.DeleteFile(archiveFile);
                    }
                }
                catch (Exception ex)
                {
                    //it is not critical if we fail to delete the .zip file
                    Trace.Warning("Failed to delete runner package zip '{0}'. Exception: {1}", archiveFile, ex);
                }
            }

            // copy latest runner into runner root folder
            // copy bin from _work/_update -> bin.version under root
            string binVersionDir = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), $"{Constants.Path.BinDirectory}.{_targetPackage.Version}");

            Directory.CreateDirectory(binVersionDir);
            Trace.Info($"Copy {Path.Combine(latestRunnerDirectory, Constants.Path.BinDirectory)} to {binVersionDir}.");
            IOUtil.CopyDirectory(Path.Combine(latestRunnerDirectory, Constants.Path.BinDirectory), binVersionDir, token);

            // copy externals from _work/_update -> externals.version under root
            string externalsVersionDir = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), $"{Constants.Path.ExternalsDirectory}.{_targetPackage.Version}");

            Directory.CreateDirectory(externalsVersionDir);
            Trace.Info($"Copy {Path.Combine(latestRunnerDirectory, Constants.Path.ExternalsDirectory)} to {externalsVersionDir}.");
            IOUtil.CopyDirectory(Path.Combine(latestRunnerDirectory, Constants.Path.ExternalsDirectory), externalsVersionDir, token);

            // copy and replace all .sh/.cmd files
            Trace.Info($"Copy any remaining .sh/.cmd files into runner root.");
            foreach (FileInfo file in new DirectoryInfo(latestRunnerDirectory).GetFiles() ?? new FileInfo[0])
            {
                string destination = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.Root), file.Name);

                // Removing the file instead of just trying to overwrite it works around permissions issues on linux.
                // https://github.com/actions/runner/issues/981
                Trace.Info($"Copy {file.FullName} to {destination}");
                IOUtil.DeleteFile(destination);
                file.CopyTo(destination, true);
            }
        }
Beispiel #30
0
 public bool IsMatch(ResolutionContext context)
 {
     return(PrimitiveExtensions.IsNullableType(context.DestinationType));
 }