<commit_before># Copyright 2016 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Documentation generator for Skylark"""

# internal imports
import gflags
import jinja2
import mistune
import os
import re
import shutil
import sys
import tempfile
import zipfile

from skydoc import macro_extractor
from skydoc import rule
from skydoc import rule_extractor

gflags.DEFINE_string('output_dir', '',
    'The directory to write the output generated documentation to if '
    '--zip=false')
gflags.DEFINE_string('output_file', '',
    'The output zip archive file to write if --zip=true.')
gflags.DEFINE_string('format', 'markdown',
    'The output format. Possible values are markdown and html')
gflags.DEFINE_bool('zip', True,
    'Whether to generate a ZIP arhive containing the output files. If '
    '--zip is true, then skydoc will generate a zip file, skydoc.zip by '
    'default or as specified by --output_file. If --zip is false, then '
    'skydoc will generate documentation, either in Markdown or HTML as '
    'specifed by --format, in the current directory or --output_dir if set.')

FLAGS = gflags.FLAGS

DEFAULT_OUTPUT_DIR = '.'
DEFAULT_OUTPUT_FILE = 'skydoc.zip'

WORKSPACE_DIR = 'io_bazel_skydoc'
TEMPLATE_PATH = 'skydoc/templates'
CSS_PATH = 'skydoc/sass'

CSS_FILE = 'main.css'
CSS_DIR = 'css'

def _create_jinja_environment():
  env = jinja2.Environment(
      loader=jinja2.FileSystemLoader(_runfile_path(TEMPLATE_PATH)),
      keep_trailing_newline=True,
      line_statement_prefix='%')
  env.filters['markdown'] = lambda text: jinja2.Markup(mistune.markdown(text))
  return env


# TODO(dzc): Remove this workaround once we switch to a self-contained Python
# binary format such as PEX.
def _runfile_path(path):
  """Prepends the given path with the path to the root of the runfiles tree.

  The files that skydoc depend on are generated in the Bazel runfiles tree.
  There is no built-in way to get the root of the runfiles tree but it is
  possible to generate it from sys.argv[0]. The code here is adapted from the
  Bazel Python launcher stub.

  Args:
    path: The relative path from the root of the runfiles tree.

  Returns:
    Returns path prepended with the absolute path to the root of the runfiles
    tree.
  """
  script_filename = os.path.abspath(sys.argv[0])
  while True:
    runfiles_dir = script_filename + '.runfiles'
    if os.path.isdir(runfiles_dir):
      break

    # Follow a symlink and try again.
    if os.path.islink(script_filename):
      link = os.readlink(script_filename)
      script_filename = os.path.join(os.path.dirname(script_filename), link)
      continue

    matchobj = re.match("(.*\.runfiles)/.*", os.path.abspath(sys.argv[0]))
    if matchobj:
      runfiles_dir = matchobj.group(1)
      break

    raise AssertionError('Cannot find .runfiles directory.')
  return os.path.join(runfiles_dir, WORKSPACE_DIR, path)

def merge_languages(macro_language, rule_language):
  for rule in rule_language.rule:
    new_rule = macro_language.rule.add()
    new_rule.CopyFrom(rule)
  return macro_language

class MarkdownWriter(object):
  """Writer for generating documentation in Markdown."""

  def __init__(self, output_dir, output_file, output_zip):
    self.__output_dir = output_dir
    self.__output_file = output_file
    self.__output_zip = output_zip

  def write(self, rulesets):
    """Write the documentation for the rules contained in rulesets."""
    try:
      temp_dir = tempfile.mkdtemp()
      output_files = []
      for ruleset in rulesets:
        output_files.append(self._write_ruleset(temp_dir, ruleset))

      if self.__output_zip:
        # We are generating a zip archive containing all the documentation.
        # Write each documentation file generated in the temp directory to the
        # zip file.
        with zipfile.ZipFile(self.__output_file, 'w') as zf:
          for output_file in output_files:
            zf.write(output_file, os.path.basename(output_file))
      else:
        # We are generating documentation in the output_dir directory. Copy each
        # documentation file to output_dir.
        for output_file in output_files:
          shutil.copyfile(
              output_file,
              os.path.join(self.__output_dir, os.path.basename(output_file)))

    finally:
      # Delete temporary directory.
      shutil.rmtree(temp_dir)

  def _write_ruleset(self, output_dir, ruleset):
    # Load template and render Markdown.
    env = _create_jinja_environment()
    template = env.get_template('markdown.jinja')
    out = template.render(ruleset=ruleset)

    # Write output to file.
    output_file = "%s/%s.md" % (output_dir, ruleset.name)
    with open(output_file, "w") as f:
      f.write(out)
    return output_file

class HtmlWriter(object):
  """Writer for generating documentation in HTML."""

  def __init__(self, output_dir, output_file, output_zip):
    self.__output_dir = output_dir
    self.__output_file = output_file
    self.__output_zip = output_zip
    self.__env = _create_jinja_environment()

  def write(self, rulesets):
    # Generate navigation used for all rules.
    nav_template = self.__env.get_template('nav.jinja')
    nav = nav_template.render(rulesets=rulesets)

    try:
      temp_dir = tempfile.mkdtemp()
      output_files = []
      for ruleset in rulesets:
        output_files.append(self._write_ruleset(temp_dir, ruleset, nav))

      if self.__output_zip:
        with zipfile.ZipFile(self.__output_file, 'w') as zf:
          for output_file in output_files:<commit_msg>Do not generate page for .bzl file with no public rules. (#19)<commit_after># Copyright 2016 The Bazel Authors. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Documentation generator for Skylark"""

# internal imports
import gflags
import jinja2
import mistune
import os
import re
import shutil
import sys
import tempfile
import zipfile

from skydoc import macro_extractor
from skydoc import rule
from skydoc import rule_extractor

gflags.DEFINE_string('output_dir', '',
    'The directory to write the output generated documentation to if '
    '--zip=false')
gflags.DEFINE_string('output_file', '',
    'The output zip archive file to write if --zip=true.')
gflags.DEFINE_string('format', 'markdown',
    'The output format. Possible values are markdown and html')
gflags.DEFINE_bool('zip', True,
    'Whether to generate a ZIP arhive containing the output files. If '
    '--zip is true, then skydoc will generate a zip file, skydoc.zip by '
    'default or as specified by --output_file. If --zip is false, then '
    'skydoc will generate documentation, either in Markdown or HTML as '
    'specifed by --format, in the current directory or --output_dir if set.')

FLAGS = gflags.FLAGS

DEFAULT_OUTPUT_DIR = '.'
DEFAULT_OUTPUT_FILE = 'skydoc.zip'

WORKSPACE_DIR = 'io_bazel_skydoc'
TEMPLATE_PATH = 'skydoc/templates'
CSS_PATH = 'skydoc/sass'

CSS_FILE = 'main.css'
CSS_DIR = 'css'

def _create_jinja_environment():
  env = jinja2.Environment(
      loader=jinja2.FileSystemLoader(_runfile_path(TEMPLATE_PATH)),
      keep_trailing_newline=True,
      line_statement_prefix='%')
  env.filters['markdown'] = lambda text: jinja2.Markup(mistune.markdown(text))
  return env


# TODO(dzc): Remove this workaround once we switch to a self-contained Python
# binary format such as PEX.
def _runfile_path(path):
  """Prepends the given path with the path to the root of the runfiles tree.

  The files that skydoc depend on are generated in the Bazel runfiles tree.
  There is no built-in way to get the root of the runfiles tree but it is
  possible to generate it from sys.argv[0]. The code here is adapted from the
  Bazel Python launcher stub.

  Args:
    path: The relative path from the root of the runfiles tree.

  Returns:
    Returns path prepended with the absolute path to the root of the runfiles
    tree.
  """
  script_filename = os.path.abspath(sys.argv[0])
  while True:
    runfiles_dir = script_filename + '.runfiles'
    if os.path.isdir(runfiles_dir):
      break

    # Follow a symlink and try again.
    if os.path.islink(script_filename):
      link = os.readlink(script_filename)
      script_filename = os.path.join(os.path.dirname(script_filename), link)
      continue

    matchobj = re.match("(.*\.runfiles)/.*", os.path.abspath(sys.argv[0]))
    if matchobj:
      runfiles_dir = matchobj.group(1)
      break

    raise AssertionError('Cannot find .runfiles directory.')
  return os.path.join(runfiles_dir, WORKSPACE_DIR, path)

def merge_languages(macro_language, rule_language):
  for rule in rule_language.rule:
    new_rule = macro_language.rule.add()
    new_rule.CopyFrom(rule)
  return macro_language

class MarkdownWriter(object):
  """Writer for generating documentation in Markdown."""

  def __init__(self, output_dir, output_file, output_zip):
    self.__output_dir = output_dir
    self.__output_file = output_file
    self.__output_zip = output_zip

  def write(self, rulesets):
    """Write the documentation for the rules contained in rulesets."""
    try:
      temp_dir = tempfile.mkdtemp()
      output_files = []
      for ruleset in rulesets:
        if len(ruleset.rules) > 0:
          output_files.append(self._write_ruleset(temp_dir, ruleset))

      if self.__output_zip:
        # We are generating a zip archive containing all the documentation.
        # Write each documentation file generated in the temp directory to the
        # zip file.
        with zipfile.ZipFile(self.__output_file, 'w') as zf:
          for output_file in output_files:
            zf.write(output_file, os.path.basename(output_file))
      else:
        # We are generating documentation in the output_dir directory. Copy each
        # documentation file to output_dir.
        for output_file in output_files:
          shutil.copyfile(
              output_file,
              os.path.join(self.__output_dir, os.path.basename(output_file)))

    finally:
      # Delete temporary directory.
      shutil.rmtree(temp_dir)

  def _write_ruleset(self, output_dir, ruleset):
    # Load template and render Markdown.
    env = _create_jinja_environment()
    template = env.get_template('markdown.jinja')
    out = template.render(ruleset=ruleset)

    # Write output to file.
    output_file = "%s/%s.md" % (output_dir, ruleset.name)
    with open(output_file, "w") as f:
      f.write(out)
    return output_file

class HtmlWriter(object):
  """Writer for generating documentation in HTML."""

  def __init__(self, output_dir, output_file, output_zip):
    self.__output_dir = output_dir
    self.__output_file = output_file
    self.__output_zip = output_zip
    self.__env = _create_jinja_environment()

  def write(self, rulesets):
    # Generate navigation used for all rules.
    nav_template = self.__env.get_template('nav.jinja')
    nav = nav_template.render(rulesets=rulesets)

    try:
      temp_dir = tempfile.mkdtemp()
      output_files = []
      for ruleset in rulesets:
        if len(ruleset.rules) > 0:
          output_files.append(self._write_ruleset(temp_dir, ruleset, nav))

      if self.__output_zip:
        with zipfile.ZipFile(self.__output_file, 'w') as zf:
          for output_file in output_files:
{'fraction_non_alphanumeric': 0.08751325340510561, 'fraction_numerical': 0.002936138977244923, 'mean_word_length': 3.531411677753141, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5652218', 'n_tokens_mistral': 3764, 'n_tokens_neox': 3641, 'n_words': 1198}