diff options
author | Justin Clark-Casey (justincc) | 2010-06-30 00:10:44 +0100 |
---|---|---|
committer | Justin Clark-Casey (justincc) | 2010-06-30 00:10:44 +0100 |
commit | 5925aac859ee493fd7f6b10026c84a6a22626c79 (patch) | |
tree | f7584dad5efc48c29ab51ef433a014900df98a29 | |
parent | Revert "stop exceptions in setting and getting state from propogating since t... (diff) | |
download | opensim-SC_OLD-5925aac859ee493fd7f6b10026c84a6a22626c79.zip opensim-SC_OLD-5925aac859ee493fd7f6b10026c84a6a22626c79.tar.gz opensim-SC_OLD-5925aac859ee493fd7f6b10026c84a6a22626c79.tar.bz2 opensim-SC_OLD-5925aac859ee493fd7f6b10026c84a6a22626c79.tar.xz |
Add --merge switch to load iar.
When this switch is used, iar folders are merged with existing same-name user inventory folders.
This makes it a little easier to back and restore entire individual user inventories, among other things
Added unit test to check behaviour
6 files changed, 169 insertions, 90 deletions
diff --git a/OpenSim/Framework/Serialization/ArchiveConstants.cs b/OpenSim/Framework/Serialization/ArchiveConstants.cs index 475a9de..3143e3b 100644 --- a/OpenSim/Framework/Serialization/ArchiveConstants.cs +++ b/OpenSim/Framework/Serialization/ArchiveConstants.cs | |||
@@ -27,6 +27,7 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | using System.Text; | ||
30 | using OpenMetaverse; | 31 | using OpenMetaverse; |
31 | 32 | ||
32 | namespace OpenSim.Framework.Serialization | 33 | namespace OpenSim.Framework.Serialization |
@@ -171,6 +172,30 @@ namespace OpenSim.Framework.Serialization | |||
171 | public static string CreateOarObjectPath(string objectName, UUID uuid, Vector3 pos) | 172 | public static string CreateOarObjectPath(string objectName, UUID uuid, Vector3 pos) |
172 | { | 173 | { |
173 | return OBJECTS_PATH + CreateOarObjectFilename(objectName, uuid, pos); | 174 | return OBJECTS_PATH + CreateOarObjectFilename(objectName, uuid, pos); |
174 | } | 175 | } |
176 | |||
177 | /// <summary> | ||
178 | /// Extract a plain path from an IAR path | ||
179 | /// </summary> | ||
180 | /// <param name="iarPath"></param> | ||
181 | /// <returns></returns> | ||
182 | public static string ExtractPlainPathFromIarPath(string iarPath) | ||
183 | { | ||
184 | List<string> plainDirs = new List<string>(); | ||
185 | |||
186 | string[] iarDirs = iarPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); | ||
187 | |||
188 | foreach (string iarDir in iarDirs) | ||
189 | { | ||
190 | if (!iarDir.Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR)) | ||
191 | plainDirs.Add(iarDir); | ||
192 | |||
193 | int i = iarDir.LastIndexOf(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); | ||
194 | |||
195 | plainDirs.Add(iarDir.Remove(i)); | ||
196 | } | ||
197 | |||
198 | return string.Join("/", plainDirs.ToArray()); | ||
199 | } | ||
175 | } | 200 | } |
176 | } | 201 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs index 9996074..f130b3e 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs | |||
@@ -54,6 +54,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
54 | 54 | ||
55 | private UserAccount m_userInfo; | 55 | private UserAccount m_userInfo; |
56 | private string m_invPath; | 56 | private string m_invPath; |
57 | |||
58 | /// <summary> | ||
59 | /// Do we want to merge this load with existing inventory? | ||
60 | /// </summary> | ||
61 | protected bool m_merge; | ||
57 | 62 | ||
58 | /// <value> | 63 | /// <value> |
59 | /// We only use this to request modules | 64 | /// We only use this to request modules |
@@ -66,19 +71,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
66 | private Stream m_loadStream; | 71 | private Stream m_loadStream; |
67 | 72 | ||
68 | public InventoryArchiveReadRequest( | 73 | public InventoryArchiveReadRequest( |
69 | Scene scene, UserAccount userInfo, string invPath, string loadPath) | 74 | Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge) |
70 | : this( | 75 | : this( |
71 | scene, | 76 | scene, |
72 | userInfo, | 77 | userInfo, |
73 | invPath, | 78 | invPath, |
74 | new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress)) | 79 | new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress), |
80 | merge) | ||
75 | { | 81 | { |
76 | } | 82 | } |
77 | 83 | ||
78 | public InventoryArchiveReadRequest( | 84 | public InventoryArchiveReadRequest( |
79 | Scene scene, UserAccount userInfo, string invPath, Stream loadStream) | 85 | Scene scene, UserAccount userInfo, string invPath, Stream loadStream, bool merge) |
80 | { | 86 | { |
81 | m_scene = scene; | 87 | m_scene = scene; |
88 | m_merge = merge; | ||
82 | m_userInfo = userInfo; | 89 | m_userInfo = userInfo; |
83 | m_invPath = invPath; | 90 | m_invPath = invPath; |
84 | m_loadStream = loadStream; | 91 | m_loadStream = loadStream; |
@@ -91,14 +98,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
91 | /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are | 98 | /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are |
92 | /// returned | 99 | /// returned |
93 | /// </returns> | 100 | /// </returns> |
94 | public List<InventoryNodeBase> Execute() | 101 | public HashSet<InventoryNodeBase> Execute() |
95 | { | 102 | { |
96 | string filePath = "ERROR"; | 103 | string filePath = "ERROR"; |
97 | int successfulAssetRestores = 0; | 104 | int successfulAssetRestores = 0; |
98 | int failedAssetRestores = 0; | 105 | int failedAssetRestores = 0; |
99 | int successfulItemRestores = 0; | 106 | int successfulItemRestores = 0; |
100 | 107 | ||
101 | List<InventoryNodeBase> loadedNodes = new List<InventoryNodeBase>(); | 108 | HashSet<InventoryNodeBase> loadedNodes = new HashSet<InventoryNodeBase>(); |
102 | 109 | ||
103 | List<InventoryFolderBase> folderCandidates | 110 | List<InventoryFolderBase> folderCandidates |
104 | = InventoryArchiveUtils.FindFolderByPath( | 111 | = InventoryArchiveUtils.FindFolderByPath( |
@@ -158,9 +165,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
158 | { | 165 | { |
159 | successfulItemRestores++; | 166 | successfulItemRestores++; |
160 | 167 | ||
161 | // If we're loading an item directly into the given destination folder then we need to record | 168 | // If we aren't loading the folder containing the item then well need to update the |
162 | // it separately from any loaded root folders | 169 | // viewer separately for that item. |
163 | if (rootDestinationFolder == foundFolder) | 170 | if (!loadedNodes.Contains(foundFolder)) |
164 | loadedNodes.Add(item); | 171 | loadedNodes.Add(item); |
165 | } | 172 | } |
166 | } | 173 | } |
@@ -203,14 +210,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
203 | string iarPath, | 210 | string iarPath, |
204 | InventoryFolderBase rootDestFolder, | 211 | InventoryFolderBase rootDestFolder, |
205 | Dictionary <string, InventoryFolderBase> resolvedFolders, | 212 | Dictionary <string, InventoryFolderBase> resolvedFolders, |
206 | List<InventoryNodeBase> loadedNodes) | 213 | HashSet<InventoryNodeBase> loadedNodes) |
207 | { | 214 | { |
208 | string iarPathExisting = iarPath; | 215 | string iarPathExisting = iarPath; |
209 | 216 | ||
210 | // m_log.DebugFormat( | 217 | // m_log.DebugFormat( |
211 | // "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID); | 218 | // "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID); |
212 | 219 | ||
213 | InventoryFolderBase destFolder = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders); | 220 | InventoryFolderBase destFolder |
221 | = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders); | ||
214 | 222 | ||
215 | m_log.DebugFormat( | 223 | m_log.DebugFormat( |
216 | "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]", | 224 | "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]", |
@@ -249,46 +257,55 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
249 | { | 257 | { |
250 | string originalArchivePath = archivePath; | 258 | string originalArchivePath = archivePath; |
251 | 259 | ||
252 | InventoryFolderBase destFolder = null; | 260 | while (archivePath.Length > 0) |
253 | |||
254 | if (archivePath.Length > 0) | ||
255 | { | 261 | { |
256 | while (null == destFolder && archivePath.Length > 0) | 262 | m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath); |
263 | |||
264 | if (resolvedFolders.ContainsKey(archivePath)) | ||
257 | { | 265 | { |
258 | m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath); | 266 | m_log.DebugFormat( |
267 | "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath); | ||
268 | return resolvedFolders[archivePath]; | ||
269 | } | ||
270 | else | ||
271 | { | ||
272 | if (m_merge) | ||
273 | { | ||
274 | // TODO: Using m_invPath is totally wrong - what we need to do is strip the uuid from the | ||
275 | // iar name and try to find that instead. | ||
276 | string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath); | ||
277 | List<InventoryFolderBase> folderCandidates | ||
278 | = InventoryArchiveUtils.FindFolderByPath( | ||
279 | m_scene.InventoryService, m_userInfo.PrincipalID, plainPath); | ||
280 | |||
281 | if (folderCandidates.Count != 0) | ||
282 | { | ||
283 | InventoryFolderBase destFolder = folderCandidates[0]; | ||
284 | resolvedFolders[archivePath] = destFolder; | ||
285 | return destFolder; | ||
286 | } | ||
287 | } | ||
259 | 288 | ||
260 | if (resolvedFolders.ContainsKey(archivePath)) | 289 | // Don't include the last slash so find the penultimate one |
290 | int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2); | ||
291 | |||
292 | if (penultimateSlashIndex >= 0) | ||
261 | { | 293 | { |
262 | m_log.DebugFormat( | 294 | // Remove the last section of path so that we can see if we've already resolved the parent |
263 | "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath); | 295 | archivePath = archivePath.Remove(penultimateSlashIndex + 1); |
264 | destFolder = resolvedFolders[archivePath]; | ||
265 | } | 296 | } |
266 | else | 297 | else |
267 | { | 298 | { |
268 | // Don't include the last slash so find the penultimate one | 299 | m_log.DebugFormat( |
269 | int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2); | 300 | "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}", |
270 | 301 | originalArchivePath); | |
271 | if (penultimateSlashIndex >= 0) | 302 | archivePath = string.Empty; |
272 | { | 303 | return rootDestFolder; |
273 | // Remove the last section of path so that we can see if we've already resolved the parent | ||
274 | archivePath = archivePath.Remove(penultimateSlashIndex + 1); | ||
275 | } | ||
276 | else | ||
277 | { | ||
278 | m_log.DebugFormat( | ||
279 | "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}", | ||
280 | originalArchivePath); | ||
281 | archivePath = string.Empty; | ||
282 | destFolder = rootDestFolder; | ||
283 | } | ||
284 | } | 304 | } |
285 | } | 305 | } |
286 | } | 306 | } |
287 | 307 | ||
288 | if (null == destFolder) | 308 | return rootDestFolder; |
289 | destFolder = rootDestFolder; | ||
290 | |||
291 | return destFolder; | ||
292 | } | 309 | } |
293 | 310 | ||
294 | /// <summary> | 311 | /// <summary> |
@@ -314,24 +331,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
314 | string iarPathExisting, | 331 | string iarPathExisting, |
315 | string iarPathToReplicate, | 332 | string iarPathToReplicate, |
316 | Dictionary <string, InventoryFolderBase> resolvedFolders, | 333 | Dictionary <string, InventoryFolderBase> resolvedFolders, |
317 | List<InventoryNodeBase> loadedNodes) | 334 | HashSet<InventoryNodeBase> loadedNodes) |
318 | { | 335 | { |
319 | string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); | 336 | string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); |
320 | int i = 0; | ||
321 | 337 | ||
322 | while (i < rawDirsToCreate.Length) | 338 | for (int i = 0; i < rawDirsToCreate.Length; i++) |
323 | { | 339 | { |
324 | // m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]); | 340 | // m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]); |
325 | 341 | ||
342 | if (!rawDirsToCreate[i].Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR)) | ||
343 | continue; | ||
344 | |||
326 | int identicalNameIdentifierIndex | 345 | int identicalNameIdentifierIndex |
327 | = rawDirsToCreate[i].LastIndexOf( | 346 | = rawDirsToCreate[i].LastIndexOf( |
328 | ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); | 347 | ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); |
329 | 348 | ||
330 | if (identicalNameIdentifierIndex < 0) | ||
331 | { | ||
332 | i++; | ||
333 | continue; | ||
334 | } | ||
335 | string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); | 349 | string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); |
336 | 350 | ||
337 | newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); | 351 | newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); |
@@ -354,8 +368,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
354 | 368 | ||
355 | if (0 == i) | 369 | if (0 == i) |
356 | loadedNodes.Add(destFolder); | 370 | loadedNodes.Add(destFolder); |
357 | |||
358 | i++; | ||
359 | } | 371 | } |
360 | } | 372 | } |
361 | 373 | ||
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs index cfefbe9..668c344 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs | |||
@@ -91,12 +91,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
91 | 91 | ||
92 | scene.AddCommand( | 92 | scene.AddCommand( |
93 | this, "load iar", | 93 | this, "load iar", |
94 | "load iar <first> <last> <inventory path> <password> [<IAR path>]", | 94 | "load iar <first> <last> <inventory path> <password> [<IAR path>]", |
95 | //"load iar [--merge] <first> <last> <inventory path> <password> [<IAR path>]", | 95 | //"load iar [--merge] <first> <last> <inventory path> <password> [<IAR path>]", |
96 | "Load user inventory archive (IAR).", | 96 | "Load user inventory archive (IAR).", |
97 | //"--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones" | 97 | //"--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones" |
98 | //+ "<first> is user's first name." + Environment.NewLine | 98 | //+ "<first> is user's first name." + Environment.NewLine |
99 | "<first> is user's first name." + Environment.NewLine | 99 | "<first> is user's first name." + Environment.NewLine |
100 | + "<last> is user's last name." + Environment.NewLine | 100 | + "<last> is user's last name." + Environment.NewLine |
101 | + "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine | 101 | + "<inventory path> is the path inside the user's inventory where the IAR should be loaded." + Environment.NewLine |
102 | + "<password> is the user's password." + Environment.NewLine | 102 | + "<password> is the user's password." + Environment.NewLine |
@@ -136,16 +136,16 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
136 | if (handlerInventoryArchiveSaved != null) | 136 | if (handlerInventoryArchiveSaved != null) |
137 | handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException); | 137 | handlerInventoryArchiveSaved(id, succeeded, userInfo, invPath, saveStream, reportedException); |
138 | } | 138 | } |
139 | 139 | ||
140 | public bool ArchiveInventory( | 140 | public bool ArchiveInventory( |
141 | Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream) | 141 | Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream) |
142 | { | 142 | { |
143 | return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>()); | 143 | return ArchiveInventory(id, firstName, lastName, invPath, pass, saveStream, new Dictionary<string, object>()); |
144 | } | 144 | } |
145 | 145 | ||
146 | public bool ArchiveInventory( | 146 | public bool ArchiveInventory( |
147 | Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream, | 147 | Guid id, string firstName, string lastName, string invPath, string pass, Stream saveStream, |
148 | Dictionary<string, object> options) | 148 | Dictionary<string, object> options) |
149 | { | 149 | { |
150 | if (m_scenes.Count > 0) | 150 | if (m_scenes.Count > 0) |
151 | { | 151 | { |
@@ -184,8 +184,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
184 | } | 184 | } |
185 | 185 | ||
186 | public bool ArchiveInventory( | 186 | public bool ArchiveInventory( |
187 | Guid id, string firstName, string lastName, string invPath, string pass, string savePath, | 187 | Guid id, string firstName, string lastName, string invPath, string pass, string savePath, |
188 | Dictionary<string, object> options) | 188 | Dictionary<string, object> options) |
189 | { | 189 | { |
190 | if (m_scenes.Count > 0) | 190 | if (m_scenes.Count > 0) |
191 | { | 191 | { |
@@ -224,13 +224,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
224 | } | 224 | } |
225 | 225 | ||
226 | public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream) | 226 | public bool DearchiveInventory(string firstName, string lastName, string invPath, string pass, Stream loadStream) |
227 | { | 227 | { |
228 | return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>()); | 228 | return DearchiveInventory(firstName, lastName, invPath, pass, loadStream, new Dictionary<string, object>()); |
229 | } | 229 | } |
230 | 230 | ||
231 | public bool DearchiveInventory( | 231 | public bool DearchiveInventory( |
232 | string firstName, string lastName, string invPath, string pass, Stream loadStream, | 232 | string firstName, string lastName, string invPath, string pass, Stream loadStream, |
233 | Dictionary<string, object> options) | 233 | Dictionary<string, object> options) |
234 | { | 234 | { |
235 | if (m_scenes.Count > 0) | 235 | if (m_scenes.Count > 0) |
236 | { | 236 | { |
@@ -241,10 +241,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
241 | if (CheckPresence(userInfo.PrincipalID)) | 241 | if (CheckPresence(userInfo.PrincipalID)) |
242 | { | 242 | { |
243 | InventoryArchiveReadRequest request; | 243 | InventoryArchiveReadRequest request; |
244 | bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false); | ||
244 | 245 | ||
245 | try | 246 | try |
246 | { | 247 | { |
247 | request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream); | 248 | request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge); |
248 | } | 249 | } |
249 | catch (EntryPointNotFoundException e) | 250 | catch (EntryPointNotFoundException e) |
250 | { | 251 | { |
@@ -273,8 +274,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
273 | } | 274 | } |
274 | 275 | ||
275 | public bool DearchiveInventory( | 276 | public bool DearchiveInventory( |
276 | string firstName, string lastName, string invPath, string pass, string loadPath, | 277 | string firstName, string lastName, string invPath, string pass, string loadPath, |
277 | Dictionary<string, object> options) | 278 | Dictionary<string, object> options) |
278 | { | 279 | { |
279 | if (m_scenes.Count > 0) | 280 | if (m_scenes.Count > 0) |
280 | { | 281 | { |
@@ -285,10 +286,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
285 | if (CheckPresence(userInfo.PrincipalID)) | 286 | if (CheckPresence(userInfo.PrincipalID)) |
286 | { | 287 | { |
287 | InventoryArchiveReadRequest request; | 288 | InventoryArchiveReadRequest request; |
289 | bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false); | ||
288 | 290 | ||
289 | try | 291 | try |
290 | { | 292 | { |
291 | request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath); | 293 | request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge); |
292 | } | 294 | } |
293 | catch (EntryPointNotFoundException e) | 295 | catch (EntryPointNotFoundException e) |
294 | { | 296 | { |
@@ -322,13 +324,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
322 | /// <param name="cmdparams"></param> | 324 | /// <param name="cmdparams"></param> |
323 | protected void HandleLoadInvConsoleCommand(string module, string[] cmdparams) | 325 | protected void HandleLoadInvConsoleCommand(string module, string[] cmdparams) |
324 | { | 326 | { |
325 | m_log.Info("[INVENTORY ARCHIVER]: PLEASE NOTE THAT THIS FACILITY IS EXPERIMENTAL. BUG REPORTS WELCOME."); | 327 | m_log.Info("[INVENTORY ARCHIVER]: PLEASE NOTE THAT THIS FACILITY IS EXPERIMENTAL. BUG REPORTS WELCOME."); |
326 | 328 | ||
327 | Dictionary<string, object> options = new Dictionary<string, object>(); | 329 | Dictionary<string, object> options = new Dictionary<string, object>(); |
328 | OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; }); | 330 | OptionSet optionSet = new OptionSet().Add("m|merge", delegate (string v) { options["merge"] = v != null; }); |
329 | 331 | ||
330 | List<string> mainParams = optionSet.Parse(cmdparams); | 332 | List<string> mainParams = optionSet.Parse(cmdparams); |
331 | 333 | ||
332 | if (mainParams.Count < 6) | 334 | if (mainParams.Count < 6) |
333 | { | 335 | { |
334 | m_log.Error( | 336 | m_log.Error( |
@@ -349,7 +351,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
349 | if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath, options)) | 351 | if (DearchiveInventory(firstName, lastName, invPath, pass, loadPath, options)) |
350 | m_log.InfoFormat( | 352 | m_log.InfoFormat( |
351 | "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}", | 353 | "[INVENTORY ARCHIVER]: Loaded archive {0} for {1} {2}", |
352 | loadPath, firstName, lastName); | 354 | loadPath, firstName, lastName); |
353 | } | 355 | } |
354 | 356 | ||
355 | /// <summary> | 357 | /// <summary> |
@@ -454,7 +456,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver | |||
454 | /// Notify the client of loaded nodes if they are logged in | 456 | /// Notify the client of loaded nodes if they are logged in |
455 | /// </summary> | 457 | /// </summary> |
456 | /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param> | 458 | /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param> |
457 | private void UpdateClientWithLoadedNodes(UserAccount userInfo, List<InventoryNodeBase> loadedNodes) | 459 | private void UpdateClientWithLoadedNodes(UserAccount userInfo, HashSet<InventoryNodeBase> loadedNodes) |
458 | { | 460 | { |
459 | if (loadedNodes.Count == 0) | 461 | if (loadedNodes.Count == 0) |
460 | return; | 462 | return; |
diff --git a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs index 5130fa5..5fad0a9 100644 --- a/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs +++ b/OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/Tests/InventoryArchiverTests.cs | |||
@@ -514,7 +514,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
514 | UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); | 514 | UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); |
515 | 515 | ||
516 | Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>(); | 516 | Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>(); |
517 | List<InventoryNodeBase> nodesLoaded = new List<InventoryNodeBase>(); | 517 | HashSet<InventoryNodeBase> nodesLoaded = new HashSet<InventoryNodeBase>(); |
518 | 518 | ||
519 | string folder1Name = "1"; | 519 | string folder1Name = "1"; |
520 | string folder2aName = "2a"; | 520 | string folder2aName = "2a"; |
@@ -529,7 +529,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
529 | 529 | ||
530 | { | 530 | { |
531 | // Test replication of path1 | 531 | // Test replication of path1 |
532 | new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) | 532 | new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) |
533 | .ReplicateArchivePathToUserInventory( | 533 | .ReplicateArchivePathToUserInventory( |
534 | iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), | 534 | iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), |
535 | foldersCreated, nodesLoaded); | 535 | foldersCreated, nodesLoaded); |
@@ -546,7 +546,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
546 | 546 | ||
547 | { | 547 | { |
548 | // Test replication of path2 | 548 | // Test replication of path2 |
549 | new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) | 549 | new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) |
550 | .ReplicateArchivePathToUserInventory( | 550 | .ReplicateArchivePathToUserInventory( |
551 | iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), | 551 | iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), |
552 | foldersCreated, nodesLoaded); | 552 | foldersCreated, nodesLoaded); |
@@ -592,10 +592,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
592 | 592 | ||
593 | string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); | 593 | string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); |
594 | 594 | ||
595 | new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) | 595 | new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false) |
596 | .ReplicateArchivePathToUserInventory( | 596 | .ReplicateArchivePathToUserInventory( |
597 | itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), | 597 | itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), |
598 | new Dictionary<string, InventoryFolderBase>(), new List<InventoryNodeBase>()); | 598 | new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); |
599 | 599 | ||
600 | List<InventoryFolderBase> folder1PostCandidates | 600 | List<InventoryFolderBase> folder1PostCandidates |
601 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); | 601 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); |
@@ -617,5 +617,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests | |||
617 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); | 617 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); |
618 | Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); | 618 | Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); |
619 | } | 619 | } |
620 | |||
621 | /// <summary> | ||
622 | /// Test replication of a partly existing archive path to the user's inventory. This should create | ||
623 | /// a merged path. | ||
624 | /// </summary> | ||
625 | [Test] | ||
626 | public void TestMergeIarPath() | ||
627 | { | ||
628 | TestHelper.InMethod(); | ||
629 | log4net.Config.XmlConfigurator.Configure(); | ||
630 | |||
631 | Scene scene = SceneSetupHelpers.SetupScene("inventory"); | ||
632 | UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); | ||
633 | |||
634 | string folder1ExistingName = "a"; | ||
635 | string folder2Name = "b"; | ||
636 | |||
637 | InventoryFolderBase folder1 | ||
638 | = UserInventoryTestUtils.CreateInventoryFolder( | ||
639 | scene.InventoryService, ua1.PrincipalID, folder1ExistingName); | ||
640 | |||
641 | string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random()); | ||
642 | string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random()); | ||
643 | |||
644 | string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); | ||
645 | |||
646 | new InventoryArchiveReadRequest(scene, ua1, folder1ExistingName, (Stream)null, true) | ||
647 | .ReplicateArchivePathToUserInventory( | ||
648 | itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), | ||
649 | new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>()); | ||
650 | |||
651 | List<InventoryFolderBase> folder1PostCandidates | ||
652 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); | ||
653 | Assert.That(folder1PostCandidates.Count, Is.EqualTo(1)); | ||
654 | Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID)); | ||
655 | |||
656 | List<InventoryFolderBase> folder2PostCandidates | ||
657 | = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b"); | ||
658 | Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); | ||
659 | } | ||
620 | } | 660 | } |
621 | } \ No newline at end of file | 661 | } \ No newline at end of file |
diff --git a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs index 36dae6b..9c20d68 100644 --- a/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs +++ b/OpenSim/Region/CoreModules/Framework/Library/LibraryModule.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -173,16 +173,16 @@ namespace OpenSim.Region.CoreModules.Framework.Library | |||
173 | m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); | 173 | m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); |
174 | simpleName = GetInventoryPathFromName(simpleName); | 174 | simpleName = GetInventoryPathFromName(simpleName); |
175 | 175 | ||
176 | InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName); | 176 | InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false); |
177 | try | 177 | try |
178 | { | 178 | { |
179 | List<InventoryNodeBase> nodes = archread.Execute(); | 179 | HashSet<InventoryNodeBase> nodes = archread.Execute(); |
180 | if (nodes != null && nodes.Count == 0) | 180 | if (nodes != null && nodes.Count == 0) |
181 | { | 181 | { |
182 | // didn't find the subfolder with the given name; place it on the top | 182 | // didn't find the subfolder with the given name; place it on the top |
183 | m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); | 183 | m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); |
184 | archread.Close(); | 184 | archread.Close(); |
185 | archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName); | 185 | archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false); |
186 | archread.Execute(); | 186 | archread.Execute(); |
187 | } | 187 | } |
188 | foreach (InventoryNodeBase node in nodes) | 188 | foreach (InventoryNodeBase node in nodes) |
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs index fe71ed5..5ae6439 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LS_Api.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |