[bluefish] replace non-free jsmin.py

Tom Callaway spot at fedoraproject.org
Tue Sep 3 20:43:24 UTC 2013


commit bf0f86c7eca139b28e80d96c8d6550e19e2b2e4d
Author: Tom Callaway <spot at fedoraproject.org>
Date:   Tue Sep 3 16:43:44 2013 -0400

    replace non-free jsmin.py

 bluefish.spec |   16 +++-
 jsmin.py      |  282 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 sources       |    2 +-
 3 files changed, 295 insertions(+), 5 deletions(-)
---
diff --git a/bluefish.spec b/bluefish.spec
index b76f316..3b198ed 100644
--- a/bluefish.spec
+++ b/bluefish.spec
@@ -1,6 +1,6 @@
 %global pkgver 2.2.4
 #global prerel rc1
-%global rpmrel 2
+%global rpmrel 3
 
 Name:		bluefish
 Version:	%{pkgver}
@@ -9,7 +9,12 @@ Summary:	GTK2 web development application for experienced users
 Group:		Development/Tools
 License:	GPLv3+
 URL:		http://bluefish.openoffice.nl/
-Source0:	http://www.bennewitz.com/bluefish/stable/source/bluefish-%{version}%{?prerel:-%{prerel}}.tar.bz2
+# Upstream source contains non-free jsmin.py
+# Source0:	http://www.bennewitz.com/bluefish/stable/source/bluefish-%{version}%{?prerel:-%{prerel}}.tar.bz2
+# To generate clean source, simply rm -rf data/jsmin.py
+# We provide a replacement in Source1.
+Source0:	bluefish-%{version}%{?prerel:-%{prerel}}-clean.tar.bz2
+Source1:	https://raw.github.com/v8/v8/master/tools/jsmin.py
 BuildRoot:	%{_tmppath}/%{name}-%{version}-%{release}-root-%(id -nu)
 BuildRequires:	desktop-file-utils
 BuildRequires:	enchant-devel >= 1.4.2
@@ -73,8 +78,8 @@ Files common to every architecture version of %{name}.
 %prep
 %setup -q -n %{name}-%{version}%{?prerel:-%{prerel}}
 
-# Fix line endings
-sed -i -e 's/\r$//' data/jsmin.py
+cp -a %{SOURCE1} data/
+sed -i 's|python2.4|python|g' data/jsmin.py
 
 %build
 %configure	--disable-dependency-tracking \
@@ -158,6 +163,9 @@ fi
 %{_mandir}/man1/%{name}.1*
 
 %changelog
+* Tue Sep  3 2013 Tom Callaway <spot at fedoraproject.org> - 2.2.4-3
+- remove non-free jsmin.py code, replace with free jsmin.py
+
 * Sun Jul 28 2013 Paul Howarth <paul at city-fan.org> - 2.2.4-2
 - Install docs to %%{_pkgdocdir} where available
 
diff --git a/jsmin.py b/jsmin.py
new file mode 100644
index 0000000..250dea9
--- /dev/null
+++ b/jsmin.py
@@ -0,0 +1,282 @@
+#!/usr/bin/python2.4
+
+# Copyright 2012 the V8 project authors. All rights reserved.
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+#       notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+#       copyright notice, this list of conditions and the following
+#       disclaimer in the documentation and/or other materials provided
+#       with the distribution.
+#     * Neither the name of Google Inc. nor the names of its
+#       contributors may be used to endorse or promote products derived
+#       from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""A JavaScript minifier.
+
+It is far from being a complete JS parser, so there are many valid
+JavaScript programs that will be ruined by it.  Another strangeness is that
+it accepts $ and % as parts of identifiers.  It doesn't merge lines or strip
+out blank lines in order to ease debugging.  Variables at the top scope are
+properties of the global object so we can't rename them.  It is assumed that
+you introduce variables with var as if JavaScript followed C++ scope rules
+around curly braces, so the declaration must be above the first use.
+
+Use as:
+import jsmin
+minifier = JavaScriptMinifier()
+program1 = minifier.JSMinify(program1)
+program2 = minifier.JSMinify(program2)
+"""
+
+import re
+
+
+class JavaScriptMinifier(object):
+  """An object that you can feed code snippets to to get them minified."""
+
+  def __init__(self):
+    # We prepopulate the list of identifiers that shouldn't be used.  These
+    # short language keywords could otherwise be used by the script as variable
+    # names.
+    self.seen_identifiers = {"do": True, "in": True}
+    self.identifier_counter = 0
+    self.in_comment = False
+    self.map = {}
+    self.nesting = 0
+
+  def LookAtIdentifier(self, m):
+    """Records identifiers or keywords that we see in use.
+
+    (So we can avoid renaming variables to these strings.)
+    Args:
+      m: The match object returned by re.search.
+
+    Returns:
+      Nothing.
+    """
+    identifier = m.group(1)
+    self.seen_identifiers[identifier] = True
+
+  def Push(self):
+    """Called when we encounter a '{'."""
+    self.nesting += 1
+
+  def Pop(self):
+    """Called when we encounter a '}'."""
+    self.nesting -= 1
+    # We treat each top-level opening brace as a single scope that can span
+    # several sets of nested braces.
+    if self.nesting == 0:
+      self.map = {}
+      self.identifier_counter = 0
+
+  def Declaration(self, m):
+    """Rewrites bits of the program selected by a regexp.
+
+    These can be curly braces, literal strings, function declarations and var
+    declarations.  (These last two must be on one line including the opening
+    curly brace of the function for their variables to be renamed).
+
+    Args:
+      m: The match object returned by re.search.
+
+    Returns:
+      The string that should replace the match in the rewritten program.
+    """
+    matched_text = m.group(0)
+    if matched_text == "{":
+      self.Push()
+      return matched_text
+    if matched_text == "}":
+      self.Pop()
+      return matched_text
+    if re.match("[\"'/]", matched_text):
+      return matched_text
+    m = re.match(r"var ", matched_text)
+    if m:
+      var_names = matched_text[m.end():]
+      var_names = re.split(r",", var_names)
+      return "var " + ",".join(map(self.FindNewName, var_names))
+    m = re.match(r"(function\b[^(]*)\((.*)\)\{$", matched_text)
+    if m:
+      up_to_args = m.group(1)
+      args = m.group(2)
+      args = re.split(r",", args)
+      self.Push()
+      return up_to_args + "(" + ",".join(map(self.FindNewName, args)) + "){"
+
+    if matched_text in self.map:
+      return self.map[matched_text]
+
+    return matched_text
+
+  def CharFromNumber(self, number):
+    """A single-digit base-52 encoding using a-zA-Z."""
+    if number < 26:
+      return chr(number + 97)
+    number -= 26
+    return chr(number + 65)
+
+  def FindNewName(self, var_name):
+    """Finds a new 1-character or 2-character name for a variable.
+
+    Enters it into the mapping table for this scope.
+
+    Args:
+      var_name: The name of the variable before renaming.
+
+    Returns:
+      The new name of the variable.
+    """
+    new_identifier = ""
+    # Variable names that end in _ are member variables of the global object,
+    # so they can be visible from code in a different scope.  We leave them
+    # alone.
+    if var_name in self.map:
+      return self.map[var_name]
+    if self.nesting == 0:
+      return var_name
+    while True:
+      identifier_first_char = self.identifier_counter % 52
+      identifier_second_char = self.identifier_counter // 52
+      new_identifier = self.CharFromNumber(identifier_first_char)
+      if identifier_second_char != 0:
+        new_identifier = (
+            self.CharFromNumber(identifier_second_char - 1) + new_identifier)
+      self.identifier_counter += 1
+      if not new_identifier in self.seen_identifiers:
+        break
+
+    self.map[var_name] = new_identifier
+    return new_identifier
+
+  def RemoveSpaces(self, m):
+    """Returns literal strings unchanged, replaces other inputs with group 2.
+
+    Other inputs are replaced with the contents of capture 1.  This is either
+    a single space or an empty string.
+
+    Args:
+      m: The match object returned by re.search.
+
+    Returns:
+      The string that should be inserted instead of the matched text.
+    """
+    entire_match = m.group(0)
+    replacement = m.group(1)
+    if re.match(r"'.*'$", entire_match):
+      return entire_match
+    if re.match(r'".*"$', entire_match):
+      return entire_match
+    if re.match(r"/.+/$", entire_match):
+      return entire_match
+    return replacement
+
+  def JSMinify(self, text):
+    """The main entry point.  Takes a text and returns a compressed version.
+
+    The compressed version hopefully does the same thing.  Line breaks are
+    preserved.
+
+    Args:
+      text: The text of the code snippet as a multiline string.
+
+    Returns:
+      The compressed text of the code snippet as a multiline string.
+    """
+    new_lines = []
+    for line in re.split(r"\n", text):
+      line = line.replace("\t", " ")
+      if self.in_comment:
+        m = re.search(r"\*/", line)
+        if m:
+          line = line[m.end():]
+          self.in_comment = False
+        else:
+          new_lines.append("")
+          continue
+
+      if not self.in_comment:
+        line = re.sub(r"/\*.*?\*/", " ", line)
+        line = re.sub(r"//.*", "", line)
+        m = re.search(r"/\*", line)
+        if m:
+          line = line[:m.start()]
+          self.in_comment = True
+
+      # Strip leading and trailing spaces.
+      line = re.sub(r"^ +", "", line)
+      line = re.sub(r" +$", "", line)
+      # A regexp that matches a literal string surrounded by "double quotes".
+      # This regexp can handle embedded backslash-escaped characters including
+      # embedded backslash-escaped double quotes.
+      double_quoted_string = r'"(?:[^"\\]|\\.)*"'
+      # A regexp that matches a literal string surrounded by 'double quotes'.
+      single_quoted_string = r"'(?:[^'\\]|\\.)*'"
+      # A regexp that matches a regexp literal surrounded by /slashes/.
+      # Don't allow a regexp to have a ) before the first ( since that's a
+      # syntax error and it's probably just two unrelated slashes.
+      # Also don't allow it to come after anything that can only be the
+      # end of a primary expression.
+      slash_quoted_regexp = r"(?<![\w$'\")\]])/(?:(?=\()|(?:[^()/\\]|\\.)+)(?:\([^/\\]|\\.)*/"
+      # Replace multiple spaces with a single space.
+      line = re.sub("|".join([double_quoted_string,
+                              single_quoted_string,
+                              slash_quoted_regexp,
+                              "( )+"]),
+                    self.RemoveSpaces,
+                    line)
+      # Strip single spaces unless they have an identifier character both before
+      # and after the space.  % and $ are counted as identifier characters.
+      line = re.sub("|".join([double_quoted_string,
+                              single_quoted_string,
+                              slash_quoted_regexp,
+                              r"(?<![a-zA-Z_0-9$%]) | (?![a-zA-Z_0-9$%])()"]),
+                    self.RemoveSpaces,
+                    line)
+      # Collect keywords and identifiers that are already in use.
+      if self.nesting == 0:
+        re.sub(r"([a-zA-Z0-9_$%]+)", self.LookAtIdentifier, line)
+      function_declaration_regexp = (
+          r"\bfunction"              # Function definition keyword...
+          r"( [\w$%]+)?"             # ...optional function name...
+          r"\([\w$%,]+\)\{")         # ...argument declarations.
+      # Unfortunately the keyword-value syntax { key:value } makes the key look
+      # like a variable where in fact it is a literal string.  We use the
+      # presence or absence of a question mark to try to distinguish between
+      # this case and the ternary operator: "condition ? iftrue : iffalse".
+      if re.search(r"\?", line):
+        block_trailing_colon = r""
+      else:
+        block_trailing_colon = r"(?![:\w$%])"
+      # Variable use.  Cannot follow a period precede a colon.
+      variable_use_regexp = r"(?<![.\w$%])[\w$%]+" + block_trailing_colon
+      line = re.sub("|".join([double_quoted_string,
+                              single_quoted_string,
+                              slash_quoted_regexp,
+                              r"\{",                  # Curly braces.
+                              r"\}",
+                              r"\bvar [\w$%,]+",      # var declarations.
+                              function_declaration_regexp,
+                              variable_use_regexp]),
+                    self.Declaration,
+                    line)
+      new_lines.append(line)
+
+    return "\n".join(new_lines) + "\n"
diff --git a/sources b/sources
index f1ba4c0..01660a8 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-abc06b90c38c3714f19428d16a5cb311  bluefish-2.2.4.tar.bz2
+24180aa005941aa1bdd5b704952e28f6  bluefish-2.2.4-clean.tar.bz2


More information about the scm-commits mailing list