import * as child_process from 'node:child_process';
import { type IWaitForExitResult } from '@rushstack/node-core-library';
import type { RushConfiguration } from '../api/RushConfiguration';
import { syncNpmrc } from './npmrcUtilities';
export type UNINITIALIZED = 'UNINITIALIZED';
export declare const UNINITIALIZED: UNINITIALIZED;
export interface IEnvironment {
    [environmentVariableName: string]: string | undefined;
}
/**
 * Options for {@link Utilities.executeCommandAsync}.
 */
export interface IExecuteCommandOptions {
    command: string;
    args: string[];
    workingDirectory: string;
    environment?: IEnvironment;
    suppressOutput?: boolean;
    keepEnvironment?: boolean;
    /**
     * Note that this takes precedence over {@link IExecuteCommandOptions.suppressOutput}
     */
    onStdoutStreamChunk?: (chunk: string) => string | void;
    captureExitCodeAndSignal?: boolean;
}
/**
 * Options for {@link Utilities.installPackageInDirectoryAsync}.
 */
export interface IInstallPackageInDirectoryOptions {
    directory: string;
    packageName: string;
    version: string;
    tempPackageTitle: string;
    maxInstallAttempts: number;
    commonRushConfigFolder: string | undefined;
    suppressOutput?: boolean;
    /**
     * Whether to filter npm-incompatible properties from .npmrc.
     * This should be true when the .npmrc is configured for a different package manager (pnpm/yarn)
     * but npm is being used to install packages.
     */
    filterNpmIncompatibleProperties?: boolean;
}
export interface ILifecycleCommandOptions {
    /**
     * The rush configuration, if the command is running in a rush repo.
     */
    rushConfiguration: RushConfiguration | undefined;
    /**
     * Working directory for running the command
     */
    workingDirectory: string;
    /**
     * The folder containing a local .npmrc, which will be used for the INIT_CWD environment variable
     */
    initCwd: string;
    /**
     * If true, suppress the process's output, but if there is a nonzero exit code then print stderr
     */
    handleOutput: boolean;
    /**
     * an existing environment to copy instead of process.env
     */
    initialEnvironment?: IEnvironment;
    /**
     * Options for what should be added to the PATH variable
     */
    environmentPathOptions: IEnvironmentPathOptions;
    /**
     * If true, attempt to establish a NodeJS IPC channel to the child process.
     */
    ipc?: boolean;
    /**
     * If true, wire up SubprocessTerminator to the child process.
     */
    connectSubprocessTerminator?: boolean;
}
export interface IEnvironmentPathOptions {
    /**
     * If true, include <project root>/node_modules/.bin in the PATH. If both this and
     * {@link IEnvironmentPathOptions.includeRepoBin} are set, this path will take precedence.
     */
    includeProjectBin?: boolean;
    /**
     * If true, include <repo root>/common/temp/node_modules/.bin in the PATH.
     */
    includeRepoBin?: boolean;
    /**
     * Additional folders to be prepended to the search PATH.
     */
    additionalPathFolders?: string[] | undefined;
}
export interface IDisposable {
    dispose(): void;
}
export type IExecuteCommandAndCaptureOutputOptions = Omit<IExecuteCommandOptions, 'suppressOutput' | 'onStdoutStreamChunk'>;
type OptionalKeys<T> = {
    [K in keyof T]-?: {} extends Pick<T, K> ? K : never;
}[keyof T];
export type OptionalToUndefined<T> = Omit<T, OptionalKeys<T>> & {
    [K in OptionalKeys<T>]-?: Exclude<T[K], undefined> | undefined;
};
export interface ICommandAndArgs {
    command: string;
    args: string[];
}
export declare class Utilities {
    static syncNpmrc: typeof syncNpmrc;
    /**
     * Node.js equivalent of performance.now().
     */
    static getTimeInMs(): number;
    /**
     * Retries a function until a timeout is reached. The function is expected to throw if it failed and
     *  should be retried.
     */
    static retryUntilTimeout<TResult>(fn: () => TResult, maxWaitTimeMs: number, getTimeoutError: (innerError: Error) => Error, fnName: string): TResult;
    /**
     * Creates the specified folder by calling FileSystem.ensureFolder(), but using a
     * retry loop to recover from temporary locks that may be held by other processes.
     * If the folder already exists, no error occurs.
     */
    static createFolderWithRetry(folderName: string): void;
    /**
     * Determines if a path points to a directory and that it exists.
     */
    static directoryExists(directoryPath: string): boolean;
    /**
     * BE VERY CAREFUL CALLING THIS FUNCTION!
     * If you specify the wrong folderPath (e.g. "/"), it could potentially delete your entire
     * hard disk.
     */
    static dangerouslyDeletePath(folderPath: string): void;
    static isFileTimestampCurrentAsync(dateToCompare: Date, inputFilePaths: string[]): Promise<boolean>;
    static executeCommandAsync(options: IExecuteCommandOptions & {
        captureExitCodeAndSignal: true;
    }): Promise<Pick<IWaitForExitResult, 'exitCode' | 'signal'>>;
    static executeCommandAsync(options: IExecuteCommandOptions): Promise<void>;
    /**
     * Executes the command with the specified command-line parameters, and waits for it to complete.
     * The current directory will be set to the specified workingDirectory.
     */
    static executeCommandAndCaptureOutputAsync(options: IExecuteCommandAndCaptureOutputOptions & {
        captureExitCodeAndSignal?: false;
    }): Promise<string>;
    static executeCommandAndCaptureOutputAsync(options: IExecuteCommandAndCaptureOutputOptions & {
        captureExitCodeAndSignal: true;
    }): Promise<IWaitForExitResult<string>>;
    /**
     * Attempts to run Utilities.executeCommand() up to maxAttempts times before giving up.
     */
    static executeCommandWithRetryAsync(options: IExecuteCommandOptions, maxAttempts: number, retryCallback?: () => void): Promise<void>;
    /**
     * Executes the command using cmd if running on windows, or using sh if running on a non-windows OS.
     * @param command - the command to run on shell
     * @param options - options for how the command should be run
     */
    static executeLifecycleCommand(command: string, options: ILifecycleCommandOptions): number;
    /**
     * Executes the command using cmd if running on windows, or using sh if running on a non-windows OS.
     * @param command - the command to run on shell
     * @param options - options for how the command should be run
     */
    static executeLifecycleCommandAsync(command: string, options: ILifecycleCommandOptions): child_process.ChildProcess;
    /**
     * Installs a package by name and version in the specified directory.
     */
    static installPackageInDirectoryAsync({ packageName, version, tempPackageTitle, commonRushConfigFolder, maxInstallAttempts, suppressOutput, directory, filterNpmIncompatibleProperties }: IInstallPackageInDirectoryOptions): Promise<void>;
    /**
     * Copies the file "sourcePath" to "destinationPath", overwriting the target file location.
     * If the source file does not exist, then the target file is deleted.
     */
    static syncFile(sourcePath: string, destinationPath: string): void;
    static getRushConfigNotFoundError(): Error;
    static usingAsync<TDisposable extends IDisposable>(getDisposableAsync: () => Promise<TDisposable> | IDisposable, doActionAsync: (disposable: TDisposable) => Promise<void> | void): Promise<void>;
    static trimAfterLastSlash(filePath: string): string;
    /**
     * If the path refers to a symlink, `FileSystem.exists()` would normally test whether the symlink
     * points to a target that exists. By contrast, `existsOrIsBrokenSymlink()` will return true even if
     * the symlink exists but its target does not. */
    static existsOrIsSymlink(linkPath: string): boolean;
    /** @internal */
    static _convertCommandAndArgsToShell(command: string, isWindows?: boolean): ICommandAndArgs;
    static _convertCommandAndArgsToShell(options: ICommandAndArgs, isWindows?: boolean): ICommandAndArgs;
    private static _executeLifecycleCommandInternal;
    /**
     * Returns a process.env environment suitable for executing lifecycle scripts.
     * @param initialEnvironment - an existing environment to copy instead of process.env
     *
     * @remarks
     * Rush._assignRushInvokedFolder() assigns the `RUSH_INVOKED_FOLDER` variable globally
     * via the parent process's environment.
     */
    private static _createEnvironmentForRushCommand;
    /**
     * Prepend the node_modules/.bin folder under the specified folder to the specified PATH variable. For example,
     * if `rootDirectory` is "/foobar" and `existingPath` is "/bin", this function will return
     * "/foobar/node_modules/.bin:/bin"
     */
    private static _prependNodeModulesBinToPath;
    /**
     * Executes the command with the specified command-line parameters, and waits for it to complete.
     * The current directory will be set to the specified workingDirectory.
     */
    private static _executeCommandInternalAsync;
    private static _processResult;
}
export {};
//# sourceMappingURL=Utilities.d.ts.map