internal static MemoryStore Create(CmdData args) { // Disallow an attempt to clone another memory store // TODO: How should the ICloneStore input reference another memory store? if (args.CmdName == nameof(ICloneStore)) { throw new NotImplementedException(nameof(MemoryStore)); } // Create the AC file that represents the store root branch Guid storeId = args.GetGuid(nameof(ICreateStore.StoreId)); string name = args.GetValue <string>(nameof(ICreateStore.Name)); var ac = new BranchInfo(storeId: storeId, parentId: Guid.Empty, branchId: storeId, branchName: name, createdAt: args.CreatedAt); return(new MemoryStore(ac)); }
internal static FileStore Create(CmdData args) { // Expand the supplied name to include the current working directory (or // expand a relative path) string enteredName = args.GetValue <string>(nameof(ICreateStore.Name)); string name = Path.GetFileNameWithoutExtension(enteredName); string folderName = Path.GetFullPath(enteredName); // Disallow if the folder name already exists. // It may be worth relaxing this rule at some future date. The // reason for disallowing it is because an existing folder may // well contain sub-folders, but we also use sub-folders to // represent the branch hierarchy. So things would be a bit // mixed up. That said, it would be perfectly plausible to // place branch sub-folders under a separate ".ac" folder (in // much the same way as git). That might be worth considering // if we want to support a "working directory" like that // provided by git. if (Directory.Exists(folderName)) { throw new ApplicationException($"{folderName} already exists"); } // Confirm the folder is on a local drive if (!IsLocalDrive(folderName)) { throw new ApplicationException("Command stores can only be initialized on a local fixed drive"); } // Create the folder for the store (but if the folder already exists, // confirm that it does not already hold any AC files). if (Directory.Exists(folderName)) { if (GetAcFilePath(folderName) != null) { throw new ApplicationException($"{folderName} has already been initialized"); } } else { Log.Info("Creating " + folderName); Directory.CreateDirectory(folderName); } Guid storeId = args.GetGuid(nameof(ICreateStore.StoreId)); FileStore result = null; // If we're cloning, copy over the source data if (args.CmdName == nameof(ICloneStore)) { // TODO: When cloning from a real remote, using wget might be a // good choice (but that doesn't really fit with what's below) ICloneStore cs = (args as ICloneStore); IRemoteStore rs = GetRemoteStore(cs); // Retrieve metadata for all remote branches BranchInfo[] acs = rs.GetBranches() .OrderBy(x => x.CreatedAt) .ToArray(); var branchFolders = new Dictionary <Guid, string>(); // Copy over all branches foreach (BranchInfo ac in acs) { // Get the data for the branch (do this before we do any tweaking // of the folder path from the AC file -- if the command supplier is // a local file store, we won't be able to read the command data files // after changing the folder name recorded in the AC) IdRange range = new IdRange(ac.BranchId, 0, ac.CommandCount - 1); CmdData[] data = rs.GetData(range).ToArray(); // TODO: what follows is very similar to the CopyIn method. // Consider using that instead (means an empty FileStore needs // to be created up front) // Determine the output location for the AC file (relative to the // location that should have already been defined for the parent) if (!branchFolders.TryGetValue(ac.ParentId, out string parentFolder)) { Debug.Assert(ac.ParentId.Equals(Guid.Empty)); parentFolder = folderName; } string dataFolder = Path.Combine(parentFolder, ac.BranchName); branchFolders[ac.BranchId] = dataFolder; SaveBranchInfo(dataFolder, ac); // Copy over the command data foreach (CmdData cd in data) { FileStore.WriteData(dataFolder, cd); } } // If the origin is a folder on the local file system, ensure it's // saved as an absolute path (relative specs may confuse directory // navigation, depending on what the current directory is at the time) string origin = cs.Origin; if (Directory.Exists(origin)) { origin = Path.GetFullPath(origin); } // Save the store metadata var root = new StoreInfo(storeId, name, rs.Id, origin); SaveStoreInfo(folderName, root); // And suck it back up again string acSpec = Path.Combine(folderName, acs[0].BranchId + ".ac"); result = FileStore.Load(acSpec); } else { // Create the AC file that represents the store root branch var ac = new BranchInfo(storeId: storeId, parentId: Guid.Empty, branchId: storeId, branchName: name, createdAt: args.CreatedAt); // Create the store metadata var storeInfo = new StoreInfo(storeId, name, Guid.Empty); // Create the store and save it result = new FileStore(folderName, storeInfo, new BranchInfo[] { ac }, ac.BranchId); // Save the AC file plus the store metadata FileStore.SaveBranchInfo(folderName, ac); result.SaveStoreInfo(); } return(result); }
internal static SQLiteStore Create(CmdData args) { // Disallow store names that correspond to tables in the database (bear // in mind that the entered name may or may not include a directory path) string enteredName = args.GetValue <string>(nameof(ICreateStore.Name)); string name = Path.GetFileNameWithoutExtension(enteredName); if (IsReservedName(name)) { throw new ApplicationException("Store name not allowed"); } // Expand the supplied name to include the current working directory (or // expand a relative path) string fullSpec = Path.GetFullPath(enteredName); string fileType = Path.GetExtension(fullSpec); if (String.IsNullOrEmpty(fileType)) { fullSpec += ".ac-sqlite"; } // Disallow if the database file already exists if (File.Exists(fullSpec)) { throw new ApplicationException($"{fullSpec} already exists"); } // Confirm the file is on a local drive if (!IsLocalDrive(fullSpec)) { throw new ApplicationException("Command stores can only be initialized on a local fixed drive"); } // Ensure the folder exists string folderName = Path.GetDirectoryName(fullSpec); if (!Directory.Exists(folderName)) { Log.Trace("Creating " + folderName); Directory.CreateDirectory(folderName); } Guid storeId = args.GetGuid(nameof(ICreateStore.StoreId)); SQLiteStore result = null; if (args.CmdName == nameof(ICloneStore)) { // Copy the SQLite database // TODO: To handle database files on remote machines ICloneStore cs = (args as ICloneStore); Log.Info($"Copying {cs.Origin} to {fullSpec}"); File.Copy(cs.Origin, fullSpec); // Load the copied store result = SQLiteStore.Load(fullSpec, cs); } else { Log.Info("Creating " + fullSpec); SQLiteDatabase db = CreateDatabase(fullSpec); // Create the AC file that represents the store root branch var ac = new BranchInfo(storeId: storeId, parentId: Guid.Empty, branchId: storeId, branchName: name, createdAt: args.CreatedAt); // Create the store metadata var storeInfo = new StoreInfo(storeId, name, Guid.Empty); // Create the store and save it result = new SQLiteStore(storeInfo, new BranchInfo[] { ac }, ac.BranchId, db); // Save the info for the master branch plus the store metadata result.SaveBranchInfo(ac); result.SaveStoreInfo(); // The last branch is the root of the new database result.SaveProperty(PropertyNaming.LastBranch, storeId.ToString()); } return(result); }