コード例 #1
0
ファイル: MainClass.cs プロジェクト: nuxleus/ajaxmin
        private int ProcessCrunchGroup(CrunchGroup crunchGroup)
        {
            int retVal = 0;

            // length of all the source files combined
            long sourceLength = 0;

            // create a string builder we'll dump our output into
            StringBuilder outputBuilder = new StringBuilder();
            try
            {
                // if we have a resource file, process it now
                ResourceStrings resourceStrings = null;
                if (crunchGroup.Resource.Length > 0)
                {
                    try
                    {
                        resourceStrings = ProcessResourceFile(crunchGroup.Resource);
                    }
                    catch (IOException e)
                    {
                        Debug.WriteLine(e.ToString());
                    }
                    catch (BadImageFormatException e)
                    {
                        Debug.WriteLine(e.ToString());
                    }
                }

                switch (crunchGroup.InputType)
                {
                    case InputType.Css:
                        // see how many input files there are
                        if (crunchGroup.Count == 0)
                        {
                            // no input files -- take from stdin
                            retVal = ProcessCssFile(string.Empty, m_encodingInputName, resourceStrings, outputBuilder, ref sourceLength);
                        }
                        else
                        {
                            // process each input file
                            for (int ndx = 0; retVal == 0 && ndx < crunchGroup.Count; ++ndx)
                            {
                                retVal = ProcessCssFile(crunchGroup[ndx], crunchGroup[ndx].EncodingName ?? m_encodingInputName, resourceStrings, outputBuilder, ref sourceLength);
                            }
                        }
                        break;

                    case InputType.JavaScript:
                        if (resourceStrings != null)
                        {
                            // make sure the resource strings know the name of the resource object
                            resourceStrings.Name = crunchGroup.ResourceObjectName;
                        }

                        if (m_echoInput && resourceStrings != null)
                        {
                            // we're just echoing the output -- so output a JS version of the dictionary
                            // create JS from the dictionary and output it to the stream
                            // leave the object null
                            string resourceObject = CreateJSFromResourceStrings(resourceStrings);
                            outputBuilder.Append(resourceObject);

                            // just add the number of characters to the length 
                            // it's just an approximation
                            // NO! We don't want to include this code in the calculations.
                            // it's not actually part of the sources
                            //sourceLength += resourceObject.Length;
                        }

                        // process each input file
                        // we'll keep track of whether the last file ended in a semi-colon.
                        // we start with true so we don't add one before the first block
                        bool lastEndedSemiColon = true;
                        try
                        {
                            // see how many input files there are
                            if (crunchGroup.Count == 0)
                            {
                                // take input from stdin
                                retVal = ProcessJSFile(string.Empty, m_encodingInputName, resourceStrings, outputBuilder, ref lastEndedSemiColon, ref sourceLength);
                            }
                            else
                            {
                                // process each input file in turn
                                for (int ndx = 0; retVal == 0 && ndx < crunchGroup.Count; ++ndx)
                                {
                                    retVal = ProcessJSFile(crunchGroup[ndx], crunchGroup[ndx].EncodingName ?? m_encodingInputName, resourceStrings, outputBuilder, ref lastEndedSemiColon, ref sourceLength);
                                }
                            }
                        }
                        catch (JScriptException e)
                        {
                            retVal = 1;
                            System.Diagnostics.Debug.WriteLine(e.ToString());
                            WriteError(string.Format(CultureInfo.InvariantCulture, "JS{0}", (e.Error & 0xffff)), e.Message);
                        }

                        // if we want to ensure the stream ends in a semi-colon (command-line option)
                        // and the last file didn't...
                        if (m_terminateWithSemicolon && !lastEndedSemiColon)
                        {
                            // add one now
                            outputBuilder.Append(';');
                        }
                        break;

                    default:
                        throw new UsageException(m_outputMode, "ConflictingInputType");
                }

                // if we are pretty-printing, add a newline
                if (m_prettyPrint)
                {
                    outputBuilder.AppendLine();
                }
            }
            catch (Exception e)
            {
                retVal = 1;
                System.Diagnostics.Debug.WriteLine(e.ToString());
                WriteError("AM-EXCEPTION", e.Message);
            }

            string crunchedCode = outputBuilder.ToString();

            Encoding encodingOutput = GetOutputEncoding(crunchGroup.InputType, crunchGroup.Output.EncodingName);

            // now write the final output file
            if (string.IsNullOrEmpty(crunchGroup.Output))
            {
                // no output file specified - send to STDOUT
                // if the code is empty, don't bother outputting it to the console
                if (!string.IsNullOrEmpty(crunchedCode))
                {
                    // set the console encoding
                    try
                    {
                        // try setting the appropriate output encoding
                        Console.OutputEncoding = encodingOutput;
                    }
                    catch (IOException e)
                    {
                        // sometimes they will error, in which case we'll just set it to ascii
                        Debug.WriteLine(e.ToString());
                        Console.OutputEncoding = Encoding.ASCII;
                    }

                    // however, for some reason when I set the output encoding it
                    // STILL doesn't call the EncoderFallback to Unicode-escape characters
                    // not supported by the encoding scheme. So instead we need to run the
                    // translation outselves. Still need to set the output encoding, though,
                    // so the translated bytes get displayed properly in the console.
                    byte[] encodedBytes = encodingOutput.GetBytes(crunchedCode);

                    // only output the size analysis if we are in analyze mode
                    // change: no, output the size analysis all the time.
                    // (unless in silent mode, but WriteProgess will take care of that)
                    ////if (m_analyze)
                    {
                        // output blank line before
                        WriteProgress();

                        // if we are echoing the input, don't bother reporting the
                        // minify savings because we don't have the minified output --
                        // we have the original output
                        double percentage;
                        if (!m_echoInput)
                        {
                            // calculate the percentage saved
                            percentage = Math.Round((1 - ((double) encodedBytes.Length)/sourceLength)*100, 1);
                            WriteProgress(StringMgr.GetString(
                                              "SavingsMessage",
                                              sourceLength,
                                              encodedBytes.Length,
                                              percentage
                                              ));
                        }
                        else
                        {
                            
                            WriteProgress(StringMgr.GetString(
                                "SavingsOutputMessage",
                                encodedBytes.Length
                                ));
                        }

                        // calculate how much a simple gzip compression would compress the output
                        long gzipLength = CalculateGzipSize(encodedBytes);

                        // calculate the savings and display the result
                        percentage = Math.Round((1 - ((double)gzipLength) / encodedBytes.Length) * 100, 1);
                        WriteProgress(StringMgr.GetString("SavingsGzipMessage", gzipLength, percentage));

                        // blank line after
                        WriteProgress();
                    }

                    // send to console out
                    Console.Out.Write(Console.OutputEncoding.GetChars(encodedBytes));
                    //Console.Out.Write(crunchedCode);
                }
            }
            else
            {
                // send output to file
                try
                {
                    // make sure the destination folder exists
                    FileInfo fileInfo = new FileInfo(crunchGroup.Output);
                    DirectoryInfo destFolder = new DirectoryInfo(fileInfo.DirectoryName);
                    if (!destFolder.Exists)
                    {
                        destFolder.Create();
                    }

                    if (!File.Exists(crunchGroup.Output) || m_clobber)
                    {
                        if (m_clobber
                            && File.Exists(crunchGroup.Output) 
                            && (File.GetAttributes(crunchGroup.Output) & FileAttributes.ReadOnly) != 0)
                        {
                            // the file exists, we said we want to clobber it, but it's marked as
                            // read-only. Reset that flag.
                            File.SetAttributes(
                                crunchGroup.Output, 
                                (File.GetAttributes(crunchGroup.Output) & ~FileAttributes.ReadOnly)
                                );
                        }

                        // create the output file using the given encoding
                        using (StreamWriter outputStream = new StreamWriter(
                           crunchGroup.Output,
                           false,
                           encodingOutput
                           ))
                        {
                            outputStream.Write(crunchedCode);
                        }

                        // only output the size analysis if there is actually some output to measure
                        if (File.Exists(crunchGroup.Output))
                        {
                            // get the size of the resulting file
                            FileInfo crunchedFileInfo = new FileInfo(crunchGroup.Output);
                            long crunchedLength = crunchedFileInfo.Length;
                            if (crunchedLength > 0)
                            {
                                // blank line before
                                WriteProgress();

                                // if we are just echoing the input, don't bother calculating
                                // the minify savings because there aren't any
                                double percentage;
                                if (!m_echoInput)
                                {
                                    // calculate the percentage saved by minification
                                    percentage = Math.Round((1 - ((double) crunchedLength)/sourceLength)*100, 1);
                                    WriteProgress(StringMgr.GetString(
                                                      "SavingsMessage",
                                                      sourceLength,
                                                      crunchedLength,
                                                      percentage
                                                      ));
                                }
                                else
                                {

                                    WriteProgress(StringMgr.GetString(
                                        "SavingsOutputMessage",
                                        crunchedLength
                                        ));
                                }

                                // compute how long a simple gzip might compress the resulting file
                                long gzipLength = CalculateGzipSize(File.ReadAllBytes(crunchGroup.Output));

                                // calculate the percentage of compression and display the results
                                percentage = Math.Round((1 - ((double) gzipLength)/crunchedLength)*100, 1);
                                WriteProgress(StringMgr.GetString("SavingsGzipMessage", gzipLength, percentage));

                                // blank line after
                                WriteProgress();
                            }
                        }
                    }
                    else
                    {
                        retVal = 1;
                        WriteError("AM-IO", StringMgr.GetString("NoClobberError", crunchGroup.Output));
                    }

                }
                catch (ArgumentException e)
                {
                    retVal = 1;
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                    WriteError("AM-PATH", e.Message);
                }
                catch (UnauthorizedAccessException e)
                {
                    retVal = 1;
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                    WriteError("AM-AUTH", e.Message);
                }
                catch (PathTooLongException e)
                {
                    retVal = 1;
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                    WriteError("AM-PATH", e.Message);
                }
                catch (SecurityException e)
                {
                    retVal = 1;
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                    WriteError("AM-SEC", e.Message);
                }
                catch (IOException e)
                {
                    retVal = 1;
                    System.Diagnostics.Debug.WriteLine(e.ToString());
                    WriteError("AM-IO", e.Message);
                }
            }

            if (retVal == 0 && m_errorsFound)
            {
                // make sure we report an error
                retVal = 1;
            }
            return retVal;
        }
コード例 #2
0
ファイル: MainClass.cs プロジェクト: nuxleus/ajaxmin
        private static CrunchGroup[] ProcessXmlFile(string xmlPath, string resourcePath, string resourceObjectName, string outputFolder)
        {
            // list of crunch groups we're going to create by reading the XML file
            List<CrunchGroup> crunchGroups = new List<CrunchGroup>();
            try
            {
                // save the XML file's directory name because we'll use it as a root
                // for all the other paths in the file
                string rootPath = Path.GetDirectoryName(xmlPath);

                // open the xml file
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load(xmlPath);

                // get a list of all <output> nodes
                XmlNodeList outputNodes = xmlDoc.SelectNodes("//output");
                if (outputNodes.Count > 0)
                {
                    // process each <output> node
                    for (int ndxOutput = 0; ndxOutput < outputNodes.Count; ++ndxOutput)
                    {
                        // shortcut
                        XmlNode outputNode = outputNodes[ndxOutput];

                        // get the output file path from the path attribute (if any)
                        // it's okay for ther eto be no output file; if that's the case,
                        // the output is sent to the STDOUT stream
                        XmlAttribute pathAttribute = outputNode.Attributes["path"];
                        string outputPath = (pathAttribute == null ? string.Empty : pathAttribute.Value);
                        // if we have a value and it's a relative path...
                        if (outputPath.Length > 0 && !Path.IsPathRooted(outputPath))
                        {
                            if (string.IsNullOrEmpty(outputFolder))
                            {
                                // make it relative to the XML file
                                outputPath = Path.Combine(rootPath, outputPath);
                            }
                            else
                            {
                                // make it relative to the output folder
                                outputPath = Path.Combine(outputFolder, outputPath);
                            }
                        }

                        // see if an encoding override has been specified
                        var encodingAttribute = outputNode.Attributes["encoding"];
                        var encodingOutputName = encodingAttribute != null
                            ? encodingAttribute.Value
                            : null;

                        // create the crunch group
                        CrunchGroup crunchGroup = new CrunchGroup(outputPath, encodingOutputName);

                        // see if there's an explicit input type, and if so, set the crunch group type
                        var typeAttribute = outputNode.Attributes["type"];
                        if (typeAttribute != null)
                        {
                            switch (typeAttribute.Value.ToUpperInvariant())
                            {
                                case "JS":
                                case "JAVASCRIPT":
                                case "JSCRIPT":
                                    crunchGroup.InputType = InputType.JavaScript;
                                    break;

                                case "CSS":
                                case "STYLESHEET":
                                case "STYLESHEETS":
                                    crunchGroup.InputType = InputType.Css;
                                    break;
                            }
                        }

                        // see if there is a resource node
                        XmlNode resourceNode = outputNode.SelectSingleNode("./resource");
                        if (resourceNode != null)
                        {
                            // the path attribute MUST exist, or we will throw an error
                            pathAttribute = resourceNode.Attributes["path"];
                            if (pathAttribute != null)
                            {
                                // get the value from the attribute
                                string resourceFile = pathAttribute.Value;
                                // if it's a relative path...
                                if (!Path.IsPathRooted(resourceFile))
                                {
                                    // make it relative from the XML file
                                    resourceFile = Path.Combine(rootPath, resourceFile);
                                }
                                // make sure the resource file actually exists! It's an error if it doesn't.
                                if (!File.Exists(resourceFile))
                                {
                                    throw new XmlException(StringMgr.GetString(
                                      "XmlResourceNotExist",
                                      pathAttribute.Value
                                      ));
                                }

                                // add it to the group
                                crunchGroup.Resource = resourceFile;
                            }
                            else
                            {
                                throw new XmlException(StringMgr.GetString("ResourceNoPathAttr"));
                            }

                            // if there is a name attribute, we will use it for the object name
                            XmlAttribute nameAttribute = resourceNode.Attributes["name"];
                            if (nameAttribute != null)
                            {
                                // but first make sure it isn't empty
                                string objectName = nameAttribute.Value;
                                if (!string.IsNullOrEmpty(objectName))
                                {
                                    crunchGroup.ResourceObjectName = objectName;
                                }
                            }
                            // if no name was specified, use our default name
                            if (string.IsNullOrEmpty(crunchGroup.ResourceObjectName))
                            {
                                crunchGroup.ResourceObjectName = c_defaultResourceObjectName;
                            }
                        }
                        else if (!string.IsNullOrEmpty(resourcePath))
                        {
                            // just use the global resource path and object name passed to us
                            // (if anything was passed at all)
                            crunchGroup.Resource = resourcePath;
                            crunchGroup.ResourceObjectName = resourceObjectName;
                        }

                        // get a list of <input> nodes
                        XmlNodeList inputNodes = outputNode.SelectNodes("./input");
                        if (inputNodes.Count > 0)
                        {
                            // for each <input> element under the <output> node
                            for (int ndxInput = 0; ndxInput < inputNodes.Count; ++ndxInput)
                            {
                                // add the path attribute value to the string list.
                                // the path attribute MUST exist, or we will throw an error
                                pathAttribute = inputNodes[ndxInput].Attributes["path"];
                                if (pathAttribute != null)
                                {
                                    // get the value from the attribute
                                    string inputFile = pathAttribute.Value;
                                    // if it's a relative path...
                                    if (!Path.IsPathRooted(inputFile))
                                    {
                                        // make it relative from the XML file
                                        inputFile = Path.Combine(rootPath, inputFile);
                                    }

                                    // make sure the input file actually exists! It's an error if it doesn't.
                                    if (!File.Exists(inputFile))
                                    {
                                        throw new XmlException(StringMgr.GetString(
                                          "XmlInputNotExist",
                                          pathAttribute.Value
                                          ));
                                    }

                                    // if we don't know the type yet, let's see if the extension gives us a hint
                                    if (crunchGroup.InputType == InputType.Unknown)
                                    {
                                        switch (Path.GetExtension(inputFile).ToUpperInvariant())
                                        {
                                            case ".JS":
                                                crunchGroup.InputType = InputType.JavaScript;
                                                break;

                                            case ".CSS":
                                                crunchGroup.InputType = InputType.Css;
                                                break;
                                        }
                                    }

                                    // see if there is an encoding attribute
                                    encodingAttribute = inputNodes[ndxInput].Attributes["encoding"];
                                    string encodingName = encodingAttribute != null
                                        ? encodingAttribute.Value
                                        : null;

                                    // add the input file and its encoding (if any) to the group
                                    crunchGroup.Add(inputFile, encodingName);
                                }
                                else
                                {
                                    // no required path attribute on the <input> element
                                    throw new XmlException(StringMgr.GetString("InputNoPathAttr"));
                                }
                            }
                            // add the crunch group to the list
                            crunchGroups.Add(crunchGroup);
                        }
                        else
                        {
                            // no required <input> nodes inside the <output> node
                            throw new XmlException(StringMgr.GetString("OutputNoInputNodes"));
                        }
                    }
                }
                else
                {
                    // no required <output> nodes
                    // throw an error to end all processing
                    throw new UsageException(ConsoleOutputMode.Console, "XmlNoOutputNodes");
                }
            }
            catch (XmlException e)
            {
                // throw an error indicating the XML error
                System.Diagnostics.Debug.WriteLine(e.ToString());
                throw new UsageException(ConsoleOutputMode.Console, "InputXmlError", e.Message);
            }
            // return an array of CrunchGroup objects
            return crunchGroups.ToArray();
        }
コード例 #3
0
ファイル: MainClass.cs プロジェクト: nuxleus/ajaxmin
        private int Run()
        {
            int retVal = 0;
            CrunchGroup[] crunchGroups;

            // see if we have an XML file to process
            if (!string.IsNullOrEmpty(m_xmlInputFile))
            {
                // process the XML file, using the output path as an optional output root folder
                crunchGroups = ProcessXmlFile(m_xmlInputFile, m_resourceFile, m_resourceObjectName, m_outputFile);
            }
            else
            {
                // just pass the input and output files specified in the command line
                // to the processing method (normal operation)
                crunchGroups = new CrunchGroup[] { new CrunchGroup(m_outputFile, m_encodingOutputName, m_resourceFile, m_resourceObjectName, m_inputFiles, m_encodingInputName, m_inputType) };
            }

            if (crunchGroups.Length > 0)
            {
                // if any one crunch group is writing to stdout, then we need to make sure
                // that no progress or informational messages go to stdout or we will output 
                // invalid JavaScript/CSS. Loop through the crunch groups and if any one is
                // outputting to stdout, set the appropriate flag.
                for (var ndxGroup = 0; ndxGroup < crunchGroups.Length; ++ndxGroup)
                {
                    if (string.IsNullOrEmpty(crunchGroups[ndxGroup].Output))
                    {
                        // set the flag; no need to check any more
                        m_outputToStandardOut = true;
                        break;
                    }
                }

                // loop through all the crunch groups
                for (int ndxGroup = 0; ndxGroup < crunchGroups.Length; ++ndxGroup)
                {
                    // shortcut
                    CrunchGroup crunchGroup = crunchGroups[ndxGroup];

                    // process the crunch group
                    int crunchResult = ProcessCrunchGroup(crunchGroup);
                    // if the result contained an error...
                    if (crunchResult != 0)
                    {
                        // if we're processing more than one group, we should output an
                        // error message indicating that this group encountered an error
                        if (crunchGroups.Length > 1)
                        {
                            // non-localized string, so format is not in the resources
                            string errorCode = string.Format(CultureInfo.InvariantCulture, "AM{0:D4}", crunchResult);

                            // if there is an output file name, use it.
                            if (!string.IsNullOrEmpty(crunchGroup.Output))
                            {
                                WriteError(crunchGroup.Output,
                                    StringMgr.GetString("OutputFileErrorSubCat"),
                                    errorCode,
                                    StringMgr.GetString("OutputFileError", crunchResult)
                                    );
                            }
                            else if (!string.IsNullOrEmpty(m_xmlInputFile))
                            {
                                // use the XML file as the location, and the index of the group for more info
                                // inside the message
                                WriteError(m_xmlInputFile,
                                    StringMgr.GetString("OutputGroupErrorSubCat"),
                                    errorCode,
                                    StringMgr.GetString("OutputGroupError", ndxGroup, crunchResult)
                                    );
                            }
                            else
                            {
                                // no output file name, and not from an XML file. If it's not from an XML
                                // file, then there really should only be one crunch group.
                                // but just in case, use "stdout" as the output file and the index of the group 
                                // in the list (which should probably just be zero)
                                WriteError("stdout",
                                    StringMgr.GetString("OutputGroupErrorSubCat"),
                                    errorCode,
                                    StringMgr.GetString("OutputGroupError", ndxGroup, crunchResult)
                                    );
                            }
                        }
                        // return the error. Only the last one will be used
                        retVal = crunchResult;
                    }
                }
            }
            else
            {
                // no crunch groups
                throw new UsageException(ConsoleOutputMode.Console, "NoInput");
            }

            return retVal;
        }