Beispiel #1
0
        private static string ResolveMappingLocalPath(DefinitionWorkspaceMapping definitionMapping, string sourcesDirectory)
        {
            string relativePath =
                (definitionMapping.LocalPath ?? string.Empty)
                .Trim('/', '\\');

            if (Path.DirectorySeparatorChar == '\\')
            {
                relativePath = relativePath.Replace('/', Path.DirectorySeparatorChar);
            }
            else
            {
                relativePath = relativePath.Replace('\\', Path.DirectorySeparatorChar);
            }

            return(Path.Combine(sourcesDirectory, relativePath));
        }
Beispiel #2
0
            public static ITfsVCWorkspace MatchExactWorkspace(
                IExecutionContext executionContext,
                ITfsVCWorkspace[] tfWorkspaces,
                string name,
                DefinitionWorkspaceMapping[] definitionMappings,
                string sourcesDirectory)
            {
                ArgUtil.NotNullOrEmpty(name, nameof(name));
                ArgUtil.NotNullOrEmpty(sourcesDirectory, nameof(sourcesDirectory));

                // Short-circuit early if the sources directory is empty.
                //
                // Consider the sources directory to be empty if it only contains a .tf directory exists. This can
                // indicate the workspace is in a corrupted state and the tf commands (e.g. status) will not return
                // reliable information. An easy way to reproduce this is to delete the workspace directory, then
                // run "tf status" on that workspace. The .tf directory will be recreated but the contents will be
                // in a corrupted state.
                if (!Directory.Exists(sourcesDirectory) ||
                    !Directory.EnumerateFileSystemEntries(sourcesDirectory).Any(x => !x.EndsWith($"{Path.DirectorySeparatorChar}.tf")))
                {
                    executionContext.Debug("Sources directory does not exist or is empty.");
                    return(null);
                }

                string machineName = Environment.MachineName;

                executionContext.Debug($"Attempting to find a workspace: '{name}'");
                foreach (ITfsVCWorkspace tfWorkspace in tfWorkspaces ?? new ITfsVCWorkspace[0])
                {
                    // Compare the workspace name.
                    if (!string.Equals(tfWorkspace.Name, name, StringComparison.Ordinal))
                    {
                        executionContext.Debug($"Skipping workspace: '{tfWorkspace.Name}'");
                        continue;
                    }

                    executionContext.Debug($"Candidate workspace: '{tfWorkspace.Name}'");

                    // Compare the machine name.
                    if (!string.Equals(tfWorkspace.Computer, machineName, StringComparison.Ordinal))
                    {
                        executionContext.Debug($"Expected computer name: '{machineName}'. Actual: '{tfWorkspace.Computer}'");
                        continue;
                    }

                    // Compare the number of mappings.
                    if ((tfWorkspace.Mappings?.Length ?? 0) != (definitionMappings?.Length ?? 0))
                    {
                        executionContext.Debug($"Expected number of mappings: '{definitionMappings?.Length ?? 0}'. Actual: '{tfWorkspace.Mappings?.Length ?? 0}'");
                        continue;
                    }

                    // Sort the definition mappings.
                    List <DefinitionWorkspaceMapping> sortedDefinitionMappings =
                        (definitionMappings ?? new DefinitionWorkspaceMapping[0])
                        .OrderBy(x => x.MappingType != DefinitionMappingType.Cloak) // Cloaks first
                        .ThenBy(x => !x.Recursive)                                  // Then recursive maps
                        .ThenBy(x => x.NormalizedServerPath)                        // Then sort by the normalized server path
                        .ToList();
                    for (int i = 0; i < sortedDefinitionMappings.Count; i++)
                    {
                        DefinitionWorkspaceMapping mapping = sortedDefinitionMappings[i];
                        executionContext.Debug($"Definition mapping[{i}]: cloak '{mapping.MappingType == DefinitionMappingType.Cloak}', recursive '{mapping.Recursive}', server path '{mapping.NormalizedServerPath}', local path '{mapping.GetRootedLocalPath(sourcesDirectory)}'");
                    }

                    // Sort the TF mappings.
                    List <ITfsVCMapping> sortedTFMappings =
                        (tfWorkspace.Mappings ?? new ITfsVCMapping[0])
                        .OrderBy(x => !x.Cloak)    // Cloaks first
                        .ThenBy(x => !x.Recursive) // Then recursive maps
                        .ThenBy(x => x.ServerPath) // Then sort by server path
                        .ToList();
                    for (int i = 0; i < sortedTFMappings.Count; i++)
                    {
                        ITfsVCMapping mapping = sortedTFMappings[i];
                        executionContext.Debug($"Found mapping[{i}]: cloak '{mapping.Cloak}', recursive '{mapping.Recursive}', server path '{mapping.ServerPath}', local path '{mapping.LocalPath}'");
                    }

                    // Compare the mappings.
                    bool allMatch = true;
                    for (int i = 0; i < sortedTFMappings.Count; i++)
                    {
                        ITfsVCMapping tfMapping = sortedTFMappings[i];
                        DefinitionWorkspaceMapping definitionMapping = sortedDefinitionMappings[i];

                        // Compare the cloak flag.
                        bool expectedCloak = definitionMapping.MappingType == DefinitionMappingType.Cloak;
                        if (tfMapping.Cloak != expectedCloak)
                        {
                            executionContext.Debug($"Expected mapping[{i}] cloak: '{expectedCloak}'. Actual: '{tfMapping.Cloak}'");
                            allMatch = false;
                            break;
                        }

                        // Compare the recursive flag.
                        if (!expectedCloak && tfMapping.Recursive != definitionMapping.Recursive)
                        {
                            executionContext.Debug($"Expected mapping[{i}] recursive: '{definitionMapping.Recursive}'. Actual: '{tfMapping.Recursive}'");
                            allMatch = false;
                            break;
                        }

                        // Compare the server path. Normalize the expected server path for a single-level map.
                        string expectedServerPath = definitionMapping.NormalizedServerPath;
                        if (!string.Equals(tfMapping.ServerPath, expectedServerPath, StringComparison.Ordinal))
                        {
                            executionContext.Debug($"Expected mapping[{i}] server path: '{expectedServerPath}'. Actual: '{tfMapping.ServerPath}'");
                            allMatch = false;
                            break;
                        }

                        // Compare the local path.
                        if (!expectedCloak)
                        {
                            string expectedLocalPath = definitionMapping.GetRootedLocalPath(sourcesDirectory);
                            if (!string.Equals(tfMapping.LocalPath, expectedLocalPath, StringComparison.Ordinal))
                            {
                                executionContext.Debug($"Expected mapping[{i}] local path: '{expectedLocalPath}'. Actual: '{tfMapping.LocalPath}'");
                                allMatch = false;
                                break;
                            }
                        }
                    }

                    if (allMatch)
                    {
                        executionContext.Debug("Matching workspace found.");
                        return(tfWorkspace);
                    }
                }

                executionContext.Debug("Matching workspace not found.");
                return(null);
            }
        private ITfsVCWorkspace MatchExactWorkspace(ITfsVCWorkspace[] tfWorkspaces, string name, DefinitionWorkspaceMapping[] definitionMappings, string sourcesDirectory)
        {
            ArgUtil.NotNullOrEmpty(name, nameof(name));
            ArgUtil.NotNullOrEmpty(sourcesDirectory, nameof(sourcesDirectory));

            // Short-circuit early if the sources directory is empty.
            //
            // Consider the sources directory to be empty if it only contains a .tf directory exists. This can
            // indicate the workspace is in a corrupted state and the tf commands (e.g. status) will not return
            // reliable information. An easy way to reproduce this is to delete the workspace directory, then
            // run "tf status" on that workspace. The .tf directory will be recreated but the contents will be
            // in a corrupted state.
            if (!Directory.Exists(sourcesDirectory) ||
                !Directory.EnumerateFileSystemEntries(sourcesDirectory).Any(x => !x.EndsWith($"{Path.DirectorySeparatorChar}.tf")))
            {
                Trace.Info($"Sources directory does not exist or is empty.");
                return null;
            }

            string machineName = Environment.MachineName;
            Trace.Info("Attempting to find a matching workspace.");
            Trace.Info($"Expected workspace name '{name}', machine name '{machineName}', number of mappings '{definitionMappings?.Length ?? 0}'.");
            foreach (ITfsVCWorkspace tfWorkspace in tfWorkspaces ?? new ITfsVCWorkspace[0])
            {
                // Compare the works name, machine name, and number of mappings.
                Trace.Info($"Candidate workspace name '{tfWorkspace.Name}', machine name '{tfWorkspace.Computer}', number of mappings '{tfWorkspace.Mappings?.Length ?? 0}'.");
                if (!string.Equals(tfWorkspace.Name, name, StringComparison.Ordinal) ||
                    !string.Equals(tfWorkspace.Computer, machineName, StringComparison.Ordinal) ||
                    (tfWorkspace.Mappings?.Length ?? 0) != (definitionMappings?.Length ?? 0))
                {
                    continue;
                }

                // TODO: Is there such a thing as a single level cloak?
                // Sort the TF mappings.
                List<ITfsVCMapping> sortedTFMappings =
                    (tfWorkspace.Mappings ?? new ITfsVCMapping[0])
                    .OrderBy(x => !x.Cloak) // Cloaks first
                    .ThenBy(x => !x.Recursive) // Then recursive maps
                    .ThenBy(x => x.ServerPath) // Then sort by server path
                    .ToList();
                sortedTFMappings.ForEach(x => Trace.Info($"TF mapping: cloak '{x.Cloak}', recursive '{x.Recursive}', server path '{x.ServerPath}', local path '{x.LocalPath}'."));

                // Sort the definition mappings.
                List<DefinitionWorkspaceMapping> sortedDefinitionMappings =
                    (definitionMappings ?? new DefinitionWorkspaceMapping[0])
                    .OrderBy(x => x.MappingType != DefinitionMappingType.Cloak) // Cloaks first
                    .ThenBy(x => !x.Recursive) // Then recursive maps
                    .ThenBy(x => x.NormalizedServerPath) // Then sort by the normalized server path
                    .ToList();
                sortedDefinitionMappings.ForEach(x => Trace.Info($"Definition mapping: cloak '{x.MappingType == DefinitionMappingType.Cloak}', recursive '{x.Recursive}', server path '{x.NormalizedServerPath}', local path '{ResolveMappingLocalPath(x, sourcesDirectory)}'."));

                // Compare the mappings,
                bool allMatch = true;
                for (int i = 0 ; i < sortedTFMappings.Count ; i++)
                {
                    ITfsVCMapping tfMapping = sortedTFMappings[i];
                    DefinitionWorkspaceMapping definitionMapping = sortedDefinitionMappings[i];
                    if (tfMapping.Cloak)
                    {
                        // The TF mapping is a cloak.

                        // Verify the definition mapping is a cloak and the server paths match.
                        if (definitionMapping.MappingType != DefinitionMappingType.Cloak ||
                            !string.Equals(tfMapping.ServerPath, definitionMapping.ServerPath, StringComparison.Ordinal))
                        {
                            allMatch = false; // Mapping comparison failed.
                            break;
                        }
                    }
                    else
                    {
                        // The TF mapping is a map.

                        // Verify the definition mapping is a map and the local paths match.
                        if (definitionMapping.MappingType != DefinitionMappingType.Map ||
                            !string.Equals(tfMapping.LocalPath, ResolveMappingLocalPath(definitionMapping, sourcesDirectory), StringComparison.Ordinal))
                        {
                            allMatch = false; // Mapping comparison failed.
                            break;
                        }

                        if (tfMapping.Recursive)
                        {
                            // The TF mapping is a recursive map.

                            // Verify the server paths match.
                            if (!string.Equals(tfMapping.ServerPath, definitionMapping.ServerPath, StringComparison.Ordinal))
                            {
                                allMatch = false; // Mapping comparison failed.
                                break;
                            }
                        }
                        else
                        {
                            // The TF mapping is a single-level map.

                            // Verify the definition mapping is a single-level map and the normalized server paths match.
                            if (definitionMapping.Recursive ||
                                !string.Equals(tfMapping.ServerPath, definitionMapping.NormalizedServerPath, StringComparison.Ordinal))
                            {
                                allMatch = false; // Mapping comparison failed.
                                break;
                            }
                        }
                    }
                }

                if (allMatch)
                {
                    Trace.Info("Matching workspace found.");
                    return tfWorkspace;
                }
            }

            Trace.Info("Matching workspace not found.");
            return null;
        }
Beispiel #4
0
        private ITfsVCWorkspace MatchExactWorkspace(ITfsVCWorkspace[] tfWorkspaces, string name, DefinitionWorkspaceMapping[] definitionMappings, string sourcesDirectory)
        {
            ArgUtil.NotNullOrEmpty(name, nameof(name));
            ArgUtil.NotNullOrEmpty(sourcesDirectory, nameof(sourcesDirectory));

            // Short-circuit early if the sources directory is empty.
            //
            // Consider the sources directory to be empty if it only contains a .tf directory exists. This can
            // indicate the workspace is in a corrupted state and the tf commands (e.g. status) will not return
            // reliable information. An easy way to reproduce this is to delete the workspace directory, then
            // run "tf status" on that workspace. The .tf directory will be recreated but the contents will be
            // in a corrupted state.
            if (!Directory.Exists(sourcesDirectory) ||
                !Directory.EnumerateFileSystemEntries(sourcesDirectory).Any(x => !x.EndsWith($"{Path.DirectorySeparatorChar}.tf")))
            {
                Trace.Info($"Sources directory does not exist or is empty.");
                return(null);
            }

            string machineName = Environment.MachineName;

            Trace.Info("Attempting to find a matching workspace.");
            Trace.Info($"Expected workspace name '{name}', machine name '{machineName}', number of mappings '{definitionMappings?.Length ?? 0}'.");
            foreach (ITfsVCWorkspace tfWorkspace in tfWorkspaces ?? new ITfsVCWorkspace[0])
            {
                // Compare the works name, machine name, and number of mappings.
                Trace.Info($"Candidate workspace name '{tfWorkspace.Name}', machine name '{tfWorkspace.Computer}', number of mappings '{tfWorkspace.Mappings?.Length ?? 0}'.");
                if (!string.Equals(tfWorkspace.Name, name, StringComparison.Ordinal) ||
                    !string.Equals(tfWorkspace.Computer, machineName, StringComparison.Ordinal) ||
                    (tfWorkspace.Mappings?.Length ?? 0) != (definitionMappings?.Length ?? 0))
                {
                    continue;
                }

                // TODO: Is there such a thing as a single level cloak?
                // Sort the TF mappings.
                List <ITfsVCMapping> sortedTFMappings =
                    (tfWorkspace.Mappings ?? new ITfsVCMapping[0])
                    .OrderBy(x => !x.Cloak)    // Cloaks first
                    .ThenBy(x => !x.Recursive) // Then recursive maps
                    .ThenBy(x => x.ServerPath) // Then sort by server path
                    .ToList();
                sortedTFMappings.ForEach(x => Trace.Info($"TF mapping: cloak '{x.Cloak}', recursive '{x.Recursive}', server path '{x.ServerPath}', local path '{x.LocalPath}'."));

                // Sort the definition mappings.
                List <DefinitionWorkspaceMapping> sortedDefinitionMappings =
                    (definitionMappings ?? new DefinitionWorkspaceMapping[0])
                    .OrderBy(x => x.MappingType != DefinitionMappingType.Cloak) // Cloaks first
                    .ThenBy(x => !x.Recursive)                                  // Then recursive maps
                    .ThenBy(x => x.NormalizedServerPath)                        // Then sort by the normalized server path
                    .ToList();
                sortedDefinitionMappings.ForEach(x => Trace.Info($"Definition mapping: cloak '{x.MappingType == DefinitionMappingType.Cloak}', recursive '{x.Recursive}', server path '{x.NormalizedServerPath}', local path '{ResolveMappingLocalPath(x, sourcesDirectory)}'."));

                // Compare the mappings,
                bool allMatch = true;
                for (int i = 0; i < sortedTFMappings.Count; i++)
                {
                    ITfsVCMapping tfMapping = sortedTFMappings[i];
                    DefinitionWorkspaceMapping definitionMapping = sortedDefinitionMappings[i];
                    if (tfMapping.Cloak)
                    {
                        // The TF mapping is a cloak.

                        // Verify the definition mapping is a cloak and the server paths match.
                        if (definitionMapping.MappingType != DefinitionMappingType.Cloak ||
                            !string.Equals(tfMapping.ServerPath, definitionMapping.ServerPath, StringComparison.Ordinal))
                        {
                            allMatch = false; // Mapping comparison failed.
                            break;
                        }
                    }
                    else
                    {
                        // The TF mapping is a map.

                        // Verify the definition mapping is a map and the local paths match.
                        if (definitionMapping.MappingType != DefinitionMappingType.Map ||
                            !string.Equals(tfMapping.LocalPath, ResolveMappingLocalPath(definitionMapping, sourcesDirectory), StringComparison.Ordinal))
                        {
                            allMatch = false; // Mapping comparison failed.
                            break;
                        }

                        if (tfMapping.Recursive)
                        {
                            // The TF mapping is a recursive map.

                            // Verify the server paths match.
                            if (!string.Equals(tfMapping.ServerPath, definitionMapping.ServerPath, StringComparison.Ordinal))
                            {
                                allMatch = false; // Mapping comparison failed.
                                break;
                            }
                        }
                        else
                        {
                            // The TF mapping is a single-level map.

                            // Verify the definition mapping is a single-level map and the normalized server paths match.
                            if (definitionMapping.Recursive ||
                                !string.Equals(tfMapping.ServerPath, definitionMapping.NormalizedServerPath, StringComparison.Ordinal))
                            {
                                allMatch = false; // Mapping comparison failed.
                                break;
                            }
                        }
                    }
                }

                if (allMatch)
                {
                    Trace.Info("Matching workspace found.");
                    return(tfWorkspace);
                }
            }

            Trace.Info("Matching workspace not found.");
            return(null);
        }
        private static string ResolveMappingLocalPath(DefinitionWorkspaceMapping definitionMapping, string sourcesDirectory)
        {
            string relativePath =
                (definitionMapping.LocalPath ?? string.Empty)
                .Trim('/', '\\');
            if (Path.DirectorySeparatorChar == '\\')
            {
                relativePath = relativePath.Replace('/', Path.DirectorySeparatorChar);
            }
            else
            {
                relativePath = relativePath.Replace('\\', Path.DirectorySeparatorChar);
            }

            return Path.Combine(sourcesDirectory, relativePath);
        }