public StageSourceDirectory ExpandStages(string challenge, Stage toStage = null)
        {
            var challengeSource = _filesystem.ChallengesSource.Challenges[challenge];
            if (toStage == null)
            {
                var lastStageDir = challengeSource.Stages.Last(s => 
                    s.Name().StartsWith("stage", StringComparison.OrdinalIgnoreCase));
                toStage = Stage.Parse(lastStageDir.Name());
            }

            var challengeTarget = _filesystem.Expand.Challenges[challenge];
            StageSourceDirectory priorTarget = null;
            for (var stage = Stage.Zero; stage.Number <= toStage.Number; stage = stage + 1)
            {
                var source = challengeSource.Stage(stage);
                var target = challengeTarget.Stage(stage);

                target.DeleteContents();

                if (priorTarget != null)
                {
                    priorTarget.CopyContentsInto(target);
                }

                source.CopyContentsInto(target);
                priorTarget = target;
            }

            return priorTarget;
        }
        public override bool Execute()
        {
            var challengeDir = _dcsFiles.ChallengesSource.Challenges[Challenge];
            StageSourceDirectory sourceDir = null;
            var stage = new Stage(Stage);
            sourceDir = stage.Number == 0
                ? challengeDir.Stage("tip")
                : _expandedChallenges.ExpandStages(Challenge, new Stage(Stage - 1));
            var targetDir = challengeDir.Stage(stage);

            _log.InfoFormat("{0} -> {1}", sourceDir, targetDir);
            targetDir.DeleteContents();
            targetDir.Create();
            sourceDir.CopyContentsInto(targetDir);
            return true;
        }
        public override bool Execute()
        {
            if (Stage == 0)
            {
                throw new Exception("Cannot winnow stage 0");
            }

            var stage = new Stage(Stage);
            var challengeDir = _dcsFiles.ChallengesSource.Challenges[Challenge];
            var stageDir = challengeDir.Stage(stage);
            _log.InfoFormat("Winnowing stage dir {0}", stageDir);

            var priorStageExpanded = _expandedChallenges.ExpandStages(Challenge, stage - 1);
            foreach (var file in stageDir.Recurse().OfType<IFile>())
            {
                string relativePath = file.PathRelativeFrom(stageDir);
                var priorFile = priorStageExpanded.File(relativePath);
                if (priorFile.ContentsAreEqualTo(file))
                {
                    _log.DebugFormat("{0} X", file);
                    file.Delete();
                }

                // alternate diff method using Git diff
                //var priorInfo = priorFile.Info();
                //var fileInfo = file.Info();
                //if (priorInfo.Exists
                //    && priorInfo.Length == fileInfo.Length
                //    || _shell.RunBackground("diff", "{0} {1}".FormatFrom(priorFile, file)) == 0)
            }

            foreach (var dir in stageDir.Recurse().OfType<IDirectory>().Reverse())
            {
                if (dir.IsEmpty())
                {
                    dir.Delete();
                }
            }

            return true;
        }
 public StageSourceDirectory Stage(Stage stage)
 {
     return Stage(stage.Name);
 }
        public override bool Execute()
        {
            if (!To.HasValue && From.HasValue)
            {
                To = From;
            }
            if (!From.HasValue && To.HasValue)
            {
                From = To;
            }

            if (From > To)
            {
                throw new Exception("Invalid args");
            }

            _log.Debug("Cleaning up orphan processes");
            _killOrphansOperation.Execute();

            var challengeDir = _dcsFilesystem.ChallengesSource.Challenges[Challenge];
            if (Solution == null)
            {
                Solution = challengeDir.Stage(new Stage(0)).Solutions.Single().Key;
            }
            _log.InfoFormat("Using challenge {0}", Challenge);
            _log.InfoFormat("Using solution {0}", Solution);

            var expandedChallenge = _expandedChallenges.GetExpandedChallenge(Challenge);
            bool passed = true;

            for (var stage = new Stage(From.Value); stage.Number <= To.Value; stage += 1)
            {
                var expandedStage = expandedChallenge.Stage(stage);

                var stageBuildDir = _dcsFilesystem.CreateBuildDir("{0}-{1}".FormatFrom(Challenge, stage));

                _log.InfoFormat("Copying content into {0}", stageBuildDir);
                expandedStage.CopySolutionIntoBuildDir(Solution, stageBuildDir);

                _log.InfoFormat("Testing {0}", stageBuildDir);
                var assessment = _assessmentService.Assess(Challenge, stage, stageBuildDir);
                string output = assessment.BuildOutput;
                assessment.BuildOutput = output.Left(200);
                if (assessment.Outcome != AssessmentOutcome.Success)
                {
                    passed = false;
                    _log.Warn(JsonConvert.SerializeObject(assessment));
                    _log.Debug(output);

                    System.Console.WriteLine(output);
                }
                else
                {
                    _log.Info(JsonConvert.SerializeObject(assessment));
                    _log.Debug(output);
                }

                if (Cleanup)
                {
                    Thread.Sleep(50);
                    if (!FuncUtil.TryExecute(stageBuildDir.Delete))
                    {
                        _log.WarnFormat("Failed to clean up build dir {0}", stageBuildDir);
                    }
                }
            }

            _log.Info(passed ? "Stages passed" : "Stages failed");

            return passed;
        }
        public AssessmentResult Assess(string challenge, Stage stage, StageBuildDirectory stageBuildDir)
        {
            // get solution settings

            var settingsFile = stageBuildDir.SolutionConfigFile;
            if (!settingsFile.Exists())
            {
                return new AssessmentResult(AssessmentOutcome.InvalidContent)
                {
                    Message = "Could not find solution-config.json in the solution root",
                };
            }
            var solutionSettings = settingsFile.Read();
            if (string.IsNullOrEmpty(solutionSettings.Run))
            {
                return new AssessmentResult(AssessmentOutcome.InvalidContent)
                {
                    Message = "'start' param not provided in solution-config.json",
                };
            }

            // build solution

            if (solutionSettings.MsBuild != null)
            {
                string buildSolution = stageBuildDir.File(solutionSettings.MsBuild).Path;
                _log.DebugFormat("Building {0}", buildSolution);
                var buildProcessStart = new ProcessStartInfo("msbuild", buildSolution);

                using (var buildRun = ProcessRun.Start(buildProcessStart))
                {
                    if (!buildRun.Task.Wait(TimeSpan.FromSeconds(15)))
                    {
                        buildRun.Kill();
                        return new AssessmentResult(AssessmentOutcome.BuildFailure)
                        {
                            Message = "Build timed out",
                            BuildOutput = buildRun.Task.Result.StandardOutput,
                        };
                    }

                    if (buildRun.Task.Result.ExitCode != 0)
                    {
                        return new AssessmentResult(AssessmentOutcome.BuildFailure)
                        {
                            Message = "Build failed",
                            BuildOutput = buildRun.Task.Result.OutputSummary,
                        };
                    }
                }
            }

            // get start file

            var startFile = stageBuildDir.File(solutionSettings.Run);
            _log.DebugFormat("Starting {0}", startFile);
            if (!startFile.Exists())
            {
                return new AssessmentResult(AssessmentOutcome.BuildFailure)
                {
                    Message = string.Format("Could not find executable {0} specified in solution-config.json",
                        solutionSettings.Run),
                };
            }

            // update features

            var stageExpandedDir = _expandedChallenges
                .GetExpandedChallenge(challenge)
                .Stage(stage);
            if (!stageBuildDir.PathEquals(stageExpandedDir))
            {
                var buildFeaturesDir = stageBuildDir.Directory("features");
                buildFeaturesDir.DeleteContents();
                stageExpandedDir.Directory("features").CopyContentsInto(buildFeaturesDir);
            }

            // run assessment

            _log.DebugFormat("Starting solution assessment {0} {1}", startFile, stageBuildDir);
            var result = _runner.Run(startFile, stageBuildDir);
            return result;
        }