/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { var io = GetIO(); var bucket = GetBucket(); string binary = input.GetArgument("binary"); if (input.GetOption("list") || string.IsNullOrEmpty(binary)) { OutputList(bucket, io); return(ExitCodes.Normal); } var dispatcher = bucket.GetEventDispatcher(); if (output.IsNormal) { output.SetVerbosity(OutputOptions.VerbosityQuiet); } var scriptEventArgs = new ScriptEventArgs("__exec_command", bucket, io, true, input.GetArgument("args")); dispatcher.AddListener("__exec_command", (sender, eventArgs) => { if (dispatcher is BEventDispatcher bucketEventDispatcher) { bucketEventDispatcher.ExecuteScript(binary, sender, (ScriptEventArgs)eventArgs); return; } throw new NotSupportedException("The \"exec\" command can be used only when the event system is BucketEventSystem."); }); dispatcher.Dispatch(this, scriptEventArgs); return(scriptEventArgs.ExitCode); }
/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { if (input.GetOption("list")) { return(ListScripts(output)); } string script = input.GetArgument("script"); if (string.IsNullOrEmpty(script)) { throw new RuntimeException("Missing required argument \"script\""); } var defiendEvents = new HashSet <string>(ScriptEvents.GetEvents()); var disabledScript = script.ToUpper().Replace("-", "_"); if (!defiendEvents.Contains(script) && defiendEvents.Contains(disabledScript)) { throw new RuntimeException($"Script \"{script}\" cannot be run with this command"); } var bucket = GetBucket(); var devMode = input.GetOption("dev") || !input.GetOption("no-dev"); var eventDispatcher = bucket.GetEventDispatcher(); if (!eventDispatcher.HasListener(script)) { throw new RuntimeException($"Script \"{script}\" is not defined in this package"); } string[] args = input.GetArgument("args"); string timeout = input.GetOption("timeout"); if (timeout != null) { BucketProcessExecutor.SetDefaultTimeout(int.Parse(timeout)); } var eventArgs = new ScriptEventArgs(script, bucket, GetIO(), devMode, args); eventDispatcher.Dispatch(this, eventArgs); return(eventArgs.ExitCode); }
/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { var bucket = GetBucket(true, input.GetOption("no-plugins")); string[] packages = input.GetArgument("packages") ?? Array.Empty <string>(); packages = ProcessRootRequires(bucket.GetPackage(), input, packages); // todo: set no-progress. // todo: add gui interactive select the packages. var commandEvent = new CommandEventArgs(PluginEvents.Command, "update", input, output); bucket.GetEventDispatcher().Dispatch(this, commandEvent); var io = GetIO(); var installer = new BucketInstaller(io, bucket); var config = bucket.GetConfig(); var(preferSource, preferDist) = GetPreferredInstallOptions(config, input); ISet <string> GetUpdateWhitlist() { if (input.GetOption("lock")) { return(new HashSet <string>(new[] { "lock" })); } return(packages.Empty() ? null : new HashSet <string>(packages)); } installer.SetDryRun(input.GetOption("dry-run")) .SetVerbose(input.GetOption("verbose")) .SetPreferSource(preferSource) .SetPreferDist(preferDist) .SetDevMode(!input.GetOption("no-dev")) .SetRunScripts(!input.GetOption("no-scripts")) .SetSkipSuggest(input.GetOption("no-suggest")) .SetIgnorePlatformRequirements(input.GetOption("ignore-platform-reqs")) .SetUpdate(true) .SetUpdateWhitelist(GetUpdateWhitlist()) .SetWhitelistAllDependencies(input.GetOption("with-all-dependencies")) .SetWhitelistTransitiveDependencies(input.GetOption("with-dependencies")) .SetPreferStable(input.GetOption("prefer-stable")) .SetPreferLowest(input.GetOption("prefer-lowest")); if (input.GetOption("no-plugins")) { installer.DisablePlugins(); } return(installer.Run()); }
/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { var io = GetIO(); string[] args = input.GetArgument("packages"); if (!args.Empty()) { io.WriteError($"<error>Invalid argument {string.Join(Str.Space, args)}. Use \"bucket require {string.Join(Str.Space, args)}\" instead to add packages to your bucket.json.</error>"); return(ExitCodes.GeneralException); } var bucket = GetBucket(true, input.GetOption("no-plugins")); // todo: set no-progress. var commandEvent = new CommandEventArgs(PluginEvents.Command, "install", input, output); bucket.GetEventDispatcher().Dispatch(this, commandEvent); var installer = new BucketInstaller(io, bucket); var config = bucket.GetConfig(); var(preferSource, preferDist) = GetPreferredInstallOptions(config, input); installer.SetDryRun(input.GetOption("dry-run")) .SetVerbose(input.GetOption("verbose")) .SetPreferSource(preferSource) .SetPreferDist(preferDist) .SetDevMode(!input.GetOption("no-dev")) .SetRunScripts(!input.GetOption("no-scripts")) .SetSkipSuggest(input.GetOption("no-suggest")) .SetIgnorePlatformRequirements(input.GetOption("ignore-platform-reqs")); if (input.GetOption("no-plugins")) { installer.DisablePlugins(); } return(installer.Run()); }
/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { var platformRepository = new RepositoryPlatform(); var io = GetIO(); var bucket = GetBucket(false); if (!bucket) { var factory = new Factory(); bucket = factory.CreateBucket(io, new ConfigBucket(), input.HasRawOption("--no-plugins")); } var localInstalledRepository = bucket.GetRepositoryManager().GetLocalInstalledRepository(); var repositoryInstalled = new RepositoryComposite(localInstalledRepository, platformRepository); var repositories = new RepositoryComposite(Arr.Merge(new[] { repositoryInstalled }, bucket.GetRepositoryManager().GetRepositories())); var commandEvent = new CommandEventArgs(PluginEvents.Command, "search", input, output); bucket.GetEventDispatcher().Dispatch(this, commandEvent); var flags = input.GetOption("only-name") ? SearchMode.Name : SearchMode.Fulltext; var results = repositories.Search(string.Join(Str.Space, input.GetArgument("tokens")), flags, input.GetOption("type")); var seed = new HashSet <string>(); foreach (var result in results) { if (!seed.Add(result.GetName())) { continue; } io.Write(result.ToString()); } return(ExitCodes.Normal); }
/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { var io = GetIO(); var versionUtility = new BucketVersions(io, config, transport); Channel?storedChannel = null; foreach (var channel in new[] { Channel.Stable, Channel.Preview, Channel.Dev }) { // An unstable version will overwrite a stable version. if (input.GetOption(channel.ToString().ToLower())) { versionUtility.SetChannel(channel); storedChannel = channel; } } if (input.GetOption("set-channel-only")) { if (storedChannel != null) { io.WriteError($"Channel {storedChannel.ToString().ToLower()} has been saved."); } else { io.WriteError($"Channel not stored."); } return(ExitCodes.Normal); } if (input.GetOption("update-keys")) { return(FetchKeys(io, config)); } if (input.GetOption("rollback")) { return(Rollback(io, installDir, backupDir)); } var(lastedVersion, remoteFileUri, lastedVersionPretty, _) = versionUtility.GetLatest(); var updateVersion = input.GetArgument("version") ?? lastedVersion; var updatingWithDev = versionUtility.GetChannel() == Channel.Dev; // If it is the latest version we end the update. if (Bucket.GetVersion() == updateVersion) { io.WriteError($"<info>You are already using bucket version <comment>{Bucket.GetVersionPretty()}</comment> ({Bucket.GetVersion()},{versionUtility.GetChannel().ToString().ToLower()} channel).</info>"); CheckCleanupBackups(io, input, backupDir); return(ExitCodes.Normal); } if (string.IsNullOrEmpty(remoteFileUri)) { var remoteRelativePath = updatingWithDev ? $"/snapshot/{updateVersion}/bucket.zip" : $"/releases/{updateVersion}/bucket.zip"; remoteFileUri = $"{baseUri}{remoteRelativePath}"; } else if (!BucketUri.IsAbsoluteUri(remoteFileUri)) { remoteFileUri = new Uri(new Uri(baseUri), remoteFileUri).ToString(); } var tempFile = Path.Combine(tempDir, Path.GetFileName(remoteFileUri)); var signatureFile = updatingWithDev ? $"{home}/keys.dev.pem" : $"{home}/keys.tags.pem"; tempFile = DownloadRemoteFile(io, remoteFileUri, tempFile, signatureFile); // Clean up the backup first, so that the current version // will be the last version. CheckCleanupBackups(io, input, backupDir); try { InstalltionBucket(installDir, tempFile, backupFile); } #pragma warning disable CA1031 catch (SException ex) #pragma warning restore CA1031 { fileSystem.Delete(tempFile); io.WriteError($"<error>The file is corrupted ({ex.Message}).</error>"); io.WriteError("<error>Please re-run the self-update command to try again.</error>"); return(ExitCodes.GeneralException); } // The version number may be entered by the user. if (updateVersion == lastedVersion) { io.WriteError($"Bucket has been successfully upgraded to: <comment>{Bucket.ParseVersionPretty(lastedVersionPretty)}</comment> ({lastedVersion})"); } else { io.WriteError($"Bucket has been successfully upgraded to: <comment>{updateVersion}</comment>"); } if (fileSystem.Exists(backupFile, FileSystemOptions.File)) { io.WriteError($"Use <info>bucket self-update --rollback</info> to return to version <comment>{Bucket.GetVersionPretty()}</comment> ({Bucket.GetVersion()})"); } else { io.WriteError($"<warning>A backup of the current version could not be written to {backupFile}, no rollback possible</warning>"); } return(ExitCodes.Normal); }
/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { string[] packages = input.GetArgument("packages"); packages = Arr.Map(packages, (package) => package.ToLower()); var file = Factory.GetBucketFile(); var filePath = Path.Combine(Environment.CurrentDirectory, file); var jsonFile = new JsonFile(filePath); var configBucket = jsonFile.Read <ConfigBucket>(); var backup = File.ReadAllText(filePath); var source = new JsonConfigSource(jsonFile); var io = GetIO(); var requireKey = input.GetOption("dev") ? LinkType.RequireDev : LinkType.Require; var alternativeRequireKey = input.GetOption("dev") ? LinkType.Require : LinkType.RequireDev; var requireMapping = new Dictionary <string, string>(); var alternativeRequireMapping = new Dictionary <string, string>(); void EstablishCaseMapping(IDictionary <string, string> mapping, LinkType type) { var collection = type == LinkType.Require ? configBucket.Requires : configBucket.RequiresDev; if (collection == null) { return; } foreach (var item in collection) { mapping[item.Key.ToLower()] = item.Key; } } EstablishCaseMapping(requireMapping, requireKey); EstablishCaseMapping(alternativeRequireMapping, alternativeRequireKey); bool TryGetMatchPackages(IDictionary <string, string> mapping, string package, out IEnumerable <string> matches) { var result = new List <string>(); var regexPackage = BasePackage.PackageNameToRegexPattern(package); foreach (var item in mapping) { if (Regex.IsMatch(item.Key, regexPackage, RegexOptions.IgnoreCase)) { result.Add(item.Value); } } matches = result; return(result.Count > 0); } foreach (var package in packages) { if (requireMapping.TryGetValue(package, out string originalName)) { source.RemoveLink(requireKey, originalName); } else if (alternativeRequireMapping.TryGetValue(package, out originalName)) { io.WriteError($"<warning>{originalName} could not be found in {Str.LowerDashes(requireKey.ToString())} but it is present in {Str.LowerDashes(alternativeRequireKey.ToString())}</warning>"); if (io.IsInteractive && io.AskConfirmation($"Do you want to remove it from {Str.LowerDashes(alternativeRequireKey.ToString())} [<comment>yes</comment>]? ", true)) { source.RemoveLink(alternativeRequireKey, originalName); } } else if (TryGetMatchPackages(requireMapping, package, out IEnumerable <string> matches)) { foreach (var match in matches) { source.RemoveLink(requireKey, match); } } else if (TryGetMatchPackages(alternativeRequireMapping, package, out matches)) { foreach (var match in matches) { io.WriteError($"<warning>{match} could not be found in {Str.LowerDashes(requireKey.ToString())} but it is present in {Str.LowerDashes(alternativeRequireKey.ToString())}</warning>"); if (io.IsInteractive && io.AskConfirmation($"Do you want to remove it from {Str.LowerDashes(alternativeRequireKey.ToString())} [<comment>yes</comment>]? ", true)) { source.RemoveLink(alternativeRequireKey, match); } } } else { io.WriteError($"<warning>{package} is not required in your bucket.json and has not been removed</warning>"); } } if (input.GetOption("no-update")) { return(ExitCodes.Normal); } // todo: implement installer uninstall. ResetBucket(); var bucket = GetBucket(true, input.GetOption("no-plugins")); // todo: set no-progress. var commandEvent = new CommandEventArgs(PluginEvents.Command, "remove", input, output); bucket.GetEventDispatcher().Dispatch(this, commandEvent); ISet <string> GetRemoveWhitlist() { Guard.Requires <UnexpectedException>(packages.Length > 0); return(new HashSet <string>(packages)); } var installer = new BucketInstaller(io, bucket); var status = installer .SetVerbose(input.GetOption("verbose")) .SetDevMode(!input.GetOption("update-no-dev")) .SetRunScripts(!input.GetOption("no-scripts")) .SetUpdate(true) .SetUpdateWhitelist(GetRemoveWhitlist()) .SetWhitelistTransitiveDependencies(!input.GetOption("no-update-with-dependencies")) .SetIgnorePlatformRequirements(input.GetOption("ignore-platform-reqs")) .Run(); if (status != 0) { io.WriteError($"{Environment.NewLine}<error>Removal failed, reverting {file} to its original content.</error>"); File.WriteAllText(filePath, backup); } return(status); }
/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { var file = input.GetArgument("file") ?? Factory.GetBucketFile(); var io = GetIO(); var fileSystem = new FileSystemLocal(); if (!fileSystem.Exists(file)) { io.WriteError($"<error>{file} not found.</error>"); return(ExitCodes.FileNotFoundException); } var checkPublish = !input.GetOption("no-check-publish"); var checkLock = !input.GetOption("no-check-lock"); var isStrict = input.GetOption("strict"); var validator = new ValidatorBucket(fileSystem, io); var(warnings, publishErrors, errors) = validator.Validate(file); var lockErrors = Array.Empty <string>(); var bucket = Factory.Create(io, file, input.HasRawOption("--no-plugins")); var locker = bucket.GetLocker(); if (locker.IsLocked() && !locker.IsFresh()) { lockErrors = new[] { "The lock file is not up to date with the latest changes in bucket.json, it is recommended that you run `bucket update`." }; } OuputResult(file, ref errors, ref warnings, checkPublish, publishErrors, checkLock, lockErrors, isStrict); int GetStrictExitCode() { return((isStrict && !warnings.Empty()) ? ExitCodes.ValidationWarning : GameBox.Console.ExitCodes.Normal); } var exitCode = errors.Length > 0 ? ExitCodes.ValidationErrors : GetStrictExitCode(); if (input.GetOption("with-dependencies")) { var localInstalledRepository = bucket.GetRepositoryManager().GetLocalInstalledRepository(); foreach (var package in localInstalledRepository.GetPackages()) { var path = bucket.GetInstallationManager().GetInstalledPath(package); file = Path.Combine(path, "bucket.json"); if (!Directory.Exists(path) || !File.Exists(file)) { continue; } (warnings, publishErrors, errors) = validator.Validate(file); OuputResult(file, ref errors, ref warnings, checkPublish, publishErrors, isStrict: isStrict); var depCode = !errors.Empty() ? ExitCodes.ValidationErrors : GetStrictExitCode(); exitCode = Math.Max(depCode, exitCode); } } var commandEvent = new CommandEventArgs(PluginEvents.Command, "validate", input, output); bucket.GetEventDispatcher().Dispatch(this, commandEvent); return(Math.Max(exitCode, commandEvent.ExitCode)); }
/// <inheritdoc /> protected override int Execute(IInput input, IOutput output) { file = Factory.GetBucketFile(); filePath = Path.Combine(Environment.CurrentDirectory, file); var io = GetIO(); newlyCreated = !File.Exists(filePath); if (newlyCreated) { try { File.WriteAllText(filePath, NewBucketContent); } #pragma warning disable CA1031 catch (SException ex) #pragma warning restore CA1031 { io.WriteError($"<error>{file} could not be created: {ex.Message}.</error>"); return(ExitCodes.GeneralException); } } backup = File.ReadAllText(filePath); if (string.IsNullOrEmpty(backup)) { File.WriteAllText(filePath, NewBucketContent); backup = NewBucketContent; } json = new JsonFile(filePath); var bucket = GetBucket(true, input.GetOption("no-plugins")); // todo: import mock platform repository = new RepositoryComposite( Arr.Merge( new[] { new RepositoryPlatform(bucket.GetPackage().GetPlatforms()) }, bucket.GetRepositoryManager().GetRepositories())); var preferredStability = Stabilities.Stable; var preferredStable = bucket.GetPackage().IsPreferStable ?? false; if (!preferredStable) { preferredStability = bucket.GetPackage().GetMinimumStability() ?? preferredStability; } var requireKey = input.GetOption("dev") ? LinkType.RequireDev : LinkType.Require; var removeKey = input.GetOption("dev") ? LinkType.Require : LinkType.RequireDev; var requirements = FormatRequirements( DetermineRequirements(input, output, input.GetArgument("packages"), preferredStability, !input.GetOption("no-update"))); // validate requirements format. var versionParser = new BVersionParser(); foreach (var item in requirements) { var package = item.Key; var constraint = item.Value; if (package.ToLower() == bucket.GetPackage().GetName()) { io.WriteError($"<error>Root package \"{package}\" cannot require itself in its bucket.json</error>"); return(ExitCodes.Normal); } versionParser.ParseConstraints(constraint); } var sortPackages = input.GetOption("sort-packages") || bucket.GetConfig().Get(Settings.SortPackages); if (!UpdateFileCleanly(json, requirements, requireKey, removeKey, sortPackages)) { File.WriteAllText(filePath, backup); throw new RuntimeException("Failed to write to file successfully, operation has been rolled back."); } io.WriteError($"<info>{file} has been {(newlyCreated ? "created" : "update")}</info>"); if (input.GetOption("no-update")) { return(ExitCodes.Normal); } try { return(DoUpdate(input, output, io, requirements)); } catch (SException) { RevertBucketFile(false); throw; } }