Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ uucore = { path = "deps/coreutils/src/uucore" }
uucore_procs = { path = "deps/coreutils/src/uucore_procs" }

[dependencies]
# Dependency versions match those used in deps/coreutils.
wild = "2.2.1"
clap = { version = "4.5", features = ["wrap_help", "cargo", "color"] }
itertools = "0.14"
phf = "0.13"
Expand Down Expand Up @@ -130,8 +132,14 @@ ntfind = { package = "find", path = "deps/ntfind" }
[dependencies.windows-sys]
version = "*"
features = [
"Win32_Foundation",
"Win32_Security_Cryptography",
"Win32_Storage_FileSystem",
"Win32_System_Console",
"Win32_System_Pipes",
"Win32_System_Registry",
"Win32_UI_Shell",
"Win32_UI_WindowsAndMessaging",
]

[build-dependencies]
Expand Down
15 changes: 15 additions & 0 deletions PSScriptAnalyzerSettings.psd1
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
@{
Rules = @{
PSUseCompatibleCommands = @{
Enable = $true
TargetProfiles = @('win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')
}
PSUseCompatibleSyntax = @{
Enable = $true
TargetVersions = @('5.1', '7.0')
}
PSAvoidOverwritingBuiltInCmdlets = @{ Enable = $false }
PSUseShouldProcessForStateChangingFunctions = @{ Enable = $false }
PSUseSingularNouns = @{ Enable = $false }
}
}
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ Or grab the latest build from our [Release Page](https://github.com/microsoft/co
> [!NOTE]
> Any command not mentioned is included in this suite. The following only lists conflicts.
> [!NOTE]
> You can remove additional utilities using `coreutils-manager disable <utility name>`.
> See `coreutils-manager --help` for other management commands.
> [!WARNING]
> PowerShell 7.4 or later is required.
> PowerShell 7.6 or later is recommended for `~` support.
Expand Down
7 changes: 6 additions & 1 deletion build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ fn generate_uutils_map() {
entries.push(("sort".into(), "(sort_uumain, sort_uu_app)".into()));
}

entries.push((
"coreutils-manager".into(),
"(manager::uumain, manager::uu_app)".into(),
));

entries.sort();

let mut phf_map = phf_codegen::OrderedMap::new();
Expand All @@ -74,7 +79,7 @@ type UtilityMap<T> = phf::OrderedMap<&'static str, (fn(T) -> i32, fn() -> Comman

#[allow(clippy::too_many_lines)]
#[allow(clippy::unreadable_literal)]
fn util_map<T: Args>() -> UtilityMap<T> {{
const fn util_map<T: Args>() -> UtilityMap<T> {{
{}
}}
",
Expand Down
27 changes: 13 additions & 14 deletions coreutils.iss
Original file line number Diff line number Diff line change
Expand Up @@ -93,25 +93,24 @@ end;
procedure CreateHardlinks;
var
Output: TExecOutput;
Name: String;
ResultCode, I: Integer;
Detail: String;
ResultCode: Integer;
begin
ForceDirectories(g_AppBinDirPath);
ForceDirectories(g_AppCmdDirPath);

if (not ExecAndCaptureOutput(g_CoreutilsExePath, '--list', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode, Output)) or (ResultCode <> 0) then
RaiseException('Failed to execute coreutils.exe --list');

for I := 0 to GetArrayLength(Output.StdOut) - 1 do
if (not ExecAndCaptureOutput(g_CoreutilsExePath, 'coreutils-manager refresh', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode, Output)) or (ResultCode <> 0) then
begin
Name := Trim(Output.StdOut[I]);
if (Name <> '') and (Name <> '[') then
begin
if not CreateHardLink(g_AppBinDirPath + Name + '.exe', g_CoreutilsExePath, 0) then
RaiseException('Failed to create hardlink for ' + Name);
if not CreateHardLink(g_AppCmdDirPath + Name + '.cmd', g_CoreutilsExePath, 0) then
RaiseException('Failed to create hardlink for ' + Name);
end;
Detail := '';
if GetArrayLength(Output.StdErr) > 0 then
Detail := Output.StdErr[0]
else if GetArrayLength(Output.StdOut) > 0 then
Detail := Output.StdOut[0];

if Detail <> '' then
RaiseException('Failed to refresh coreutils links: ' + Detail)
else
RaiseException('Failed to refresh coreutils links');
end;
end;

Expand Down
31 changes: 19 additions & 12 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// Microsoft-authored changes, which Microsoft makes available to uutils
// under the uutils MIT License for upstream incorporation. See NOTICE.md.

mod manager;
mod nthelpers;

use std::borrow::Cow;
Expand All @@ -16,9 +17,10 @@ use std::sync::atomic::AtomicU32;

use clap::Command;
use itertools::Itertools as _;
use uucore::Args;
use uucore::display::Quotable as _;
use uucore::windows_sys::Win32::System::Threading::GetCurrentProcess;
use uucore::{Args, error::strip_errno, locale};
use uucore::{error::strip_errno, locale};
use windows_sys::Win32::Globalization::CP_UTF8;
use windows_sys::Win32::System::Console;
use windows_sys::Win32::System::Threading::TerminateProcess;
Expand All @@ -28,10 +30,14 @@ unsafe extern "C" {
unsafe fn ntsort_main(argc: i32, argv: *const *const u8) -> i32;
}

const VERSION: &str = env!("CARGO_PKG_VERSION");

include!(concat!(env!("OUT_DIR"), "/uutils_map.rs"));

// While uucore::Args is a trait, this is the actual type it'll resolve to in the end.
type ArgsType = std::iter::Chain<std::vec::IntoIter<std::ffi::OsString>, wild::ArgsOs>;

const VERSION: &str = env!("CARGO_PKG_VERSION");
const UTIL_MAP: UtilityMap<ArgsType> = util_map();

fn usage<T>(utils: &UtilityMap<T>, name: &str) {
let display_list = utils.keys().copied().join(", ");
let width = cmp::min(textwrap::termwidth(), 100) - 8; // (opinion/heuristic) max 100 chars wide with 4 character side indentions
Expand Down Expand Up @@ -70,18 +76,19 @@ fn main() {
// ntsort just hardcodes to CP_OEMCP, so it also isn't affected.
set_console_modes();

let utils = util_map();
let mut args = uucore::args_os();

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed this code such that I have access to util_map() in the the manager.rs module. I could've just called util_map() again but that felt sloppy to me.

// `wild::args_os()` is what `uucore::args_os()` uses under the hood.
// By using it directly we avoid duplicating all arg strings.
let mut args = wild::args_os();

let binary = binary_path(&mut args);
let binary_as_util = name(&binary).unwrap_or_else(|| {
usage(&utils, "<unknown binary name>");
usage(&UTIL_MAP, "<unknown binary name>");
exit(0);
});

// binary name ends with util name?
let is_coreutils = binary_as_util.ends_with("utils");
let matched_util = utils
let matched_util = UTIL_MAP
.keys()
.filter(|&&u| binary_as_util.ends_with(u) && !is_coreutils)
.max_by_key(|u| u.len()); //Prefer stty more than tty. *utils is not ls
Expand Down Expand Up @@ -110,7 +117,7 @@ fn main() {
exit(1);
}
let mut out = io::stdout().lock();
for util in utils.keys() {
for util in UTIL_MAP.keys() {
if let Err(e) = writeln!(out, "{util}")
&& e.kind() != io::ErrorKind::BrokenPipe
{
Expand All @@ -133,7 +140,7 @@ fn main() {
_ => {}
}

match utils.get(util) {
match UTIL_MAP.get(util) {
Some(&(uumain, _)) => {
// TODO: plug the deactivation of the translation
// and load the English strings directly at compilation time in the
Expand All @@ -151,7 +158,7 @@ fn main() {
not_found(&util_os)
};

match utils.get(util) {
match UTIL_MAP.get(util) {
Some(&(uumain, _)) => {
setup_localization_or_exit(util);
let code = uumain(
Expand All @@ -165,7 +172,7 @@ fn main() {
None => not_found(&util_os),
}
}
usage(&utils, binary_as_util);
usage(&UTIL_MAP, binary_as_util);
exit(0);
} else if util.starts_with('-') {
// Argument looks like an option but wasn't recognized
Expand All @@ -179,7 +186,7 @@ fn main() {
// GNU just fails, but busybox tests needs usage
// todo: patch the test suite instead
if binary_as_util.ends_with("box") {
usage(&utils, binary_as_util);
usage(&UTIL_MAP, binary_as_util);
} else {
let _ = writeln!(io::stderr(), "coreutils: missing argument");
}
Expand Down
Loading