Merge branch 'iar-merge'

Conflicts:
	OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiveReadRequest.cs
	OpenSim/Region/CoreModules/Avatar/Inventory/Archiver/InventoryArchiverModule.cs
prebuild-update
Justin Clark-Casey (justincc) 2010-08-04 20:56:52 +01:00
commit a133acbd5f
6 changed files with 167 additions and 88 deletions

View File

@ -27,6 +27,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Text;
using OpenMetaverse; using OpenMetaverse;
namespace OpenSim.Framework.Serialization namespace OpenSim.Framework.Serialization
@ -172,5 +173,29 @@ namespace OpenSim.Framework.Serialization
{ {
return OBJECTS_PATH + CreateOarObjectFilename(objectName, uuid, pos); return OBJECTS_PATH + CreateOarObjectFilename(objectName, uuid, pos);
} }
/// <summary>
/// Extract a plain path from an IAR path
/// </summary>
/// <param name="iarPath"></param>
/// <returns></returns>
public static string ExtractPlainPathFromIarPath(string iarPath)
{
List<string> plainDirs = new List<string>();
string[] iarDirs = iarPath.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
foreach (string iarDir in iarDirs)
{
if (!iarDir.Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR))
plainDirs.Add(iarDir);
int i = iarDir.LastIndexOf(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR);
plainDirs.Add(iarDir.Remove(i));
}
return string.Join("/", plainDirs.ToArray());
}
} }
} }

View File

@ -55,6 +55,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
private UserAccount m_userInfo; private UserAccount m_userInfo;
private string m_invPath; private string m_invPath;
/// <summary>
/// Do we want to merge this load with existing inventory?
/// </summary>
protected bool m_merge;
/// <value> /// <value>
/// We only use this to request modules /// We only use this to request modules
/// </value> /// </value>
@ -66,19 +71,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
private Stream m_loadStream; private Stream m_loadStream;
public InventoryArchiveReadRequest( public InventoryArchiveReadRequest(
Scene scene, UserAccount userInfo, string invPath, string loadPath) Scene scene, UserAccount userInfo, string invPath, string loadPath, bool merge)
: this( : this(
scene, scene,
userInfo, userInfo,
invPath, invPath,
new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress)) new GZipStream(ArchiveHelpers.GetStream(loadPath), CompressionMode.Decompress),
merge)
{ {
} }
public InventoryArchiveReadRequest( public InventoryArchiveReadRequest(
Scene scene, UserAccount userInfo, string invPath, Stream loadStream) Scene scene, UserAccount userInfo, string invPath, Stream loadStream, bool merge)
{ {
m_scene = scene; m_scene = scene;
m_merge = merge;
m_userInfo = userInfo; m_userInfo = userInfo;
m_invPath = invPath; m_invPath = invPath;
m_loadStream = loadStream; m_loadStream = loadStream;
@ -91,7 +98,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
/// A list of the inventory nodes loaded. If folders were loaded then only the root folders are /// A list of the inventory nodes loaded. If folders were loaded then only the root folders are
/// returned /// returned
/// </returns> /// </returns>
public List<InventoryNodeBase> Execute() public HashSet<InventoryNodeBase> Execute()
{ {
try try
{ {
@ -100,7 +107,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
int failedAssetRestores = 0; int failedAssetRestores = 0;
int successfulItemRestores = 0; int successfulItemRestores = 0;
List<InventoryNodeBase> loadedNodes = new List<InventoryNodeBase>(); HashSet<InventoryNodeBase> loadedNodes = new HashSet<InventoryNodeBase>();
List<InventoryFolderBase> folderCandidates List<InventoryFolderBase> folderCandidates
= InventoryArchiveUtils.FindFolderByPath( = InventoryArchiveUtils.FindFolderByPath(
@ -158,9 +165,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
{ {
successfulItemRestores++; successfulItemRestores++;
// If we're loading an item directly into the given destination folder then we need to record // If we aren't loading the folder containing the item then well need to update the
// it separately from any loaded root folders // viewer separately for that item.
if (rootDestinationFolder == foundFolder) if (!loadedNodes.Contains(foundFolder))
loadedNodes.Add(item); loadedNodes.Add(item);
} }
} }
@ -205,14 +212,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
string iarPath, string iarPath,
InventoryFolderBase rootDestFolder, InventoryFolderBase rootDestFolder,
Dictionary <string, InventoryFolderBase> resolvedFolders, Dictionary <string, InventoryFolderBase> resolvedFolders,
List<InventoryNodeBase> loadedNodes) HashSet<InventoryNodeBase> loadedNodes)
{ {
string iarPathExisting = iarPath; string iarPathExisting = iarPath;
// m_log.DebugFormat( // m_log.DebugFormat(
// "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID); // "[INVENTORY ARCHIVER]: Loading folder {0} {1}", rootDestFolder.Name, rootDestFolder.ID);
InventoryFolderBase destFolder = ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders); InventoryFolderBase destFolder
= ResolveDestinationFolder(rootDestFolder, ref iarPathExisting, resolvedFolders);
// m_log.DebugFormat( // m_log.DebugFormat(
// "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]", // "[INVENTORY ARCHIVER]: originalArchivePath [{0}], section already loaded [{1}]",
@ -251,22 +259,35 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
{ {
// string originalArchivePath = archivePath; // string originalArchivePath = archivePath;
InventoryFolderBase destFolder = null; while (archivePath.Length > 0)
if (archivePath.Length > 0)
{ {
while (null == destFolder && archivePath.Length > 0) m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath);
{
// m_log.DebugFormat("[INVENTORY ARCHIVER]: Trying to resolve destination folder {0}", archivePath);
if (resolvedFolders.ContainsKey(archivePath)) if (resolvedFolders.ContainsKey(archivePath))
{ {
// m_log.DebugFormat( // m_log.DebugFormat(
// "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath); // "[INVENTORY ARCHIVER]: Found previously created folder from archive path {0}", archivePath);
destFolder = resolvedFolders[archivePath]; return resolvedFolders[archivePath];
} }
else else
{ {
if (m_merge)
{
// TODO: Using m_invPath is totally wrong - what we need to do is strip the uuid from the
// iar name and try to find that instead.
string plainPath = ArchiveConstants.ExtractPlainPathFromIarPath(archivePath);
List<InventoryFolderBase> folderCandidates
= InventoryArchiveUtils.FindFolderByPath(
m_scene.InventoryService, m_userInfo.PrincipalID, plainPath);
if (folderCandidates.Count != 0)
{
InventoryFolderBase destFolder = folderCandidates[0];
resolvedFolders[archivePath] = destFolder;
return destFolder;
}
}
// Don't include the last slash so find the penultimate one // Don't include the last slash so find the penultimate one
int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2); int penultimateSlashIndex = archivePath.LastIndexOf("/", archivePath.Length - 2);
@ -281,16 +302,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
// "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}", // "[INVENTORY ARCHIVER]: Found no previously created folder for archive path {0}",
// originalArchivePath); // originalArchivePath);
archivePath = string.Empty; archivePath = string.Empty;
destFolder = rootDestFolder; return rootDestFolder;
}
} }
} }
} }
if (null == destFolder) return rootDestFolder;
destFolder = rootDestFolder;
return destFolder;
} }
/// <summary> /// <summary>
@ -316,24 +333,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
string iarPathExisting, string iarPathExisting,
string iarPathToReplicate, string iarPathToReplicate,
Dictionary <string, InventoryFolderBase> resolvedFolders, Dictionary <string, InventoryFolderBase> resolvedFolders,
List<InventoryNodeBase> loadedNodes) HashSet<InventoryNodeBase> loadedNodes)
{ {
string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries); string[] rawDirsToCreate = iarPathToReplicate.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
int i = 0;
while (i < rawDirsToCreate.Length) for (int i = 0; i < rawDirsToCreate.Length; i++)
{ {
// m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]); // m_log.DebugFormat("[INVENTORY ARCHIVER]: Creating folder {0} from IAR", rawDirsToCreate[i]);
if (!rawDirsToCreate[i].Contains(ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR))
continue;
int identicalNameIdentifierIndex int identicalNameIdentifierIndex
= rawDirsToCreate[i].LastIndexOf( = rawDirsToCreate[i].LastIndexOf(
ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR); ArchiveConstants.INVENTORY_NODE_NAME_COMPONENT_SEPARATOR);
if (identicalNameIdentifierIndex < 0)
{
i++;
continue;
}
string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex); string newFolderName = rawDirsToCreate[i].Remove(identicalNameIdentifierIndex);
newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName); newFolderName = InventoryArchiveUtils.UnescapeArchivePath(newFolderName);
@ -356,8 +370,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (0 == i) if (0 == i)
loadedNodes.Add(destFolder); loadedNodes.Add(destFolder);
i++;
} }
} }

View File

@ -241,10 +241,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (CheckPresence(userInfo.PrincipalID)) if (CheckPresence(userInfo.PrincipalID))
{ {
InventoryArchiveReadRequest request; InventoryArchiveReadRequest request;
bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
try try
{ {
request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream); request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadStream, merge);
} }
catch (EntryPointNotFoundException e) catch (EntryPointNotFoundException e)
{ {
@ -285,10 +286,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (CheckPresence(userInfo.PrincipalID)) if (CheckPresence(userInfo.PrincipalID))
{ {
InventoryArchiveReadRequest request; InventoryArchiveReadRequest request;
bool merge = (options.ContainsKey("merge") ? (bool)options["merge"] : false);
try try
{ {
request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath); request = new InventoryArchiveReadRequest(m_aScene, userInfo, invPath, loadPath, merge);
} }
catch (EntryPointNotFoundException e) catch (EntryPointNotFoundException e)
{ {
@ -334,7 +336,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
if (mainParams.Count < 6) if (mainParams.Count < 6)
{ {
m_log.Error( m_log.Error(
"[INVENTORY ARCHIVER]: usage is load iar <first name> <last name> <inventory path> <user password> [<load file path>]"); "[INVENTORY ARCHIVER]: usage is load iar [--merge] <first name> <last name> <inventory path> <user password> [<load file path>]");
return; return;
} }
@ -469,7 +471,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
/// Notify the client of loaded nodes if they are logged in /// Notify the client of loaded nodes if they are logged in
/// </summary> /// </summary>
/// <param name="loadedNodes">Can be empty. In which case, nothing happens</param> /// <param name="loadedNodes">Can be empty. In which case, nothing happens</param>
private void UpdateClientWithLoadedNodes(UserAccount userInfo, List<InventoryNodeBase> loadedNodes) private void UpdateClientWithLoadedNodes(UserAccount userInfo, HashSet<InventoryNodeBase> loadedNodes)
{ {
if (loadedNodes.Count == 0) if (loadedNodes.Count == 0)
return; return;

View File

@ -629,7 +629,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene); UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene);
Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>(); Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>();
List<InventoryNodeBase> nodesLoaded = new List<InventoryNodeBase>(); HashSet<InventoryNodeBase> nodesLoaded = new HashSet<InventoryNodeBase>();
string folder1Name = "1"; string folder1Name = "1";
string folder2aName = "2a"; string folder2aName = "2a";
@ -644,7 +644,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
{ {
// Test replication of path1 // Test replication of path1
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
.ReplicateArchivePathToUserInventory( .ReplicateArchivePathToUserInventory(
iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID), iarPath1, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
foldersCreated, nodesLoaded); foldersCreated, nodesLoaded);
@ -661,7 +661,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
{ {
// Test replication of path2 // Test replication of path2
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
.ReplicateArchivePathToUserInventory( .ReplicateArchivePathToUserInventory(
iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID), iarPath2, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
foldersCreated, nodesLoaded); foldersCreated, nodesLoaded);
@ -707,10 +707,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName }); string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null) new InventoryArchiveReadRequest(scene, ua1, null, (Stream)null, false)
.ReplicateArchivePathToUserInventory( .ReplicateArchivePathToUserInventory(
itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID), itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
new Dictionary<string, InventoryFolderBase>(), new List<InventoryNodeBase>()); new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
List<InventoryFolderBase> folder1PostCandidates List<InventoryFolderBase> folder1PostCandidates
= InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName); = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
@ -732,5 +732,45 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
= InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b"); = InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1Post, "b");
Assert.That(folder2PostCandidates.Count, Is.EqualTo(1)); Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
} }
/// <summary>
/// Test replication of a partly existing archive path to the user's inventory. This should create
/// a merged path.
/// </summary>
[Test]
public void TestMergeIarPath()
{
TestHelper.InMethod();
log4net.Config.XmlConfigurator.Configure();
Scene scene = SceneSetupHelpers.SetupScene("inventory");
UserAccount ua1 = UserProfileTestUtils.CreateUserWithInventory(scene);
string folder1ExistingName = "a";
string folder2Name = "b";
InventoryFolderBase folder1
= UserInventoryTestUtils.CreateInventoryFolder(
scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
string folder1ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder1ExistingName, UUID.Random());
string folder2ArchiveName = InventoryArchiveWriteRequest.CreateArchiveFolderName(folder2Name, UUID.Random());
string itemArchivePath = string.Join("", new string[] { folder1ArchiveName, folder2ArchiveName });
new InventoryArchiveReadRequest(scene, ua1, folder1ExistingName, (Stream)null, true)
.ReplicateArchivePathToUserInventory(
itemArchivePath, scene.InventoryService.GetRootFolder(ua1.PrincipalID),
new Dictionary<string, InventoryFolderBase>(), new HashSet<InventoryNodeBase>());
List<InventoryFolderBase> folder1PostCandidates
= InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, ua1.PrincipalID, folder1ExistingName);
Assert.That(folder1PostCandidates.Count, Is.EqualTo(1));
Assert.That(folder1PostCandidates[0].ID, Is.EqualTo(folder1.ID));
List<InventoryFolderBase> folder2PostCandidates
= InventoryArchiveUtils.FindFolderByPath(scene.InventoryService, folder1PostCandidates[0], "b");
Assert.That(folder2PostCandidates.Count, Is.EqualTo(1));
}
} }
} }

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *
@ -173,16 +173,16 @@ namespace OpenSim.Region.CoreModules.Framework.Library
m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName); m_log.InfoFormat("[LIBRARY MODULE]: Loading library archive {0} ({1})...", iarFileName, simpleName);
simpleName = GetInventoryPathFromName(simpleName); simpleName = GetInventoryPathFromName(simpleName);
InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName); InventoryArchiveReadRequest archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, simpleName, iarFileName, false);
try try
{ {
List<InventoryNodeBase> nodes = archread.Execute(); HashSet<InventoryNodeBase> nodes = archread.Execute();
if (nodes != null && nodes.Count == 0) if (nodes != null && nodes.Count == 0)
{ {
// didn't find the subfolder with the given name; place it on the top // didn't find the subfolder with the given name; place it on the top
m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName); m_log.InfoFormat("[LIBRARY MODULE]: Didn't find {0} in library. Placing archive on the top level", simpleName);
archread.Close(); archread.Close();
archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName); archread = new InventoryArchiveReadRequest(m_MockScene, uinfo, "/", iarFileName, false);
archread.Execute(); archread.Execute();
} }
foreach (InventoryNodeBase node in nodes) foreach (InventoryNodeBase node in nodes)

View File

@ -1,4 +1,4 @@
/* /*
* Copyright (c) Contributors, http://opensimulator.org/ * Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders. * See CONTRIBUTORS.TXT for a full list of copyright holders.
* *