Exemple #1
0
        public override IWorkspace Open(LocalConn conn)
        {
            IWorkspace workspace = null;

            switch (conn.Type)
            {
            case Base.Common.EnumDataSourceType.SHAPEFILE:
                workspace = WorkspaceUtil.OpenShapeFileWorkspace(conn.Path);
                break;

            case Base.Common.EnumDataSourceType.COVERAGE:
                workspace = WorkspaceUtil.OpenCoverageWorkspace(conn.Path);
                break;

            case Base.Common.EnumDataSourceType.PERSONAL_GEODATABASE:
                workspace = WorkspaceUtil.OpenMdbWorspace(conn.Path);
                break;

            case Base.Common.EnumDataSourceType.FILE_GEODATABASE:
                workspace = WorkspaceUtil.OpenFileGdbWorkspace(conn.Path);
                break;

            case Base.Common.EnumDataSourceType.TIN:
                workspace = WorkspaceUtil.OpenTinWorkspace(conn.Path);
                break;

            case Base.Common.EnumDataSourceType.CAD:
                workspace = WorkspaceUtil.OpenCadWorkspace(conn.Path);
                break;

            default:
                throw new Exception($"不支持当前本地文件格式[{conn.Path}]");
            }
            return(workspace);
        }
        /// <summary>
        /// 获取topo下的geometry union的数据
        /// </summary>
        /// <param name="featureClass">源要素类</param>
        /// <param name="queryClause">查询条件</param>
        /// <param name="queryGeometry">指定范围下</param>
        /// <param name="spatialRelType">空间参考类型</param>
        /// <param name="topoUnionGeometry">输出topo union后的geometry</param>
        /// <param name="oidList">输出OID集合</param>
        /// <param name="geometryField">geometry字段名称,默认为Shape</param>
        public static void GetTopounionGeometryByQuery(IFeatureClass featureClass, String queryClause,
                                                       IGeometry queryGeometry, esriSpatialRelEnum spatialRelType,
                                                       out IGeometry topoUnionGeometry, out IList <string> oidList, string geometryField = "Shape")
        {
            List <IFeature> featureList = new List <IFeature>();

            topoUnionGeometry = null;
            oidList           = new List <string>();
            try
            {
                ISpatialFilter spatialFilter = new SpatialFilter();
                if (!string.IsNullOrEmpty(queryClause))
                {
                    spatialFilter.WhereClause = queryClause;
                }
                if (!string.IsNullOrEmpty(geometryField))
                {
                    spatialFilter.GeometryField = geometryField;
                }
                if (queryGeometry != null)
                {
                    spatialFilter.Geometry   = queryGeometry;
                    spatialFilter.SpatialRel = spatialRelType;
                }
                ITopologicalOperator topologicalOperator = null;
                IFeatureCursor       featureCursor       = featureClass.Search(spatialFilter, false);
                IFeature             feature             = featureCursor.NextFeature();
                IGeometry            geometryTemp;

                while (feature != null)
                {
                    geometryTemp = feature.Shape; // feature.ShapeCopy;
                    if (topologicalOperator == null)
                    {
                        topologicalOperator = geometryTemp as ITopologicalOperator;
                    }
                    else
                    {
                        topologicalOperator = topologicalOperator.Union(geometryTemp) as ITopologicalOperator;
                    }
                    oidList.Add(feature.OID.ToString());

                    featureList.Add(feature);
                    feature = featureCursor.NextFeature();
                }

                topoUnionGeometry = topologicalOperator as IGeometry;
                WorkspaceUtil.ReleaseComObject(featureCursor);
            }
            catch (Exception e)
            {
                LOG.Error(e, $"{nameof(GetTopounionGeometryByQuery)}抛异常");
            }
        }
Exemple #3
0
        public override void Init(IDictionary <string, Property> parameters)
        {
            if (!parameters.ContainsKey(nameof(this.FeatureClass_Source_First)))
            {
                throw new Exception("没有找到输入参数【总规用地图层】");
            }
            if (!parameters.ContainsKey(nameof(this.Yddm_First)))
            {
                throw new Exception("没有找到输入参数【总规用地代码属性】");
            }
            if (!parameters.ContainsKey(nameof(this.FeatureClass_Source_Second)))
            {
                throw new Exception("没有找到输入参数【控规用地图层】");
            }
            if (!parameters.ContainsKey(nameof(this.Yddm_Second)))
            {
                throw new Exception("没有找到输入参数【控规用地代码属性】");
            }
            if (!parameters.ContainsKey(nameof(this.ResultGDBPath)))
            {
                LOG.Info("没有指定新的输出路径,现在使用默认路径");
                this.ResultGDBPath = base.OutputParametersMeta[nameof(this.ResultGDBPath)].DefaultValue.ToString();
            }
            else
            {
                LOG.Info("使用新的输出路径");
                this.ResultGDBPath = parameters[nameof(this.ResultGDBPath)].ToString();
            }

            this.FeatureClass_Source_First = parameters[nameof(this.FeatureClass_Source_First)].ToString();
            WorkspaceUtil.OpenFeatureClass(this.FeatureClass_Source_First, SEPARATOR_FEATURE_PATH, out this.m_localWorkspace_first, out this.m_featureClass_first);
            if (this.m_featureClass_first.FeatureDataset != null)
            {
                // 注意有要素集情况下的路径格式
                this.sourceLayerFirstFullPath = this.FeatureClass_Source_First.Split(SEPARATOR_FEATURE_PATH)[0] + "/" + this.m_featureClass_first.FeatureDataset.Name + "/" + this.FeatureClass_Source_First.Split(SEPARATOR_FEATURE_PATH)[1];
            }
            else
            {
                this.sourceLayerFirstFullPath = this.FeatureClass_Source_First.Split(SEPARATOR_FEATURE_PATH)[0] + "/" + this.FeatureClass_Source_First.Split(SEPARATOR_FEATURE_PATH)[1];
            }
            this.FeatureClass_Source_Second = parameters[nameof(this.FeatureClass_Source_Second)].ToString();
            WorkspaceUtil.OpenFeatureClass(this.FeatureClass_Source_Second, SEPARATOR_FEATURE_PATH, out this.m_localWorkspace_second, out this.m_featureClass_second);
            if (this.m_featureClass_second.FeatureDataset != null)
            {
                this.sourceLayerSecondFullPath = this.FeatureClass_Source_Second.Split(SEPARATOR_FEATURE_PATH)[0] + "/" + this.m_featureClass_second.FeatureDataset.Name + "/" + this.FeatureClass_Source_Second.Split(SEPARATOR_FEATURE_PATH)[1];
            }
            else
            {
                this.sourceLayerSecondFullPath = this.FeatureClass_Source_Second.Split(SEPARATOR_FEATURE_PATH)[0] + "/" + this.FeatureClass_Source_Second.Split(SEPARATOR_FEATURE_PATH)[1];
            }

            this.Yddm_First  = parameters[nameof(this.Yddm_First)].ToString();
            this.Yddm_Second = parameters[nameof(this.Yddm_Second)].ToString();
        }
Exemple #4
0
        public override Result Execute()
        {
            string resultGDBPath = this.ResultGDBPath;

            try
            {
                if (!Directory.Exists(this.ResultGDBPath))
                {
                    DirectoryInfo dirInfo = Directory.CreateDirectory(this.ResultGDBPath);
                }
                resultGDBPath = Path.Combine(this.ResultGDBPath, string.Format("result_{0}.gdb", DateUtil.CurrentTimeMillis));
                string pTempletMDBFile  = AppDomain.CurrentDomain.BaseDirectory + GlobalSystemConfig.PATH_TEMPLATE_FGDB;// "template/fgdb.gdb";
                long   beginMillisecond = DateUtil.CurrentTimeMillis;
                // 创建一份gdb
                DirectFileUtil.CopyDirectInfo(pTempletMDBFile, resultGDBPath);
                IWorkspace resultWorkspace = WorkspaceUtil.OpenFileGdbWorkspace(resultGDBPath);
                LOG.Info("创建GDB消耗时间:[" + (DateUtil.CurrentTimeMillis - beginMillisecond) + "] 毫秒");
                // 拷贝源对比图层
                beginMillisecond = DateUtil.CurrentTimeMillis;
                //if (!WorkspaceServices.CopyLayer(new string[] { this.sourceLayerFirstFullPath, this.sourceLayerSecondFullPath }, resultGDBPath))
                //{
                //    LOG.Error("拷贝图层失败,中止计算");
                //    return new Result(STATUS.ERROR, "拷贝图层失败", SysStatusCode.DME3000, false);
                //}
                //LOG.Info("拷贝源对比图层消耗时间:[" + (DateUtil.CurrentTimeMillis() - beginMillisecond) + "] 毫秒");
                // 图层融合(union)
                UnionTool unionTool = new UnionTool
                {
                    InputFeatures = new String[] { this.sourceLayerFirstFullPath, this.sourceLayerSecondFullPath },
                    OutputFeature = resultGDBPath + "/" + this.ReulstLayerName
                };
                object result = unionTool.Excute();
                if (null == result)
                {
                    return(new Result(EnumSystemStatusCode.DME_ERROR, "图层联合分析失败", EnumSystemStatusCode.DME_ERROR, false));
                }
                // 对输出图层进行规则计算
                // TODO
                return(new Result(EnumSystemStatusCode.DME_SUCCESS, "差异分析完成", EnumSystemStatusCode.DME_SUCCESS, true));
            } catch (Exception ex)
            {
                LOG.Error("差异分析失败,详情:" + ex.Message);
                return(new Result(EnumSystemStatusCode.DME_ERROR, "差异分析失败,详情:" + ex.Message, EnumSystemStatusCode.DME_ERROR, false));
            }
        }
        /// <summary>
        /// 两个要素类进行擦除操作
        /// </summary>
        /// <param name="sourceFeatureClass">源要素类</param>
        /// <param name="eraseFeatureClass">用于擦除的要素类,必须是个面要素类</param>
        public static void Erase(IFeatureClass sourceFeatureClass, IFeatureClass eraseFeatureClass)
        {
            if (eraseFeatureClass.ShapeType != esriGeometryType.esriGeometryPolygon)
            {
                throw new Exception("EraseFeatureClass不是个面要素类");
            }
            if (esriGeometryType.esriGeometryPoint == sourceFeatureClass.ShapeType)
            {
                throw new Exception("SourceFeatureClass不能是个点要素类");
            }
            // 先要临时复制一个要素类

            // 遍历用于擦除的要素
            IFeatureCursor eraseFeatureCursor = eraseFeatureClass.Search(null, false);
            IFeature       eraseFeature       = null;

            while ((eraseFeature = eraseFeatureCursor.NextFeature()) != null)
            {
                ISpatialFilter spatialFilter = new SpatialFilterClass
                {
                    Geometry   = eraseFeature.Shape,
                    SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects
                };
                IFeatureCursor sourceFeatureCursor = sourceFeatureClass.Update(spatialFilter, false);
                IFeature       sourceFeature       = null;
                while ((sourceFeature = sourceFeatureCursor.NextFeature()) != null)
                {
                    IGeometry            geometry      = sourceFeature.ShapeCopy;
                    ITopologicalOperator topoOper      = geometry as ITopologicalOperator;
                    IGeometry            geoDifference = topoOper.Difference(eraseFeature.Shape);
                    sourceFeature.Shape = geoDifference;
                    sourceFeatureCursor.UpdateFeature(sourceFeature);
                }
                // 释放游标
                WorkspaceUtil.ReleaseComObject(sourceFeatureCursor);
            }
        }
Exemple #6
0
        public async Task GetSourceAsync(
            IExecutionContext executionContext,
            ServiceEndpoint endpoint,
            CancellationToken cancellationToken)
        {
            Trace.Entering();
            // Validate args.
            ArgUtil.NotNull(executionContext, nameof(executionContext));
            ArgUtil.NotNull(endpoint, nameof(endpoint));

#if OS_WINDOWS
            // Validate .NET Framework 4.6 or higher is installed.
            var netFrameworkUtil = HostContext.GetService <INetFrameworkUtil>();
            if (!netFrameworkUtil.Test(new Version(4, 6)))
            {
                throw new Exception(StringUtil.Loc("MinimumNetFramework46"));
            }
#endif

            // Create the tf command manager.
            var tf = HostContext.CreateService <ITfsVCCommandManager>();
            tf.CancellationToken = cancellationToken;
            tf.Endpoint          = endpoint;
            tf.ExecutionContext  = executionContext;

            // Setup proxy.
            var agentProxy = HostContext.GetService <IVstsAgentWebProxy>();
            if (!string.IsNullOrEmpty(executionContext.Variables.Agent_ProxyUrl) && !agentProxy.IsBypassed(endpoint.Url))
            {
                executionContext.Debug($"Configure '{tf.FilePath}' to work through proxy server '{executionContext.Variables.Agent_ProxyUrl}'.");
                tf.SetupProxy(executionContext.Variables.Agent_ProxyUrl, executionContext.Variables.Agent_ProxyUsername, executionContext.Variables.Agent_ProxyPassword);
            }

            // Add TF to the PATH.
            string tfPath = tf.FilePath;
            ArgUtil.File(tfPath, nameof(tfPath));
            var varUtil = HostContext.GetService <IVarUtil>();
            executionContext.Output(StringUtil.Loc("Prepending0WithDirectoryContaining1", Constants.PathVariable, Path.GetFileName(tfPath)));
            varUtil.PrependPath(Path.GetDirectoryName(tfPath));
            executionContext.Debug($"{Constants.PathVariable}: '{Environment.GetEnvironmentVariable(Constants.PathVariable)}'");

#if OS_WINDOWS
            // Set TFVC_BUILDAGENT_POLICYPATH
            string policyDllPath = Path.Combine(HostContext.GetDirectory(WellKnownDirectory.ServerOM), "Microsoft.TeamFoundation.VersionControl.Controls.dll");
            ArgUtil.File(policyDllPath, nameof(policyDllPath));
            const string policyPathEnvKey = "TFVC_BUILDAGENT_POLICYPATH";
            executionContext.Output(StringUtil.Loc("SetEnvVar", policyPathEnvKey));
            Environment.SetEnvironmentVariable(policyPathEnvKey, policyDllPath);
#endif

            // Check if the administrator accepted the license terms of the TEE EULA when configuring the agent.
            AgentSettings settings = HostContext.GetService <IConfigurationStore>().GetSettings();
            if (tf.Features.HasFlag(TfsVCFeatures.Eula) && settings.AcceptTeeEula)
            {
                // Check if the "tf eula -accept" command needs to be run for the current user.
                bool skipEula = false;
                try
                {
                    skipEula = tf.TestEulaAccepted();
                }
                catch (Exception ex)
                {
                    executionContext.Debug("Unexpected exception while testing whether the TEE EULA has been accepted for the current user.");
                    executionContext.Debug(ex.ToString());
                }

                if (!skipEula)
                {
                    // Run the command "tf eula -accept".
                    try
                    {
                        await tf.EulaAsync();
                    }
                    catch (Exception ex)
                    {
                        executionContext.Debug(ex.ToString());
                        executionContext.Warning(ex.Message);
                    }
                }
            }

            // Get the workspaces.
            executionContext.Output(StringUtil.Loc("QueryingWorkspaceInfo"));
            ITfsVCWorkspace[] tfWorkspaces = await tf.WorkspacesAsync();

            // Determine the workspace name.
            string buildDirectory = executionContext.Variables.Agent_BuildDirectory;
            ArgUtil.NotNullOrEmpty(buildDirectory, nameof(buildDirectory));
            string workspaceName = $"ws_{Path.GetFileName(buildDirectory)}_{settings.AgentId}";
            executionContext.Variables.Set(Constants.Variables.Build.RepoTfvcWorkspace, workspaceName);

            // Get the definition mappings.
            DefinitionWorkspaceMapping[] definitionMappings =
                JsonConvert.DeserializeObject <DefinitionWorkspaceMappings>(endpoint.Data[WellKnownEndpointData.TfvcWorkspaceMapping])?.Mappings;

            // Determine the sources directory.
            string sourcesDirectory = GetEndpointData(endpoint, Constants.EndpointData.SourcesDirectory);
            ArgUtil.NotNullOrEmpty(sourcesDirectory, nameof(sourcesDirectory));

            // Attempt to re-use an existing workspace if the command manager supports scorch
            // or if clean is not specified.
            ITfsVCWorkspace existingTFWorkspace = null;
            bool            clean = endpoint.Data.ContainsKey(WellKnownEndpointData.Clean) &&
                                    StringUtil.ConvertToBoolean(endpoint.Data[WellKnownEndpointData.Clean], defaultValue: false);
            if (tf.Features.HasFlag(TfsVCFeatures.Scorch) || !clean)
            {
                existingTFWorkspace = WorkspaceUtil.MatchExactWorkspace(
                    executionContext: executionContext,
                    tfWorkspaces: tfWorkspaces,
                    name: workspaceName,
                    definitionMappings: definitionMappings,
                    sourcesDirectory: sourcesDirectory);
                if (existingTFWorkspace != null)
                {
                    if (tf.Features.HasFlag(TfsVCFeatures.GetFromUnmappedRoot))
                    {
                        // Undo pending changes.
                        ITfsVCStatus tfStatus = await tf.StatusAsync(localPath : sourcesDirectory);

                        if (tfStatus?.HasPendingChanges ?? false)
                        {
                            await tf.UndoAsync(localPath : sourcesDirectory);

                            // Cleanup remaining files/directories from pend adds.
                            tfStatus.AllAdds
                            .OrderByDescending(x => x.LocalItem)     // Sort descending so nested items are deleted before their parent is deleted.
                            .ToList()
                            .ForEach(x =>
                            {
                                executionContext.Output(StringUtil.Loc("Deleting", x.LocalItem));
                                IOUtil.Delete(x.LocalItem, cancellationToken);
                            });
                        }
                    }
                    else
                    {
                        // Perform "undo" for each map.
                        foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings ?? new DefinitionWorkspaceMapping[0])
                        {
                            if (definitionMapping.MappingType == DefinitionMappingType.Map)
                            {
                                // Check the status.
                                string       localPath = definitionMapping.GetRootedLocalPath(sourcesDirectory);
                                ITfsVCStatus tfStatus  = await tf.StatusAsync(localPath : localPath);

                                if (tfStatus?.HasPendingChanges ?? false)
                                {
                                    // Undo.
                                    await tf.UndoAsync(localPath : localPath);

                                    // Cleanup remaining files/directories from pend adds.
                                    tfStatus.AllAdds
                                    .OrderByDescending(x => x.LocalItem)     // Sort descending so nested items are deleted before their parent is deleted.
                                    .ToList()
                                    .ForEach(x =>
                                    {
                                        executionContext.Output(StringUtil.Loc("Deleting", x.LocalItem));
                                        IOUtil.Delete(x.LocalItem, cancellationToken);
                                    });
                                }
                            }
                        }
                    }

                    // Scorch.
                    if (clean)
                    {
                        // Try to scorch.
                        try
                        {
                            await tf.ScorchAsync();
                        }
                        catch (ProcessExitCodeException ex)
                        {
                            // Scorch failed.
                            // Warn, drop the folder, and re-clone.
                            executionContext.Warning(ex.Message);
                            existingTFWorkspace = null;
                        }
                    }
                }
            }

            // Create a new workspace.
            if (existingTFWorkspace == null)
            {
                // Remove any conflicting workspaces.
                await RemoveConflictingWorkspacesAsync(
                    tf : tf,
                    tfWorkspaces : tfWorkspaces,
                    name : workspaceName,
                    directory : sourcesDirectory);

                // Remove any conflicting workspace from a different computer.
                // This is primarily a hosted scenario where a registered hosted
                // agent can land on a different computer each time.
                tfWorkspaces = await tf.WorkspacesAsync(matchWorkspaceNameOnAnyComputer : true);

                foreach (ITfsVCWorkspace tfWorkspace in tfWorkspaces ?? new ITfsVCWorkspace[0])
                {
                    await tf.WorkspaceDeleteAsync(tfWorkspace);
                }

                // Recreate the sources directory.
                executionContext.Debug($"Deleting: '{sourcesDirectory}'.");
                IOUtil.DeleteDirectory(sourcesDirectory, cancellationToken);
                Directory.CreateDirectory(sourcesDirectory);

                // Create the workspace.
                await tf.WorkspaceNewAsync();

                // Remove the default mapping.
                if (tf.Features.HasFlag(TfsVCFeatures.DefaultWorkfoldMap))
                {
                    await tf.WorkfoldUnmapAsync("$/");
                }

                // Sort the definition mappings.
                definitionMappings =
                    (definitionMappings ?? new DefinitionWorkspaceMapping[0])
                    .OrderBy(x => x.NormalizedServerPath?.Length ?? 0) // By server path length.
                    .ToArray() ?? new DefinitionWorkspaceMapping[0];

                // Add the definition mappings to the workspace.
                foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings)
                {
                    switch (definitionMapping.MappingType)
                    {
                    case DefinitionMappingType.Cloak:
                        // Add the cloak.
                        await tf.WorkfoldCloakAsync(serverPath : definitionMapping.ServerPath);

                        break;

                    case DefinitionMappingType.Map:
                        // Add the mapping.
                        await tf.WorkfoldMapAsync(
                            serverPath : definitionMapping.ServerPath,
                            localPath : definitionMapping.GetRootedLocalPath(sourcesDirectory));

                        break;

                    default:
                        throw new NotSupportedException();
                    }
                }
            }

            if (tf.Features.HasFlag(TfsVCFeatures.GetFromUnmappedRoot))
            {
                // Get.
                await tf.GetAsync(localPath : sourcesDirectory);
            }
            else
            {
                // Perform "get" for each map.
                foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings ?? new DefinitionWorkspaceMapping[0])
                {
                    if (definitionMapping.MappingType == DefinitionMappingType.Map)
                    {
                        await tf.GetAsync(localPath : definitionMapping.GetRootedLocalPath(sourcesDirectory));
                    }
                }
            }

            // Steps for shelveset/gated.
            string shelvesetName = GetEndpointData(endpoint, Constants.EndpointData.SourceTfvcShelveset);
            if (!string.IsNullOrEmpty(shelvesetName))
            {
                // Steps for gated.
                ITfsVCShelveset tfShelveset        = null;
                string          gatedShelvesetName = GetEndpointData(endpoint, Constants.EndpointData.GatedShelvesetName);
                if (!string.IsNullOrEmpty(gatedShelvesetName))
                {
                    // Clean the last-saved-checkin-metadata for existing workspaces.
                    //
                    // A better long term fix is to add a switch to "tf unshelve" that completely overwrites
                    // the last-saved-checkin-metadata, instead of merging associated work items.
                    //
                    // The targeted workaround for now is to create a trivial change and "tf shelve /move",
                    // which will delete the last-saved-checkin-metadata.
                    if (existingTFWorkspace != null)
                    {
                        executionContext.Output("Cleaning last saved checkin metadata.");

                        // Find a local mapped directory.
                        string firstLocalDirectory =
                            (definitionMappings ?? new DefinitionWorkspaceMapping[0])
                            .Where(x => x.MappingType == DefinitionMappingType.Map)
                            .Select(x => x.GetRootedLocalPath(sourcesDirectory))
                            .FirstOrDefault(x => Directory.Exists(x));
                        if (firstLocalDirectory == null)
                        {
                            executionContext.Warning("No mapped folder found. Unable to clean last-saved-checkin-metadata.");
                        }
                        else
                        {
                            // Create a trival change and "tf shelve /move" to clear the
                            // last-saved-checkin-metadata.
                            string cleanName     = "__tf_clean_wksp_metadata";
                            string tempCleanFile = Path.Combine(firstLocalDirectory, cleanName);
                            try
                            {
                                File.WriteAllText(path: tempCleanFile, contents: "clean last-saved-checkin-metadata", encoding: Encoding.UTF8);
                                await tf.AddAsync(tempCleanFile);

                                await tf.ShelveAsync(shelveset : cleanName, commentFile : tempCleanFile, move : true);
                            }
                            catch (Exception ex)
                            {
                                executionContext.Warning($"Unable to clean last-saved-checkin-metadata. {ex.Message}");
                                try
                                {
                                    await tf.UndoAsync(tempCleanFile);
                                }
                                catch (Exception ex2)
                                {
                                    executionContext.Warning($"Unable to undo '{tempCleanFile}'. {ex2.Message}");
                                }
                            }
                            finally
                            {
                                IOUtil.DeleteFile(tempCleanFile);
                            }
                        }
                    }

                    // Get the shelveset metadata.
                    tfShelveset = await tf.ShelvesetsAsync(shelveset : shelvesetName);

                    // The above command throws if the shelveset is not found,
                    // so the following assertion should never fail.
                    ArgUtil.NotNull(tfShelveset, nameof(tfShelveset));
                }

                // Unshelve.
                await tf.UnshelveAsync(shelveset : shelvesetName);

                // Ensure we undo pending changes for shelveset build at the end.
                _undoShelvesetPendingChanges = true;

                if (!string.IsNullOrEmpty(gatedShelvesetName))
                {
                    // Create the comment file for reshelve.
                    StringBuilder comment    = new StringBuilder(tfShelveset.Comment ?? string.Empty);
                    string        runCi      = GetEndpointData(endpoint, Constants.EndpointData.GatedRunCI);
                    bool          gatedRunCi = StringUtil.ConvertToBoolean(runCi, true);
                    if (!gatedRunCi)
                    {
                        if (comment.Length > 0)
                        {
                            comment.AppendLine();
                        }

                        comment.Append(Constants.Build.NoCICheckInComment);
                    }

                    string commentFile = null;
                    try
                    {
                        commentFile = Path.GetTempFileName();
                        File.WriteAllText(path: commentFile, contents: comment.ToString(), encoding: Encoding.UTF8);

                        // Reshelve.
                        await tf.ShelveAsync(shelveset : gatedShelvesetName, commentFile : commentFile, move : false);
                    }
                    finally
                    {
                        // Cleanup the comment file.
                        if (File.Exists(commentFile))
                        {
                            File.Delete(commentFile);
                        }
                    }
                }
            }

            // Cleanup proxy settings.
            if (!string.IsNullOrEmpty(executionContext.Variables.Agent_ProxyUrl) && !agentProxy.IsBypassed(endpoint.Url))
            {
                executionContext.Debug($"Remove proxy setting for '{tf.FilePath}' to work through proxy server '{executionContext.Variables.Agent_ProxyUrl}'.");
                tf.CleanupProxySetting();
            }
        }
        public async Task GetSourceAsync(
            AgentTaskPluginExecutionContext executionContext,
            Pipelines.RepositoryResource repository,
            CancellationToken cancellationToken)
        {
            // Validate args.
            ArgUtil.NotNull(executionContext, nameof(executionContext));
            ArgUtil.NotNull(repository, nameof(repository));

            // Validate .NET Framework 4.6 or higher is installed.
            if (PlatformUtil.RunningOnWindows && !NetFrameworkUtil.Test(new Version(4, 6), executionContext))
            {
                throw new Exception(StringUtil.Loc("MinimumNetFramework46"));
            }

            // determine if we've been asked to suppress some checkout step output
            bool reducedOutput = AgentKnobs.QuietCheckout.GetValue(executionContext).AsBoolean();

            if (reducedOutput)
            {
                executionContext.Output(StringUtil.Loc("QuietCheckoutModeRequested"));
                executionContext.SetTaskVariable(AgentKnobs.QuietCheckoutRuntimeVarName, Boolean.TrueString);
            }


            // Create the tf command manager.
            ITfsVCCliManager tf;

            if (PlatformUtil.RunningOnWindows)
            {
                tf = new TFCliManager();
            }
            else
            {
                tf = new TeeCliManager();
            }

            tf.CancellationToken = cancellationToken;
            tf.Repository        = repository;
            tf.ExecutionContext  = executionContext;
            if (repository.Endpoint != null)
            {
                // the endpoint should either be the SystemVssConnection (id = guild.empty, name = SystemVssConnection)
                // or a real service endpoint to external service which has a real id
                var endpoint = executionContext.Endpoints.Single(
                    x => (repository.Endpoint.Id != Guid.Empty && x.Id == repository.Endpoint.Id) ||
                    (repository.Endpoint.Id == Guid.Empty && string.Equals(x.Name, repository.Endpoint.Name.ToString(), StringComparison.OrdinalIgnoreCase)));
                ArgUtil.NotNull(endpoint, nameof(endpoint));
                tf.Endpoint = endpoint;
            }

            // Setup proxy.
            var agentProxy = executionContext.GetProxyConfiguration();

            if (agentProxy != null && !string.IsNullOrEmpty(agentProxy.ProxyAddress) && !agentProxy.WebProxy.IsBypassed(repository.Url))
            {
                executionContext.Debug($"Configure '{tf.FilePath}' to work through proxy server '{agentProxy.ProxyAddress}'.");
                tf.SetupProxy(agentProxy.ProxyAddress, agentProxy.ProxyUsername, agentProxy.ProxyPassword);
            }

            // Setup client certificate.
            var agentCertManager = executionContext.GetCertConfiguration();

            if (agentCertManager != null && agentCertManager.SkipServerCertificateValidation)
            {
                executionContext.Debug("TF does not support ignoring SSL certificate validation error.");
            }

            // prepare client cert, if the repository's endpoint url match the TFS/VSTS url
            var systemConnection = executionContext.Endpoints.Single(x => string.Equals(x.Name, WellKnownServiceEndpointNames.SystemVssConnection, StringComparison.OrdinalIgnoreCase));

            if (!string.IsNullOrEmpty(agentCertManager?.ClientCertificateFile) &&
                Uri.Compare(repository.Url, systemConnection.Url, UriComponents.SchemeAndServer, UriFormat.Unescaped, StringComparison.OrdinalIgnoreCase) == 0)
            {
                executionContext.Debug($"Configure '{tf.FilePath}' to work with client cert '{agentCertManager.ClientCertificateFile}'.");
                tf.SetupClientCertificate(agentCertManager.ClientCertificateFile, agentCertManager.ClientCertificatePrivateKeyFile, agentCertManager.ClientCertificateArchiveFile, agentCertManager.ClientCertificatePassword);
            }

            // Add TF to the PATH.
            string tfPath = tf.FilePath;

            ArgUtil.File(tfPath, nameof(tfPath));
            executionContext.Output(StringUtil.Loc("Prepending0WithDirectoryContaining1", PathUtil.PathVariable, Path.GetFileName(tfPath)));
            executionContext.PrependPath(Path.GetDirectoryName(tfPath));
            executionContext.Debug($"PATH: '{Environment.GetEnvironmentVariable("PATH")}'");

            if (PlatformUtil.RunningOnWindows)
            {
                // Set TFVC_BUILDAGENT_POLICYPATH
                string policyDllPath = Path.Combine(executionContext.Variables.GetValueOrDefault("Agent.HomeDirectory")?.Value, "externals", "tf", "Microsoft.TeamFoundation.VersionControl.Controls.dll");
                ArgUtil.File(policyDllPath, nameof(policyDllPath));
                const string policyPathEnvKey = "TFVC_BUILDAGENT_POLICYPATH";
                executionContext.Output(StringUtil.Loc("SetEnvVar", policyPathEnvKey));
                executionContext.SetVariable(policyPathEnvKey, policyDllPath);
            }

            // Check if the administrator accepted the license terms of the TEE EULA when configuring the agent.
            if (tf.Features.HasFlag(TfsVCFeatures.Eula) && StringUtil.ConvertToBoolean(executionContext.Variables.GetValueOrDefault("Agent.AcceptTeeEula")?.Value))
            {
                // Check if the "tf eula -accept" command needs to be run for the current user.
                bool skipEula = false;
                try
                {
                    skipEula = tf.TestEulaAccepted();
                }
                catch (Exception ex)
                {
                    executionContext.Debug("Unexpected exception while testing whether the TEE EULA has been accepted for the current user.");
                    executionContext.Debug(ex.ToString());
                }

                if (!skipEula)
                {
                    // Run the command "tf eula -accept".
                    try
                    {
                        await tf.EulaAsync();
                    }
                    catch (Exception ex)
                    {
                        executionContext.Debug(ex.ToString());
                        executionContext.Warning(ex.Message);
                    }
                }
            }

            // Get the workspaces.
            executionContext.Output(StringUtil.Loc("QueryingWorkspaceInfo"));
            ITfsVCWorkspace[] tfWorkspaces = await tf.WorkspacesAsync();

            // Determine the workspace name.
            string buildDirectory = executionContext.Variables.GetValueOrDefault("agent.builddirectory")?.Value;

            ArgUtil.NotNullOrEmpty(buildDirectory, nameof(buildDirectory));
            string workspaceName = $"ws_{Path.GetFileName(buildDirectory)}_{executionContext.Variables.GetValueOrDefault("agent.id")?.Value}";

            executionContext.SetVariable("build.repository.tfvc.workspace", workspaceName);

            // Get the definition mappings.
            var workspaceMappings = repository.Properties.Get <IList <Pipelines.WorkspaceMapping> >(Pipelines.RepositoryPropertyNames.Mappings);

            DefinitionWorkspaceMapping[] definitionMappings = workspaceMappings.Select(x => new DefinitionWorkspaceMapping()
            {
                ServerPath = x.ServerPath, LocalPath = x.LocalPath, MappingType = x.Exclude ? DefinitionMappingType.Cloak : DefinitionMappingType.Map
            }).ToArray();

            // Determine the sources directory.
            string sourcesDirectory = repository.Properties.Get <string>(Pipelines.RepositoryPropertyNames.Path);

            ArgUtil.NotNullOrEmpty(sourcesDirectory, nameof(sourcesDirectory));

            // Attempt to re-use an existing workspace if the command manager supports scorch
            // or if clean is not specified.
            ITfsVCWorkspace existingTFWorkspace = null;
            bool            clean = StringUtil.ConvertToBoolean(executionContext.GetInput(Pipelines.PipelineConstants.CheckoutTaskInputs.Clean));

            if (tf.Features.HasFlag(TfsVCFeatures.Scorch) || !clean)
            {
                existingTFWorkspace = WorkspaceUtil.MatchExactWorkspace(
                    executionContext: executionContext,
                    tfWorkspaces: tfWorkspaces,
                    name: workspaceName,
                    definitionMappings: definitionMappings,
                    sourcesDirectory: sourcesDirectory);
                if (existingTFWorkspace != null)
                {
                    if (tf.Features.HasFlag(TfsVCFeatures.GetFromUnmappedRoot))
                    {
                        // Undo pending changes.
                        ITfsVCStatus tfStatus = await tf.StatusAsync(localPath : sourcesDirectory);

                        if (tfStatus?.HasPendingChanges ?? false)
                        {
                            await tf.UndoAsync(localPath : sourcesDirectory);

                            // Cleanup remaining files/directories from pend adds.
                            tfStatus.AllAdds
                            .OrderByDescending(x => x.LocalItem)     // Sort descending so nested items are deleted before their parent is deleted.
                            .ToList()
                            .ForEach(x =>
                            {
                                executionContext.Output(StringUtil.Loc("Deleting", x.LocalItem));
                                IOUtil.Delete(x.LocalItem, cancellationToken);
                            });
                        }
                    }
                    else
                    {
                        // Perform "undo" for each map.
                        foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings ?? new DefinitionWorkspaceMapping[0])
                        {
                            if (definitionMapping.MappingType == DefinitionMappingType.Map)
                            {
                                // Check the status.
                                string       localPath = definitionMapping.GetRootedLocalPath(sourcesDirectory);
                                ITfsVCStatus tfStatus  = await tf.StatusAsync(localPath : localPath);

                                if (tfStatus?.HasPendingChanges ?? false)
                                {
                                    // Undo.
                                    await tf.UndoAsync(localPath : localPath);

                                    // Cleanup remaining files/directories from pend adds.
                                    tfStatus.AllAdds
                                    .OrderByDescending(x => x.LocalItem)     // Sort descending so nested items are deleted before their parent is deleted.
                                    .ToList()
                                    .ForEach(x =>
                                    {
                                        executionContext.Output(StringUtil.Loc("Deleting", x.LocalItem));
                                        IOUtil.Delete(x.LocalItem, cancellationToken);
                                    });
                                }
                            }
                        }
                    }

                    // Scorch.
                    if (clean)
                    {
                        // Try to scorch.
                        try
                        {
                            await tf.ScorchAsync();
                        }
                        catch (ProcessExitCodeException ex)
                        {
                            // Scorch failed.
                            // Warn, drop the folder, and re-clone.
                            executionContext.Warning(ex.Message);
                            existingTFWorkspace = null;
                        }
                    }
                }
            }

            // Create a new workspace.
            if (existingTFWorkspace == null)
            {
                // Remove any conflicting workspaces.
                await RemoveConflictingWorkspacesAsync(
                    tf : tf,
                    tfWorkspaces : tfWorkspaces,
                    name : workspaceName,
                    directory : sourcesDirectory);

                // Remove any conflicting workspace from a different computer.
                // This is primarily a hosted scenario where a registered hosted
                // agent can land on a different computer each time.
                tfWorkspaces = await tf.WorkspacesAsync(matchWorkspaceNameOnAnyComputer : true);

                foreach (ITfsVCWorkspace tfWorkspace in tfWorkspaces ?? new ITfsVCWorkspace[0])
                {
                    await tf.TryWorkspaceDeleteAsync(tfWorkspace);
                }

                // Recreate the sources directory.
                executionContext.Debug($"Deleting: '{sourcesDirectory}'.");
                IOUtil.DeleteDirectory(sourcesDirectory, cancellationToken);
                Directory.CreateDirectory(sourcesDirectory);

                // Create the workspace.
                await tf.WorkspaceNewAsync();

                // Remove the default mapping.
                if (tf.Features.HasFlag(TfsVCFeatures.DefaultWorkfoldMap))
                {
                    await tf.WorkfoldUnmapAsync("$/");
                }

                // Sort the definition mappings.
                definitionMappings =
                    (definitionMappings ?? new DefinitionWorkspaceMapping[0])
                    .OrderBy(x => x.NormalizedServerPath?.Length ?? 0) // By server path length.
                    .ToArray() ?? new DefinitionWorkspaceMapping[0];

                // Add the definition mappings to the workspace.
                foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings)
                {
                    switch (definitionMapping.MappingType)
                    {
                    case DefinitionMappingType.Cloak:
                        // Add the cloak.
                        await tf.WorkfoldCloakAsync(serverPath : definitionMapping.ServerPath);

                        break;

                    case DefinitionMappingType.Map:
                        // Add the mapping.
                        await tf.WorkfoldMapAsync(
                            serverPath : definitionMapping.ServerPath,
                            localPath : definitionMapping.GetRootedLocalPath(sourcesDirectory));

                        break;

                    default:
                        throw new NotSupportedException();
                    }
                }
            }

            if (tf.Features.HasFlag(TfsVCFeatures.GetFromUnmappedRoot))
            {
                // Get.
                await tf.GetAsync(localPath : sourcesDirectory, quiet : reducedOutput);
            }
            else
            {
                // Perform "get" for each map.
                foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings ?? new DefinitionWorkspaceMapping[0])
                {
                    if (definitionMapping.MappingType == DefinitionMappingType.Map)
                    {
                        await tf.GetAsync(localPath : definitionMapping.GetRootedLocalPath(sourcesDirectory), quiet : reducedOutput);
                    }
                }
            }

            // Steps for shelveset/gated.
            string shelvesetName = repository.Properties.Get <string>(Pipelines.RepositoryPropertyNames.Shelveset);

            if (!string.IsNullOrEmpty(shelvesetName))
            {
                // Steps for gated.
                ITfsVCShelveset tfShelveset        = null;
                string          gatedShelvesetName = executionContext.Variables.GetValueOrDefault("build.gated.shelvesetname")?.Value;
                if (!string.IsNullOrEmpty(gatedShelvesetName))
                {
                    // Clean the last-saved-checkin-metadata for existing workspaces.
                    //
                    // A better long term fix is to add a switch to "tf unshelve" that completely overwrites
                    // the last-saved-checkin-metadata, instead of merging associated work items.
                    //
                    // The targeted workaround for now is to create a trivial change and "tf shelve /move",
                    // which will delete the last-saved-checkin-metadata.
                    if (existingTFWorkspace != null)
                    {
                        executionContext.Output("Cleaning last saved checkin metadata.");

                        // Find a local mapped directory.
                        string firstLocalDirectory =
                            (definitionMappings ?? new DefinitionWorkspaceMapping[0])
                            .Where(x => x.MappingType == DefinitionMappingType.Map)
                            .Select(x => x.GetRootedLocalPath(sourcesDirectory))
                            .FirstOrDefault(x => Directory.Exists(x));
                        if (firstLocalDirectory == null)
                        {
                            executionContext.Warning("No mapped folder found. Unable to clean last-saved-checkin-metadata.");
                        }
                        else
                        {
                            // Create a trival change and "tf shelve /move" to clear the
                            // last-saved-checkin-metadata.
                            string cleanName     = "__tf_clean_wksp_metadata";
                            string tempCleanFile = Path.Combine(firstLocalDirectory, cleanName);
                            try
                            {
                                File.WriteAllText(path: tempCleanFile, contents: "clean last-saved-checkin-metadata", encoding: Encoding.UTF8);
                                await tf.AddAsync(tempCleanFile);

                                await tf.ShelveAsync(shelveset : cleanName, commentFile : tempCleanFile, move : true);
                            }
                            catch (Exception ex)
                            {
                                executionContext.Warning($"Unable to clean last-saved-checkin-metadata. {ex.Message}");
                                try
                                {
                                    await tf.UndoAsync(tempCleanFile);
                                }
                                catch (Exception ex2)
                                {
                                    executionContext.Warning($"Unable to undo '{tempCleanFile}'. {ex2.Message}");
                                }
                            }
                            finally
                            {
                                IOUtil.DeleteFile(tempCleanFile);
                            }
                        }
                    }

                    // Get the shelveset metadata.
                    tfShelveset = await tf.ShelvesetsAsync(shelveset : shelvesetName);

                    // The above command throws if the shelveset is not found,
                    // so the following assertion should never fail.
                    ArgUtil.NotNull(tfShelveset, nameof(tfShelveset));
                }

                // Unshelve.
                bool unshelveErrorsAllowed = AgentKnobs.AllowTfvcUnshelveErrors.GetValue(executionContext).AsBoolean();
                await tf.UnshelveAsync(shelveset : shelvesetName, unshelveErrorsAllowed);

                // Ensure we undo pending changes for shelveset build at the end.
                executionContext.SetTaskVariable("UndoShelvesetPendingChanges", bool.TrueString);

                if (!string.IsNullOrEmpty(gatedShelvesetName))
                {
                    // Create the comment file for reshelve.
                    StringBuilder comment    = new StringBuilder(tfShelveset.Comment ?? string.Empty);
                    string        runCi      = executionContext.Variables.GetValueOrDefault("build.gated.runci")?.Value;
                    bool          gatedRunCi = StringUtil.ConvertToBoolean(runCi, true);
                    if (!gatedRunCi)
                    {
                        if (comment.Length > 0)
                        {
                            comment.AppendLine();
                        }

                        comment.Append("***NO_CI***");
                    }

                    string commentFile = null;
                    try
                    {
                        commentFile = Path.GetTempFileName();
                        File.WriteAllText(path: commentFile, contents: comment.ToString(), encoding: Encoding.UTF8);

                        // Reshelve.
                        await tf.ShelveAsync(shelveset : gatedShelvesetName, commentFile : commentFile, move : false);
                    }
                    finally
                    {
                        // Cleanup the comment file.
                        if (File.Exists(commentFile))
                        {
                            File.Delete(commentFile);
                        }
                    }
                }
            }

            // Cleanup proxy settings.
            if (agentProxy != null && !string.IsNullOrEmpty(agentProxy.ProxyAddress) && !agentProxy.WebProxy.IsBypassed(repository.Url))
            {
                executionContext.Debug($"Remove proxy setting for '{tf.FilePath}' to work through proxy server '{agentProxy.ProxyAddress}'.");
                tf.CleanupProxySetting();
            }

            // Set intra-task variable for post job cleanup
            executionContext.SetTaskVariable("repository", repository.Alias);
        }
Exemple #8
0
        public async Task GetSourceAsync(
            IExecutionContext executionContext,
            ServiceEndpoint endpoint,
            CancellationToken cancellationToken)
        {
            Trace.Entering();
            // Validate args.
            ArgUtil.NotNull(executionContext, nameof(executionContext));
            ArgUtil.NotNull(endpoint, nameof(endpoint));

            // Create the tf command manager.
            var tf = HostContext.CreateService <ITfsVCCommandManager>();

            tf.CancellationToken = cancellationToken;
            tf.Endpoint          = endpoint;
            tf.ExecutionContext  = executionContext;

            // Add TF to the PATH.
            string tfPath = tf.FilePath;

            ArgUtil.File(tfPath, nameof(tfPath));
            var varUtil = HostContext.GetService <IVarUtil>();

            executionContext.Output(StringUtil.Loc("Prepending0WithDirectoryContaining1", Constants.PathVariable, Path.GetFileName(tfPath)));
            varUtil.PrependPath(Path.GetDirectoryName(tfPath));
            executionContext.Debug($"{Constants.PathVariable}: '{Environment.GetEnvironmentVariable(Constants.PathVariable)}'");

            // Check if the administrator accepted the license terms of the TEE EULA when configuring the agent.
            AgentSettings settings = HostContext.GetService <IConfigurationStore>().GetSettings();

            if (tf.Features.HasFlag(TfsVCFeatures.Eula) && settings.AcceptTeeEula)
            {
                // Check if the "tf eula -accept" command needs to be run for the current user.
                bool skipEula = false;
                try
                {
                    skipEula = tf.TestEulaAccepted();
                }
                catch (Exception ex)
                {
                    executionContext.Debug("Unexpected exception while testing whether the TEE EULA has been accepted for the current user.");
                    executionContext.Debug(ex.ToString());
                }

                if (!skipEula)
                {
                    // Run the command "tf eula -accept".
                    try
                    {
                        await tf.EulaAsync();
                    }
                    catch (Exception ex)
                    {
                        executionContext.Debug(ex.ToString());
                        executionContext.Warning(ex.Message);
                    }
                }
            }

            // Get the workspaces.
            executionContext.Output(StringUtil.Loc("QueryingWorkspaceInfo"));
            ITfsVCWorkspace[] tfWorkspaces = await tf.WorkspacesAsync();

            // Determine the workspace name.
            string buildDirectory = executionContext.Variables.Agent_BuildDirectory;

            ArgUtil.NotNullOrEmpty(buildDirectory, nameof(buildDirectory));
            string workspaceName = $"ws_{Path.GetFileName(buildDirectory)}_{settings.AgentId}";

            executionContext.Variables.Set(Constants.Variables.Build.RepoTfvcWorkspace, workspaceName);

            // Get the definition mappings.
            DefinitionWorkspaceMapping[] definitionMappings =
                JsonConvert.DeserializeObject <DefinitionWorkspaceMappings>(endpoint.Data[WellKnownEndpointData.TfvcWorkspaceMapping])?.Mappings;

            // Determine the sources directory.
            string sourcesDirectory = GetEndpointData(endpoint, Constants.EndpointData.SourcesDirectory);

            ArgUtil.NotNullOrEmpty(sourcesDirectory, nameof(sourcesDirectory));

            // Attempt to re-use an existing workspace if the command manager supports scorch
            // or if clean is not specified.
            ITfsVCWorkspace existingTFWorkspace = null;
            bool            clean = endpoint.Data.ContainsKey(WellKnownEndpointData.Clean) &&
                                    StringUtil.ConvertToBoolean(endpoint.Data[WellKnownEndpointData.Clean], defaultValue: false);

            if (tf.Features.HasFlag(TfsVCFeatures.Scorch) || !clean)
            {
                existingTFWorkspace = WorkspaceUtil.MatchExactWorkspace(
                    executionContext: executionContext,
                    tfWorkspaces: tfWorkspaces,
                    name: workspaceName,
                    definitionMappings: definitionMappings,
                    sourcesDirectory: sourcesDirectory);
                if (existingTFWorkspace != null)
                {
                    if (tf.Features.HasFlag(TfsVCFeatures.GetFromUnmappedRoot))
                    {
                        // Undo pending changes.
                        ITfsVCStatus tfStatus = await tf.StatusAsync(localPath : sourcesDirectory);

                        if (tfStatus?.HasPendingChanges ?? false)
                        {
                            await tf.UndoAsync(localPath : sourcesDirectory);

                            // Cleanup remaining files/directories from pend adds.
                            tfStatus.AllAdds
                            .OrderByDescending(x => x.LocalItem)     // Sort descending so nested items are deleted before their parent is deleted.
                            .ToList()
                            .ForEach(x =>
                            {
                                executionContext.Output(StringUtil.Loc("Deleting", x.LocalItem));
                                IOUtil.Delete(x.LocalItem, cancellationToken);
                            });
                        }
                    }
                    else
                    {
                        // Perform "undo" for each map.
                        foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings ?? new DefinitionWorkspaceMapping[0])
                        {
                            if (definitionMapping.MappingType == DefinitionMappingType.Map)
                            {
                                // Check the status.
                                string       localPath = definitionMapping.GetRootedLocalPath(sourcesDirectory);
                                ITfsVCStatus tfStatus  = await tf.StatusAsync(localPath : localPath);

                                if (tfStatus?.HasPendingChanges ?? false)
                                {
                                    // Undo.
                                    await tf.UndoAsync(localPath : localPath);

                                    // Cleanup remaining files/directories from pend adds.
                                    tfStatus.AllAdds
                                    .OrderByDescending(x => x.LocalItem)     // Sort descending so nested items are deleted before their parent is deleted.
                                    .ToList()
                                    .ForEach(x =>
                                    {
                                        executionContext.Output(StringUtil.Loc("Deleting", x.LocalItem));
                                        IOUtil.Delete(x.LocalItem, cancellationToken);
                                    });
                                }
                            }
                        }
                    }

                    // Scorch.
                    if (clean)
                    {
                        // Try to scorch.
                        try
                        {
                            await tf.ScorchAsync();
                        }
                        catch (ProcessExitCodeException ex)
                        {
                            // Scorch failed.
                            // Warn, drop the folder, and re-clone.
                            executionContext.Warning(ex.Message);
                            existingTFWorkspace = null;
                        }
                    }
                }
            }

            // Create a new workspace.
            if (existingTFWorkspace == null)
            {
                // Remove any conflicting workspaces.
                await RemoveConflictingWorkspacesAsync(
                    tf : tf,
                    tfWorkspaces : tfWorkspaces,
                    name : workspaceName,
                    directory : sourcesDirectory);

                // Remove any conflicting workspace from a different computer.
                // This is primarily a hosted scenario where a registered hosted
                // agent can land on a different computer each time.
                tfWorkspaces = await tf.WorkspacesAsync(matchWorkspaceNameOnAnyComputer : true);

                foreach (ITfsVCWorkspace tfWorkspace in tfWorkspaces ?? new ITfsVCWorkspace[0])
                {
                    await tf.WorkspaceDeleteAsync(tfWorkspace);
                }

                // Recreate the sources directory.
                executionContext.Debug($"Deleting: '{sourcesDirectory}'.");
                IOUtil.DeleteDirectory(sourcesDirectory, cancellationToken);
                Directory.CreateDirectory(sourcesDirectory);

                // Create the workspace.
                await tf.WorkspaceNewAsync();

                // Remove the default mapping.
                if (tf.Features.HasFlag(TfsVCFeatures.DefaultWorkfoldMap))
                {
                    await tf.WorkfoldUnmapAsync("$/");
                }

                // Sort the definition mappings.
                definitionMappings =
                    (definitionMappings ?? new DefinitionWorkspaceMapping[0])
                    .OrderBy(x => x.NormalizedServerPath?.Length ?? 0) // By server path length.
                    .ToArray() ?? new DefinitionWorkspaceMapping[0];

                // Add the definition mappings to the workspace.
                foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings)
                {
                    switch (definitionMapping.MappingType)
                    {
                    case DefinitionMappingType.Cloak:
                        // Add the cloak.
                        await tf.WorkfoldCloakAsync(serverPath : definitionMapping.ServerPath);

                        break;

                    case DefinitionMappingType.Map:
                        // Add the mapping.
                        await tf.WorkfoldMapAsync(
                            serverPath : definitionMapping.ServerPath,
                            localPath : definitionMapping.GetRootedLocalPath(sourcesDirectory));

                        break;

                    default:
                        throw new NotSupportedException();
                    }
                }
            }

            if (tf.Features.HasFlag(TfsVCFeatures.GetFromUnmappedRoot))
            {
                // Get.
                await tf.GetAsync(localPath : sourcesDirectory);
            }
            else
            {
                // Perform "get" for each map.
                foreach (DefinitionWorkspaceMapping definitionMapping in definitionMappings ?? new DefinitionWorkspaceMapping[0])
                {
                    if (definitionMapping.MappingType == DefinitionMappingType.Map)
                    {
                        await tf.GetAsync(localPath : definitionMapping.GetRootedLocalPath(sourcesDirectory));
                    }
                }
            }

            string shelvesetName = GetEndpointData(endpoint, Constants.EndpointData.SourceTfvcShelveset);

            if (!string.IsNullOrEmpty(shelvesetName))
            {
                // Get the shelveset details.
                ITfsVCShelveset tfShelveset        = null;
                string          gatedShelvesetName = GetEndpointData(endpoint, Constants.EndpointData.GatedShelvesetName);
                if (!string.IsNullOrEmpty(gatedShelvesetName))
                {
                    tfShelveset = await tf.ShelvesetsAsync(shelveset : shelvesetName);

                    // The command throws if the shelveset is not found.
                    // This assertion should never fail.
                    ArgUtil.NotNull(tfShelveset, nameof(tfShelveset));
                }

                // Unshelve.
                await tf.UnshelveAsync(shelveset : shelvesetName);

                if (!string.IsNullOrEmpty(gatedShelvesetName))
                {
                    // Create the comment file for reshelve.
                    StringBuilder comment    = new StringBuilder(tfShelveset.Comment ?? string.Empty);
                    string        runCi      = GetEndpointData(endpoint, Constants.EndpointData.GatedRunCI);
                    bool          gatedRunCi = StringUtil.ConvertToBoolean(runCi, true);
                    if (!gatedRunCi)
                    {
                        if (comment.Length > 0)
                        {
                            comment.AppendLine();
                        }

                        comment.Append(Constants.Build.NoCICheckInComment);
                    }

                    string commentFile = null;
                    try
                    {
                        commentFile = Path.GetTempFileName();
                        File.WriteAllText(path: commentFile, contents: comment.ToString(), encoding: Encoding.UTF8);

                        // Reshelve.
                        await tf.ShelveAsync(shelveset : gatedShelvesetName, commentFile : commentFile);
                    }
                    finally
                    {
                        // Cleanup the comment file.
                        if (File.Exists(commentFile))
                        {
                            File.Delete(commentFile);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 获取指定空间范围下相交的要素集合
        /// </summary>
        /// <param name="featureClass">被查询要素类</param>
        /// <param name="queryClause">查询条件</param>
        /// <param name="queryGeometry">指定空间范围</param>
        /// <param name="intersectFeatureDTOs">输出相交要素信息</param>
        /// <param name="sumIntersectArea">输出相交部分的总面积</param>
        /// <param name="geometryField">geometry字段名称,默认为Shape</param>
        public static void GetIntersectFeaturesByQuery(IFeatureClass featureClass, string queryClause,
                                                       IGeometry queryGeometry, out IList <IntersectFeatureDTO> intersectFeatureDTOs,
                                                       out double sumIntersectArea, string geometryField = "Shape")
        {
            List <IFeature> featureList = new List <IFeature>();

            intersectFeatureDTOs = new List <IntersectFeatureDTO>();
            sumIntersectArea     = 0d;

            try
            {
                ISpatialFilter spatialFilter = new SpatialFilter();
                if (queryClause != null)
                {
                    spatialFilter.WhereClause = queryClause;
                }
                if (queryGeometry != null)
                {
                    spatialFilter.Geometry   = queryGeometry;
                    spatialFilter.SpatialRel = esriSpatialRelEnum.esriSpatialRelIntersects;
                }
                if (geometryField != null)
                {
                    spatialFilter.GeometryField = geometryField;
                }

                IFeatureCursor featureCursor = featureClass.Search(spatialFilter, false);
                IFeature       feature       = featureCursor.NextFeature();

                IntersectFeatureDTO intersectFeatureDTOTemp = null;

                while (feature != null)
                {
                    IGeometry intersectGeometry = OverlayCommonTool.GetIntersectGeometry(queryGeometry as IPolygon, feature.Shape as IPolygon);

                    if (null == intersectGeometry || intersectGeometry.IsEmpty)
                    {
                        continue;
                    }

                    intersectFeatureDTOTemp = new IntersectFeatureDTO
                    {
                        Geometry          = feature.Shape,
                        OID               = feature.OID,
                        Coordinates       = GeometryUtil.ConvertGeometryToJson(intersectGeometry, out string message),
                        Area              = GeometryUtil.GetArea(intersectGeometry),
                        QueryGeometry     = queryGeometry,
                        IntersectGeometry = intersectGeometry,
                        GeoType           = EnumUtil.GetEnumName <esriGeometryType>((int)intersectGeometry.GeometryType)
                    };
                    intersectFeatureDTOs.Add(intersectFeatureDTOTemp);
                    IArea  area          = intersectGeometry as IArea;
                    double intersectArea = area.Area;
                    sumIntersectArea += intersectArea;

                    featureList.Add(feature);
                    feature = featureCursor.NextFeature();
                }
                WorkspaceUtil.ReleaseComObject(featureCursor);
            }
            catch (Exception e)
            {
                LOG.Error(e);
            }
        }
Exemple #10
0
        public override Result Execute()
        {
            if (!base.InitComplete)
            {
                throw new BusinessException((int)EnumSystemStatusCode.DME_FAIL_INIT, "初始化工作未完成");
            }
            DMEWorkspaceBridge <IWorkspace, IFeatureClass> dmeWorkspaceBridge = new DMEWorkspaceBridge <IWorkspace, IFeatureClass>();

            dmeWorkspaceBridge.SetWorkspace(new EsriWorkspace());
            // 目前先以ORACLE和MDB为数据源类型
            // 获取source feature class
            this.SourceFeatureClass = dmeWorkspaceBridge.GetFeatureClass(this.sourceFeatureClassDTO);
            // 获取target feature class
            this.TargetFeatureClass = dmeWorkspaceBridge.GetFeatureClass(this.targetFeatureClassDTO);

            if (AnalysisType.COVER == this.AnalysisType)
            {
                OverlayCommonTool.GetTopounionGeometryByQuery(this.SourceFeatureClass, null, null, esriSpatialRelEnum.esriSpatialRelUndefined,
                                                              out IGeometry sourceGeom, out IList <string> oidList);
                //找出touch的要素oid,排除掉touch的图形
                OverlayCommonTool.GetTopounionGeometryByQuery(this.TargetFeatureClass, null, sourceGeom, esriSpatialRelEnum.esriSpatialRelTouches, out IGeometry touchGeom, out IList <string> touchOIDList);
                //通过intersect查找压盖部分的要素
                string queryClause = null;
                if (touchOIDList != null && touchOIDList.Count > 0)
                {
                    queryClause = $"OBJECTID  NOT in ({string.Join(",", ((List<string>)touchOIDList).ToArray())})";
                }
                // 求取空间相交的部分
                OverlayCommonTool.GetIntersectFeaturesByQuery(this.TargetFeatureClass, queryClause, sourceGeom,
                                                              out IList <IntersectFeatureDTO> intersectFeatureDTOs, out double sumIntersectArea);

                if (intersectFeatureDTOs?.Count > 0)
                {
                    OverlayRespDTO overlayRespDTO = new OverlayRespDTO
                    {
                        SumArea = sumIntersectArea
                    };
                    foreach (var item in intersectFeatureDTOs)
                    {
                        FeatureRespDTO intersectFeatureRespDTO = new FeatureRespDTO
                        {
                            OID         = item.OID,
                            Area        = item.Area,
                            Coordinates = item.Coordinates,
                            GeoType     = item.GeoType
                        };
                        overlayRespDTO.Features.Add(intersectFeatureRespDTO);
                    }
                    Property resultProp = base.OutputParametersMeta[nameof(Result)];
                    resultProp.Value = overlayRespDTO;
                    return(new Result(EnumSystemStatusCode.DME_SUCCESS, "运行完成", EnumSystemStatusCode.DME_SUCCESS, null));
                }
            }
            else if (AnalysisType.OVERTOP == this.AnalysisType)
            {
                // 先拷贝一份mdb模板
                string sTemplate = System.AppDomain.CurrentDomain.BaseDirectory + GlobalSystemConfig.PATH_TEMPLATE_PGDB;// @"\template\pgdb.mdb";
                string sPath     = System.AppDomain.CurrentDomain.BaseDirectory + GlobalSystemConfig.DIR_TEMP + "/" + GuidUtil.NewGuid() + ".mdb";
                File.Copy(sTemplate, sPath);
                IWorkspace mdbWorkspace = WorkspaceUtil.OpenMdbWorspace(sPath);
                if (FeatureClassUtil.ExportToWorkspace(this.SourceFeatureClass, mdbWorkspace))
                {
                    // 获取导出的临时要素类信息
                    IFeatureClass tempExpFeatureClass = WorkspaceUtil.GetFeatureClass(mdbWorkspace, this.sourceFeatureClassDTO.Name);
                    // 进行擦除操作
                    OverlayCommonTool.Erase(tempExpFeatureClass, this.TargetFeatureClass);
                    // 计算完保存结果,如何保存?
                    if (tempExpFeatureClass != null)
                    {
                        OverlayRespDTO overlayRespDTO = new OverlayRespDTO();
                        // 总面积
                        double         sumArea        = 0;
                        IFeatureCursor pFeatureCursor = tempExpFeatureClass.Search(null, false);
                        IFeature       pFeature       = null;
                        //获得“Area”字段
                        //IFields fields = pFeatureCursor.Fields;
                        //int areaIndex = fields.FindField("Area");
                        while ((pFeature = pFeatureCursor.NextFeature()) != null)
                        {
                            double area = ((IArea)pFeature.Shape).Area;// (double)pFeature.get_Value(areaIndex);
                            sumArea += area;
                            FeatureRespDTO featureRespDTO = new FeatureRespDTO
                            {
                                OID         = pFeature.OID,
                                Area        = area,
                                Coordinates = GeometryUtil.ConvertGeometryToJson(pFeature.Shape, out string msg)
                            };
                            overlayRespDTO.Features.Add(featureRespDTO);
                            pFeature = pFeatureCursor.NextFeature();
                        }
                        overlayRespDTO.SumArea = sumArea;
                        Property resultProp = base.OutputParametersMeta[nameof(Result)];
                        resultProp.Value = overlayRespDTO;
                        return(new Result(EnumSystemStatusCode.DME_SUCCESS, "运行完成", EnumSystemStatusCode.DME_SUCCESS, null));
                    }
                }
                // 删除临时文件
                if (IsClearTemp && File.Exists(sPath))
                {
                    File.Delete(sPath);
                }
            }
            else
            {
                throw new BusinessException((int)EnumSystemStatusCode.DME_FAIL, "分析类型不匹配");
            }

            return(new Result(EnumSystemStatusCode.DME_SUCCESS, "运行完成,但没有运算结果", EnumSystemStatusCode.DME_SUCCESS, null));
        }
Exemple #11
0
 public override IFeatureClass GetFeatureClass(IWorkspace workspace, string featureClassName)
 {
     return(WorkspaceUtil.GetFeatureClass(workspace, featureClassName));
 }
Exemple #12
0
 public override IWorkspace Open(OracleConn conn)
 {
     return(WorkspaceUtil.OpenSdeWorkspace(conn.Username, conn.Password, conn.Server));
 }