mirror of
https://github.com/aaru-dps/Aaru.git
synced 2025-12-16 19:24:25 +00:00
Complete rework of output of fs ls command output.
This commit is contained in:
71
Aaru.Core/FileAttributesExtensions.cs
Normal file
71
Aaru.Core/FileAttributesExtensions.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
// /***************************************************************************
|
||||
// Aaru Data Preservation Suite
|
||||
// ----------------------------------------------------------------------------
|
||||
//
|
||||
// Filename : Ls.cs
|
||||
// Author(s) : Natalia Portillo <claunia@claunia.com>
|
||||
//
|
||||
// Component : Commands.
|
||||
//
|
||||
// --[ 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 Aaru.CommonTypes.Structs;
|
||||
|
||||
namespace Aaru.Core;
|
||||
|
||||
public static class FileAttributesExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Returns a 19-character string representation of the attributes
|
||||
/// </summary>
|
||||
public static string ToAttributeChars(this FileAttributes flags)
|
||||
{
|
||||
char[] attr = new char[19];
|
||||
for(int i = 0; i < attr.Length; i++) attr[i] = '.';
|
||||
|
||||
(FileAttributes Flag, int Slot, char Symbol)[] attrs =
|
||||
[
|
||||
(FileAttributes.AppendOnly, 1, 'a'), (FileAttributes.Alias, 0, 'l'), (FileAttributes.Archive, 1, 'A'),
|
||||
(FileAttributes.BlockDevice, 0, 'b'), (FileAttributes.Bundle, 0, 'B'),
|
||||
(FileAttributes.CharDevice, 0, 'c'), (FileAttributes.Compressed, 5, 'z'),
|
||||
(FileAttributes.Device, 0, 'v'), (FileAttributes.Directory, 0, 'd'), (FileAttributes.Encrypted, 6, 'e'),
|
||||
(FileAttributes.Extents, 7, 'e'), (FileAttributes.FIFO, 0, 'F'), (FileAttributes.File, 0, 'f'),
|
||||
(FileAttributes.HasBeenInited, 8, 'i'), (FileAttributes.HasCustomIcon, 9, 'c'),
|
||||
(FileAttributes.HasNoINITs, 8, 'n'), (FileAttributes.Hidden, 4, 'H'),
|
||||
(FileAttributes.Immutable, 2, 'i'), (FileAttributes.IndexedDirectory, 1, 'i'),
|
||||
(FileAttributes.Inline, 11, 'i'), (FileAttributes.IntegrityStream, 12, 'i'),
|
||||
(FileAttributes.IsOnDesk, 13, 'd'), (FileAttributes.Journaled, 14, 'j'),
|
||||
(FileAttributes.NoAccessTime, 15, 'a'), (FileAttributes.NoCopyOnWrite, 16, 'w'),
|
||||
(FileAttributes.NoDump, 1, 'd'), (FileAttributes.Password, 17, 'p'), (FileAttributes.ReadOnly, 2, 'R'),
|
||||
(FileAttributes.ReparsePoint, 0, 'r'), (FileAttributes.Sparse, 18, 's'),
|
||||
(FileAttributes.Shadow, 0, 'l'), (FileAttributes.Stationery, 0, 't'), (FileAttributes.Symlink, 0, 'l'),
|
||||
(FileAttributes.System, 3, 'S'), (FileAttributes.TopDirectory, 0, 'T'),
|
||||
(FileAttributes.Undeletable, 2, 'u'), (FileAttributes.Pipe, 0, 'p'), (FileAttributes.Socket, 0, 's'),
|
||||
(FileAttributes.Deleted, 2, 'd'), (FileAttributes.Executable, 10, 'x')
|
||||
];
|
||||
|
||||
// 4) Post-process extras: only overwrite slots still ‘.’
|
||||
foreach((FileAttributes flag, int slot, char symbol) in attrs)
|
||||
if(slot >= 0 && slot < attr.Length && attr[slot] == '.' && flags.HasFlag(flag))
|
||||
attr[slot] = symbol;
|
||||
|
||||
return new string(attr);
|
||||
}
|
||||
}
|
||||
6
Aaru.Localization/UI.Designer.cs
generated
6
Aaru.Localization/UI.Designer.cs
generated
@@ -6111,5 +6111,11 @@ namespace Aaru.Localization {
|
||||
return ResourceManager.GetString("Running_in_0_architecture", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
public static string Title_Date_modified {
|
||||
get {
|
||||
return ResourceManager.GetString("Title_Date_modified", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2154,7 +2154,7 @@ Probadores:
|
||||
<value>[bold][blue]ATIP:[/][/]</value>
|
||||
</data>
|
||||
<data name="Title_Attributes" xml:space="preserve">
|
||||
<value>Atributos</value>
|
||||
<value>[bold][gold3]Atributos[/][/]</value>
|
||||
</data>
|
||||
<data name="Title_Author" xml:space="preserve">
|
||||
<value>Autor</value>
|
||||
@@ -3053,4 +3053,7 @@ Probadores:
|
||||
<data name="Unable_to_get_separate_tracks_not_checksumming_them" xml:space="preserve">
|
||||
<value>[yellow]No se pudieron separar las pistas, no se harán checksum de ellas[/]</value>
|
||||
</data>
|
||||
<data name="Title_Date_modified" xml:space="preserve">
|
||||
<value>[bold][dodgerblue1]Fecha modificación[/][/]</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -2239,7 +2239,7 @@ Testers:
|
||||
<value>Last write</value>
|
||||
</data>
|
||||
<data name="Title_Attributes" xml:space="preserve">
|
||||
<value>Attributes</value>
|
||||
<value>[bold][gold3]Attributes[/][/]</value>
|
||||
</data>
|
||||
<data name="Title_GID" xml:space="preserve">
|
||||
<value>GID</value>
|
||||
@@ -3132,4 +3132,7 @@ Do you want to continue?</value>
|
||||
<data name="Running_in_0_architecture" xml:space="preserve">
|
||||
<value>Running in {0} architecture</value>
|
||||
</data>
|
||||
<data name="Title_Date_modified" xml:space="preserve">
|
||||
<value>[bold][dodgerblue1]Date modified[/][/]</value>
|
||||
</data>
|
||||
</root>
|
||||
@@ -249,7 +249,7 @@ sealed class LsCommand : Command<LsCommand.Settings>
|
||||
|
||||
if(error == ErrorNumber.NoError)
|
||||
{
|
||||
ListFilesInDir("/", fs, settings.LongFormat);
|
||||
ListFilesInDir("/", fs);
|
||||
|
||||
Statistics.AddFilesystem(fs.Metadata.Type);
|
||||
}
|
||||
@@ -278,7 +278,7 @@ sealed class LsCommand : Command<LsCommand.Settings>
|
||||
|
||||
if(error == ErrorNumber.NoError)
|
||||
{
|
||||
ListFilesInDir("/", fs, settings.LongFormat);
|
||||
ListFilesInDir("/", fs);
|
||||
|
||||
Statistics.AddFilesystem(fs.Metadata.Type);
|
||||
}
|
||||
@@ -299,7 +299,7 @@ sealed class LsCommand : Command<LsCommand.Settings>
|
||||
return (int)ErrorNumber.NoError;
|
||||
}
|
||||
|
||||
static void ListFilesInDir(string path, [NotNull] IReadOnlyFilesystem fs, bool longFormat)
|
||||
static void ListFilesInDir(string path, [NotNull] IReadOnlyFilesystem fs)
|
||||
{
|
||||
ErrorNumber error = ErrorNumber.InvalidArgument;
|
||||
IDirNode node = null;
|
||||
@@ -339,29 +339,63 @@ sealed class LsCommand : Command<LsCommand.Settings>
|
||||
fs.CloseDir(node);
|
||||
});
|
||||
|
||||
var table = new Table();
|
||||
|
||||
table.Border(TableBorder.None);
|
||||
|
||||
table.AddColumn(new TableColumn($"[underline]{UI.Title_Attributes}[/]")
|
||||
{
|
||||
NoWrap = true,
|
||||
Alignment = Justify.Right
|
||||
});
|
||||
|
||||
table.AddColumn(new TableColumn($"[underline]{UI.Title_Size}[/]")
|
||||
{
|
||||
NoWrap = true,
|
||||
Alignment = Justify.Right,
|
||||
Width = 12
|
||||
});
|
||||
|
||||
table.AddColumn(new TableColumn($"[underline]{UI.Title_Date_modified}[/]")
|
||||
{
|
||||
NoWrap = true,
|
||||
Alignment = Justify.Center,
|
||||
Width = 20
|
||||
});
|
||||
|
||||
table.AddColumn(new TableColumn($"[underline]{UI.Title_Name}[/]")
|
||||
{
|
||||
NoWrap = true,
|
||||
Alignment = Justify.Left
|
||||
});
|
||||
|
||||
foreach(KeyValuePair<string, FileEntryInfo> entry in
|
||||
stats.OrderBy(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == false))
|
||||
{
|
||||
if(longFormat)
|
||||
{
|
||||
if(entry.Value != null)
|
||||
{
|
||||
if(entry.Value.Attributes.HasFlag(FileAttributes.Directory))
|
||||
{
|
||||
AaruLogging.WriteLine("{0, 10:d} {0, 12:T} {1, -20} {2}",
|
||||
$"[dodgerblue1]{entry.Value.CreationTimeUtc}[/]",
|
||||
UI.Directory_abbreviation,
|
||||
$"[teal]{Markup.Escape(entry.Key)}[/]");
|
||||
table.AddRow($"[gold3]{entry.Value.Attributes.ToAttributeChars()}[/]",
|
||||
"",
|
||||
"",
|
||||
$"[green]{Markup.Escape(entry.Key)}[/]");
|
||||
|
||||
AaruLogging.Information($"{entry.Value.Attributes.ToAttributeChars()} {entry.Key}");
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
AaruLogging.WriteLine("{0, 10:d} {0, 12:T} {1, 6}{2, 14:N0} {3}",
|
||||
$"[dodgerblue1]{entry.Value.CreationTimeUtc}[/]",
|
||||
$"[fuchsia]{entry.Value.Inode}[/]",
|
||||
table.AddRow($"[gold3]{entry.Value.Attributes.ToAttributeChars()}[/]",
|
||||
$"[lime]{entry.Value.Length}[/]",
|
||||
$"[teal]{Markup.Escape(entry.Key)}[/]");
|
||||
$"[dodgerblue1]{entry.Value.LastWriteTimeUtc:s}[/]",
|
||||
$"[green]{Markup.Escape(entry.Key)}[/]");
|
||||
|
||||
AaruLogging
|
||||
.Information($"{entry.Value.Attributes.ToAttributeChars()} {entry.Value.Length} {entry.Value.LastWriteTimeUtc:s} {entry.Key}");
|
||||
}
|
||||
|
||||
|
||||
error = fs.ListXAttr(path + "/" + entry.Key, out List<string> xattrs);
|
||||
|
||||
if(error != ErrorNumber.NoError) continue;
|
||||
@@ -372,28 +406,28 @@ sealed class LsCommand : Command<LsCommand.Settings>
|
||||
error = fs.GetXattr(path + "/" + entry.Key, xattr, ref xattrBuf);
|
||||
|
||||
if(error == ErrorNumber.NoError)
|
||||
AaruLogging.WriteLine("\t\t[orange3]{0}[/]\t{1:##,#}",
|
||||
Markup.Escape(xattr),
|
||||
xattrBuf.Length);
|
||||
{
|
||||
table.AddRow("", $"[lime]{xattrBuf.Length}[/]", "", $"[fuchsia]{Markup.Escape(xattr)}[/]");
|
||||
|
||||
AaruLogging.Information($"{xattrBuf.Length} {xattr}");
|
||||
}
|
||||
}
|
||||
else
|
||||
AaruLogging.WriteLine("{0, 47}{1}", string.Empty, Markup.Escape(entry.Key));
|
||||
}
|
||||
else
|
||||
{
|
||||
AaruLogging.WriteLine(entry.Value?.Attributes.HasFlag(FileAttributes.Directory) == true
|
||||
? "[green]{0}/[/]"
|
||||
: "[teal]{0}[/]",
|
||||
Markup.Escape(entry.Key));
|
||||
table.AddRow("", "", "", $"[green]{Markup.Escape(entry.Key)}[/]");
|
||||
|
||||
AaruLogging.Information(entry.Key);
|
||||
}
|
||||
}
|
||||
|
||||
AnsiConsole.Write(table);
|
||||
AaruLogging.WriteLine();
|
||||
|
||||
|
||||
foreach(KeyValuePair<string, FileEntryInfo> subdirectory in
|
||||
stats.Where(e => e.Value?.Attributes.HasFlag(FileAttributes.Directory) == true))
|
||||
ListFilesInDir(path + "/" + subdirectory.Key, fs, longFormat);
|
||||
ListFilesInDir(path + "/" + subdirectory.Key, fs);
|
||||
}
|
||||
|
||||
#region Nested type: Settings
|
||||
@@ -404,10 +438,6 @@ sealed class LsCommand : Command<LsCommand.Settings>
|
||||
[CommandOption("-e|--encoding")]
|
||||
[DefaultValue(null)]
|
||||
public string Encoding { get; init; }
|
||||
[Description("Use long format.")]
|
||||
[CommandOption("-l|--long-format")]
|
||||
[DefaultValue(true)]
|
||||
public bool LongFormat { get; init; }
|
||||
[Description("Comma separated name=value pairs of options to pass to filesystem plugin.")]
|
||||
[CommandOption("-O|--options")]
|
||||
[DefaultValue(null)]
|
||||
|
||||
Reference in New Issue
Block a user