예제 #1
0
        /// <summary>
        /// replaces all flavor statements with the correct flavor content in this string
        /// </summary>
        /// <param name="s">the string to flavor</param>
        /// <param name="activeFlavors">a list of active flavors</param>
        /// <param name="logSession">log session for logging</param>
        /// <returns>the flavored string</returns>
        public string FlavorString(string s, List <string> activeFlavors, Log.AsyncLogSession logSession)
        {
            //repeatedly replace statements with their flavor content
            Match statementMatch = null;
            Dictionary <string, string> flavors;

            do
            {
                //match string using regex, match the first statement
                statementMatch = Regex.Match(s, FLAVOR_STATEMENT_PATTERN);
                if (!statementMatch.Success)
                {
                    continue;
                }

                //get full statement AND expression from match
                string statement  = statementMatch.Value;
                string expression = statementMatch.Groups[1].Value;
                logSession?.vv($"process statement {statement}");

                //skip if expression is empty
                if (string.IsNullOrWhiteSpace(expression))
                {
                    break;
                }

                //get flavors for expression, skip if there are none
                flavors = GetFlavorsFromExpression(expression, logSession);
                if (flavors == null || flavors.Count <= 0)
                {
                    break;
                }

                //get the correct flavor to use, skip if none of the flavors is valid
                string flavor = GetFirstFlavor(flavors.Keys, activeFlavors);

                //get the right content for the flavor, default to string.Empty
                string flavorContent = string.Empty;
                if (string.IsNullOrWhiteSpace(flavor))
                {
                    logSession?.w($"no active flavor for {statement}, fallback to empty");
                }
                else
                {
                    flavorContent = flavors[flavor];
                    if (string.IsNullOrWhiteSpace(flavorContent))
                    {
                        logSession?.w($"flavor content for flavor {flavor} is empty!");
                    }
                }

                //replace flavor statement with content
                logSession?.d($"replacing {statement} with {flavorContent}...");
                s = s.ReplaceFirst(statement, flavorContent);
            }while (statementMatch.Success);
            return(s);
        }
예제 #2
0
        /// <summary>
        /// Flavor a project directory
        /// </summary>
        /// <param name="inputDir">the directory to flavor</param>
        /// <param name="outputDir">where the project directory is mirrored to, flavored</param>
        /// <param name="activeFlavors">a list of all active flavors</param>
        /// <param name="parallelProcessing">should files be processed in parallel?</param>
        public void FlavorProject(DirectoryInfo inputDir, DirectoryInfo outputDir, List <string> activeFlavors, bool parallelProcessing = false)
        {
            //counters for flavoring results
            int flavoredChanged   = 0,
                flavoredUnchanged = 0,
                copied            = 0,
                skipped           = 0;

            //setup function for each file (~= loop body)
            Action <FileInfo> processAction = (FileInfo input) =>
            {
                using (Log.AsyncLogSession logSession = Log.StartAsync())
                {
                    //set tag of session
                    logSession.PushTag(input.Name);

                    //create output fileinfo
                    FileInfo output = new FileInfo(Path.Combine(outputDir.FullName, Path.GetRelativePath(inputDir.FullName, input.FullName)));

                    //flavor the file, count results
                    switch (FlavorFile(input, output, activeFlavors, logSession))
                    {
                    case FlavorResult.FlavoredReplace:
                        flavoredChanged++;
                        break;

                    case FlavorResult.FlavoredSkipped:
                        flavoredUnchanged++;
                        break;

                    case FlavorResult.Copied:
                        copied++;
                        break;

                    case FlavorResult.Skipped:
                        skipped++;
                        break;
                    }
                }
            };

            //enumerate files
            if (parallelProcessing)
            {
                inputDir.EnumerateAllFilesParallel("*.*", true, processAction);
            }
            else
            {
                inputDir.EnumerateAllFiles("*.*", true, processAction);
            }

            //log results
            Log.i($"Finished processing. {flavoredChanged} flavored files changed, {flavoredUnchanged} unchanged, {copied} files copied and {skipped} files skipped entirely.");
        }
예제 #3
0
        /// <summary>
        /// flavor a single file
        /// </summary>
        /// <param name="input">input file to flavor</param>
        /// <param name="output">where the file is mirrored to, flavored</param>
        /// <param name="activeFlavors">a list of all active flavors</param>
        /// <param name="logSession">logging session for this file</param>
        public FlavorResult FlavorFile(FileInfo input, FileInfo output, List <string> activeFlavors, Log.AsyncLogSession logSession)
        {
            //check filter first
            bool shouldFlavor = FlavorFilter.MatchesFilter(input);

            //check if file should be included
            if (!IncludeFilter.ShouldInclude(input, output, shouldFlavor))
            {
                logSession?.v("Skipping file: does not match includeFilter!");
                return(FlavorResult.Skipped);
            }

            //check if file should be flavored or just copied
            if (shouldFlavor)
            {
                //process into a temp file
                FileInfo temp = new FileInfo(Path.GetTempFileName());
                using (StreamReader inputStream = input.OpenText())
                    using (StreamWriter outputStream = temp.CreateText())
                    {
                        seasoner.FlavorStream(inputStream, outputStream, activeFlavors, logSession);
                    }

                //check if old output and temp file are the same
                if (output.Exists && FileComparator.IsSameFile(output, temp))
                {
                    logSession.v("old processed file matches the new one, not replacing");
                    temp.Delete();
                    return(FlavorResult.FlavoredSkipped);
                }
                else
                {
                    //not equal, move temp to output
                    string delTemp = temp.FullName;
                    temp.MoveTo(output.FullName, true);
                    IncludeFilter.PostProcessed(input, output);

                    //delete old temp file
                    if (File.Exists(delTemp))
                    {
                        File.Delete(delTemp);
                    }
                    return(FlavorResult.FlavoredReplace);
                }
            }
            else
            {
                //check if file in output is the same as in input
                if (output.Exists && FileComparator.IsSameFile(input, output))
                {
                    logSession.v("old copied file matches file in input, skipping");
                    return(FlavorResult.Skipped);
                }

                //copy file from input to output
                input.CopyTo(output.FullName, true);
                IncludeFilter.PostProcessed(input, output);
                return(FlavorResult.Copied);
            }
        }
예제 #4
0
        /// <summary>
        /// flavors a stream of text
        /// </summary>
        /// <param name="input">the input stream (eg. source file)</param>
        /// <param name="output">the output file (eg. output file)</param>
        /// <param name="activeFlavors">a list of currently active flavors</param>
        /// <param name="logSession">log session for logging</param>
        public void FlavorStream(StreamReader input, StreamWriter output, List <string> activeFlavors, Log.AsyncLogSession logSession)
        {
            //log processing the file
            logSession?.v($"Start processing stream...");

            //process line by line
            string ln;
            int    lnCount = 0;

            while ((ln = input.ReadLine()) != null)
            {
                //set logging tag
                logSession?.PushTag($"{logSession?.GetTag()}:{lnCount++}");

                //flavor string and write to output
                ln = FlavorString(ln, activeFlavors, logSession);
                output.WriteLine(ln);

                //pop back tag
                logSession?.PopTag();
            }
        }
예제 #5
0
        /// <summary>
        /// splits the expression list into flavor/content pairs
        /// </summary>
        /// <param name="expression">the expression to split into pairs</param>
        /// <returns>the flavor/content pairs</returns>
        Dictionary <string /*flavor name*/, string /*flavor content*/> GetFlavorsFromExpression(string expression, Log.AsyncLogSession logSession)
        {
            //init dictionary to hold results
            Dictionary <string, string> flavorDict = new Dictionary <string, string>();

            //match all expressions
            MatchCollection expressionMatches = Regex.Matches(expression, FLAVOR_EXPRESSION_PATTERN);

            logSession?.d($"Processing expressions for {expression}, found {expressionMatches.Count} matches.");
            if (expressionMatches.Count <= 0)
            {
                return(null);
            }

            //enumerate all expressionss
            foreach (Match expressionMatch in expressionMatches)
            {
                //skip if no succcess or CG1 or CG2 are not valid
                if (!expressionMatch.Success ||
                    string.IsNullOrWhiteSpace(expressionMatch.Groups[1].Value) ||
                    expressionMatch.Groups[2].Value == null)
                {
                    continue;
                }

                //get flavor name and flavor content
                string flavorName    = expressionMatch.Groups[1].Value;
                string flavorContent = expressionMatch.Groups[2].Value;

                //do some processing with the strings
                flavorName    = flavorName.ToLower().Trim();
                flavorContent = flavorContent.Trim();

                //skip if dict already contains this flavor name
                if (flavorDict.ContainsKey(flavorName))
                {
                    logSession?.w($"Duplicate flavor {flavorName} in expression {expression}!");
                    continue;
                }

                //add to dict
                logSession?.v($"add {flavorName} - {flavorContent} to dict");
                flavorDict.Add(flavorName, flavorContent);
            }

            //return null if dict is empty
            logSession?.v($"flavorDict.Count is {flavorDict.Count}");
            if (flavorDict.Count <= 0)
            {
                return(null);
            }

            //return filled dict
            return(flavorDict);
        }