예제 #1
0
        void TemplateProcessed(TemplateProcessed obj)
        {
            if (obj.Template.EndsWith("XamarinApp.sln"))
            {
                // we have to check based upon the SolutionIdentifier because when this file is processed the projects itself are not copied yet (or are skipped)
                // therefore they will be marked as NotFound, and not able to identity the type; solutionIdentifier can always be used

                var solution = FluentMSBuild.Use(obj.File).Solution;
                if (!Configuration.UseIOS)
                {
                    var projects = solution.Projects.Where(q => q.SolutionIdentifier == "XamarinApp.iOS");
                    RemoveProjects(projects, solution);
                    solution.RemoveConfigurations(ProjectSubType.XamarinIOS);
                }

                if (!Configuration.UseAndroid)
                {
                    var projects = solution.Projects.Where(q => q.SolutionIdentifier == "XamarinApp.Android");
                    RemoveProjects(projects, solution);
                }
            }

            void RemoveProjects(IEnumerable <Project> projects, Solution solution)
            {
                foreach (var project in projects)
                {
                    solution.Remove(project);
                }
            }
        }
예제 #2
0
        public override void Execute()
        {
            // ViewModel
            var viewModelFile       = Path.Combine(TemplatePath, "{{ Name }}.cs");
            var viewModelTargetFile = Path.Combine(WorkingDirectory, TargetFileName(viewModelFile, TemplatePath));

            viewModelTargetFile = FluentHandlebars.Create(this)
                                  .WithAllHelpers()
                                  .HavingModel(Configuration)
                                  .UsingFileTemplate(viewModelFile)
                                  .OutputFile(viewModelTargetFile, false); //DO NOT OVERWRITE ViewModel

            FluentMSBuild.Use(viewModelTargetFile)
            .WithBuildAction(BuildAction.Compile)
            .AddToProject();

            // generated ViewModel
            var generatedViewModelFile       = Path.Combine(TemplatePath, "{{ Name }}.generated.cs");
            var generatedViewModelTargetFile = Path.Combine(WorkingDirectory, TargetFileName(generatedViewModelFile, TemplatePath));

            generatedViewModelTargetFile = FluentHandlebars.Create(this)
                                           .WithAllHelpers()
                                           .WithCustomHelper(Helpers)
                                           .HavingModel(Configuration)
                                           .UsingFileTemplate(generatedViewModelFile)
                                           .OutputFile(generatedViewModelTargetFile, true);

            FluentMSBuild.Use(generatedViewModelTargetFile)
            .WithBuildAction(BuildAction.Compile)
            .WithDependencyOn(viewModelTargetFile)
            .AddToProject();

            FluentMSBuild.Use(InputFileName)
            .WithBuildAction(BuildAction.None)
            .WithDependencyOn(viewModelTargetFile)
            .AddToProject();
        }
        public override void Execute()
        {
            // get and write asset log
            var assetLogFile = Path.Combine(WorkingDirectory, "assets-log.json");

            if (!File.Exists(assetLogFile))
            {
                File.WriteAllText(assetLogFile, string.Empty);
            }

            var assetLogs         = new List <AssetLog>();
            var assetLogsContents = File.ReadAllText(assetLogFile);

            if (!string.IsNullOrEmpty(assetLogsContents))
            {
                assetLogs = assetLogsContents.FromJson <List <AssetLog> >();
            }

            var needToUpdateLog = false;

            if (!string.IsNullOrEmpty(Configuration.AssetDefault?.Pattern))
            {
                var files = Directory.GetFiles(Path.Combine(WorkingDirectory, Configuration.AssetsPath), Configuration.AssetDefault.Pattern);
                foreach (var file in files)
                {
                    var fileName = new FileInfo(file).Name;
                    if (Configuration.Assets.FirstOrDefault(q => q.File == fileName) == null)
                    {
                        Configuration.Assets.Add(new AssetClass()
                        {
                            File = fileName
                        });
                    }
                }
            }

            if (!string.IsNullOrEmpty(Configuration.AssetDefault?.Size))
            {
                foreach (var asset in Configuration.Assets)
                {
                    if (string.IsNullOrEmpty(asset.Size))
                    {
                        asset.Size = Configuration.AssetDefault.Size;
                    }
                }
            }

            foreach (var asset in Configuration.Assets)
            {
                var path = Path.Combine(WorkingDirectory, Configuration.AssetsPath, asset.File);
                if (!File.Exists(path))
                {
                    Log.Error($"Could not find {asset.File} in {Configuration.AssetsPath}");
                    continue;
                }

                var assetFileInfo = new FileInfo(path);
                var found         = assetLogs.FirstOrDefault(a => a.AssetFile == asset.File);

                if (found == null)
                {
                    assetLogs.Add(new AssetLog()
                    {
                        AssetFile   = asset.File,
                        LastUpdated = assetFileInfo.LastWriteTimeUtc,
                        FileSize    = assetFileInfo.Length,
                        Size        = asset.Size
                    });
                }
                else
                {
                    if (found.FileSize == assetFileInfo.Length && found.LastUpdated == assetFileInfo.LastWriteTimeUtc && found.Size == asset.Size)
                    {
                        Log.Debug($"Skipping {asset.File} - No Change");
                        continue;
                    }

                    found.LastUpdated = assetFileInfo.LastWriteTimeUtc;
                    found.FileSize    = assetFileInfo.Length;
                    found.Size        = asset.Size;
                }

                needToUpdateLog = true;
                Log.Information($"Processing {asset.File}");

                var svg = new SKSvg();
                svg.Load(path);

                var sourceActualWidth  = svg.Picture.CullRect.Width;
                var sourceActualHeight = svg.Picture.CullRect.Height;

                var wantedBaseWidth  = 0.0F;
                var wantedBaseHeight = 0.0F;

                if (!string.IsNullOrEmpty(asset.Size))
                {
                    var sizeParts = asset.Size.Split('x');
                    if (sizeParts.Length == 2)
                    {
                        var widthOk  = float.TryParse(sizeParts[0], NumberStyles.Integer, new CultureInfo("en-US"), out wantedBaseWidth);
                        var heightOk = float.TryParse(sizeParts[1], NumberStyles.Integer, new CultureInfo("en-US"), out wantedBaseHeight);

                        if (!widthOk)
                        {
                            wantedBaseWidth = sourceActualWidth;
                        }
                        if (!heightOk)
                        {
                            wantedBaseHeight = sourceActualHeight;
                        }
                    }
                }
                else
                {
                    wantedBaseWidth  = sourceActualWidth;
                    wantedBaseHeight = sourceActualHeight;
                }

                var nominalRatio = Math.Max((double)wantedBaseWidth / (double)sourceActualWidth, (double)wantedBaseHeight / (double)sourceActualHeight);

                foreach (var platform in Configuration.Platforms)
                {
                    var configs = new List <Output>();
                    switch (platform.Type)
                    {
                    case Platforms.iOS:
                        configs.AddRange(new[]
                        {
                            new Output()
                            {
                                Ratio = 1
                            },
                            new Output()
                            {
                                Ratio = 2, Suffix = "@2x"
                            },
                            new Output()
                            {
                                Ratio = 3, Suffix = "@3x"
                            }
                        });
                        break;

                    case Platforms.Android:
                    {
                        var folderPrefix = "mipmap";
                        if (platform.AndroidOptions != null && !string.IsNullOrEmpty(platform.AndroidOptions.AssetFolderPrefix.ToString()))
                        {
                            folderPrefix = platform.AndroidOptions.AssetFolderPrefix.ToString();
                        }

                        configs.AddRange(new[]
                            {
                                new Output()
                                {
                                    Ratio = 1.0, Path = $"{folderPrefix}-mdpi"
                                },
                                new Output()
                                {
                                    Ratio = 1.5, Path = $"{folderPrefix}-hdpi"
                                },
                                new Output()
                                {
                                    Ratio = 2, Path = $"{folderPrefix}-xhdpi"
                                },
                                new Output()
                                {
                                    Ratio = 3, Path = $"{folderPrefix}-xxhdpi"
                                },
                                new Output()
                                {
                                    Ratio = 4, Path = $"{folderPrefix}-xxxhdpi"
                                },
                            });
                        break;
                    }

                    case Platforms.UWP:
                        configs.AddRange(new[]
                        {
                            new Output()
                            {
                                Ratio = 1.0, Suffix = ".scale-100"
                            },
                            new Output()
                            {
                                Ratio = 1.25, Suffix = ".scale-125"
                            },
                            new Output()
                            {
                                Ratio = 1.50, Suffix = ".scale-150"
                            },
                            new Output()
                            {
                                Ratio = 2, Suffix = ".scale-200"
                            },
                            new Output()
                            {
                                Ratio = 4, Suffix = ".scale-400"
                            },
                        });
                        break;

                    default:
                        throw new ArgumentOutOfRangeException();
                    }

                    foreach (var config in configs)
                    {
                        var destinationFolder = "Resources";
                        if (platform.Type == Platforms.UWP)
                        {
                            destinationFolder = "Assets";
                        }
                        var destinationFile = Path.Combine(WorkingDirectory, platform.ProjectPath, destinationFolder);

                        if (string.IsNullOrEmpty(config.Path))
                        {
                            destinationFile = Path.Combine(destinationFile, $"{asset.GetSafeFile().Replace(".svg", "")}{config.Suffix}.png");
                        }
                        else
                        {
                            destinationFile = Path.Combine(destinationFile, config.Path, $"{asset.GetSafeFile().Replace(".svg", ".png")}");
                        }

                        var destinationPath = new FileInfo(destinationFile);
                        if (!Directory.Exists(destinationPath.DirectoryName))
                        {
                            Directory.CreateDirectory(destinationPath.DirectoryName);
                        }

                        var resizeRatio = config.Ratio;

                        var adjustRatio  = nominalRatio * resizeRatio;
                        var scaledWidth  = sourceActualWidth * adjustRatio;
                        var scaledHeight = sourceActualHeight * adjustRatio;

                        var bmp    = new SKBitmap((int)scaledWidth, (int)scaledHeight);
                        var canvas = new SKCanvas(bmp);

                        // Make a matrix to scale the SVG
                        var matrix = SKMatrix.MakeScale((float)adjustRatio, (float)adjustRatio);

                        canvas.Clear(SKColors.Transparent);

                        // Draw the svg onto the canvas with our scaled matrix
                        canvas.DrawPicture(svg.Picture, ref matrix);

                        // Save the op
                        canvas.Save();

                        // Export the canvas
                        var img = SKImage.FromBitmap(bmp);

                        var data = img.Encode(SKEncodedImageFormat.Png, 100);
                        using (var fs = File.Open(destinationFile, FileMode.Create))
                        {
                            data.SaveTo(fs);
                        }

                        switch (platform.Type)
                        {
                        case Platforms.iOS:
                            FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.BundleResource).AddToProject();
                            break;

                        case Platforms.Android:
                            FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.AndroidResource).AddToProject();
                            break;

                        case Platforms.UWP:
                            FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.Content).AddToProject();
                            break;
                        }
                    }
                }
            }

            if (needToUpdateLog)
            {
                File.WriteAllText(assetLogFile, assetLogs.ToJson());
            }
        }
        public override void Execute()
        {
            JsConfig.IncludeNullValues  = false;
            JsConfig.EmitCamelCaseNames = true;

            foreach (var platform in Configuration.Platforms)
            {
                var fileName = Path.Combine(WorkingDirectory, platform.IconFileName);
                var fileInfo = new FileInfo(fileName);
                if (!File.Exists(fileInfo.FullName))
                {
                    Log.Error($"Icon not found ({fileInfo.FullName})");
                    continue;
                }

                var svg = SkiaHelper.Load(fileInfo.FullName);

                var sourceActualWidth  = svg.Picture.CullRect.Width;
                var sourceActualHeight = svg.Picture.CullRect.Height;


                var assets = new List <ExportAsset>();

                var platformPath = new DirectoryInfo(Path.Combine(WorkingDirectory, platform.ProjectPath));
                if (!platformPath.Exists)
                {
                    Log.Error($"Platform path for {platform.Type} not found ({platformPath.FullName})");
                    continue;
                }

                switch (platform.Type)
                {
                case Platforms.iOS:
                {
                    var targetPath = Path.Combine(platformPath.FullName, "Assets.xcassets", "AppIcon.appiconset");
                    var sizes      = new[] { 20, 29, 40, 58, 60, 76, 80, 87, 120, 152, 167, 180, 1024 };
                    assets.AddRange(sizes.Select(size => new ExportAsset(fileInfo.FullName, targetPath, $"Icon-App-{size}x{size}.png", sourceActualWidth, sourceActualHeight, size, size)));
                    break;
                }

                case Platforms.AppleWatch:
                {
                    var targetPath = Path.Combine(platformPath.FullName, "Assets.xcassets", "AppIcon.appiconset");
                    var sizes      = new[] { 48, 55, 58, 80, 87, 88, 172, 196 };
                    assets.AddRange(sizes.Select(size => new ExportAsset(fileInfo.FullName, targetPath, $"Icon-App-{size}x{size}.png", sourceActualWidth, sourceActualHeight, size, size)));
                    break;
                }

                case Platforms.MacOs:
                {
                    var targetPath = Path.Combine(platformPath.FullName, "Assets.xcassets", "AppIcon.appiconset");
                    var sizes      = new[] { 16, 32, 64, 128, 256, 512, 1024 };
                    assets.AddRange(sizes.Select(size => new ExportAsset(fileInfo.FullName, targetPath, $"Icon-App-{size}x{size}.png", sourceActualWidth, sourceActualHeight, size, size)));
                    break;
                }

                case Platforms.Android:
                {
                    var folderPrefix = "mipmap";
                    if (platform.AndroidOptions != null && !string.IsNullOrEmpty(platform.AndroidOptions.AssetFolderPrefix.ToString()))
                    {
                        folderPrefix = platform.AndroidOptions.AssetFolderPrefix.ToString();
                    }
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-mdpi"), "Icon.png", sourceActualWidth, sourceActualHeight, 48,
                                               48));
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-hdpi"), "Icon.png", sourceActualWidth, sourceActualHeight, 72,
                                               72));
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-xhdpi"), "Icon.png", sourceActualWidth, sourceActualHeight, 96,
                                               96));
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-xxhdpi"), "Icon.png", sourceActualWidth, sourceActualHeight,
                                               144, 144));
                    assets.Add(new ExportAsset(fileInfo.FullName, Path.Combine(platformPath.FullName, "Resources", $"{folderPrefix}-xxxhdpi"), "Icon.png", sourceActualWidth, sourceActualHeight,
                                               192, 192));
                    break;
                }

                case Platforms.UWP:
                {
                    // https://docs.microsoft.com/en-us/windows/uwp/design/shell/tiles-and-notifications/app-assets#asset-size-tables
                    var targetPath = Path.Combine(platformPath.FullName, "Assets");
                    var sizes      = new[] { 71, 150, 310, 44 };
                    var scales     = new[] { 100, 125, 150, 200, 400 };
                    foreach (var size in sizes)
                    {
                        assets.AddRange(scales.Select(scale =>
                                                      new ExportAsset(fileInfo.FullName, targetPath, $"Square{size}x{size}Logo.scale-{scale}.png", sourceActualWidth, sourceActualHeight, size, size)));
                    }
                    break;
                }

                default:
                    throw new ArgumentOutOfRangeException();
                }

                foreach (var asset in assets)
                {
                    var bmp    = new SKBitmap((int)asset.ScaledWidth, (int)asset.ScaledHeight);
                    var canvas = new SKCanvas(bmp);
                    var matrix = SKMatrix.MakeScale((float)asset.Ratio, (float)asset.Ratio);
                    canvas.Clear(SKColors.Transparent);
                    canvas.DrawPicture(svg.Picture, ref matrix);
                    canvas.Save();

                    // Export the canvas
                    var img = SKImage.FromBitmap(bmp);

                    var data = img.Encode(SKEncodedImageFormat.Png, 100);
                    asset.FileName.EnsureFolderExists();
                    using (var fs = File.Open(asset.FileName, FileMode.Create))
                    {
                        Log.Information($"Writing {asset.FileName}");
                        data.SaveTo(fs);
                    }

                    var platformProjectFolder = Path.Combine(WorkingDirectory, platform.ProjectPath);

                    var destinationFolder = "Resources";
                    if (platform.Type == Platforms.UWP)
                    {
                        destinationFolder = "Assets";
                    }
                    var destinationFile = Path.Combine(WorkingDirectory, platform.ProjectPath, destinationFolder, asset.FileName);

                    switch (platform.Type)
                    {
                    case Platforms.iOS:
                    case Platforms.AppleWatch:
                    case Platforms.MacOs:
                        FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.ImageAsset).AddToProject();
                        break;

                    case Platforms.Android:
                        FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.AndroidResource).AddToProject();
                        break;

                    case Platforms.UWP:
                        FluentMSBuild.Use(destinationFile).WithBuildAction(BuildAction.Content).AddToProject();
                        break;
                    }
                }

                if (platform.Type == Platforms.iOS || platform.Type == Platforms.AppleWatch || platform.Type == Platforms.MacOs)
                {
                    var contentsFile = Path.Combine(platformPath.FullName, "Assets.xcassets", "AppIcon.appiconset", "Contents.json");
                    Log.Information($"Writing {contentsFile}");

                    var contents = File.ReadAllText(contentsFile).FromJson <XcodeContents>();

                    foreach (var contentsImage in contents.Images)
                    {
                        var process = false;
                        switch (platform.Type)
                        {
                        case Platforms.iOS when contentsImage.Idiom == "iphone" || contentsImage.Idiom == "ipad" || contentsImage.Idiom == "ios-marketing":
                        case Platforms.AppleWatch when contentsImage.Idiom == "watch":
                        case Platforms.MacOs when contentsImage.Idiom == "mac":
                            process = true;
                            break;
                        }

                        if (process)
                        {
                            // calculate needed size
                            var size  = double.Parse(contentsImage.Size.Split('x')[0], NumberStyles.Float, new CultureInfo("en-US"));
                            var scale = double.Parse(contentsImage.Scale.Substring(0, 1));

                            var foundSize = assets.FirstOrDefault(a => a.ScaledWidth == size * scale);
                            if (foundSize != null)
                            {
                                contentsImage.Filename = new FileInfo(foundSize.FileName).Name;
                            }
                        }
                    }

                    File.WriteAllText(contentsFile, contents.ToJson().IndentJson());
                }
            }
        }
예제 #5
0
        protected override int Execute()
        {
            base.Execute();

            // find csproj
            var csproj = Directory.GetFiles(WorkingDirectory, "*.csproj", SearchOption.AllDirectories).FirstOrDefault();

            if (csproj == null)
            {
                Log.Fatal($"Could not find .csproj in underlying folders of {WorkingDirectory}");
            }

            // increase
            var addBuild = !(!BuildOption.HasValue() && (MajorOption.HasValue() || MinorOption.HasValue()));

            FluentMSBuild.Use(csproj).IncrementVersion(MajorOption.HasValue(), MinorOption.HasValue(), addBuild);

            // Creating temporary folder
            var tempFolder = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

            Log.Debug($"Creating temp folder {tempFolder}");
            Directory.CreateDirectory(tempFolder);

            Log.Information("Packing generator...");
            DotNetRunner.Pack(tempFolder);

            var nupkg     = Directory.GetFiles(tempFolder, "*.nupkg").FirstOrDefault();
            var nupkgFile = new FileInfo(nupkg).Name;

            Log.Information($"Pushing generator {nupkgFile}");

            var source = string.Empty;
            var apiKey = string.Empty;

            if (SourceOption.HasValue())
            {
                source = SourceOption.ParsedValue.FromEnvironmentOrDefault();
                if (string.IsNullOrEmpty(source))
                {
                    Log.Fatal("When specifying --source your need to add a valid source (--source https://{YourUrl})");
                }
            }

            if (ApiKeyOption.HasValue())
            {
                apiKey = ApiKeyOption.ParsedValue.FromEnvironmentOrDefault();
                if (string.IsNullOrEmpty(apiKey))
                {
                    Log.Fatal("When specifying --apikey your need to add a valid api key (--apikey YourKey");
                }
            }

            var nugetPush = DotNetRunner.NugetPush(nupkg, source, apiKey);

            if (nugetPush == 0)
            {
                Log.Information("Package was pushed");
                DotNetRunner.InstallOrUpdateLocal(nupkgFile, tempFolder);
                Log.Information("Genyman generator was installed locally");
            }
            else
            {
                Log.Information("Skipping local installation of Genyman generator - Nuget Failed");
            }

            // Cleanup

            var files = Directory.GetFiles(tempFolder);

            foreach (var file in files)
            {
                Log.Debug($"Cleanup. Deleting file {file}");
                File.Delete(file);
            }

            Log.Debug($"Cleanup. Deleting folder {tempFolder}");
            Directory.Delete(tempFolder);


            return(0);
        }