From 2f96e12e39991cf7648f3315470edbd7dc9813e3 Mon Sep 17 00:00:00 2001 From: James South Date: Thu, 4 Sep 2014 14:48:21 +0100 Subject: [PATCH 01/10] Fixing merge conflict Former-commit-id: 10badff56a72fda7f479a9946c393e8890dfdc38 --- src/ImageProcessor.Web/Properties/AssemblyInfo.cs | 2 +- src/ImageProcessor/Properties/AssemblyInfo.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs index 4f1c51a1e7..89ec3b951c 100644 --- a/src/ImageProcessor.Web/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor.Web/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. diff --git a/src/ImageProcessor/Properties/AssemblyInfo.cs b/src/ImageProcessor/Properties/AssemblyInfo.cs index c0669d12a7..0980baf3ba 100644 --- a/src/ImageProcessor/Properties/AssemblyInfo.cs +++ b/src/ImageProcessor/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -// -------------------------------------------------------------------------------------------------------------------- +// -------------------------------------------------------------------------------------------------------------------- // // Copyright (c) James South. // Licensed under the Apache License, Version 2.0. From 7aa0bc21bd48f8e72cba1c93e5937bbb84b1bd7c Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 7 Sep 2014 20:00:49 +0100 Subject: [PATCH 02/10] Merging v2 branch Former-commit-id: eb3a6a13e95738b199275b901f67b420fd5c8d46 --- build/Build.ImageProcessor.Plugins.Cair.proj | 54 +++++++++++++ build/Build.bat | 7 +- .../ImageProcessor.Plugins.Cair.nuspec | 37 +++++++++ .../ImageProcessor.Plugins.WebP.nuspec | 60 ++++++++------- .../NuSpecs/ImageProcessor.Web.Config.nuspec | 66 ++++++++-------- build/NuSpecs/ImageProcessor.Web.nuspec | 62 ++++++++------- build/NuSpecs/ImageProcessor.nuspec | 50 ++++++------ src/ImageProcessorConsole/Program.cs | 18 ++++- ...git-id => night-bridge.png.REMOVED.git-id} | 0 .../output/2006-citybus.jpg.REMOVED.git-id | 2 +- .../images/output/2008.jpg.REMOVED.git-id | 2 +- .../output/2012-citybus.jpg.REMOVED.git-id | 2 +- .../Arc-de-Triomphe-France.jpg.REMOVED.git-id | 2 +- .../output/Image with gaps.jpg.REMOVED.git-id | 2 +- ...e_triomphe_paris_france.jpg.REMOVED.git-id | 2 +- .../images/output/mountain.jpg.REMOVED.git-id | 2 +- .../images/output/rotate.jpg.REMOVED.git-id | 2 +- ...Arc_de_triomphe-square1.jpg.REMOVED.git-id | 2 +- .../images/output/test.jpg.REMOVED.git-id | 2 +- .../CairBootstrapper.cs | 47 ++++-------- .../ImageProcessor.Plugins.Cair.csproj | 3 +- .../ContentAwareResizeConvolutionType.cs | 43 ----------- .../Imaging/ContentAwareResizeLayer.cs | 66 ++++++++++------ .../Imaging/OutputType.cs | 53 +++++++++++++ .../Processors/ContentAwareResize.cs | 76 +++++++------------ .../Resources/Unmanaged/x86/Usage.txt | 41 ++++++++++ 26 files changed, 436 insertions(+), 267 deletions(-) create mode 100644 build/Build.ImageProcessor.Plugins.Cair.proj create mode 100644 build/NuSpecs/ImageProcessor.Plugins.Cair.nuspec rename src/ImageProcessorConsole/images/input/{night-bridge.jpg.REMOVED.git-id => night-bridge.png.REMOVED.git-id} (100%) delete mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeConvolutionType.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/OutputType.cs create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/Usage.txt diff --git a/build/Build.ImageProcessor.Plugins.Cair.proj b/build/Build.ImageProcessor.Plugins.Cair.proj new file mode 100644 index 0000000000..d4668467da --- /dev/null +++ b/build/Build.ImageProcessor.Plugins.Cair.proj @@ -0,0 +1,54 @@ + + + .\ + + + + + + + + Release + _BuildOutput\ + False + $(MSBuildProjectDirectory)\$(BuildFolder) + $(BuildFolderAbsolutePath)ImageProcessor.Plugins.Cair\lib\net45 + ..\src\Plugins\ImageProcessor\ImageProcessor.Plugins.Cair\ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/build/Build.bat b/build/Build.bat index f5ec6373b6..deb60032ff 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -4,8 +4,11 @@ SET version=2.0.1.0 SET webversion=4.0.0.0 SET webconfigversion=2.0.0.0 SET webppluginversion=1.0.1.0 +SET cairpluginversion=1.0.0.0 -ECHO Building ImageProcessor %version%, ImageProcessor.Web %webversion%, ImageProcessor.Web.Config %webconfigversion%, and ImageProcessor.Plugins.WebP %webppluginversion% +ECHO Building ImageProcessor %version%, ImageProcessor.Web %webversion%, ImageProcessor.Web.Config %webconfigversion% + +ECHO Building ImageProcessor.Plugins.WebP %webppluginversion%, ImageProcessor.Plugins.Cair %cairpluginversion% ECHO Removing _BuildOutput directory so everything is nice and clean RD _BuildOutput /q /s @@ -13,12 +16,14 @@ RD _BuildOutput /q /s %windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.ImageProcessor.proj" /p:BUILD_RELEASE=%version% /p:BUILD_COMMENT=%comment% %windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.ImageProcessor.Web.proj" /p:BUILD_RELEASE=%webversion% /p:BUILD_COMMENT=%comment% %windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.ImageProcessor.Plugins.WebP.proj" /p:BUILD_RELEASE=%webppluginversion% /p:BUILD_COMMENT=%comment% +%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.ImageProcessor.Plugins.Cair.proj" /p:BUILD_RELEASE=%cairpluginversion% /p:BUILD_COMMENT=%comment% ECHO Packing the NuGet release files ..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.nuspec -Version %version% ..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Web.nuspec -Version %webversion% ..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Web.Config.nuspec -Version %webconfigversion% ..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Plugins.WebP.nuspec -Version %webppluginversion% +..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Plugins.Cair.nuspec -Version %cairpluginversion% PAUSE IF ERRORLEVEL 1 GOTO :showerror diff --git a/build/NuSpecs/ImageProcessor.Plugins.Cair.nuspec b/build/NuSpecs/ImageProcessor.Plugins.Cair.nuspec new file mode 100644 index 0000000000..3560ec1544 --- /dev/null +++ b/build/NuSpecs/ImageProcessor.Plugins.Cair.nuspec @@ -0,0 +1,37 @@ + + + + ImageProcessor.Plugins.Cair + 1.0.0.0 + ImageProcessor.Plugins.Cair + James South + James South + http://imageprocessor.org + http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png + false + + Adds support to ImageProcessor for Content Aware Image Resizing. + + If you use ImageProcessor please get in touch via my twitter @james_m_south + + Feedback is always welcome + + Adds support to ImageProcessor for Content Aware Image Resizing. + + James South + en-GB + + Image Imaging ASP Performance Processing HttpModule Cache Resize AutoRotate Rotate RoundedCorners + Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg + Bitmap Png WebP Tiff Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF Cair SeamCarving + + + + + + + + + + + diff --git a/build/NuSpecs/ImageProcessor.Plugins.WebP.nuspec b/build/NuSpecs/ImageProcessor.Plugins.WebP.nuspec index 2b73746c52..98826898d2 100644 --- a/build/NuSpecs/ImageProcessor.Plugins.WebP.nuspec +++ b/build/NuSpecs/ImageProcessor.Plugins.WebP.nuspec @@ -1,32 +1,38 @@  - - ImageProcessor.Plugins.WebP - 1.0.0.0 - ImageProcessor.Plugins.WebP - James South - James South - http://imageprocessor.org - http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png - false - Adds support to ImageProcessor for the WebP image format. + + ImageProcessor.Plugins.WebP + 1.0.0.0 + ImageProcessor.Plugins.WebP + James South + James South + http://imageprocessor.org + http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png + false + + Adds support to ImageProcessor for the WebP image format. -If you use ImageProcessor please get in touch via my twitter @james_m_south + If you use ImageProcessor please get in touch via my twitter @james_m_south -Feedback is always welcome - Adds support to ImageProcessor for the WebP image format. - - James South - en-GB - Image Imaging ASP Performance Processing HttpModule Cache Resize Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png WebP Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated - - - - - - - - - - + Feedback is always welcome + + Adds support to ImageProcessor for the WebP image format. + + James South + en-GB + + Image Imaging ASP Performance Processing HttpModule Cache Resize AutoRotate Rotate RoundedCorners + Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg + Bitmap Png WebP Tiff Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF Cair SeamCarving + + + + + + + + + + + diff --git a/build/NuSpecs/ImageProcessor.Web.Config.nuspec b/build/NuSpecs/ImageProcessor.Web.Config.nuspec index 45786ebd55..0b66945dfd 100644 --- a/build/NuSpecs/ImageProcessor.Web.Config.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.Config.nuspec @@ -1,35 +1,41 @@ - - ImageProcessor.Web.Config - 1.1.0.0 - ImageProcessor.Web.Config - James South - James South - http://imageprocessor.org - http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png - false - Adds configuration to your ImageProcessor.Web solution to allow you to override the default settings. + + ImageProcessor.Web.Config + 1.1.0.0 + ImageProcessor.Web.Config + James South + James South + http://imageprocessor.org + http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png + false + + Adds configuration to your ImageProcessor.Web solution to allow you to override the default settings. -If you use ImageProcessor please get in touch via my twitter @james_m_south + If you use ImageProcessor please get in touch via my twitter @james_m_south -Feedback is always welcome - ImageProcessor.Web configuration settings for ASP.NET websites. - - James South - en-GB - Image Imaging ASP Performance Processing HttpModule Cache Resize Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png WebP Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated - - - - - - - - - - - - - + Feedback is always welcome + + ImageProcessor.Web configuration settings for ASP.NET websites. + + James South + en-GB + + Image Imaging ASP Performance Processing HttpModule Cache Resize AutoRotate Rotate RoundedCorners + Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg + Bitmap Png WebP Tiff Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF Cair SeamCarving + + + + + + + + + + + + + + diff --git a/build/NuSpecs/ImageProcessor.Web.nuspec b/build/NuSpecs/ImageProcessor.Web.nuspec index 9f765206e3..ddcc68c942 100644 --- a/build/NuSpecs/ImageProcessor.Web.nuspec +++ b/build/NuSpecs/ImageProcessor.Web.nuspec @@ -1,34 +1,40 @@ - - ImageProcessor.Web - 3.2.0.0 - ImageProcessor.Web - James South - James South - http://imageprocessor.org - http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png - false - ImageProcessor.Web adds a configurable HttpModule to your website which allows on-the-fly processing of image files. The module also comes with a file and browser based cache that can handle millions of images, increasing your processing output and saving precious server memory. + + ImageProcessor.Web + 3.2.0.0 + ImageProcessor.Web + James South + James South + http://imageprocessor.org + http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png + false + + ImageProcessor.Web adds a configurable HttpModule to your website which allows on-the-fly processing of image files. The module also comes with a file and browser based cache that can handle millions of images, increasing your processing output and saving precious server memory. -Methods include: Resize, Rotate, Rounded Corners, Flip, Crop, Watermark, Filter, Saturation, Brightness, Contrast, Quality, Format, Vignette, Gaussian Blur, Gaussian Sharpen, and Transparency. + Methods include: Resize, Rotate, Rounded Corners, Flip, Crop, Watermark, Filter, Saturation, Brightness, Contrast, Quality, Format, Vignette, Gaussian Blur, Gaussian Sharpen, and Transparency. -If you use ImageProcessor please get in touch via my twitter @james_m_south + If you use ImageProcessor please get in touch via my twitter @james_m_south -Feedback is always welcome - An extension to ImageProcessor that allows on-the-fly processing of image files in an ASP.NET website - - James South - en-GB - Image Imaging ASP Performance Processing HttpModule Cache Resize AutoRotate Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png WebP Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF - - - - - - - - - - + Feedback is always welcome + + An extension to ImageProcessor that allows on-the-fly processing of image files in an ASP.NET website + + James South + en-GB + + Image Imaging ASP Performance Processing HttpModule Cache Resize AutoRotate Rotate RoundedCorners + Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg + Bitmap Png WebP Tiff Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF Cair SeamCarving + + + + + + + + + + + diff --git a/build/NuSpecs/ImageProcessor.nuspec b/build/NuSpecs/ImageProcessor.nuspec index 2b9c8af53b..2e5f84fdfa 100644 --- a/build/NuSpecs/ImageProcessor.nuspec +++ b/build/NuSpecs/ImageProcessor.nuspec @@ -1,28 +1,34 @@  - - ImageProcessor - 1.9.0.0 - ImageProcessor - James South - James South - http://imageprocessor.org - http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png - false - Image Processor is an easy to use and extend processing library written in C#. Its fluent API makes common imaging tasks very simple to perform. + + ImageProcessor + 1.9.0.0 + ImageProcessor + James South + James South + http://imageprocessor.org + http://raw.githubusercontent.com/JimBobSquarePants/ImageProcessor/master/build/content/imageprocessor.128.png + false + + Image Processor is an easy to use and extend processing library written in C#. Its fluent API makes common imaging tasks very simple to perform. -Methods include; Resize, Rotate, Rounded Corners, Flip, Crop, Watermark, Filter, Saturation, Brightness, Contrast, Quality, Format, Vignette, Gaussian Blur, Gaussian Sharpen, and Transparency. + Methods include; Resize, Rotate, Rounded Corners, Flip, Crop, Watermark, Filter, Saturation, Brightness, Contrast, Quality, Format, Vignette, Gaussian Blur, Gaussian Sharpen, and Transparency. -If you use ImageProcessor please get in touch on my twitter @james_m_south. + If you use ImageProcessor please get in touch on my twitter @james_m_south. -Feedback is always welcome. - A library for manipulating image files written in C#. - - James South - en-GB - Image Imaging ASP Performance Processing Resize AutoRotate Rotate RoundedCorners Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg Bitmap Png WebP Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF - - - - + Feedback is always welcome. + + A library for manipulating image files written in C#. + + James South + en-GB + + Image Imaging ASP Performance Processing HttpModule Cache Resize AutoRotate Rotate RoundedCorners + Flip Crop Filter Effects Quality Watermark Alpha Vignette Saturation Brightness Contrast Gif Jpg Jpeg + Bitmap Png WebP Tiff Fluent GDI Gaussian Blur Sharpen Tint Quantizer Animated EXIF Cair SeamCarving + + + + + diff --git a/src/ImageProcessorConsole/Program.cs b/src/ImageProcessorConsole/Program.cs index 6293a3edce..f7658b7d1f 100644 --- a/src/ImageProcessorConsole/Program.cs +++ b/src/ImageProcessorConsole/Program.cs @@ -12,11 +12,13 @@ namespace ImageProcessorConsole { using System; using System.Collections.Generic; + using System.Diagnostics; using System.Drawing; using System.IO; using System.Linq; using ImageProcessor; using ImageProcessor.Plugins.Cair; + using ImageProcessor.Plugins.Cair.Imaging; /// /// The program. @@ -48,6 +50,11 @@ namespace ImageProcessorConsole { byte[] photoBytes = File.ReadAllBytes(fileInfo.FullName); + Console.WriteLine("Processing: " + fileInfo.Name); + + Stopwatch stopwatch = new Stopwatch(); + stopwatch.Start(); + // ImageProcessor using (MemoryStream inStream = new MemoryStream(photoBytes)) { @@ -55,15 +62,24 @@ namespace ImageProcessorConsole { Size size = new Size(800, 0); + ContentAwareResizeLayer layer = new ContentAwareResizeLayer(size) + { + ConvolutionType = ConvolutionType.Sobel + }; + // Load, resize, set the format and quality and save an image. imageFactory.Load(inStream) //.BackgroundColor(Color.White) //.Resize(new Size((int)(size.Width * 1.1), 0)) - .ContentAwareResize(size) + .ContentAwareResize(layer) //.Constrain(size) .Save(Path.GetFullPath(Path.Combine(Path.GetDirectoryName(path), @"..\..\images\output", fileInfo.Name))); + + stopwatch.Stop(); } } + + Console.WriteLine("Processed: " + fileInfo.Name + " in " + stopwatch.ElapsedMilliseconds + "ms"); } } diff --git a/src/ImageProcessorConsole/images/input/night-bridge.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/input/night-bridge.png.REMOVED.git-id similarity index 100% rename from src/ImageProcessorConsole/images/input/night-bridge.jpg.REMOVED.git-id rename to src/ImageProcessorConsole/images/input/night-bridge.png.REMOVED.git-id diff --git a/src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id index 5fe88ad754..233b2595f7 100644 --- a/src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/2006-citybus.jpg.REMOVED.git-id @@ -1 +1 @@ -33f7e25da5675197f18bb2fa2c9fe5fa366e84ec \ No newline at end of file +c6cb11afaf9fdb9181772246e5c873d8f7d1b99c \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id index fcb030451d..01ba573540 100644 --- a/src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/2008.jpg.REMOVED.git-id @@ -1 +1 @@ -f24f17627804b11d823240d49c91ec17fb7fd55d \ No newline at end of file +10b48cac44776a023df7585ba2c68c3f51b0f803 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id index 3ade52d600..731a81b1ac 100644 --- a/src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/2012-citybus.jpg.REMOVED.git-id @@ -1 +1 @@ -def19dd7469cf2eba1f595e7263d9d48fda85825 \ No newline at end of file +e631eb3491496bb83f99cd41a752f79c9d7f6830 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id index 83ecfe0323..437ecbc461 100644 --- a/src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/Arc-de-Triomphe-France.jpg.REMOVED.git-id @@ -1 +1 @@ -8cf61b55acca1a3d1a69177ddc439685ee0ba192 \ No newline at end of file +782056919992bb7e453eeee5d9c0034e03b57506 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id index 7ea6903419..99c38fa2f1 100644 --- a/src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/Image with gaps.jpg.REMOVED.git-id @@ -1 +1 @@ -629284a6f834f5d1cf185e3603a50c484dd9121a \ No newline at end of file +1d9ded0201edcd248140b4ec02f69ccdb4b539e5 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id index e3f15eac73..b55932abb8 100644 --- a/src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/arc_de_triomphe_paris_france.jpg.REMOVED.git-id @@ -1 +1 @@ -3d652e0628f2042e7aca0751384ba21f1182ef5f \ No newline at end of file +2880457cc09cd2897b5f9f377807ec22f8f83013 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id index 05e668428c..aba0ec52f1 100644 --- a/src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/mountain.jpg.REMOVED.git-id @@ -1 +1 @@ -1c48519b2675b9dd90e8e95d6421148b25b8c317 \ No newline at end of file +34dcced6c7c3e4dd6fae239eba8eddef6234028d \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/rotate.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/rotate.jpg.REMOVED.git-id index 5ebfcd78d6..ec3d83b76b 100644 --- a/src/ImageProcessorConsole/images/output/rotate.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/rotate.jpg.REMOVED.git-id @@ -1 +1 @@ -a0aa8338f74f3539c2531f43fa9027a3ce0a39fb \ No newline at end of file +de6754762f7705f9109ea364f42ca128e454e853 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id index 6f31ad7d11..481fa6aaad 100644 --- a/src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/shutterstock_19173982_Arc_de_triomphe-square1.jpg.REMOVED.git-id @@ -1 +1 @@ -04f6093d3345a4c8b48333c32972753dd0949730 \ No newline at end of file +24db72130626e81b9a4262c891dd28e6d97e5a96 \ No newline at end of file diff --git a/src/ImageProcessorConsole/images/output/test.jpg.REMOVED.git-id b/src/ImageProcessorConsole/images/output/test.jpg.REMOVED.git-id index 8f920f20c2..65ec37fb75 100644 --- a/src/ImageProcessorConsole/images/output/test.jpg.REMOVED.git-id +++ b/src/ImageProcessorConsole/images/output/test.jpg.REMOVED.git-id @@ -1 +1 @@ -f7b1543810ada7598773d6ee31bc7c0c20afaa9f \ No newline at end of file +4885438f0b97e3aae59d6e214b5ec455358ae225 \ No newline at end of file diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/CairBootstrapper.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/CairBootstrapper.cs index 60a9eb0ce6..2baf4fa70f 100644 --- a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/CairBootstrapper.cs +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/CairBootstrapper.cs @@ -32,12 +32,12 @@ namespace ImageProcessor.Plugins.Cair /// /// Gets the cair path. /// - public static string CairPath { get; private set; } + public static string CairExecutablePath { get; private set; } /// - /// Gets the cair image path. + /// Gets the cair base path. /// - public static string CairImagePath { get; private set; } + public static string CairPath { get; private set; } /// /// Registers the embedded CAIR executable. @@ -47,12 +47,17 @@ namespace ImageProcessor.Plugins.Cair // None of the tools used here are called using dllimport so we don't go through the normal registration channel. string folder = ImageProcessorBootstrapper.Instance.NativeBinaryFactory.Is64BitEnvironment ? "x64" : "x86"; Assembly assembly = Assembly.GetExecutingAssembly(); - string targetBasePath = new Uri(assembly.Location).LocalPath; - string multithreaderTargetPath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + "pthreadVSE2.dll")); + CairPath = Path.GetFullPath(Path.Combine(new Uri(assembly.Location).LocalPath, "..\\" + folder + "\\imageprocessor.cair\\")); + CairExecutablePath = Path.Combine(CairPath, "CAIR.exe"); + string multithreaderTargetPath = Path.Combine(CairPath, "pthreadVSE2.dll"); - // Set the global variable. - CairPath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + "CAIR.exe")); - CairImagePath = Path.GetFullPath(Path.Combine(targetBasePath, "..\\" + folder + "\\" + "cairimages\\")); + // Create the folder for storing temporary images. + // ReSharper disable once AssignNullToNotNullAttribute + DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(CairPath)); + if (!directoryInfo.Exists) + { + directoryInfo.Create(); + } // Get the resources and copy them across. const string CairResourcePath = "ImageProcessor.Plugins.Cair.Resources.Unmanaged.x86.CAIR.exe"; @@ -64,13 +69,6 @@ namespace ImageProcessor.Plugins.Cair { if (resourceStream != null) { - // ReSharper disable once AssignNullToNotNullAttribute - DirectoryInfo threaderDirectoryInfo = new DirectoryInfo(Path.GetDirectoryName(multithreaderTargetPath)); - if (!threaderDirectoryInfo.Exists) - { - threaderDirectoryInfo.Create(); - } - using (FileStream fileStream = File.OpenWrite(multithreaderTargetPath)) { resourceStream.CopyTo(fileStream); @@ -83,27 +81,12 @@ namespace ImageProcessor.Plugins.Cair { if (resourceStream != null) { - // ReSharper disable once AssignNullToNotNullAttribute - DirectoryInfo cairDirectoryInfo = new DirectoryInfo(Path.GetDirectoryName(CairPath)); - if (!cairDirectoryInfo.Exists) - { - cairDirectoryInfo.Create(); - } - - using (FileStream fileStream = File.OpenWrite(CairPath)) + using (FileStream fileStream = File.OpenWrite(CairExecutablePath)) { resourceStream.CopyTo(fileStream); } } } - - // Lastly create the image folder for storing temporary images. - // ReSharper disable once AssignNullToNotNullAttribute - DirectoryInfo directoryInfo = new DirectoryInfo(Path.GetDirectoryName(CairImagePath)); - if (!directoryInfo.Exists) - { - directoryInfo.Create(); - } } } -} +} \ No newline at end of file diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj index 75ba8715e6..45c0d70a3d 100644 --- a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/ImageProcessor.Plugins.Cair.csproj @@ -45,9 +45,10 @@ - + + diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeConvolutionType.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeConvolutionType.cs deleted file mode 100644 index 143b0fd3cf..0000000000 --- a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeConvolutionType.cs +++ /dev/null @@ -1,43 +0,0 @@ -// -------------------------------------------------------------------------------------------------------------------- -// -// Copyright (c) James South. -// Licensed under the Apache License, Version 2.0. -// -// -// Provides enumeration of the content aware resize convolution types. -// -// -------------------------------------------------------------------------------------------------------------------- - -namespace ImageProcessor.Plugins.Cair.Imaging -{ - /// - /// Provides enumeration of the content aware resize convolution types. - /// - public enum ContentAwareResizeConvolutionType - { - /// - /// The Prewitt kernel convolution type. - /// - Prewitt = 0, - - /// - /// The V1 kernel convolution type. - /// - V1 = 1, - - /// - /// The VSquare kernel convolution type. - /// - VSquare = 2, - - /// - /// The Sobel kernel convolution type. - /// - Sobel = 3, - - /// - /// The Laplacian kernel convolution type. - /// - Laplacian = 4 - } -} \ No newline at end of file diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs index d81b299072..c8b5dc02fe 100644 --- a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ContentAwareResizeLayer.cs @@ -20,7 +20,7 @@ namespace ImageProcessor.Plugins.Cair.Imaging /// /// The convolution type to apply to the layer. /// - private ContentAwareResizeConvolutionType convolutionType = ContentAwareResizeConvolutionType.Prewitt; + private ConvolutionType convolutionType = ConvolutionType.Prewitt; /// /// The energy function to apply to the layer. @@ -28,14 +28,14 @@ namespace ImageProcessor.Plugins.Cair.Imaging private EnergyFunction energyFunction = EnergyFunction.Forward; /// - /// Whether to assign multiple threads to the resizing method. + /// The expected output type. /// - private bool parallelize = true; + private OutputType outputType = OutputType.Cair; /// - /// Whether to pre-scale the image to reduce errors in the output. + /// Whether to assign multiple threads to the resizing method. /// - private bool prescale = true; + private bool parallelize = true; /// /// The timeout in milliseconds to attempt to resize for. @@ -53,15 +53,10 @@ namespace ImageProcessor.Plugins.Cair.Imaging this.Size = size; } - /// - /// Gets or sets the size. - /// - public Size Size { get; set; } - /// /// Gets or sets the content aware resize convolution type (Default ContentAwareResizeConvolutionType.Prewitt). /// - public ContentAwareResizeConvolutionType ConvolutionType + public ConvolutionType ConvolutionType { get { @@ -91,36 +86,52 @@ namespace ImageProcessor.Plugins.Cair.Imaging } /// - /// Gets or sets a value indicating whether to assign multiple threads to the resizing method. - /// (Default true) + /// Gets or sets the expected output type. /// - public bool Parallelize + public OutputType OutputType { get { - return this.parallelize; + return this.outputType; } set { - this.parallelize = value; + this.outputType = value; } } /// - /// Gets or sets a value indicating whether to pre-scale the image to reduce errors in the output. + /// Gets or sets the size. + /// + public Size Size { get; set; } + + /// + /// Gets or sets the the file path to a bitmap file that provides weight indicators specified using + /// color to guide preservation of image portions during carving. + /// + /// The following colors define weight guidance. + /// - Protect the weight. + /// - Remove the weight. + /// - No weight. + /// + /// + public string WeightPath { get; set; } + + /// + /// Gets or sets a value indicating whether to assign multiple threads to the resizing method. /// (Default true) /// - public bool PreScale + public bool Parallelize { get { - return this.prescale; + return this.parallelize; } set { - this.prescale = value; + this.parallelize = value; } } @@ -162,7 +173,12 @@ namespace ImageProcessor.Plugins.Cair.Imaging } return this.Size == resizeLayer.Size - && this.ConvolutionType == resizeLayer.ConvolutionType; + && this.ConvolutionType == resizeLayer.ConvolutionType + && this.EnergyFunction == resizeLayer.EnergyFunction + && this.OutputType == resizeLayer.OutputType + && this.Parallelize == resizeLayer.Parallelize + && this.Timeout == resizeLayer.Timeout + && this.WeightPath == resizeLayer.WeightPath; } /// @@ -173,7 +189,13 @@ namespace ImageProcessor.Plugins.Cair.Imaging /// public override int GetHashCode() { - return this.Size.GetHashCode() + this.ConvolutionType.GetHashCode(); + return this.Size.GetHashCode() + + this.ConvolutionType.GetHashCode() + + this.EnergyFunction.GetHashCode() + + this.OutputType.GetHashCode() + + this.Parallelize.GetHashCode() + + this.Timeout.GetHashCode() + + this.WeightPath.GetHashCode(); } } } diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/OutputType.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/OutputType.cs new file mode 100644 index 0000000000..168776c6f6 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/OutputType.cs @@ -0,0 +1,53 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Enumerates the output type to produce. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Plugins.Cair.Imaging +{ + /// + /// Enumerates the output type to produce. + /// + public enum OutputType + { + /// + /// Output the result as a carved image. The default action. + /// + Cair = 0, + + /// + /// Output the result as a greyscale image. + /// + Grayscale = 1, + + /// + /// Output the result highlighting the detected edges. + /// + Edge = 2, + + /// + /// Output the result highlighting the vertical energy patterns. + /// + VerticalEnergy = 3, + + /// + /// Output the result highlighting the vertical energy patterns. + /// + HorizontalEnergy = 4, + + /// + /// Appears to do nothing. + /// + Removal = 5, + + /// + /// Output the result as a carved image with the focus on high quality output over speed. + /// + CairHighDefinition = 6 + } +} diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Processors/ContentAwareResize.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Processors/ContentAwareResize.cs index c85f5b6608..aca83388be 100644 --- a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Processors/ContentAwareResize.cs +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Processors/ContentAwareResize.cs @@ -19,7 +19,6 @@ namespace ImageProcessor.Plugins.Cair.Processors using System.IO; using ImageProcessor.Common.Exceptions; - using ImageProcessor.Imaging; using ImageProcessor.Plugins.Cair.Imaging; using ImageProcessor.Processors; @@ -69,17 +68,14 @@ namespace ImageProcessor.Plugins.Cair.Processors string fileName = Guid.NewGuid().ToString(); // Use bmp's as the temporary files since they are lossless and support transparency. - string sourcePath = Path.Combine(CairBootstrapper.CairImagePath, fileName + ".bmp"); - string resizedPath = Path.Combine(CairBootstrapper.CairImagePath, fileName + "-r.bmp"); + string sourcePath = Path.Combine(CairBootstrapper.CairPath, fileName + ".bmp"); + string resizedPath = Path.Combine(CairBootstrapper.CairPath, fileName + "-r.bmp"); // Gather the parameters. - int width = this.DynamicParameter.Size.Width ?? 0; - int height = this.DynamicParameter.Size.Height ?? 0; - ContentAwareResizeConvolutionType convolutionType = this.DynamicParameter.ConvolutionType; - EnergyFunction energyFunction = this.DynamicParameter.EnergyFunction; - bool prescale = this.DynamicParameter.PreScale; - bool parallelize = this.DynamicParameter.Parallelize; - int timeout = this.DynamicParameter.Timeout ?? 60000; + ContentAwareResizeLayer layer = (ContentAwareResizeLayer)this.DynamicParameter; + int width = layer.Size.Width; + int height = layer.Size.Height; + int timeout = layer.Timeout > 0 ? layer.Timeout : 60000; int defaultMaxWidth; int defaultMaxHeight; @@ -115,48 +111,28 @@ namespace ImageProcessor.Plugins.Cair.Processors if (width > 0 && height > 0 && width <= maxWidth && height <= maxHeight) { - if (prescale) - { - if (width < image.Width || height < image.Height) - { - int preWidth = Math.Min(image.Width, width + 50); //(int)Math.Ceiling(width * 1.25)); - ResizeLayer layer = new ResizeLayer(new Size(preWidth, 0)); - Dictionary resizeSettings = new Dictionary - { - { - "MaxWidth", image.Width.ToString("G") - }, - { - "MaxHeight", image.Height.ToString("G") - } - }; - Resize resize = new Resize { DynamicParameter = layer, Settings = resizeSettings }; - image = resize.ProcessImage(factory); - } - } - // Save the temporary bitmap. image.Save(sourcePath, ImageFormat.Bmp); // Process the image using the CAIR executable. string arguments = string.Format( - " -I \"{0}\" -O \"{1}\" -C {2} -X {3} -Y {4} -E {5} -T {6}", + " -I \"{0}\" -O \"{1}\" -C {2} -X {3} -Y {4} -E {5} -T {6} -R {7}", sourcePath, resizedPath, - (int)convolutionType, + (int)layer.ConvolutionType, width, height, - (int)energyFunction, - parallelize ? Math.Min(4, Environment.ProcessorCount) : 1); - - bool success = this.ProcessCairImage(arguments, timeout); + (int)layer.EnergyFunction, + layer.Parallelize ? Math.Min(4, Environment.ProcessorCount) : 1, + (int)layer.OutputType); - if (!success) + if (!string.IsNullOrWhiteSpace(layer.WeightPath)) { - throw new ImageProcessingException( - "Error processing image with " + this.GetType().Name + " due to timeout."); + arguments = string.Format("{0} -W {1}", arguments, layer.WeightPath); } + this.ProcessCairImage(arguments, timeout); + // Assign the new image. newImage = new Bitmap(resizedPath); newImage.MakeTransparent(); @@ -202,13 +178,10 @@ namespace ImageProcessor.Plugins.Cair.Processors /// /// The time in milliseconds to attempt to resize the image for. /// - /// - /// The . - /// - private bool ProcessCairImage(string arguments, int timeout) + private void ProcessCairImage(string arguments, int timeout) { // Set up and start a new process to resize the image. - ProcessStartInfo start = new ProcessStartInfo(CairBootstrapper.CairPath, arguments) + ProcessStartInfo start = new ProcessStartInfo(CairBootstrapper.CairExecutablePath, arguments) { WindowStyle = ProcessWindowStyle.Hidden, UseShellExecute = false, @@ -222,18 +195,21 @@ namespace ImageProcessor.Plugins.Cair.Processors { if (process != null) { - bool result = process.WaitForExit(timeout); - - if (!result) + if (!process.WaitForExit(timeout)) { process.Kill(); + + throw new ImageProcessingException("Error processing image with " + this.GetType().Name + " due to timeout."); } - return result; + string output = string.Format(" {0} {1}", process.StandardError.ReadToEnd(), process.StandardOutput.ReadToEnd()); + + if (process.ExitCode != 0) + { + throw new ImageProcessingException("Error processing image with " + this.GetType().Name + output); + } } } - - return false; } } } diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/Usage.txt b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/Usage.txt new file mode 100644 index 0000000000..a6b19bcef8 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Resources/Unmanaged/x86/Usage.txt @@ -0,0 +1,41 @@ +CAIR CLI Usage: + +cair -I + +Other options: + -O + Default: Dependent on operation + -W + Bitmap with: Black- no weight + Green- Protect weight + Red- Remove weight + Default: Weights are all zero + -S + Default: 100,000 + -X + Default: Source image width + -Y + Default: Source image height + -R + CAIR: 0 + Grayscale: 1 + Edge: 2 + Vertical Energy: 3 + Horizontal Energy: 4 + Removal: 5 + CAIR_HD: 6 + Default: CAIR + -C + Prewitt: 0 + V1: 1 + V_SQUARE: 2 + Sobel: 3 + Laplacian: 4 + Default: Prewitt + + -E + Backward: 0 + Forward: 1 + Default: Backward + -T + Default : CAIR_NUM_THREADS (4) From b796817ffc10b8d8c73b2748331c8a91c2d4a75f Mon Sep 17 00:00:00 2001 From: James South Date: Sun, 7 Sep 2014 20:34:04 +0100 Subject: [PATCH 03/10] Adding convolution type file Former-commit-id: 85e965b874fbc702157da8348cc2cec4d973d3b5 --- .../Imaging/ConvolutionType.cs | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ConvolutionType.cs diff --git a/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ConvolutionType.cs b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ConvolutionType.cs new file mode 100644 index 0000000000..b9e0aa26a6 --- /dev/null +++ b/src/Plugins/ImageProcessor/ImageProcessor.Plugins.Cair/Imaging/ConvolutionType.cs @@ -0,0 +1,43 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) James South. +// Licensed under the Apache License, Version 2.0. +// +// +// Provides enumeration of the content aware resize convolution types. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace ImageProcessor.Plugins.Cair.Imaging +{ + /// + /// Provides enumeration of the content aware resize convolution types. + /// + public enum ConvolutionType + { + /// + /// The Prewitt kernel convolution type. + /// + Prewitt = 0, + + /// + /// The V1 kernel convolution type. + /// + V1 = 1, + + /// + /// The VSquare kernel convolution type. + /// + VSquare = 2, + + /// + /// The Sobel kernel convolution type. + /// + Sobel = 3, + + /// + /// The Laplacian kernel convolution type. + /// + Laplacian = 4 + } +} \ No newline at end of file From 9826fe1e9ab91b689187db98690a0689bd82acca Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 19 Sep 2014 11:25:35 +0200 Subject: [PATCH 04/10] Replaces the old-school batch file with a shiny new PSake build script Former-commit-id: 1fa7d934e56afe551654425637151a8f1b19bc5f --- build/Build.bat | 35 +- build/build.ps1 | 55 +++ build/psake.psm1 | 847 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 904 insertions(+), 33 deletions(-) create mode 100644 build/build.ps1 create mode 100644 build/psake.psm1 diff --git a/build/Build.bat b/build/Build.bat index deb60032ff..9fbd8906f5 100644 --- a/build/Build.bat +++ b/build/Build.bat @@ -1,34 +1,3 @@ -@ECHO OFF +@echo off -SET version=2.0.1.0 -SET webversion=4.0.0.0 -SET webconfigversion=2.0.0.0 -SET webppluginversion=1.0.1.0 -SET cairpluginversion=1.0.0.0 - -ECHO Building ImageProcessor %version%, ImageProcessor.Web %webversion%, ImageProcessor.Web.Config %webconfigversion% - -ECHO Building ImageProcessor.Plugins.WebP %webppluginversion%, ImageProcessor.Plugins.Cair %cairpluginversion% - -ECHO Removing _BuildOutput directory so everything is nice and clean -RD _BuildOutput /q /s - -%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.ImageProcessor.proj" /p:BUILD_RELEASE=%version% /p:BUILD_COMMENT=%comment% -%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.ImageProcessor.Web.proj" /p:BUILD_RELEASE=%webversion% /p:BUILD_COMMENT=%comment% -%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.ImageProcessor.Plugins.WebP.proj" /p:BUILD_RELEASE=%webppluginversion% /p:BUILD_COMMENT=%comment% -%windir%\Microsoft.NET\Framework\v4.0.30319\msbuild.exe "Build.ImageProcessor.Plugins.Cair.proj" /p:BUILD_RELEASE=%cairpluginversion% /p:BUILD_COMMENT=%comment% - -ECHO Packing the NuGet release files -..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.nuspec -Version %version% -..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Web.nuspec -Version %webversion% -..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Web.Config.nuspec -Version %webconfigversion% -..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Plugins.WebP.nuspec -Version %webppluginversion% -..\src\.nuget\NuGet.exe pack NuSpecs\ImageProcessor.Plugins.Cair.nuspec -Version %cairpluginversion% -PAUSE - -IF ERRORLEVEL 1 GOTO :showerror - -GOTO :EOF - -:showerror -PAUSE +powershell "Import-Module %~dp0\psake.psm1 ; Invoke-Psake %~dp0\build.ps1 ; exit $LASTEXITCODE" \ No newline at end of file diff --git a/build/build.ps1 b/build/build.ps1 new file mode 100644 index 0000000000..ff0c251926 --- /dev/null +++ b/build/build.ps1 @@ -0,0 +1,55 @@ +Properties { + $version = "2.0.1.0" + $webversion = "4.0.0.0" + $webconfigversion = "2.0.0.0" + $webppluginversion = "1.0.1.0" + $cairpluginversion = "1.0.0.0" + + $PROJ_PATH = "." + $BIN_PATH = (Join-Path $PROJ_PATH "_BuildOutput") + $NUGET_EXE = "..\src\.nuget\NuGet.exe" + $NUSPECS_PATH = (Join-Path $PROJ_PATH "NuSpecs") + $NUGET_OUTPUT = (Join-Path $BIN_PATH "NuGets") + # TODO: add opencover and nunit runner binaries +} + +Framework "4.0x86" +FormatTaskName "-------- {0} --------" + +task default -depends Cleanup-Binaries, Build-Solution, Generate-Package + +# cleans up the binaries output folder +task Cleanup-Binaries { + Write-Host "Removing $BIN_PATH directory so everything is nice and clean" + if (Test-Path $BIN_PATH) { + Remove-Item $BIN_PATH -Force -Recurse + } +} + +# builds the solutions +task Build-Solution -depends Cleanup-Binaries { + Write-Host "Building projects" + Exec { + msbuild (Join-Path $PROJ_PATH "Build.ImageProcessor.proj") /p:BUILD_RELEASE="$version" + msbuild (Join-Path $PROJ_PATH "Build.ImageProcessor.Web.proj") /p:BUILD_RELEASE="$version" + msbuild (Join-Path $PROJ_PATH "Build.ImageProcessor.Plugins.WebP.proj") /p:BUILD_RELEASE="$version" + msbuild (Join-Path $PROJ_PATH "Build.ImageProcessor.Plugins.Cair.proj") /p:BUILD_RELEASE="$version" + } +} + +# generates a Nuget package +task Generate-Package -depends Build-Solution { + Write-Host "Generating Nuget packages for each project" + + # Nuget doesn't create the output dir automatically... + if (-not (Test-Path $NUGET_OUTPUT)) { + mkdir $NUGET_OUTPUT | Out-Null + } + + # Package the nuget + & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.nuspec") -OutputDirectory $NUGET_OUTPUT + & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.Web.nuspec") -OutputDirectory $NUGET_OUTPUT + & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.Web.Config.nuspec") -OutputDirectory $NUGET_OUTPUT + & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.Plugins.WebP.nuspec") -OutputDirectory $NUGET_OUTPUT + & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.Plugins.Cair.nuspec") -OutputDirectory $NUGET_OUTPUT +} \ No newline at end of file diff --git a/build/psake.psm1 b/build/psake.psm1 new file mode 100644 index 0000000000..c0d8ded039 --- /dev/null +++ b/build/psake.psm1 @@ -0,0 +1,847 @@ +# psake +# Copyright (c) 2012 James Kovacs +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. + +#Requires -Version 2.0 + +#-- Public Module Functions --# + +# .ExternalHelp psake.psm1-help.xml +function Invoke-Task +{ + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)] [string]$taskName + ) + + Assert $taskName ($msgs.error_invalid_task_name) + + $taskKey = $taskName.ToLower() + + if ($currentContext.aliases.Contains($taskKey)) { + $taskName = $currentContext.aliases.$taskKey.Name + $taskKey = $taskName.ToLower() + } + + $currentContext = $psake.context.Peek() + + Assert ($currentContext.tasks.Contains($taskKey)) ($msgs.error_task_name_does_not_exist -f $taskName) + + if ($currentContext.executedTasks.Contains($taskKey)) { return } + + Assert (!$currentContext.callStack.Contains($taskKey)) ($msgs.error_circular_reference -f $taskName) + + $currentContext.callStack.Push($taskKey) + + $task = $currentContext.tasks.$taskKey + + $precondition_is_valid = & $task.Precondition + + if (!$precondition_is_valid) { + WriteColoredOutput ($msgs.precondition_was_false -f $taskName) -foregroundcolor Cyan + } else { + if ($taskKey -ne 'default') { + + if ($task.PreAction -or $task.PostAction) { + Assert ($task.Action -ne $null) ($msgs.error_missing_action_parameter -f $taskName) + } + + if ($task.Action) { + try { + foreach($childTask in $task.DependsOn) { + Invoke-Task $childTask + } + + $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() + $currentContext.currentTaskName = $taskName + + & $currentContext.taskSetupScriptBlock + + if ($task.PreAction) { + & $task.PreAction + } + + if ($currentContext.config.taskNameFormat -is [ScriptBlock]) { + & $currentContext.config.taskNameFormat $taskName + } else { + WriteColoredOutput ($currentContext.config.taskNameFormat -f $taskName) -foregroundcolor Cyan + } + + foreach ($variable in $task.requiredVariables) { + Assert ((test-path "variable:$variable") -and ((get-variable $variable).Value -ne $null)) ($msgs.required_variable_not_set -f $variable, $taskName) + } + + & $task.Action + + if ($task.PostAction) { + & $task.PostAction + } + + & $currentContext.taskTearDownScriptBlock + $task.Duration = $stopwatch.Elapsed + } catch { + if ($task.ContinueOnError) { + "-"*70 + WriteColoredOutput ($msgs.continue_on_error -f $taskName,$_) -foregroundcolor Yellow + "-"*70 + $task.Duration = $stopwatch.Elapsed + } else { + throw $_ + } + } + } else { + # no action was specified but we still execute all the dependencies + foreach($childTask in $task.DependsOn) { + Invoke-Task $childTask + } + } + } else { + foreach($childTask in $task.DependsOn) { + Invoke-Task $childTask + } + } + + Assert (& $task.Postcondition) ($msgs.postcondition_failed -f $taskName) + } + + $poppedTaskKey = $currentContext.callStack.Pop() + Assert ($poppedTaskKey -eq $taskKey) ($msgs.error_corrupt_callstack -f $taskKey,$poppedTaskKey) + + $currentContext.executedTasks.Push($taskKey) +} + +# .ExternalHelp psake.psm1-help.xml +function Exec +{ + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)][scriptblock]$cmd, + [Parameter(Position=1,Mandatory=0)][string]$errorMessage = ($msgs.error_bad_command -f $cmd), + [Parameter(Position=2,Mandatory=0)][int]$maxRetries = 0, + [Parameter(Position=3,Mandatory=0)][string]$retryTriggerErrorPattern = $null + ) + + $tryCount = 1 + + do { + try { + $global:lastexitcode = 0 + & $cmd + if ($lastexitcode -ne 0) { + throw ("Exec: " + $errorMessage) + } + break + } + catch [Exception] + { + if ($tryCount -gt $maxRetries) { + throw $_ + } + + if ($retryTriggerErrorPattern -ne $null) { + $isMatch = [regex]::IsMatch($_.Exception.Message, $retryTriggerErrorPattern) + + if ($isMatch -eq $false) { + throw $_ + } + } + + Write-Host "Try $tryCount failed, retrying again in 1 second..." + + $tryCount++ + + [System.Threading.Thread]::Sleep([System.TimeSpan]::FromSeconds(1)) + } + } + while ($true) +} + +# .ExternalHelp psake.psm1-help.xml +function Assert +{ + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)]$conditionToCheck, + [Parameter(Position=1,Mandatory=1)]$failureMessage + ) + if (!$conditionToCheck) { + throw ("Assert: " + $failureMessage) + } +} + +# .ExternalHelp psake.psm1-help.xml +function Task +{ + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)][string]$name = $null, + [Parameter(Position=1,Mandatory=0)][scriptblock]$action = $null, + [Parameter(Position=2,Mandatory=0)][scriptblock]$preaction = $null, + [Parameter(Position=3,Mandatory=0)][scriptblock]$postaction = $null, + [Parameter(Position=4,Mandatory=0)][scriptblock]$precondition = {$true}, + [Parameter(Position=5,Mandatory=0)][scriptblock]$postcondition = {$true}, + [Parameter(Position=6,Mandatory=0)][switch]$continueOnError = $false, + [Parameter(Position=7,Mandatory=0)][string[]]$depends = @(), + [Parameter(Position=8,Mandatory=0)][string[]]$requiredVariables = @(), + [Parameter(Position=9,Mandatory=0)][string]$description = $null, + [Parameter(Position=10,Mandatory=0)][string]$alias = $null, + [Parameter(Position=11,Mandatory=0)][string]$maxRetries = 0, + [Parameter(Position=12,Mandatory=0)][string]$retryTriggerErrorPattern = $null + ) + if ($name -eq 'default') { + Assert (!$action) ($msgs.error_default_task_cannot_have_action) + } + + $newTask = @{ + Name = $name + DependsOn = $depends + PreAction = $preaction + Action = $action + PostAction = $postaction + Precondition = $precondition + Postcondition = $postcondition + ContinueOnError = $continueOnError + Description = $description + Duration = [System.TimeSpan]::Zero + RequiredVariables = $requiredVariables + Alias = $alias + MaxRetries = $maxRetries + RetryTriggerErrorPattern = $retryTriggerErrorPattern + } + + $taskKey = $name.ToLower() + + $currentContext = $psake.context.Peek() + + Assert (!$currentContext.tasks.ContainsKey($taskKey)) ($msgs.error_duplicate_task_name -f $name) + + $currentContext.tasks.$taskKey = $newTask + + if($alias) + { + $aliasKey = $alias.ToLower() + + Assert (!$currentContext.aliases.ContainsKey($aliasKey)) ($msgs.error_duplicate_alias_name -f $alias) + + $currentContext.aliases.$aliasKey = $newTask + } +} + +# .ExternalHelp psake.psm1-help.xml +function Properties { + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)][scriptblock]$properties + ) + $psake.context.Peek().properties += $properties +} + +# .ExternalHelp psake.psm1-help.xml +function Include { + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)][string]$fileNamePathToInclude + ) + Assert (test-path $fileNamePathToInclude -pathType Leaf) ($msgs.error_invalid_include_path -f $fileNamePathToInclude) + $psake.context.Peek().includes.Enqueue((Resolve-Path $fileNamePathToInclude)); +} + +# .ExternalHelp psake.psm1-help.xml +function FormatTaskName { + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)]$format + ) + $psake.context.Peek().config.taskNameFormat = $format +} + +# .ExternalHelp psake.psm1-help.xml +function TaskSetup { + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)][scriptblock]$setup + ) + $psake.context.Peek().taskSetupScriptBlock = $setup +} + +# .ExternalHelp psake.psm1-help.xml +function TaskTearDown { + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)][scriptblock]$teardown + ) + $psake.context.Peek().taskTearDownScriptBlock = $teardown +} + +# .ExternalHelp psake.psm1-help.xml +function Framework { + [CmdletBinding()] + param( + [Parameter(Position=0,Mandatory=1)][string]$framework + ) + $psake.context.Peek().config.framework = $framework + ConfigureBuildEnvironment +} + +# .ExternalHelp psake.psm1-help.xml +function Invoke-psake { + [CmdletBinding()] + param( + [Parameter(Position = 0, Mandatory = 0)][string] $buildFile, + [Parameter(Position = 1, Mandatory = 0)][string[]] $taskList = @(), + [Parameter(Position = 2, Mandatory = 0)][string] $framework, + [Parameter(Position = 3, Mandatory = 0)][switch] $docs = $false, + [Parameter(Position = 4, Mandatory = 0)][hashtable] $parameters = @{}, + [Parameter(Position = 5, Mandatory = 0)][hashtable] $properties = @{}, + [Parameter(Position = 6, Mandatory = 0)][alias("init")][scriptblock] $initialization = {}, + [Parameter(Position = 7, Mandatory = 0)][switch] $nologo = $false + ) + try { + if (-not $nologo) { + "psake version {0}`nCopyright (c) 2010 James Kovacs`n" -f $psake.version + } + + if (!$buildFile) { + $buildFile = $psake.config_default.buildFileName + } + elseif (!(test-path $buildFile -pathType Leaf) -and (test-path $psake.config_default.buildFileName -pathType Leaf)) { + # If the $config.buildFileName file exists and the given "buildfile" isn 't found assume that the given + # $buildFile is actually the target Tasks to execute in the $config.buildFileName script. + $taskList = $buildFile.Split(', ') + $buildFile = $psake.config_default.buildFileName + } + + # Execute the build file to set up the tasks and defaults + Assert (test-path $buildFile -pathType Leaf) ($msgs.error_build_file_not_found -f $buildFile) + + $psake.build_script_file = get-item $buildFile + $psake.build_script_dir = $psake.build_script_file.DirectoryName + $psake.build_success = $false + + $psake.context.push(@{ + "taskSetupScriptBlock" = {}; + "taskTearDownScriptBlock" = {}; + "executedTasks" = new-object System.Collections.Stack; + "callStack" = new-object System.Collections.Stack; + "originalEnvPath" = $env:path; + "originalDirectory" = get-location; + "originalErrorActionPreference" = $global:ErrorActionPreference; + "tasks" = @{}; + "aliases" = @{}; + "properties" = @(); + "includes" = new-object System.Collections.Queue; + "config" = CreateConfigurationForNewContext $buildFile $framework + }) + + LoadConfiguration $psake.build_script_dir + + $stopwatch = [System.Diagnostics.Stopwatch]::StartNew() + + set-location $psake.build_script_dir + + LoadModules + + $frameworkOldValue = $framework + . $psake.build_script_file.FullName + + $currentContext = $psake.context.Peek() + + if ($framework -ne $frameworkOldValue) { + writecoloredoutput $msgs.warning_deprecated_framework_variable -foregroundcolor Yellow + $currentContext.config.framework = $framework + } + + ConfigureBuildEnvironment + + while ($currentContext.includes.Count -gt 0) { + $includeFilename = $currentContext.includes.Dequeue() + . $includeFilename + } + + if ($docs) { + WriteDocumentation + CleanupEnvironment + return + } + + foreach ($key in $parameters.keys) { + if (test-path "variable:\$key") { + set-item -path "variable:\$key" -value $parameters.$key -WhatIf:$false -Confirm:$false | out-null + } else { + new-item -path "variable:\$key" -value $parameters.$key -WhatIf:$false -Confirm:$false | out-null + } + } + + # The initial dot (.) indicates that variables initialized/modified in the propertyBlock are available in the parent scope. + foreach ($propertyBlock in $currentContext.properties) { + . $propertyBlock + } + + foreach ($key in $properties.keys) { + if (test-path "variable:\$key") { + set-item -path "variable:\$key" -value $properties.$key -WhatIf:$false -Confirm:$false | out-null + } + } + + # Simple dot sourcing will not work. We have to force the script block into our + # module's scope in order to initialize variables properly. + . $MyInvocation.MyCommand.Module $initialization + + # Execute the list of tasks or the default task + if ($taskList) { + foreach ($task in $taskList) { + invoke-task $task + } + } elseif ($currentContext.tasks.default) { + invoke-task default + } else { + throw $msgs.error_no_default_task + } + + WriteColoredOutput ("`n" + $msgs.build_success + "`n") -foregroundcolor Green + + WriteTaskTimeSummary $stopwatch.Elapsed + + $psake.build_success = $true + } catch { + $currentConfig = GetCurrentConfigurationOrDefault + if ($currentConfig.verboseError) { + $error_message = "{0}: An Error Occurred. See Error Details Below: `n" -f (Get-Date) + $error_message += ("-" * 70) + "`n" + $error_message += "Error: {0}`n" -f (ResolveError $_ -Short) + $error_message += ("-" * 70) + "`n" + $error_message += ResolveError $_ + $error_message += ("-" * 70) + "`n" + $error_message += "Script Variables" + "`n" + $error_message += ("-" * 70) + "`n" + $error_message += get-variable -scope script | format-table | out-string + } else { + # ($_ | Out-String) gets error messages with source information included. + $error_message = "Error: {0}: `n{1}" -f (Get-Date), (ResolveError $_ -Short) + } + + $psake.build_success = $false + + # if we are running in a nested scope (i.e. running a psake script from a psake script) then we need to re-throw the exception + # so that the parent script will fail otherwise the parent script will report a successful build + $inNestedScope = ($psake.context.count -gt 1) + if ( $inNestedScope ) { + throw $_ + } else { + if (!$psake.run_by_psake_build_tester) { + WriteColoredOutput $error_message -foregroundcolor Red + } + } + } finally { + CleanupEnvironment + } +} + +#-- Private Module Functions --# +function WriteColoredOutput { + param( + [string] $message, + [System.ConsoleColor] $foregroundcolor + ) + + $currentConfig = GetCurrentConfigurationOrDefault + if ($currentConfig.coloredOutput -eq $true) { + if (($Host.UI -ne $null) -and ($Host.UI.RawUI -ne $null) -and ($Host.UI.RawUI.ForegroundColor -ne $null)) { + $previousColor = $Host.UI.RawUI.ForegroundColor + $Host.UI.RawUI.ForegroundColor = $foregroundcolor + } + } + + $message + + if ($previousColor -ne $null) { + $Host.UI.RawUI.ForegroundColor = $previousColor + } +} + +function LoadModules { + $currentConfig = $psake.context.peek().config + if ($currentConfig.modules) { + + $scope = $currentConfig.moduleScope + + $global = [string]::Equals($scope, "global", [StringComparison]::CurrentCultureIgnoreCase) + + $currentConfig.modules | foreach { + resolve-path $_ | foreach { + "Loading module: $_" + $module = import-module $_ -passthru -DisableNameChecking -global:$global + if (!$module) { + throw ($msgs.error_loading_module -f $_.Name) + } + } + } + "" + } +} + +function LoadConfiguration { + param( + [string] $configdir = $PSScriptRoot + ) + + $psakeConfigFilePath = (join-path $configdir "psake-config.ps1") + + if (test-path $psakeConfigFilePath -pathType Leaf) { + try { + $config = GetCurrentConfigurationOrDefault + . $psakeConfigFilePath + } catch { + throw "Error Loading Configuration from psake-config.ps1: " + $_ + } + } +} + +function GetCurrentConfigurationOrDefault() { + if ($psake.context.count -gt 0) { + return $psake.context.peek().config + } else { + return $psake.config_default + } +} + +function CreateConfigurationForNewContext { + param( + [string] $buildFile, + [string] $framework + ) + + $previousConfig = GetCurrentConfigurationOrDefault + + $config = new-object psobject -property @{ + buildFileName = $previousConfig.buildFileName; + framework = $previousConfig.framework; + taskNameFormat = $previousConfig.taskNameFormat; + verboseError = $previousConfig.verboseError; + coloredOutput = $previousConfig.coloredOutput; + modules = $previousConfig.modules; + moduleScope = $previousConfig.moduleScope; + } + + if ($framework) { + $config.framework = $framework; + } + + if ($buildFile) { + $config.buildFileName = $buildFile; + } + + return $config +} + +function ConfigureBuildEnvironment { + $framework = $psake.context.peek().config.framework + if ($framework -cmatch '^((?:\d+\.\d+)(?:\.\d+){0,1})(x86|x64){0,1}$') { + $versionPart = $matches[1] + $bitnessPart = $matches[2] + } else { + throw ($msgs.error_invalid_framework -f $framework) + } + $versions = $null + $buildToolsVersions = $null + switch ($versionPart) { + '1.0' { + $versions = @('v1.0.3705') + } + '1.1' { + $versions = @('v1.1.4322') + } + '2.0' { + $versions = @('v2.0.50727') + } + '3.0' { + $versions = @('v2.0.50727') + } + '3.5' { + $versions = @('v3.5', 'v2.0.50727') + } + '4.0' { + $versions = @('v4.0.30319') + } + '4.5.1' { + $versions = @('v4.0.30319') + $buildToolsVersions = @('12.0') + } + default { + throw ($msgs.error_unknown_framework -f $versionPart, $framework) + } + } + + $bitness = 'Framework' + if ($versionPart -ne '1.0' -and $versionPart -ne '1.1') { + switch ($bitnessPart) { + 'x86' { + $bitness = 'Framework' + $buildToolsKey = 'MSBuildToolsPath32' + } + 'x64' { + $bitness = 'Framework64' + $buildToolsKey = 'MSBuildToolsPath' + } + { [string]::IsNullOrEmpty($_) } { + $ptrSize = [System.IntPtr]::Size + switch ($ptrSize) { + 4 { + $bitness = 'Framework' + $buildToolsKey = 'MSBuildToolsPath32' + } + 8 { + $bitness = 'Framework64' + $buildToolsKey = 'MSBuildToolsPath' + } + default { + throw ($msgs.error_unknown_pointersize -f $ptrSize) + } + } + } + default { + throw ($msgs.error_unknown_bitnesspart -f $bitnessPart, $framework) + } + } + } + $frameworkDirs = @() + if ($buildToolsVersions -ne $null) { + $frameworkDirs = @($buildToolsVersions | foreach { (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\MSBuild\ToolsVersions\$_" -Name $buildToolsKey).$buildToolsKey }) + } + $frameworkDirs = $frameworkDirs + @($versions | foreach { "$env:windir\Microsoft.NET\$bitness\$_\" }) + + for ($i = 0; $i -lt $frameworkDirs.Count; $i++) { + $dir = $frameworkDirs[$i] + if ($dir -Match "\$\(Registry:HKEY_LOCAL_MACHINE(.*?)@(.*)\)") { + $key = "HKLM:" + $matches[1] + $name = $matches[2] + $dir = (Get-ItemProperty -Path $key -Name $name).$name + $frameworkDirs[$i] = $dir + } + } + + $frameworkDirs | foreach { Assert (test-path $_ -pathType Container) ($msgs.error_no_framework_install_dir_found -f $_)} + + $env:path = ($frameworkDirs -join ";") + ";$env:path" + # if any error occurs in a PS function then "stop" processing immediately + # this does not effect any external programs that return a non-zero exit code + $global:ErrorActionPreference = "Stop" +} + +function CleanupEnvironment { + if ($psake.context.Count -gt 0) { + $currentContext = $psake.context.Peek() + $env:path = $currentContext.originalEnvPath + Set-Location $currentContext.originalDirectory + $global:ErrorActionPreference = $currentContext.originalErrorActionPreference + [void] $psake.context.Pop() + } +} + +function SelectObjectWithDefault +{ + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline=$true)] + [PSObject] + $InputObject, + [string] + $Name, + $Value + ) + + process { + if ($_ -eq $null) { $Value } + elseif ($_ | Get-Member -Name $Name) { + $_.$Name + } + elseif (($_ -is [Hashtable]) -and ($_.Keys -contains $Name)) { + $_.$Name + } + else { $Value } + } +} + +# borrowed from Jeffrey Snover http://blogs.msdn.com/powershell/archive/2006/12/07/resolve-error.aspx +# modified to better handle SQL errors +function ResolveError +{ + [CmdletBinding()] + param( + [Parameter(ValueFromPipeline=$true)] + $ErrorRecord=$Error[0], + [Switch] + $Short + ) + + process { + if ($_ -eq $null) { $_ = $ErrorRecord } + $ex = $_.Exception + + if (-not $Short) { + $error_message = "`nErrorRecord:{0}ErrorRecord.InvocationInfo:{1}Exception:`n{2}" + $formatted_errorRecord = $_ | format-list * -force | out-string + $formatted_invocationInfo = $_.InvocationInfo | format-list * -force | out-string + $formatted_exception = '' + + $i = 0 + while ($ex -ne $null) { + $i++ + $formatted_exception += ("$i" * 70) + "`n" + + ($ex | format-list * -force | out-string) + "`n" + $ex = $ex | SelectObjectWithDefault -Name 'InnerException' -Value $null + } + + return $error_message -f $formatted_errorRecord, $formatted_invocationInfo, $formatted_exception + } + + $lastException = @() + while ($ex -ne $null) { + $lastMessage = $ex | SelectObjectWithDefault -Name 'Message' -Value '' + $lastException += ($lastMessage -replace "`n", '') + if ($ex -is [Data.SqlClient.SqlException]) { + $lastException += "(Line [$($ex.LineNumber)] " + + "Procedure [$($ex.Procedure)] Class [$($ex.Class)] " + + " Number [$($ex.Number)] State [$($ex.State)] )" + } + $ex = $ex | SelectObjectWithDefault -Name 'InnerException' -Value $null + } + $shortException = $lastException -join ' --> ' + + $header = $null + $current = $_ + $header = (($_.InvocationInfo | + SelectObjectWithDefault -Name 'PositionMessage' -Value '') -replace "`n", ' '), + ($_ | SelectObjectWithDefault -Name 'Message' -Value ''), + ($_ | SelectObjectWithDefault -Name 'Exception' -Value '') | + ? { -not [String]::IsNullOrEmpty($_) } | + Select -First 1 + + $delimiter = '' + if ((-not [String]::IsNullOrEmpty($header)) -and + (-not [String]::IsNullOrEmpty($shortException))) + { $delimiter = ' [<<==>>] ' } + + return "$($header)$($delimiter)Exception: $($shortException)" + } +} + +function WriteDocumentation { + $currentContext = $psake.context.Peek() + + if ($currentContext.tasks.default) { + $defaultTaskDependencies = $currentContext.tasks.default.DependsOn + } else { + $defaultTaskDependencies = @() + } + + $currentContext.tasks.Keys | foreach-object { + if ($_ -eq "default") { + return + } + + $task = $currentContext.tasks.$_ + new-object PSObject -property @{ + Name = $task.Name; + Alias = $task.Alias; + Description = $task.Description; + "Depends On" = $task.DependsOn -join ", " + Default = if ($defaultTaskDependencies -contains $task.Name) { $true } + } + } | sort 'Name' | format-table -autoSize -wrap -property Name,Alias,"Depends On",Default,Description +} + +function WriteTaskTimeSummary($invokePsakeDuration) { + "-" * 70 + "Build Time Report" + "-" * 70 + $list = @() + $currentContext = $psake.context.Peek() + while ($currentContext.executedTasks.Count -gt 0) { + $taskKey = $currentContext.executedTasks.Pop() + $task = $currentContext.tasks.$taskKey + if ($taskKey -eq "default") { + continue + } + $list += new-object PSObject -property @{ + Name = $task.Name; + Duration = $task.Duration + } + } + [Array]::Reverse($list) + $list += new-object PSObject -property @{ + Name = "Total:"; + Duration = $invokePsakeDuration + } + # using "out-string | where-object" to filter out the blank line that format-table prepends + $list | format-table -autoSize -property Name,Duration | out-string -stream | where-object { $_ } +} + +DATA msgs { +convertfrom-stringdata @' + error_invalid_task_name = Task name should not be null or empty string. + error_task_name_does_not_exist = Task {0} does not exist. + error_circular_reference = Circular reference found for task {0}. + error_missing_action_parameter = Action parameter must be specified when using PreAction or PostAction parameters for task {0}. + error_corrupt_callstack = Call stack was corrupt. Expected {0}, but got {1}. + error_invalid_framework = Invalid .NET Framework version, {0} specified. + error_unknown_framework = Unknown .NET Framework version, {0} specified in {1}. + error_unknown_pointersize = Unknown pointer size ({0}) returned from System.IntPtr. + error_unknown_bitnesspart = Unknown .NET Framework bitness, {0}, specified in {1}. + error_no_framework_install_dir_found = No .NET Framework installation directory found at {0}. + error_bad_command = Error executing command {0}. + error_default_task_cannot_have_action = 'default' task cannot specify an action. + error_duplicate_task_name = Task {0} has already been defined. + error_duplicate_alias_name = Alias {0} has already been defined. + error_invalid_include_path = Unable to include {0}. File not found. + error_build_file_not_found = Could not find the build file {0}. + error_no_default_task = 'default' task required. + error_loading_module = Error loading module {0}. + warning_deprecated_framework_variable = Warning: Using global variable $framework to set .NET framework version used is deprecated. Instead use Framework function or configuration file psake-config.ps1. + required_variable_not_set = Variable {0} must be set to run task {1}. + postcondition_failed = Postcondition failed for task {0}. + precondition_was_false = Precondition was false, not executing task {0}. + continue_on_error = Error in task {0}. {1} + build_success = Build Succeeded! +'@ +} + +import-localizeddata -bindingvariable msgs -erroraction silentlycontinue + +$script:psake = @{} +$psake.version = "4.3.2" # contains the current version of psake +$psake.context = new-object system.collections.stack # holds onto the current state of all variables +$psake.run_by_psake_build_tester = $false # indicates that build is being run by psake-BuildTester +$psake.config_default = new-object psobject -property @{ + buildFileName = "default.ps1"; + framework = "4.0"; + taskNameFormat = "Executing {0}"; + verboseError = $false; + coloredOutput = $true; + modules = $null; + moduleScope = ""; +} # contains default configuration, can be overriden in psake-config.ps1 in directory with psake.psm1 or in directory with current build script + +$psake.build_success = $false # indicates that the current build was successful +$psake.build_script_file = $null # contains a System.IO.FileInfo for the current build script +$psake.build_script_dir = "" # contains a string with fully-qualified path to current build script + +LoadConfiguration + +export-modulemember -function Invoke-psake, Invoke-Task, Task, Properties, Include, FormatTaskName, TaskSetup, TaskTearDown, Framework, Assert, Exec -variable psake From a0cfcb59bc4bdf39354bc40be70b6cc41fd697c2 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 19 Sep 2014 11:50:02 +0200 Subject: [PATCH 05/10] Refactors a bit the build script, and automatically modifies the nuspecs Former-commit-id: 759f3ee86b9d6250efc347eeb5285ed01818f619 --- build/build.ps1 | 40 ++++++++++++++++++++++++++++------------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/build/build.ps1 b/build/build.ps1 index ff0c251926..51cad760ba 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -5,9 +5,10 @@ Properties { $webppluginversion = "1.0.1.0" $cairpluginversion = "1.0.0.0" - $PROJ_PATH = "." + # build paths to various files + $PROJ_PATH = (Resolve-Path ".") $BIN_PATH = (Join-Path $PROJ_PATH "_BuildOutput") - $NUGET_EXE = "..\src\.nuget\NuGet.exe" + $NUGET_EXE = (Resolve-Path "..\src\.nuget\NuGet.exe") $NUSPECS_PATH = (Join-Path $PROJ_PATH "NuSpecs") $NUGET_OUTPUT = (Join-Path $BIN_PATH "NuGets") # TODO: add opencover and nunit runner binaries @@ -29,11 +30,11 @@ task Cleanup-Binaries { # builds the solutions task Build-Solution -depends Cleanup-Binaries { Write-Host "Building projects" - Exec { - msbuild (Join-Path $PROJ_PATH "Build.ImageProcessor.proj") /p:BUILD_RELEASE="$version" - msbuild (Join-Path $PROJ_PATH "Build.ImageProcessor.Web.proj") /p:BUILD_RELEASE="$version" - msbuild (Join-Path $PROJ_PATH "Build.ImageProcessor.Plugins.WebP.proj") /p:BUILD_RELEASE="$version" - msbuild (Join-Path $PROJ_PATH "Build.ImageProcessor.Plugins.Cair.proj") /p:BUILD_RELEASE="$version" + $projects = @("Build.ImageProcessor.proj", "Build.ImageProcessor.Web.proj", "Build.ImageProcessor.Plugins.WebP.proj", "Build.ImageProcessor.Plugins.Cair.proj") + $projects | % { + Exec { + msbuild (Join-Path $PROJ_PATH $_) /p:BUILD_RELEASE="$version" + } } } @@ -47,9 +48,24 @@ task Generate-Package -depends Build-Solution { } # Package the nuget - & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.nuspec") -OutputDirectory $NUGET_OUTPUT - & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.Web.nuspec") -OutputDirectory $NUGET_OUTPUT - & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.Web.Config.nuspec") -OutputDirectory $NUGET_OUTPUT - & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.Plugins.WebP.nuspec") -OutputDirectory $NUGET_OUTPUT - & $NUGET_EXE Pack (Join-Path $NUSPECS_PATH "ImageProcessor.Plugins.Cair.nuspec") -OutputDirectory $NUGET_OUTPUT + $nuspecs = @{ + "ImageProcessor.nuspec" = $version ; + "ImageProcessor.Web.nuspec" = $webversion ; + "ImageProcessor.Web.Config.nuspec" = $webconfigversion ; + "ImageProcessor.Plugins.WebP.nuspec" = $webppluginversion ; + "ImageProcessor.Plugins.Cair.nuspec" = $cairpluginversion + } + + $nuspecs.GetEnumerator() | % { + $nuspec_local_path = (Join-Path $NUSPECS_PATH $_.Key) + Write-Host "Building package from $nuspec_local_path" + + # change the version values + [xml]$nuspec_contents = Get-Content $nuspec_local_path + $nuspec_contents.package.metadata.version = $_.Value + $nuspec_contents.Save($nuspec_local_path) + + # pack the nuget + & $NUGET_EXE Pack $nuspec_local_path -OutputDirectory $NUGET_OUTPUT + } } \ No newline at end of file From 1f58a02d4836322df1c41cc7258f237cec5997b1 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 19 Sep 2014 12:06:50 +0200 Subject: [PATCH 06/10] Runs unit tests as part of the build process Former-commit-id: 9b6bfe4121ce1455701a10baff059d85de1ef2d0 --- build/build.ps1 | 51 ++++++++++++++++++++++++++------ src/.nuget/packages.config | 5 ++++ src/packages/repositories.config | 6 ---- 3 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 src/.nuget/packages.config diff --git a/build/build.ps1 b/build/build.ps1 index 51cad760ba..df64127f96 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -6,18 +6,21 @@ Properties { $cairpluginversion = "1.0.0.0" # build paths to various files - $PROJ_PATH = (Resolve-Path ".") - $BIN_PATH = (Join-Path $PROJ_PATH "_BuildOutput") - $NUGET_EXE = (Resolve-Path "..\src\.nuget\NuGet.exe") - $NUSPECS_PATH = (Join-Path $PROJ_PATH "NuSpecs") - $NUGET_OUTPUT = (Join-Path $BIN_PATH "NuGets") - # TODO: add opencover and nunit runner binaries + $PROJ_PATH = Resolve-Path "." + $SRC_PATH = Resolve-Path "..\src" + $BIN_PATH = Join-Path $PROJ_PATH "_BuildOutput" + $NUGET_EXE = Join-Path $SRC_PATH ".nuget\NuGet.exe" + $NUSPECS_PATH = Join-Path $PROJ_PATH "NuSpecs" + $NUGET_OUTPUT = Join-Path $BIN_PATH "NuGets" + + # nunit runner binaries + $NUNIT_EXE = Join-Path $SRC_PATH "packages\NUnit.Runners.2.6.3\tools\nunit-console.exe" } Framework "4.0x86" FormatTaskName "-------- {0} --------" -task default -depends Cleanup-Binaries, Build-Solution, Generate-Package +task default -depends Cleanup-Binaries, Build-Solution, Run-Tests, Generate-Package # cleans up the binaries output folder task Cleanup-Binaries { @@ -30,14 +33,44 @@ task Cleanup-Binaries { # builds the solutions task Build-Solution -depends Cleanup-Binaries { Write-Host "Building projects" - $projects = @("Build.ImageProcessor.proj", "Build.ImageProcessor.Web.proj", "Build.ImageProcessor.Plugins.WebP.proj", "Build.ImageProcessor.Plugins.Cair.proj") + $projects = @( + "Build.ImageProcessor.proj", + "Build.ImageProcessor.Web.proj", + "Build.ImageProcessor.Plugins.WebP.proj", + "Build.ImageProcessor.Plugins.Cair.proj" + ) + $projects | % { + Write-Host "Building project $_" Exec { msbuild (Join-Path $PROJ_PATH $_) /p:BUILD_RELEASE="$version" } } } +# runs the unit tests +task Run-Tests { + Write-Host "Building the unit test projects" + + $projects = @( + "ImageProcessor.UnitTests", + "ImageProcessor.Web.UnitTests" + ) + + $projects | % { + Write-Host "Building project $_" + Exec { + msbuild (Join-Path $SRC_PATH "$_\$_.csproj") /t:Build /p:Configuration=Release /p:Platform="AnyCPU" /p:Warnings=true /v:Normal /nologo /clp:WarningsOnly`;ErrorsOnly`;Summary`;PerformanceSummary + } + } + + Write-Host "Running unit tests" + $projects | % { + Write-Host "Running tests on project $_" + & $NUNIT_EXE (Join-Path $SRC_PATH "$_\bin\Release\$_.dll") + } +} + # generates a Nuget package task Generate-Package -depends Build-Solution { Write-Host "Generating Nuget packages for each project" @@ -58,7 +91,7 @@ task Generate-Package -depends Build-Solution { $nuspecs.GetEnumerator() | % { $nuspec_local_path = (Join-Path $NUSPECS_PATH $_.Key) - Write-Host "Building package from $nuspec_local_path" + Write-Host "Building Nuget package from $nuspec_local_path" # change the version values [xml]$nuspec_contents = Get-Content $nuspec_local_path diff --git a/src/.nuget/packages.config b/src/.nuget/packages.config new file mode 100644 index 0000000000..840553686b --- /dev/null +++ b/src/.nuget/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/packages/repositories.config b/src/packages/repositories.config index 3406fa91f7..bfef3f66b6 100644 --- a/src/packages/repositories.config +++ b/src/packages/repositories.config @@ -1,12 +1,6 @@  - - - - - - \ No newline at end of file From 3764d14445c6721cb66b78d1d38eb05145e41f6f Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 19 Sep 2014 12:11:04 +0200 Subject: [PATCH 07/10] Ignores test artifacts Former-commit-id: f9b163f8fc0e82371bc67db7951a492e5980a3dd --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2fc43e4a10..3fd18e8e1f 100644 --- a/.gitignore +++ b/.gitignore @@ -167,6 +167,7 @@ pip-log.txt build/_BuildOutput/ build/*.nupkg +build/TestResult.xml *.db _site/ \ No newline at end of file From 41016cdaed9351e31c3b30f5b256d5a715558e9d Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 19 Sep 2014 15:04:48 +0200 Subject: [PATCH 08/10] Runs code coverage over unit tests Former-commit-id: 811e1ad71fc90e985d2709d9f78bb4ac87e17f2d --- build/build.ps1 | 51 ++++++++++++++++++++++++++++++-------- build/tests.bat | 3 +++ src/.nuget/packages.config | 1 + 3 files changed, 44 insertions(+), 11 deletions(-) create mode 100644 build/tests.bat diff --git a/build/build.ps1 b/build/build.ps1 index df64127f96..6b8fa99b6f 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -5,29 +5,40 @@ Properties { $webppluginversion = "1.0.1.0" $cairpluginversion = "1.0.0.0" - # build paths to various files + # Input and output paths $PROJ_PATH = Resolve-Path "." $SRC_PATH = Resolve-Path "..\src" - $BIN_PATH = Join-Path $PROJ_PATH "_BuildOutput" - $NUGET_EXE = Join-Path $SRC_PATH ".nuget\NuGet.exe" $NUSPECS_PATH = Join-Path $PROJ_PATH "NuSpecs" + $BIN_PATH = Join-Path $PROJ_PATH "_BuildOutput" $NUGET_OUTPUT = Join-Path $BIN_PATH "NuGets" + $TEST_RESULTS = Join-Path $PROJ_PATH "TestResults" - # nunit runner binaries + # External binaries paths + $NUGET_EXE = Join-Path $SRC_PATH ".nuget\NuGet.exe" $NUNIT_EXE = Join-Path $SRC_PATH "packages\NUnit.Runners.2.6.3\tools\nunit-console.exe" + $OPENCOVER_EXE = Join-Path $SRC_PATH "packages\OpenCover.4.5.3207\OpenCover.Console.exe" + $REPORTGEN_EXE = Join-Path $SRC_PATH "packages\ReportGenerator.1.9.1.0\ReportGenerator.exe" } Framework "4.0x86" FormatTaskName "-------- {0} --------" -task default -depends Cleanup-Binaries, Build-Solution, Run-Tests, Generate-Package +task default -depends Cleanup-Binaries, Build-Solution, Generate-Package # cleans up the binaries output folder task Cleanup-Binaries { - Write-Host "Removing $BIN_PATH directory so everything is nice and clean" + Write-Host "Removing binaries and artifacts so everything is nice and clean" if (Test-Path $BIN_PATH) { Remove-Item $BIN_PATH -Force -Recurse } + + if (Test-Path $NUGET_OUTPUT) { + Remove-Item $NUGET_OUTPUT -Force -Recurse + } + + if (Test-Path $TEST_RESULTS) { + Remove-Item $TEST_RESULTS -Force -Recurse + } } # builds the solutions @@ -49,25 +60,43 @@ task Build-Solution -depends Cleanup-Binaries { } # runs the unit tests -task Run-Tests { +task Run-Tests -depends Cleanup-Binaries { Write-Host "Building the unit test projects" + if (-not (Test-Path $TEST_RESULTS)) { + mkdir $TEST_RESULTS | Out-Null + } + + # make sure the runner exes are restored + & $NUGET_EXE restore (Join-Path $SRC_PATH "ImageProcessor.sln") + $projects = @( "ImageProcessor.UnitTests", "ImageProcessor.Web.UnitTests" ) + # build the test projects (they don't have specific build files like the main projects) $projects | % { Write-Host "Building project $_" Exec { - msbuild (Join-Path $SRC_PATH "$_\$_.csproj") /t:Build /p:Configuration=Release /p:Platform="AnyCPU" /p:Warnings=true /v:Normal /nologo /clp:WarningsOnly`;ErrorsOnly`;Summary`;PerformanceSummary + msbuild (Join-Path $SRC_PATH "$_\$_.csproj") /t:Build /p:Configuration=Release /p:Platform="AnyCPU" /p:Warnings=true /v:Normal /nologo } } - Write-Host "Running unit tests" + # run the Nunit test runner on the test DLLs + Write-Host "Running code coverage over unit tests" $projects | % { - Write-Host "Running tests on project $_" - & $NUNIT_EXE (Join-Path $SRC_PATH "$_\bin\Release\$_.dll") + $TestDllFolder = Join-Path $SRC_PATH "$_\bin\Release" + $TestDdlPath = Join-Path $TestDllFolder "$_.dll" + $TestOutputPath = Join-Path $TEST_RESULTS "$($_)_Unit.xml" + $CoverageOutputPath = Join-Path $TEST_RESULTS "$($_)_Coverage.xml" + + Write-Host "Running code coverage on project $_" + & $OPENCOVER_EXE -register:user -target:$NUNIT_EXE -targetargs:"$TestDdlPath /result:$TestOutputPath /noshadow /nologo" -targetdir:$TestDllFolder -output:$CoverageOutputPath + + Write-Host "Transforming coverage result file to HTML" + & $REPORTGEN_EXE -reports:$TestOutputPath -targetdir:(Join-Path $TEST_RESULTS "Tests\$_") + & $REPORTGEN_EXE -reports:$CoverageOutputPath -targetdir:(Join-Path $TEST_RESULTS "Coverage\$_") } } diff --git a/build/tests.bat b/build/tests.bat new file mode 100644 index 0000000000..58708e0fbe --- /dev/null +++ b/build/tests.bat @@ -0,0 +1,3 @@ +@echo off + +powershell "Import-Module %~dp0\psake.psm1 ; Invoke-Psake %~dp0\build.ps1 Run-Tests ; exit $LASTEXITCODE" \ No newline at end of file diff --git a/src/.nuget/packages.config b/src/.nuget/packages.config index 840553686b..9cfde32e18 100644 --- a/src/.nuget/packages.config +++ b/src/.nuget/packages.config @@ -2,4 +2,5 @@ + \ No newline at end of file From 68caa34394f43b85035b8b8bece559f7a282e351 Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Fri, 19 Sep 2014 15:41:36 +0200 Subject: [PATCH 09/10] Splits unit tests and code coverage because unit tests are fast, but coverage is incredibly slow Former-commit-id: a9100ddc8cd7c6a9f0bfbc47d901795b31b2f7c1 --- ...UnitHTMLReportGenerator.exe.REMOVED.git-id | 1 + build/NUnitHTMLReportGenerator.exe.config | 7 ++ build/build.ps1 | 89 ++++++++++++------- build/{tests.bat => coverage.bat} | 2 +- 4 files changed, 66 insertions(+), 33 deletions(-) create mode 100644 build/NUnitHTMLReportGenerator.exe.REMOVED.git-id create mode 100644 build/NUnitHTMLReportGenerator.exe.config rename build/{tests.bat => coverage.bat} (63%) diff --git a/build/NUnitHTMLReportGenerator.exe.REMOVED.git-id b/build/NUnitHTMLReportGenerator.exe.REMOVED.git-id new file mode 100644 index 0000000000..e34edfefe3 --- /dev/null +++ b/build/NUnitHTMLReportGenerator.exe.REMOVED.git-id @@ -0,0 +1 @@ +75c3885b6db49741cd7c7efe3bda996c2fae5ae7 \ No newline at end of file diff --git a/build/NUnitHTMLReportGenerator.exe.config b/build/NUnitHTMLReportGenerator.exe.config new file mode 100644 index 0000000000..3143478cc7 --- /dev/null +++ b/build/NUnitHTMLReportGenerator.exe.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/build/build.ps1 b/build/build.ps1 index 6b8fa99b6f..cacc9b196b 100644 --- a/build/build.ps1 +++ b/build/build.ps1 @@ -18,12 +18,34 @@ Properties { $NUNIT_EXE = Join-Path $SRC_PATH "packages\NUnit.Runners.2.6.3\tools\nunit-console.exe" $OPENCOVER_EXE = Join-Path $SRC_PATH "packages\OpenCover.4.5.3207\OpenCover.Console.exe" $REPORTGEN_EXE = Join-Path $SRC_PATH "packages\ReportGenerator.1.9.1.0\ReportGenerator.exe" + $NUNITREPORT_EXE = Join-Path $PROJ_PATH "NUnitHTMLReportGenerator.exe" + + # list of projects + $BuildProjects = @( + "Build.ImageProcessor.proj", + "Build.ImageProcessor.Web.proj", + "Build.ImageProcessor.Plugins.WebP.proj", + "Build.ImageProcessor.Plugins.Cair.proj" + ) + + $TestProjects = @( + "ImageProcessor.UnitTests", + "ImageProcessor.Web.UnitTests" + ) + + $Nuspecs = @{ + "ImageProcessor.nuspec" = $version ; + "ImageProcessor.Web.nuspec" = $webversion ; + "ImageProcessor.Web.Config.nuspec" = $webconfigversion ; + "ImageProcessor.Plugins.WebP.nuspec" = $webppluginversion ; + "ImageProcessor.Plugins.Cair.nuspec" = $cairpluginversion + } } Framework "4.0x86" FormatTaskName "-------- {0} --------" -task default -depends Cleanup-Binaries, Build-Solution, Generate-Package +task default -depends Cleanup-Binaries, Build-Solution, Run-Tests, Generate-Package # cleans up the binaries output folder task Cleanup-Binaries { @@ -44,14 +66,8 @@ task Cleanup-Binaries { # builds the solutions task Build-Solution -depends Cleanup-Binaries { Write-Host "Building projects" - $projects = @( - "Build.ImageProcessor.proj", - "Build.ImageProcessor.Web.proj", - "Build.ImageProcessor.Plugins.WebP.proj", - "Build.ImageProcessor.Plugins.Cair.proj" - ) - - $projects | % { + + $BuildProjects | % { Write-Host "Building project $_" Exec { msbuild (Join-Path $PROJ_PATH $_) /p:BUILD_RELEASE="$version" @@ -59,8 +75,8 @@ task Build-Solution -depends Cleanup-Binaries { } } -# runs the unit tests -task Run-Tests -depends Cleanup-Binaries { +# builds the test projects +task Build-Tests -depends Cleanup-Binaries { Write-Host "Building the unit test projects" if (-not (Test-Path $TEST_RESULTS)) { @@ -70,32 +86,49 @@ task Run-Tests -depends Cleanup-Binaries { # make sure the runner exes are restored & $NUGET_EXE restore (Join-Path $SRC_PATH "ImageProcessor.sln") - $projects = @( - "ImageProcessor.UnitTests", - "ImageProcessor.Web.UnitTests" - ) - # build the test projects (they don't have specific build files like the main projects) - $projects | % { + $TestProjects | % { Write-Host "Building project $_" Exec { msbuild (Join-Path $SRC_PATH "$_\$_.csproj") /t:Build /p:Configuration=Release /p:Platform="AnyCPU" /p:Warnings=true /v:Normal /nologo } } - # run the Nunit test runner on the test DLLs - Write-Host "Running code coverage over unit tests" - $projects | % { +} + +# runs the unit tests +task Run-Tests -depends Build-Tests { + Write-Host "Running unit tests" + $TestProjects | % { $TestDllFolder = Join-Path $SRC_PATH "$_\bin\Release" $TestDdlPath = Join-Path $TestDllFolder "$_.dll" $TestOutputPath = Join-Path $TEST_RESULTS "$($_)_Unit.xml" + + Write-Host "Running unit tests on project $_" + & $NUNIT_EXE $TestDdlPath /result:$TestOutputPath /noshadow /nologo + + $ReportPath = (Join-Path $TEST_RESULTS "Tests") + if (-not (Test-Path $ReportPath)) { + mkdir $ReportPath | Out-Null + } + + Write-Host "Transforming tests results file to HTML" + & $NUNITREPORT_EXE $TestOutputPath (Join-Path $ReportPath "$_.html") + } +} + +# runs the code coverage (separate from the unit test because it takes so much longer) +task Run-Coverage -depends Build-Tests { + Write-Host "Running code coverage over unit tests" + $TestProjects | % { + $TestDllFolder = Join-Path $SRC_PATH "$_\bin\Release" + $TestDdlPath = Join-Path $TestDllFolder "$_.dll" $CoverageOutputPath = Join-Path $TEST_RESULTS "$($_)_Coverage.xml" Write-Host "Running code coverage on project $_" - & $OPENCOVER_EXE -register:user -target:$NUNIT_EXE -targetargs:"$TestDdlPath /result:$TestOutputPath /noshadow /nologo" -targetdir:$TestDllFolder -output:$CoverageOutputPath + & $OPENCOVER_EXE -register:user -target:$NUNIT_EXE -targetargs:"$TestDdlPath /noshadow /nologo" -targetdir:$TestDllFolder -output:$CoverageOutputPath - Write-Host "Transforming coverage result file to HTML" - & $REPORTGEN_EXE -reports:$TestOutputPath -targetdir:(Join-Path $TEST_RESULTS "Tests\$_") + Write-Host "Transforming coverage results file to HTML" & $REPORTGEN_EXE -reports:$CoverageOutputPath -targetdir:(Join-Path $TEST_RESULTS "Coverage\$_") } } @@ -110,15 +143,7 @@ task Generate-Package -depends Build-Solution { } # Package the nuget - $nuspecs = @{ - "ImageProcessor.nuspec" = $version ; - "ImageProcessor.Web.nuspec" = $webversion ; - "ImageProcessor.Web.Config.nuspec" = $webconfigversion ; - "ImageProcessor.Plugins.WebP.nuspec" = $webppluginversion ; - "ImageProcessor.Plugins.Cair.nuspec" = $cairpluginversion - } - - $nuspecs.GetEnumerator() | % { + $Nuspecs.GetEnumerator() | % { $nuspec_local_path = (Join-Path $NUSPECS_PATH $_.Key) Write-Host "Building Nuget package from $nuspec_local_path" diff --git a/build/tests.bat b/build/coverage.bat similarity index 63% rename from build/tests.bat rename to build/coverage.bat index 58708e0fbe..16cb3e6d6a 100644 --- a/build/tests.bat +++ b/build/coverage.bat @@ -1,3 +1,3 @@ @echo off -powershell "Import-Module %~dp0\psake.psm1 ; Invoke-Psake %~dp0\build.ps1 Run-Tests ; exit $LASTEXITCODE" \ No newline at end of file +powershell "Import-Module %~dp0\psake.psm1 ; Invoke-Psake %~dp0\build.ps1 Run-Coverage ; exit $LASTEXITCODE" \ No newline at end of file From 7a85471192e5ceea2d0c7c523bda23c43f6d87da Mon Sep 17 00:00:00 2001 From: Thomas Broust Date: Mon, 22 Sep 2014 17:25:05 +0200 Subject: [PATCH 10/10] Uses a XML config file for the projects instead of having to modify the powershell at each release Former-commit-id: 0860a606aa02bd55b1af1f56eb9cd9c62ed539c6 --- build/Build.ImageProcessor.Plugins.Cair.proj | 54 ------- build/Build.ImageProcessor.Plugins.WebP.proj | 54 ------- build/Build.ImageProcessor.Web.proj | 57 ------- build/Build.ImageProcessor.proj | 54 ------- ...ICSharpCode.SharpZipLib.dll.REMOVED.git-id | 1 - .../MSBuild.Community.Tasks.Targets | 147 ----------------- ...MSBuild.Community.Tasks.chm.REMOVED.git-id | 1 - ...MSBuild.Community.Tasks.dll.REMOVED.git-id | 1 - ...MSBuild.Community.Tasks.xml.REMOVED.git-id | 1 - ...MSBuild.Community.Tasks.xsd.REMOVED.git-id | 1 - build/MSBuildCommunityTasks/Sample.proj | 153 ------------------ build/build.ps1 | 74 +++++---- build/build.xml | 43 +++++ ...UnitHTMLReportGenerator.exe.REMOVED.git-id | 0 .../NUnitHTMLReportGenerator.exe.config | 0 15 files changed, 84 insertions(+), 557 deletions(-) delete mode 100644 build/Build.ImageProcessor.Plugins.Cair.proj delete mode 100644 build/Build.ImageProcessor.Plugins.WebP.proj delete mode 100644 build/Build.ImageProcessor.Web.proj delete mode 100644 build/Build.ImageProcessor.proj delete mode 100644 build/MSBuildCommunityTasks/ICSharpCode.SharpZipLib.dll.REMOVED.git-id delete mode 100644 build/MSBuildCommunityTasks/MSBuild.Community.Tasks.Targets delete mode 100644 build/MSBuildCommunityTasks/MSBuild.Community.Tasks.chm.REMOVED.git-id delete mode 100644 build/MSBuildCommunityTasks/MSBuild.Community.Tasks.dll.REMOVED.git-id delete mode 100644 build/MSBuildCommunityTasks/MSBuild.Community.Tasks.xml.REMOVED.git-id delete mode 100644 build/MSBuildCommunityTasks/MSBuild.Community.Tasks.xsd.REMOVED.git-id delete mode 100644 build/MSBuildCommunityTasks/Sample.proj create mode 100644 build/build.xml rename build/{ => tools}/NUnitHTMLReportGenerator.exe.REMOVED.git-id (100%) rename build/{ => tools}/NUnitHTMLReportGenerator.exe.config (100%) diff --git a/build/Build.ImageProcessor.Plugins.Cair.proj b/build/Build.ImageProcessor.Plugins.Cair.proj deleted file mode 100644 index d4668467da..0000000000 --- a/build/Build.ImageProcessor.Plugins.Cair.proj +++ /dev/null @@ -1,54 +0,0 @@ - - - .\ - - - - - - - - Release - _BuildOutput\ - False - $(MSBuildProjectDirectory)\$(BuildFolder) - $(BuildFolderAbsolutePath)ImageProcessor.Plugins.Cair\lib\net45 - ..\src\Plugins\ImageProcessor\ImageProcessor.Plugins.Cair\ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/Build.ImageProcessor.Plugins.WebP.proj b/build/Build.ImageProcessor.Plugins.WebP.proj deleted file mode 100644 index c2fca90fde..0000000000 --- a/build/Build.ImageProcessor.Plugins.WebP.proj +++ /dev/null @@ -1,54 +0,0 @@ - - - .\ - - - - - - - - Release - _BuildOutput\ - False - $(MSBuildProjectDirectory)\$(BuildFolder) - $(BuildFolderAbsolutePath)ImageProcessor.Plugins.WebP\lib\net45 - ..\src\Plugins\ImageProcessor\ImageProcessor.Plugins.WebP\ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/Build.ImageProcessor.Web.proj b/build/Build.ImageProcessor.Web.proj deleted file mode 100644 index ae6936faf0..0000000000 --- a/build/Build.ImageProcessor.Web.proj +++ /dev/null @@ -1,57 +0,0 @@ - - - .\ - - - - - - - - Release - _BuildOutput\ - False - ..\..\..\build\$(BuildFolder) - $(MSBuildProjectDirectory)\$(BuildFolder) - $(BuildFolder)bin\ - $(BuildFolderRelativeToProjects)bin\ - $(BuildFolderAbsolutePath)ImageProcessor.Web\lib\net45 - ..\src\ImageProcessor.Web\ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/Build.ImageProcessor.proj b/build/Build.ImageProcessor.proj deleted file mode 100644 index 134c1ed9fe..0000000000 --- a/build/Build.ImageProcessor.proj +++ /dev/null @@ -1,54 +0,0 @@ - - - .\ - - - - - - - - Release - _BuildOutput\ - False - $(MSBuildProjectDirectory)\$(BuildFolder) - $(BuildFolderAbsolutePath)ImageProcessor\lib\net45 - ..\src\ImageProcessor\ - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/MSBuildCommunityTasks/ICSharpCode.SharpZipLib.dll.REMOVED.git-id b/build/MSBuildCommunityTasks/ICSharpCode.SharpZipLib.dll.REMOVED.git-id deleted file mode 100644 index 0dc5124b53..0000000000 --- a/build/MSBuildCommunityTasks/ICSharpCode.SharpZipLib.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -77bafe8ba867a1618b8735200289f6fad68b825e \ No newline at end of file diff --git a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.Targets b/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.Targets deleted file mode 100644 index 875d7c4c84..0000000000 --- a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.Targets +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - $(MSBuildExtensionsPath)\MSBuildCommunityTasks - $(MSBuildCommunityTasksPath)\MSBuild.Community.Tasks.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.chm.REMOVED.git-id b/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.chm.REMOVED.git-id deleted file mode 100644 index 0863f2d0fa..0000000000 --- a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.chm.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -e9cfb77efd964e4fb6659c0c2cc9bc934b7edb17 \ No newline at end of file diff --git a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.dll.REMOVED.git-id b/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.dll.REMOVED.git-id deleted file mode 100644 index 0c5894f4d6..0000000000 --- a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.dll.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -3d1dbd357f5e4ae47bf017d4227811bd052b5347 \ No newline at end of file diff --git a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.xml.REMOVED.git-id b/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.xml.REMOVED.git-id deleted file mode 100644 index 7bdd152c52..0000000000 --- a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.xml.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -0ddc819937fec260f50b99350f7643feced88342 \ No newline at end of file diff --git a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.xsd.REMOVED.git-id b/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.xsd.REMOVED.git-id deleted file mode 100644 index c226e06db1..0000000000 --- a/build/MSBuildCommunityTasks/MSBuild.Community.Tasks.xsd.REMOVED.git-id +++ /dev/null @@ -1 +0,0 @@ -14f9e4c08f357d1b2f185dbe24df292ce74ef064 \ No newline at end of file diff --git a/build/MSBuildCommunityTasks/Sample.proj b/build/MSBuildCommunityTasks/Sample.proj deleted file mode 100644 index 3b52ad68c9..0000000000 --- a/build/MSBuildCommunityTasks/Sample.proj +++ /dev/null @@ -1,153 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - list = new List(); - list.Add("Happy"); - list.Add("New"); - list.Add("Year"); - Console.WriteLine("Hello MSBuild Community Scripting World."); - foreach(string s in list) - { - Console.WriteLine(s); - } - } - ]]> - - - - -