Example #1
0
 public Move(DateTime timestamp, PartialGisDataset oldDataset, PartialGisDataset?newDataset,
             PartialGisDataset?replacementDataset = null, string replacementLayerFilePath = null,
             string remarks = null)
 {
     Timestamp                = timestamp;
     OldDataset               = oldDataset;
     NewDataset               = newDataset;
     ReplacementDataset       = replacementDataset;
     ReplacementLayerFilePath = string.IsNullOrWhiteSpace(replacementLayerFilePath) ? null : replacementLayerFilePath;
     Remarks = string.IsNullOrWhiteSpace(remarks) ? null : remarks;
 }
Example #2
0
        private bool IsWorkspaceMatch(GisDataset dataset, PartialGisDataset moveFrom)
        {
            // Assumes workspace paths in moves do not have volume information
            string movePath = moveFrom.Workspace.Folder;
            string fullPath = dataset.Workspace.WithoutVolume;

            // TODO: The WorkspaceProgId from map data may have a ".1" (or other number?) suffix  (everything in Theme Manager ends in '.1')
            if (moveFrom.WorkspaceProgId != null && moveFrom.WorkspaceProgId == dataset.WorkspaceProgId)
            {
                return(false);
            }
            return(string.Compare(fullPath, movePath, StringComparison.OrdinalIgnoreCase) == 0);
        }
Example #3
0
        private bool IsPartialWorkspaceMatch(GisDataset dataset, PartialGisDataset moveFrom)
        {
            // A partial workspace match (i.e. the current or an ancestral folder has moved) is only valid
            // if the moveFrom.DatasourceName is null; if not null, then we must do a DataSourceMatch
            if (moveFrom.DatasourceName != null)
            {
                return(false);
            }
            // Assumes workspace paths in moves do not have volume information
            string movePath = moveFrom.Workspace.Folder;
            string fullPath = dataset.Workspace.WithoutVolume;

            // Just searching for oldPath somewhere in newPath could yield some false positives.
            // Instead, strip the volume and only match the beginning of the string
            return(fullPath.StartsWith(movePath, StringComparison.OrdinalIgnoreCase));
        }
Example #4
0
 private bool IsDataSourceMatch(GisDataset dataset, PartialGisDataset moveFrom)
 {
     if (dataset.DatasourceName == null)
     {
         return(false);
     }
     if (moveFrom.DatasourceName == null)
     {
         return(false);
     }
     if (String.Compare(dataset.DatasourceName, moveFrom.DatasourceName, StringComparison.OrdinalIgnoreCase) != 0)
     {
         return(false);
     }
     if (moveFrom.DatasourceType != null && moveFrom.DatasourceType != dataset.DatasourceType)
     {
         return(false);
     }
     return(IsWorkspaceMatch(dataset, moveFrom));
 }
Example #5
0
            private PartialGisDataset?PatchDataset(GisDataset source, PartialGisDataset newDataset)
            {
                //A partial dataset must have a fully specified workspace, but a move may describe a parent folder
                //This method patches the new dataset by applying the move to the source workspace
                //The workspace in the move's old dataset must be a prefix of the input source for this method to return a non-null result

                var searchString           = OldDataset.Workspace.Folder;
                int positionOfSearchString = source.Workspace.Folder.IndexOf(searchString, StringComparison.OrdinalIgnoreCase);

                if (positionOfSearchString < 0)
                {
                    return(null);
                }
                var newWorkspace = source.Workspace.Folder.Substring(0, positionOfSearchString) +
                                   newDataset.Workspace.Folder +
                                   source.Workspace.Folder.Substring(positionOfSearchString + searchString.Length);

                return(new PartialGisDataset(
                           newWorkspace,
                           newDataset.WorkspaceProgId,
                           newDataset.DatasourceName,
                           newDataset.DatasourceType
                           ));
            }
Example #6
0
        public Moves(string csvPath, char delimiter = '|', bool check = false)
        {
            const int fieldCount = 15;
            int       lineNum    = 0;

            //This is a very simple CSV parser, as the input is very simple.
            //The constructor is very forgiving on the input.  It ignores any record which isn't valid.  It doesn't throw any exceptions
            //It may contain an empty list of moves, which will is dealt with appropriately
            //The csv file used for input should be validated whenever it is edited.
            //Validation rules:
            //   Each row must have 15 fields; row is split on delimiter ('|') which must not appear in a field.
            //   Each row requires a "timestamp" in the first field, and the timestamp must be ordered from oldest to newest
            //   There must be an old workspace path in the 2nd column.
            //   Workspace paths must not have volume information
            //   Column 3 if provided must be a valid esri WorkspaceFactoryProgId
            //   Column 5 if provided must be a valid esriDatasetType
            //   Replacement datasets are not supported - use replacement layer file
            //   New and old datasets must not differ in workspace type or dataset type - use replacement layer file
            //   If newDataset is null (i.e old is deleted), trash or archive, then a replacement layer file should be provided.
            //      A remark is all that is mandatory when newDataset is null.
            //   Column 2 and 6 must be empty or a valid esri WorkspaceFactoryProgId string.
            //   Columns 4 and 8 must be empty or a valid esriDatasetType string.
            //   workspace changes (i.e. dataSourceName is null) should be exclusive.
            //      i.e. if there is a move /a/b => /x/y, we should not have /a/b/c => ...

            try
            {
                DateTime previousTimestamp = DateTime.MinValue;
                foreach (string line in File.ReadLines(csvPath))
                {
                    lineNum += 1;
                    var row = line.Split(delimiter);
                    if (row.Length != fieldCount)
                    {
                        if (check)
                        {
                            Console.WriteLine($"Warning: Wrong number of columns ({row.Length} not {fieldCount}) at line {lineNum}; Skipping.");
                        }
                        continue;
                    }
                    if (lineNum == 1 && row[0] == "timestamp")
                    {
                        // Skip a header row if present
                        continue;
                    }

                    if (!DateTime.TryParse(row[0], out DateTime timestamp))
                    {
                        if (check)
                        {
                            Console.WriteLine($"Warning: Value in column #1 ({row[0]}) at line {lineNum} is not a DateTime; Skipping.");
                        }
                        continue;
                    }
                    if (timestamp < previousTimestamp)
                    {
                        if (check)
                        {
                            Console.WriteLine($"Warning: Timestamp in column #1 must be increasing. Line {lineNum} is out of order; Skipping.");
                        }
                        continue;
                    }
                    previousTimestamp = timestamp;

                    if (string.IsNullOrWhiteSpace(row[1]))
                    {
                        if (check)
                        {
                            Console.WriteLine($"Warning: No value provided for column #2 (Old Workspace Path) at line {lineNum}; Skipping.");
                        }
                        continue;
                    }
                    else if (!IsSimpleRelativePath(row[1]))
                    {
                        if (check)
                        {
                            Console.WriteLine($"Warning: Value in column #1 ({row[1]}) at line {lineNum} is not a simple relative path; Skipping.");
                        }
                        continue;
                    }
                    if (!string.IsNullOrWhiteSpace(row[4]) && !IsEsriDatasetType(row[4]))
                    {
                        if (check)
                        {
                            Console.WriteLine($"Warning: Value in column #5 ({row[4]}) at line {lineNum} is not an esriDatasetType; Skipping.");
                        }
                        continue;
                    }

                    if (!string.IsNullOrWhiteSpace(row[2]) && !IsWorkspaceFactoryProgId(row[2]))
                    {
                        if (check)
                        {
                            Console.WriteLine($"Warning: Value in column #3 ({row[2]}) at line {lineNum} is not an esriProgID; Skipping.");
                        }
                        continue;
                    }

                    var oldDataset = new PartialGisDataset(row[1], row[2], row[3], row[4]);

                    PartialGisDataset?newDataset = null;
                    if (!string.IsNullOrWhiteSpace(row[5]))
                    {
                        if (!IsSimpleRelativePath(row[5]))
                        {
                            if (check)
                            {
                                Console.WriteLine($"Warning: Value in column #6 ({row[5]}) at line {lineNum} is not a simple relative path; Skipping.");
                            }
                            continue;
                        }
                        if (!string.IsNullOrWhiteSpace(row[6]) && row[2] != row[6])
                        {
                            if (check)
                            {
                                Console.WriteLine($"Warning: Column #7 does not match column #3 at line {lineNum} (new_workspace_type = {row[6]} <> old_workspace_type = {row[2]}); Skipping.");
                            }
                            continue;
                        }
                        // We do not need to check that row[6] is a progID, because it must be null or the same as row[2], which has already been checked.
                        if (!string.IsNullOrWhiteSpace(row[8]))
                        {
                            if (!IsEsriDatasetType(row[8]))
                            {
                                if (check)
                                {
                                    Console.WriteLine($"Warning: Value in column #9 ({row[8]}) at line {lineNum} is not an esriDatasetType; Skipping.");
                                }
                                continue;
                            }
                            if (row[4] != row[8])
                            {
                                if (check)
                                {
                                    Console.WriteLine($"Warning: Column #9 does not match column #5 at line {lineNum} (new_dataset_type = {row[8]} <> old_dataset_type = {row[4]}); Skipping.");
                                }
                                continue;
                            }
                        }
                        newDataset = new PartialGisDataset(row[5], row[6], row[7], row[8]);
                    }

                    // replacement data source is not supported, so we ignore row[9] to row[12]
                    if (check)
                    {
                        if (!string.IsNullOrWhiteSpace(row[9]) || !string.IsNullOrWhiteSpace(row[10]) ||
                            !string.IsNullOrWhiteSpace(row[11]) || !string.IsNullOrWhiteSpace(row[12]))
                        {
                            Console.WriteLine($"Warning: Values in columns 10 to 13 (Replacement datasets) at line {lineNum} are not supported; Using null for replacement dataset.");
                        }
                    }

                    var layerFile = string.IsNullOrWhiteSpace(row[13]) ? null : row[13].Trim();
                    if (layerFile != null)
                    {
                        if (!IsSimilarToLayerFile(layerFile))
                        {
                            if (check)
                            {
                                Console.WriteLine($"Warning: Value in column #14 ({layerFile}) at line {lineNum} is not a valid layer file; Skipping.");
                            }
                            continue;
                        }
                    }

                    var remarks = string.IsNullOrWhiteSpace(row[14]) ? null : row[14].Trim();

                    if (newDataset == null && layerFile == null && remarks == null)
                    {
                        if (check)
                        {
                            Console.WriteLine($"Warning: Incomplete move at line {lineNum}. Neither a new dataset (column #6), nor a replacement layer file (column #14), nor a remark (column #15) was provided; Skipping.");
                        }
                        continue;
                    }
                    if (check)
                    {
                        if ((newDataset == null || newDataset.Value.Workspace.IsInTrash || newDataset.Value.Workspace.IsInArchive) && layerFile == null)
                        {
                            Console.WriteLine($"Warning: A value in column #14 (replacement_layerFile_path) at line {lineNum} is STRONGLY encouraged when column #5-8 (new_dataset) is null or in the Trash/Archive.");
                        }
                    }

                    _moves.Add(new Move(timestamp, oldDataset, newDataset, null, layerFile, remarks));
                }
                if (check)
                {
                    Console.WriteLine($"Scanned {lineNum} lines. Found {_moves.Count} moves.");
                    Console.WriteLine("Checking consistency of moves");
                    ConsistencyCheck(_moves);
                    Console.WriteLine("Done.");
                }
            }
            catch (Exception e)
            {
                if (check)
                {
                    Console.WriteLine($"Aborting due to error at line {lineNum}: {e.Message}.");
                }
            }
        }