Esempio n. 1
0
        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));
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }