From 7bd2a3976eec0237b08ab2d879c7fd339607e97b Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Sun, 7 May 2017 15:33:11 -0500 Subject: [PATCH 01/18] (GH-1284) Install-ChocolateyPackage aliases File/File64 When passing File and FileType to Install-ChocolateyPackage, it can cause the following issue to occur: ~~~ ERROR: Cannot bind parameter because parameter 'fileType' is specified more than once. To provide multiple values to parameters that can accept multiple values, use the array syntax. For example, "-parameter value1,value2,value3". ~~~ This is well documented at https://github.com/chocolatey/choco/wiki/Troubleshooting#error-cannot-bind-parameter-because-parameter-filetype-is-specified-more-than-once : ~~~powershell $toolsPath = $(Split-Path -parent $MyInvocation.MyCommand.Definition) $packageArgs = @{ packageName = 'test' fileType = 'MSI' file = "$toolsPath\somefile.msi" softwareName = 'test' silentArgs = '/qn /norestart' validExitCodes= @(0) } Install-ChocolateyPackage @packageArgs was meant to be used in this scenario ~~~ `Install-ChocolateyPackage` doesn't have both a `File` parameter and a `FileType` parameter. PowerShell has a "feature" where it does partial matching of parameters. When you splat the parameters in, it tries to apply both `File` and `FileType` to `FileType` and throws the above error. Correct this behavior by setting aliases --- .../functions/Install-ChocolateyPackage.ps1 | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/chocolatey.resources/helpers/functions/Install-ChocolateyPackage.ps1 b/src/chocolatey.resources/helpers/functions/Install-ChocolateyPackage.ps1 index 7578dcdbbb..294dcf2ca1 100644 --- a/src/chocolatey.resources/helpers/functions/Install-ChocolateyPackage.ps1 +++ b/src/chocolatey.resources/helpers/functions/Install-ChocolateyPackage.ps1 @@ -91,6 +91,12 @@ a 32 bit installation on a 64 bit system. Prefer HTTPS when available. Can be HTTP, FTP, or File URIs. +In 0.10.6+, `File` and `FileFullPath` are aliases for Url. These +aliases, if used in earlier versions of Chocolatey, produce `ERROR: +Cannot bind parameter because parameter 'fileType' is specified more +than once.` See https://github.com/chocolatey/choco/issues/1284. Do not +use these aliases with the community package repository until 2018. + .PARAMETER Url64bit OPTIONAL - If there is a 64 bit resource available, use this parameter. Chocolatey will automatically determine if the user is @@ -102,6 +108,13 @@ this parameter. Prefer HTTPS when available. Can be HTTP, FTP, or File URIs. +In 0.10.6+, `File64` and `FileFullPath64` are aliases for Url64Bit. +These aliases, if used in earlier versions of Chocolatey, produce +`ERROR: Cannot bind parameter because parameter 'fileType' is specified +more than once.` See https://github.com/chocolatey/choco/issues/1284. +Do not use these aliases with the community package repository until +2018. + .PARAMETER ValidExitCodes Array of exit codes indicating success. Defaults to `@(0)`. @@ -261,9 +274,9 @@ param( [parameter(Mandatory=$false, Position=1)] [alias("installerType","installType")][string] $fileType = 'exe', [parameter(Mandatory=$false, Position=2)][string[]] $silentArgs = '', - [parameter(Mandatory=$false, Position=3)][string] $url = '', + [alias("file","fileFullPath")][parameter(Mandatory=$false, Position=3)][string] $url = '', [parameter(Mandatory=$false, Position=4)] - [alias("url64")][string] $url64bit = '', + [alias("url64","file64","fileFullPath64")][string] $url64bit = '', [parameter(Mandatory=$false)] $validExitCodes = @(0), [parameter(Mandatory=$false)][string] $checksum = '', [parameter(Mandatory=$false)][string] $checksumType = '', From 100647fae0c0cd2f6800588d8432cc78353bea04 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 8 May 2017 14:12:06 -0500 Subject: [PATCH 02/18] (GH-1287) API - Ensure dll can work w/licensed code When working to determine the issue with the licensed code, a couple of incompatibilities between choco.exe and chocolatey.dll were found that were preventing Chocolatey from allowing the licensed edition to work with the DLL. Specifically, `System.Reflection.TargetInvocationException System.MethodAccessException: Attempt by method to access method failed` as methods for checking some things were missing (internalized) in the DLL, where they were available in the EXE. Adjust to allow for those items to be loaded. --- .build.custom/ilmerge.internalize.ignore.dll.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.build.custom/ilmerge.internalize.ignore.dll.txt b/.build.custom/ilmerge.internalize.ignore.dll.txt index 15e662b505..c823182d83 100644 --- a/.build.custom/ilmerge.internalize.ignore.dll.txt +++ b/.build.custom/ilmerge.internalize.ignore.dll.txt @@ -1,2 +1,4 @@ chocolatey.* -NuGet.* \ No newline at end of file +NuGet.* +SimpleInjector.* +Rhino.Licensing.* \ No newline at end of file From 581db0177e43d6e2b9dd1852a6cef9f25df878dc Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Sun, 14 May 2017 14:25:05 -0500 Subject: [PATCH 03/18] (maint) formatting --- src/chocolatey/GetChocolatey.cs | 22 +++++++++---------- .../runners/GenericRunner.cs | 2 -- .../services/NugetService.cs | 1 - 3 files changed, 11 insertions(+), 14 deletions(-) diff --git a/src/chocolatey/GetChocolatey.cs b/src/chocolatey/GetChocolatey.cs index 56a8f2c5a6..90fecb4d83 100644 --- a/src/chocolatey/GetChocolatey.cs +++ b/src/chocolatey/GetChocolatey.cs @@ -54,10 +54,10 @@ private static void add_assembly_resolver() { var requestedAssembly = new AssemblyName(args.Name); if (requestedAssembly.get_public_key_token().is_equal_to(ApplicationParameters.OfficialChocolateyPublicKey) - && !requestedAssembly.Name.is_equal_to("chocolatey.licensed") + && !requestedAssembly.Name.is_equal_to("chocolatey.licensed") && !requestedAssembly.Name.EndsWith(".resources", StringComparison.OrdinalIgnoreCase)) { - return typeof(Lets).Assembly; + return typeof(Lets).Assembly; } try @@ -86,8 +86,8 @@ private static void add_assembly_resolver() public class GetChocolatey { private readonly Container _container; + private readonly ChocolateyLicense _license; private Action _propConfig; - private ChocolateyLicense _license; /// /// Initializes a new instance of the class. @@ -119,9 +119,9 @@ public GetChocolatey SetCustomLogging(ILog logger) public GetChocolatey Set(Action propConfig) { _propConfig = propConfig; - return this; + return this; } - + /// /// Registers a container component. Does not require a dependency on Simple Injector. /// Will override existing component if registered. @@ -162,7 +162,7 @@ public GetChocolatey RegisterContainerComponent(Lifestyl where Service : class where Implementation : class, Service { - _container.Register(lifestyle); + _container.Register(lifestyle); return this; } @@ -176,7 +176,7 @@ public GetChocolatey RegisterContainerComponent(Lifestyl public GetChocolatey RegisterContainerComponent(Func implementationCreator) where Service : class { - _container.Register(implementationCreator,Lifestyle.Singleton); + _container.Register(implementationCreator, Lifestyle.Singleton); return this; } @@ -254,10 +254,10 @@ private ChocolateyConfiguration create_configuration(IList args) { var configuration = new ChocolateyConfiguration(); ConfigurationBuilder.set_up_configuration( - args, - configuration, - _container, - _license, + args, + configuration, + _container, + _license, null); Config.initialize_with(configuration); diff --git a/src/chocolatey/infrastructure.app/runners/GenericRunner.cs b/src/chocolatey/infrastructure.app/runners/GenericRunner.cs index b735fadfa9..13d6df5725 100644 --- a/src/chocolatey/infrastructure.app/runners/GenericRunner.cs +++ b/src/chocolatey/infrastructure.app/runners/GenericRunner.cs @@ -139,9 +139,7 @@ public void run(ChocolateyConfiguration config, Container container, bool isCons } fail_when_license_is_missing_or_invalid_if_requested(config); - SecurityProtocol.set_protocol(config, provideWarning:true); - EventManager.publish(new PreRunMessage(config)); var command = find_command(config, container, isConsole, parseArgs); diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index 9320c3859d..c92bb0e45d 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -321,7 +321,6 @@ public void push_run(ChocolateyConfiguration config) if (config.Sources.is_equal_to(ApplicationParameters.ChocolateyCommunityFeedPushSource) && config.RegularOutput) { - this.Log().Warn(ChocolateyLoggers.Important, () => @" Your package may be subject to moderation. A moderator will review the From aa654e4f40dc34ac3de72721b635b3736fe2c69f Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Sun, 14 May 2017 14:31:37 -0500 Subject: [PATCH 04/18] (GH-1287) Non-internal SimpleInjector XML Comments SimpleInjector is no longer internalized, so that can cause an ambiguous conflict when adding the Chocolatey library to a codebase. Add XML comments in the API to note this for all methods that call into the container. --- src/chocolatey/GetChocolatey.cs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/chocolatey/GetChocolatey.cs b/src/chocolatey/GetChocolatey.cs index 90fecb4d83..545d118180 100644 --- a/src/chocolatey/GetChocolatey.cs +++ b/src/chocolatey/GetChocolatey.cs @@ -83,6 +83,7 @@ private static void add_assembly_resolver() /// /// The place where all the magic happens. /// + /// Chocolatey - the most magical place on Windows public class GetChocolatey { private readonly Container _container; @@ -129,9 +130,12 @@ public GetChocolatey Set(Action propConfig) /// The service. /// The implementation. /// This instance + /// + /// This requires you to use ILMerged SimpleInjector. If you use SimpleInjector in your codebase, you must now use Chocolatey's version. This is required to not be internalized so licensed code will work appropriately. + /// public GetChocolatey RegisterContainerComponent(Type service, Type implementation) { - _container.Register(service,implementation,Lifestyle.Singleton); + _container.Register(service, implementation, Lifestyle.Singleton); return this; } @@ -142,8 +146,11 @@ public GetChocolatey RegisterContainerComponent(Type service, Type implementatio /// The type of the service. /// The type of the Implementation. /// This instance - public GetChocolatey RegisterContainerComponent() - where Service : class + /// + /// This requires you to use ILMerged SimpleInjector. If you use SimpleInjector in your codebase, you must now use Chocolatey's version. This is required to not be internalized so licensed code will work appropriately. + /// + public GetChocolatey RegisterContainerComponent() + where Service : class where Implementation : class, Service { return RegisterContainerComponent(Lifestyle.Singleton); @@ -152,14 +159,16 @@ public GetChocolatey RegisterContainerComponent() /// /// Registers a container component. /// Will override existing component if registered. - /// NOTE: This requires you take a dependency on SimpleInjector. /// /// The type of the service. /// The type of the Implementation. /// The lifestyle. /// This instance - public GetChocolatey RegisterContainerComponent(Lifestyle lifestyle) - where Service : class + /// + /// This requires you to use ILMerged SimpleInjector. If you use SimpleInjector in your codebase, you must now use Chocolatey's version. This is required to not be internalized so licensed code will work appropriately. + /// + public GetChocolatey RegisterContainerComponent(Lifestyle lifestyle) + where Service : class where Implementation : class, Service { _container.Register(lifestyle); @@ -173,6 +182,9 @@ public GetChocolatey RegisterContainerComponent(Lifestyl /// The type of the ervice. /// The implementation creator. /// This instance + /// + /// This requires you to use ILMerged SimpleInjector. If you use SimpleInjector in your codebase, you must now use Chocolatey's version. This is required to not be internalized so licensed code will work appropriately. + /// public GetChocolatey RegisterContainerComponent(Func implementationCreator) where Service : class { @@ -183,10 +195,12 @@ public GetChocolatey RegisterContainerComponent(Func implement /// /// Register container components when you need to do multiple setups and want to work with the container directly. /// Will override existing components if registered. - /// NOTE: This requires you take a dependency on SimpleInjector. /// /// The container setup. /// This instance + /// + /// This requires you to use ILMerged SimpleInjector. If you use SimpleInjector in your codebase, you must now use Chocolatey's version. This is required to not be internalized so licensed code will work appropriately. + /// public GetChocolatey RegisterContainerComponents(Action containerSetup) { if (containerSetup != null) From b48b83cb9261b308729097d1fde5c974a0dc14fc Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Sun, 14 May 2017 14:56:21 -0500 Subject: [PATCH 05/18] (maint) log that license file has been found --- src/chocolatey/infrastructure/licensing/LicenseValidation.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chocolatey/infrastructure/licensing/LicenseValidation.cs b/src/chocolatey/infrastructure/licensing/LicenseValidation.cs index 07ac93b163..3f12f8b64d 100644 --- a/src/chocolatey/infrastructure/licensing/LicenseValidation.cs +++ b/src/chocolatey/infrastructure/licensing/LicenseValidation.cs @@ -40,6 +40,7 @@ public static ChocolateyLicense validate() //no IFileSystem at this point if (File.Exists(licenseFile)) { + "chocolatey".Log().Debug("Evaluating license file found at '{0}'".format_with(licenseFile)); var license = new LicenseValidator(PUBLIC_KEY, licenseFile); try From 7fc61dec4d22f3b7817d66029146ea3c1dcbabbc Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Sun, 14 May 2017 15:00:27 -0500 Subject: [PATCH 06/18] (doc) Source/Key notes surrounding source/apikey It's really helpful to understand the source value and how a push source url may be different than where you query/install packages. Provide better documentation surrounding api keys and sources. --- .../commands/ChocolateyApiKeyCommand.cs | 24 +++++++++++++++---- .../commands/ChocolateySourceCommand.cs | 14 +++++++---- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs index 1b393f00ba..6ac84e9769 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs @@ -45,7 +45,7 @@ public virtual void configure_argument_parser(OptionSet optionSet, ChocolateyCon "Source [REQUIRED] - The source location for the key", option => configuration.Sources = option.remove_surrounding_quotes()) .Add("k=|key=|apikey=|api-key=", - "ApiKey - The api key for the source.", + "ApiKey - The API key for the source. This is the authentication that identifies you and allows you to push to a source. With some sources this is either a key or it could be a user name and password specified as 'user:password'.", option => configuration.ApiKeyCommand.Key = option.remove_surrounding_quotes()) ; } @@ -82,9 +82,25 @@ choco setapikey [] "chocolatey".Log().Info(ChocolateyLoggers.Important, "Examples"); "chocolatey".Log().Info(@" choco apikey - choco apikey -s""https://somewhere/out/there"" - choco apikey -s""https://somewhere/out/there/"" -k=""value"" - choco apikey -s""https://chocolatey.org/"" -k=""123-123123-123"" + choco apikey -s https://somewhere/out/there + choco apikey -s=""https://somewhere/out/there/"" -k=""value"" + choco apikey -s ""https://push.chocolatey.org/"" -k=""123-123123-123"" + choco apikey -s ""http://internal_nexus"" -k=""user:password"" + +For source location, this can be a folder/file share or an +http location. When it comes to urls, they can be different from the packages +url (where packages are searched and installed from). As an example, for +Chocolatey's community package package repository, the package url is +https://chocolatey.org/api/v2, but the push url is https://push.chocolatey.org +(and the deprecated https://chocolatey.org/ as a push url). Check the +documentation for your choice of repository to learn what the push url is. + +For the key, this can be an apikey that is provided by your source repository. +With some sources, like Nexus, this can be a NuGet API key or it could be a +user name and password specified as 'user:password' for the API key. Please see +your repository's documentation (for Nexus, please see +https://bit.ly/nexus2apikey). + "); "chocolatey".Log().Info(ChocolateyLoggers.Important, "Connecting to Chocolatey.org"); diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateySourceCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateySourceCommand.cs index 8b9a42be89..8da74aefd0 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateySourceCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateySourceCommand.cs @@ -47,7 +47,7 @@ public virtual void configure_argument_parser(OptionSet optionSet, ChocolateyCon "Name - the name of the source. Required with some actions. Defaults to empty.", option => configuration.SourceCommand.Name = option.remove_surrounding_quotes()) .Add("s=|source=", - "Source - The source. Defaults to empty.", + "Source - The source. This can be a folder/file share or an http location. If it is a url, it will be a location you can go to in a browser and it returns OData with something that says Packages in the browser, similar to what you see when you go to https://chocolatey.org/api/v2/. Defaults to empty.", option => configuration.Sources = option.remove_surrounding_quotes()) .Add("u=|user=", "User - used with authenticated feeds. Defaults to empty.", @@ -125,12 +125,18 @@ choco sources [list]|add|remove|disable|enable [] "chocolatey".Log().Info(@" choco source choco source list - choco source add -n=bob -s""https://somewhere/out/there/api/v2/"" - choco source add -n=bob -s""'https://somewhere/out/there/api/v2/'"" -cert=\Users\bob\bob.pfx - choco source add -n=bob -s""'https://somewhere/out/there/api/v2/'"" -u=bob -p=12345 + choco source add -n=bob -s=""https://somewhere/out/there/api/v2/"" + choco source add -n=bob -s ""'https://somewhere/out/there/api/v2/'"" -cert=\Users\bob\bob.pfx + choco source add -n=bob -s ""'https://somewhere/out/there/api/v2/'"" -u=bob -p=12345 choco source disable -n=bob choco source enable -n=bob choco source remove -n=bob + +When it comes to the source location, this can be a folder/file share or an http +location. If it is a url, it will be a location you can go to in a browser and +it returns OData with something that says Packages in the browser, similar to +what you see when you go to https://chocolatey.org/api/v2/. + "); "chocolatey".Log().Info(ChocolateyLoggers.Important, "Options and Switches"); From 2738a8c709c2bfeab7c4ecdc2744fe5eed468255 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 15 May 2017 13:40:33 -0500 Subject: [PATCH 07/18] (build) option to build debug version Provide an option to build debugging versions of Chocolatey. This should not be used in production scenarios as Chocolatey uses a different path versus ChocolateyInstall environment variable to determine where it is and could lead to very unexpected and hard to find bugs. --- build.debug.bat | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 build.debug.bat diff --git a/build.debug.bat b/build.debug.bat new file mode 100644 index 0000000000..12355ea50e --- /dev/null +++ b/build.debug.bat @@ -0,0 +1,35 @@ +@echo off + +::Project UppercuT - http://uppercut.googlecode.com +::No edits to this file are required - http://uppercut.pbwiki.com + +if '%1' == '/?' goto usage +if '%1' == '-?' goto usage +if '%1' == '?' goto usage +if '%1' == '/help' goto usage + +SET DIR=%cd% +SET BUILD_DIR=%~d0%~p0% +SET NANT="%BUILD_DIR%lib\Nant\nant.exe" +SET build.config.settings="%DIR%\.uppercut" + +%NANT% /logger:"NAnt.Core.DefaultLogger" /quiet /nologo /f:"%BUILD_DIR%.build\default.build" -D:build.config.settings=%build.config.settings% -D:msbuild.configuration="Debug" -D:run.nuget="false" -D:test.framework="None" -D:cover.framework="None" -D:run.codesign="false" %* + +::#-D:run.ilmerge="false" + +if %ERRORLEVEL% NEQ 0 goto errors + +call %DIR%\documentscenarios.bat + +goto finish + +:usage +echo. +echo Usage: build.bat +echo. +goto finish + +:errors +EXIT /B %ERRORLEVEL% + +:finish \ No newline at end of file From bc1fff2cb44b0dbf05fcca4aebf3c77a10cc845f Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 15 May 2017 13:45:50 -0500 Subject: [PATCH 08/18] (GH-1294) API - Expose container directly Sometimes you need to get to an instance of something provided by Chocolatey that is loaded into the container. Provide a way to get to instances of items loaded on the container by accessing the container directly. Provide warning that once the container is accessed, no more items can be registered on the container. --- src/chocolatey/GetChocolatey.cs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/GetChocolatey.cs b/src/chocolatey/GetChocolatey.cs index 545d118180..9e3c123680 100644 --- a/src/chocolatey/GetChocolatey.cs +++ b/src/chocolatey/GetChocolatey.cs @@ -212,7 +212,20 @@ public GetChocolatey RegisterContainerComponents(Action containerSetu } /// - /// Call this method to run chocolatey after you have set the options. + /// Returns the Chocolatey container. + /// WARNING: Once you call GetInstance of any kind, no more items can be registered on the container + /// + /// The IoC Container (implemented as a SimpleInjector.Container) + /// + /// This requires you to use ILMerged SimpleInjector. If you use SimpleInjector in your codebase, you must now use Chocolatey's version. This is required to not be internalized so licensed code will work appropriately. + /// + public Container Container() + { + return _container; + } + + /// + /// Call this method to run Chocolatey after you have set the options. /// public void Run() { From 7ad0c12e3b730a0f0129d10b9d24e7bac38226aa Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 15 May 2017 13:50:14 -0500 Subject: [PATCH 09/18] (maint) API - Note methods that won't allow changes Some methods, once called, will not allow changes to the container. So they will need to be called after you have fully registered all of the container components. --- src/chocolatey/GetChocolatey.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/GetChocolatey.cs b/src/chocolatey/GetChocolatey.cs index 9e3c123680..591706c674 100644 --- a/src/chocolatey/GetChocolatey.cs +++ b/src/chocolatey/GetChocolatey.cs @@ -226,6 +226,7 @@ public Container Container() /// /// Call this method to run Chocolatey after you have set the options. + /// WARNING: Once this is called, you will not be able to register additional container components. /// public void Run() { @@ -237,8 +238,9 @@ public void Run() /// /// Call this method to run chocolatey after you have set the options. - /// Commandline arguments to add to configuration. + /// WARNING: Once this is called, you will not be able to register additional container components. /// + /// Commandline arguments to add to configuration. public void RunConsole(string[] args) { extract_resources(); @@ -249,6 +251,7 @@ public void RunConsole(string[] args) /// /// Run chocolatey after setting the options, and list the results. + /// WARNING: Once this is called, you will not be able to register additional container components. /// /// The typer of results you're expecting back. public IEnumerable List() @@ -263,6 +266,7 @@ public IEnumerable List() /// /// Run chocolatey after setting the options, /// and get the count of items that would be returned if you listed the results. + /// WARNING: Once this is called, you will not be able to register additional container components. /// /// /// Is intended to be more efficient then simply calling List and then Count() on the returned list. @@ -299,6 +303,11 @@ private ChocolateyConfiguration create_configuration(IList args) return configuration; } + /// + /// Gets the configuration. + /// + /// The configuration for Chocolatey + /// Only call this once you have registered all container components with Chocolatey public ChocolateyConfiguration GetConfiguration() { return create_configuration(new List()); From 5ace6fdd63c1cfdf1448e930e279061db7ff0500 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 15 May 2017 14:28:30 -0500 Subject: [PATCH 10/18] (GH-1296) API - Reuse existing base configuration Previously, every time the configuration was called for in the API it would return a new `ChocolateyConfiguration` object. However this would not work with licensed editions of Chocolatey, as they load some base information into that configuration and need to ensure that they can load that base configuration each time and licensed functionality. Ensure instead that the configuration gets reset to the base each time it is used and doesn't lose that base information. --- src/chocolatey/GetChocolatey.cs | 94 ++++++++++++++++++++++++++------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/src/chocolatey/GetChocolatey.cs b/src/chocolatey/GetChocolatey.cs index 591706c674..68bdb27868 100644 --- a/src/chocolatey/GetChocolatey.cs +++ b/src/chocolatey/GetChocolatey.cs @@ -231,9 +231,17 @@ public Container Container() public void Run() { extract_resources(); - var configuration = create_configuration(new List()); - var runner = new GenericRunner(); - runner.run(configuration, _container, isConsole: false, parseArgs: null); + + ensure_original_configuration(new List(), + (config) => + { + config.RegularOutput = true; + var runner = new GenericRunner(); + runner.run(config, _container, isConsole: false, parseArgs: command => + { + command.handle_validation(config); + }); + }); } /// @@ -244,9 +252,14 @@ public void Run() public void RunConsole(string[] args) { extract_resources(); - var configuration = create_configuration(new List(args)); - var runner = new ConsoleApplication(); - runner.run(args, configuration, _container); + + ensure_original_configuration(new List(args), + (config) => + { + var runner = new ConsoleApplication(); + runner.run(args, config, _container); + }); + } /// @@ -257,10 +270,14 @@ public void RunConsole(string[] args) public IEnumerable List() { extract_resources(); - var configuration = create_configuration(new List()); - configuration.RegularOutput = true; - var runner = new GenericRunner(); - return runner.list(configuration, _container, isConsole: false, parseArgs: null); + + return ensure_original_configuration(new List(), + (config) => + { + config.RegularOutput = true; + var runner = new GenericRunner(); + return runner.list(config, _container, isConsole: false, parseArgs: null); + }); } /// @@ -275,23 +292,64 @@ public IEnumerable List() public int ListCount() { extract_resources(); - var configuration = create_configuration(new List()); - configuration.RegularOutput = true; - var runner = new GenericRunner(); - return runner.count(configuration, _container, isConsole: false, parseArgs: null); + + return ensure_original_configuration(new List(), + (config) => + { + config.RegularOutput = true; + var runner = new GenericRunner(); + return runner.count(config, _container, isConsole: false, parseArgs: null); + }); + } + + private void ensure_original_configuration(IList args, Action action) + { + var success = ensure_original_configuration(args, + (config) => + { + if (action != null) action.Invoke(config); + return true; + }); + } + + private T ensure_original_configuration(IList args, Func function) + { + var originalConfig = Config.get_configuration_settings().deep_copy(); + var configuration = create_configuration(args); + var returnValue = default(T); + try + { + if (function != null) + { + returnValue = function.Invoke(configuration); + } + } + finally + { + // reset that configuration each time + configuration = originalConfig; + Config.initialize_with(originalConfig); + } + + return returnValue; } + /// + /// Creates the configuration. + /// + /// The arguments. + /// The configuration for Chocolatey private ChocolateyConfiguration create_configuration(IList args) { - var configuration = new ChocolateyConfiguration(); + // get or create a ChocolateyConfiguration. This maps directly + // to the same thing that is loaded into the container + var configuration = Config.get_configuration_settings(); ConfigurationBuilder.set_up_configuration( args, configuration, _container, _license, null); - - Config.initialize_with(configuration); configuration.PromptForConfirmation = false; configuration.AcceptLicense = true; @@ -304,7 +362,7 @@ private ChocolateyConfiguration create_configuration(IList args) } /// - /// Gets the configuration. + /// Gets the configuration. Should be used purely for informational purposes /// /// The configuration for Chocolatey /// Only call this once you have registered all container components with Chocolatey From aa19c5c0f2b9a6602f9a2bcf06f000ee016719f7 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 15 May 2017 14:46:04 -0500 Subject: [PATCH 11/18] (maint) Do not load config back into global When getting the config in the console application, there is no need to reinitialize it back into the global configuration as it is already set up that way during container registration. --- src/chocolatey.console/Program.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/chocolatey.console/Program.cs b/src/chocolatey.console/Program.cs index cc35c6c48b..dbd1f8060f 100644 --- a/src/chocolatey.console/Program.cs +++ b/src/chocolatey.console/Program.cs @@ -59,7 +59,7 @@ private static void Main(string[] args) "LogFileOnly".Log().Info(() => "".PadRight(60, '=')); - var config = container.GetInstance(); + var config = Config.get_configuration_settings(); var fileSystem = container.GetInstance(); var warnings = new List(); @@ -71,7 +71,6 @@ private static void Main(string[] args) license, warning => { warnings.Add(warning); } ); - Config.initialize_with(config); report_version_and_exit_if_requested(args, config); From 3323a5a19fd5015f8f03f6f47d7d29c6713034ea Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 15 May 2017 14:51:15 -0500 Subject: [PATCH 12/18] (GH-389) API - Ensure ChocolateyInstall env var When running Chocolatey, it is helpful to ensure environment variables are set correctly. Sometimes ChocolateyInstall location will not have been determined correctly or be waiting on a reboot/explorer.exe restart prior to applications realizing that the value has changed. Ensure that even with that, the value for ChocolateyInstall is determined correctly. --- src/chocolatey/GetChocolatey.cs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/chocolatey/GetChocolatey.cs b/src/chocolatey/GetChocolatey.cs index 68bdb27868..e1e49e0da8 100644 --- a/src/chocolatey/GetChocolatey.cs +++ b/src/chocolatey/GetChocolatey.cs @@ -230,6 +230,7 @@ public Container Container() /// public void Run() { + ensure_environment(); extract_resources(); ensure_original_configuration(new List(), @@ -251,6 +252,7 @@ public void Run() /// Commandline arguments to add to configuration. public void RunConsole(string[] args) { + ensure_environment(); extract_resources(); ensure_original_configuration(new List(args), @@ -269,6 +271,7 @@ public void RunConsole(string[] args) /// The typer of results you're expecting back. public IEnumerable List() { + ensure_environment(); extract_resources(); return ensure_original_configuration(new List(), @@ -291,6 +294,7 @@ public IEnumerable List() /// public int ListCount() { + ensure_environment(); extract_resources(); return ensure_original_configuration(new List(), @@ -368,9 +372,31 @@ private ChocolateyConfiguration create_configuration(IList args) /// Only call this once you have registered all container components with Chocolatey public ChocolateyConfiguration GetConfiguration() { + ensure_environment(); + return create_configuration(new List()); } + private void ensure_environment() + { + string chocolateyInstall = string.Empty; + +#if !DEBUG + chocolateyInstall = Environment.GetEnvironmentVariable(ApplicationParameters.ChocolateyInstallEnvironmentVariableName, EnvironmentVariableTarget.Machine); + if (string.IsNullOrWhiteSpace(chocolateyInstall)) + { + chocolateyInstall = Environment.GetEnvironmentVariable(ApplicationParameters.ChocolateyInstallEnvironmentVariableName, EnvironmentVariableTarget.User); + } +#endif + + if (string.IsNullOrWhiteSpace(chocolateyInstall)) + { + chocolateyInstall = Environment.GetEnvironmentVariable(ApplicationParameters.ChocolateyInstallEnvironmentVariableName); + } + + Environment.SetEnvironmentVariable(ApplicationParameters.ChocolateyInstallEnvironmentVariableName, chocolateyInstall); + } + private void extract_resources() { //refactor - thank goodness this is temporary, cuz manifest resource streams are dumb From 952e16bd31cabebb9fff3309e81bfc32c1323211 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Mon, 15 May 2017 14:52:58 -0500 Subject: [PATCH 13/18] (maint) API - Warn on extraction errors If extraction fails for internal resources, the API should log an Error but not fail the process. Other parts of the application could fail the process later and that is expected if things are missing. However extraction could occur without proper permissions and the API should just log that it was unable to as not every call through Chocolatey is going to need those resources. --- src/chocolatey/GetChocolatey.cs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/GetChocolatey.cs b/src/chocolatey/GetChocolatey.cs index e1e49e0da8..a0685934a8 100644 --- a/src/chocolatey/GetChocolatey.cs +++ b/src/chocolatey/GetChocolatey.cs @@ -408,7 +408,15 @@ private void extract_resources() "tools" }; - AssemblyFileExtractor.extract_all_resources_to_relative_directory(_container.GetInstance(), Assembly.GetAssembly(typeof(ChocolateyResourcesAssembly)), ApplicationParameters.InstallLocation, folders, ApplicationParameters.ChocolateyFileResources); + try + { + AssemblyFileExtractor.extract_all_resources_to_relative_directory(_container.GetInstance(), Assembly.GetAssembly(typeof(ChocolateyResourcesAssembly)), ApplicationParameters.InstallLocation, folders, ApplicationParameters.ChocolateyFileResources); + } + catch (Exception ex) + { + this.Log().Error("Unable to extract resources. Please ensure the ChocolateyInstall environment variable is set properly. Details:{0} {1}".format_with(Environment.NewLine,ex.ToString())); + } + } } From 103312782f501ea71011671b724026ae9debd67e Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Wed, 17 May 2017 17:50:24 -0500 Subject: [PATCH 14/18] (GH-1298) GenericRunner.list() should match run() Previously, in the GenericRunner, `run` does the following things that list does not implement: * set up tasks surrounding pre and post messages * send pre and post messages * set the security protocol to ensure no issues in returning data Ensure that list implements these items as well. --- .../runners/GenericRunner.cs | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/src/chocolatey/infrastructure.app/runners/GenericRunner.cs b/src/chocolatey/infrastructure.app/runners/GenericRunner.cs index 13d6df5725..dfeb5a62f6 100644 --- a/src/chocolatey/infrastructure.app/runners/GenericRunner.cs +++ b/src/chocolatey/infrastructure.app/runners/GenericRunner.cs @@ -193,21 +193,43 @@ private void remove_nuget_cache(Container container) public IEnumerable list(ChocolateyConfiguration config, Container container, bool isConsole, Action parseArgs) { + var tasks = container.GetAllInstances(); + foreach (var task in tasks) + { + task.initialize(); + } + fail_when_license_is_missing_or_invalid_if_requested(config); + SecurityProtocol.set_protocol(config, provideWarning: true); + EventManager.publish(new PreRunMessage(config)); - var command = find_command(config, container, isConsole, parseArgs) as IListCommand; - if (command == null) + try { - if (!string.IsNullOrWhiteSpace(config.CommandName)) + var command = find_command(config, container, isConsole, parseArgs) as IListCommand; + if (command == null) { - throw new Exception("The implementation of '{0}' does not support listing '{1}'".format_with(config.CommandName, typeof(T).Name)); + if (!string.IsNullOrWhiteSpace(config.CommandName)) + { + throw new Exception("The implementation of '{0}' does not support listing '{1}'".format_with(config.CommandName, typeof(T).Name)); + } + return new List(); + } + else + { + this.Log().Debug("_ {0}:{1} - Normal List Mode _".format_with(ApplicationParameters.Name, command.GetType().Name)); + return command.list(config); } - return new List(); } - else + finally { - this.Log().Debug("_ {0}:{1} - Normal List Mode _".format_with(ApplicationParameters.Name, command.GetType().Name)); - return command.list(config); + EventManager.publish(new PostRunMessage(config)); + + foreach (var task in tasks.or_empty_list_if_null()) + { + task.shutdown(); + } + + remove_nuget_cache(container); } } From 921c8eb5215914a5645359175230c5eee1e85f67 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Wed, 17 May 2017 17:51:43 -0500 Subject: [PATCH 15/18] (GH-1298) GenericRunner.count() sets security protocol When attempting to get a count, set the security protocol to ensure no issues in returning data are produced. This is used mostly in the API and nowhere else. --- src/chocolatey/infrastructure.app/runners/GenericRunner.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/chocolatey/infrastructure.app/runners/GenericRunner.cs b/src/chocolatey/infrastructure.app/runners/GenericRunner.cs index dfeb5a62f6..3b82da8945 100644 --- a/src/chocolatey/infrastructure.app/runners/GenericRunner.cs +++ b/src/chocolatey/infrastructure.app/runners/GenericRunner.cs @@ -236,6 +236,7 @@ public IEnumerable list(ChocolateyConfiguration config, Container containe public int count(ChocolateyConfiguration config, Container container, bool isConsole, Action parseArgs) { fail_when_license_is_missing_or_invalid_if_requested(config); + SecurityProtocol.set_protocol(config, provideWarning: true); var command = find_command(config, container, isConsole, parseArgs) as IListCommand; if (command == null) From f508b6855a9329f1b6c04e6944d3f1b8d0580c12 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Thu, 18 May 2017 12:28:10 -0500 Subject: [PATCH 16/18] (GH-1285) Add old/new default push source Add checks to see if someone is using an old or new push source. If one of those is being used, display the warning about moderation. --- src/chocolatey/infrastructure.app/ApplicationParameters.cs | 3 ++- src/chocolatey/infrastructure.app/services/NugetService.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/chocolatey/infrastructure.app/ApplicationParameters.cs b/src/chocolatey/infrastructure.app/ApplicationParameters.cs index 3d55651e9e..d4330537cb 100644 --- a/src/chocolatey/infrastructure.app/ApplicationParameters.cs +++ b/src/chocolatey/infrastructure.app/ApplicationParameters.cs @@ -66,7 +66,8 @@ public static class ApplicationParameters public static readonly string ChocolateyPackageInfoStoreLocation = _fileSystem.combine_paths(InstallLocation, ".chocolatey"); public static readonly string ExtensionsLocation = _fileSystem.combine_paths(InstallLocation, "extensions"); public static readonly string TemplatesLocation = _fileSystem.combine_paths(InstallLocation, "templates"); - public static readonly string ChocolateyCommunityFeedPushSource = "https://chocolatey.org/"; + public static readonly string ChocolateyCommunityFeedPushSourceOld = "https://chocolatey.org/"; + public static readonly string ChocolateyCommunityFeedPushSource = "https://push.chocolatey.org/"; public static readonly string ChocolateyCommunityFeedSource = "https://chocolatey.org/api/v2/"; public static readonly string ChocolateyLicensedFeedSource = "https://licensedpackages.chocolatey.org/api/v2/"; public static readonly string ChocolateyLicensedFeedSourceName = "chocolatey.licensed"; diff --git a/src/chocolatey/infrastructure.app/services/NugetService.cs b/src/chocolatey/infrastructure.app/services/NugetService.cs index c92bb0e45d..5feb17407a 100644 --- a/src/chocolatey/infrastructure.app/services/NugetService.cs +++ b/src/chocolatey/infrastructure.app/services/NugetService.cs @@ -319,7 +319,7 @@ public void push_run(ChocolateyConfiguration config) NugetPush.push_package(config, _fileSystem.get_full_path(nupkgFilePath)); - if (config.Sources.is_equal_to(ApplicationParameters.ChocolateyCommunityFeedPushSource) && config.RegularOutput) + if (config.RegularOutput && (config.Sources.is_equal_to(ApplicationParameters.ChocolateyCommunityFeedPushSource) ||config.Sources.is_equal_to(ApplicationParameters.ChocolateyCommunityFeedPushSourceOld))) { this.Log().Warn(ChocolateyLoggers.Important, () => @" From 794f4984ee5e1e4a6466e30ea2bf54b1d288d255 Mon Sep 17 00:00:00 2001 From: Rob Reynolds Date: Thu, 18 May 2017 12:45:38 -0500 Subject: [PATCH 17/18] (GH-1285) Default push to new or old w/warning When pushing larger packages, the original push url was subject to a timeout of 100 seconds, a limitation of using Cloudflare. The error: `Error publishing package. NuGet server returned 524: Origin Time-out" when pushing through the Cloudflare infrastructure. Instead, convert to a new default push url that is not subject to a timeout by Cloudflare. To ensure this is not a breaking change, determine whether the old apikey was set and use it with a warning to change it over to use the new url. --- .../commands/ChocolateyApiKeyCommand.cs | 2 +- .../commands/ChocolateyPushCommand.cs | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs index 6ac84e9769..6a745d646d 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyApiKeyCommand.cs @@ -103,7 +103,7 @@ choco apikey "); - "chocolatey".Log().Info(ChocolateyLoggers.Important, "Connecting to Chocolatey.org"); + "chocolatey".Log().Info(ChocolateyLoggers.Important, "Connecting to Chocolatey.org (Community Package Repository)"); "chocolatey".Log().Info(() => @" In order to save your API key for {0}, log in (or register, confirm and then log in) to diff --git a/src/chocolatey/infrastructure.app/commands/ChocolateyPushCommand.cs b/src/chocolatey/infrastructure.app/commands/ChocolateyPushCommand.cs index 8fa8f539ab..7f57268465 100644 --- a/src/chocolatey/infrastructure.app/commands/ChocolateyPushCommand.cs +++ b/src/chocolatey/infrastructure.app/commands/ChocolateyPushCommand.cs @@ -74,6 +74,28 @@ public virtual void handle_additional_argument_parsing(IList unparsedArg if (string.IsNullOrWhiteSpace(configuration.Sources)) { configuration.Sources = ApplicationParameters.ChocolateyCommunityFeedPushSource; + var newSourceKey = _configSettingsService.get_api_key(configuration, null); + + if (string.IsNullOrWhiteSpace(newSourceKey)) + { + configuration.Sources = ApplicationParameters.ChocolateyCommunityFeedPushSourceOld; + var oldSourceKey = _configSettingsService.get_api_key(configuration, null); + + if (string.IsNullOrWhiteSpace(oldSourceKey)) + { + configuration.Sources = ApplicationParameters.ChocolateyCommunityFeedPushSource; + } + else + { + this.Log().Warn(ChocolateyLoggers.Important, @"ACTION: Please update your apikey to use + '{0}' + instead of + '{1}'. + The latter source url is now considered deprecated and will not be + checked as the default source in Chocolatey v1.0. For details, run + `choco apikey -?`".format_with(ApplicationParameters.ChocolateyCommunityFeedPushSource, ApplicationParameters.ChocolateyCommunityFeedPushSourceOld)); + } + } } if (!string.IsNullOrWhiteSpace(configuration.Sources)) From 995c9ee8984bdac7ff28e9f0bcbd5ebd6a6e5fb1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Gill=C3=A9?= Date: Wed, 17 May 2017 20:40:58 +0200 Subject: [PATCH 18/18] Remove duplicate word --- src/chocolatey/infrastructure.app/templates/NuspecTemplate.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/chocolatey/infrastructure.app/templates/NuspecTemplate.cs b/src/chocolatey/infrastructure.app/templates/NuspecTemplate.cs index cb28bf9435..b8b1d4da45 100644 --- a/src/chocolatey/infrastructure.app/templates/NuspecTemplate.cs +++ b/src/chocolatey/infrastructure.app/templates/NuspecTemplate.cs @@ -61,7 +61,7 @@ public class NuspecTemplate https://_Software_Location_REMOVE_OR_FILL_OUT_ - +