diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 39004d4028..8add2afb66 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -267,12 +267,13 @@ namespace OpenSim m_console.Commands.AddCommand("region", false, "save oar", //"save oar [-v|--version=] [-p|--profile=] []", - "save oar [-p|--profile=] []", + "save oar [-p|--profile=] [--noassets] []", "Save a region's data to an OAR archive.", // "-v|--version= generates scene objects as per older versions of the serialization (e.g. -v=0)" + Environment.NewLine - "-p|--profile= adds the url of the profile service to the saved user information" + Environment.NewLine - + "The OAR path must be a filesystem path." - + " If this is not given then the oar is saved to region.oar in the current directory.", + "-p|--profile= adds the url of the profile service to the saved user information." + Environment.NewLine + + " The OAR path must be a filesystem path." + + " If this is not given then the oar is saved to region.oar in the current directory." + Environment.NewLine + + "--noassets stops assets being saved to the OAR.", SaveOar); m_console.Commands.AddCommand("region", false, "edit scale", diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs index 597b7809e5..6a86dfe2fd 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiveWriteRequestPreparation.cs @@ -58,7 +58,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// The maximum major version of OAR that we can write. /// - public static int MAX_MAJOR_VERSION = 0; + public static int MAX_MAJOR_VERSION = 0; + + /// + /// Determine whether this oar will save assets. Default is true. + /// + public bool SaveAssets { get; set; } protected Scene m_scene; protected Stream m_saveStream; @@ -73,10 +78,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// If there was a problem opening a stream for the file specified by the savePath /// - public ArchiveWriteRequestPreparation(Scene scene, string savePath, Guid requestId) + public ArchiveWriteRequestPreparation(Scene scene, string savePath, Guid requestId) : this(scene, requestId) { - m_scene = scene; - try { m_saveStream = new GZipStream(new FileStream(savePath, FileMode.Create), CompressionMode.Compress); @@ -86,10 +89,8 @@ namespace OpenSim.Region.CoreModules.World.Archiver m_log.ErrorFormat( "[ARCHIVER]: Mismatch between Mono and zlib1g library version when trying to create compression stream." + "If you've manually installed Mono, have you appropriately updated zlib1g as well?"); - m_log.Error(e); + m_log.ErrorFormat("{0} {1}", e.Message, e.StackTrace); } - - m_requestId = requestId; } /// @@ -98,11 +99,17 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// /// The stream to which to save data. /// The id associated with this request - public ArchiveWriteRequestPreparation(Scene scene, Stream saveStream, Guid requestId) + public ArchiveWriteRequestPreparation(Scene scene, Stream saveStream, Guid requestId) : this(scene, requestId) + { + m_saveStream = saveStream; + } + + protected ArchiveWriteRequestPreparation(Scene scene, Guid requestId) { m_scene = scene; - m_saveStream = saveStream; m_requestId = requestId; + + SaveAssets = true; } /// @@ -111,22 +118,15 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// if there was an io problem with creating the file public void ArchiveRegion(Dictionary options) { + if (options.ContainsKey("noassets") && (bool)options["noassets"]) + SaveAssets = false; + try { Dictionary assetUuids = new Dictionary(); EntityBase[] entities = m_scene.GetEntities(); List sceneObjects = new List(); - - /* - foreach (ILandObject lo in m_scene.LandChannel.AllParcels()) - { - if (name == lo.LandData.Name) - { - // This is the parcel we want - } - } - */ // Filter entities so that we only have scene objects. // FIXME: Would be nicer to have this as a proper list in SceneGraph, since lots of methods @@ -141,17 +141,24 @@ namespace OpenSim.Region.CoreModules.World.Archiver sceneObjects.Add((SceneObjectGroup)entity); } } - - UuidGatherer assetGatherer = new UuidGatherer(m_scene.AssetService); - - foreach (SceneObjectGroup sceneObject in sceneObjects) + + if (SaveAssets) { - assetGatherer.GatherAssetUuids(sceneObject, assetUuids); + UuidGatherer assetGatherer = new UuidGatherer(m_scene.AssetService); + + foreach (SceneObjectGroup sceneObject in sceneObjects) + { + assetGatherer.GatherAssetUuids(sceneObject, assetUuids); + } + + m_log.DebugFormat( + "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", + sceneObjects.Count, assetUuids.Count); + } + else + { + m_log.DebugFormat("[ARCHIVER]: Not saving assets since --noassets was specified"); } - - m_log.DebugFormat( - "[ARCHIVER]: {0} scene objects to serialize requiring save of {1} assets", - sceneObjects.Count, assetUuids.Count); // Make sure that we also request terrain texture assets RegionSettings regionSettings = m_scene.RegionInfo.RegionSettings; @@ -187,11 +194,14 @@ namespace OpenSim.Region.CoreModules.World.Archiver // XXX: I know this is a weak way of doing it since external non-OAR aware tar executables will not do this archiveWriter.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, CreateControlFile(options)); m_log.InfoFormat("[ARCHIVER]: Added control file to archive."); - - new AssetsRequest( - new AssetsArchiver(archiveWriter), assetUuids, - m_scene.AssetService, m_scene.UserAccountService, - m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets).Execute(); + + if (SaveAssets) + new AssetsRequest( + new AssetsArchiver(archiveWriter), assetUuids, + m_scene.AssetService, m_scene.UserAccountService, + m_scene.RegionInfo.ScopeID, options, awre.ReceivedAllAssets).Execute(); + else + awre.ReceivedAllAssets(new List(), new List()); } catch (Exception) { @@ -204,7 +214,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver /// Create the control file for the most up to date archive /// /// - public static string CreateControlFile(Dictionary options) + public string CreateControlFile(Dictionary options) { int majorVersion = MAX_MAJOR_VERSION, minorVersion = 6; // @@ -258,6 +268,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver xtw.WriteElementString("datetime", ((int)t.TotalSeconds).ToString()); xtw.WriteElementString("id", UUID.Random().ToString()); xtw.WriteEndElement(); + + xtw.WriteElementString("assets_included", SaveAssets.ToString()); + xtw.WriteEndElement(); xtw.Flush(); diff --git a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs index 9277c594f0..08eb80cc2e 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/ArchiverModule.cs @@ -127,6 +127,7 @@ namespace OpenSim.Region.CoreModules.World.Archiver OptionSet ops = new OptionSet(); // ops.Add("v|version=", delegate(string v) { options["version"] = v; }); ops.Add("p|profile=", delegate(string v) { options["profile"] = v; }); + ops.Add("noassets", delegate(string v) { options["noassets"] = v != null; }); List mainParams = ops.Parse(cmdparams); @@ -160,7 +161,12 @@ namespace OpenSim.Region.CoreModules.World.Archiver public void ArchiveRegion(Stream saveStream, Guid requestId) { - new ArchiveWriteRequestPreparation(m_scene, saveStream, requestId).ArchiveRegion(new Dictionary()); + ArchiveRegion(saveStream, requestId, new Dictionary()); + } + + public void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary options) + { + new ArchiveWriteRequestPreparation(m_scene, saveStream, requestId).ArchiveRegion(options); } public void DearchiveRegion(string loadPath) diff --git a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs index 2eb2861005..34e2e23a01 100644 --- a/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs +++ b/OpenSim/Region/CoreModules/World/Archiver/Tests/ArchiverTests.cs @@ -211,6 +211,89 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests // TODO: Test presence of more files and contents of files. } + /// + /// Test saving an OpenSim Region Archive with the no assets option + /// + [Test] + public void TestSaveOarNoAssets() + { + TestHelper.InMethod(); +// log4net.Config.XmlConfigurator.Configure(); + + SceneObjectPart part1 = CreateSceneObjectPart1(); + SceneObjectGroup sog1 = new SceneObjectGroup(part1); + m_scene.AddNewSceneObject(sog1, false); + + SceneObjectPart part2 = CreateSceneObjectPart2(); + + AssetNotecard nc = new AssetNotecard(); + nc.BodyText = "Hello World!"; + nc.Encode(); + UUID ncAssetUuid = new UUID("00000000-0000-0000-1000-000000000000"); + UUID ncItemUuid = new UUID("00000000-0000-0000-1100-000000000000"); + AssetBase ncAsset + = AssetHelpers.CreateAsset(ncAssetUuid, AssetType.Notecard, nc.AssetData, UUID.Zero); + m_scene.AssetService.Store(ncAsset); + SceneObjectGroup sog2 = new SceneObjectGroup(part2); + TaskInventoryItem ncItem + = new TaskInventoryItem { Name = "ncItem", AssetID = ncAssetUuid, ItemID = ncItemUuid }; + part2.Inventory.AddInventoryItem(ncItem, true); + + m_scene.AddNewSceneObject(sog2, false); + + MemoryStream archiveWriteStream = new MemoryStream(); + + Guid requestId = new Guid("00000000-0000-0000-0000-808080808080"); + + Dictionary options = new Dictionary(); + options.Add("noassets", true); + m_archiverModule.ArchiveRegion(archiveWriteStream, requestId, options); + //AssetServerBase assetServer = (AssetServerBase)scene.CommsManager.AssetCache.AssetServer; + //while (assetServer.HasWaitingRequests()) + // assetServer.ProcessNextRequest(); + + // Don't wait for completion - with --noassets save oar happens synchronously +// Monitor.Wait(this, 60000); + + Assert.That(m_lastRequestId, Is.EqualTo(requestId)); + + byte[] archive = archiveWriteStream.ToArray(); + MemoryStream archiveReadStream = new MemoryStream(archive); + TarArchiveReader tar = new TarArchiveReader(archiveReadStream); + + List foundPaths = new List(); + List expectedPaths = new List(); + expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog1)); + expectedPaths.Add(ArchiveHelpers.CreateObjectPath(sog2)); + + string filePath; + TarArchiveReader.TarEntryType tarEntryType; + + byte[] data = tar.ReadEntry(out filePath, out tarEntryType); + Assert.That(filePath, Is.EqualTo(ArchiveConstants.CONTROL_FILE_PATH)); + + ArchiveReadRequest arr = new ArchiveReadRequest(m_scene, (Stream)null, false, false, Guid.Empty); + arr.LoadControlFile(filePath, data); + + Assert.That(arr.ControlFileLoaded, Is.True); + + while (tar.ReadEntry(out filePath, out tarEntryType) != null) + { + if (filePath.StartsWith(ArchiveConstants.ASSETS_PATH)) + { + Assert.Fail("Asset was found in saved oar of TestSaveOarNoAssets()"); + } + else if (filePath.StartsWith(ArchiveConstants.OBJECTS_PATH)) + { + foundPaths.Add(filePath); + } + } + + Assert.That(foundPaths, Is.EquivalentTo(expectedPaths)); + + // TODO: Test presence of more files and contents of files. + } + /// /// Test loading an OpenSim Region Archive. /// @@ -230,7 +313,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests // upset load tar.WriteDir(ArchiveConstants.TERRAINS_PATH); - tar.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, ArchiveWriteRequestPreparation.CreateControlFile(new Dictionary())); + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary())); SceneObjectPart part1 = CreateSceneObjectPart1(); SceneObjectGroup object1 = new SceneObjectGroup(part1); @@ -331,7 +416,9 @@ namespace OpenSim.Region.CoreModules.World.Archiver.Tests TarArchiveWriter tar = new TarArchiveWriter(archiveWriteStream); tar.WriteDir(ArchiveConstants.TERRAINS_PATH); - tar.WriteFile(ArchiveConstants.CONTROL_FILE_PATH, ArchiveWriteRequestPreparation.CreateControlFile(new Dictionary())); + tar.WriteFile( + ArchiveConstants.CONTROL_FILE_PATH, + new ArchiveWriteRequestPreparation(null, (Stream)null, Guid.Empty).CreateControlFile(new Dictionary())); RegionSettings rs = new RegionSettings(); rs.AgentLimit = 17; diff --git a/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs b/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs index d8229de5a5..3fafc47648 100644 --- a/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IRegionArchiverModule.cs @@ -52,31 +52,44 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Archive the region to the given path /// - /// + /// /// This method occurs asynchronously. If you want notification of when it has completed then subscribe to /// the EventManager.OnOarFileSaved event. - /// + /// /// /// If supplied, this request Id is later returned in the saved event + /// Options for the save void ArchiveRegion(string savePath, Guid requestId, Dictionary options); /// /// Archive the region to a stream. /// - /// + /// /// This method occurs asynchronously. If you want notification of when it has completed then subscribe to /// the EventManager.OnOarFileSaved event. - /// + /// /// /// If supplied, this request Id is later returned in the saved event void ArchiveRegion(Stream saveStream, Guid requestId); + /// + /// Archive the region to a stream. + /// + /// + /// This method occurs asynchronously. If you want notification of when it has completed then subscribe to + /// the EventManager.OnOarFileSaved event. + /// + /// + /// If supplied, this request Id is later returned in the saved event + /// Options for the save + void ArchiveRegion(Stream saveStream, Guid requestId, Dictionary options); + /// /// Dearchive the given region archive. This replaces the existing scene. /// - /// + /// /// If you want notification of when it has completed then subscribe to the EventManager.OnOarFileLoaded event. - /// + /// /// void DearchiveRegion(string loadPath);