Compare commits

...

2 Commits

11 changed files with 344 additions and 275 deletions

View File

@@ -1,63 +1,81 @@
using Microsoft.Extensions.Logging;
using TBDel.Models; using TBDel.Models;
using TBDel.Services; using TBDel.Services;
namespace TBDel.Commands; namespace TBDel.Commands
public class AddCommand
{ {
public class AddCommand
public static async Task<Boolean> AddEntry(string[] args)
{ {
// TODO: Add unique Id support public static async Task AddEntry(string[] args)
// TODO: Add duplicate path check
// TODO: Add support for multiple paths
if (args.Length > 1)
{ {
string workingDirectory = Directory.GetCurrentDirectory(); // TODO: Add duplicate path check
string absolutePath = Path.Combine(workingDirectory, args[1]); // TODO: Add support for multiple paths
if (File.Exists(absolutePath))
if (args.Length > 1)
{ {
Console.WriteLine($"Adding: {absolutePath}"); string workingDirectory = Directory.GetCurrentDirectory();
var entry = new FileEntry { Path = absolutePath, DateAdded = DateTime.Now }; string absolutePath = Path.Combine(workingDirectory, args[1]);
var dbService = new DbService(); var dbService = new DbService();
if (await dbService.AddFileEntryAsync(entry))
if (File.Exists(absolutePath))
{ {
Console.ForegroundColor = ConsoleColor.Green; Console.WriteLine($"Adding: {absolutePath}");
Console.WriteLine("File added successfully."); var entry = new FileEntry { Id = GenerateUniqueId(dbService), Path = absolutePath, DateAdded = DateTime.Now };
Console.ResetColor(); if (await dbService.AddFileEntryAsync(entry))
return true; {
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("File added successfully.");
Console.ResetColor();
return;
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Failed to add file.");
Console.ResetColor();
return;
}
} }
else else if (Directory.Exists(absolutePath))
{ {
Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine($"Adding: {absolutePath}");
Console.WriteLine("Failed to add file."); var entry = new FolderEntry() { Id = GenerateUniqueId(dbService), Path = absolutePath, DateAdded = DateTime.Now };
Console.ResetColor(); if (await dbService.AddFolderEntryAsync(entry))
return false; {
} Console.ForegroundColor = ConsoleColor.Green;
} Console.WriteLine("Directory added successfully.");
else if (Directory.Exists(absolutePath)) Console.ResetColor();
{ return;
Console.WriteLine($"Adding: {absolutePath}"); }
var entry = new FolderEntry() { Path = absolutePath, DateAdded = DateTime.Now }; else
var dbService = new DbService(); {
if (await dbService.AddFolderEntryAsync(entry)) Console.ForegroundColor = ConsoleColor.Red;
{ Console.WriteLine("Failed to add directory.");
Console.ForegroundColor = ConsoleColor.Green; Console.ResetColor();
Console.WriteLine("Directory added successfully."); return;
Console.ResetColor(); }
return true;
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Failed to add directory.");
Console.ResetColor();
return false;
} }
} }
} }
return false;
private static uint GenerateUniqueId(DbService dbService)
{
// Hopefully not running away from me one day
Random random = new Random();
uint newId;
do
{
newId = (uint)random.Next(10000, 99999);
} while (IdExists(newId, dbService));
return newId;
}
private static bool IdExists(uint id, DbService dbService)
{
// Not async? Not a problem (yet(?))
var fileEntries = dbService.GetFileEntriesAsync().Result;
var folderEntries = dbService.GetFolderEntriesAsync().Result;
return fileEntries.Any(e => e.Id == id) || folderEntries.Any(e => e.Id == id);
}
} }
} }

View File

@@ -1,55 +1,49 @@
using TBDel.Services; using TBDel.Services;
namespace TBDel.Commands; namespace TBDel.Commands
public class DeleteCommand
{ {
public static async Task DeleteAll() public class DeleteAllCommand
{ {
var dbService = new DbService(); public static async Task DeleteAll()
var allFiles = await dbService.GetFileEntriesAsync();
var allFolders = await dbService.GetFolderEntriesAsync();
if (allFiles.Count == 0 && allFolders.Count == 0)
{ {
Console.WriteLine("No files or folders found."); var dbService = new DbService();
return; var allFiles = await dbService.GetFileEntriesAsync();
} var allFolders = await dbService.GetFolderEntriesAsync();
Console.ForegroundColor = ConsoleColor.Yellow; if (allFiles.Count == 0 && allFolders.Count == 0)
Console.WriteLine($"Are you sure you want to permanently delete {allFiles.Count} file(s) and {allFolders.Count} folder(s)? (y/N)"); {
Console.ResetColor(); Console.WriteLine("No files or folders found.");
var input = Console.ReadLine(); return;
if (input != "y") }
{
Console.ForegroundColor = ConsoleColor.Red; Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine("Operation cancelled."); Console.Write($"Are you sure you want to permanently delete {allFiles.Count} file(s) and {allFolders.Count} folder(s)? (y/N)");
Console.ResetColor();
var input = Console.ReadLine();
if (input != "y")
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Operation cancelled.");
Console.ResetColor();
return;
}
foreach (var file in allFiles)
{
Console.WriteLine($"Deleting file: {file.Path}");
File.Delete(file.Path);
await dbService.RemoveFileEntryAsync(file.Id);
}
foreach (var folder in allFolders)
{
Console.WriteLine($"Deleting directory: {folder.Path}");
Directory.Delete(folder.Path, true);
await dbService.RemoveFolderEntryAsync(folder.Id);
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("All files and folders deleted successfully.");
Console.ResetColor(); Console.ResetColor();
return;
}
var toBeDeletedFiles = new List<string>();
var toBeDeletedFolders = new List<string>();
foreach (var file in allFiles)
{
toBeDeletedFiles.Add(file.Path);
}
foreach (var folder in allFolders)
{
toBeDeletedFolders.Add(folder.Path);
}
foreach (var file in toBeDeletedFiles)
{
Console.WriteLine($"Deleting file: {file}");
File.Delete(file);
await dbService.RemoveFileEntryAsync(file);
}
foreach (var folder in toBeDeletedFolders)
{
Console.WriteLine($"Deleting directory: {folder}");
Directory.Delete(folder, true);
await dbService.RemoveFolderEntryAsync(folder);
} }
} }
} }

View File

@@ -0,0 +1,38 @@
using TBDel.Models;
using TBDel.Services;
namespace TBDel.Commands
{
public class DeleteCommand
{
public static async Task DeleteEntry(string[] args)
{
var dbService = new DbService();
if (args.Length > 1 && uint.TryParse(args[1], out uint id))
{
Console.WriteLine($"Deleting entry with ID: {id}");
bool fileDeleted = await dbService.RemoveFileEntryAsync(id);
bool folderDeleted = await dbService.RemoveFolderEntryAsync(id);
if (fileDeleted || folderDeleted)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Entry deleted successfully.");
Console.ResetColor();
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Something went wrong. Entry not found.");
Console.ResetColor();
}
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Invalid or missing ID argument.");
Console.ResetColor();
}
}
}
}

View File

@@ -1,77 +1,78 @@
using TBDel.Models; using TBDel.Models;
using TBDel.Services; using TBDel.Services;
namespace TBDel.Commands; namespace TBDel.Commands
public class ListCommand
{ {
public static async Task List(string[] args) public class ListCommand
{ {
if (args.Length > 2) public static async Task List(string[] args)
{ {
Console.WriteLine("Too many arguments."); if (args.Length > 2)
return;
}
if (args.Length == 1)
{
Console.WriteLine("Listing both files and folders.");
await ListFiles();
for (int i = 0; i < 110; i++)
{ {
Console.Write("-"); Console.WriteLine("Too many arguments.");
return;
}
if (args.Length == 1)
{
Console.WriteLine("Listing both files and folders.");
await ListFiles();
for (int i = 0; i < 110; i++)
{
Console.Write("-");
}
Console.Write("\n");
await ListFolders();
}
else if (args[1] == "files")
{
await ListFiles();
}
else if (args[1] == "folders")
{
await ListFolders();
} }
Console.Write("\n");
await ListFolders();
} }
else if (args[1] == "files")
{
await ListFiles();
}
else if (args[1] == "folders")
{
await ListFolders();
}
}
private static async Task ListFiles() private static async Task ListFiles()
{ {
var dbService = new DbService(); var dbService = new DbService();
var filesList = await dbService.GetFileEntriesAsync(); var filesList = await dbService.GetFileEntriesAsync();
if (filesList.Count == 0) if (filesList.Count == 0)
{ {
Console.WriteLine("No files found."); Console.WriteLine("No files found.");
return; return;
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Found {0} file(s):\n", filesList.Count);
Console.WriteLine("{0,-10} {1,-90} {2,10}\n", "ID", "Path", "Date added");
Console.ResetColor();
foreach (var file in filesList)
{
Console.WriteLine("{0,-10} {1,-90} {2,10}", file.Id, file.Path, file.DateAdded);
}
} }
Console.ForegroundColor = ConsoleColor.Green; private static async Task ListFolders()
Console.WriteLine("Found {0} file(s):\n", filesList.Count);
Console.WriteLine("{0,-100} {1,10}\n", "Path", "Date added");
Console.ResetColor();
foreach (var file in filesList)
{ {
Console.WriteLine("{0,-100} {1,10}", file.Path, file.DateAdded); var dbService = new DbService();
var foldersList = await dbService.GetFolderEntriesAsync();
if (foldersList.Count == 0)
{
Console.WriteLine("No folders found.");
return;
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Found {0} folder(s):\n", foldersList.Count);
Console.WriteLine("{0,-10} {1,-90} {2,10}\n", "ID", "Path", "Date added");
Console.ResetColor();
foreach (var folder in foldersList)
{
Console.WriteLine("{0,-10} {1,-90} {2,10}", folder.Id, folder.Path, folder.DateAdded);
}
} }
} }
private static async Task ListFolders() }
{
var dbService = new DbService();
var foldersList = await dbService.GetFolderEntriesAsync();
if (foldersList.Count == 0)
{
Console.WriteLine("No folders found.");
return;
}
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine("Found {0} folder(s):\n", foldersList.Count);
Console.WriteLine("{0,-100} {1,10}\n", "Path", "Date added");
Console.ResetColor();
foreach (var folder in foldersList)
{
Console.WriteLine("{0,-100} {1,10}", folder.Path, folder.DateAdded);
}
}
}

View File

@@ -1,11 +1,26 @@
using System.Text.Json.Serialization;
namespace TBDel.Models; namespace TBDel.Models;
public class FileEntry public class FileEntry
{ {
// Unique 5 digit number for each entry // Unique 5 digit number for each entry
uint Id { get; set; } public uint Id { get; set; }
// Absolute path // Absolute path
public string Path { get; set; } = string.Empty; public string Path { get; set; } = string.Empty;
// Date added // Date added
public DateTime DateAdded { get; set; } public DateTime DateAdded { get; set; }
public FileEntry()
{
}
// To support trimmed binary
[JsonConstructor]
public FileEntry(uint id, string path, DateTime dateAdded)
{
Id = id;
Path = path;
DateAdded = dateAdded;
}
} }

View File

@@ -1,6 +1,16 @@
using System.Text.Json.Serialization;
namespace TBDel.Models; namespace TBDel.Models;
// The same as FileEntry // The same as FileEntry
public class FolderEntry : FileEntry public class FolderEntry : FileEntry
{ {
public FolderEntry() : base()
{
}
[JsonConstructor]
public FolderEntry(uint id, string path, DateTime dateAdded) : base(id, path, dateAdded)
{
}
} }

15
Models/JsonContext.cs Normal file
View File

@@ -0,0 +1,15 @@
using System.Text.Json.Serialization;
using TBDel.Models;
// All this just because the binary size was 40MB for this little CLI tool
namespace TBDel.Services
{
[JsonSourceGenerationOptions(WriteIndented = true)]
[JsonSerializable(typeof(DatabaseContent))]
[JsonSerializable(typeof(FileEntry))]
[JsonSerializable(typeof(FolderEntry))]
internal partial class JsonContext : JsonSerializerContext
{
}
}

View File

@@ -23,10 +23,10 @@ namespace TBDel
await AddCommand.AddEntry(args); await AddCommand.AddEntry(args);
break; break;
case "delete": case "delete":
await DeleteCommand.DeleteEntry(args);
break; break;
case "deleteall": case "deleteall":
await DeleteCommand.DeleteAll(); await DeleteAllCommand.DeleteAll();
break; break;
case "list": case "list":
await ListCommand.List(args); await ListCommand.List(args);

View File

@@ -1,64 +1,107 @@
using JsonFlatFileDataStore; using System.Text.Json;
using TBDel.Models; using TBDel.Models;
namespace TBDel.Services; namespace TBDel.Services
public class DbService
{ {
private readonly DataStore _store; public class DbService
private readonly IDocumentCollection<FileEntry> _fileCollection;
private readonly IDocumentCollection<FolderEntry> _folderCollection;
public DbService()
{ {
string dbPath = private readonly string _dbPath;
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TBDel_Db.json"); private List<FileEntry> _fileCollection;
var _store = new DataStore(dbPath,minifyJson:true); private List<FolderEntry> _folderCollection;
_fileCollection = _store.GetCollection<FileEntry>();
_folderCollection = _store.GetCollection<FolderEntry>();
}
public DbService()
public async Task<Boolean> AddFileEntryAsync(FileEntry entry)
{
return await _fileCollection.InsertOneAsync(entry);
}
public async Task<Boolean> AddFolderEntryAsync(FolderEntry entry)
{
return await _folderCollection.InsertOneAsync(entry);
}
public async Task<List<FileEntry>> GetFileEntriesAsync()
{
return _fileCollection.AsQueryable().ToList();
}
public async Task<List<FolderEntry>> GetFolderEntriesAsync()
{
return _folderCollection.AsQueryable().ToList();
}
public async Task<Boolean> RemoveFileEntryAsync(string path)
{
var entryToRemove = _fileCollection.AsQueryable().FirstOrDefault(e => e.Path == path);
if (entryToRemove != null)
{ {
return await _fileCollection.DeleteOneAsync(e => e.Path == path); // or entryToRemove.Path _dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "TBDel_Db.json");
LoadData();
} }
return false; private void LoadData()
{
if (File.Exists(_dbPath))
{
var json = File.ReadAllText(_dbPath);
var dbContent = JsonSerializer.Deserialize(json, JsonContext.Default.DatabaseContent) ?? new DatabaseContent();
_fileCollection = dbContent.FileEntries;
_folderCollection = dbContent.FolderEntries;
}
else
{
_fileCollection = new List<FileEntry>();
_folderCollection = new List<FolderEntry>();
}
}
private void SaveData()
{
var dbContent = new DatabaseContent
{
FileEntries = _fileCollection,
FolderEntries = _folderCollection
};
var json = JsonSerializer.Serialize(dbContent, JsonContext.Default.DatabaseContent);
File.WriteAllText(_dbPath, json);
}
public async Task<bool> AddFileEntryAsync(FileEntry entry)
{
_fileCollection.Add(entry);
SaveData();
return await Task.FromResult(true);
}
public async Task<bool> AddFolderEntryAsync(FolderEntry entry)
{
_folderCollection.Add(entry);
SaveData();
return await Task.FromResult(true);
}
public async Task<List<FileEntry>> GetFileEntriesAsync()
{
return await Task.FromResult(_fileCollection.ToList());
}
public async Task<List<FolderEntry>> GetFolderEntriesAsync()
{
return await Task.FromResult(_folderCollection.ToList());
}
public async Task<bool> RemoveFileEntryAsync(uint id)
{
var entryToRemove = _fileCollection.FirstOrDefault(e => e.Id == id);
if (entryToRemove != null)
{
_fileCollection.Remove(entryToRemove);
SaveData();
return await Task.FromResult(true);
}
return await Task.FromResult(false);
}
public async Task<bool> RemoveFolderEntryAsync(uint id)
{
var entryToRemove = _folderCollection.FirstOrDefault(e => e.Id == id);
if (entryToRemove != null)
{
_folderCollection.Remove(entryToRemove);
SaveData();
return await Task.FromResult(true);
}
return await Task.FromResult(false);
}
} }
public async Task<Boolean> RemoveFolderEntryAsync(string path) public class DatabaseContent
{ {
var entryToRemove = _folderCollection.AsQueryable().FirstOrDefault(e => e.Path == path); public DatabaseContent()
if (entryToRemove != null)
{ {
return await _folderCollection.DeleteOneAsync(e => e.Path == path); // or entryToRemove.Path FileEntries = new List<FileEntry>();
FolderEntries = new List<FolderEntry>();
} }
return false;
public List<FileEntry> FileEntries { get; set; }
public List<FolderEntry> FolderEntries { get; set; }
} }
} }

View File

@@ -5,11 +5,7 @@
<TargetFramework>net9.0</TargetFramework> <TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<PublishAot>true</PublishAot>
</PropertyGroup> </PropertyGroup>
<ItemGroup>
<PackageReference Include="JsonFlatFileDataStore" Version="2.4.2" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="9.0.1" />
</ItemGroup>
</Project> </Project>

View File

@@ -1,61 +0,0 @@
namespace TBDel.TUIHelper;
public class Header
{
public static void Show(String _headerText)
{
// Get third of the terminal width
int viewWidth = Console.WindowWidth/3;
// Show the header seperator
Console.Write("#");
for (int i = 0; i <= viewWidth-2; i++)
{
Console.Write("=");
}
// Move to the next line
Console.WriteLine("#");
Console.Write("#");
for (int i = 0; i <= viewWidth - 2;i++)
{
Console.Write(" ");
}
Console.Write("#");
Console.Write("\n#");
int textReletiveStartPosition = ((viewWidth - 2)- _headerText.Length)/2;
for (int i = 0; i < textReletiveStartPosition; i++)
{
Console.Write(" ");
}
Console.Write(_headerText);
for (int i = 0; i <= textReletiveStartPosition; i++)
{
Console.Write(" ");
}
Console.WriteLine("#");
Console.Write("#");
for (int i = 0; i <= viewWidth - 2;i++)
{
Console.Write(" ");
}
Console.Write("#");
Console.Write("\n#");
for (int i = 0; i <= viewWidth-2; i++)
{
Console.Write("=");
}
Console.WriteLine("#");
}
}