-
Notifications
You must be signed in to change notification settings - Fork 369
NuGet package support in scriptcs
scriptcs has integrated support for NuGet packages. The integration is used for the following use cases.
- Using .NET libraries within a script - NuGet is the standard mechanism for publishing .NET libraries. scriptcs users can install most NuGet packages and directly use them within their scripts.
- Using Script Packs - Script Packs provide a more script-friendly wrapper around other NuGet packages, and remove the need for repetitive boilerplate coding. Script Packs are published as NuGet packages.
- Using Script Libraries - Script Libraries allow sharing scripts for reuse by publishing them in a package.
- Using Modules - Modules are an extensibility point in scriptcs that allows extend the scriptcs "runtime" itself.
The scriptcs model is based on a convention over configuration approach. Packages are not explicitly referenced within the script, instead the presence of a package locally means that it is automatically loaded / available.
There are 2 locations for packages in scriptcs.
Global packages live in ".\AppData\Local\ScriptCs\Packages"
. These packages contain scriptcs Modules. For example the FSharpModule
is installed globally, and adds the ability for scriptcs to support using F#'s compiler / F# scripts.
Global packages are installed with scriptcs using scriptcs -install -g
i.e. scriptcs -install ScriptCs.FSharp -g
will install the FSharp module globally.
Global packages are automatically loaded when scriptcs starts up. We use MEF to scan the global packages for any [IModule
] (https://github.com/scriptcs/scriptcs/blob/dev/src/ScriptCs.Contracts/IModule.cs) implementations. Any modules that are found are then invoked so they can configure scriptcs using the supplied module configuration object. Examples
Note: We are planning to change how global packages work in the near future. Once thes changes happen, scriptcs modules will not be installed globally, rather they will be installed at the app level. Global packages will still exist, but will only be used only for supporting CLI commands, similar to how node.js has global NPM packages.
App in this case is a folder with a bunch of scripts. A scriptcs App can have local packages installed. To install them the scriptcs -install
command is used specifying the package name. On package installation, a scriptcs_packages.config
file will be stored in the script folder. This is the packages.config file using NuGet's standard format. The packages themselves reside in a local scriptcs_packages
folder.
Local packages are used for the following reasons:
- 3rd Party libraries - You can install 99% of NuGet packages in order to leverage existing libraries.
- Script Packs - These are wrapper libraries that inject things into the scriptcs environment to make 3rd party libraries more scriptable. You can read more about them [here] (https://github.com/scriptcs/scriptcs/wiki/Script-Packs)
- Repl commands - scriptcs can be extended with custom [REPL Commands] (https://github.com/scriptcs/scriptcs/blob/dev/src/ScriptCs.Contracts/IReplCommand.cs).
- Script Libaries - These are new [feature] (https://github.com/scriptcs/scriptcs/wiki/Script-Libraries) in scriptcs that allow easily packaging up functions and classes authored in script in a reusable way to allow them to be easily consumed by others. One significant thing they do is inject common using statements and references into the script.
At runtime (either in the REPL or running a script) we scan for the local scriptcs_packages.config
file. If one is found, then we will look for the scriptcs_packages
folder. If that is not found, we will automatically attempt to install the packages. Once the packages are installed (or if they exist) we will then automatically load them into memory. We use MEF to do this. We then use MEF to scan packages for Script Packs. Any that are found are initialized, allowing them to inject imports and references.
As mentioned earlier, packages are installed into scripts using the scriptcs -install
command.
- A user can supply a specific package i.e.
scriptcs -install Automapper
to have that package installed. scriptcs will automatically install that package and all its dependencies. It will then create ascriptcs_packages.config
file if it does not exist. - If no package is supplied, then scriptcs will look for the local
scriptcs_packages.config
file and install all the packages within that file. - Users can pass the
-g
option to install packages globally. - Users can pass the
-pre
option in order to have scriptcs pull pre-release packages. By default it does not. - Users can supply a local
scriptcs_nuget.config
file to override package sources with additional sources like a local folder.
We rely on the NuGet.Core package by default to handle all our NuGet package resolution. We use it to query NuGet to get the packages that need to be installed and to do the actual installation.
One problem we have seen customers get into the past is having their app packages conflict with the versions scriptcs itself uses, or having conflicts within Script Packs due to the depending on an older version of our ScriptCs.Contracts
assembly.
To mitigate this we have an AppDomainAssemblyResolver
which overrides resolution at the App Domain level and automatically redirects assembly requests at runtime to the last version that is registered with the resolver. This doesn't solve binary conflict problems, but does solve versioning problems.
For example, let's assume a Script Pack (in a package) references ScriptCs.Contracts
version 0.10, yet the person is running on ScriptCs version 0.13. At runtime when the Script Pack assembly requests for 0.10, it will get back 0.13 automatically.
All the services we use in scriptcs to install packages are pluggable and rely on contracts for which the default is NuGet. This gives us the ability to support other providers like Paket
.
- Home
- Build scriptcs
- Building on Mac and Linux
- Using scriptcs
- The command line
- Package installation
- Writing a script
- Compiling (and caching) to a .dll
- Debugging a script
- REPL
- Running scripts in Atom
- REPL
- Script Packs
- Script Libraries
- Modules
- Hosting
- Community
- Known Issues