当前位置: 首页>>代码示例>>Python>>正文


Python build_file_address_mapper.BuildFileAddressMapper类代码示例

本文整理汇总了Python中pants.build_graph.build_file_address_mapper.BuildFileAddressMapper的典型用法代码示例。如果您正苦于以下问题:Python BuildFileAddressMapper类的具体用法?Python BuildFileAddressMapper怎么用?Python BuildFileAddressMapper使用的例子?那么恭喜您, 这里精选的类代码示例或许可以为您提供帮助。


在下文中一共展示了BuildFileAddressMapper类的10个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的Python代码示例。

示例1: __init__

  def __init__(self, root_dir, options, build_config, run_tracker, reporting, build_graph=None,
               exiter=sys.exit):
    """
    :param str root_dir: The root directory of the pants workspace (aka the "build root").
    :param Options options: The global, pre-initialized Options instance.
    :param BuildConfiguration build_config: A pre-initialized BuildConfiguration instance.
    :param Runtracker run_tracker: The global, pre-initialized/running RunTracker instance.
    :param Reporting reporting: The global, pre-initialized Reporting instance.
    :param BuildGraph build_graph: A BuildGraph instance (for graph reuse, optional).
    :param func exiter: A function that accepts an exit code value and exits (for tests, Optional).
    """
    self._root_dir = root_dir
    self._options = options
    self._build_config = build_config
    self._run_tracker = run_tracker
    self._reporting = reporting
    self._exiter = exiter

    self._goals = []
    self._targets = []
    self._requested_goals = self._options.goals
    self._target_specs = self._options.target_specs
    self._help_request = self._options.help_request

    self._global_options = options.for_global_scope()
    self._tag = self._global_options.tag
    self._fail_fast = self._global_options.fail_fast
    # Will be provided through context.address_mapper.build_ignore_patterns.
    self._explain = self._global_options.explain
    self._kill_nailguns = self._global_options.kill_nailguns

    pants_ignore = self._global_options.pants_ignore or []
    self._project_tree = self._get_project_tree(self._global_options.build_file_rev, pants_ignore)
    self._build_file_parser = BuildFileParser(self._build_config, self._root_dir)
    build_ignore_patterns = self._global_options.ignore_patterns or []
    self._address_mapper = BuildFileAddressMapper(
      self._build_file_parser,
      self._project_tree,
      build_ignore_patterns,
      exclude_target_regexps=self._global_options.exclude_target_regexp
    )
    self._build_graph = self._select_buildgraph(self._global_options.enable_v2_engine,
                                                self._global_options.pants_ignore,
                                                build_graph)
开发者ID:RobinTec,项目名称:pants,代码行数:44,代码来源:goal_runner.py

示例2: setUp

  def setUp(self):
    """
    :API: public
    """
    super(BaseTest, self).setUp()
    Goal.clear()
    Subsystem.reset()

    self.real_build_root = BuildRoot().path

    self.build_root = os.path.realpath(mkdtemp(suffix='_BUILD_ROOT'))
    self.subprocess_dir = os.path.join(self.build_root, '.pids')
    self.addCleanup(safe_rmtree, self.build_root)

    self.pants_workdir = os.path.join(self.build_root, '.pants.d')
    safe_mkdir(self.pants_workdir)

    self.options = defaultdict(dict)  # scope -> key-value mapping.
    self.options[''] = {
      'pants_workdir': self.pants_workdir,
      'pants_supportdir': os.path.join(self.build_root, 'build-support'),
      'pants_distdir': os.path.join(self.build_root, 'dist'),
      'pants_configdir': os.path.join(self.build_root, 'config'),
      'pants_subprocessdir': self.subprocess_dir,
      'cache_key_gen_version': '0-test',
    }
    self.options['cache'] = {
      'read_from': [],
      'write_to': [],
    }

    BuildRoot().path = self.build_root
    self.addCleanup(BuildRoot().reset)

    self._build_configuration = BuildConfiguration()
    self._build_configuration.register_aliases(self.alias_groups)
    self.build_file_parser = BuildFileParser(self._build_configuration, self.build_root)
    self.project_tree = FileSystemProjectTree(self.build_root)
    self.address_mapper = BuildFileAddressMapper(self.build_file_parser, self.project_tree,
                                                 build_ignore_patterns=self.build_ignore_patterns)
    self.build_graph = MutableBuildGraph(address_mapper=self.address_mapper)
开发者ID:adamchainz,项目名称:pants,代码行数:41,代码来源:base_test.py

示例3: __init__

    def __init__(self, root_dir, options, build_config, run_tracker, reporting, exiter=sys.exit):
        """
    :param str root_dir: The root directory of the pants workspace (aka the "build root").
    :param Options options: The global, pre-initialized Options instance.
    :param BuildConfiguration build_config: A pre-initialized BuildConfiguration instance.
    :param Runtracker run_tracker: The global, pre-initialized/running RunTracker instance.
    :param Reporting reporting: The global, pre-initialized Reporting instance.
    :param func exiter: A function that accepts an exit code value and exits (for tests, Optional).
    """
        self._root_dir = root_dir
        self._options = options
        self._build_config = build_config
        self._run_tracker = run_tracker
        self._reporting = reporting
        self._exiter = exiter

        self._goals = []
        self._targets = []
        self._requested_goals = self._options.goals
        self._target_specs = self._options.target_specs
        self._help_request = self._options.help_request

        self._global_options = options.for_global_scope()
        self._tag = self._global_options.tag
        self._fail_fast = self._global_options.fail_fast
        self._spec_excludes = self._global_options.spec_excludes
        self._explain = self._global_options.explain
        self._kill_nailguns = self._global_options.kill_nailguns

        self._project_tree = self._get_project_tree(self._global_options.build_file_rev)
        self._build_file_parser = BuildFileParser(self._build_config, self._root_dir)
        self._address_mapper = BuildFileAddressMapper(self._build_file_parser, self._project_tree)
        self._build_graph = BuildGraph(self._address_mapper)
        self._spec_parser = CmdLineSpecParser(
            self._root_dir,
            self._address_mapper,
            spec_excludes=self._spec_excludes,
            exclude_target_regexps=self._global_options.exclude_target_regexp,
        )
开发者ID:dfabulich,项目名称:pants,代码行数:39,代码来源:goal_runner.py

示例4: GoalRunnerFactory

class GoalRunnerFactory(object):
    def __init__(self, root_dir, options, build_config, run_tracker, reporting, exiter=sys.exit):
        """
    :param str root_dir: The root directory of the pants workspace (aka the "build root").
    :param Options options: The global, pre-initialized Options instance.
    :param BuildConfiguration build_config: A pre-initialized BuildConfiguration instance.
    :param Runtracker run_tracker: The global, pre-initialized/running RunTracker instance.
    :param Reporting reporting: The global, pre-initialized Reporting instance.
    :param func exiter: A function that accepts an exit code value and exits (for tests, Optional).
    """
        self._root_dir = root_dir
        self._options = options
        self._build_config = build_config
        self._run_tracker = run_tracker
        self._reporting = reporting
        self._exiter = exiter

        self._goals = []
        self._targets = []
        self._requested_goals = self._options.goals
        self._target_specs = self._options.target_specs
        self._help_request = self._options.help_request

        self._global_options = options.for_global_scope()
        self._tag = self._global_options.tag
        self._fail_fast = self._global_options.fail_fast
        self._spec_excludes = self._global_options.spec_excludes
        self._explain = self._global_options.explain
        self._kill_nailguns = self._global_options.kill_nailguns

        self._project_tree = self._get_project_tree(self._global_options.build_file_rev)
        self._build_file_parser = BuildFileParser(self._build_config, self._root_dir)
        self._address_mapper = BuildFileAddressMapper(self._build_file_parser, self._project_tree)
        self._build_graph = BuildGraph(self._address_mapper)
        self._spec_parser = CmdLineSpecParser(
            self._root_dir,
            self._address_mapper,
            spec_excludes=self._spec_excludes,
            exclude_target_regexps=self._global_options.exclude_target_regexp,
        )

    def _get_project_tree(self, build_file_rev):
        """Creates the project tree for build files for use in a given pants run."""
        if build_file_rev:
            return ScmProjectTree(self._root_dir, get_scm(), build_file_rev)
        else:
            return FileSystemProjectTree(self._root_dir)

    def _expand_goals(self, goals):
        """Check and populate the requested goals for a given run."""
        for goal in goals:
            try:
                self._address_mapper.resolve_spec(goal)
                logger.warning(
                    "Command-line argument '{0}' is ambiguous and was assumed to be "
                    "a goal. If this is incorrect, disambiguate it with ./{0}.".format(goal)
                )
            except AddressLookupError:
                pass

        if self._help_request:
            help_printer = HelpPrinter(self._options)
            result = help_printer.print_help()
            self._exiter(result)

        self._goals.extend([Goal.by_name(goal) for goal in goals])

    def _expand_specs(self, specs, fail_fast):
        """Populate the BuildGraph and target list from a set of input specs."""
        with self._run_tracker.new_workunit(name="parse", labels=[WorkUnitLabel.SETUP]):

            def filter_for_tag(tag):
                return lambda target: tag in map(str, target.tags)

            tag_filter = wrap_filters(create_filters(self._tag, filter_for_tag))

            for spec in specs:
                for address in self._spec_parser.parse_addresses(spec, fail_fast):
                    self._build_graph.inject_address_closure(address)
                    target = self._build_graph.get_target(address)
                    if tag_filter(target):
                        self._targets.append(target)

    def _maybe_launch_pantsd(self):
        """Launches pantsd if configured to do so."""
        if self._global_options.enable_pantsd:
            # Avoid runtracker output if pantsd is disabled. Otherwise, show up to inform the user its on.
            with self._run_tracker.new_workunit(name="pantsd", labels=[WorkUnitLabel.SETUP]):
                PantsDaemonLauncher.global_instance().maybe_launch()

    def _is_quiet(self):
        return any(goal.has_task_of_type(QuietTaskMixin) for goal in self._goals) or self._explain

    def _setup_context(self):
        self._maybe_launch_pantsd()

        with self._run_tracker.new_workunit(name="setup", labels=[WorkUnitLabel.SETUP]):
            self._expand_goals(self._requested_goals)
            self._expand_specs(self._target_specs, self._fail_fast)

#.........这里部分代码省略.........
开发者ID:dfabulich,项目名称:pants,代码行数:101,代码来源:goal_runner.py

示例5: GoalRunnerFactory

class GoalRunnerFactory(object):
  def __init__(self, root_dir, options, build_config, run_tracker, reporting, exiter=sys.exit):
    """
    :param str root_dir: The root directory of the pants workspace (aka the "build root").
    :param Options options: The global, pre-initialized Options instance.
    :param BuildConfiguration build_config: A pre-initialized BuildConfiguration instance.
    :param Runtracker run_tracker: The global, pre-initialized/running RunTracker instance.
    :param Reporting reporting: The global, pre-initialized Reporting instance.
    :param func exiter: A function that accepts an exit code value and exits (for tests, Optional).
    """
    self._root_dir = root_dir
    self._options = options
    self._build_config = build_config
    self._run_tracker = run_tracker
    self._reporting = reporting
    self._exiter = exiter

    self._goals = []
    self._targets = []
    self._requested_goals = self._options.goals
    self._target_specs = self._options.target_specs
    self._help_request = self._options.help_request

    self._global_options = options.for_global_scope()
    self._tag = self._global_options.tag
    self._fail_fast = self._global_options.fail_fast
    self._spec_excludes = self._global_options.spec_excludes
    self._explain = self._global_options.explain
    self._kill_nailguns = self._global_options.kill_nailguns

    self._build_file_type = self._get_buildfile_type(self._global_options.build_file_rev)
    self._build_file_parser = BuildFileParser(self._build_config, self._root_dir)
    self._address_mapper = BuildFileAddressMapper(self._build_file_parser, self._build_file_type)
    self._build_graph = BuildGraph(self._address_mapper)
    self._spec_parser = CmdLineSpecParser(
      self._root_dir,
      self._address_mapper,
      spec_excludes=self._spec_excludes,
      exclude_target_regexps=self._global_options.exclude_target_regexp
    )

  def _get_buildfile_type(self, build_file_rev):
    """Selects the BuildFile type for use in a given pants run."""
    if build_file_rev:
      ScmBuildFile.set_rev(build_file_rev)
      ScmBuildFile.set_scm(get_scm())
      return ScmBuildFile
    else:
      return FilesystemBuildFile

  def _expand_goals(self, goals):
    """Check and populate the requested goals for a given run."""
    for goal in goals:
      if self._address_mapper.from_cache(self._root_dir, goal, must_exist=False).file_exists():
        logger.warning("Command-line argument '{0}' is ambiguous and was assumed to be "
                       "a goal. If this is incorrect, disambiguate it with ./{0}.".format(goal))

    if self._help_request:
      help_printer = HelpPrinter(self._options)
      help_printer.print_help()
      self._exiter(0)

    self._goals.extend([Goal.by_name(goal) for goal in goals])

  def _expand_specs(self, specs, fail_fast):
    """Populate the BuildGraph and target list from a set of input specs."""
    with self._run_tracker.new_workunit(name='parse', labels=[WorkUnitLabel.SETUP]):
      def filter_for_tag(tag):
        return lambda target: tag in map(str, target.tags)

      tag_filter = wrap_filters(create_filters(self._tag, filter_for_tag))

      for spec in specs:
        for address in self._spec_parser.parse_addresses(spec, fail_fast):
          self._build_graph.inject_address_closure(address)
          target = self._build_graph.get_target(address)
          if tag_filter(target):
            self._targets.append(target)

  def _is_quiet(self):
    return any(goal.has_task_of_type(QuietTaskMixin) for goal in self._goals) or self._explain

  def _setup_context(self):
    # TODO(John Sirois): Kill when source root registration is lifted out of BUILD files.
    with self._run_tracker.new_workunit(name='bootstrap', labels=[WorkUnitLabel.SETUP]):
      source_root_bootstrapper = SourceRootBootstrapper.global_instance()
      source_root_bootstrapper.bootstrap(self._address_mapper, self._build_file_parser)

    with self._run_tracker.new_workunit(name='setup', labels=[WorkUnitLabel.SETUP]):
      self._expand_goals(self._requested_goals)
      self._expand_specs(self._target_specs, self._fail_fast)

      # Now that we've parsed the bootstrap BUILD files, and know about the SCM system.
      self._run_tracker.run_info.add_scm_info()

      # Update the Reporting settings now that we have options and goal info.
      invalidation_report = self._reporting.update_reporting(self._global_options,
                                                             self._is_quiet(),
                                                             self._run_tracker)

#.........这里部分代码省略.........
开发者ID:qma,项目名称:pants,代码行数:101,代码来源:goal_runner.py

示例6: BaseTest


#.........这里部分代码省略.........
      'cache_key_gen_version': '0-test',
    }
    self.options['cache'] = {
      'read_from': [],
      'write_to': [],
    }

    BuildRoot().path = self.build_root
    self.addCleanup(BuildRoot().reset)

    self._build_configuration = BuildConfiguration()
    self._build_configuration.register_aliases(self.alias_groups)
    self.build_file_parser = BuildFileParser(self._build_configuration, self.build_root)
    self.project_tree = FileSystemProjectTree(self.build_root)
    self.reset_build_graph()

  def buildroot_files(self, relpath=None):
    """Returns the set of all files under the test build root.

    :API: public

    :param string relpath: If supplied, only collect files from this subtree.
    :returns: All file paths found.
    :rtype: set
    """
    def scan():
      for root, dirs, files in os.walk(os.path.join(self.build_root, relpath or '')):
        for f in files:
          yield os.path.relpath(os.path.join(root, f), self.build_root)
    return set(scan())

  def reset_build_graph(self):
    """Start over with a fresh build graph with no targets in it."""
    self.address_mapper = BuildFileAddressMapper(self.build_file_parser, self.project_tree,
                                                 build_ignore_patterns=self.build_ignore_patterns)
    self.build_graph = MutableBuildGraph(address_mapper=self.address_mapper)

  def set_options_for_scope(self, scope, **kwargs):
    self.options[scope].update(kwargs)

  def context(self, for_task_types=None, for_subsystems=None, options=None,
              target_roots=None, console_outstream=None, workspace=None,
              **kwargs):
    """
    :API: public

    :param dict **kwargs: keyword arguments passed in to `create_options_for_optionables`.
    """
    # Many tests use source root functionality via the SourceRootConfig.global_instance().
    # (typically accessed via Target.target_base), so we always set it up, for convenience.
    optionables = {SourceRootConfig}
    extra_scopes = set()

    for_subsystems = for_subsystems or ()
    for subsystem in for_subsystems:
      if subsystem.options_scope is None:
        raise TaskError('You must set a scope on your subsystem type before using it in tests.')
      optionables.add(subsystem)

    for_task_types = for_task_types or ()
    for task_type in for_task_types:
      scope = task_type.options_scope
      if scope is None:
        raise TaskError('You must set a scope on your task type before using it in tests.')
      optionables.add(task_type)
      # If task is expected to inherit goal-level options, register those directly on the task,
开发者ID:benjyw,项目名称:pants,代码行数:67,代码来源:base_test.py

示例7: reset_build_graph

 def reset_build_graph(self):
   """Start over with a fresh build graph with no targets in it."""
   self.address_mapper = BuildFileAddressMapper(self.build_file_parser, self.project_tree,
                                                build_ignore_patterns=self.build_ignore_patterns)
   self.build_graph = MutableBuildGraph(address_mapper=self.address_mapper)
开发者ID:benjyw,项目名称:pants,代码行数:5,代码来源:base_test.py

示例8: reset_build_graph

 def reset_build_graph(self):
   """Start over with a fresh build graph with no targets in it."""
   self.address_mapper = BuildFileAddressMapper(self.build_file_parser, FileSystemProjectTree(self.build_root))
   self.build_graph = MutableBuildGraph(address_mapper=self.address_mapper)
开发者ID:adamchainz,项目名称:pants,代码行数:4,代码来源:base_test.py

示例9: GoalRunnerFactory

class GoalRunnerFactory(object):
  def __init__(self, root_dir, options, build_config, run_tracker, reporting, build_graph=None,
               exiter=sys.exit):
    """
    :param str root_dir: The root directory of the pants workspace (aka the "build root").
    :param Options options: The global, pre-initialized Options instance.
    :param BuildConfiguration build_config: A pre-initialized BuildConfiguration instance.
    :param Runtracker run_tracker: The global, pre-initialized/running RunTracker instance.
    :param Reporting reporting: The global, pre-initialized Reporting instance.
    :param BuildGraph build_graph: A BuildGraph instance (for graph reuse, optional).
    :param func exiter: A function that accepts an exit code value and exits (for tests, Optional).
    """
    self._root_dir = root_dir
    self._options = options
    self._build_config = build_config
    self._run_tracker = run_tracker
    self._reporting = reporting
    self._exiter = exiter

    self._goals = []
    self._targets = []
    self._requested_goals = self._options.goals
    self._target_specs = self._options.target_specs
    self._help_request = self._options.help_request

    self._global_options = options.for_global_scope()
    self._tag = self._global_options.tag
    self._fail_fast = self._global_options.fail_fast
    # Will be provided through context.address_mapper.build_ignore_patterns.
    self._explain = self._global_options.explain
    self._kill_nailguns = self._global_options.kill_nailguns

    pants_ignore = self._global_options.pants_ignore or []
    self._project_tree = self._get_project_tree(self._global_options.build_file_rev, pants_ignore)
    self._build_file_parser = BuildFileParser(self._build_config, self._root_dir)
    build_ignore_patterns = self._global_options.ignore_patterns or []
    self._address_mapper = BuildFileAddressMapper(
      self._build_file_parser,
      self._project_tree,
      build_ignore_patterns,
      exclude_target_regexps=self._global_options.exclude_target_regexp
    )
    self._build_graph = self._select_buildgraph(self._global_options.enable_v2_engine,
                                                self._global_options.pants_ignore,
                                                build_graph)

  def _select_buildgraph(self, use_engine, path_ignore_patterns, cached_buildgraph=None):
    """Selects a BuildGraph to use then constructs and returns it.

    :param bool use_engine: Whether or not to use the v2 engine to construct the BuildGraph.
    :param list path_ignore_patterns: The path ignore patterns from `--pants-ignore`.
    :param LegacyBuildGraph cached_buildgraph: A cached graph to reuse, if available.
    """
    if cached_buildgraph is not None:
      return cached_buildgraph
    elif use_engine:
      root_specs = EngineInitializer.parse_commandline_to_spec_roots(options=self._options,
                                                                     build_root=self._root_dir)
      graph_helper = EngineInitializer.setup_legacy_graph(path_ignore_patterns)
      return graph_helper.create_graph(root_specs)
    else:
      return MutableBuildGraph(self._address_mapper)

  def _get_project_tree(self, build_file_rev, pants_ignore):
    """Creates the project tree for build files for use in a given pants run."""
    if build_file_rev:
      return ScmProjectTree(self._root_dir, get_scm(), build_file_rev, pants_ignore)
    else:
      return FileSystemProjectTree(self._root_dir, pants_ignore)

  def _expand_goals(self, goals):
    """Check and populate the requested goals for a given run."""
    for goal in goals:
      try:
        self._address_mapper.resolve_spec(goal)
        logger.warning("Command-line argument '{0}' is ambiguous and was assumed to be "
                       "a goal. If this is incorrect, disambiguate it with ./{0}.".format(goal))
      except AddressLookupError:
        pass

    if self._help_request:
      help_printer = HelpPrinter(self._options)
      result = help_printer.print_help()
      self._exiter(result)

    self._goals.extend([Goal.by_name(goal) for goal in goals])

  def _expand_specs(self, spec_strs, fail_fast):
    """Populate the BuildGraph and target list from a set of input specs."""
    with self._run_tracker.new_workunit(name='parse', labels=[WorkUnitLabel.SETUP]):
      def filter_for_tag(tag):
        return lambda target: tag in map(str, target.tags)

      tag_filter = wrap_filters(create_filters(self._tag, filter_for_tag))

      # Parse all specs into unique Spec objects.
      spec_parser = CmdLineSpecParser(self._root_dir)
      specs = OrderedSet()
      for spec_str in spec_strs:
        specs.add(spec_parser.parse_spec(spec_str))
#.........这里部分代码省略.........
开发者ID:RobinTec,项目名称:pants,代码行数:101,代码来源:goal_runner.py

示例10: BaseTest


#.........这里部分代码省略.........
            "pants_subprocessdir": self.subprocess_dir,
            "cache_key_gen_version": "0-test",
        }
        self.options["cache"] = {"read_from": [], "write_to": []}

        BuildRoot().path = self.build_root
        self.addCleanup(BuildRoot().reset)

        self._build_configuration = BuildConfiguration()
        self._build_configuration.register_aliases(self.alias_groups)
        self.build_file_parser = BuildFileParser(self._build_configuration, self.build_root)
        self.project_tree = FileSystemProjectTree(self.build_root)
        self.reset_build_graph()

    def buildroot_files(self, relpath=None):
        """Returns the set of all files under the test build root.

    :API: public

    :param string relpath: If supplied, only collect files from this subtree.
    :returns: All file paths found.
    :rtype: set
    """

        def scan():
            for root, dirs, files in os.walk(os.path.join(self.build_root, relpath or "")):
                for f in files:
                    yield os.path.relpath(os.path.join(root, f), self.build_root)

        return set(scan())

    def reset_build_graph(self):
        """Start over with a fresh build graph with no targets in it."""
        self.address_mapper = BuildFileAddressMapper(
            self.build_file_parser, self.project_tree, build_ignore_patterns=self.build_ignore_patterns
        )
        self.build_graph = MutableBuildGraph(address_mapper=self.address_mapper)

    def set_options_for_scope(self, scope, **kwargs):
        self.options[scope].update(kwargs)

    def context(
        self,
        for_task_types=None,
        options=None,
        passthru_args=None,
        target_roots=None,
        console_outstream=None,
        workspace=None,
        for_subsystems=None,
    ):
        """
    :API: public
    """
        # Many tests use source root functionality via the SourceRootConfig.global_instance()
        # (typically accessed via Target.target_base), so we always set it up, for convenience.
        optionables = {SourceRootConfig}
        extra_scopes = set()

        for_subsystems = for_subsystems or ()
        for subsystem in for_subsystems:
            if subsystem.options_scope is None:
                raise TaskError("You must set a scope on your subsystem type before using it in tests.")
            optionables.add(subsystem)

        for_task_types = for_task_types or ()
开发者ID:CaitieM20,项目名称:pants,代码行数:67,代码来源:base_test.py


注:本文中的pants.build_graph.build_file_address_mapper.BuildFileAddressMapper类示例由纯净天空整理自Github/MSDocs等开源代码及文档管理平台,相关代码片段筛选自各路编程大神贡献的开源项目,源码版权归原作者所有,传播和使用请参考对应项目的License;未经允许,请勿转载。