mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
399 lines
15 KiB
C#
399 lines
15 KiB
C#
// /***************************************************************************
|
|
// Aaru Data Preservation Suite
|
|
// ----------------------------------------------------------------------------
|
|
//
|
|
// Filename : Statistics.cs
|
|
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
|
//
|
|
// Component : Commands.
|
|
//
|
|
// --[ Description ] ----------------------------------------------------------
|
|
//
|
|
// Implements the 'stats' command.
|
|
//
|
|
// --[ License ] --------------------------------------------------------------
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as
|
|
// published by the Free Software Foundation, either version 3 of the
|
|
// License, or (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
//
|
|
// ----------------------------------------------------------------------------
|
|
// Copyright © 2011-2025 Natalia Portillo
|
|
// ****************************************************************************/
|
|
|
|
using System.Linq;
|
|
using Aaru.CommonTypes.Enums;
|
|
using Aaru.Console;
|
|
using Aaru.Database;
|
|
using Aaru.Database.Models;
|
|
using Aaru.Localization;
|
|
using Serilog;
|
|
using Spectre.Console;
|
|
using Spectre.Console.Cli;
|
|
using Command = Aaru.Database.Models.Command;
|
|
|
|
namespace Aaru.Commands.Database;
|
|
|
|
sealed class StatisticsCommand : Command<StatisticsCommand.Settings>
|
|
{
|
|
public override int Execute(CommandContext context, Settings settings)
|
|
|
|
{
|
|
MainClass.PrintCopyright();
|
|
|
|
Log.Information(UI.Database_statistics_command);
|
|
|
|
var ctx = AaruContext.Create(Aaru.Settings.Settings.LocalDbPath);
|
|
|
|
if(!ctx.Commands.Any() &&
|
|
!ctx.Filesystems.Any() &&
|
|
!ctx.Filters.Any() &&
|
|
!ctx.MediaFormats.Any() &&
|
|
!ctx.Medias.Any() &&
|
|
!ctx.Partitions.Any() &&
|
|
!ctx.SeenDevices.Any())
|
|
{
|
|
AaruConsole.WriteLine(UI.There_are_no_statistics);
|
|
Log.Information(UI.There_are_no_statistics);
|
|
|
|
return (int)ErrorNumber.NothingFound;
|
|
}
|
|
|
|
bool thereAreStats = false;
|
|
Table table;
|
|
|
|
if(ctx.Commands.Any())
|
|
{
|
|
table = new Table
|
|
{
|
|
Title = new TableTitle($"[blue]{UI.Commands_statistics}[/]")
|
|
};
|
|
|
|
Log.Information(UI.Commands_statistics);
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][purple]{UI.Title_Command}[/][/]").Centered()));
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][teal]{UI.Title_Times_used}[/][/]").Centered()));
|
|
table.Columns[1].RightAligned();
|
|
table.Border(TableBorder.Rounded);
|
|
table.BorderColor(Color.Yellow);
|
|
|
|
if(ctx.Commands.Any(c => c.Name == "analyze"))
|
|
{
|
|
foreach(Command oldAnalyze in ctx.Commands.Where(c => c.Name == "analyze"))
|
|
{
|
|
oldAnalyze.Name = "fs-info";
|
|
ctx.Commands.Update(oldAnalyze);
|
|
}
|
|
|
|
ulong count = 0;
|
|
|
|
foreach(Command fsInfo in ctx.Commands.Where(c => c.Name == "fs-info" && c.Synchronized))
|
|
{
|
|
count += fsInfo.Count;
|
|
ctx.Remove(fsInfo);
|
|
}
|
|
|
|
if(count > 0)
|
|
{
|
|
ctx.Commands.Add(new Command
|
|
{
|
|
Count = count,
|
|
Name = "fs-info",
|
|
Synchronized = true
|
|
});
|
|
}
|
|
|
|
ctx.SaveChanges();
|
|
}
|
|
|
|
foreach(string command in ctx.Commands.Select(c => c.Name).Distinct().OrderBy(c => c))
|
|
{
|
|
ulong count = ctx.Commands.Where(c => c.Name == command && c.Synchronized)
|
|
.Select(c => c.Count)
|
|
.FirstOrDefault();
|
|
|
|
count += (ulong)ctx.Commands.LongCount(c => c.Name == command && !c.Synchronized);
|
|
|
|
if(count == 0) continue;
|
|
|
|
table.AddRow($"[italic][purple]{Markup.Escape(command)}[/][/]", $"[italic][aqua]{count}[/][/]");
|
|
Log.Information("({Command}) - {Count}", command, count);
|
|
thereAreStats = true;
|
|
}
|
|
|
|
AnsiConsole.Write(table);
|
|
AaruConsole.WriteLine();
|
|
}
|
|
|
|
if(ctx.Filters.Any())
|
|
{
|
|
table = new Table
|
|
{
|
|
Title = new TableTitle($"[blue]{UI.Filters_statistics}[/]")
|
|
};
|
|
|
|
Log.Information(UI.Filters_statistics);
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][purple]{UI.Title_Filter}[/][/]").Centered()));
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][teal]{UI.Title_Times_used}[/][/]").Centered()));
|
|
table.Columns[1].RightAligned();
|
|
table.Border(TableBorder.Rounded);
|
|
table.BorderColor(Color.Yellow);
|
|
|
|
foreach(string filter in ctx.Filters.Select(c => c.Name).Distinct().OrderBy(c => c))
|
|
{
|
|
ulong count = ctx.Filters.Where(c => c.Name == filter && c.Synchronized)
|
|
.Select(c => c.Count)
|
|
.FirstOrDefault();
|
|
|
|
count += (ulong)ctx.Filters.LongCount(c => c.Name == filter && !c.Synchronized);
|
|
|
|
if(count == 0) continue;
|
|
|
|
table.AddRow($"[italic][purple]{Markup.Escape(filter)}[/][/]", $"[italic][aqua]{count}[/][/]");
|
|
Log.Information("({Filter}) - {Count}", filter, count);
|
|
thereAreStats = true;
|
|
}
|
|
|
|
AnsiConsole.Write(table);
|
|
AaruConsole.WriteLine();
|
|
}
|
|
|
|
if(ctx.MediaFormats.Any())
|
|
{
|
|
table = new Table
|
|
{
|
|
Title = new TableTitle($"[blue]{UI.Media_image_format_statistics}[/]")
|
|
};
|
|
|
|
Log.Information(UI.Media_image_format_statistics);
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][purple]{UI.Title_Format}[/][/]").Centered()));
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][teal]{UI.Title_Times_used}[/][/]").Centered()));
|
|
table.Columns[1].RightAligned();
|
|
table.Border(TableBorder.Rounded);
|
|
table.BorderColor(Color.Yellow);
|
|
|
|
foreach(string format in ctx.MediaFormats.Select(c => c.Name).Distinct().OrderBy(c => c))
|
|
{
|
|
ulong count = ctx.MediaFormats.Where(c => c.Name == format && c.Synchronized)
|
|
.Select(c => c.Count)
|
|
.FirstOrDefault();
|
|
|
|
count += (ulong)ctx.MediaFormats.LongCount(c => c.Name == format && !c.Synchronized);
|
|
|
|
if(count == 0) continue;
|
|
|
|
table.AddRow($"[italic][purple]{Markup.Escape(format)}[/][/]", $"[italic][aqua]{count}[/][/]");
|
|
Log.Information("({Format}) - {Count}", format, count);
|
|
thereAreStats = true;
|
|
}
|
|
|
|
AnsiConsole.Write(table);
|
|
AaruConsole.WriteLine();
|
|
}
|
|
|
|
if(ctx.Partitions.Any())
|
|
{
|
|
table = new Table
|
|
{
|
|
Title = new TableTitle($"[blue]{UI.Partitioning_scheme_statistics}[/]")
|
|
};
|
|
|
|
Log.Information(UI.Partitioning_scheme_statistics);
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][purple]{UI.Title_Scheme}[/][/]").Centered()));
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][teal]{UI.Title_Times_used}[/][/]").Centered()));
|
|
table.Columns[1].RightAligned();
|
|
table.Border(TableBorder.Rounded);
|
|
table.BorderColor(Color.Yellow);
|
|
|
|
foreach(string partition in ctx.Partitions.Select(c => c.Name).Distinct().OrderBy(c => c))
|
|
{
|
|
ulong count = ctx.Partitions.Where(c => c.Name == partition && c.Synchronized)
|
|
.Select(c => c.Count)
|
|
.FirstOrDefault();
|
|
|
|
count += (ulong)ctx.Partitions.LongCount(c => c.Name == partition && !c.Synchronized);
|
|
|
|
if(count == 0) continue;
|
|
|
|
table.AddRow($"[italic][purple]{Markup.Escape(partition)}[/][/]", $"[italic][aqua]{count}[/][/]");
|
|
Log.Information("({Partition}) - {Count}", partition, count);
|
|
thereAreStats = true;
|
|
}
|
|
|
|
AnsiConsole.Write(table);
|
|
AaruConsole.WriteLine();
|
|
}
|
|
|
|
if(ctx.Filesystems.Any())
|
|
{
|
|
table = new Table
|
|
{
|
|
Title = new TableTitle($"[blue]{UI.Filesystem_statistics}[/]")
|
|
};
|
|
|
|
Log.Information(UI.Filesystem_statistics);
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][purple]{UI.Title_Filesystem}[/][/]").Centered()));
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][teal]{UI.Title_Times_used}[/][/]").Centered()));
|
|
table.Columns[1].RightAligned();
|
|
table.Border(TableBorder.Rounded);
|
|
table.BorderColor(Color.Yellow);
|
|
|
|
foreach(string filesystem in ctx.Filesystems.Select(c => c.Name).Distinct().OrderBy(c => c))
|
|
{
|
|
ulong count = ctx.Filesystems.Where(c => c.Name == filesystem && c.Synchronized)
|
|
.Select(c => c.Count)
|
|
.FirstOrDefault();
|
|
|
|
count += (ulong)ctx.Filesystems.LongCount(c => c.Name == filesystem && !c.Synchronized);
|
|
|
|
if(count == 0) continue;
|
|
|
|
table.AddRow($"[italic][purple]{Markup.Escape(filesystem)}[/][/]", $"[italic][aqua]{count}[/][/]");
|
|
Log.Information("({Filesystem}) - {Count}", filesystem, count);
|
|
thereAreStats = true;
|
|
}
|
|
|
|
AnsiConsole.Write(table);
|
|
AaruConsole.WriteLine();
|
|
}
|
|
|
|
if(ctx.SeenDevices.Any())
|
|
{
|
|
table = new Table
|
|
{
|
|
Title = new TableTitle($"[blue]{UI.Device_statistics}[/]")
|
|
};
|
|
|
|
Log.Information(UI.Device_statistics);
|
|
|
|
table.AddColumn($"[bold][blue]{UI.Title_Manufacturer}[/][/]");
|
|
table.AddColumn($"[bold][purple]{UI.Title_Model}[/][/]");
|
|
table.AddColumn($"[bold][teal]{UI.Title_Revision}[/][/]");
|
|
table.AddColumn($"[bold][rosybrown]{UI.Title_Bus}[/][/]");
|
|
table.Border(TableBorder.Rounded);
|
|
table.BorderColor(Color.Yellow);
|
|
|
|
foreach(DeviceStat ds in ctx.SeenDevices.OrderBy(ds => ds.Manufacturer)
|
|
.ThenBy(ds => ds.Model)
|
|
.ThenBy(ds => ds.Revision)
|
|
.ThenBy(ds => ds.Bus))
|
|
{
|
|
table.AddRow($"[italic][blue]{Markup.Escape(ds.Manufacturer ?? "")}[/][/]",
|
|
$"[italic][purple]{Markup.Escape(ds.Model ?? "")}[/][/]",
|
|
$"[italic][teal]{Markup.Escape(ds.Revision ?? "")}[/][/]",
|
|
$"[italic][rosybrown]{Markup.Escape(ds.Bus ?? "")}[/][/]");
|
|
|
|
Log.Information("({Manufacturer}) - {Model} {Revision} ({Bus})",
|
|
ds.Manufacturer ?? "",
|
|
ds.Model ?? "",
|
|
ds.Revision ?? "",
|
|
ds.Bus ?? "");
|
|
}
|
|
|
|
AnsiConsole.Write(table);
|
|
AaruConsole.WriteLine();
|
|
thereAreStats = true;
|
|
}
|
|
|
|
if(ctx.Medias.Any(ms => ms.Real))
|
|
{
|
|
table = new Table
|
|
{
|
|
Title = new TableTitle($"[blue]{UI.Media_found_in_real_device_statistics}[/]")
|
|
};
|
|
|
|
Log.Information(UI.Media_found_in_real_device_statistics);
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][purple]{Localization.Core.Title_Type_for_media}[/][/]")
|
|
.Centered()));
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][teal]{UI.Title_Times_used}[/][/]").Centered()));
|
|
table.Columns[1].RightAligned();
|
|
table.Border(TableBorder.Rounded);
|
|
table.BorderColor(Color.Yellow);
|
|
|
|
foreach(string media in ctx.Medias.Where(ms => ms.Real).Select(ms => ms.Type).Distinct().OrderBy(ms => ms))
|
|
{
|
|
ulong count = ctx.Medias.Where(c => c.Type == media && c.Synchronized && c.Real)
|
|
.Select(c => c.Count)
|
|
.FirstOrDefault();
|
|
|
|
count += (ulong)ctx.Medias.LongCount(c => c.Type == media && !c.Synchronized && c.Real);
|
|
|
|
if(count <= 0) continue;
|
|
|
|
table.AddRow($"[italic][purple]{Markup.Escape(media)}[/][/]", $"[italic][aqua]{count}[/][/]");
|
|
Log.Information("({Media}) - {Count}", media, count);
|
|
|
|
thereAreStats = true;
|
|
}
|
|
|
|
AnsiConsole.Write(table);
|
|
AaruConsole.WriteLine();
|
|
}
|
|
|
|
if(ctx.Medias.Any(ms => !ms.Real))
|
|
{
|
|
table = new Table
|
|
{
|
|
Title = new TableTitle($"[blue]{UI.Media_found_in_images_statistics}[/]")
|
|
};
|
|
|
|
Log.Information(UI.Media_found_in_images_statistics);
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][purple]{Localization.Core.Title_Type_for_media}[/][/]")
|
|
.Centered()));
|
|
|
|
table.AddColumn(new TableColumn(new Markup($"[bold][teal]{UI.Title_Times_used}[/][/]").Centered()));
|
|
table.Columns[1].RightAligned();
|
|
table.Border(TableBorder.Rounded);
|
|
table.BorderColor(Color.Yellow);
|
|
|
|
foreach(string media in ctx.Medias.Where(ms => !ms.Real).Select(ms => ms.Type).Distinct().OrderBy(ms => ms))
|
|
{
|
|
ulong count = ctx.Medias.Where(c => c.Type == media && c.Synchronized && !c.Real)
|
|
.Select(c => c.Count)
|
|
.FirstOrDefault();
|
|
|
|
count += (ulong)ctx.Medias.LongCount(c => c.Type == media && !c.Synchronized && !c.Real);
|
|
|
|
if(count <= 0) continue;
|
|
|
|
table.AddRow($"[italic][purple]{Markup.Escape(media)}[/][/]", $"[italic][aqua]{count}[/][/]");
|
|
Log.Information("({Media}) - {Count}", media, count);
|
|
|
|
thereAreStats = true;
|
|
}
|
|
|
|
AnsiConsole.Write(table);
|
|
AaruConsole.WriteLine();
|
|
}
|
|
|
|
if(!thereAreStats)
|
|
{
|
|
AaruConsole.WriteLine(UI.There_are_no_statistics);
|
|
Log.Information(UI.There_are_no_statistics);
|
|
}
|
|
|
|
return (int)ErrorNumber.NoError;
|
|
}
|
|
|
|
#region Nested type: Settings
|
|
|
|
public class Settings : DatabaseFamily {}
|
|
|
|
#endregion
|
|
} |