diff --git a/README.md b/README.md index 20e06b9fc..4d87053cf 100644 --- a/README.md +++ b/README.md @@ -1,55 +1,40 @@ +| README.md | +|:---| + +![](docs/artwork/Squirrel-Logo.png) + # Squirrel: It's like ClickOnce but Works™ -Squirrel is both a set of tools and a library, to completely manage both installation and updating your Desktop Windows application, written in either C# or any other language (i.e. Squirrel can manage native C++ applications). +Squirrel is both a set of tools and a library, to completely manage both installation and updating your Desktop Windows application, written in either C# or any other language (i.e., Squirrel can manage native C++ applications). Squirrel uses NuGet packages to create installation and update packages, which means that you probably already know most of what you need to create an installer. -## Getting Started +## What Do We Want? -Check out the [user documentation](/docs) for how to use Squirrel. A good place to start reading is the [Getting Started page](/docs/getting-started.md), which includes a Quick Start guide. +Windows apps should be as fast and as easy to install and update as apps like Google Chrome. From an app developer's side, it should be really straightforward to create an installer for my app, and publish updates to it, without having to jump through insane hoops. -## What Do We Want? +* **Integrating** an app to use Squirrel should be extremely easy, provide a client API, and be developer friendly. +* **Packaging** is really easy, can be automated, and supports delta update packages. +* **Distributing** should be straightforward, use simple HTTP updates, and provide multiple "channels" (a-la Chrome Dev/Beta/Release). +* **Installing** is Wizard-Free™, with no UAC dialogs, does not require reboot, and is .NET Framework friendly. +* **Updating** is in the background, doesn't interrupt the user, and does not require a reboot. + +Refer to our full list of goals for [integrating, packaging, distributing, installing, and updating](docs/goals.md). -Deployment and Updates for Desktop applications are a real drag. ClickOnce almost works, but has some glaring bugs that don't seem like they'll ever be fixed. So let's own our own future and build a new one. +## Documentation -Windows apps should be as fast and as easy to install and update as apps like Google Chrome. From an app developer's side, it should be really straightforward to create an installer for my app, and publish updates to it, without having to jump through insane hoops +See the documentation [Table of Contents](docs/readme.md) for an overview of the available documentation for Squirrel.Windows. It includes a [Getting Started Guide](docs/GettingStarted/0-index.md) as well as additional topics related to using Squirrel in your applications. -#### Installation -* Install is Wizard-Free™ and doesn't look awful (or at least, it should have the *possibility* to not look awful) -* No UAC dialogs, which means.... -* ...installs to the local user account (i.e. under `%LocalAppData%`) -* Uninstall gives a chance for the application to clean up (i.e. I get to run a chunk of code on uninstall) -* No Reboots. None! -* Can pull down the .NET Framework if need be +## License and Usage -#### Updates +See [COPYING](COPYING) for details on copyright and usage of the Squirrel.Windows software. -* Updates should be able to be applied while the application is running -* At no time should the user ever be forced to stop what he or she is doing -* No Reboots. None! -* The client API should be able to check for updates, receive a (preferably in HTML) ChangeLog -#### Production -* Generating an installer given an existing .NET application should be really easy, like it is for ClickOnce -* Hosting an update server should be really straightforward as well, and should be able to be done using simple HTTP (i.e. I should be able to host my installer and update feed via S3) -* Creating an update for my app should be a very simple process that is easily automated -* Support for multiple "channels" (a-la Chrome Dev/Beta/Release) -#### Building Squirrel -For the Impatient: -```sh -git clone https://github.com/squirrel/squirrel.windows -git submodule update --init --recursive ## THIS IS THE PART YOU PROBABLY FORGOT -.\.nuget\nuget.exe restore -msbuild /p:Configuration=Release -``` -Squirrel.Windows is a fairly typical C# / C++ project, the only special part is making sure to clone submodules via the command above. -## How can I get involved? -Check out https://github.com/Squirrel/Squirrel.Windows.Next/issues/9 for more information about joining the Squirrel Slack room diff --git a/docs/advanced-releasify.md b/docs/advanced-releasify.md deleted file mode 100644 index 405d58299..000000000 --- a/docs/advanced-releasify.md +++ /dev/null @@ -1,52 +0,0 @@ -## Advanced package creation - -Here is a simplified help output specifically around creating releases: - -``` -Usage: Squirrel.exe command [OPTS] -Creates Squirrel packages - -Commands - --releasify=VALUE Update or generate a releases directory with a - given NuGet package - -Options: - -h, -?, --help Display Help and exit - -r, --releaseDir=VALUE Path to a release directory to use with Releasify - -p, --packagesDir=VALUE Path to the NuGet Packages directory for C# apps - --bootstrapperExe=VALUE - Path to the Setup.exe to use as a template - -g, --loadingGif=VALUE Path to an animated GIF to be displayed during - installation - -n, --signWithParams=VALUE Sign the installer via SignTool.exe with the - parameters given -``` - -### Loading GIFs - -Squirrel installers don't have any UI - the goal of a Squirrel installer is to install so blindingly fast that double-clicking on Setup.exe *feels* like double-clicking on an app shortcut. Make your installer **fast**. - -However, for large applications, this isn't possible. For these apps, Squirrel will optionally display a graphic as a "splash screen" while installation is processing, but only if installation takes more than a pre-set amount of time. This will be centered, backed by a transparent window, and can optionally be an animated GIF. Specify this via the `-g` parameter. - -### Setup.exe Signing - -Signing your installer with a valid code signing certificate is one of the most important things that you need to do for production apps. Both IE SmartScreen as well as virus scanning software will give a significant amount of "points" to apps that are signed correctly, preventing your users from getting scary dialogs. - -Acquire a code-signing certificate - it's recommended to get a Windows Error Reporting-compatible certificate, see [this MSDN article](http://msdn.microsoft.com/en-us/library/windows/hardware/hh801887.aspx) for more information, then pass the `-n` parameter, which are the parameters you would pass to `signtool.exe sign` to sign the app. - -Squirrel makes signing easy, as it signs all of your application's executables as *well* as the final generated Setup.exe. - -An example invocation including both of these features would be something like: - -``` -Squirrel --releasify MyApp.nupkg -g .\loading.gif -n "/a /f CodeCert.pfx /p MySecretCertPassword" -``` - - -### Machine-Wide Installs via MSI (#466) - -Squirrel's Releasify command generates an MSI file suitable for installation via Group Policy. This MSI isn't a general-purpose installer, this means that once you run the MSI, users from now on will get the app installed, on next Login. - -So, most normal users should continue to run the Setup.exe's generated by Releasify, but if you want to have an IT Admin Friendly version, you can hand off the MSI - -Most users of Squirrel won't have to do anything new to enable this behavior, though certain NuGet package IDs / names might cause problems with MSI. Generating MSIs can be disabled via the --no-msi flag. \ No newline at end of file diff --git a/docs/api.md b/docs/api.md deleted file mode 100644 index bbc0a9eb9..000000000 --- a/docs/api.md +++ /dev/null @@ -1,66 +0,0 @@ -## Squirrel.dll - -This is the assembly your project should reference in order to use Squirrel in-app updates functionality. - -### UpdateManager - -Main entry point for using Squirrel functionality. Here's an example of how to create one: - -```cs -using (var mgr = new UpdateManager("http://your-server/releases")) -{ - // Use updateManager -} -``` - -### GitHub UpdateManager - -To use GitHub Releases as the location where your application updates are hosted: - -```cs -var updateManager = UpdateManager.GitHubUpdateManager('https://github.com/myuser/myrepo'); - -// or to include pre-releases - -var updateManager = UpdateManager.GitHubUpdateManager('https://github.com/myuser/myrepo', prerelease: true); -``` - -Issue #442 contains a brief explanation of how this works. - -### Methods for managing updates - -These methods are the primary methods you'll use to interact with app updates and apply them. - -* `UpdateApp`: Downloads and updates the app to the latest version. This method is the "Easy Mode" method that does everything all in one go. - -* `CheckForUpdate`: Checks on the server if there are updates available. Returns an `UpdateInfo` object that contains information about any pending updates. - -* `DownloadReleases`: Downloads release files (the `nupkg` file deltas) from the server to the local machine - -* `ApplyReleases` Installs the downloaded packages, and returns the new `app-[version]` directory path. - -### Methods for helping you to set up your app - -These methods help you to set up your application in Squirrel events - if you're not using custom Squirrel events, you probably don't need to call these methods. - -* `[Create/Remove]ShortcutsForExecutable`: Creates and removes shortcuts on the desktop or in the Start Menu. - -* `[Create/Remove]UninstallerRegistryEntry`: Creates and removes the uninstaller entry. Normally called by `Update.exe`. - -### UpdateInfo - -Contains information about available and installed releases. - -* `ReleaseEntry CurrentlyInstalledVersion` -* `ReleaseEntry FutureReleaseEntry` -* `public string PackageDirectory` -* `List ReleasesToApply` - -### ReleaseEntry - -Contains the specifics of each release. - -* `string SHA1` -* `string Filename` -* `long Filesize` -* `bool IsDelta` diff --git a/docs/artwork/Squirrel-Logo.png b/docs/artwork/Squirrel-Logo.png new file mode 100644 index 000000000..ce7f7e81a Binary files /dev/null and b/docs/artwork/Squirrel-Logo.png differ diff --git a/docs/artwork/Squirrel-Logo.svg b/docs/artwork/Squirrel-Logo.svg new file mode 100644 index 000000000..1751d2f5f --- /dev/null +++ b/docs/artwork/Squirrel-Logo.svg @@ -0,0 +1,203 @@ + + + + + + + + + + + + Created by Jetro Cabau Quirós + from the Noun Project + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Squirrel + + diff --git a/docs/contributing/building-squirrel.md b/docs/contributing/building-squirrel.md new file mode 100644 index 000000000..4bbf44623 --- /dev/null +++ b/docs/contributing/building-squirrel.md @@ -0,0 +1,21 @@ +| [docs](..) / [contributing](.) / building-squirrel.md +|:---| + +# Building Squirrel + +Squirrel.Windows is a fairly typical C# / C++ project, the only special part is making sure to clone submodules via the command shown below. + +For the Impatient: + +```sh +git clone https://github.com/squirrel/squirrel.windows +git submodule update --init --recursive ## THIS IS THE PART YOU PROBABLY FORGOT +.\.NuGet\NuGet.exe restore +msbuild /p:Configuration=Release +``` + +**Tip:** You can compile the Squirrel.Windows solution with Visual Studio version 2013 and above (including community edition). + +--- +| Return: [Table of Contents](../readme.md) | +|----| diff --git a/docs/contributing/contributing.md b/docs/contributing/contributing.md new file mode 100644 index 000000000..75868f403 --- /dev/null +++ b/docs/contributing/contributing.md @@ -0,0 +1,21 @@ +| [docs](..) / [contributing](.) / contributing.md +|:---| + +# Contributing + +Why not give back and help make Squirrel even better? Here is an overview of ways you can become more involved. + +* **Join the Squirrel Slack Room** - email [paul@paulbetts.org](mailto:paul@paulbetts.org) with the email address you'd like to receive an invite. +* **Contribute Documentation** - improve the documentation or provide additional code examples to benefit others. +* **Subscribe to Issues on GitHub** - have some experience using Squirrel? Help answer questions under issues or post a Pull Request fixing a bug. +* **Contribute Code** - have a great feature that you feel is a good fit for Squirrel? Send a Pull Request. + + +## See Also + +* [Building Squirrel](building-squirrel.md) - steps to build squirrel for the impatient. +* [VS Solution Overview](vs-solution-overview.md) - overview of the various projects in the Squirrel.Windows Visual Studio solution. + +--- +| Return: [Table of Contents](../readme.md) | +|----| diff --git a/docs/contributing/vs-solution-overview.md b/docs/contributing/vs-solution-overview.md new file mode 100644 index 000000000..b53f44c2d --- /dev/null +++ b/docs/contributing/vs-solution-overview.md @@ -0,0 +1,29 @@ +| [docs](..) / [contributing](.) / vs-solution-overview.md +|:---| + +# Visual Studio Solution Overview + +An overview of the various projects in the Squirrel.Windows Visual Studio solution and how they relate to different aspects of the update process. + + +| Project / Assembly Name | Libraries (NuGet) | Libraries (NuGet) | Releases Directory (releasify output) | MyApp (install location) | +| -------------------------------- | --------- | ----- | ------------------ | ------------- | ----------- | +| **Core** NuGet.Squirrel.dll | NuGet.Squirrel.dll | | | | +| **Squirrel** Squirrel.dll | Squirrel.dll | | | | +| **SyncRelease** SyncRelease.exe | | SyncRelease.exe | | | +| **Update** Update.exe | | Squirrel.exe | | Update.exe | +| **Setup** Setup.exe | | Setup.exe | Setup.exe (+MyApp.Latest.nupkg) | | +| **WriteZipToSetup** WriteZipToSetup.exe | | WriteZipToSetup.exe | | | + +* **Project / Assembly Name**: Solution project name (from Squirrel.sln) and output assembly name. +* **Libraries (NuGet)**: Program libraries installed added as references in your MyApp solution when adding the Squirrel.Windows NuGet package to your project. +* **Libraries (NuGet)**: Executable tools included in the Squirrel.Windows NuGet package used to prepare deployments via the Package Manager Console (e.g., Squirrel.exe). +* **Releases Directory (releasify output)**: Directory where the Squirrel --releasify process outputs the packages and Setup application for your project (e.g., MyAppSourceCode/Releases). +* **MyApp (install location)**: MyApp install directory (e.g., %LOCALAPPDATA%\MyApp) where the application is actually installed and updated via Squirrel.Windows. + +**Note**: Note that the Squirrel.exe application found in the tools directory of the Squirrel.Windows NuGet package is actually a renamed version of the Update.exe application (see Squirrel.Windows\src\Squirrel.nuspec) + +--- +| Return: [Table of Contents](../readme.md) | +|----| + diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 000000000..e25f8127e --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,57 @@ +| [docs](.) / faq.md | +|:---| + +# Frequently Asked Questions (FAQ) + +Frequently Asked Questions for Squirrel.Windows, organized by area below. + +## Integrating + +1. **Can Squirrel.Windows be used on applications that aren't made with .Net?** + Yes, you can package a non-c# application in the same manner as described in the Getting Started guide. For additional customization, see [custom squirrel events for non-c# apps](using/custom-squirrel-events-non-CS.md). +1. **How do I migrate a ClickOnce app to Squirrel?** + You may want to look into the [ClickOnceToSquirrelMigrator](https://github.com/flagbug/ClickOnceToSquirrelMigrator) migration helper. + +## Packaging + +1. **How can I tell was is going wrong with the releasify?** + Check `packages\Squirrel.Windows.VERSION\tools\SquirrelSetup.log` for logging information when creating packages. +2. **Do I really have to add all the Squirrel DLLs to my app ?** + Yes, you have to add them all to the NuGet package, however, [others](https://github.com/Squirrel/Squirrel.Windows/issues/531) have used [ILMerge](http://research.microsoft.com/en-us/people/mbarnett/ilmerge.aspx) to generate a single assembly. + +## Distributing + +1. **Can I distribute update files on IIS?** +Yes you can, see [Microsoft IIS](using/microsoft-iis.md) for details. + +## Installing + +1. **The Initial Install via `Setup.exe` is failing. How do I learn what is going wrong?** + Check `%LocalAppData%\SquirrelTemp\SquirrelSetup.log` for logs related to the initial install. +1. **Installer application doesn't do anything. The animation flashes but the application never starts.** + The app is likely crashing on the first run (see [Debugging Installs](using/debugging-installs.md) for details). +2. **The Installer seems to be blocked in Enterprise environments. How can confirm this?** + Squirrel may be prevented from installing if Group Policy disallows the running of executables from `%LocalAppData%`. In this case, the "show log" button on the "installation failed" dialog will fail because `Update.exe` can not run to create a log file. + + The `Setup.exe` for your application should still copy files to `%LocalAppData%\SquirrelTemp` as a pre-installation step. To verify that Group Policy is restricting you, execute `Update.exe` from the command line: + + ``` +C:\>%LocalAppData\MyApp\Update.exe +This program is blocked by group policy. For more information, contact your system administrator. + ``` + + The best course of action is to request that executables for Squirrel and your application be whitelisted by your corporate overlords. + + +## Updating + +1. **How do I determine what is going wrong with the UpdateManager in MyApp?** + You can setup your `\bin` directory so you can execute MyApp in the Visual Studio debugger and simply step through the update process as well as catch exceptions and log the results (see [Debugging Updates](using/debugging-updates.md) for details) +2. **I've Distributed a Broken Copy of Update.exe. How can I fix this?** + Sometimes, you might ship a broken copy of `Update.exe` that succeeds the initial install, but doesn't do what you want for some reason. To fix this, you can force an update of the `Update.exe` by including a copy of `Squirrel.exe` in your app update package. If Squirrel sees this, it will copy in this latest version to the local app installation. +3. **How can you replace DLLs while they're loaded? Impossible!** + You can't. So, how can you do it? The basic trick that ClickOnce uses is, you have a folder of EXEs and DLLs, and an Application Shortcut. When ClickOnce goes to update its stuff, it builds a completely *new* folder of binaries, then the last thing it does is rewrite the app shortcut to point to the new folder. See [] + +--- +| Return: [Table of Contents](readme.md) | +|:---| diff --git a/docs/getting-started.md b/docs/getting-started.md deleted file mode 100644 index 147997ef2..000000000 --- a/docs/getting-started.md +++ /dev/null @@ -1,42 +0,0 @@ -## Quick Start (for the impatient) - -* `Install-Package squirrel.windows`, or grab the binaries from the Releases section - -* In your app at an appropriate time (not at startup, don't interrupt the user's work), call: - -```cs -//Do not forget to add Squirrel namespace! -using Squirrel; - -using (var mgr = new UpdateManager("https://path/to/my/update/folder")) -{ - await mgr.UpdateApp(); -} -``` - -* Use NuGet Package Explorer (or any other way) to create a NuGet package for your app. Make sure that package doesn't have any dependencies. Here's a good example package: - -![](http://cl.ly/image/261D2x2X1e3G/content#png) - -* Open the NuGet Package Console, and type `Squirrel --releasify path/to/the/nuget/package.nupkg` - -You should have a folder called `Releases` with three files in it. Publish those all to S3 in the same folder and you've now got an installer. - - -## BETA: Some hacky notes that will go away soon - -1. Make sure your NuGet package doesn't have any `` tags. - -1. Use the `` tag to include all of your app's dependencies, even ones that for a normal NuGet package wouldn't be there. Make sure to include `Squirrel.dll` and its dependencies too! Every file in the References section of your app should be there. - -1. Put all of your app files in `lib/net45`. I don't care if your app isn't actually a .NET 4.5 app, just do it. Even if your app is written in COBOL, put it in `lib/net45`. - -## What about shortcuts? - -Every EXE in your package will automatically get a shortcut. If you don't want this to be the case, follow the steps for handling Squirrel events below. - -## Handling Squirrel events - -Squirrel events are optional, but they can be super useful, as it gives you a chance to do "custom install actions" on install / uninstall / update. Most production applications will end up doing this, but simple applications can accept the default behavior without any problems. - -Check out the [article on Squirrel Events](./squirrel-events.md) to get started. diff --git a/docs/getting-started/0-overview.md b/docs/getting-started/0-overview.md new file mode 100644 index 000000000..e7a843dab --- /dev/null +++ b/docs/getting-started/0-overview.md @@ -0,0 +1,34 @@ +| [docs](..) / [getting-started](.) / 0-overview.md| +|:---| + +# Getting Started Guide + +Getting Started will walk you through the integration of Squirrel.Windows for a basic c# Windows Forms application named MyApp. + +## MyApp + +MyApp simply displays the assembly location and application version on a simple form. + +![](images/1-MyApp.png) + +For simplicity, any unneeded references and files have been removed from the solution. + +![](images/1-MyApp-Solution.png) + +If you wish to follow along, you can [download](Example/MyApp.zip) a zip file of the MyApp solution. + +## Overview +This guide will go over the following steps to demonstrate using Squirrel.Windows to distribute and update MyApp. + +1. [Integrating](1-integrating.md) - integrating Squirrel `UpdateManager` into your application. +1. [Packaging](2-packaging.md) - packaging application files and preparing them for release. +1. [Distributing](3-distributing.md) - providing install and update files for users. +1. [Installing](4-installing.md) - process of initial installation of your application. +1. [Updating](5-updating.md) - process of updating an existing install. + +--- +| Next: [1. Integrating](1-integrating.md)| +|:---| + + + diff --git a/docs/getting-started/1-integrating.md b/docs/getting-started/1-integrating.md new file mode 100644 index 000000000..81b2fb2cf --- /dev/null +++ b/docs/getting-started/1-integrating.md @@ -0,0 +1,59 @@ +| [docs](..) / [getting-started](.) / 1-integrating.md | +|:---| + + + +# Step 1. Integrating + +The first step is to configure MyApp to work with Squirrel.Windows. This requires you to install the Squirrel.Windows NuGet Package into the `MyApp.sln`. + +## Installing Squirrel.Windows + +The easiest way to install the Squirrel.Windows is using the [Package Manager Console](https://docs.NuGet.org/consume/package-manager-console) in Visual Studio after loading the MyApp solution. + +~~~powershell +PM> Install-Package Squirrel.Windows +~~~ + +### Squirrel.Windows References + +The package will install a number of dependent packages as well as tools that will be used to prepare MyApp to be released. The References in the Solution Explorer of the MyApp project now looks like the following (as of Squirrel.Windows version 1.2.2): + +![](images/1.1-post-package-install.png) + +**Tip:** Alternatively, you can use the "Manage NuGet Packages" GUI to install Squirrel.Windows (right clicking on your project in the Solution Explorer of Visual Studio and select "Manage NuGet Packages..."). + +## Basic Updating + +For the basic example we are going to have MyApp update from your local file system rather than distributing the files via the web. See section [2.2 More Packaging](2.2-More-Packaging.md) for additional options related to the distributing the update files. + +### Basic Squirrel.Windows Update Code +The following code is added to MyApp `Program.cs` to cause the application to check for, download, and install any new releases of MyApp in the background while you use the application. + +**`Program.cs`** + +~~~cs +using Squirrel; +~~~ + +**`static void Main()`** + +~~~cs Task.Run(async () => { + using (var mgr = new UpdateManager("C:\\Projects\\MyApp\\Releases")) + { + await mgr.UpdateApp(); + } }); +~~~ + +The code above demonstrates the most basic update mechanism using the `UpdateApp()` method in an asynchronous task. The actions it takes will be discussed further in section [1.5 Updating](1.5-Updating.md). + +**Caution:** The path you provide the `UpdateManager` is the path to the directory where the `RELEASES` file is located (which is also named `Releases` by default), and not the actual `RELEASES` file. + +**Tip:** By default, the files for updating MyApp will be placed in the same directory as your `MyApp.sln` file under a `Releases` directory (e.g., `C:\Projects\MyApp\Releases`). + + +**Tip:** In this example we simply put the code in the `Program.cs` file. For a production application, place the update code later in start-up process so as to avoid slowing down your program start. + +--- +| Previous: [Getting Started Guide](0-overview.md) | Next: [2. Packaging](2-packaging.md)| +|:---|:---| diff --git a/docs/getting-started/2-packaging.md b/docs/getting-started/2-packaging.md new file mode 100644 index 000000000..22225540b --- /dev/null +++ b/docs/getting-started/2-packaging.md @@ -0,0 +1,74 @@ +| [docs](..) / [getting-started](.) / 2-packaging.md | +|:---| + +# Step 2. Packaging + +Packaging is the process of building, packing, and preparing MyApp release packages for distribution. + +## Building + +The first step in preparing the application for distribution is to build the application. + +1. **Set MyApp Version** - set the initial application version. + + **`Properties\AssemblyInfo.cs`** + + ~~~cs + [assembly: AssemblyVersion("1.0.0")] [assembly: AssemblyFileVersion("1.0.0")] + ~~~ +2. **Switch to Release** - switch your build configuration to `Release`. +3. **Build MyApp** - build your application to ensure the latest changes are included in the package we will be creating. + +## Packing + +Squirrel uses [NuGet](https://www.NuGet.org/) for bundling application files and various application properties (e.g., application name, version, description) in a single release package. + +Section [2.2 More Packaging](2.2-More-Packaging.md) provides additional details on using NuGet and `.nuspec` files to automate the packing of your application. We will be going through the process using the [NuGet Package Explorer](https://npe.codeplex.com/) to manually create a NuGet package. + +1. **Creating a New NuGet Package** - the first step is to create a new NuGet package. +2. **Edit Metadata** - update package metadata for MyApp. + * **Id** - name of the application (no spaces) + * **Version** - version specified in `Properties\Assembly.cs` + * **Dependencies** - Squirrel expects no dependencies in the package (all files should be explicitly added to the package) +3. **Add lib & net45** - add the `lib` folder and the `net45` folder to the project. Squirrel is expecting a single `lib / net45` directory provided regardless of whether your app is a `net45` application. +4. **Add Release Files** - add all the files from `bin\Release` needed by MyApp to execute (including the various files required by Squirrel). + * **Include MyApp Files:** MyApp.exe, MyApp.exe.config, any non-standard .NET dll's needed by MyApp.exe. + * **Include Squirrel Files:** Squirrel.dll, Splat.dll, NuGet.Squirrel.dll, Mono.Cecil.\*, DeltaCompressonDotNet.\*, ICSharpCode.SharpZipLib.\* + * **Exclude:** *.vshost.\*, *.pdb files +5. **Save the NuGet Package File** - save the NuGet package file to where you can easily access later (e.g., `MyApp.sln` directory). Follow the given naming format (e.g., `MyApp.1.0.0.nupkg`). + +![](images/1.2-nuget-package-explorer.png) + +## Releasifying + +Releasifying is the process of preparing the `MyApp.1.0.0.nupkg` for distribution. + +### Using Releasify + +You use the `Squirrel.exe` tool that was included in the Squirrel.Windows package you installed in the `MyApp.sln` previously. + +Use the [Package Manager Console](https://docs.NuGet.org/consume/package-manager-console) to execute `Squirrel.exe --releasify` command. + +~~~powershell +PM> Squirrel --releasify MyApp.1.0.0.nupkg +~~~ + +**Tip:** If you get an error stating that `...'Squirrel' is not recognized...` then you may simply need to restart Visual Studio so the `Package Manager Console` will have loaded all the package tools. + +### Releasify Output + +The `Squirrel --releasify` command completes the following: + +* **Create `Releases` Directory** - creates a Releases directory (in the `MyApp.sln` directory by default). +* **Create `Setup.exe`** - creates a `Setup.exe` file which includes the latest version of the application to be installed. * **Create `RELEASES` File** - creates a file that provides a list of all release files for MyApp to be used during the update process +* **Create `MyApp.1.0.0-full.nupkg`** - copies the package you created to the `Releases` directory. +* **Create `MyApp.*.*.*-delta.nupkg`** - if you are releasing an update, releasify creates a delta file package to reduce the update package size (see [1.5 Updating](1.5-Updating.md) for details). + +**`C:\Projects\MyApp\Releases`** + +![](images/1.2-releases-directory.png) + + +--- +| Previous: [1. Integrating](1-integrating.md) | Next: [3. Distributing](3-distributing.md)| +|:---|:---| \ No newline at end of file diff --git a/docs/getting-started/3-distributing.md b/docs/getting-started/3-distributing.md new file mode 100644 index 000000000..78ca990f7 --- /dev/null +++ b/docs/getting-started/3-distributing.md @@ -0,0 +1,22 @@ +| [docs](..) / [getting-started](.) / 3-distributing.md | +|:---| + +# Step 3. Distributing + +After packaging MyApp for distribution, the various files in the `Releases` directory are used to distribute MyApp to users. + +* **Setup Application** - the `Setup.exe` application is provided to new users to install the current version of MyApp (see [Installing](4-installing.md) for details). +* **Update Files** - the `RELEASES` file, along with versioned full and delta packages, are used by the update process (see [Updating](5-updating.md) for details). + +## Local File Distribution + +For simplicity, this Getting Started guide uses a local file system location for updates. The location is defined in the update location provided to the `UpdateManager` (see code in [Integrating: Basic Updating](1-integrating.md)). + +This generally is not practical for updates, unless all your users have access to similar network path where the files could be easily placed. + + + +--- +| Previous: [2. Packaging](2-packaging.md) | Next: [4. Installing](4-installing.md)| +|:---|:---| + diff --git a/docs/getting-started/4-installing.md b/docs/getting-started/4-installing.md new file mode 100644 index 000000000..8f212655c --- /dev/null +++ b/docs/getting-started/4-installing.md @@ -0,0 +1,31 @@ +| [docs](..) / [getting-started](.) / 4-installing.md | +|:---| +# Step 4. Installing + +The process to install MyApp is as simple as executing the `Setup.exe` application. `Setup.exe` is generated by the `Squirrel --releasify` process and is located in the `Releases` directory. + +## Setup.exe + +`Setup.exe` is a C++ bootstrapper application used to install MyApp on the user's local system. It includes the latest full version of the MyApp package files embedded in the exe file (see [Install Process](../using/install-process.md) for details). + +## Install Process Overview + +The `Setup.exe` application does the following (see [Install Process](../using/install-process.md) for details): + +* Creates a `%LocalAppData%\MyApp` directory for the MyApp to be installed. +* Extracts and prepares the MyApp files under an `app-1.0.0` directory. +* Launches `app-1.0.0\MyApp.exe` at the end of the setup process. + +### Installed File Structure + +An installation for MyApp will look like the following after the initial installation. + +#### `%LocalAppData%\MyApp` Directory + +![](images/1.3-local-app-data-dir.png) + + +--- +| Previous: [3. Distributing](3-distributing.md) | Next: [5. Updating](5-updating.md)| +|:---|:---| + diff --git a/docs/getting-started/5-updating.md b/docs/getting-started/5-updating.md new file mode 100644 index 000000000..9ec9264bb --- /dev/null +++ b/docs/getting-started/5-updating.md @@ -0,0 +1,99 @@ +| [docs](..) / [getting-started](.) / 5-updating.md | +|:---| + +# Step 5. Updating + +The update process uses the update files generated by the `Squirrel --releasify` process. This includes the `RELEASES` file as well as versioned full and delta packages as required. The location of where to look for the distributed update files is provided to the `UpdateManager` in the MyApp code (see code in [Integrating: Basic Updating](1-integrating.md)). + +Updating MyApp to a new version is the culmination of integrating, packaging, and distributing after installing MyApp. The process will cause you to revisit the packaging and distributing steps. +HH + +To release a new update, you must first build, pack, and releasify your updated application. + +### Building + +1. **Update MyApp Version** - update the application version. + + **`Properties\AssemblyInfo.cs`** + + ~~~cs + [assembly: AssemblyVersion("1.0.1")] [assembly: AssemblyFileVersion("1.0.1")] + ~~~ +2. **Switch to Release** - switch your build configuration to `Release`. +3. **Build MyApp** - build your application to ensure the latest changes are included in the package we will be creating. + +### Packing + +Using [NuGet Package Explorer](https://npe.codeplex.com/) complete the following: + +1. **Open Previous NuGet Package** - open the previous NuGet package you created for MyApp version 1.0.0. +2. **Update Version** - update the version in the metadata. +4. **Replace Release Files** - replace the changed files under `lib\net45`. You can simply drag and drop any program specific files that have changed (i.e., the `MyApp.exe` file is the only one that has updated in the example). +5. **Save the NuGet Package File as New Version** - use the "Save As..." feature to save the new version of the package `MyApp.1.0.1.nupkg`. + +### Releasifying + +Use the [Package Manager Console](https://docs.NuGet.org/consume/package-manager-console) to execute `Squirrel.exe --releasify` command using the new `MyApp.1.0.1.nupkg` package. + +~~~powershell +PM> Squirrel --releasify MyApp.1.0.1.nupkg +~~~ + +**Tip:** If you get an error stating that `...'Squirrel' is not recognized...` then you may simply need to restart Visual Studio so the `Package Manager Console` will have loaded all the package tools. This behavior has been seen on the Community Edition of VS 2013. + +#### Releasify Output + +After packaging the new MyApp version 1.0.1, the `Releases` directory has been updated as follows: + +* **Updated Setup Application** - the `Setup.exe` application has been updated to include the latest MyApp version 1.0.1 package. +* **Updated Files** - the `RELEASES` file has been appended to include the newly created full and delta packages. + +## Distributing the New Release + +The `Releases` directory now includes the updated files to distribute to your users. + +**`Releases` Directory** + +![](images/1.5-releases-directory.png) + +The `RELEASES` file contains SHA1 hash, filename, and file size for each package. This information is utilized by the application update process. + +**`RELEASES` File** + +~~~ +E3F67244E4166A65310C816221A12685C83F8E6F MyApp-1.0.0-full.nupkg 600725 +0D777EA94C612E8BF1EA7379164CAEFBA6E24463 MyApp-1.0.1-delta.nupkg 6030 +85F4D657F8424DD437D1B33CC4511EA7AD86B1A7 MyApp-1.0.1-full.nupkg 600752 +~~~ + + +## Application Updating + +In [Step 1. Integrating](1-integrating.md), we configured MyApp to look for and install any updates in the background each time MyApp is executed. In the MyApp example, a path to the `Releases` directory on the file system was specified. + +### Updating Process Overview + +The following steps are performed by the `UpdateManager` each time MyApp is executed (see [Update Process](../using/update-process.md) for details): + +* The `UpdateManager` checks the `RELEASES` file at the distribution location for any updates. +* Any update packages are downloaded and the new MyApp is prepared for execution. +* App shortcuts are updated and old versions of MyApp are cleaned up. + +### MyApp Example + +The first time I run MyApp after providing the update the application is executed like normal. + +![](images/1-MyApp.png) + +In the background, MyApp has obtained and applied the updates in the installation directory. + +![](images/1.5-local-app-data-dir.png) + +The next time MyApp is executed, it will be the newly installed version. + +![](images/1.5-MyApp.png) + +--- +| Previous: [4. Installing](4-installing.md) | Return: [Table of Contents](../readme.md)| +|:---|:---| + diff --git a/docs/getting-started/example/MyApp.zip b/docs/getting-started/example/MyApp.zip new file mode 100644 index 000000000..8b1ab5e9f Binary files /dev/null and b/docs/getting-started/example/MyApp.zip differ diff --git a/docs/getting-started/images/1-MyApp-Solution.png b/docs/getting-started/images/1-MyApp-Solution.png new file mode 100644 index 000000000..f3cb6bd53 Binary files /dev/null and b/docs/getting-started/images/1-MyApp-Solution.png differ diff --git a/docs/getting-started/images/1-MyApp.png b/docs/getting-started/images/1-MyApp.png new file mode 100644 index 000000000..106f55e4c Binary files /dev/null and b/docs/getting-started/images/1-MyApp.png differ diff --git a/docs/getting-started/images/1.1-post-package-install.png b/docs/getting-started/images/1.1-post-package-install.png new file mode 100644 index 000000000..2b29a9f5a Binary files /dev/null and b/docs/getting-started/images/1.1-post-package-install.png differ diff --git a/docs/getting-started/images/1.2-nuget-package-explorer.png b/docs/getting-started/images/1.2-nuget-package-explorer.png new file mode 100644 index 000000000..6af6dd3a4 Binary files /dev/null and b/docs/getting-started/images/1.2-nuget-package-explorer.png differ diff --git a/docs/getting-started/images/1.2-releases-directory.png b/docs/getting-started/images/1.2-releases-directory.png new file mode 100644 index 000000000..a5bad1af6 Binary files /dev/null and b/docs/getting-started/images/1.2-releases-directory.png differ diff --git a/docs/getting-started/images/1.3-local-app-data-dir.png b/docs/getting-started/images/1.3-local-app-data-dir.png new file mode 100644 index 000000000..31ce379db Binary files /dev/null and b/docs/getting-started/images/1.3-local-app-data-dir.png differ diff --git a/docs/getting-started/images/1.5-MyApp.png b/docs/getting-started/images/1.5-MyApp.png new file mode 100644 index 000000000..c4337225b Binary files /dev/null and b/docs/getting-started/images/1.5-MyApp.png differ diff --git a/docs/getting-started/images/1.5-local-app-data-dir.png b/docs/getting-started/images/1.5-local-app-data-dir.png new file mode 100644 index 000000000..ec3626679 Binary files /dev/null and b/docs/getting-started/images/1.5-local-app-data-dir.png differ diff --git a/docs/getting-started/images/1.5-releases-directory.png b/docs/getting-started/images/1.5-releases-directory.png new file mode 100644 index 000000000..f0a89efd3 Binary files /dev/null and b/docs/getting-started/images/1.5-releases-directory.png differ diff --git a/docs/goals.md b/docs/goals.md new file mode 100644 index 000000000..1eae720f2 --- /dev/null +++ b/docs/goals.md @@ -0,0 +1,46 @@ +| [docs](.) / goals.md | +|:---| + +# What Do We Want? + +Deployment and Updates for Desktop applications are a real drag. ClickOnce almost works, but has some glaring bugs that don't seem like they'll ever be fixed. So let's own our own future and build a new one. + +Windows apps should be as fast and as easy to install and update as apps like Google Chrome. From an app developer's side, it should be really straightforward to create an installer for my app, and publish updates to it, without having to jump through insane hoops + +## Configuring + +* Integrating the installer for an existing .NET application should be really easy. +* The client API should be able to check for updates and receive a (preferably in HTML) ChangeLog. +* Developer should have control over custom actions and events during installing and updating. +* Uninstall gives a chance for the application to clean up (i.e. I get to run a chunk of code on uninstall) + +## Packaging + +* Generating an installer given an existing .NET application should be really easy, like it is for ClickOnce. +* Creating an update for my app should be a very simple process that is easily automated. +* Packaging will support delta files to reduce the size of update packages. + +## Distributing + +* Hosting an update server should be really straightforward, and should be able to be done using simple HTTP (i.e. I should be able to host my installer and update feed via S3). +* Support for multiple "channels" (a-la Chrome Dev/Beta/Release). + +## Installing + +* Install is Wizard-Free™ and doesn't look awful (or at least, it should have the *possibility* to not look awful). +* No UAC dialogs, which means.... +* ...installs to the local user account (i.e. under `%LocalAppData%`). +* No Reboots. None! +* Can pull down the .NET Framework if need be. + +## Updating + +* Updates should be able to be applied while the application is running. +* At no time should the user ever be forced to stop what he or she is doing. +* No Reboots. None! + + + +--- +| Return: [Table of Contents](readme.md) | +|:---| diff --git a/docs/hosting-releases-on-iis.md b/docs/hosting-releases-on-iis.md deleted file mode 100644 index 77f290ce1..000000000 --- a/docs/hosting-releases-on-iis.md +++ /dev/null @@ -1,17 +0,0 @@ -# Hosting on IIS -All versions of IIS (including Microsoft Azure PaaS) deny serving files when -the extension MIME type is unknown. If you are hosting your updates in this -manner then you will need to add a Web.config to your downloads repository as -follows: - - - - - - - - - - - -*eg:* ~/downloads/Web.config diff --git a/docs/naming-conventions.md b/docs/naming-conventions.md deleted file mode 100644 index 7c532b4d1..000000000 --- a/docs/naming-conventions.md +++ /dev/null @@ -1,21 +0,0 @@ -## Naming Conventions - -Squirrel uses information from your app's EXE as well as from the NuGet package to fill in a lot of different pieces of the setup and uninstall UI: - -#### Uninstaller - -![](http://cl.ly/image/2N2p3S2a2q3h/content#png) - -#### Start Menu / Desktop shortcuts - -![](http://cl.ly/image/1V0k450c0a0H/content#png) - -![](http://cl.ly/image/1s1O1Q2e023g/content#png) - -#### App Folder - -![](http://cl.ly/image/3o1q2y2n3O14/content#png) - -#### Releases Folder - -![](http://cl.ly/image/062i0h37311T/content#png) diff --git a/docs/readme.md b/docs/readme.md new file mode 100644 index 000000000..b52b41537 --- /dev/null +++ b/docs/readme.md @@ -0,0 +1,59 @@ +| [docs](.) / Table of Contents | +|:---| + +![](artwork/Squirrel-Logo.png) + +# Table of Contents + +This document provides a table of contents for all the Squirrel documentation. + +## General Documentation + +* **[Squirrel Goals](goals.md)** - overview of the goals of the Squirrel.Windows project. +* **[Frequently Asked Questions (FAQ)](faq.md)** - list of frequently asked questions. +* **[Squirrel.Windows License](../COPYING)** - copyright and license for using Squirrel.Windows + +## Getting Started Guide + +The **[Getting Started Guide](getting-started/0-overview.md)** provides a step-by-step guide for integrating Squirrel into a simple Windows Forms application named MyApp. + +1. **[Integrating](getting-started/1-integrating.md)** - integrating Squirrel `UpdateManager` into MyApp. +1. **[Packaging](getting-started/2-packaging.md)** - packaging MyApp files and preparing them for release. +1. **[Distributing](getting-started/3-distributing.md)** - providing install and update files for MyApp. +1. **[Installing](getting-started/4-installing.md)** - process of initial installation of MyApp. +1. **[Updating](getting-started/5-updating.md)** - process of updating an existing install of MyApp. + +## Using Squirrel + + +* **Installing** - documentation related to the initial installation of your application via Setup.exe (and Setup.msi). + * [Install Process](using/install-process.md) - overview of the steps in the install process. + * [Custom Squirrel Events](using/custom-squirrel-events.md) - preforming custom actions for Squirrel events. + * [Custom Squirrel Events (non-c# apps)](using/custom-squirrel-events-non-cs.md) - steps on making a non-c# application Squirrel Aware and handling custom events. + * [Loading GIF](using/loading-gif.md) - specify a "loading" image during initial install of large applications. + * [GitHub](using/github.md) - overview of using GitHub for installing, distributing, and updating. + * [Machine-wide Installs](using/machine-wide-installs.md) - generating an MSI file suitable for installation via Group Policy. + * [Debugging Installs](using/debugging-installs.md) - tips for debugging Squirrel.Windows initial installs. +* **Packaging** - documentation related to packaging app files and preparing them for release. + * [NuGet Package Metadata](using/nuget-package-metadata.md) - overview of the NuGet metadata and its uses by Squirrel. + * [Squirrel Command Line](using/squirrel-command-line.md) - command line options for `Squirrel --releasify` + * [Delta Packages](using/delta-packages.md) - an overview of how `Squirrel.exe` creates delta packages. + * [Application Signing](using/application-signing.md) - adding code signing to `Setup.exe` and your application. +* **Distributing** - documentation related to distributing the Setup.exe and update package files. + * [Microsoft IIS](using/microsoft-iis.md) - overview of using Microsoft IIS for distributing your application. + * [Amazon S3](using/amazon-s3.md) - overview of using Amazon S3 for distributing your application. + * [GitHub](using/github.md) - overview of using GitHub for installing, distributing, and updating. +* **Updating** - documentation related to updating an existing install via the `UpdateManager`. + * [Update Process](using/update-process.md) - overview of the steps in the update process. + * [Update Manager](using/update-manager.md) - reference guide for the `UpdateManager`. + * [GitHub](using/github.md) - overview of using GitHub for installing, distributing, and updating. + * [Debugging Updates](using/debugging-updates.md) - tips for debugging Squirrel.Windows updates. + + +## Contributing + +Why not give back and help make Squirrel even better by contributing to the project. + +* [Contributing](contributing/contributing.md) - overview of ways you can become more involved with Squirrel.Windows. +* [Building Squirrel](contributing/building-squirrel.md) - steps to build squirrel for the impatient. +* [VS Solution Overview](contributing/vs-solution-overview.md) - overview of the various projects in the Squirrel.Windows Visual Studio solution. diff --git a/docs/squirrel-events.md b/docs/squirrel-events.md deleted file mode 100644 index d0bdde34a..000000000 --- a/docs/squirrel-events.md +++ /dev/null @@ -1,61 +0,0 @@ -## Handling Squirrel Events - -Squirrel events allow you to handle custom events around the installation and updating process, which is important because Squirrel doesn't do much of anything at installation time automatically. However, since the code is executing inside your application, it's way easier to do stuff than other systems where you're writing custom "installer DLLs". - -### Custom Events means you opt-out of default behavior - -When none of the apps in your package are "Squirrel-Aware", Squirrel does some things on your behalf to make your life easier, the primary one being that every EXE in your app package automatically gets a shortcut on both the Desktop and the Start Menu. Once you enable Squirrel events *for even a single EXE file*, you must do this yourself. - -### Getting Started - -In your app's `AssemblyInfo.cs`, add the following line: - -``` -[assembly: AssemblyMetadata("SquirrelAwareVersion", "1")] -``` - -For non-C# applications, add an entry to the *English* Version Block info called "SquirrelAwareVersion" with a value of "1". Typically this is done via the "App.rc" resource file. Here's a typical entry: - -``` -BLOCK "StringFileInfo" -BEGIN - BLOCK "040904b0" - BEGIN - VALUE "FileDescription", "Installer for Squirrel-based applications" - VALUE "FileVersion", "0.5.0.0" - VALUE "InternalName", "Setup.exe" - VALUE "LegalCopyright", "Copyright (C) 2014" - VALUE "OriginalFilename", "Setup.exe" - VALUE "ProductName", "Squirrel-based application" - VALUE "ProductVersion", "0.5.0.0" - VALUE "SquirrelAwareVersion", "1" - END -END -``` - -This means that this EXE will be executed by the installer in a number of different scenarios, with special flags - you should handle them correctly: - -* `--squirrel-install x.y.z.m` - called when your app is installed. Exit as soon as you're finished setting up the app -* `--squirrel-firstrun` - called after everything is set up. You should treat this like a normal app run (maybe show the "Welcome" screen) -* `--squirrel-updated x.y.z.m` - called when your app is updated to the given version. Exit as soon as you're finished. -* `--squirrel-obsolete x.y.z.m` - called when your out-of-date app is no longer the newest version. Exit as soon as you're finished. -* `--squirrel-uninstall x.y.z.m` - called when your app is uninstalled. Exit as soon as you're finished. - -## C# Developers, do this instead - -If you are writing a C# app, it is **highly encouraged** to use the `SquirrelAwareApp` helper class to implement this. Here's an implementation that is similar to the default (i.e. non-squirrel-aware) behavior: - -```cs -static bool ShowTheWelcomeWizard; - -using (var mgr = new UpdateManager(updateUrl)) -{ - // Note, in most of these scenarios, the app exits after this method - // completes! - SquirrelAwareApp.HandleEvents( - onInitialInstall: v => mgr.CreateShortcutForThisExe(), - onAppUpdate: v => mgr.CreateShortcutForThisExe(), - onAppUninstall: v => mgr.RemoveShortcutForThisExe(), - onFirstRun: () => ShowTheWelcomeWizard = true); -} -``` diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md deleted file mode 100644 index 104a455c4..000000000 --- a/docs/troubleshooting.md +++ /dev/null @@ -1,27 +0,0 @@ -## What happens when things go wrong - -Squirrel logs a lot of information, but currently it's spread out in a few different places (which isn't Ideal). Here's how to figure out what's happening: - -* *While creating packages*: Check `packages\Squirrel.Windows.VERSION\tools\SquirrelSetup.log` - -* *During Initial Install*: Check `%LocalAppData%\SquirrelTemp\SquirrelSetup.log` - -* *Updating the app*: Catch thrown exceptions and log the results. Alternatively, set up Splat Logging, see [here](https://github.com/Squirrel/Squirrel.Windows.Next/blob/6d7ae23602a3d9a7636265403d42c1090260e6dc/src/Update/Program.cs#L53) for an example. In future versions, this will be less annoying. - -## How do I update my local copy of Update.exe on users' machines? - -Sometimes, you might ship a busted copy of Update.exe that succeeds the initial install, but doesn't do what you want for some reason. To fix this, you can update Update.exe by including your copy of "Squirrel.exe" in your app update. If Squirrel sees this, it will copy in the latest version into the local app installation. - -## Enterprise environments and Group Policy - -Squirrel may be prevented from installing if Group Policy disallows the running of executables from `%LocalAppData%`. In this case, the "show log" button on the "installation failed" dialog will fail because `Update.exe` can not run to create a log file. - -The `Setup.exe` for your application should still copy files to `%LocalAppData%\SquirrelTemp` as a pre-installation step. To verify that Group Policy is restricting you: - -``` -C:\Users\\AppData\Local\SquirrelTemp>Update.exe -This program is blocked by group policy. For more information, contact your system administrator. -``` - -The best course of action is to request that executables for Squirrel and your application be whitelisted by your corporate overlords. - diff --git a/docs/using/amazon-s3.md b/docs/using/amazon-s3.md new file mode 100644 index 000000000..cac4aab9b --- /dev/null +++ b/docs/using/amazon-s3.md @@ -0,0 +1,34 @@ +| [docs](..) / [using](.) / amazon-s3.md +|:---| + +# Amazon S3 + +Amazon S3 can be used as an easy mechanism to host your releases + +## Amazon S3 Setup + +The following steps setup an S3 account and prepares MyApp for distribution. + +1. **Register for Amazon AWS** - if you haven't already, register for an Amazon AWS account and go to the AWS Console. +2. **Create Bucket** - create a new bucket to hold your application updates +3. **Update the Package Location** - update the package location on the `UpdateManager` in MyApp to use the S3 `Link` address for the files minus the actual file name. This is the address for downloading the file and is similar to the following address: + `https://s3-us-west-2.amazonaws.com/myapp.bucket` +4. **Build, Pack, Releasify** - perform the necessary steps to build, package, and releasify MyApp for distribution. +3. **Upload Files** - upload the files from the Squirrel `Releases` directory into the S3 bucket. +4. **Make Public** - make the files public by selecting the files and performing the "Make Public" action. + +## Amazon S3 Updates + +After you have setup your S3 account, the following steps will distribute a new package for release. + +4. **Build, Pack, Releasify** - perform the necessary steps to build, package, and releasify MyApp for distribution. +3. **Upload Files** - upload the new files from the Squirrel `Releases` directory. Make sure to include the new `Setup.exe` and `RELEASES` file along with any full and delta files for the new version. +4. **Make Public** - make the new files public by selecting the files and performing the "Make Public" action. + + +--- +| Return: [Table of Contents](../readme.md) | +|----| + + + diff --git a/docs/using/application-signing.md b/docs/using/application-signing.md new file mode 100644 index 000000000..ebcfa378e --- /dev/null +++ b/docs/using/application-signing.md @@ -0,0 +1,30 @@ +| [docs](..) / [using](.) / application-signing.md +|:---| + + +# Application Signing + +Signing your installer with a valid code signing certificate is one of the most important things that you need to do for production apps. Both IE SmartScreen as well as virus scanning software will give a significant amount of "points" to apps that are signed correctly, preventing your users from getting scary dialogs. + +Acquire a code-signing certificate - it's recommended to get a Windows Error Reporting-compatible certificate, see this MSDN article for more information, then pass the -n parameter, which are the parameters you would pass to `signtool.exe sign` to sign the app. + +Squirrel makes signing easy, as it signs all of your application's executables *as well* as the final generated Setup.exe. + +An example invocation including both of these features would be something like: + +~~~powershell +PM> Squirrel --releasify MyApp.1.0.0.nupkg -n "/a /f CodeCert.pfx /p MySecretCertPassword" +~~~ + + + +## See Also +* [Squirrel Command Line](squirrel-command-line.md) - command line options for `Squirrel --releasify` + + +--- +| Return: [Table of Contents](../readme.md) | +|----| + + + diff --git a/docs/using/custom-squirrel-events-non-cs.md b/docs/using/custom-squirrel-events-non-cs.md new file mode 100644 index 000000000..badb61563 --- /dev/null +++ b/docs/using/custom-squirrel-events-non-cs.md @@ -0,0 +1,45 @@ +| [docs](..) / [using](.) / custom-squirrel-events-non-cs.md +|:---| + +# Custom Squirrel Events (Non-C# Apps) + +Squirrel events allow you to handle custom events around the installation and updating process. + +### Making Your App Squirrel Aware + +Add an entry to the *English* Version Block info called "SquirrelAwareVersion" with a value of "1". Typically this is done via the "App.rc" resource file. Here's a typical entry: + +``` +BLOCK "StringFileInfo" +BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileDescription", "Installer for Squirrel-based applications" + VALUE "FileVersion", "0.5.0.0" + VALUE "InternalName", "Setup.exe" + VALUE "LegalCopyright", "Copyright (C) 2014" + VALUE "OriginalFilename", "Setup.exe" + VALUE "ProductName", "Squirrel-based application" + VALUE "ProductVersion", "0.5.0.0" + VALUE "SquirrelAwareVersion", "1" + END +END +``` + +### Application Startup Commands + +This means that this EXE will be executed by the installer in a number of different scenarios, with special flags - you should handle them correctly: + +* `--squirrel-install x.y.z.m` - called when your app is installed. Exit as soon as you're finished setting up the app +* `--squirrel-firstrun` - called after everything is set up. You should treat this like a normal app run (maybe show the "Welcome" screen) +* `--squirrel-updated x.y.z.m` - called when your app is updated to the given version. Exit as soon as you're finished. +* `--squirrel-obsolete x.y.z.m` - called when your out-of-date app is no longer the newest version. Exit as soon as you're finished. +* `--squirrel-uninstall x.y.z.m` - called when your app is uninstalled. Exit as soon as you're finished. + +## See Also + +* [Custom Squirrel Events for c# Apps](custom-squirrel-events.md) - steps on making a c# application Squirrel Aware and handling custom events. + +--- +| Return: [Table of Contents](../readme.md) | +|----| \ No newline at end of file diff --git a/docs/using/custom-squirrel-events.md b/docs/using/custom-squirrel-events.md new file mode 100644 index 000000000..956342b6a --- /dev/null +++ b/docs/using/custom-squirrel-events.md @@ -0,0 +1,55 @@ +| [docs](..) / [using](.) / custom-squirrel-events.md +|:---| + +# Custom Squirrel Events + +## Handling Squirrel Events + +Squirrel events allow you to handle custom events around the installation and updating process, which is important because Squirrel doesn't do much of anything at installation time automatically. However, since the code is executing inside your application, it's way easier to do stuff than other systems where you're writing custom "installer DLLs". + +### Overriding Default Behaviors + +When none of the apps in your package are "Squirrel-Aware", Squirrel does some things on your behalf to make your life easier, the primary one being that every EXE in your app package automatically gets a shortcut on both the Desktop and the Start Menu. Once you enable Squirrel events *for even a single EXE file*, you must do this yourself. + +### Making Your App Squirrel Aware + +In your app's `AssemblyInfo.cs`, add the following line: + +``` +[assembly: AssemblyMetadata("SquirrelAwareVersion", "1")] +``` + +### Using the `SquirrelAwareApp` Helper + +If you are writing a C# app, it is **highly encouraged** to use the `SquirrelAwareApp` helper class to implement this. Here's an implementation that is similar to the default (i.e. non-squirrel-aware) behavior: + +```cs +static bool ShowTheWelcomeWizard; +... +using (var mgr = new UpdateManager(updateUrl)) +{ + // Note, in most of these scenarios, the app exits after this method + // completes! + SquirrelAwareApp.HandleEvents( + onInitialInstall: v => mgr.CreateShortcutForThisExe(), + onAppUpdate: v => mgr.CreateShortcutForThisExe(), + onAppUninstall: v => mgr.RemoveShortcutForThisExe(), + onFirstRun: () => ShowTheWelcomeWizard = true); +} +``` + +## App Setup Helper Methods + +These methods help you to set up your application in Squirrel events - if you're not using custom Squirrel events, you probably don't need to call these methods. + +* `[Create/Remove]ShortcutsForExecutable` - creates and removes shortcuts on the desktop or in the Start Menu. + +* `[Create/Remove]UninstallerRegistryEntry` - creates and removes the uninstaller entry. Normally called by `Update.exe`. + +## See Also + +* [Custom Squirrel Events for non-c# Apps](custom-squirrel-events-non-cs.md) - steps on making a non-c# application Squirrel Aware and handling custom events. + +--- +| Return: [Table of Contents](../readme.md) | +|----| \ No newline at end of file diff --git a/docs/using/debugging-installs.md b/docs/using/debugging-installs.md new file mode 100644 index 000000000..700ae073c --- /dev/null +++ b/docs/using/debugging-installs.md @@ -0,0 +1,22 @@ +| [docs](..) / [using](.) / debugging-installs.md +|:---| + +# Debugging Installs + +The following tips will help you to debug the installation of an Squirrel app. + +## Simulating an Install and First Run + +If the install of your application doesn't seem to be working, you can explore the behavior by executing the install steps from the command line: + +~~~ps +C:\user\AppData\Local\MyApp> Update.exe --squirrel-install 1.0.0 +C:\user\AppData\Local\MyApp> Update.exe --squirrel-firstrun +~~~ + +The first cmd should create some shortcuts then immediately exit, then the 2nd one should start your app ([source](https://github.com/Squirrel/Squirrel.Windows/issues/525)) + + +--- +| Return: [Table of Contents](../readme.md) | +|----| \ No newline at end of file diff --git a/docs/using/debugging-updates.md b/docs/using/debugging-updates.md new file mode 100644 index 000000000..d7eb041b4 --- /dev/null +++ b/docs/using/debugging-updates.md @@ -0,0 +1,38 @@ +| [docs](..) / [using](.) / debugging-updates.md +|:---| + +# Debugging Updates + +The following tips will help you to debug the update process in your application. + +## Update.exe not found? + +Executing MyApp from Visual Studio will execute the update process and you will get the following exception from the `UpdateManager`: + +~~~ +Update.exe not found, not a Squirrel-installed app? +~~~ + +The `UpdateManager` is expecting to find the `Update.exe` application installed one directory up from the EXE (e.g., the `\bin` directory for default Visual Studio projects). + +To resolve this, you can simply place a file named `Update.exe` or you can copy the `Squirrel.exe` from the `MyApp\packages\squirrel.windows.1.2.2.tools` directory and rename it Update.exe (this is the actual Update.exe packaged inside `Setup.exe`). + +Executing MyApp from Visual Studio will now cause it to complete the update process and your `\bin` directory will resemble the `%LocalAppData\MyApp%` install directory: + +![](images/debugging-update-dir.png) + +## Catching Update Exceptions + +You can catch thrown exceptions and log the results. + +~~~cs +Task.Run(async () => { try { using (var mgr = new UpdateManager("C:\\Projects\\MyApp\\Releases")) { await mgr.UpdateApp(); } } catch (Exception ex) { + // perform logging here or inform user here... } }); +~~~ + +Alternatively, set up Splat Logging, see [here](https://github.com/Squirrel/Squirrel.Windows.Next/blob/6d7ae23602a3d9a7636265403d42c1090260e6dc/src/Update/Program.cs#L53) for an example. + + +--- +| Return: [Table of Contents](../readme.md) | +|----| \ No newline at end of file diff --git a/docs/using/delta-packages.md b/docs/using/delta-packages.md new file mode 100644 index 000000000..5bb288946 --- /dev/null +++ b/docs/using/delta-packages.md @@ -0,0 +1,34 @@ +| [docs](..) / [using](.) / delta-packages.md +|:---| + + +# Delta Packages + +Now, once we've got a full package, we need to generate a Delta package. To do this, we'll replace all the DLL/EXEs in the NuGet packages with bsdiff files. [bspatch/bsdiff](http://code.logos.com/blog/2010/12/binary_patching_with_bsdiff.html) is a mostly efficient algorithm for calculating diffs between binary files (especially Native binaries, but it works well for .NET ones too), and a way to apply them. + +So, this is pretty easy: + +1. Extract the previous NuGet package +1. Extract the current NuGet package +1. Replace every EXE/DLL with the bsdiff. So, `lib\net40\MyCoolApp.exe` becomes `lib\net40\MyCoolApp.exe.diff`. Create a file that contains a SHA1 of the expected resulting file and its filesize called `lib\net40\MyCoolApp.exe.shasum` +1. New DLLs in current get put in verbatim +1. Zip it back up + +The .shasum file has the same format as the Releases file described in the "'Latest' Pointer" section, except that it will only have one entry. + +So now we've got all of the *metadata* of the original package, just none of its *contents*. To get the final package, we do the following: + +1. Take the previous version, expand it out +1. Take the delta version, do the same +1. For each DLL in the previous package, we bspatch it, then check the shasum file to ensure we created the correct resulting file +1. If we find a DLL in the new package, just copy it over +1. If we can't find a bspatch for a file, nuke it (it doesn't exist in the new rev) +1. Zip it back up + + +--- +| Return: [Table of Contents](../readme.md) | +|----| + + + diff --git a/docs/using/github.md b/docs/using/github.md new file mode 100644 index 000000000..d52b5959b --- /dev/null +++ b/docs/using/github.md @@ -0,0 +1,71 @@ +| [docs](..) / [using](.) / github.md +|:---| + +# Using GitHub + +GitHub release assets can be used to distribute the necessary Squirrel files for the Squirrel install and update process. It still requires you to upload all the release files as assets for each release, but provides you a means of hosting your update files via your GitHub repository. + +## Installing from GitHub + +GitHub allows you to provide a [static link](https://help.github.com/articles/linking-to-releases/) to a repositories latest release page. You can direct your users to download the `Setup.exe` from the list of assets you uploaded for the release. + +~~~ +https://github.com/myuser/MyApp/releases/latest +~~~ + +**Tip:** This link simply redirects to the repositories latest release page, and cannot be used to download an asset directly (i.e., you can't simply make a static link to ".../releases/latest/Setup.exe"). However, you can use the [GitHub API with ajax](http://stackoverflow.com/a/26454035) to provide a direct link on your website and avoid the user having to select the correct file or navigate to the GitHub website. + +## Distributing from GitHub + +The following steps are required to distribute your RELEASES and update NuGet packages with GitHub: + +1. **Commit Latest Code** - In order for GitHub to mark a new release as the `Latest`, you have at least on additional commit since since the last release tag was added (i.e., releases tags must not share the same commit). +1. **Create a New Release** - [Create a new GitHub release](https://help.github.com/articles/creating-releases/) in your MyApp repository matching your current release version (e.g., 1.0.0). +2. **Upload Release Files** - upload all of the files from `Releases` as assets of the GitHub release (e.g., RELEASES, MyApp.1.0.0-full.nupkg, MyApp.1.0.1-delta.nupkg, MyApp.1.0.1-full.nupkg). +3. **Set Pre-release (optional)** - if desired, set the release as a pre-release. +4. **Publish the Release** - click the "Publish Release" to make the release available to the general public and your users. + +**Important:** You must upload all packages as assets you wish to be available for update (i.e., the GitHubUpdateManager doesn't look back to previous GitHub releases for previous version packages). If you only include the latest packages, Squirrel will be forced to download the latest full package for each update. + + +## Updating with GitHub + +The Updating process requires you to build, package, releasify, and distribute the update files. + +**Important:** You must ensure there is at least one additional commit since the last version release before adding a new release. GitHub will not update the latest release if the new release tag is tied to the same last commit as a previous release tag. + +### GitHub Update Manager + +To use GitHub release assets as your distribution mechanism you need to replace `UpdateManager` with `GitHubUpdateManager` when integrating Squirrel in your app: + +**`Program.cs`** + +~~~cs +using Squirrel; +~~~ + +**`static void Main()`** + +~~~cs +Task task = Task.Run(async () => { using (var mgr = UpdateManager.GitHubUpdateManager("https://github.com/myuser/myapp")) { await mgr.Result.UpdateApp(); } }); +~~~ + +**Tip:** You can also specify that the update manager should use `prerelease` for updating (see method signature for details). + +**Source:** See [Issue #442](https://github.com/Squirrel/Squirrel.Windows/issues/442) for more information. + +### How it Works + +The GitHub API is used by the `GitHubUpdateManager` to obtain the correct release and asset files for downloading. The following actions are performed: + +1. Extracts the username and repository from the url (e.g., "myuser" and "myapp"). +2. Uses the GitHub API to get the latest release information. For example, the following url obtains a json list of all release information for the Squirrel.Windows repository: [https://api.github.com/repos/Squirrel/Squirrel.Windows/releases](https://api.github.com/repos/Squirrel/Squirrel.Windows/releases) +3. Obtains the correct download path from the `html_url` attribute of the latest release (or pre-release if specified) to be used as the path for downloading assets. +4. Follows the normal Squirrel update process by looking for a `RELEASES` file and downloading the necessary delta or full application packages. + +--- +| Return: [Table of Contents](../readme.md) | +|----| + + + diff --git a/docs/using/images/debugging-update-dir.png b/docs/using/images/debugging-update-dir.png new file mode 100644 index 000000000..74b75f66d Binary files /dev/null and b/docs/using/images/debugging-update-dir.png differ diff --git a/docs/using/images/uninstall-app.png b/docs/using/images/uninstall-app.png new file mode 100644 index 000000000..173664a73 Binary files /dev/null and b/docs/using/images/uninstall-app.png differ diff --git a/docs/using/install-process.md b/docs/using/install-process.md new file mode 100644 index 000000000..064c1da69 --- /dev/null +++ b/docs/using/install-process.md @@ -0,0 +1,73 @@ +| [docs](..) / [using](.) / install-process.md +|:---| + +# Install Process + +This section goes into detail about the install process. + +## Setup.exe + +`Setup.exe` is a C++ bootstrapper application used to install your app on the user's local system. It is generated as part of the `Squirrel --releasify` process. + +The `Setup.exe` file includes the `Update.exe` application and the latest version of the MyApp package to be installed. A single executable file can be provided due to the `WriteZipToSetup.exe` tool injecting the appropriate files into the exe. + +In addition, the `Setup.exe` will also ensure that .NET 4.5 is installed on the user's computer. + +## Install Location + +The `Setup.exe`, and later the `UpdateManager` in MyApp must have the ability to write files to and execute files from the application install location. To ensure permission for all types of users, the user's application data directory is selected as the install location (i.e., `%LocalAppData%\MyApp`). + +The installation root really only needs to consist of two types of folders: + +* **Packages** - folder used to download and assemble the update package files. +* **App Folders** - the "installed" application files for a given version of MyApp. + +``` +\%LocalAppData% + \packages + MyApp-1.0.0.nupkg + MyApp-1.0.1-delta.nupkg + MyApp-1.0.1.nupkg + \app-1.0.0 + MyApp.exe + \app-1.0.1 + MyApp.exe +``` + +The packages directory is effectively immutable, it simply consists of the packages we've downloaded. Using the user's local application data directory means that we the needed write-access to the install directory on a per-user basis. + +**Tip:** See [Machine-wide Installs](machine-wide-installs.md) for more information on ensuring your application pushed to all users in an enterprise environment. + +## Install Process Overview + +The `Setup.exe` application preforms the following: + +1. **Ensures .NET Framework Installed** - determines if .NET Framework is available, and if not relaunches itself with `/installfx45` to download and launch the .NET Framework installer. +1. **Create `%LocalAppData%\MyApp` Directory** - creates a directory for the MyApp to be installed. +2. **Extracts `Update.exe`** - extracts the `Update.exe` application to the application directory (`%LocalAppData%\MyApp`). +3. **Extracts `MyApp.1.0.0-full.nupkg`** - extracts the MyApp full application package to the `%LocalAppData%\MyApp\packages\temp` directory. +4. **Executes `Update.exe` to Finish Install** - executes the `Updater.exe` application with the `/install` switch to finish the application installation and then launch the application. + 1. **Copy MyApp to `app-1.0.0` Directory** - copy the full version of MyApp files to a application sub-directory (e.g., `MyApp\app-1.0.0`). + 2. **Launch MyApp** - at the end of the setup process, the Updater launches the newly installed version of MyApp. +6. **MyApp Creates Shortcuts** - the first execution of the application will cause shortcuts to be created on the desktop and Windows start menu for MyApp. + +## Desktop & Windows Start Shortcuts + +By default, application shortcuts are created on the desktop and the Windows Start menu that point to the `Update.exe` application with additional arguments pointing to the correct application to execute. + +**`MyApp.lnk` (Application Shortcut)** + +* **Target:** `C:\Users\kbailey\AppData\Local\MyApp\Update.exe --processStart MyApp.exe` +* **Start in:** `C:\Users\kbailey\AppData\Local\MyApp\app-1.0.0` + + +## See Also + +* [Loading GIF](loading-gif.md) - specify a "loading" image during initial install of large applications. +* [Machine-wide Installs](machine-wide-installs.md) - generating an MSI file suitable for installation via Group Policy. +* [NuGet Package Metadata](using/nuget-package-metadata.md) - overview of the NuGet metadata and its uses by Squirrel. + +--- +| Return: [Table of Contents](../readme.md) | +|----| + diff --git a/docs/using/loading-gif.md b/docs/using/loading-gif.md new file mode 100644 index 000000000..2f0effafe --- /dev/null +++ b/docs/using/loading-gif.md @@ -0,0 +1,20 @@ +| [docs](..) / [using](.) / loading-gif.md +|:---| + +# Loading GIF + +Squirrel installers don't have any UI - the goal of a Squirrel installer is to install so blindingly fast that double-clicking on Setup.exe *feels* like double-clicking on an app shortcut. Make your installer **fast**. + +However, for large applications, this isn't possible. For these apps, Squirrel will optionally display a graphic as a "splash screen" while installation is processing, but only if installation takes more than a pre-set amount of time. This will be centered, backed by a transparent window, and can optionally be an animated GIF. Specify this via the `-g` parameter. + +~~~powershell +PM> Squirrel --releasify MyApp.1.0.0.nupkg -g .\loading.gif +~~~ + +## See Also +* [Squirrel Command Line](squirrel-command-line.md) - command line options for `Squirrel --releasify` + + +--- +| Return: [Table of Contents](../readme.md) | +|----| diff --git a/docs/using/machine-wide-installs.md b/docs/using/machine-wide-installs.md new file mode 100644 index 000000000..a5fb21f1a --- /dev/null +++ b/docs/using/machine-wide-installs.md @@ -0,0 +1,24 @@ +| [docs](..) / [using](.) / machine-wide-installs.md +|:---| + + +# Machine-wide Installs + +Squirrel's Releasify command generates an MSI file suitable for installation via Group Policy. This MSI isn't a general-purpose installer, this means that once you run the MSI, users from now on will get the app installed, on next Login. + +So, most normal users should continue to run the Setup.exe's generated by Releasify, but if you want to have an IT Admin Friendly version, you can hand off the MSI + +Most users of Squirrel won't have to do anything new to enable this behavior, though certain NuGet package IDs / names might cause problems with MSI. + +**Source:** See [issue #466](https://github.com/Squirrel/Squirrel.Windows/issues/466) for more details. + +### Disabling MSI Generation +Generating MSIs can be disabled via the --no-msi flag as shown below: + +~~~powershell +PM> Squirrel --releasify MyApp.1.0.0.nupkg --no-msi +~~~ + +--- +| Return: [Table of Contents](../readme.md) | +|----| diff --git a/docs/using/microsoft-iis.md b/docs/using/microsoft-iis.md new file mode 100644 index 000000000..e05d5c9d4 --- /dev/null +++ b/docs/using/microsoft-iis.md @@ -0,0 +1,34 @@ +| [docs](..) / [using](.) / microsoft-iis.md +|:---| + +# Microsoft IIS + +If you use Microsoft IIS to distribute the necessary Squirrel files, you must provide a custom `Web.config` file as described below. + +## Hosting on IIS + +All versions of IIS (including Microsoft Azure PaaS) deny serving files when +the extension MIME type is unknown. If you are hosting your updates in this +manner then you will need to add a `Web.config` to your downloads repository as +follows: + +**`~/downloads/Web.config` File** + +~~~xml + + + + + + + + + +~~~ + + +--- +| Return: [Table of Contents](../readme.md) | +|----| + + diff --git a/docs/using/nuget-package-metadata.md b/docs/using/nuget-package-metadata.md new file mode 100644 index 000000000..8c7df98f6 --- /dev/null +++ b/docs/using/nuget-package-metadata.md @@ -0,0 +1,17 @@ +| [docs](..) / [using](.) / nuget-package-metadata.md +|:---| + +# NuGet Package Metadata + +Squirrel uses information from your app's EXE as well as the NuGet package Metadata for the setup and uninstall UI. + +* **Id** - name of the application (no spaces or [dots](https://github.com/Squirrel/Squirrel.Windows/issues/523)). Used to name the release packages (e.g., **MyApp**-1.0.0-full.nupkg). +* **Title** - used for the name of the application in the Windows Application Uninstaller. +* **Version** - version specified in `Properties\Assembly.cs`. Used for naming the release package(e.g., MyApp-**1.0.0**-full.nupkg) as well as describing the version number in the Windows Uninstaller (see screenshot below). +* **Icon Url** - url to an icon to be used for the application. Used for the shortcuts and Windows Uninstaller icons. + +![](images/uninstall-app.png) + +--- +| Return: [Table of Contents](../readme.md) | +|----| diff --git a/docs/using/squirrel-command-line.md b/docs/using/squirrel-command-line.md new file mode 100644 index 000000000..827fb916d --- /dev/null +++ b/docs/using/squirrel-command-line.md @@ -0,0 +1,37 @@ +| [docs](..) / [using](.) / squirrel-command-line.md +|:---| + +# Squirrel Command Line + +Here is a simplified help output specifically around creating releases: + +``` +Usage: Squirrel.exe command [OPTS] +Creates Squirrel packages + +Commands + --releasify=VALUE Update or generate a releases directory with a + given NuGet package + +Options: + -h, -?, --help Display Help and exit + -r, --releaseDir=VALUE Path to a release directory to use with Releasify + -p, --packagesDir=VALUE Path to the NuGet Packages directory for C# apps + --bootstrapperExe=VALUE + Path to the Setup.exe to use as a template + -g, --loadingGif=VALUE Path to an animated GIF to be displayed during + installation + -n, --signWithParams=VALUE Sign the installer via SignTool.exe with the + parameters given +``` + +## See Also +* [Loading GIF](loading-gif.md) - specify a "loading" image during initial install of large applications. +* [Application Signing](application-signing.md) - adding code signing to `Setup.exe` and your application. + +--- +| Return: [Table of Contents](../readme.md) | +|----| + + + diff --git a/docs/using/update-manager.md b/docs/using/update-manager.md new file mode 100644 index 000000000..353cf2933 --- /dev/null +++ b/docs/using/update-manager.md @@ -0,0 +1,57 @@ +| [docs](..) / [using](.) / update-manager.md +|:---| + +# Update Manager Reference + +## Basic Updating + +The "Easy Mode" method that does everything all in one go. + +* `UpdateApp` - downloads and updates the app to the latest version. + +## Advanced Updating + +The following methods are provided to allow you to have more control of the update process (i.e., to interact with app updates and apply them if desired). + +* `CheckForUpdate` - checks on the server if there are updates available. Returns an `UpdateInfo` object that contains information about any pending updates. + +* `DownloadReleases` - downloads release files (the `nupkg` file deltas) from the server to the local machine + +* `ApplyReleases` - installs the downloaded packages, and returns the new `app-[version]` directory path. + +### UpdateInfo + +The `UpdateInfo` class contains information about available and installed releases. + +~~~cs +public class UpdateInfo +{ + public ReleaseEntry CurrentlyInstalledVersion; + public ReleaseEntry FutureReleaseEntry; + public List ReleasesToApply; +} +~~~ + +### ReleaseEntry + +The `ReleaseEntry` class contains the specifics of each release. + +~~~cs +public interface ReleaseEntry +{ + public string SHA1; + public string Filename; + public long Filesize; + public bool IsDelta; +} +~~~ + + +## See Also +* [Update Process](update-process.md) - overview of the steps in the update process. +* [GitHub Update Manager](update-manager-github.md) - process of using `GitHubUpdateManager`. + +--- +| Return: [Table of Contents](../readme.md) | +|----| + diff --git a/docs/using/update-process.md b/docs/using/update-process.md new file mode 100644 index 000000000..f53f063be --- /dev/null +++ b/docs/using/update-process.md @@ -0,0 +1,25 @@ +| [docs](..) / [using](.) / update-process.md +|:---| + + +# Update Process + +The following steps are performed by the `UpdateManager` each time your app is executed: + +1. **Check for Updates** - the `RELEASES` file at the distribution location is downloaded and compared to local `RELEASES` file to check for any updates. +2. **Download & Verify Update Packages** - if there is a new release, the `UpdateManager` determines whether to download the deltas or the latest full package to update to the current version. The packages are compared against their SHA1 in the `RELEASES` file for verification. +3. **Build Full Package from Deltas** - if delta packages were downloaded, a new full package is created from the previous full package and the downloaded delta file. +3. **Install New Version** - the current version of MyApp is extracted from the full package and placed in a new `%LocalAppData%\MyApp` install directory based on the version number (e.g., `app-1.0.1`). +4. **Update Shortcuts** - desktop and Windows Start Menu shortcuts are updated to point to the new MyApp version (via the `--processStart` command line parameter passed to `Update.exe`). +5. **Previous Version Clean-up** - on the next startup of MyApp, the previous packages and installed app directory of all but the previous install are also deleted. + +## See Also + +* [Update Manager](update-manager.md) - reference guide for the `UpdateManager`. +* [Debugging Updates](debugging-updates.md) - tips on debugging your Squirrel application. + + +--- +| Return: [Table of Contents](../readme.md) | +|----| + diff --git a/docs/using/x-doc-template.md b/docs/using/x-doc-template.md new file mode 100644 index 000000000..6612adceb --- /dev/null +++ b/docs/using/x-doc-template.md @@ -0,0 +1,26 @@ +| [docs](..) / [using](.) / filename.md +|:---| + +# Title + +text + +## Sub-title + +text + +~~~cs +code +~~~ + +**Tip:** text + + +## See Also + +* [seealso]() - text + + +--- +| Return: [Table of Contents](../readme.md) | +|----| \ No newline at end of file diff --git a/specs/ClientImplementation.md b/specs/ClientImplementation.md deleted file mode 100644 index 9aa2f1d6e..000000000 --- a/specs/ClientImplementation.md +++ /dev/null @@ -1,117 +0,0 @@ -# Client-side Library - -To be able to meet the specifications of the "updates" section of the README (especially the bits about 'No Reboots', 'Updates should be applied while the app is running'), we have to be a bit more clever than "Stuff everything in a folder, hit go". - -### How can you replace DLLs while they're loaded? Impossible! - -You can't. So, how can you do it? The basic trick that ClickOnce uses is, you have a folder of EXEs and DLLs, and an Application Shortcut. When ClickOnce goes to update its stuff, it builds a completely *new* folder of binaries, then the last thing it does is rewrite the app shortcut to point to the new folder. - -So, to that end, the installation root really only needs to consist of two folders: - -``` - \packages - MyCoolApp-1.0.nupkg - MyCoolApp-1.1-delta.nupkg - MyCoolApp-1.1.nupkg ## Generated from 1.0+1.1-delta - \app-[version] -``` - -Packages is effectively immutable, it simply consists of the packages we've downloaded. This means however, that we need write-access to our own install directory - this is fine for per-user installs, but if the user has installed to Program Files, we'll need to come up with another solution. And that solution is, "Only support per-user installs". - -## The Update process, from start to finish - -### Syncing the packages directory - -The first thing that the Squirrel client will do to start the updates process, is download the remote version of "Releases". Comparing this file to the Releases file on disk will tell us whether an update is available. - -Determining whether to use the delta packages or not will depend on the download size - the updater will take the smaller of "latest full package" vs. "Sum of all delta packages between current and latest". The updater makes a choice, then fetches down all the files and checks them against the SHA1s in the Releases file. - -If the installer decided to do a Delta update, it will then use the Delta updates against the existing Full package to build a new Full package. - -### Installing a full update - -Since we've done the prep work to create a new NuGet package from the deltas, the actual update process only has to deal with full NuGet packages. This is as simple as: - -1. Extract the NuGet package to a temp dir -1. Move lib\net45 to \app-[newversion] -1. Rewrite the shortcut to point to \app-[newversion] - -On next startup, we blow away \app-[version] since it's now the previous version of the code. - -### What do we do on Setup? (Bootstrapping) - -TODO - -### Client-side API - -Referencing Squirrel.dll, `UpdateManager` is all the app dev needs to use. - - UpdateManager - UpdateInfo CheckForUpdates() - UpdateInfo DownloadUpdate() - List ApplyUpdates() - -`UpdateInfo` contains information about pending updates if there is any, and is null if there isn't. - -``` - UpdateInfo - ReleaseEntry CurrentlyInstalledVersion - ReleaseEntry FutureReleaseEntry - IEnumerable ReleasesToApply -``` - -And `ReleaseEntry` contains the specifics of each release: - -``` - ReleaseEntry - string SHA1 - string Filename - long Filesize - bool IsDelta -``` - -## Applying Updates - -First, check the location where your application updates are hosted: - -```cs -var updateManager = new UpdateManager(@"C:\Users\brendanforster\Desktop\TestApp"); - -var updateInfo = await updateManager.CheckForUpdate(); - -if (updateInfo == null) { - Console.WriteLine("No updates found"); -} else if (!updateInfo.ReleasesToApply.Any()) { - Console.WriteLine("You're up to date!"); -} else { - var latest = updateInfo.ReleasesToApply.MaxBy(x => x.Version).First(); - Console.WriteLine("You can update to {0}", latest.Version); -} -``` - -Depending on the result you get from this operation, you might: - - - not detect any updates - - be on the latest version - - have one or more versions to apply - -### Fetch all the Updates - -The result from `CheckForUpdates` will contain a list of releases to apply to your current application. - -That result becomes the input to `DownloadReleases`: - -```cs -var releases = updateInfo.ReleasesToApply; - -await updateManager.DownloadReleases(releases); -``` - -### Apply The Updates - -And lastly, once those updates have been downloaded, tell Squirrel to apply them: - -```cs -var results = await updateManager.ApplyReleases(downloadedUpdateInfo); -updateManager.Dispose(); // don't forget to tidy up after yourself -``` diff --git a/specs/Implementation.md b/specs/Implementation.md deleted file mode 100644 index 6bc1ce5c4..000000000 --- a/specs/Implementation.md +++ /dev/null @@ -1,61 +0,0 @@ -# Implementation - -## Major Pieces - -TODO - -## Production / "Server Side" - -### The tricky part - -Ironically, the difficulty of using NuGet packages as a distribution container for your app, is *if your app uses NuGet*. This is because NuGet (with good reason!) packages the *list* of dependencies, not the actual binaries. So, if we were to try to use the NuGet package of the App directly, we'd be missing a bunch of DLLs. - -So, we need an application that can *flatten* a NuGet dependency tree and repack the package with all the DLLs. While this is a lot of steps, it's actually pretty straightforward: - -1. Extract the App's NuGet package to a temp directory. -1. Walk the list of dependencies. For each dependency, extract it on top of the temp directory (i.e. so that its `lib/*` ends up in the App's dir) -1. Recursively do the same thing (i.e. recurse down the dependency tree) -1. Edit the root NuGet package XML and remove all its explicit dependencies. - -This is kind of the moral equivalent of the Rails Gem "vendor freeze" I guess. - -### Delta Packages - -Now, once we've got a full package, we need to generate a Delta package. To do this, we'll replace all the DLL/EXEs in the NuGet packages with bsdiff files. [bspatch/bsdiff](http://code.logos.com/blog/2010/12/binary_patching_with_bsdiff.html) is a mostly efficient algorithm for calculating diffs between binary files (especially Native binaries, but it works well for .NET ones too), and a way to apply them. - -So, this is pretty easy: - -1. Extract the previous NuGet package -1. Extract the current NuGet package -1. Replace every EXE/DLL with the bsdiff. So, `lib\net40\MyCoolApp.exe` becomes `lib\net40\MyCoolApp.exe.diff`. Create a file that contains a SHA1 of the expected resulting file and its filesize called `lib\net40\MyCoolApp.exe.shasum` -1. New DLLs in current get put in verbatim -1. Zip it back up - -The .shasum file has the same format as the Releases file described in the "'Latest' Pointer" section, except that it will only have one entry. - -So now we've got all of the *metadata* of the original package, just none of its *contents*. To get the final package, we do the following: - -1. Take the previous version, expand it out -1. Take the delta version, do the same -1. For each DLL in the previous package, we bspatch it, then check the shasum file to ensure we created the correct resulting file -1. If we find a DLL in the new package, just copy it over -1. If we can't find a bspatch for a file, nuke it (it doesn't exist in the new rev) -1. Zip it back up - -### ChangeLogs / Release Notes - -To write release notes for each release, we're going to reuse the `` NuSpec element. However, we're going to standard that you can write Markdown in this element, and as part of generating a flattened package, we will render this Markdown as HTML. - -### "Latest" Pointer - -One of the last things we do before finishing `Create-Release` is that we write out a simple "Releases" file alongside the flattened and Delta NuGet packages. This is a text file that has the name of all of the release package filenames in the folder in release order (i.e. oldest at top, newest at bottom), along with the SHA1 hashes of their contents and their file sizes. So, something like: - -``` - 94689fede03fed7ab59c24337673a27837f0c3ec MyCoolApp-1.0.nupkg 1004502 - 3a2eadd15dd984e4559f2b4d790ec8badaeb6a39 MyCoolApp-1.1.nupkg 1040561 - 14db31d2647c6d2284882a2e101924a9c409ee67 MyCoolApp-1.1-delta.nupkg 80396 -``` - -TODO about URL shit - -This format has a number of advantages - it's dead simple, yet enables us to check for package corruption, as well as makes it efficient to determine what to do if a user gets multiple versions behind (i.e. whether it's worth it to download all of the delta packages to catch them up, or to just download the latest full package) diff --git a/specs/Installer.md b/specs/Installer.md deleted file mode 100644 index 76ab93905..000000000 --- a/specs/Installer.md +++ /dev/null @@ -1,45 +0,0 @@ -# Installer - -The installer consists of two parts: `Setup.exe` (C++ bootstrapper) and `Update.exe` (C# Squirrel Client). There are several main design goals of the installer: - -* Run as quickly as possible, with as little user interface interaction as possible. The faster we can get into the application, the better. An ideal install experience is that once `Setup.exe` gets clicked, within 3sec the application is running on the user's machine. Double-clicking `Setup.exe` should feel like clicking the app shortcut. - -* `Setup.exe` should be written such that it does as little work as possible, because C++. - -* Running an older `Setup.exe` should simply execute the current app. - -* Support installation of non-C# applications - -## Setup.exe - -Setup.exe does the following operations: - -1. Determines if the .NET Framework is installed -1. If not, relaunches itself with `/installfx45`, which opens a progress dialog which downloads the .NET Framework and silently invokes it. -1. Extract `Update.exe` and `AppName-full.nupkg` to `%LocalAppData%\Squirrel\Temp` which are embedded as resources. -1. Execute `Update.exe` with the `/install` switch, and apply any switches that were applied to Setup.exe -1. Nuke the extracted temporary files from step 3. - -## Update.exe - -Update.exe is a generic client for Squirrel which supports several operations: - -* `--install [directory] [/silent]` - Install the NuPkg file given (or any NuPkg files in the same directory as itself), and launch their applications. If `/silent` is given, don't launch anything. Copy `Update.exe` to the application root directory. Install also writes an entry in Programs and Features which will invoke `/uninstall`. -* `--uninstall` - Completely uninstall the application associated with the directory in which `Update.exe` resides. -* `--download URL` - Check for updates from the given URL and write information about available versions to standard output in JSON format. -* `--update URL` - Updates the application to the latest version from the remote URL - -## Sample JSON output - -``` -{ - currentVersion: "1.0.0.0", - futureVersion: "1.0.0.1", - releasesToApply: [ - { - version: "1.0.0.1", - releaseNotes: "This does a thing" - } - ] -} -``` diff --git a/specs/Scenarios.md b/specs/Scenarios.md deleted file mode 100644 index a124213d0..000000000 --- a/specs/Scenarios.md +++ /dev/null @@ -1,23 +0,0 @@ -## Scenarios - -#### Production - -I'm a developer with a WPF application. I have *zero* way to distribute my application at the moment. I go to NuGet and install the Squirrel client library. - -Now, I want to publish a release. To do so, I pop into the PowerShell Console and type `New-Release`. What does this do? It: - -* Creates a NuGet package of my app (i.e. via shelling out to NuGet.exe or w/e) -* It puts the package in a special "Releases" directory of my solution (along with a delta package for updates) -* It also creates a Setup.exe that I can distribute to people -* Can also transform `changelog.md` to `changelog.html` using the bundled Markdown library that ships with Squirrel - -I've created a new release. Now, I want to share it with the world! I upload the contents of my Releases directory verbatim to the web via S3 / FTP / whatever. - -In my app, I call `bool UpdateManager.CheckForUpdates("http://mycoolsite.com/releases/")` - similar to ClickOnce API but not awful. The library helps me check for updates, get the ChangeLog HTML to render, and if I'm really lazy, I can just call `UpdateManager.ShowUpdateNotification()` and get a stock WPF dialog walking the user through the upgrade. For production applications, I get the information I need to create my own update experience (yet I don't have to do any of the actual heavy lifting). - -When I call `UpdateManager.Upgrade()`, the application does the update in the background, without disturbing the user at all - the next time the app restarts, it's the new version. - - -#### Users - -I click on a link, and within seconds my application starts. No install experience, no dialogs, no UAC. diff --git a/specs/SquirrelRewriteNotes.md b/specs/SquirrelRewriteNotes.md deleted file mode 100644 index 22bde9907..000000000 --- a/specs/SquirrelRewriteNotes.md +++ /dev/null @@ -1,15 +0,0 @@ -#### What even is this? - -This is Squirrel.Windows, rewritten to drop a lot of the things that caused the original (never finished) version of Squirrel for Windows. Here's a few examples: - -* Squirrel.Windows did an enormous of work to support .NET 4.0, and brought in a ton of dependencies to make it happen. vNext requires .NET 4.5, and uses a minimum of dependencies. - -* Squirrel.Windows allowed too much setup customization via installation hooks. This feature was super hard because installation hooks often had their own dependencies that blew up when we tried to load them. vNext loses this feature. - -* Squirrel.Windows had a super complicated WiX-based installer that was an unholy nightmare. vNext replaces this with a single hardcoded C++ EXE whose goal is to display as little UI as possible. [Installer Spec](https://github.com/Squirrel/Squirrel.Windows.Next/blob/master/specs/Installer.md) - -* Squirrel.Windows was super IObservable-heavy, when the reality is that the vast majority of installer ops should just be synchronous. Ditch Rx completely and use async/await only when necessary. - -* We didn't get anything but suffering out of IO abstractions. Kill 'em all. - -* Squirrel got hella confused while walking the dependency tree by trying to detect which files in the NuGet package we were *actually* using (i.e. if you're a .NET 4.5 project, you could be using binaries from `Net20`, `Net35`, `Net45`, etc). Instead, write a Targets file which simply dumps the reference list to the output directory, and use that to inform which files should be in the final package. [Tools Spec](https://github.com/Squirrel/Squirrel.Windows.Next/blob/master/specs/Tools.md) diff --git a/specs/Tools.md b/specs/Tools.md deleted file mode 100644 index 8792ccaa7..000000000 --- a/specs/Tools.md +++ /dev/null @@ -1,19 +0,0 @@ -## Scenarios - -At the end of the day, here's how a developer will use Squirrel: - -1. Add the **Squirrel** package to your application -1. As part of the install for Squirrel, NuGet Package Build is enabled in the csproj file -1. The user edits the generated `.nuspec` to specify some details about their app -1. From the NuGet package console, run `Squirrel --releasify` - this builds the world, and you end up with a `$SolutionDir/Releases` folder that has both a Squirrel release package as well as a `Setup.exe` - -## How does this work: - -As part of adding Squirrel to your application, a `targets` file gets added to your csproj file. This targets file dumps all of the references in your application to the output directory in a simple text file, as well as a list of files marked as content. - -Calling `Squirrel --releasify` results in this process being kicked off: - -1. For the current project, build release and delta packages. -1. Create a Zip file consisting of `update.exe` and the latest full release from `Releases`. -1. Using Win32 API Abuse™, put that into `setup.exe`, a C++ bootstrapper application whose sole goal is to download .NET 4.5, install it, then run update.exe -1. Copy that to the Releases folder.